Allow tag relations + bump ecto deps
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -579,7 +579,7 @@ defmodule Mobilizon.Actors do
|
||||
"""
|
||||
def authenticate(%{user: user, password: password}) do
|
||||
# Does password match the one stored in the database?
|
||||
case Comeonin.Argon2.checkpw(password, user.password_hash) do
|
||||
case Argon2.verify_pass(password, user.password_hash) do
|
||||
true ->
|
||||
# Yes, create and return the token
|
||||
MobilizonWeb.Guardian.encode_and_sign(user)
|
||||
|
||||
@@ -12,7 +12,7 @@ defmodule Mobilizon.Actors.Service.Activation do
|
||||
with %User{} = user <- Actors.get_user_by_activation_token(token),
|
||||
{:ok, %User{} = user} <-
|
||||
Actors.update_user(user, %{
|
||||
"confirmed_at" => DateTime.utc_now(),
|
||||
"confirmed_at" => DateTime.utc_now() |> DateTime.truncate(:second),
|
||||
"confirmation_sent_at" => nil,
|
||||
"confirmation_token" => nil
|
||||
}) do
|
||||
@@ -26,7 +26,10 @@ defmodule Mobilizon.Actors.Service.Activation do
|
||||
|
||||
def resend_confirmation_email(%User{} = user, locale \\ "en") do
|
||||
with :ok <- Tools.we_can_send_email(user, :confirmation_sent_at),
|
||||
{:ok, user} <- Actors.update_user(user, %{"confirmation_sent_at" => DateTime.utc_now()}) do
|
||||
{:ok, user} <-
|
||||
Actors.update_user(user, %{
|
||||
"confirmation_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
|
||||
}) do
|
||||
send_confirmation_email(user, locale)
|
||||
Logger.info("Sent confirmation email again to #{user.email}")
|
||||
{:ok, user.email}
|
||||
|
||||
@@ -43,7 +43,7 @@ defmodule Mobilizon.Actors.Service.ResetPassword do
|
||||
Repo.update(
|
||||
User.send_password_reset_changeset(user, %{
|
||||
"reset_password_token" => Tools.random_string(30),
|
||||
"reset_password_sent_at" => DateTime.utc_now()
|
||||
"reset_password_sent_at" => DateTime.utc_now() |> DateTime.truncate(:second)
|
||||
})
|
||||
) do
|
||||
mail =
|
||||
|
||||
@@ -11,7 +11,10 @@ defmodule Mobilizon.Actors.Service.Tools do
|
||||
:ok
|
||||
|
||||
_ ->
|
||||
case Timex.before?(Timex.shift(Map.get(user, key), hours: 1), DateTime.utc_now()) do
|
||||
case Timex.before?(
|
||||
Timex.shift(Map.get(user, key), hours: 1),
|
||||
DateTime.utc_now() |> DateTime.truncate(:second)
|
||||
) do
|
||||
true ->
|
||||
:ok
|
||||
|
||||
|
||||
@@ -89,7 +89,12 @@ defmodule Mobilizon.Actors.User do
|
||||
case changeset do
|
||||
%Ecto.Changeset{valid?: true, changes: %{email: _email}} ->
|
||||
changeset = put_change(changeset, :confirmation_token, random_string(30))
|
||||
put_change(changeset, :confirmation_sent_at, DateTime.utc_now())
|
||||
|
||||
put_change(
|
||||
changeset,
|
||||
:confirmation_sent_at,
|
||||
DateTime.utc_now() |> DateTime.truncate(:second)
|
||||
)
|
||||
|
||||
_ ->
|
||||
changeset
|
||||
@@ -122,7 +127,7 @@ defmodule Mobilizon.Actors.User do
|
||||
put_change(
|
||||
changeset,
|
||||
:password_hash,
|
||||
Comeonin.Argon2.hashpwsalt(password)
|
||||
Argon2.hash_pwd_salt(password)
|
||||
)
|
||||
|
||||
_ ->
|
||||
|
||||
@@ -32,16 +32,16 @@ defmodule Mobilizon.Events.Event do
|
||||
schema "events" do
|
||||
field(:url, :string)
|
||||
field(:local, :boolean, default: true)
|
||||
field(:begins_on, Timex.Ecto.DateTimeWithTimezone)
|
||||
field(:begins_on, :utc_datetime)
|
||||
field(:description, :string)
|
||||
field(:ends_on, Timex.Ecto.DateTimeWithTimezone)
|
||||
field(:ends_on, :utc_datetime)
|
||||
field(:title, :string)
|
||||
field(:status, Mobilizon.Events.EventStatusEnum, default: :confirmed)
|
||||
field(:visibility, Mobilizon.Events.EventVisibilityEnum, default: :public)
|
||||
field(:join_options, Mobilizon.Events.JoinOptionsEnum, default: :free)
|
||||
field(:thumbnail, :string)
|
||||
field(:large_image, :string)
|
||||
field(:publish_at, Timex.Ecto.DateTimeWithTimezone)
|
||||
field(:publish_at, :utc_datetime)
|
||||
field(:uuid, Ecto.UUID, default: Ecto.UUID.generate())
|
||||
field(:online_address, :string)
|
||||
field(:phone_address, :string)
|
||||
|
||||
@@ -458,8 +458,32 @@ defmodule Mobilizon.Events do
|
||||
[%Tag{}, ...]
|
||||
|
||||
"""
|
||||
def list_tags do
|
||||
Repo.all(Tag)
|
||||
def list_tags(page \\ nil, limit \\ nil) do
|
||||
Repo.all(
|
||||
Tag
|
||||
|> paginate(page, limit)
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the list of tags for an event.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> list_tags_for_event(id)
|
||||
[%Participant{}, ...]
|
||||
|
||||
"""
|
||||
def list_tags_for_event(id, page \\ nil, limit \\ nil) do
|
||||
Repo.all(
|
||||
from(
|
||||
t in Tag,
|
||||
join: e in "events_tags",
|
||||
on: t.id == e.tag_id,
|
||||
where: e.event_id == ^id
|
||||
)
|
||||
|> paginate(page, limit)
|
||||
)
|
||||
end
|
||||
|
||||
@doc """
|
||||
@@ -543,6 +567,85 @@ defmodule Mobilizon.Events do
|
||||
Tag.changeset(tag, %{})
|
||||
end
|
||||
|
||||
alias Mobilizon.Events.TagRelation
|
||||
|
||||
@doc """
|
||||
Create a relation between two tags
|
||||
"""
|
||||
def create_tag_relation(attrs \\ {}) do
|
||||
%TagRelation{}
|
||||
|> TagRelation.changeset(attrs)
|
||||
|> Repo.insert(conflict_target: [:tag_id, :link_id], on_conflict: [inc: [weight: 1]])
|
||||
end
|
||||
|
||||
@doc """
|
||||
Remove a tag relation
|
||||
"""
|
||||
def delete_tag_relation(%TagRelation{} = tag_relation) do
|
||||
Repo.delete(tag_relation)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns whether two tags are linked or not
|
||||
"""
|
||||
def are_tags_linked(%Tag{id: tag1_id}, %Tag{id: tag2_id}) do
|
||||
case from(tr in TagRelation,
|
||||
where: tr.tag_id == ^min(tag1_id, tag2_id) and tr.link_id == ^max(tag1_id, tag2_id)
|
||||
)
|
||||
|> Repo.one() do
|
||||
%TagRelation{} -> true
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns the tags neighbors for a given tag
|
||||
|
||||
We can't rely on the single many_to_many relation since we also want tags that link to our tag, not just tags linked by this one
|
||||
|
||||
The SQL query looks like this:
|
||||
```sql
|
||||
SELECT * FROM tags t
|
||||
RIGHT JOIN (
|
||||
SELECT weight, link_id AS id
|
||||
FROM tag_relations t2
|
||||
WHERE tag_id = 1
|
||||
UNION ALL
|
||||
SELECT tag_id AS id, weight
|
||||
FROM tag_relations t2
|
||||
WHERE link_id = 1
|
||||
) tr
|
||||
ON t.id = tr.id
|
||||
ORDER BY tr.weight
|
||||
DESC;
|
||||
```
|
||||
"""
|
||||
def tag_neighbors(%Tag{id: id}, relation_minimum \\ 1, limit \\ 10) do
|
||||
query2 =
|
||||
from(tr in TagRelation,
|
||||
select: %{id: tr.tag_id, weight: tr.weight},
|
||||
where: tr.link_id == ^id
|
||||
)
|
||||
|
||||
query =
|
||||
from(tr in TagRelation,
|
||||
select: %{id: tr.link_id, weight: tr.weight},
|
||||
union_all: ^query2,
|
||||
where: tr.tag_id == ^id
|
||||
)
|
||||
|
||||
final_query =
|
||||
from(t in Tag,
|
||||
right_join: q in subquery(query),
|
||||
on: [id: t.id],
|
||||
where: q.weight >= ^relation_minimum,
|
||||
limit: ^limit,
|
||||
order_by: [desc: q.weight]
|
||||
)
|
||||
|
||||
Repo.all(final_query)
|
||||
end
|
||||
|
||||
alias Mobilizon.Events.Participant
|
||||
|
||||
@doc """
|
||||
|
||||
@@ -15,8 +15,8 @@ defmodule Mobilizon.Events.Session do
|
||||
field(:subtitle, :string)
|
||||
field(:title, :string)
|
||||
field(:videos_urls, :string)
|
||||
field(:begins_on, Timex.Ecto.DateTimeWithTimezone)
|
||||
field(:ends_on, Timex.Ecto.DateTimeWithTimezone)
|
||||
field(:begins_on, :utc_datetime)
|
||||
field(:ends_on, :utc_datetime)
|
||||
belongs_to(:event, Event)
|
||||
belongs_to(:track, Track)
|
||||
|
||||
|
||||
@@ -39,10 +39,12 @@ defmodule Mobilizon.Events.Tag do
|
||||
import Ecto.Changeset
|
||||
alias Mobilizon.Events.Tag
|
||||
alias Mobilizon.Events.Tag.TitleSlug
|
||||
alias Mobilizon.Events.TagRelation
|
||||
|
||||
schema "tags" do
|
||||
field(:title, :string)
|
||||
field(:slug, TitleSlug.Type)
|
||||
many_to_many(:related_tags, Tag, join_through: TagRelation)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
41
lib/mobilizon/events/tag_relations.ex
Normal file
41
lib/mobilizon/events/tag_relations.ex
Normal file
@@ -0,0 +1,41 @@
|
||||
defmodule Mobilizon.Events.TagRelation do
|
||||
@moduledoc """
|
||||
Represents a tag for events
|
||||
"""
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Mobilizon.Events.Tag
|
||||
alias Mobilizon.Events.TagRelation
|
||||
|
||||
@primary_key false
|
||||
schema "tag_relations" do
|
||||
belongs_to(:tag, Tag, primary_key: true)
|
||||
belongs_to(:link, Tag, primary_key: true)
|
||||
field(:weight, :integer, default: 1)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def changeset(%TagRelation{} = tag, attrs) do
|
||||
changeset =
|
||||
tag
|
||||
|> cast(attrs, [:tag_id, :link_id, :weight])
|
||||
|> validate_required([:tag_id, :link_id])
|
||||
|
||||
# Return if tag_id or link_id are not set because it will fail later otherwise
|
||||
with %Ecto.Changeset{errors: []} <- changeset do
|
||||
changes = changeset.changes
|
||||
|
||||
changeset =
|
||||
changeset
|
||||
|> put_change(:tag_id, min(changes.tag_id, changes.link_id))
|
||||
|> put_change(:link_id, max(changes.tag_id, changes.link_id))
|
||||
|
||||
changeset
|
||||
|> unique_constraint(:tag_id, name: :tag_relations_pkey)
|
||||
|> check_constraint(:tag_id,
|
||||
name: :no_self_loops_check,
|
||||
message: "Can't add a relation on self"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,5 @@
|
||||
Postgrex.Types.define(
|
||||
Mobilizon.PostgresTypes,
|
||||
[Geo.PostGIS.Extension] ++ Ecto.Adapters.Postgres.extensions(),
|
||||
json: Poison
|
||||
json: Jason
|
||||
)
|
||||
|
||||
@@ -2,7 +2,9 @@ defmodule Mobilizon.Repo do
|
||||
@moduledoc """
|
||||
Mobilizon Repo
|
||||
"""
|
||||
use Ecto.Repo, otp_app: :mobilizon
|
||||
use Ecto.Repo,
|
||||
otp_app: :mobilizon,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
|
||||
@doc """
|
||||
Dynamically loads the repository url from the
|
||||
|
||||
@@ -5,7 +5,7 @@ defmodule MobilizonWeb.AuthErrorHandler do
|
||||
import Plug.Conn
|
||||
|
||||
def auth_error(conn, {type, _reason}, _opts) do
|
||||
body = Poison.encode!(%{message: to_string(type)})
|
||||
body = Jason.encode!(%{message: to_string(type)})
|
||||
send_resp(conn, 401, body)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,7 @@ defmodule MobilizonWeb.Endpoint do
|
||||
Plug.Parsers,
|
||||
parsers: [:urlencoded, :multipart, :json],
|
||||
pass: ["*/*"],
|
||||
json_decoder: Poison
|
||||
json_decoder: Jason
|
||||
)
|
||||
|
||||
plug(Plug.MethodOverride)
|
||||
|
||||
40
lib/mobilizon_web/resolvers/tag.ex
Normal file
40
lib/mobilizon_web/resolvers/tag.ex
Normal file
@@ -0,0 +1,40 @@
|
||||
defmodule MobilizonWeb.Resolvers.Tag do
|
||||
@moduledoc """
|
||||
Handles the tag-related GraphQL calls
|
||||
"""
|
||||
require Logger
|
||||
alias Mobilizon.Events.Event
|
||||
alias Mobilizon.Events.Tag
|
||||
|
||||
def list_tags(_parent, %{page: page, limit: limit}, _resolution) do
|
||||
tags = Mobilizon.Events.list_tags(page, limit)
|
||||
|
||||
{:ok, tags}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Retrieve the list of tags for an event
|
||||
"""
|
||||
def list_tags_for_event(%Event{id: id}, _args, _resolution) do
|
||||
{:ok, Mobilizon.Events.list_tags_for_event(id)}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Retrieve the list of related tags for a given tag ID
|
||||
"""
|
||||
def get_related_tags(_parent, %{tag_id: tag_id}, _resolution) do
|
||||
with %Tag{} = tag <- Mobilizon.Events.get_tag!(tag_id),
|
||||
tags <- Mobilizon.Events.tag_neighbors(tag) do
|
||||
{:ok, tags}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Retrieve the list of related tags for a parent tag
|
||||
"""
|
||||
def get_related_tags(%Tag{} = tag, _args, _resolution) do
|
||||
with tags <- Mobilizon.Events.tag_neighbors(tag) do
|
||||
{:ok, tags}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,6 +8,7 @@ defmodule MobilizonWeb.Schema.EventType do
|
||||
import_types(MobilizonWeb.Schema.AddressType)
|
||||
import_types(MobilizonWeb.Schema.Events.ParticipantType)
|
||||
import_types(MobilizonWeb.Schema.Events.CategoryType)
|
||||
import_types(MobilizonWeb.Schema.TagType)
|
||||
alias MobilizonWeb.Resolvers
|
||||
|
||||
@desc "An event"
|
||||
@@ -37,7 +38,12 @@ defmodule MobilizonWeb.Schema.EventType do
|
||||
)
|
||||
|
||||
field(:attributed_to, :actor, description: "Who the event is attributed to (often a group)")
|
||||
# field(:tags, list_of(:tag))
|
||||
|
||||
field(:tags, list_of(:tag),
|
||||
resolve: &MobilizonWeb.Resolvers.Tag.list_tags_for_event/3,
|
||||
description: "The event's tags"
|
||||
)
|
||||
|
||||
field(:category, :category, description: "The event's category")
|
||||
|
||||
field(:participants, list_of(:participant),
|
||||
|
||||
30
lib/mobilizon_web/schema/tag.ex
Normal file
30
lib/mobilizon_web/schema/tag.ex
Normal file
@@ -0,0 +1,30 @@
|
||||
defmodule MobilizonWeb.Schema.TagType do
|
||||
@moduledoc """
|
||||
Schema representation for Tags
|
||||
"""
|
||||
use Absinthe.Schema.Notation
|
||||
alias MobilizonWeb.Resolvers
|
||||
|
||||
@desc "A tag"
|
||||
object :tag do
|
||||
field(:id, :id, description: "The tag's ID")
|
||||
field(:slug, :string, description: "The tags's slug")
|
||||
field(:title, :string, description: "The tag's title")
|
||||
|
||||
field(
|
||||
:related,
|
||||
list_of(:tag),
|
||||
resolve: &Resolvers.Tag.get_related_tags/3,
|
||||
description: "Related tags to this tag"
|
||||
)
|
||||
end
|
||||
|
||||
object :tag_queries do
|
||||
@desc "Get the list of tags"
|
||||
field :tags, non_null(list_of(:tag)) do
|
||||
arg(:page, :integer, default_value: 1)
|
||||
arg(:limit, :integer, default_value: 10)
|
||||
resolve(&Resolvers.Tag.list_tags/3)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -495,7 +495,10 @@ defmodule Mobilizon.Service.ActivityPub do
|
||||
ical_events =
|
||||
body
|
||||
|> ExIcal.parse()
|
||||
|> ExIcal.by_range(DateTime.utc_now(), DateTime.utc_now() |> Timex.shift(years: 1))
|
||||
|> ExIcal.by_range(
|
||||
DateTime.utc_now(),
|
||||
DateTime.utc_now() |> DateTime.truncate(:second) |> Timex.shift(years: 1)
|
||||
)
|
||||
|
||||
activities =
|
||||
ical_events
|
||||
|
||||
@@ -46,7 +46,7 @@ defmodule Mobilizon.Service.ActivityPub.Utils do
|
||||
end
|
||||
|
||||
def make_date do
|
||||
DateTime.utc_now() |> DateTime.to_iso8601()
|
||||
DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
@@ -59,7 +59,7 @@ defmodule Mobilizon.Service.Federator do
|
||||
_e ->
|
||||
# Just drop those for now
|
||||
Logger.error("Unhandled activity")
|
||||
Logger.error(Poison.encode!(params, pretty: 2))
|
||||
Logger.error(Jason.encode!(params))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user