Various typespec and compilation improvements

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-09-10 11:27:59 +02:00
parent 029a4ea194
commit de047c8939
125 changed files with 790 additions and 357 deletions

View File

@@ -15,12 +15,13 @@ defmodule Mobilizon.GraphQL.API.Reports do
@doc """
Create a report/flag on an actor, and optionally on an event or on comments.
"""
@spec report(map()) :: {:ok, Activity.t(), Report.t()} | {:error, any()}
def report(args) do
case {:make_activity, ActivityPub.flag(args, Map.get(args, :forward, false) == true)} do
{:make_activity, {:ok, %Activity{} = activity, %Report{} = report}} ->
case ActivityPub.flag(args, Map.get(args, :forward, false) == true) do
{:ok, %Activity{} = activity, %Report{} = report} ->
{:ok, activity, report}
{:make_activity, err} ->
err ->
{:error, err}
end
end
@@ -28,10 +29,12 @@ defmodule Mobilizon.GraphQL.API.Reports do
@doc """
Update the state of a report
"""
@spec update_report_status(Actor.t(), Report.t(), ReportStatus.t()) ::
{:ok, Report.t()} | {:error, String.t()}
def update_report_status(%Actor{} = actor, %Report{} = report, state) do
with {:valid_state, true} <-
{:valid_state, ReportStatus.valid_value?(state)},
{:ok, report} <- ReportsAction.update_report(report, %{"status" => state}),
{:ok, %Report{} = report} <- ReportsAction.update_report(report, %{"status" => state}),
{:ok, _} <- Admin.log_action(actor, "update", report) do
{:ok, report}
else
@@ -42,7 +45,8 @@ defmodule Mobilizon.GraphQL.API.Reports do
@doc """
Create a note on a report
"""
@spec create_report_note(Report.t(), Actor.t(), String.t()) :: {:ok, Note.t()}
@spec create_report_note(Report.t(), Actor.t(), String.t()) ::
{:ok, Note.t()} | {:error, String.t()}
def create_report_note(
%Report{id: report_id},
%Actor{id: moderator_id, user_id: user_id} = moderator,
@@ -67,7 +71,7 @@ defmodule Mobilizon.GraphQL.API.Reports do
@doc """
Delete a report note
"""
@spec delete_report_note(Note.t(), Actor.t()) :: {:ok, Note.t()}
@spec delete_report_note(Note.t(), Actor.t()) :: {:ok, Note.t()} | {:error, String.t()}
def delete_report_note(
%Note{moderator_id: note_moderator_id} = note,
%Actor{id: moderator_id, user_id: user_id} = moderator

View File

@@ -10,7 +10,7 @@ defmodule Mobilizon.GraphQL.API.Utils do
@doc """
Creates HTML content from text and mentions
"""
@spec make_content_html(String.t(), list(), String.t()) :: String.t()
@spec make_content_html(String.t(), list(), String.t()) :: {String.t(), list(), list()}
def make_content_html(text, additional_tags, content_type) do
with {text, mentions, tags} <- format_input(text, content_type, []) do
{text, mentions, additional_tags ++ Enum.map(tags, fn {_, tag} -> tag end)}

View File

@@ -66,7 +66,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Comment do
with {:actor, %Actor{id: actor_id} = _actor} <- {:actor, Users.get_actor_for_user(user)},
%CommentModel{actor_id: comment_actor_id} = comment <-
Mobilizon.Discussions.get_comment_with_preload(comment_id),
true <- actor_id === comment_actor_id,
true <- actor_id == comment_actor_id,
{:ok, _, %CommentModel{} = comment} <- Comments.update_comment(comment, %{text: text}) do
{:ok, comment}
end

View File

@@ -6,7 +6,10 @@ defmodule Mobilizon.GraphQL.Resolvers.Event.Utils do
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.Event
alias Mobilizon.Federation.ActivityPub.Permission
import Mobilizon.Service.Guards, only: [is_valid_string: 1]
@spec can_event_be_updated_by?(%Event{id: String.t()}, Actor.t()) ::
boolean
def can_event_be_updated_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Actor{} = actor_member
@@ -21,10 +24,13 @@ defmodule Mobilizon.GraphQL.Resolvers.Event.Utils do
Event.can_be_managed_by?(event, actor_member_id)
end
@spec can_event_be_deleted_by?(%Event{id: String.t(), url: String.t()}, Actor.t()) ::
boolean
def can_event_be_deleted_by?(
%Event{attributed_to: %Actor{type: :Group}} = event,
%Event{attributed_to: %Actor{type: :Group}, id: event_id, url: event_url} = event,
%Actor{} = actor_member
) do
)
when is_valid_string(event_id) and is_valid_string(event_url) do
Permission.can_delete_group_object?(actor_member, event)
end

View File

@@ -101,7 +101,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Member do
with %Actor{id: actor_id} <- Users.get_actor_for_user(user),
%Member{actor: %Actor{id: member_actor_id}} = member <-
Actors.get_member(member_id),
{:is_same_actor, true} <- {:is_same_actor, member_actor_id === actor_id},
{:is_same_actor, true} <- {:is_same_actor, member_actor_id == actor_id},
{:ok, _activity, %Member{} = member} <-
ActivityPub.accept(
:invite,
@@ -119,7 +119,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Member do
with %Actor{id: actor_id} <- Users.get_actor_for_user(user),
{:invitation_exists, %Member{actor: %Actor{id: member_actor_id}} = member} <-
{:invitation_exists, Actors.get_member(member_id)},
{:is_same_actor, true} <- {:is_same_actor, member_actor_id === actor_id},
{:is_same_actor, true} <- {:is_same_actor, member_actor_id == actor_id},
{:ok, _activity, %Member{} = member} <-
ActivityPub.reject(
:invite,

View File

@@ -95,6 +95,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
ActivityPub.create(:todo_list, Map.put(args, :actor_id, group_id), true, %{}) do
{:ok, todo_list}
else
{:actor, nil} ->
{:error, dgettext("errors", "No profile found for user")}
{:member, _} ->
{:error, dgettext("errors", "Profile is not member of group")}
end
@@ -187,6 +190,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
ActivityPub.create(:todo, Map.put(args, :creator_id, actor_id), true, %{}) do
{:ok, todo}
else
{:actor, nil} ->
{:error, dgettext("errors", "No profile found for user")}
{:todo_list, _} ->
{:error, dgettext("errors", "Todo list doesn't exist")}
@@ -212,6 +218,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
ActivityPub.update(todo, args, true, %{}) do
{:ok, todo}
else
{:actor, nil} ->
{:error, dgettext("errors", "No profile found for user")}
{:todo_list, _} ->
{:error, dgettext("errors", "Todo list doesn't exist")}

View File

@@ -65,9 +65,8 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
refresh_token: _refresh_token,
user: %User{} = user
} = user_and_tokens} <- Authenticator.authenticate(email, password),
{:ok, %User{} = user} <- update_user_login_information(user, context),
user_and_tokens <- Map.put(user_and_tokens, :user, user) do
{:ok, user_and_tokens}
{:ok, %User{} = user} <- update_user_login_information(user, context) do
{:ok, %{user_and_tokens | user: user}}
else
{:error, :user_not_found} ->
{:error, :user_not_found}
@@ -133,7 +132,7 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
- create the user
- send a validation email to the user
"""
@spec create_user(any, map, any) :: tuple
@spec create_user(any, %{email: String.t()}, any) :: tuple
def create_user(_parent, %{email: email} = args, _resolution) do
with :registration_ok <- check_registration_config(email),
:not_deny_listed <- check_registration_denylist(email),
@@ -160,20 +159,21 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
end
end
@spec check_registration_config(map) :: atom
@spec check_registration_config(String.t()) :: atom
defp check_registration_config(email) do
cond do
Config.instance_registrations_open?() ->
:registration_ok
Config.instance_registrations_allowlist?() ->
check_allow_listed_email?(email)
check_allow_listed_email(email)
true ->
:registration_closed
end
end
@spec check_registration_denylist(String.t()) :: :deny_listed | :not_deny_listed
defp check_registration_denylist(email) do
# Remove everything behind the +
email = String.replace(email, ~r/(\+.*)(?=\@)/, "")
@@ -183,8 +183,8 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
else: :not_deny_listed
end
@spec check_allow_listed_email?(String.t()) :: :registration_ok | :not_allowlisted
defp check_allow_listed_email?(email) do
@spec check_allow_listed_email(String.t()) :: :registration_ok | :not_allowlisted
defp check_allow_listed_email(email) do
if email_in_list(email, Config.instance_registrations_allowlist()),
do: :registration_ok,
else: :not_allowlisted
@@ -199,12 +199,14 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
@doc """
Validate an user, get its actor and a token
"""
@spec validate_user(map(), %{token: String.t()}, map()) :: {:ok, map()}
def validate_user(_parent, %{token: token}, _resolution) do
with {:check_confirmation_token, {:ok, %User{} = user}} <-
{:check_confirmation_token, Email.User.check_confirmation_token(token)},
{:get_actor, actor} <- {:get_actor, Users.get_actor_for_user(user)},
{:ok, %{access_token: access_token, refresh_token: refresh_token}} <-
Authenticator.generate_tokens(user) do
{:get_actor, actor} <- {:get_actor, Users.get_actor_for_user(user)} do
{:ok, %{access_token: access_token, refresh_token: refresh_token}} =
Authenticator.generate_tokens(user)
{:ok,
%{
access_token: access_token,
@@ -267,12 +269,16 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
@doc """
Reset the password from an user
"""
@spec reset_password(map(), %{password: String.t(), token: String.t()}, map()) ::
{:ok, map()} | {:error, String.t()}
def reset_password(_parent, %{password: password, token: token}, _resolution) do
with {:ok, %User{email: email} = user} <-
Email.User.check_reset_password_token(password, token),
{:ok, %{access_token: access_token, refresh_token: refresh_token}} <-
Authenticator.authenticate(email, password) do
{:ok, %{access_token: access_token, refresh_token: refresh_token, user: user}}
case Email.User.check_reset_password_token(password, token) do
{:ok, %User{email: email} = user} ->
{:ok, tokens} = Authenticator.authenticate(email, password)
{:ok, Map.put(tokens, :user, user)}
{:error, error} ->
{:error, error}
end
end
@@ -369,6 +375,9 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
|> Repo.update() do
{:ok, user}
else
{:can_change_password, false} ->
{:error, dgettext("errors", "You cannot change your password.")}
{:current_password, _} ->
{:error, dgettext("errors", "The current password is invalid")}
@@ -408,14 +417,18 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
{:ok, user}
else
{:current_password, _} ->
{:current_password, {:error, _}} ->
{:error, dgettext("errors", "The password provided is invalid")}
{:same_email, true} ->
{:error, dgettext("errors", "The new email must be different")}
{:email_valid, _} ->
{:email_valid, false} ->
{:error, dgettext("errors", "The new email doesn't seem to be valid")}
{:error, %Ecto.Changeset{} = err} ->
Logger.debug(inspect(err))
{:error, dgettext("errors", "Failed to update user email")}
end
end
@@ -423,12 +436,21 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
{:error, dgettext("errors", "You need to be logged-in to change your email")}
end
@spec validate_email(map(), %{token: String.t()}, map()) ::
{:ok, User.t()} | {:error, String.t()}
def validate_email(_parent, %{token: token}, _resolution) do
with {:get, %User{} = user} <- {:get, Users.get_user_by_activation_token(token)},
{:ok, %User{} = user} <- Users.validate_email(user) do
{:ok, user}
else
{:get, nil} ->
case Users.get_user_by_activation_token(token) do
%User{} = user ->
case Users.validate_email(user) do
{:ok, %User{} = user} ->
{:ok, user}
{:error, %Ecto.Changeset{} = err} ->
Logger.debug(inspect(err))
{:error, dgettext("errors", "Failed to validate user email")}
end
nil ->
{:error, dgettext("errors", "Invalid activation token")}
end
end
@@ -547,12 +569,17 @@ defmodule Mobilizon.GraphQL.Resolvers.User do
def update_locale(_parent, %{locale: locale}, %{
context: %{current_user: %User{locale: current_locale} = user}
}) do
with true <- current_locale != locale,
{:ok, %User{} = updated_user} <- Users.update_user(user, %{locale: locale}) do
{:ok, updated_user}
if current_locale != locale do
case Users.update_user(user, %{locale: locale}) do
{:ok, %User{} = updated_user} ->
{:ok, updated_user}
{:error, %Ecto.Changeset{} = err} ->
Logger.debug(err)
{:error, dgettext("errors", "Error while updating locale")}
end
else
false ->
{:ok, user}
{:ok, user}
end
end

View File

@@ -23,6 +23,7 @@ defmodule Mobilizon.GraphQL.Schema.TagType do
object :tag_queries do
@desc "Get the list of tags"
field :tags, non_null(list_of(:tag)) do
arg(:filter, :string, description: "The filter to apply to the search")
arg(:page, :integer, default_value: 1, description: "The page in the paginated tags list")
arg(:limit, :integer, default_value: 10, description: "The limit of tags per page")
resolve(&Tag.list_tags/3)