Various refactoring and typespec improvements

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2021-09-24 16:46:42 +02:00
parent d235653876
commit 1893d9f55b
142 changed files with 1854 additions and 1297 deletions

View File

@@ -15,7 +15,8 @@ defmodule Mobilizon.Activities.Activity do
:message,
:message_params,
:object_type,
:object_id
:object_id,
:object
]
@attrs @required_attrs ++ @optional_attrs
@@ -28,6 +29,7 @@ defmodule Mobilizon.Activities.Activity do
message_params: map(),
object_type: ObjectType.t(),
object_id: String.t(),
object: map(),
author: Actor.t(),
group: Actor.t()
}
@@ -41,12 +43,14 @@ defmodule Mobilizon.Activities.Activity do
field(:message_params, :map, default: %{})
field(:object_type, ObjectType)
field(:object_id, :string)
field(:object, :map, virtual: true)
field(:inserted_at, :utc_datetime)
belongs_to(:author, Actor)
belongs_to(:group, Actor)
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(activity, attrs) do
activity
|> cast(attrs, @attrs)

View File

@@ -11,7 +11,7 @@ defmodule Mobilizon.Actors.Actor do
alias Mobilizon.Actors.{ActorOpenness, ActorType, ActorVisibility, Follower, Member}
alias Mobilizon.Addresses.Address
alias Mobilizon.Discussions.Comment
alias Mobilizon.Events.{Event, FeedToken}
alias Mobilizon.Events.{Event, FeedToken, Participant}
alias Mobilizon.Medias.File
alias Mobilizon.Reports.{Note, Report}
alias Mobilizon.Users.User
@@ -33,8 +33,8 @@ defmodule Mobilizon.Actors.Actor do
posts_url: String.t(),
events_url: String.t(),
type: ActorType.t(),
name: String.t(),
domain: String.t(),
name: String.t() | nil,
domain: String.t() | nil,
summary: String.t(),
preferred_username: String.t(),
keys: String.t(),
@@ -42,12 +42,13 @@ defmodule Mobilizon.Actors.Actor do
openness: ActorOpenness.t(),
visibility: ActorVisibility.t(),
suspended: boolean,
avatar: File.t(),
banner: File.t(),
avatar: File.t() | nil,
banner: File.t() | nil,
user: User.t(),
followers: [Follower.t()],
followings: [Follower.t()],
organized_events: [Event.t()],
participations: [Participant.t()],
comments: [Comment.t()],
feed_tokens: [FeedToken.t()],
created_reports: [Report.t()],
@@ -184,6 +185,7 @@ defmodule Mobilizon.Actors.Actor do
has_many(:created_reports, Report, foreign_key: :reporter_id)
has_many(:subject_reports, Report, foreign_key: :reported_id)
has_many(:report_notes, Note, foreign_key: :moderator_id)
has_many(:participations, Participant, foreign_key: :actor_id)
has_many(:mentions, Mention)
has_many(:shares, Share, foreign_key: :actor_id)
has_many(:owner_shares, Share, foreign_key: :owner_actor_id)
@@ -243,7 +245,7 @@ defmodule Mobilizon.Actors.Actor do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = actor, attrs) do
actor
|> cast(attrs, @attrs)
@@ -278,7 +280,7 @@ defmodule Mobilizon.Actors.Actor do
@doc """
Changeset for person registration.
"""
@spec registration_changeset(t, map) :: Ecto.Changeset.t()
@spec registration_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def registration_changeset(%__MODULE__{} = actor, attrs) do
actor
|> cast(attrs, @registration_attrs)
@@ -293,19 +295,14 @@ defmodule Mobilizon.Actors.Actor do
"""
@spec remote_actor_creation_changeset(map) :: Ecto.Changeset.t()
def remote_actor_creation_changeset(attrs) do
changeset =
%__MODULE__{}
|> cast(attrs, @remote_actor_creation_attrs)
|> validate_required(@remote_actor_creation_required_attrs)
|> common_changeset(attrs)
|> unique_username_validator()
|> validate_required(:domain)
|> validate_length(:summary, max: 5000)
|> validate_length(:preferred_username, max: 100)
Logger.debug("Remote actor creation: #{inspect(changeset)}")
changeset
%__MODULE__{}
|> cast(attrs, @remote_actor_creation_attrs)
|> validate_required(@remote_actor_creation_required_attrs)
|> common_changeset(attrs)
|> unique_username_validator()
|> validate_required(:domain)
|> validate_length(:summary, max: 5000)
|> validate_length(:preferred_username, max: 100)
end
@spec common_changeset(Ecto.Changeset.t(), map()) :: Ecto.Changeset.t()
@@ -323,7 +320,7 @@ defmodule Mobilizon.Actors.Actor do
@doc """
Changeset for group creation
"""
@spec group_creation_changeset(t, map) :: Ecto.Changeset.t()
@spec group_creation_changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def group_creation_changeset(actor, params) do
actor
|> cast(params, @group_creation_attrs)
@@ -416,12 +413,8 @@ defmodule Mobilizon.Actors.Actor do
@spec build_relay_creation_attrs :: Ecto.Changeset.t()
def build_relay_creation_attrs do
data = %{
name: Config.get([:instance, :name], "Mobilizon"),
summary:
Config.get(
[:instance, :description],
"An internal service actor for this Mobilizon instance"
),
name: Config.instance_name(),
summary: Config.instance_description(),
keys: Crypto.generate_rsa_2048_private_key(),
preferred_username: "relay",
domain: nil,

View File

@@ -75,13 +75,20 @@ defmodule Mobilizon.Actors do
@doc """
Gets an actor with preloaded relations.
"""
@spec get_actor_with_preload(integer | String.t()) :: Actor.t() | nil
@spec get_actor_with_preload(integer | String.t(), boolean) :: Actor.t() | nil
def get_actor_with_preload(id, include_suspended \\ false) do
id
|> actor_with_preload_query(include_suspended)
|> Repo.one()
end
@spec get_actor_with_preload!(integer | String.t(), boolean) :: Actor.t()
def get_actor_with_preload!(id, include_suspended \\ false) do
id
|> actor_with_preload_query(include_suspended)
|> Repo.one!()
end
@doc """
Gets a local actor with preloaded relations.
"""
@@ -148,9 +155,7 @@ defmodule Mobilizon.Actors do
"""
@spec get_actor_by_name(String.t(), ActorType.t() | nil) :: Actor.t() | nil
def get_actor_by_name(name, type \\ nil) do
query = from(a in Actor)
query
Actor
|> filter_by_type(type)
|> filter_by_name(name |> String.trim() |> String.trim_leading("@") |> String.split("@"))
|> Repo.one()
@@ -161,9 +166,7 @@ defmodule Mobilizon.Actors do
"""
@spec get_local_actor_by_name(String.t()) :: Actor.t() | nil
def get_local_actor_by_name(name) do
query = from(a in Actor)
query
Actor
|> filter_by_name([name])
|> Repo.one()
end
@@ -210,7 +213,8 @@ defmodule Mobilizon.Actors do
@doc """
Creates a new person actor.
"""
@spec new_person(map) :: {:ok, Actor.t()} | {:error, Ecto.Changeset.t()}
@spec new_person(map, default_actor :: boolean()) ::
{:ok, Actor.t()} | {:error, Ecto.Changeset.t()}
def new_person(args, default_actor \\ false) do
args = Map.put(args, :keys, Crypto.generate_rsa_2048_private_key())
@@ -323,8 +327,8 @@ defmodule Mobilizon.Actors do
String.t(),
boolean,
boolean,
integer,
integer
integer | nil,
integer | nil
) :: Page.t()
def list_actors(
type \\ :Person,
@@ -367,7 +371,23 @@ defmodule Mobilizon.Actors do
|> Page.build_page(page, limit)
end
@spec filter_actors(Ecto.Query.t(), String.t(), String.t(), String.t(), boolean(), boolean()) ::
@spec list_suspended_actors_to_purge(Keyword.t()) :: list(Actors.t())
def list_suspended_actors_to_purge(options) do
suspension_days = Keyword.get(options, :suspension, 30)
Actor
|> filter_suspended_days(suspension_days)
|> Repo.all()
end
@spec filter_actors(
Ecto.Queryable.t(),
String.t(),
String.t(),
String.t(),
boolean(),
boolean()
) ::
Ecto.Query.t()
defp filter_actors(
query,
@@ -403,14 +423,27 @@ defmodule Mobilizon.Actors do
defp filter_remote(query, true), do: filter_local(query)
defp filter_remote(query, false), do: filter_external(query)
@spec filter_suspended(Ecto.Query.t(), boolean()) :: Ecto.Query.t()
@spec filter_suspended(Ecto.Queryable.t(), boolean()) :: Ecto.Query.t()
defp filter_suspended(query, true), do: where(query, [a], a.suspended)
defp filter_suspended(query, false), do: where(query, [a], not a.suspended)
@spec filter_out_anonymous_actor_id(Ecto.Query.t(), integer() | String.t()) :: Ecto.Query.t()
@spec filter_out_anonymous_actor_id(Ecto.Queryable.t(), integer() | String.t()) ::
Ecto.Query.t()
defp filter_out_anonymous_actor_id(query, anonymous_actor_id),
do: where(query, [a], a.id != ^anonymous_actor_id)
@spec filter_suspended_days(Ecto.Queryable.t(), integer()) :: Ecto.Query.t()
defp filter_suspended_days(query, suspended_days) do
expiration_date = DateTime.add(DateTime.utc_now(), suspended_days * 24 * -3600)
where(
query,
[a],
a.suspended and
a.updated_at > ^expiration_date
)
end
@doc """
Returns the list of local actors by their username.
"""
@@ -486,14 +519,14 @@ defmodule Mobilizon.Actors do
end
end
@spec get_local_group_by_url(String.t()) :: Actor.t()
@spec get_local_group_by_url(String.t()) :: Actor.t() | nil
def get_local_group_by_url(group_url) do
group_query()
|> where([q], q.url == ^group_url and is_nil(q.domain))
|> Repo.one()
end
@spec get_group_by_members_url(String.t()) :: Actor.t()
@spec get_group_by_members_url(String.t()) :: Actor.t() | nil
def get_group_by_members_url(members_url) do
group_query()
|> where([q], q.members_url == ^members_url)
@@ -531,7 +564,7 @@ defmodule Mobilizon.Actors do
{:ok, %{insert_group: %Actor{} = group, add_admin_member: %Member{} = _admin_member}} ->
{:ok, group}
{:error, %Ecto.Changeset{} = err} ->
{:error, _err, %Ecto.Changeset{} = err, _} ->
{:error, err}
end
else
@@ -606,7 +639,7 @@ defmodule Mobilizon.Actors do
@doc """
Gets a single member.
"""
@spec get_member(integer | String.t()) :: {:ok, Member.t()} | nil
@spec get_member(integer | String.t()) :: Member.t() | nil
def get_member(id) do
Member
|> Repo.get(id)
@@ -623,7 +656,7 @@ defmodule Mobilizon.Actors do
@doc """
Gets a single member of an actor (for example a group).
"""
@spec get_member(integer | String.t(), integer | String.t()) ::
@spec get_member(actor_id :: integer | String.t(), parent_id :: integer | String.t()) ::
{:ok, Member.t()} | {:error, :member_not_found}
def get_member(actor_id, parent_id) do
case Repo.get_by(Member, actor_id: actor_id, parent_id: parent_id) do
@@ -1190,31 +1223,35 @@ defmodule Mobilizon.Actors do
@doc """
Makes an actor following another actor.
"""
@spec follow(Actor.t(), Actor.t(), String.t() | nil, boolean | nil) ::
{:ok, Follower.t()} | {:error, atom, String.t()}
@spec follow(
followed :: Actor.t(),
follower :: Actor.t(),
url :: String.t() | nil,
approved :: boolean | nil
) ::
{:ok, Follower.t()}
| {:error, :already_following | :followed_suspended | Ecto.Changeset.t()}
def follow(%Actor{} = followed, %Actor{} = follower, url \\ nil, approved \\ true) do
with {:suspended, false} <- {:suspended, followed.suspended},
# Check if followed has blocked follower
{:already_following, nil} <- {:already_following, is_following(follower, followed)} do
Logger.info(
"Making #{Actor.preferred_username_and_domain(follower)} follow #{Actor.preferred_username_and_domain(followed)} " <>
"(approved: #{approved})"
)
create_follower(%{
"actor_id" => follower.id,
"target_actor_id" => followed.id,
"approved" => approved,
"url" => url
})
if followed.suspended do
{:error, :followed_suspended}
else
{:already_following, %Follower{}} ->
{:error, :already_following,
"Could not follow actor: you are already following #{Actor.preferred_username_and_domain(followed)}"}
case is_following(follower, followed) do
%Follower{} ->
{:error, :already_following}
{:suspended, _} ->
{:error, :suspended,
"Could not follow actor: #{Actor.preferred_username_and_domain(followed)} has been suspended"}
nil ->
Logger.info(
"Making #{Actor.preferred_username_and_domain(follower)} follow #{Actor.preferred_username_and_domain(followed)} " <>
"(approved: #{approved})"
)
create_follower(%{
"actor_id" => follower.id,
"target_actor_id" => followed.id,
"approved" => approved,
"url" => url
})
end
end
end
@@ -1331,7 +1368,7 @@ defmodule Mobilizon.Actors do
)
end
@spec actor_by_username_or_name_query(Ecto.Query.t(), String.t()) :: Ecto.Query.t()
@spec actor_by_username_or_name_query(Ecto.Queryable.t(), String.t()) :: Ecto.Query.t()
defp actor_by_username_or_name_query(query, ""), do: query
defp actor_by_username_or_name_query(query, username) do
@@ -1358,7 +1395,7 @@ defmodule Mobilizon.Actors do
)
end
@spec actors_for_location(Ecto.Query.t(), String.t(), integer()) :: Ecto.Query.t()
@spec actors_for_location(Ecto.Queryable.t(), String.t(), integer()) :: Ecto.Query.t()
defp actors_for_location(query, location, radius)
when is_valid_string(location) and not is_nil(radius) do
with {lon, lat} <- Geohax.decode(location),
@@ -1474,7 +1511,7 @@ defmodule Mobilizon.Actors do
|> select([m, _a], m)
end
@spec filter_member_role(Ecto.Query.t(), list(atom()) | atom()) :: Ecto.Query.t()
@spec filter_member_role(Ecto.Queryable.t(), list(atom()) | atom()) :: Ecto.Query.t()
defp filter_member_role(query, []), do: query
defp filter_member_role(query, roles) when is_list(roles) do
@@ -1597,24 +1634,24 @@ defmodule Mobilizon.Actors do
|> order_by(desc: :updated_at)
end
@spec filter_local(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_local(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_local(query) do
from(a in query, where: is_nil(a.domain))
end
@spec filter_external(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_external(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_external(query) do
from(a in query, where: not is_nil(a.domain))
end
@spec filter_follower_actors_external(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_follower_actors_external(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_follower_actors_external(query) do
query
|> where([_f, a], not is_nil(a.domain))
|> preload([f, a], [:target_actor, :actor])
end
@spec filter_by_type(Ecto.Query.t(), ActorType.t()) :: Ecto.Query.t()
@spec filter_by_type(Ecto.Queryable.t(), ActorType.t() | nil) :: Ecto.Queryable.t()
defp filter_by_type(query, type)
when type in [:Person, :Group, :Application, :Service, :Organisation] do
from(a in query, where: a.type == ^type)
@@ -1622,12 +1659,12 @@ defmodule Mobilizon.Actors do
defp filter_by_type(query, _type), do: query
@spec filter_by_types(Ecto.Query.t(), [ActorType.t()]) :: Ecto.Query.t()
@spec filter_by_types(Ecto.Queryable.t(), [ActorType.t()]) :: Ecto.Query.t()
defp filter_by_types(query, types) do
from(a in query, where: a.type in ^types)
end
@spec filter_by_minimum_visibility(Ecto.Query.t(), atom()) :: Ecto.Query.t()
@spec filter_by_minimum_visibility(Ecto.Queryable.t(), atom()) :: Ecto.Query.t()
defp filter_by_minimum_visibility(query, :private), do: query
defp filter_by_minimum_visibility(query, :restricted) do
@@ -1642,7 +1679,7 @@ defmodule Mobilizon.Actors do
from(a in query, where: a.visibility == ^:public)
end
@spec filter_by_name(query :: Ecto.Query.t(), [String.t()]) :: Ecto.Query.t()
@spec filter_by_name(query :: Ecto.Queryable.t(), [String.t()]) :: Ecto.Query.t()
defp filter_by_name(query, [name]) do
where(query, [a], a.preferred_username == ^name and is_nil(a.domain))
end
@@ -1655,7 +1692,7 @@ defmodule Mobilizon.Actors do
end
end
@spec filter_followed_by_approved_status(Ecto.Query.t(), boolean() | nil) :: Ecto.Query.t()
@spec filter_followed_by_approved_status(Ecto.Queryable.t(), boolean() | nil) :: Ecto.Query.t()
defp filter_followed_by_approved_status(query, nil), do: query
defp filter_followed_by_approved_status(query, approved) do

View File

@@ -32,7 +32,7 @@ defmodule Mobilizon.Actors.Bot do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = bot, attrs) do
bot
|> cast(attrs, @attrs)

View File

@@ -38,7 +38,7 @@ defmodule Mobilizon.Actors.Follower do
end
@doc false
@spec changeset(follower :: t, attrs :: map) :: Ecto.Changeset.t()
@spec changeset(follower :: t | Ecto.Schema.t(), attrs :: map) :: Ecto.Changeset.t()
def changeset(follower, attrs) do
follower
|> cast(attrs, @attrs)

View File

@@ -59,7 +59,7 @@ defmodule Mobilizon.Actors.Member do
def is_administrator(%__MODULE__{}), do: false
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = member, attrs) do
member
|> cast(attrs, @attrs)

View File

@@ -57,7 +57,7 @@ defmodule Mobilizon.Addresses.Address do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = address, attrs) do
address
|> cast(attrs, @attrs)

View File

@@ -118,7 +118,7 @@ defmodule Mobilizon.Addresses do
)
end
@spec order_by_coords(Ecto.Query.t(), map | nil) :: Ecto.Query.t()
@spec order_by_coords(Ecto.Queryable.t(), map | nil) :: Ecto.Query.t()
defp order_by_coords(query, nil), do: query
defp order_by_coords(query, coords) do
@@ -128,7 +128,7 @@ defmodule Mobilizon.Addresses do
)
end
@spec filter_by_contry(Ecto.Query.t(), String.t() | nil) :: Ecto.Query.t()
@spec filter_by_contry(Ecto.Queryable.t(), String.t() | nil) :: Ecto.Query.t()
defp filter_by_contry(query, nil), do: query
defp filter_by_contry(query, country) do

View File

@@ -35,7 +35,7 @@ defmodule Mobilizon.Admin.ActionLog do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = action_log, attrs) do
action_log
|> cast(attrs, @attrs)

View File

@@ -45,7 +45,8 @@ defmodule Mobilizon.Admin do
@doc """
Log an admin action
"""
@spec log_action(Actor.t(), String.t(), String.t()) :: {:ok, ActionLog.t()}
@spec log_action(Actor.t(), String.t(), struct()) ::
{:ok, ActionLog.t()} | {:error, Ecto.Changeset.t() | :user_not_moderator}
def log_action(%Actor{user_id: user_id, id: actor_id}, action, target) do
with %User{role: role} <- Users.get_user!(user_id),
{:role, true} <- {:role, role in [:administrator, :moderator]},
@@ -58,6 +59,9 @@ defmodule Mobilizon.Admin do
"changes" => stringify_struct(target)
}) do
{:ok, create_action_log}
else
{:role, false} ->
{:error, :user_not_moderator}
end
end
@@ -109,12 +113,7 @@ defmodule Mobilizon.Admin do
end
end
def set_admin_setting_value(group, name, value) do
Setting
|> Setting.changeset(%{group: group, name: name, value: value})
|> Repo.insert(on_conflict: :replace_all, conflict_target: [:group, :name])
end
@spec save_settings(String.t(), map()) :: {:ok, any} | {:error, any}
def save_settings(group, args) do
Multi.new()
|> do_save_setting(group, args)
@@ -125,6 +124,7 @@ defmodule Mobilizon.Admin do
Setting |> where([s], s.group == ^group) |> Repo.delete_all()
end
@spec do_save_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
defp do_save_setting(transaction, _group, args) when args == %{}, do: transaction
defp do_save_setting(transaction, group, args) do
@@ -147,6 +147,7 @@ defmodule Mobilizon.Admin do
do_save_setting(transaction, group, rest)
end
@spec convert_to_string(any()) :: String.t()
defp convert_to_string(val) do
case val do
val when is_list(val) -> Jason.encode!(val)

View File

@@ -9,6 +9,12 @@ defmodule Mobilizon.Admin.Setting do
@optional_attrs [:value]
@attrs @required_attrs ++ @optional_attrs
@type t :: %{
group: String.t(),
name: String.t(),
value: String.t()
}
schema "admin_settings" do
field(:group, :string)
field(:name, :string)
@@ -18,6 +24,7 @@ defmodule Mobilizon.Admin.Setting do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(setting, attrs) do
setting
|> cast(attrs, @attrs)

View File

@@ -7,7 +7,24 @@ defmodule Mobilizon.Config do
alias Mobilizon.Service.GitStatus
require Logger
@spec instance_config :: keyword
@type mobilizon_config :: [
name: String.t(),
description: String.t(),
hostname: String.t(),
registrations_open: boolean(),
languages: list(String.t()),
default_language: String.t(),
registration_email_allowlist: list(String.t()),
registration_email_denylist: list(String.t()),
demo: boolean(),
repository: String.t(),
email_from: String.t(),
email_reply_to: String.t(),
federating: boolean(),
remove_orphan_uploads: boolean()
]
@spec instance_config :: mobilizon_config
def instance_config, do: Application.get_env(:mobilizon, :instance)
@spec instance_name :: String.t()
@@ -139,10 +156,10 @@ defmodule Mobilizon.Config do
def instance_user_agent,
do: "#{instance_hostname()} - Mobilizon #{instance_version()}"
@spec instance_federating :: String.t()
@spec instance_federating :: boolean()
def instance_federating, do: instance_config()[:federating]
@spec instance_geocoding_provider :: atom()
@spec instance_geocoding_provider :: module()
def instance_geocoding_provider,
do: get_in(Application.get_env(:mobilizon, Mobilizon.Service.Geospatial), [:service])
@@ -150,63 +167,90 @@ defmodule Mobilizon.Config do
def instance_geocoding_autocomplete,
do: instance_geocoding_provider() !== Mobilizon.Service.Geospatial.Nominatim
@spec maps_config :: [
tiles: [endpoint: String.t(), attribution: String.t()],
rounting: [type: atom]
]
defp maps_config, do: Application.get_env(:mobilizon, :maps)
@spec instance_maps_tiles_endpoint :: String.t()
def instance_maps_tiles_endpoint, do: Application.get_env(:mobilizon, :maps)[:tiles][:endpoint]
def instance_maps_tiles_endpoint, do: maps_config()[:tiles][:endpoint]
@spec instance_maps_tiles_attribution :: String.t()
def instance_maps_tiles_attribution,
do: Application.get_env(:mobilizon, :maps)[:tiles][:attribution]
do: maps_config()[:tiles][:attribution]
@spec instance_maps_routing_type :: atom()
def instance_maps_routing_type,
do: Application.get_env(:mobilizon, :maps)[:routing][:type]
do: maps_config()[:routing][:type]
@typep anonymous_config_type :: [
participation: [
allowed: boolean,
validation: [
email: [enabled: boolean(), confirmation_required: boolean()],
captcha: [enabled: boolean()]
]
],
event_creation: [
allowed: boolean,
validation: [
email: [enabled: boolean(), confirmation_required: boolean()],
captcha: [enabled: boolean()]
]
],
reports: [
allowed: boolean()
]
]
@spec anonymous_config :: anonymous_config_type
defp anonymous_config, do: Application.get_env(:mobilizon, :anonymous)
@spec anonymous_participation? :: boolean
def anonymous_participation?,
do: Application.get_env(:mobilizon, :anonymous)[:participation][:allowed]
do: anonymous_config()[:participation][:allowed]
@spec anonymous_participation_email_required? :: boolean
def anonymous_participation_email_required?,
do: Application.get_env(:mobilizon, :anonymous)[:participation][:validation][:email][:enabled]
do: anonymous_config()[:participation][:validation][:email][:enabled]
@spec anonymous_participation_email_confirmation_required? :: boolean
def anonymous_participation_email_confirmation_required?,
do:
Application.get_env(:mobilizon, :anonymous)[:participation][:validation][:email][
anonymous_config()[:participation][:validation][:email][
:confirmation_required
]
@spec anonymous_participation_email_captcha_required? :: boolean
def anonymous_participation_email_captcha_required?,
do:
Application.get_env(:mobilizon, :anonymous)[:participation][:validation][:captcha][:enabled]
do: anonymous_config()[:participation][:validation][:captcha][:enabled]
@spec anonymous_event_creation? :: boolean
def anonymous_event_creation?,
do: Application.get_env(:mobilizon, :anonymous)[:event_creation][:allowed]
do: anonymous_config()[:event_creation][:allowed]
@spec anonymous_event_creation_email_required? :: boolean
def anonymous_event_creation_email_required?,
do:
Application.get_env(:mobilizon, :anonymous)[:event_creation][:validation][:email][:enabled]
do: anonymous_config()[:event_creation][:validation][:email][:enabled]
@spec anonymous_event_creation_email_confirmation_required? :: boolean
def anonymous_event_creation_email_confirmation_required?,
do:
Application.get_env(:mobilizon, :anonymous)[:event_creation][:validation][:email][
anonymous_config()[:event_creation][:validation][:email][
:confirmation_required
]
@spec anonymous_event_creation_email_captcha_required? :: boolean
def anonymous_event_creation_email_captcha_required?,
do:
Application.get_env(:mobilizon, :anonymous)[:event_creation][:validation][:captcha][
anonymous_config()[:event_creation][:validation][:captcha][
:enabled
]
@spec anonymous_reporting? :: boolean
def anonymous_reporting?,
do: Application.get_env(:mobilizon, :anonymous)[:reports][:allowed]
do: anonymous_config()[:reports][:allowed]
@spec oauth_consumer_strategies() :: list({atom(), String.t()})
def oauth_consumer_strategies do
@@ -265,7 +309,7 @@ defmodule Mobilizon.Config do
@spec admin_settings :: map
def admin_settings, do: get_cached_value(:admin_config)
@spec get(key :: module | atom) :: any
@spec get(keys :: module | atom | [module | atom]) :: any
def get(key), do: get(key, nil)
@spec get(keys :: [module | atom], default :: any) :: any
@@ -281,7 +325,7 @@ defmodule Mobilizon.Config do
@spec get(key :: module | atom, default :: any) :: any
def get(key, default), do: Application.get_env(:mobilizon, key, default)
@spec get!(key :: module | atom) :: any
@spec get!(key :: module | atom) :: any | no_return
def get!(key) do
value = get(key, nil)

View File

@@ -87,7 +87,7 @@ defmodule Mobilizon.Discussions.Comment do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = comment, attrs) do
comment
|> common_changeset(attrs)

View File

@@ -59,7 +59,7 @@ defmodule Mobilizon.Discussions.Discussion do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = discussion, attrs) do
discussion
|> cast(attrs, @attrs)

View File

@@ -71,7 +71,7 @@ defmodule Mobilizon.Discussions do
We only get first comment of thread, and count replies.
Read: https://hexdocs.pm/absinthe/ecto.html#dataloader
"""
@spec query(atom(), map()) :: Ecto.Queryable.t()
@spec query(atom(), map()) :: Ecto.Query.t()
def query(Comment, %{top_level: true}) do
Comment
|> join(:left, [c], r in Comment, on: r.origin_comment_id == c.id)
@@ -158,7 +158,7 @@ defmodule Mobilizon.Discussions do
Gets a comment by its URL, with all associations loaded.
Raises `Ecto.NoResultsError` if the comment does not exist.
"""
@spec get_comment_from_url_with_preload(String.t()) :: Comment.t()
@spec get_comment_from_url_with_preload!(String.t()) :: Comment.t()
def get_comment_from_url_with_preload!(url) do
Comment
|> Repo.get_by!(url: url)
@@ -168,7 +168,7 @@ defmodule Mobilizon.Discussions do
@doc """
Gets a comment by its UUID, with all associations loaded.
"""
@spec get_comment_from_uuid_with_preload(String.t()) :: Comment.t()
@spec get_comment_from_uuid_with_preload(String.t()) :: Comment.t() | nil
def get_comment_from_uuid_with_preload(uuid) do
Comment
|> Repo.get_by(uuid: uuid)
@@ -355,7 +355,7 @@ defmodule Mobilizon.Discussions do
@doc """
Get a discussion by it's slug
"""
@spec get_discussion_by_slug(String.t()) :: Discussion.t()
@spec get_discussion_by_slug(String.t()) :: Discussion.t() | nil
def get_discussion_by_slug(discussion_slug) do
Discussion
|> Repo.get_by(slug: discussion_slug)
@@ -494,11 +494,11 @@ defmodule Mobilizon.Discussions do
)
end
@spec filter_comments_under_events(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_comments_under_events(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_comments_under_events(query) do
where(query, [c], is_nil(c.discussion_id) and not is_nil(c.event_id))
end
@spec preload_for_comment(Ecto.Query.t()) :: Ecto.Query.t()
@spec preload_for_comment(Ecto.Queryable.t()) :: Ecto.Query.t()
defp preload_for_comment(query), do: preload(query, ^@comment_preloads)
end

View File

@@ -35,6 +35,7 @@ defmodule Mobilizon.Events.Event do
alias Mobilizon.Web.Router.Helpers, as: Routes
@type t :: %__MODULE__{
id: String.t(),
url: String.t(),
local: boolean,
begins_on: DateTime.t(),
@@ -53,7 +54,7 @@ defmodule Mobilizon.Events.Event do
category: String.t(),
options: EventOptions.t(),
organizer_actor: Actor.t(),
attributed_to: Actor.t(),
attributed_to: Actor.t() | nil,
physical_address: Address.t(),
picture: Media.t(),
media: [Media.t()],
@@ -130,7 +131,7 @@ defmodule Mobilizon.Events.Event do
end
@doc false
@spec changeset(t, map) :: Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Changeset.t()
def changeset(%__MODULE__{} = event, attrs) do
attrs = Map.update(attrs, :uuid, Ecto.UUID.generate(), & &1)
attrs = Map.update(attrs, :url, Routes.page_url(Endpoint, :event, attrs.uuid), & &1)
@@ -289,4 +290,12 @@ defmodule Mobilizon.Events.Event do
defp put_creator_if_published(%Changeset{} = changeset, _),
do: cast_embed(changeset, :participant_stats)
@doc """
Whether we can show the event. Returns false if the organizer actor or group is suspended
"""
@spec show?(t) :: boolean()
def show?(%__MODULE__{attributed_to: %Actor{suspended: true}}), do: false
def show?(%__MODULE__{organizer_actor: %Actor{suspended: true}}), do: false
def show?(%__MODULE__{}), do: true
end

View File

@@ -36,7 +36,7 @@ defmodule Mobilizon.Events.EventMetadata do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = event_metadata, attrs) do
event_metadata
|> cast(attrs, @attrs)

View File

@@ -64,7 +64,7 @@ defmodule Mobilizon.Events.EventOptions do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = event_options, attrs) do
event_options
|> cast(attrs, @attrs)

View File

@@ -40,7 +40,7 @@ defmodule Mobilizon.Events.EventParticipantStats do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = event_options, attrs) do
event_options
|> cast(attrs, @attrs)

View File

@@ -263,7 +263,10 @@ defmodule Mobilizon.Events do
@doc """
Creates an event.
"""
@spec create_event(map) :: {:ok, Event.t()} | {:error, Changeset.t()}
@spec create_event(map) ::
{:ok, Event.t()}
| {:error, Changeset.t()}
| {:error, :update | :write, Changeset.t(), map()}
def create_event(attrs \\ %{}) do
with {:ok, %{insert: %Event{} = event}} <- do_create_event(attrs),
%Event{} = event <- Repo.preload(event, @event_preloads) do
@@ -278,7 +281,10 @@ defmodule Mobilizon.Events do
end
# We start by inserting the event and then insert a first participant if the event is not a draft
@spec do_create_event(map) :: {:ok, Event.t()} | {:error, Changeset.t()}
@spec do_create_event(map) ::
{:ok, Event.t()}
| {:error, Changeset.t()}
| {:error, :update | :write, Changeset.t(), map()}
defp do_create_event(attrs) do
Multi.new()
|> Multi.insert(:insert, Event.changeset(%Event{}, attrs))
@@ -307,7 +313,10 @@ defmodule Mobilizon.Events do
We start by updating the event and then insert a first participant if the event is not a draft anymore
"""
@spec update_event(Event.t(), map) :: {:ok, Event.t()} | {:error, Changeset.t()}
@spec update_event(Event.t(), map) ::
{:ok, Event.t()}
| {:error, Changeset.t()}
| {:error, :update | :write, Changeset.t(), map()}
def update_event(%Event{draft: old_draft} = old_event, attrs) do
with %Event{} = old_event <- Repo.preload(old_event, @event_preloads),
%Changeset{changes: changes} = changeset <-
@@ -394,7 +403,7 @@ defmodule Mobilizon.Events do
|> Repo.stream()
end
@spec list_public_local_events(integer | nil, integer | nil) :: Page.t()
@spec list_public_local_events(integer | nil, integer | nil) :: Page.t(Event.t())
def list_public_local_events(page \\ nil, limit \\ nil) do
Event
|> filter_public_visibility()
@@ -452,7 +461,7 @@ defmodule Mobilizon.Events do
DateTime.t() | nil,
integer | nil,
integer | nil
) :: Page.t()
) :: Page.t(Event.t())
def list_organized_events_for_group(
%Actor{id: group_id},
visibility \\ :public,
@@ -729,7 +738,7 @@ defmodule Mobilizon.Events do
nil
"""
@spec get_participant(integer) :: Participant.t()
@spec get_participant(integer) :: Participant.t() | nil
def get_participant(participant_id) do
Participant
|> where([p], p.id == ^participant_id)
@@ -1040,21 +1049,18 @@ defmodule Mobilizon.Events do
Deletes a participant.
"""
@spec delete_participant(Participant.t()) ::
{:ok, Participant.t()} | {:error, Changeset.t()}
{:ok, %{participant: Participant.t()}}
| {:error, :participant | :update_event_participation_stats, Changeset.t(), map()}
def delete_participant(%Participant{role: old_role} = participant) do
with {:ok, %{participant: %Participant{} = participant}} <-
Multi.new()
|> Multi.delete(:participant, participant)
|> Multi.run(:update_event_participation_stats, fn _repo,
%{
participant:
%Participant{} = participant
} ->
update_participant_stats(participant, old_role, nil)
end)
|> Repo.transaction() do
{:ok, participant}
end
Multi.new()
|> Multi.delete(:participant, participant)
|> Multi.run(:update_event_participation_stats, fn _repo,
%{
participant: %Participant{} = participant
} ->
update_participant_stats(participant, old_role, nil)
end)
|> Repo.transaction()
end
defp update_participant_stats(
@@ -1330,7 +1336,7 @@ defmodule Mobilizon.Events do
)
end
@spec user_events_query(Ecto.Query.t(), number()) :: Ecto.Query.t()
@spec user_events_query(Ecto.Queryable.t(), number()) :: Ecto.Query.t()
defp user_events_query(query, user_id) do
from(
e in query,
@@ -1373,7 +1379,7 @@ defmodule Mobilizon.Events do
)
end
@spec events_for_begins_on(Ecto.Query.t(), map()) :: Ecto.Query.t()
@spec events_for_begins_on(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_begins_on(query, args) do
begins_on = Map.get(args, :begins_on, DateTime.utc_now())
@@ -1381,7 +1387,7 @@ defmodule Mobilizon.Events do
|> where([q], q.begins_on >= ^begins_on)
end
@spec events_for_ends_on(Ecto.Query.t(), map()) :: Ecto.Query.t()
@spec events_for_ends_on(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_ends_on(query, args) do
ends_on = Map.get(args, :ends_on)
@@ -1396,7 +1402,7 @@ defmodule Mobilizon.Events do
)
end
@spec events_for_tags(Ecto.Query.t(), map()) :: Ecto.Query.t()
@spec events_for_tags(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_tags(query, %{tags: tags}) when is_valid_string(tags) do
query
|> join(:inner, [q], te in "events_tags", on: q.id == te.event_id)
@@ -1406,7 +1412,7 @@ defmodule Mobilizon.Events do
defp events_for_tags(query, _args), do: query
@spec events_for_location(Ecto.Query.t(), map()) :: Ecto.Query.t()
@spec events_for_location(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
defp events_for_location(query, %{radius: radius}) when is_nil(radius),
do: query
@@ -1472,7 +1478,7 @@ defmodule Mobilizon.Events do
from(t in Tag, where: t.title == ^title, limit: 1)
end
@spec tag_filter(Ecto.Query.t(), String.t() | nil) :: Ecto.Query.t()
@spec tag_filter(Ecto.Queryable.t(), String.t() | nil) :: Ecto.Query.t()
defp tag_filter(query, nil), do: query
defp tag_filter(query, ""), do: query
@@ -1511,7 +1517,7 @@ defmodule Mobilizon.Events do
)
end
@spec tag_relation_union_subquery(Ecto.Query.t(), integer) :: Ecto.Query.t()
@spec tag_relation_union_subquery(Ecto.Queryable.t(), integer) :: Ecto.Query.t()
defp tag_relation_union_subquery(subquery, tag_id) do
from(
tr in TagRelation,
@@ -1521,7 +1527,7 @@ defmodule Mobilizon.Events do
)
end
@spec tag_neighbors_query(Ecto.Query.t(), integer, integer) :: Ecto.Query.t()
@spec tag_neighbors_query(Ecto.Queryable.t(), integer, integer) :: Ecto.Query.t()
defp tag_neighbors_query(subquery, relation_minimum, limit) do
from(
t in Tag,
@@ -1673,38 +1679,34 @@ defmodule Mobilizon.Events do
from(tk in FeedToken, where: tk.actor_id == ^actor_id, preload: [:actor, :user])
end
@spec filter_public_visibility(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_public_visibility(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_public_visibility(query) do
from(e in query, where: e.visibility == ^:public)
end
@spec filter_unlisted_and_public_visibility(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_unlisted_and_public_visibility(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_unlisted_and_public_visibility(query) do
from(q in query, where: q.visibility in ^@public_visibility)
end
@spec filter_not_event_uuid(Ecto.Query.t(), String.t() | nil) :: Ecto.Query.t()
@spec filter_not_event_uuid(Ecto.Queryable.t(), String.t() | nil) :: Ecto.Query.t()
defp filter_not_event_uuid(query, nil), do: query
defp filter_not_event_uuid(query, not_event_uuid) do
from(e in query, where: e.uuid != ^not_event_uuid)
end
@spec filter_draft(Ecto.Query.t(), boolean) :: Ecto.Query.t()
@spec filter_draft(Ecto.Queryable.t(), boolean) :: Ecto.Query.t()
defp filter_draft(query, is_draft \\ false) do
from(e in query, where: e.draft == ^is_draft)
end
@spec filter_cancelled_events(Ecto.Query.t(), boolean()) :: Ecto.Query.t()
defp filter_cancelled_events(query, hide_cancelled \\ true)
defp filter_cancelled_events(query, false), do: query
defp filter_cancelled_events(query, true) do
@spec filter_cancelled_events(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_cancelled_events(query) do
from(e in query, where: e.status != ^:cancelled)
end
@spec filter_future_events(Ecto.Query.t(), boolean) :: Ecto.Query.t()
@spec filter_future_events(Ecto.Queryable.t(), boolean) :: Ecto.Query.t()
defp filter_future_events(query, true) do
from(q in query,
where: q.begins_on > ^DateTime.utc_now()
@@ -1713,12 +1715,12 @@ defmodule Mobilizon.Events do
defp filter_future_events(query, false), do: query
@spec filter_local(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_local(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_local(query) do
where(query, [q], q.local == true)
end
@spec filter_local_or_from_followed_instances_events(Ecto.Query.t()) ::
@spec filter_local_or_from_followed_instances_events(Ecto.Queryable.t()) ::
Ecto.Query.t()
defp filter_local_or_from_followed_instances_events(query) do
follower_actor_id = Mobilizon.Config.relay_actor_id()
@@ -1732,22 +1734,22 @@ defmodule Mobilizon.Events do
)
end
@spec filter_approved_role(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_approved_role(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_approved_role(query) do
filter_role(query, [:not_approved, :rejected])
end
@spec filter_participant_role(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_participant_role(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_participant_role(query) do
filter_role(query, :participant)
end
@spec filter_rejected_role(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_rejected_role(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_rejected_role(query) do
filter_role(query, :rejected)
end
@spec filter_role(Ecto.Query.t(), list(atom())) :: Ecto.Query.t()
@spec filter_role(Ecto.Queryable.t(), list(atom()) | atom()) :: Ecto.Query.t()
def filter_role(query, []), do: query
def filter_role(query, roles) when is_list(roles) do
@@ -1829,6 +1831,6 @@ defmodule Mobilizon.Events do
defp participation_order_begins_on_desc(query),
do: order_by(query, [_p, e, _a], desc: e.begins_on)
@spec preload_for_event(Ecto.Query.t()) :: Ecto.Query.t()
@spec preload_for_event(Ecto.Queryable.t()) :: Ecto.Query.t()
defp preload_for_event(query), do: preload(query, ^@event_preloads)
end

View File

@@ -12,7 +12,7 @@ defmodule Mobilizon.Events.FeedToken do
@type t :: %__MODULE__{
token: Ecto.UUID.t(),
actor: Actor.t(),
actor: Actor.t() | nil,
user: User.t()
}
@@ -31,7 +31,7 @@ defmodule Mobilizon.Events.FeedToken do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = feed_token, attrs) do
feed_token
|> cast(attrs, @attrs)

View File

@@ -57,7 +57,7 @@ defmodule Mobilizon.Events.Participant do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = participant, attrs) do
participant
|> cast(attrs, @attrs)

View File

@@ -27,7 +27,7 @@ defmodule Mobilizon.Events.Participant.Metadata do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(schema, params) do
schema
|> cast(params, @attrs)

View File

@@ -56,7 +56,7 @@ defmodule Mobilizon.Events.Session do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = session, attrs) do
session
|> cast(attrs, @attrs)

View File

@@ -29,7 +29,7 @@ defmodule Mobilizon.Events.Tag do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = tag, attrs) do
tag
|> cast(attrs, @attrs)

View File

@@ -28,7 +28,7 @@ defmodule Mobilizon.Events.TagRelation do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = tag, attrs) do
# Return if tag_id or link_id are not set because it will fail later otherwise
with %Ecto.Changeset{errors: [], changes: changes} = changeset <-

View File

@@ -33,7 +33,7 @@ defmodule Mobilizon.Events.Track do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = track, attrs) do
track
|> cast(attrs, @attrs)

View File

@@ -29,7 +29,7 @@ defmodule Mobilizon.Medias.File do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = file, attrs) do
file
|> cast(attrs, @attrs)

View File

@@ -42,7 +42,7 @@ defmodule Mobilizon.Medias.Media do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = media, attrs) do
media
|> cast(attrs, [:actor_id])

View File

@@ -130,7 +130,7 @@ defmodule Mobilizon.Medias do
|> Multi.run(:remove, fn _repo, %{media: %Media{file: %File{url: url}} = media} ->
case Upload.remove(url) do
{:error, err} ->
if err =~ "doesn't exist" and Keyword.get(opts, :ignore_file_not_found, false) do
if err == :enofile and Keyword.get(opts, :ignore_file_not_found, false) do
Logger.info("Deleting media and ignoring absent file.")
{:ok, media}
else

View File

@@ -31,6 +31,7 @@ defmodule Mobilizon.Mention do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(event, attrs) do
event
|> cast(attrs, @attrs)

View File

@@ -82,6 +82,7 @@ defmodule Mobilizon.Posts.Post do
@attrs @required_attrs ++ @optional_attrs
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = post, attrs) do
post
|> cast(attrs, @attrs)
@@ -153,17 +154,20 @@ defmodule Mobilizon.Posts.Post do
# In case the provided picture is an existing one
@spec put_picture(Changeset.t(), map) :: Changeset.t()
defp put_picture(%Changeset{} = changeset, %{picture: %{picture_id: id} = _picture}) do
case Medias.get_media!(id) do
%Media{} = picture ->
put_assoc(changeset, :picture, picture)
_ ->
changeset
end
%Media{} = picture = Medias.get_media!(id)
put_assoc(changeset, :picture, picture)
end
# In case it's a new picture
defp put_picture(%Changeset{} = changeset, _attrs) do
cast_assoc(changeset, :picture)
end
@doc """
Whether we can show the post. Returns false if the organizer actor or group is suspended
"""
@spec show?(t) :: boolean()
def show?(%__MODULE__{attributed_to: %Actor{suspended: true}}), do: false
def show?(%__MODULE__{author: %Actor{suspended: true}}), do: false
def show?(%__MODULE__{}), do: true
end

View File

@@ -21,6 +21,7 @@ defmodule Mobilizon.Posts do
:private
])
@spec list_public_local_posts(integer | nil, integer | nil) :: Page.t(Post.t())
def list_public_local_posts(page \\ nil, limit \\ nil) do
Post
|> filter_public()
@@ -144,12 +145,12 @@ defmodule Mobilizon.Posts do
)
end
@spec filter_public(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_public(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_public(query) do
where(query, [p], p.visibility == ^:public and not p.draft)
end
@spec filter_local(Ecto.Query.t()) :: Ecto.Query.t()
@spec filter_local(Ecto.Queryable.t()) :: Ecto.Query.t()
defp filter_local(query) do
where(query, [q], q.local == true)
end
@@ -161,7 +162,7 @@ defmodule Mobilizon.Posts do
|> preload_post_associations()
end
@spec preload_post_associations(Ecto.Query.t(), list()) :: Ecto.Query.t()
@spec preload_post_associations(Ecto.Queryable.t(), list()) :: Ecto.Query.t()
defp preload_post_associations(query, associations \\ @post_preloads) do
preload(query, ^associations)
end

View File

@@ -32,7 +32,7 @@ defmodule Mobilizon.Reports.Note do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = note, attrs) do
note
|> cast(attrs, @attrs)

View File

@@ -56,7 +56,7 @@ defmodule Mobilizon.Reports.Report do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = report, attrs) do
report
|> cast(attrs, @attrs)

View File

@@ -79,6 +79,7 @@ defmodule Mobilizon.Resources.Resource do
]
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(resource, attrs) do
resource
|> cast(attrs, @attrs)

View File

@@ -29,6 +29,7 @@ defmodule Mobilizon.Share do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map()) :: Ecto.Changeset.t()
def changeset(share, attrs) do
share
|> cast(attrs, @attrs)

View File

@@ -12,9 +12,9 @@ defmodule Mobilizon.Storage.Page do
:elements
]
@type t :: %__MODULE__{
@type t(structure) :: %__MODULE__{
total: integer,
elements: struct
elements: list(structure)
}
@doc """
@@ -23,7 +23,7 @@ defmodule Mobilizon.Storage.Page do
`field` is use to define the field that will be used for the count aggregate, which should be the same as the field used for order_by
See https://stackoverflow.com/q/12693089/10204399
"""
@spec build_page(Ecto.Query.t(), integer | nil, integer | nil, atom()) :: t
@spec build_page(Ecto.Queryable.t(), integer | nil, integer | nil, atom()) :: t(any)
def build_page(query, page, limit, field \\ :id) do
[total, elements] =
[
@@ -39,7 +39,7 @@ defmodule Mobilizon.Storage.Page do
@doc """
Add limit and offset to the query.
"""
@spec paginate(Ecto.Query.t() | struct, integer | nil, integer | nil) :: Ecto.Query.t()
@spec paginate(Ecto.Queryable.t() | struct, integer | nil, integer | nil) :: Ecto.Query.t()
def paginate(query, page \\ 1, size \\ 10)
def paginate(query, page, _size) when is_nil(page), do: paginate(query)

View File

@@ -40,6 +40,7 @@ defmodule Mobilizon.Todos.Todo do
@attrs @required_attrs ++ @optional_attrs
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(todo, attrs) do
todo
|> cast(attrs, @attrs)

View File

@@ -34,6 +34,7 @@ defmodule Mobilizon.Todos.TodoList do
@attrs @required_attrs ++ @optional_attrs
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(todo_list, attrs) do
todo_list
|> cast(attrs, @attrs)

View File

@@ -26,20 +26,21 @@ defmodule Mobilizon.Tombstone do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map()) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = tombstone, attrs) do
tombstone
|> cast(attrs, @attrs)
|> validate_required(@required_attrs)
end
@spec create_tombstone(map) :: {:ok, Ecto.Schema.t()} | {:error, Ecto.Changeset.t()}
@spec create_tombstone(map) :: {:ok, t()} | {:error, Ecto.Changeset.t()}
def create_tombstone(attrs) do
%__MODULE__{}
|> changeset(attrs)
|> Repo.insert(on_conflict: :replace_all, conflict_target: :uri)
end
@spec find_tombstone(String.t()) :: Ecto.Schema.t() | nil
@spec find_tombstone(String.t()) :: t() | nil
def find_tombstone(uri) do
__MODULE__
|> Ecto.Query.where([t], t.uri == ^uri)
@@ -54,6 +55,7 @@ defmodule Mobilizon.Tombstone do
|> Repo.delete_all()
end
@spec delete_uri_tombstone(String.t()) :: {integer(), nil}
def delete_uri_tombstone(uri) do
__MODULE__
|> Ecto.Query.where(uri: ^uri)

View File

@@ -25,6 +25,7 @@ defmodule Mobilizon.Users.ActivitySetting do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(activity_setting, attrs) do
activity_setting
|> cast(attrs, @attrs)

View File

@@ -25,6 +25,7 @@ defmodule Mobilizon.Users.PushSubscription do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(push_subscription, attrs) do
push_subscription
|> cast(attrs, [:user_id, :endpoint, :auth, :p256dh])

View File

@@ -19,6 +19,12 @@ defmodule Mobilizon.Users.Setting do
user: User.t()
}
@type location :: %{
name: String.t(),
range: integer,
geohash: String.t()
}
@required_attrs [:user_id]
@optional_attrs [
@@ -66,6 +72,7 @@ defmodule Mobilizon.Users.Setting do
end
@doc false
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(setting, attrs) do
setting
|> cast(attrs, @attrs)
@@ -73,6 +80,7 @@ defmodule Mobilizon.Users.Setting do
|> validate_required(@required_attrs)
end
@spec location_changeset(location, map) :: Ecto.Changeset.t()
def location_changeset(schema, params) do
schema
|> cast(params, @location_attrs)

View File

@@ -19,7 +19,7 @@ defmodule Mobilizon.Users.User do
password_hash: String.t(),
password: String.t(),
role: UserRole.t(),
confirmed_at: DateTime.t(),
confirmed_at: DateTime.t() | nil,
confirmation_sent_at: DateTime.t(),
confirmation_token: String.t(),
reset_password_sent_at: DateTime.t(),
@@ -32,7 +32,10 @@ defmodule Mobilizon.Users.User do
last_sign_in_at: DateTime.t(),
last_sign_in_ip: String.t(),
current_sign_in_ip: String.t(),
current_sign_in_at: DateTime.t()
current_sign_in_at: DateTime.t(),
activity_settings: [ActivitySetting.t()],
settings: Setting.t(),
unconfirmed_email: String.t() | nil
}
@required_attrs [:email]
@@ -96,7 +99,7 @@ defmodule Mobilizon.Users.User do
end
@doc false
@spec changeset(t, map) :: Ecto.Changeset.t()
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
def changeset(%__MODULE__{} = user, attrs) do
changeset =
user
@@ -129,7 +132,6 @@ defmodule Mobilizon.Users.User do
def registration_changeset(%__MODULE__{} = user, attrs) do
user
|> changeset(attrs)
|> cast_assoc(:default_actor)
|> validate_required(@registration_required_attrs)
|> hash_password()
|> save_confirmation_token()
@@ -148,7 +150,6 @@ defmodule Mobilizon.Users.User do
def auth_provider_changeset(%__MODULE__{} = user, attrs) do
user
|> changeset(attrs)
|> cast_assoc(:default_actor)
|> put_change(:confirmed_at, DateTime.utc_now() |> DateTime.truncate(:second))
|> validate_required(@auth_provider_required_attrs)
end

View File

@@ -338,10 +338,10 @@ defmodule Mobilizon.Users do
"""
def get_setting!(user_id), do: Repo.get!(Setting, user_id)
@spec get_setting(User.t()) :: Setting.t()
@spec get_setting(User.t()) :: Setting.t() | nil
def get_setting(%User{id: user_id}), do: get_setting(user_id)
@spec get_setting(String.t() | integer()) :: Setting.t()
@spec get_setting(String.t() | integer()) :: Setting.t() | nil
def get_setting(user_id), do: Repo.get(Setting, user_id)
@doc """
@@ -356,6 +356,7 @@ defmodule Mobilizon.Users do
{:error, %Ecto.Changeset{}}
"""
@spec create_setting(map()) :: {:ok, Setting.t()} | {:error, Ecto.Changeset.t()}
def create_setting(attrs \\ %{}) do
%Setting{}
|> Setting.changeset(attrs)
@@ -445,6 +446,8 @@ defmodule Mobilizon.Users do
{:error, %Ecto.Changeset{}}
"""
@spec create_push_subscription(map()) ::
{:ok, PushSubscription.t()} | {:error, Ecto.Changeset.t()}
def create_push_subscription(attrs \\ %{}) do
%PushSubscription{}
|> PushSubscription.changeset(attrs)