Spec improvements
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
cc3106e425
commit
41f086e2c9
|
@ -25,11 +25,13 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
|
|
||||||
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
# Some implementations send the actor URI as the actor field, others send the entire actor object,
|
||||||
# so figure out what the actor's URI is based on what we have.
|
# so figure out what the actor's URI is based on what we have.
|
||||||
|
@spec get_url(map() | String.t() | list(String.t()) | any()) :: String.t() | nil
|
||||||
def get_url(%{"id" => id}), do: id
|
def get_url(%{"id" => id}), do: id
|
||||||
def get_url(id) when is_binary(id), do: id
|
def get_url(id) when is_binary(id), do: id
|
||||||
def get_url(ids) when is_list(ids), do: get_url(hd(ids))
|
def get_url(ids) when is_list(ids), do: get_url(hd(ids))
|
||||||
def get_url(_), do: nil
|
def get_url(_), do: nil
|
||||||
|
|
||||||
|
@spec make_json_ld_header :: map()
|
||||||
def make_json_ld_header do
|
def make_json_ld_header do
|
||||||
%{
|
%{
|
||||||
"@context" => [
|
"@context" => [
|
||||||
|
@ -99,6 +101,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec make_date :: String.t()
|
||||||
def make_date do
|
def make_date do
|
||||||
DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
DateTime.utc_now() |> DateTime.truncate(:second) |> DateTime.to_iso8601()
|
||||||
end
|
end
|
||||||
|
@ -130,6 +133,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
Applies to activities sent by group members from outside this instance to a group of this instance,
|
Applies to activities sent by group members from outside this instance to a group of this instance,
|
||||||
we then need to relay (`Announce`) the object to other members on other instances.
|
we then need to relay (`Announce`) the object to other members on other instances.
|
||||||
"""
|
"""
|
||||||
|
@spec maybe_relay_if_group_activity(Activity.t(), Actor.t() | nil | list(Actor.t())) :: :ok
|
||||||
def maybe_relay_if_group_activity(activity, attributed_to \\ nil)
|
def maybe_relay_if_group_activity(activity, attributed_to \\ nil)
|
||||||
|
|
||||||
def maybe_relay_if_group_activity(
|
def maybe_relay_if_group_activity(
|
||||||
|
@ -153,6 +157,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec do_maybe_relay_if_group_activity(map(), list(String.t()) | String.t()) :: :ok
|
||||||
defp do_maybe_relay_if_group_activity(object, attributed_to) when is_list(attributed_to),
|
defp do_maybe_relay_if_group_activity(object, attributed_to) when is_list(attributed_to),
|
||||||
do: do_maybe_relay_if_group_activity(object, hd(attributed_to))
|
do: do_maybe_relay_if_group_activity(object, hd(attributed_to))
|
||||||
|
|
||||||
|
@ -199,6 +204,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
Adds an id and a published data if they aren't there,
|
Adds an id and a published data if they aren't there,
|
||||||
also adds it to an included object
|
also adds it to an included object
|
||||||
"""
|
"""
|
||||||
|
@spec lazy_put_activity_defaults(map()) :: map()
|
||||||
def lazy_put_activity_defaults(%{"object" => _object} = map) do
|
def lazy_put_activity_defaults(%{"object" => _object} = map) do
|
||||||
if is_map(map["object"]) do
|
if is_map(map["object"]) do
|
||||||
object = lazy_put_object_defaults(map["object"])
|
object = lazy_put_object_defaults(map["object"])
|
||||||
|
@ -215,6 +221,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
Map.put_new_lazy(map, "published", &make_date/0)
|
Map.put_new_lazy(map, "published", &make_date/0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec get_actor(map()) :: String.t() | nil
|
||||||
def get_actor(%{"actor" => actor}) when is_binary(actor) do
|
def get_actor(%{"actor" => actor}) when is_binary(actor) do
|
||||||
actor
|
actor
|
||||||
end
|
end
|
||||||
|
@ -242,6 +249,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
|
|
||||||
Takes the actor or attributedTo attributes (considers only the first elem if they're an array)
|
Takes the actor or attributedTo attributes (considers only the first elem if they're an array)
|
||||||
"""
|
"""
|
||||||
|
@spec origin_check?(String.t(), map()) :: boolean()
|
||||||
def origin_check?(id, %{"type" => "Tombstone", "id" => tombstone_id}), do: id == tombstone_id
|
def origin_check?(id, %{"type" => "Tombstone", "id" => tombstone_id}), do: id == tombstone_id
|
||||||
|
|
||||||
def origin_check?(id, %{"actor" => actor, "attributedTo" => _attributed_to} = params)
|
def origin_check?(id, %{"actor" => actor, "attributedTo" => _attributed_to} = params)
|
||||||
|
@ -283,6 +291,7 @@ defmodule Mobilizon.Federation.ActivityPub.Utils do
|
||||||
compare_uris?(uri_1, uri_2)
|
compare_uris?(uri_1, uri_2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec compare_uris?(URI.t(), URI.t()) :: boolean()
|
||||||
defp compare_uris?(%URI{} = id_uri, %URI{} = other_uri),
|
defp compare_uris?(%URI{} = id_uri, %URI{} = other_uri),
|
||||||
do: id_uri.host == other_uri.host && id_uri.port == other_uri.port
|
do: id_uri.host == other_uri.host && id_uri.port == other_uri.port
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,19 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
||||||
|
|
||||||
|
@type t :: %{code: atom(), message: String.t(), status_code: pos_integer(), field: atom()}
|
||||||
|
|
||||||
defstruct [:code, :message, :status_code, :field]
|
defstruct [:code, :message, :status_code, :field]
|
||||||
|
|
||||||
|
@type error :: {:error, any()} | {:error, any(), any(), any()} | atom()
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Normalize an error to return `t`.
|
||||||
|
"""
|
||||||
# Error Tuples
|
# Error Tuples
|
||||||
# ------------
|
# ------------
|
||||||
# Regular errors
|
# Regular errors
|
||||||
|
@spec normalize(error | list(error) | String.t() | any()) :: t()
|
||||||
def normalize({:error, reason}) do
|
def normalize({:error, reason}) do
|
||||||
handle(reason)
|
handle(reason)
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,18 +8,19 @@ defmodule Mobilizon.Actors.Member do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
alias Mobilizon.Actors.{Actor, MemberRole}
|
alias Mobilizon.Actors.{Actor, MemberRole}
|
||||||
|
alias Mobilizon.Actors.Member.Metadata
|
||||||
alias Mobilizon.Web.Endpoint
|
alias Mobilizon.Web.Endpoint
|
||||||
|
|
||||||
@type t :: %__MODULE__{
|
@type t :: %__MODULE__{
|
||||||
role: MemberRole.t(),
|
role: MemberRole.t(),
|
||||||
parent: Actor.t(),
|
parent: Actor.t(),
|
||||||
actor: Actor.t()
|
actor: Actor.t(),
|
||||||
|
metadata: Metadata.t()
|
||||||
}
|
}
|
||||||
|
|
||||||
@required_attrs [:parent_id, :actor_id, :url]
|
@required_attrs [:parent_id, :actor_id, :url]
|
||||||
@optional_attrs [:role, :invited_by_id]
|
@optional_attrs [:role, :invited_by_id]
|
||||||
@attrs @required_attrs ++ @optional_attrs
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
@metadata_attrs []
|
|
||||||
|
|
||||||
@primary_key {:id, :binary_id, autogenerate: true}
|
@primary_key {:id, :binary_id, autogenerate: true}
|
||||||
schema "members" do
|
schema "members" do
|
||||||
|
@ -27,9 +28,7 @@ defmodule Mobilizon.Actors.Member do
|
||||||
field(:url, :string)
|
field(:url, :string)
|
||||||
field(:member_since, :utc_datetime)
|
field(:member_since, :utc_datetime)
|
||||||
|
|
||||||
embeds_one :metadata, Metadata, on_replace: :delete do
|
embeds_one(:metadata, Metadata, on_replace: :delete)
|
||||||
# TODO : Use this space to put notes when someone is invited / requested to join
|
|
||||||
end
|
|
||||||
|
|
||||||
belongs_to(:invited_by, Actor)
|
belongs_to(:invited_by, Actor)
|
||||||
belongs_to(:parent, Actor)
|
belongs_to(:parent, Actor)
|
||||||
|
@ -63,7 +62,7 @@ defmodule Mobilizon.Actors.Member do
|
||||||
def changeset(%__MODULE__{} = member, attrs) do
|
def changeset(%__MODULE__{} = member, attrs) do
|
||||||
member
|
member
|
||||||
|> cast(attrs, @attrs)
|
|> cast(attrs, @attrs)
|
||||||
|> cast_embed(:metadata, with: &metadata_changeset/2)
|
|> cast_embed(:metadata)
|
||||||
|> ensure_url()
|
|> ensure_url()
|
||||||
|> update_member_since()
|
|> update_member_since()
|
||||||
|> validate_required(@required_attrs)
|
|> validate_required(@required_attrs)
|
||||||
|
@ -72,11 +71,6 @@ defmodule Mobilizon.Actors.Member do
|
||||||
|> unique_constraint(:url, name: :members_url_index)
|
|> unique_constraint(:url, name: :members_url_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp metadata_changeset(schema, params) do
|
|
||||||
schema
|
|
||||||
|> cast(params, @metadata_attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
# If there's a blank URL that's because we're doing the first insert
|
# If there's a blank URL that's because we're doing the first insert
|
||||||
@spec ensure_url(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
@spec ensure_url(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
||||||
defp ensure_url(%Ecto.Changeset{data: %__MODULE__{url: nil}} = changeset) do
|
defp ensure_url(%Ecto.Changeset{data: %__MODULE__{url: nil}} = changeset) do
|
||||||
|
|
27
lib/mobilizon/actors/member/metadata.ex
Normal file
27
lib/mobilizon/actors/member/metadata.ex
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
defmodule Mobilizon.Actors.Member.Metadata do
|
||||||
|
@moduledoc """
|
||||||
|
Represents metadata on a membership
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{}
|
||||||
|
|
||||||
|
@required_attrs []
|
||||||
|
|
||||||
|
@optional_attrs []
|
||||||
|
|
||||||
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
|
|
||||||
|
embedded_schema do
|
||||||
|
# TODO : Use this space to put notes when someone is invited / requested to join
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
|
def changeset(schema, params) do
|
||||||
|
schema
|
||||||
|
|> cast(params, @attrs)
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Medias.Media do
|
||||||
|
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
|
|
||||||
import Ecto.Changeset, only: [cast: 3, cast_embed: 2, cast_embed: 3]
|
import Ecto.Changeset, only: [cast: 3, cast_embed: 2]
|
||||||
|
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
alias Mobilizon.Discussions.Comment
|
alias Mobilizon.Discussions.Comment
|
||||||
|
@ -20,16 +20,12 @@ defmodule Mobilizon.Medias.Media do
|
||||||
actor: Actor.t()
|
actor: Actor.t()
|
||||||
}
|
}
|
||||||
|
|
||||||
@metadata_attrs [:height, :width, :blurhash]
|
@attrs [:actor_id]
|
||||||
|
|
||||||
schema "medias" do
|
schema "medias" do
|
||||||
embeds_one(:file, File, on_replace: :update)
|
embeds_one(:file, File, on_replace: :update)
|
||||||
|
|
||||||
embeds_one :metadata, Metadata, on_replace: :update do
|
embeds_one(:metadata, Metadata, on_replace: :update)
|
||||||
field(:height, :integer)
|
|
||||||
field(:width, :integer)
|
|
||||||
field(:blurhash, :string)
|
|
||||||
end
|
|
||||||
|
|
||||||
belongs_to(:actor, Actor)
|
belongs_to(:actor, Actor)
|
||||||
has_many(:event_picture, Event, foreign_key: :picture_id)
|
has_many(:event_picture, Event, foreign_key: :picture_id)
|
||||||
|
@ -45,15 +41,8 @@ defmodule Mobilizon.Medias.Media do
|
||||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
def changeset(%__MODULE__{} = media, attrs) do
|
def changeset(%__MODULE__{} = media, attrs) do
|
||||||
media
|
media
|
||||||
|> cast(attrs, [:actor_id])
|
|> cast(attrs, @attrs)
|
||||||
|> cast_embed(:file)
|
|> cast_embed(:file)
|
||||||
|> cast_embed(:metadata, with: &metadata_changeset/2)
|
|> cast_embed(:metadata)
|
||||||
end
|
|
||||||
|
|
||||||
@doc false
|
|
||||||
@spec metadata_changeset(Metadata.t(), map) :: Ecto.Changeset.t()
|
|
||||||
def metadata_changeset(metadata, attrs) do
|
|
||||||
metadata
|
|
||||||
|> cast(attrs, @metadata_attrs)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
38
lib/mobilizon/medias/media/metadata.ex
Normal file
38
lib/mobilizon/medias/media/metadata.ex
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
defmodule Mobilizon.Medias.Media.Metadata do
|
||||||
|
@moduledoc """
|
||||||
|
Represents a media metadata
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
width: non_neg_integer(),
|
||||||
|
height: non_neg_integer(),
|
||||||
|
blurhash: String.t()
|
||||||
|
}
|
||||||
|
|
||||||
|
@required_attrs []
|
||||||
|
|
||||||
|
@optional_attrs [
|
||||||
|
:width,
|
||||||
|
:height,
|
||||||
|
:blurhash
|
||||||
|
]
|
||||||
|
|
||||||
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
embedded_schema do
|
||||||
|
field(:height, :integer)
|
||||||
|
field(:width, :integer)
|
||||||
|
field(:blurhash, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
|
def changeset(schema, params) do
|
||||||
|
schema
|
||||||
|
|> cast(params, @attrs)
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,6 +10,7 @@ defmodule Mobilizon.Resources.Resource do
|
||||||
import EctoEnum
|
import EctoEnum
|
||||||
defenum(TypeEnum, folder: 0, link: 1, picture: 20, pad: 30, calc: 40, visio: 50)
|
defenum(TypeEnum, folder: 0, link: 1, picture: 20, pad: 30, calc: 40, visio: 50)
|
||||||
alias Mobilizon.Actors.Actor
|
alias Mobilizon.Actors.Actor
|
||||||
|
alias Mobilizon.Resources.Resource.Metadata
|
||||||
|
|
||||||
@type t :: %__MODULE__{
|
@type t :: %__MODULE__{
|
||||||
title: String.t(),
|
title: String.t(),
|
||||||
|
@ -17,7 +18,7 @@ defmodule Mobilizon.Resources.Resource do
|
||||||
url: String.t(),
|
url: String.t(),
|
||||||
resource_url: String.t(),
|
resource_url: String.t(),
|
||||||
type: atom(),
|
type: atom(),
|
||||||
metadata: Mobilizon.Resources.Resource.Metadata.t(),
|
metadata: Metadata.t(),
|
||||||
children: list(__MODULE__),
|
children: list(__MODULE__),
|
||||||
parent: __MODULE__,
|
parent: __MODULE__,
|
||||||
actor: Actor.t(),
|
actor: Actor.t(),
|
||||||
|
@ -37,20 +38,7 @@ defmodule Mobilizon.Resources.Resource do
|
||||||
field(:local, :boolean, default: true)
|
field(:local, :boolean, default: true)
|
||||||
field(:published_at, :utc_datetime)
|
field(:published_at, :utc_datetime)
|
||||||
|
|
||||||
embeds_one :metadata, Metadata, on_replace: :delete do
|
embeds_one(:metadata, Metadata, on_replace: :delete)
|
||||||
field(:type, :string)
|
|
||||||
field(:title, :string)
|
|
||||||
field(:description, :string)
|
|
||||||
field(:image_remote_url, :string)
|
|
||||||
field(:width, :integer)
|
|
||||||
field(:height, :integer)
|
|
||||||
field(:author_name, :string)
|
|
||||||
field(:author_url, :string)
|
|
||||||
field(:provider_name, :string)
|
|
||||||
field(:provider_url, :string)
|
|
||||||
field(:html, :string)
|
|
||||||
field(:favicon_url, :string)
|
|
||||||
end
|
|
||||||
|
|
||||||
has_many(:children, __MODULE__, foreign_key: :parent_id)
|
has_many(:children, __MODULE__, foreign_key: :parent_id)
|
||||||
belongs_to(:parent, __MODULE__, type: :binary_id)
|
belongs_to(:parent, __MODULE__, type: :binary_id)
|
||||||
|
@ -63,27 +51,13 @@ defmodule Mobilizon.Resources.Resource do
|
||||||
@required_attrs [:title, :url, :actor_id, :creator_id, :type, :path, :published_at]
|
@required_attrs [:title, :url, :actor_id, :creator_id, :type, :path, :published_at]
|
||||||
@optional_attrs [:summary, :parent_id, :resource_url, :local]
|
@optional_attrs [:summary, :parent_id, :resource_url, :local]
|
||||||
@attrs @required_attrs ++ @optional_attrs
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
@metadata_attrs [
|
|
||||||
:type,
|
|
||||||
:title,
|
|
||||||
:description,
|
|
||||||
:image_remote_url,
|
|
||||||
:width,
|
|
||||||
:height,
|
|
||||||
:author_name,
|
|
||||||
:author_url,
|
|
||||||
:provider_name,
|
|
||||||
:provider_url,
|
|
||||||
:html,
|
|
||||||
:favicon_url
|
|
||||||
]
|
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
def changeset(resource, attrs) do
|
def changeset(resource, attrs) do
|
||||||
resource
|
resource
|
||||||
|> cast(attrs, @attrs)
|
|> cast(attrs, @attrs)
|
||||||
|> cast_embed(:metadata, with: &metadata_changeset/2)
|
|> cast_embed(:metadata)
|
||||||
|> ensure_url(:resource)
|
|> ensure_url(:resource)
|
||||||
|> maybe_add_published_at()
|
|> maybe_add_published_at()
|
||||||
|> validate_resource_or_folder()
|
|> validate_resource_or_folder()
|
||||||
|
@ -91,11 +65,6 @@ defmodule Mobilizon.Resources.Resource do
|
||||||
|> unique_constraint(:url, name: :resource_url_index)
|
|> unique_constraint(:url, name: :resource_url_index)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp metadata_changeset(schema, params) do
|
|
||||||
schema
|
|
||||||
|> cast(params, @metadata_attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec validate_resource_or_folder(Changeset.t()) :: Changeset.t()
|
@spec validate_resource_or_folder(Changeset.t()) :: Changeset.t()
|
||||||
defp validate_resource_or_folder(%Changeset{} = changeset) do
|
defp validate_resource_or_folder(%Changeset{} = changeset) do
|
||||||
with {status, type} when status in [:changes, :data] <- fetch_field(changeset, :type),
|
with {status, type} when status in [:changes, :data] <- fetch_field(changeset, :type),
|
||||||
|
|
64
lib/mobilizon/resources/resource/metadata.ex
Normal file
64
lib/mobilizon/resources/resource/metadata.ex
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
defmodule Mobilizon.Resources.Resource.Metadata do
|
||||||
|
@moduledoc """
|
||||||
|
Represents a resource metadata
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
type: String.t(),
|
||||||
|
title: String.t(),
|
||||||
|
image_remote_url: String.t(),
|
||||||
|
width: non_neg_integer(),
|
||||||
|
height: non_neg_integer(),
|
||||||
|
author_name: String.t(),
|
||||||
|
author_url: String.t(),
|
||||||
|
provider_name: String.t(),
|
||||||
|
provider_url: String.t(),
|
||||||
|
html: String.t(),
|
||||||
|
favicon_url: String.t()
|
||||||
|
}
|
||||||
|
|
||||||
|
@required_attrs []
|
||||||
|
|
||||||
|
@optional_attrs [
|
||||||
|
:type,
|
||||||
|
:title,
|
||||||
|
:description,
|
||||||
|
:image_remote_url,
|
||||||
|
:width,
|
||||||
|
:height,
|
||||||
|
:author_name,
|
||||||
|
:author_url,
|
||||||
|
:provider_name,
|
||||||
|
:provider_url,
|
||||||
|
:html,
|
||||||
|
:favicon_url
|
||||||
|
]
|
||||||
|
|
||||||
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
embedded_schema do
|
||||||
|
field(:type, :string)
|
||||||
|
field(:title, :string)
|
||||||
|
field(:description, :string)
|
||||||
|
field(:image_remote_url, :string)
|
||||||
|
field(:width, :integer)
|
||||||
|
field(:height, :integer)
|
||||||
|
field(:author_name, :string)
|
||||||
|
field(:author_url, :string)
|
||||||
|
field(:provider_name, :string)
|
||||||
|
field(:provider_url, :string)
|
||||||
|
field(:html, :string)
|
||||||
|
field(:favicon_url, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
|
def changeset(schema, params) do
|
||||||
|
schema
|
||||||
|
|> cast(params, @attrs)
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,7 @@ defmodule Mobilizon.Users.Setting do
|
||||||
use Ecto.Schema
|
use Ecto.Schema
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
alias Mobilizon.Users.{NotificationPendingNotificationDelay, User}
|
alias Mobilizon.Users.{NotificationPendingNotificationDelay, User}
|
||||||
|
alias Mobilizon.Users.Setting.Location
|
||||||
|
|
||||||
@type t :: %__MODULE__{
|
@type t :: %__MODULE__{
|
||||||
timezone: String.t(),
|
timezone: String.t(),
|
||||||
|
@ -40,8 +41,6 @@ defmodule Mobilizon.Users.Setting do
|
||||||
|
|
||||||
@attrs @required_attrs ++ @optional_attrs
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
|
|
||||||
@location_attrs [:name, :range, :geohash]
|
|
||||||
|
|
||||||
@primary_key {:user_id, :id, autogenerate: false}
|
@primary_key {:user_id, :id, autogenerate: false}
|
||||||
schema "user_settings" do
|
schema "user_settings" do
|
||||||
field(:timezone, :string)
|
field(:timezone, :string)
|
||||||
|
@ -60,11 +59,7 @@ defmodule Mobilizon.Users.Setting do
|
||||||
field(:group_notifications, NotificationPendingNotificationDelay, default: :one_day)
|
field(:group_notifications, NotificationPendingNotificationDelay, default: :one_day)
|
||||||
field(:last_notification_sent, :utc_datetime)
|
field(:last_notification_sent, :utc_datetime)
|
||||||
|
|
||||||
embeds_one :location, Location, on_replace: :update, primary_key: false do
|
embeds_one(:location, Location, on_replace: :update)
|
||||||
field(:name, :string)
|
|
||||||
field(:range, :integer)
|
|
||||||
field(:geohash, :string)
|
|
||||||
end
|
|
||||||
|
|
||||||
belongs_to(:user, User, primary_key: true, type: :id, foreign_key: :id, define_field: false)
|
belongs_to(:user, User, primary_key: true, type: :id, foreign_key: :id, define_field: false)
|
||||||
|
|
||||||
|
@ -76,13 +71,7 @@ defmodule Mobilizon.Users.Setting do
|
||||||
def changeset(setting, attrs) do
|
def changeset(setting, attrs) do
|
||||||
setting
|
setting
|
||||||
|> cast(attrs, @attrs)
|
|> cast(attrs, @attrs)
|
||||||
|> cast_embed(:location, with: &location_changeset/2)
|
|> cast_embed(:location)
|
||||||
|> validate_required(@required_attrs)
|
|> validate_required(@required_attrs)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec location_changeset(location, map) :: Ecto.Changeset.t()
|
|
||||||
def location_changeset(schema, params) do
|
|
||||||
schema
|
|
||||||
|> cast(params, @location_attrs)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
38
lib/mobilizon/users/setting/location.ex
Normal file
38
lib/mobilizon/users/setting/location.ex
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
defmodule Mobilizon.Users.Setting.Location do
|
||||||
|
@moduledoc """
|
||||||
|
Represents user location information
|
||||||
|
"""
|
||||||
|
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
@type t :: %__MODULE__{
|
||||||
|
name: String.t(),
|
||||||
|
range: non_neg_integer(),
|
||||||
|
geohash: String.t()
|
||||||
|
}
|
||||||
|
|
||||||
|
@required_attrs []
|
||||||
|
|
||||||
|
@optional_attrs [
|
||||||
|
:name,
|
||||||
|
:range,
|
||||||
|
:geohash
|
||||||
|
]
|
||||||
|
|
||||||
|
@attrs @required_attrs ++ @optional_attrs
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
embedded_schema do
|
||||||
|
field(:name, :string)
|
||||||
|
field(:range, :integer)
|
||||||
|
field(:geohash, :string)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
|
def changeset(schema, params) do
|
||||||
|
schema
|
||||||
|
|> cast(params, @attrs)
|
||||||
|
end
|
||||||
|
end
|
|
@ -62,9 +62,9 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do
|
||||||
static_url = Mobilizon.Web.Endpoint.static_url()
|
static_url = Mobilizon.Web.Endpoint.static_url()
|
||||||
websocket_url = Mobilizon.Web.Endpoint.websocket_url()
|
websocket_url = Mobilizon.Web.Endpoint.websocket_url()
|
||||||
|
|
||||||
img_src = [@img_src | get_csp_config(:img_src, options)]
|
img_src = [@img_src] ++ [get_csp_config(:img_src, options)]
|
||||||
|
|
||||||
media_src = [@media_src | get_csp_config(:media_src, options)]
|
media_src = [@media_src] ++ [get_csp_config(:media_src, options)]
|
||||||
|
|
||||||
connect_src = [
|
connect_src = [
|
||||||
@connect_src,
|
@connect_src,
|
||||||
|
@ -85,22 +85,22 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
script_src = [script_src | get_csp_config(:script_src, options)]
|
script_src = [script_src] ++ [get_csp_config(:script_src, options)]
|
||||||
|
|
||||||
style_src =
|
style_src =
|
||||||
if Config.get(:env) == :dev, do: [@style_src | "'unsafe-inline' "], else: @style_src
|
if Config.get(:env) == :dev, do: [@style_src | "'unsafe-inline' "], else: @style_src
|
||||||
|
|
||||||
style_src = [style_src | get_csp_config(:style_src, options)]
|
style_src = [style_src] ++ [get_csp_config(:style_src, options)]
|
||||||
|
|
||||||
font_src = [@font_src | get_csp_config(:font_src, options)]
|
font_src = [@font_src] ++ [get_csp_config(:font_src, options)]
|
||||||
|
|
||||||
frame_src = if Config.get(:env) == :dev, do: "frame-src 'self' ", else: "frame-src 'none' "
|
frame_src = if Config.get(:env) == :dev, do: "frame-src 'self' ", else: "frame-src 'none' "
|
||||||
frame_src = [frame_src | get_csp_config(:frame_src, options)]
|
frame_src = [frame_src] ++ [get_csp_config(:frame_src, options)]
|
||||||
|
|
||||||
frame_ancestors =
|
frame_ancestors =
|
||||||
if Config.get(:env) == :dev, do: "frame-ancestors 'self' ", else: "frame-ancestors 'none' "
|
if Config.get(:env) == :dev, do: "frame-ancestors 'self' ", else: "frame-ancestors 'none' "
|
||||||
|
|
||||||
frame_ancestors = [frame_ancestors | get_csp_config(:frame_ancestors, options)]
|
frame_ancestors = [frame_ancestors] ++ [get_csp_config(:frame_ancestors, options)]
|
||||||
|
|
||||||
insecure = if scheme == "https", do: "upgrade-insecure-requests"
|
insecure = if scheme == "https", do: "upgrade-insecure-requests"
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,10 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
|
||||||
import Plug.Conn, only: [assign: 3]
|
import Plug.Conn, only: [assign: 3]
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
|
|
||||||
|
@spec init(any()) :: nil
|
||||||
def init(_), do: nil
|
def init(_), do: nil
|
||||||
|
|
||||||
|
@spec call(Plug.Conn.t(), any()) :: Plug.Conn.t()
|
||||||
def call(conn, _) do
|
def call(conn, _) do
|
||||||
locale =
|
locale =
|
||||||
[
|
[
|
||||||
|
@ -29,17 +31,22 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
|
||||||
assign(conn, :locale, locale)
|
assign(conn, :locale, locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec supported_locale?(String.t()) :: boolean()
|
||||||
defp supported_locale?(locale) do
|
defp supported_locale?(locale) do
|
||||||
GettextBackend
|
GettextBackend
|
||||||
|> Gettext.known_locales()
|
|> Gettext.known_locales()
|
||||||
|> Enum.member?(locale)
|
|> Enum.member?(locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec default_locale :: String.t()
|
||||||
defp default_locale do
|
defp default_locale do
|
||||||
Keyword.get(Mobilizon.Config.instance_config(), :default_language, "en")
|
Keyword.get(Mobilizon.Config.instance_config(), :default_language, "en")
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec determine_best_locale(String.t()) :: String.t()
|
@doc """
|
||||||
|
Determine the best available locale for a given locale ID
|
||||||
|
"""
|
||||||
|
@spec determine_best_locale(String.t()) :: String.t() | nil
|
||||||
def determine_best_locale(locale) when is_binary(locale) do
|
def determine_best_locale(locale) when is_binary(locale) do
|
||||||
locale = String.trim(locale)
|
locale = String.trim(locale)
|
||||||
locales = Gettext.known_locales(GettextBackend)
|
locales = Gettext.known_locales(GettextBackend)
|
||||||
|
@ -58,5 +65,6 @@ defmodule Mobilizon.Web.Plugs.SetLocalePlug do
|
||||||
def determine_best_locale(_), do: nil
|
def determine_best_locale(_), do: nil
|
||||||
|
|
||||||
# Keep only the first part of the locale
|
# Keep only the first part of the locale
|
||||||
|
@spec split_locale(String.t()) :: String.t()
|
||||||
defp split_locale(locale), do: locale |> String.split("_", trim: true, parts: 2) |> hd
|
defp split_locale(locale), do: locale |> String.split("_", trim: true, parts: 2) |> hd
|
||||||
end
|
end
|
||||||
|
|
|
@ -165,6 +165,11 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
|> halt()
|
|> halt()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec request(String.t(), String.t(), list(tuple()), Keyword.t()) ::
|
||||||
|
{:ok, 200 | 206 | 304, list(tuple()), any()}
|
||||||
|
| {:ok, 200 | 206 | 304, list(tuple())}
|
||||||
|
| {:error, {:invalid_http_response, pos_integer()}}
|
||||||
|
| {:error, any()}
|
||||||
defp request(method, url, headers, hackney_opts) do
|
defp request(method, url, headers, hackney_opts) do
|
||||||
Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}")
|
Logger.debug("#{__MODULE__} #{method} #{url} #{inspect(headers)}")
|
||||||
method = method |> String.downcase() |> String.to_existing_atom()
|
method = method |> String.downcase() |> String.to_existing_atom()
|
||||||
|
@ -184,6 +189,8 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec response(Plug.Conn.t(), any(), String.t(), pos_integer(), list(tuple()), Keyword.t()) ::
|
||||||
|
Plug.Conn.t()
|
||||||
defp response(conn, client, url, status, headers, opts) do
|
defp response(conn, client, url, status, headers, opts) do
|
||||||
result =
|
result =
|
||||||
conn
|
conn
|
||||||
|
@ -209,18 +216,26 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec chunk_reply(
|
||||||
|
Plug.Conn.t(),
|
||||||
|
any(),
|
||||||
|
Keyword.t(),
|
||||||
|
non_neg_integer(),
|
||||||
|
non_neg_integer() | :no_duration_limit
|
||||||
|
) ::
|
||||||
|
{:ok, Plug.Conn.t()} | {:error, any(), Plug.Conn.t()}
|
||||||
defp chunk_reply(conn, client, opts) do
|
defp chunk_reply(conn, client, opts) do
|
||||||
chunk_reply(conn, client, opts, 0, 0)
|
chunk_reply(conn, client, opts, 0, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp chunk_reply(conn, client, opts, sent_so_far, duration) do
|
defp chunk_reply(conn, client, opts, sent_so_far, duration) do
|
||||||
with {:ok, duration} <-
|
with {:ok, {duration, now}} <-
|
||||||
check_read_duration(
|
check_read_duration(
|
||||||
duration,
|
duration,
|
||||||
Keyword.get(opts, :max_read_duration, @max_read_duration)
|
Keyword.get(opts, :max_read_duration, @max_read_duration)
|
||||||
),
|
),
|
||||||
{:ok, data} <- @hackney.stream_body(client),
|
{:ok, data} <- @hackney.stream_body(client),
|
||||||
{:ok, duration} <- increase_read_duration(duration),
|
{:ok, duration} <- increase_read_duration({duration, now}),
|
||||||
sent_so_far = sent_so_far + byte_size(data),
|
sent_so_far = sent_so_far + byte_size(data),
|
||||||
:ok <- body_size_constraint(sent_so_far, Keyword.get(opts, :max_body_size)),
|
:ok <- body_size_constraint(sent_so_far, Keyword.get(opts, :max_body_size)),
|
||||||
{:ok, conn} <- chunk(conn, data) do
|
{:ok, conn} <- chunk(conn, data) do
|
||||||
|
@ -231,6 +246,8 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec head_response(Plug.Conn.t(), any(), pos_integer(), list(tuple()), Keyword.t()) ::
|
||||||
|
Plug.Conn.t() | no_return()
|
||||||
defp head_response(conn, _url, code, headers, opts) do
|
defp head_response(conn, _url, code, headers, opts) do
|
||||||
conn
|
conn
|
||||||
|> put_resp_headers(build_resp_headers(headers, opts))
|
|> put_resp_headers(build_resp_headers(headers, opts))
|
||||||
|
@ -238,6 +255,8 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
|
|
||||||
# sobelow_skip ["XSS.SendResp"]
|
# sobelow_skip ["XSS.SendResp"]
|
||||||
|
@spec error_or_redirect(Plug.Conn.t(), String.t(), pos_integer(), String.t(), Keyword.t()) ::
|
||||||
|
Plug.Conn.t()
|
||||||
defp error_or_redirect(conn, url, code, body, opts) do
|
defp error_or_redirect(conn, url, code, body, opts) do
|
||||||
if Keyword.get(opts, :redirect_on_failure, false) do
|
if Keyword.get(opts, :redirect_on_failure, false) do
|
||||||
conn
|
conn
|
||||||
|
@ -250,12 +269,14 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec downcase_headers(list(tuple())) :: list(tuple())
|
||||||
defp downcase_headers(headers) do
|
defp downcase_headers(headers) do
|
||||||
Enum.map(headers, fn {k, v} ->
|
Enum.map(headers, fn {k, v} ->
|
||||||
{String.downcase(k), v}
|
{String.downcase(k), v}
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec get_content_type(list(tuple())) :: String.t()
|
||||||
defp get_content_type(headers) do
|
defp get_content_type(headers) do
|
||||||
{_, content_type} =
|
{_, content_type} =
|
||||||
List.keyfind(headers, "content-type", 0, {"content-type", "application/octet-stream"})
|
List.keyfind(headers, "content-type", 0, {"content-type", "application/octet-stream"})
|
||||||
|
@ -264,12 +285,14 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
content_type
|
content_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec put_resp_headers(Plug.Conn.t(), list(tuple())) :: Plug.Conn.t()
|
||||||
defp put_resp_headers(conn, headers) do
|
defp put_resp_headers(conn, headers) do
|
||||||
Enum.reduce(headers, conn, fn {k, v}, conn ->
|
Enum.reduce(headers, conn, fn {k, v}, conn ->
|
||||||
put_resp_header(conn, k, v)
|
put_resp_header(conn, k, v)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec build_req_headers(list(tuple()), Keyword.t()) :: list(tuple())
|
||||||
defp build_req_headers(headers, opts) do
|
defp build_req_headers(headers, opts) do
|
||||||
headers
|
headers
|
||||||
|> downcase_headers()
|
|> downcase_headers()
|
||||||
|
@ -290,6 +313,7 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end).()
|
end).()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec build_resp_headers(list(tuple()), Keyword.t()) :: list(tuple())
|
||||||
defp build_resp_headers(headers, opts) do
|
defp build_resp_headers(headers, opts) do
|
||||||
headers
|
headers
|
||||||
|> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
|
|> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
|
||||||
|
@ -298,6 +322,7 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
|> (fn headers -> headers ++ Keyword.get(opts, :resp_headers, []) end).()
|
|> (fn headers -> headers ++ Keyword.get(opts, :resp_headers, []) end).()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec build_resp_cache_headers(list(tuple()), Keyword.t()) :: list(tuple())
|
||||||
defp build_resp_cache_headers(headers, _opts) do
|
defp build_resp_cache_headers(headers, _opts) do
|
||||||
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
|
has_cache? = Enum.any?(headers, fn {k, _} -> k in @resp_cache_headers end)
|
||||||
has_cache_control? = List.keymember?(headers, "cache-control", 0)
|
has_cache_control? = List.keymember?(headers, "cache-control", 0)
|
||||||
|
@ -321,6 +346,7 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec build_resp_content_disposition_header(list(tuple()), Keyword.t()) :: list(tuple())
|
||||||
defp build_resp_content_disposition_header(headers, opts) do
|
defp build_resp_content_disposition_header(headers, opts) do
|
||||||
opt = Keyword.get(opts, :inline_content_types, @inline_content_types)
|
opt = Keyword.get(opts, :inline_content_types, @inline_content_types)
|
||||||
|
|
||||||
|
@ -359,6 +385,8 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec header_length_constraint(list(tuple()), non_neg_integer()) ::
|
||||||
|
:ok | {:error, :body_too_large}
|
||||||
defp header_length_constraint(headers, limit) when is_integer(limit) and limit > 0 do
|
defp header_length_constraint(headers, limit) when is_integer(limit) and limit > 0 do
|
||||||
with {_, size} <- List.keyfind(headers, "content-length", 0),
|
with {_, size} <- List.keyfind(headers, "content-length", 0),
|
||||||
{size, _} <- Integer.parse(size),
|
{size, _} <- Integer.parse(size),
|
||||||
|
@ -375,15 +403,16 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
|
|
||||||
defp header_length_constraint(_, _), do: :ok
|
defp header_length_constraint(_, _), do: :ok
|
||||||
|
|
||||||
|
@spec body_size_constraint(integer(), integer()) :: :ok | {:error, :body_too_large}
|
||||||
defp body_size_constraint(size, limit) when is_integer(limit) and limit > 0 and size >= limit do
|
defp body_size_constraint(size, limit) when is_integer(limit) and limit > 0 and size >= limit do
|
||||||
{:error, :body_too_large}
|
{:error, :body_too_large}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp body_size_constraint(_, _), do: :ok
|
defp body_size_constraint(_, _), do: :ok
|
||||||
|
|
||||||
@spec check_read_duration(any(), integer()) ::
|
@spec check_read_duration(any(), integer() | :no_duration_limit) ::
|
||||||
{:ok, {integer(), integer()}}
|
{:ok, {integer(), integer()}}
|
||||||
| {:ok, :no_duration_limit, :no_duration_limit}
|
| {:ok, {:no_duration_limit, :no_duration_limit}}
|
||||||
| {:error, :read_duration_exceeded}
|
| {:error, :read_duration_exceeded}
|
||||||
defp check_read_duration(duration, max)
|
defp check_read_duration(duration, max)
|
||||||
when is_integer(duration) and is_integer(max) and max > 0 do
|
when is_integer(duration) and is_integer(max) and max > 0 do
|
||||||
|
@ -394,8 +423,12 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp check_read_duration(_, _), do: {:ok, :no_duration_limit, :no_duration_limit}
|
defp check_read_duration(_, _), do: {:ok, {:no_duration_limit, :no_duration_limit}}
|
||||||
|
|
||||||
|
@spec increase_read_duration(
|
||||||
|
{previous_duration :: pos_integer | :no_duration_limit,
|
||||||
|
started :: pos_integer | :no_duration_limit}
|
||||||
|
) :: {:ok, pos_integer()} | {:ok, :no_duration_limit}
|
||||||
defp increase_read_duration({previous_duration, started})
|
defp increase_read_duration({previous_duration, started})
|
||||||
when is_integer(previous_duration) and is_integer(started) do
|
when is_integer(previous_duration) and is_integer(started) do
|
||||||
duration = :erlang.system_time(:millisecond) - started
|
duration = :erlang.system_time(:millisecond) - started
|
||||||
|
@ -403,9 +436,10 @@ defmodule Mobilizon.Web.ReverseProxy do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp increase_read_duration(_) do
|
defp increase_read_duration(_) do
|
||||||
{:ok, :no_duration_limit, :no_duration_limit}
|
{:ok, :no_duration_limit}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec filename(String.t()) :: String.t() | nil
|
||||||
def filename(url_or_path) do
|
def filename(url_or_path) do
|
||||||
if path = URI.parse(url_or_path).path, do: Path.basename(path)
|
if path = URI.parse(url_or_path).path, do: Path.basename(path)
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,6 +17,7 @@ defmodule Mobilizon.Web.ActivityPub.ActorView do
|
||||||
@json_ld_header Utils.make_json_ld_header()
|
@json_ld_header Utils.make_json_ld_header()
|
||||||
@selected_member_roles ~w(creator administrator moderator member)a
|
@selected_member_roles ~w(creator administrator moderator member)a
|
||||||
|
|
||||||
|
@spec render(String.t(), map()) :: map()
|
||||||
def render("actor.json", %{actor: actor}) do
|
def render("actor.json", %{actor: actor}) do
|
||||||
actor
|
actor
|
||||||
|> Convertible.model_to_as()
|
|> Convertible.model_to_as()
|
||||||
|
|
|
@ -3,6 +3,7 @@ defmodule Mobilizon.Web.ActivityPub.ObjectView do
|
||||||
|
|
||||||
alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
|
alias Mobilizon.Federation.ActivityPub.{Activity, Utils}
|
||||||
|
|
||||||
|
@spec render(String.t(), map()) :: map()
|
||||||
def render("activity.json", %{activity: %Activity{local: local, data: data} = activity}) do
|
def render("activity.json", %{activity: %Activity{local: local, data: data} = activity}) do
|
||||||
%{
|
%{
|
||||||
"id" => data["id"],
|
"id" => data["id"],
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Mobilizon.Web.AuthView do
|
||||||
alias Phoenix.HTML.Tag
|
alias Phoenix.HTML.Tag
|
||||||
import Mobilizon.Web.Views.Utils
|
import Mobilizon.Web.Views.Utils
|
||||||
|
|
||||||
|
@spec render(String.t(), map()) :: String.t() | Plug.Conn.t()
|
||||||
def render("callback.html", %{
|
def render("callback.html", %{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
access_token: access_token,
|
access_token: access_token,
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Mobilizon.Web.ErrorHelpers do
|
||||||
@doc """
|
@doc """
|
||||||
Translates an error message using gettext.
|
Translates an error message using gettext.
|
||||||
"""
|
"""
|
||||||
|
@spec translate_error({msg :: String.t(), opts :: map()}) :: String.t()
|
||||||
def translate_error({msg, opts}) do
|
def translate_error({msg, opts}) do
|
||||||
# Because error messages were defined within Ecto, we must
|
# Because error messages were defined within Ecto, we must
|
||||||
# call the Gettext module passing our Gettext backend. We
|
# call the Gettext module passing our Gettext backend. We
|
||||||
|
|
|
@ -6,6 +6,7 @@ defmodule Mobilizon.Web.ErrorView do
|
||||||
alias Mobilizon.Service.Metadata.Instance
|
alias Mobilizon.Service.Metadata.Instance
|
||||||
import Mobilizon.Web.Views.Utils
|
import Mobilizon.Web.Views.Utils
|
||||||
|
|
||||||
|
@spec render(String.t(), map()) :: map() | String.t() | Plug.Conn.t()
|
||||||
def render("404.html", %{conn: conn}) do
|
def render("404.html", %{conn: conn}) do
|
||||||
with tags <- Instance.build_tags(),
|
with tags <- Instance.build_tags(),
|
||||||
{:ok, html} <- inject_tags(tags, get_locale(conn)) do
|
{:ok, html} <- inject_tags(tags, get_locale(conn)) do
|
||||||
|
|
|
@ -8,6 +8,7 @@ defmodule Mobilizon.Web.JsonLD.ObjectView do
|
||||||
alias Mobilizon.Web.Endpoint
|
alias Mobilizon.Web.Endpoint
|
||||||
alias Mobilizon.Web.JsonLD.ObjectView
|
alias Mobilizon.Web.JsonLD.ObjectView
|
||||||
|
|
||||||
|
@spec render(String.t(), map()) :: map()
|
||||||
def render("group.json", %{group: %Actor{} = group}) do
|
def render("group.json", %{group: %Actor{} = group}) do
|
||||||
%{
|
%{
|
||||||
"@context" => "http://schema.org",
|
"@context" => "http://schema.org",
|
||||||
|
@ -93,6 +94,7 @@ defmodule Mobilizon.Web.JsonLD.ObjectView do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec render_location(map()) :: map() | nil
|
||||||
defp render_location(%{physical_address: %Address{} = address}),
|
defp render_location(%{physical_address: %Address{} = address}),
|
||||||
do: render_one(address, ObjectView, "place.json", as: :address)
|
do: render_one(address, ObjectView, "place.json", as: :address)
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ defmodule Mobilizon.Web.PageView do
|
||||||
alias Mobilizon.Federation.ActivityStream.Convertible
|
alias Mobilizon.Federation.ActivityStream.Convertible
|
||||||
import Mobilizon.Web.Views.Utils
|
import Mobilizon.Web.Views.Utils
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@spec render(String.t(), %{conn: Plug.Conn.t()}) :: map() | String.t() | Plug.Conn.t()
|
||||||
def render("actor.activity-json", %{conn: %{assigns: %{object: %Actor{} = actor}}}) do
|
def render("actor.activity-json", %{conn: %{assigns: %{object: %Actor{} = actor}}}) do
|
||||||
actor
|
actor
|
||||||
|> Convertible.model_to_as()
|
|> Convertible.model_to_as()
|
||||||
|
|
|
@ -11,6 +11,7 @@ defmodule Mobilizon.Factory do
|
||||||
alias Mobilizon.Web.{Endpoint, Upload}
|
alias Mobilizon.Web.{Endpoint, Upload}
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
|
|
||||||
|
@spec user_factory :: Mobilizon.Users.User.t()
|
||||||
def user_factory do
|
def user_factory do
|
||||||
%Mobilizon.Users.User{
|
%Mobilizon.Users.User{
|
||||||
password_hash: "Jane Smith",
|
password_hash: "Jane Smith",
|
||||||
|
@ -23,6 +24,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec settings_factory :: Mobilizon.Users.Setting.t()
|
||||||
def settings_factory do
|
def settings_factory do
|
||||||
%Mobilizon.Users.Setting{
|
%Mobilizon.Users.Setting{
|
||||||
timezone: nil,
|
timezone: nil,
|
||||||
|
@ -37,6 +39,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec actor_factory :: Mobilizon.Actors.Actor.t()
|
||||||
def actor_factory do
|
def actor_factory do
|
||||||
preferred_username = sequence("thomas")
|
preferred_username = sequence("thomas")
|
||||||
|
|
||||||
|
@ -62,6 +65,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec group_factory :: Mobilizon.Actors.Actor.t()
|
||||||
def group_factory do
|
def group_factory do
|
||||||
preferred_username = sequence("myGroup")
|
preferred_username = sequence("myGroup")
|
||||||
|
|
||||||
|
@ -82,6 +86,7 @@ defmodule Mobilizon.Factory do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec instance_actor_factory :: Mobilizon.Actors.Actor.t()
|
||||||
def instance_actor_factory do
|
def instance_actor_factory do
|
||||||
preferred_username = "relay"
|
preferred_username = "relay"
|
||||||
domain = "#{sequence("mydomain")}.com"
|
domain = "#{sequence("mydomain")}.com"
|
||||||
|
@ -104,6 +109,7 @@ defmodule Mobilizon.Factory do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec follower_factory :: Mobilizon.Actors.Follower.t()
|
||||||
def follower_factory do
|
def follower_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -116,6 +122,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec tag_factory :: Mobilizon.Events.Tag.t()
|
||||||
def tag_factory do
|
def tag_factory do
|
||||||
%Mobilizon.Events.Tag{
|
%Mobilizon.Events.Tag{
|
||||||
title: sequence("MyTag"),
|
title: sequence("MyTag"),
|
||||||
|
@ -123,6 +130,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec tag_relation_factory :: Mobilizon.Events.TagRelation.t()
|
||||||
def tag_relation_factory do
|
def tag_relation_factory do
|
||||||
%Mobilizon.Events.TagRelation{
|
%Mobilizon.Events.TagRelation{
|
||||||
tag: build(:tag),
|
tag: build(:tag),
|
||||||
|
@ -130,6 +138,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec address_factory :: Mobilizon.Addresses.Address.t()
|
||||||
def address_factory do
|
def address_factory do
|
||||||
%Mobilizon.Addresses.Address{
|
%Mobilizon.Addresses.Address{
|
||||||
description: sequence("MyAddress"),
|
description: sequence("MyAddress"),
|
||||||
|
@ -143,6 +152,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec comment_factory :: Mobilizon.Discussions.Comment.t()
|
||||||
def comment_factory do
|
def comment_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -165,6 +175,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec event_factory :: Mobilizon.Events.Event.t()
|
||||||
def event_factory do
|
def event_factory do
|
||||||
actor = build(:actor)
|
actor = build(:actor)
|
||||||
start = Timex.shift(DateTime.utc_now(), hours: 2)
|
start = Timex.shift(DateTime.utc_now(), hours: 2)
|
||||||
|
@ -198,6 +209,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec participant_factory :: Mobilizon.Events.Participant.t()
|
||||||
def participant_factory do
|
def participant_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -214,6 +226,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec session_factory :: Mobilizon.Events.Session.t()
|
||||||
def session_factory do
|
def session_factory do
|
||||||
%Mobilizon.Events.Session{
|
%Mobilizon.Events.Session{
|
||||||
title: sequence("MySession"),
|
title: sequence("MySession"),
|
||||||
|
@ -222,6 +235,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec track_factory :: Mobilizon.Events.Track.t()
|
||||||
def track_factory do
|
def track_factory do
|
||||||
%Mobilizon.Events.Track{
|
%Mobilizon.Events.Track{
|
||||||
name: sequence("MyTrack"),
|
name: sequence("MyTrack"),
|
||||||
|
@ -229,6 +243,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec bot_factory :: Mobilizon.Actors.Bot.t()
|
||||||
def bot_factory do
|
def bot_factory do
|
||||||
%Mobilizon.Actors.Bot{
|
%Mobilizon.Actors.Bot{
|
||||||
source: "https://mysource.tld/feed.ics",
|
source: "https://mysource.tld/feed.ics",
|
||||||
|
@ -238,6 +253,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec member_factory :: Mobilizon.Actors.Member.t()
|
||||||
def member_factory do
|
def member_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -250,6 +266,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec feed_token_factory :: Mobilizon.Events.FeedToken.t()
|
||||||
def feed_token_factory do
|
def feed_token_factory do
|
||||||
user = build(:user)
|
user = build(:user)
|
||||||
|
|
||||||
|
@ -260,6 +277,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec file_factory :: Mobilizon.Medias.File.t()
|
||||||
def file_factory do
|
def file_factory do
|
||||||
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
|
File.cp!("test/fixtures/image.jpg", "test/fixtures/image_tmp.jpg")
|
||||||
|
|
||||||
|
@ -285,6 +303,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec media_factory :: Mobilizon.Medias.Media.t()
|
||||||
def media_factory do
|
def media_factory do
|
||||||
%Mobilizon.Medias.Media{
|
%Mobilizon.Medias.Media{
|
||||||
file: build(:file),
|
file: build(:file),
|
||||||
|
@ -292,6 +311,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec report_factory :: Mobilizon.Reports.Report.t()
|
||||||
def report_factory do
|
def report_factory do
|
||||||
%Mobilizon.Reports.Report{
|
%Mobilizon.Reports.Report{
|
||||||
content: "This is problematic",
|
content: "This is problematic",
|
||||||
|
@ -304,6 +324,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec report_note_factory :: Mobilizon.Reports.Note.t()
|
||||||
def report_note_factory do
|
def report_note_factory do
|
||||||
%Mobilizon.Reports.Note{
|
%Mobilizon.Reports.Note{
|
||||||
content: "My opinion",
|
content: "My opinion",
|
||||||
|
@ -312,6 +333,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec todo_list_factory :: Mobilizon.Todos.TodoList.t()
|
||||||
def todo_list_factory do
|
def todo_list_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -324,6 +346,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec todo_factory :: Mobilizon.Todos.Todo.t()
|
||||||
def todo_factory do
|
def todo_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -340,6 +363,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec resource_factory :: Mobilizon.Resources.Resource.t()
|
||||||
def resource_factory do
|
def resource_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
title = sequence("my resource")
|
title = sequence("my resource")
|
||||||
|
@ -358,6 +382,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec admin_setting_factory :: Mobilizon.Admin.Setting.t()
|
||||||
def admin_setting_factory do
|
def admin_setting_factory do
|
||||||
%Mobilizon.Admin.Setting{
|
%Mobilizon.Admin.Setting{
|
||||||
group: sequence("group"),
|
group: sequence("group"),
|
||||||
|
@ -366,6 +391,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec post_factory :: Mobilizon.Posts.Post.t()
|
||||||
def post_factory do
|
def post_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -386,6 +412,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec tombstone_factory :: Mobilizon.Tombstone.t()
|
||||||
def tombstone_factory do
|
def tombstone_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
|
|
||||||
|
@ -395,6 +422,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec discussion_factory :: Mobilizon.Discussions.Discussion.t()
|
||||||
def discussion_factory do
|
def discussion_factory do
|
||||||
uuid = Ecto.UUID.generate()
|
uuid = Ecto.UUID.generate()
|
||||||
actor = build(:actor)
|
actor = build(:actor)
|
||||||
|
@ -413,6 +441,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec mobilizon_activity_factory :: Mobilizon.Activities.Activity.t()
|
||||||
def mobilizon_activity_factory do
|
def mobilizon_activity_factory do
|
||||||
group = build(:group)
|
group = build(:group)
|
||||||
actor = build(:actor)
|
actor = build(:actor)
|
||||||
|
@ -433,6 +462,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec mobilizon_activity_setting_factory :: Mobilizon.Users.ActivitySetting.t()
|
||||||
def mobilizon_activity_setting_factory do
|
def mobilizon_activity_setting_factory do
|
||||||
%Mobilizon.Users.ActivitySetting{
|
%Mobilizon.Users.ActivitySetting{
|
||||||
key: "event_created",
|
key: "event_created",
|
||||||
|
@ -442,6 +472,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec push_subscription_factory :: Mobilizon.Users.PushSubscription.t()
|
||||||
def push_subscription_factory do
|
def push_subscription_factory do
|
||||||
%Mobilizon.Users.PushSubscription{
|
%Mobilizon.Users.PushSubscription{
|
||||||
digest: "",
|
digest: "",
|
||||||
|
@ -452,6 +483,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec share_factory :: Mobilizon.Share.t()
|
||||||
def share_factory do
|
def share_factory do
|
||||||
%Mobilizon.Share{
|
%Mobilizon.Share{
|
||||||
actor: build(:actor),
|
actor: build(:actor),
|
||||||
|
@ -460,6 +492,7 @@ defmodule Mobilizon.Factory do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec event_metadata_factory :: Mobilizon.Events.EventMetadata.t()
|
||||||
def event_metadata_factory do
|
def event_metadata_factory do
|
||||||
%Mobilizon.Events.EventMetadata{
|
%Mobilizon.Events.EventMetadata{
|
||||||
key: sequence("mz:custom:something"),
|
key: sequence("mz:custom:something"),
|
||||||
|
|
Loading…
Reference in a new issue