Merge branch 'fixes' into 'main'
Fix various instance view stuff and legacy cleaning Closes #1393 See merge request framasoft/mobilizon!1520
This commit is contained in:
commit
b317fe6163
|
@ -33,7 +33,7 @@
|
||||||
# If you want to enforce a style guide and need a more traditional linting
|
# If you want to enforce a style guide and need a more traditional linting
|
||||||
# experience, you can change `strict` to `true` below:
|
# experience, you can change `strict` to `true` below:
|
||||||
#
|
#
|
||||||
strict: false,
|
strict: true,
|
||||||
#
|
#
|
||||||
# If you want to use uncolored output by default, you can change `color`
|
# If you want to use uncolored output by default, you can change `color`
|
||||||
# to `false` below:
|
# to `false` below:
|
||||||
|
@ -160,6 +160,7 @@
|
||||||
#
|
#
|
||||||
{Credo.Check.Warning.LazyLogging, false},
|
{Credo.Check.Warning.LazyLogging, false},
|
||||||
{Credo.Check.Refactor.MapInto, false},
|
{Credo.Check.Refactor.MapInto, false},
|
||||||
|
{Credo.Check.Warning.MissedMetadataKeyInLoggerConfig, false}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -25,7 +25,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Invite do
|
||||||
) do
|
) do
|
||||||
Logger.debug("Handling #{actor_url} invite to #{group_url} sent to #{target_actor_url}")
|
Logger.debug("Handling #{actor_url} invite to #{group_url} sent to #{target_actor_url}")
|
||||||
|
|
||||||
if is_able_to_invite?(actor, group) do
|
if able_to_invite?(actor, group) do
|
||||||
with {:ok, %Member{url: member_url} = member} <-
|
with {:ok, %Member{url: member_url} = member} <-
|
||||||
Actors.create_member(%{
|
Actors.create_member(%{
|
||||||
parent_id: group_id,
|
parent_id: group_id,
|
||||||
|
@ -64,8 +64,8 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Invite do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_able_to_invite?(Actor.t(), Actor.t()) :: boolean
|
@spec able_to_invite?(Actor.t(), Actor.t()) :: boolean
|
||||||
defp is_able_to_invite?(%Actor{domain: actor_domain, id: actor_id}, %Actor{
|
defp able_to_invite?(%Actor{domain: actor_domain, id: actor_id}, %Actor{
|
||||||
domain: group_domain,
|
domain: group_domain,
|
||||||
id: group_id
|
id: group_id
|
||||||
}) do
|
}) do
|
||||||
|
@ -76,7 +76,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Invite do
|
||||||
# If local group, we'll send the invite
|
# If local group, we'll send the invite
|
||||||
case Actors.get_member(actor_id, group_id) do
|
case Actors.get_member(actor_id, group_id) do
|
||||||
{:ok, %Member{} = admin_member} ->
|
{:ok, %Member{} = admin_member} ->
|
||||||
Member.is_administrator(admin_member)
|
Member.administrator?(admin_member)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
false
|
false
|
||||||
|
|
|
@ -34,7 +34,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Leave do
|
||||||
local,
|
local,
|
||||||
additional
|
additional
|
||||||
) do
|
) do
|
||||||
if Participant.is_not_only_organizer(event_id, actor_id) do
|
if Participant.not_only_organizer?(event_id, actor_id) do
|
||||||
{:error, :is_only_organizer}
|
{:error, :is_only_organizer}
|
||||||
else
|
else
|
||||||
case Mobilizon.Events.get_participant(
|
case Mobilizon.Events.get_participant(
|
||||||
|
@ -83,7 +83,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Leave do
|
||||||
case Actors.get_member(actor_id, group_id) do
|
case Actors.get_member(actor_id, group_id) do
|
||||||
{:ok, %Member{id: member_id} = member} ->
|
{:ok, %Member{id: member_id} = member} ->
|
||||||
if Map.get(additional, :force_member_removal, false) || group_domain != actor_domain ||
|
if Map.get(additional, :force_member_removal, false) || group_domain != actor_domain ||
|
||||||
!Actors.is_only_administrator?(member_id, group_id) do
|
!Actors.only_administrator?(member_id, group_id) do
|
||||||
with {:ok, %Member{} = member} <- Actors.delete_member(member) do
|
with {:ok, %Member{} = member} <- Actors.delete_member(member) do
|
||||||
Mobilizon.Service.Activity.Member.insert_activity(member, subject: "member_quit")
|
Mobilizon.Service.Activity.Member.insert_activity(member, subject: "member_quit")
|
||||||
|
|
||||||
|
|
|
@ -44,13 +44,13 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do
|
||||||
) do
|
) do
|
||||||
case object |> Ownable.permissions() |> get_in([:create]) do
|
case object |> Ownable.permissions() |> get_in([:create]) do
|
||||||
:member ->
|
:member ->
|
||||||
Actors.is_member?(actor_id, group_id)
|
Actors.member?(actor_id, group_id)
|
||||||
|
|
||||||
:moderator ->
|
:moderator ->
|
||||||
Actors.is_moderator?(actor_id, group_id)
|
Actors.moderator?(actor_id, group_id)
|
||||||
|
|
||||||
:administrator ->
|
:administrator ->
|
||||||
Actors.is_administrator?(actor_id, group_id)
|
Actors.administrator?(actor_id, group_id)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
false
|
false
|
||||||
|
@ -122,21 +122,21 @@ defmodule Mobilizon.Federation.ActivityPub.Permission do
|
||||||
"Checking if activity actor #{actor_url} is a moderator from group from #{object.url}"
|
"Checking if activity actor #{actor_url} is a moderator from group from #{object.url}"
|
||||||
)
|
)
|
||||||
|
|
||||||
Actors.is_moderator?(actor_id, group_id)
|
Actors.moderator?(actor_id, group_id)
|
||||||
|
|
||||||
:administrator ->
|
:administrator ->
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"Checking if activity actor #{actor_url} is an administrator from group from #{object.url}"
|
"Checking if activity actor #{actor_url} is an administrator from group from #{object.url}"
|
||||||
)
|
)
|
||||||
|
|
||||||
Actors.is_administrator?(actor_id, group_id)
|
Actors.administrator?(actor_id, group_id)
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
Logger.debug(
|
Logger.debug(
|
||||||
"Checking if activity actor #{actor_url} is a member from group from #{object.url}"
|
"Checking if activity actor #{actor_url} is a member from group from #{object.url}"
|
||||||
)
|
)
|
||||||
|
|
||||||
Actors.is_member?(actor_id, group_id)
|
Actors.member?(actor_id, group_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -21,10 +21,10 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do
|
||||||
Logger.debug("Publishing an activity")
|
Logger.debug("Publishing an activity")
|
||||||
Logger.debug(inspect(activity, pretty: true))
|
Logger.debug(inspect(activity, pretty: true))
|
||||||
|
|
||||||
public = Visibility.is_public?(activity)
|
public = Visibility.public?(activity)
|
||||||
Logger.debug("is public ? #{public}")
|
Logger.debug("is public ? #{public}")
|
||||||
|
|
||||||
if public && is_create_activity?(activity) && Config.get([:instance, :allow_relay]) do
|
if public && create_activity?(activity) && Config.get([:instance, :allow_relay]) do
|
||||||
Logger.info(fn -> "Relaying #{activity.data["id"]} out" end)
|
Logger.info(fn -> "Relaying #{activity.data["id"]} out" end)
|
||||||
|
|
||||||
Relay.publish(activity)
|
Relay.publish(activity)
|
||||||
|
@ -125,9 +125,9 @@ defmodule Mobilizon.Federation.ActivityPub.Publisher do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_create_activity?(Activity.t()) :: boolean
|
@spec create_activity?(Activity.t()) :: boolean
|
||||||
defp is_create_activity?(%Activity{data: %{"type" => "Create"}}), do: true
|
defp create_activity?(%Activity{data: %{"type" => "Create"}}), do: true
|
||||||
defp is_create_activity?(_), do: false
|
defp create_activity?(_), do: false
|
||||||
|
|
||||||
@spec convert_members_in_recipients(list(String.t())) :: {list(String.t()), list(Actor.t())}
|
@spec convert_members_in_recipients(list(String.t())) :: {list(String.t()), list(Actor.t())}
|
||||||
defp convert_members_in_recipients(recipients) do
|
defp convert_members_in_recipients(recipients) do
|
||||||
|
|
|
@ -285,7 +285,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
object_data when is_map(object_data) <-
|
object_data when is_map(object_data) <-
|
||||||
object |> Converter.Resource.as_to_model_data(),
|
object |> Converter.Resource.as_to_model_data(),
|
||||||
{:member, true} <-
|
{:member, true} <-
|
||||||
{:member, Actors.is_member?(object_data.creator_id, object_data.actor_id)},
|
{:member, Actors.member?(object_data.creator_id, object_data.actor_id)},
|
||||||
{:ok, %Activity{} = activity, %Resource{} = resource} <-
|
{:ok, %Activity{} = activity, %Resource{} = resource} <-
|
||||||
Actions.Create.create(:resource, object_data, false) do
|
Actions.Create.create(:resource, object_data, false) do
|
||||||
{:ok, activity, resource}
|
{:ok, activity, resource}
|
||||||
|
@ -1005,14 +1005,14 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
|
|
||||||
# Comment initiates a whole discussion only if it has full title
|
# Comment initiates a whole discussion only if it has full title
|
||||||
@spec is_data_for_comment_or_discussion?(map()) :: boolean()
|
@spec data_for_comment_or_discussion?(map()) :: boolean()
|
||||||
defp is_data_for_comment_or_discussion?(object_data) do
|
defp data_for_comment_or_discussion?(object_data) do
|
||||||
is_data_a_discussion_initialization?(object_data) and
|
data_a_discussion_initialization?(object_data) and
|
||||||
is_nil(object_data.discussion_id)
|
is_nil(object_data.discussion_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Comment initiates a whole discussion only if it has full title
|
# Comment initiates a whole discussion only if it has full title
|
||||||
defp is_data_a_discussion_initialization?(object_data) do
|
defp data_a_discussion_initialization?(object_data) do
|
||||||
not Map.has_key?(object_data, :title) or
|
not Map.has_key?(object_data, :title) or
|
||||||
is_nil(object_data.title) or object_data.title == ""
|
is_nil(object_data.title) or object_data.title == ""
|
||||||
end
|
end
|
||||||
|
@ -1034,7 +1034,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
@spec transform_object_data_for_discussion(map()) :: map()
|
@spec transform_object_data_for_discussion(map()) :: map()
|
||||||
defp transform_object_data_for_discussion(object_data) do
|
defp transform_object_data_for_discussion(object_data) do
|
||||||
# Basic comment
|
# Basic comment
|
||||||
if is_data_a_discussion_initialization?(object_data) do
|
if data_a_discussion_initialization?(object_data) do
|
||||||
object_data
|
object_data
|
||||||
else
|
else
|
||||||
# Conversation
|
# Conversation
|
||||||
|
@ -1138,8 +1138,8 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_group_object_gone(object_id) do
|
defp group_object_gone_check(object_id) do
|
||||||
Logger.debug("is_group_object_gone #{object_id}")
|
Logger.debug("Checking if group object #{object_id} is gone")
|
||||||
|
|
||||||
case ActivityPub.fetch_object_from_url(object_id, force: true) do
|
case ActivityPub.fetch_object_from_url(object_id, force: true) do
|
||||||
# comments are just emptied
|
# comments are just emptied
|
||||||
|
@ -1163,14 +1163,10 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Before 1.0.4 the object of a "Remove" activity was an actor's URL
|
|
||||||
# instead of the member's URL.
|
|
||||||
# TODO: Remove in 1.2
|
|
||||||
@spec get_remove_object(map() | String.t()) :: {:ok, integer()}
|
@spec get_remove_object(map() | String.t()) :: {:ok, integer()}
|
||||||
defp get_remove_object(object) do
|
defp get_remove_object(object) do
|
||||||
case object |> Utils.get_url() |> ActivityPub.fetch_object_from_url() do
|
case object |> Utils.get_url() |> ActivityPub.fetch_object_from_url() do
|
||||||
{:ok, %Member{actor: %Actor{id: person_id}}} -> {:ok, person_id}
|
{:ok, %Member{actor: %Actor{id: person_id}}} -> {:ok, person_id}
|
||||||
{:ok, %Actor{id: person_id}} -> {:ok, person_id}
|
|
||||||
_ -> {:error, :remove_object_not_found}
|
_ -> {:error, :remove_object_not_found}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1196,7 +1192,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
@spec create_comment_or_discussion(map()) ::
|
@spec create_comment_or_discussion(map()) ::
|
||||||
{:ok, Activity.t(), struct()} | {:error, atom() | Ecto.Changeset.t()}
|
{:ok, Activity.t(), struct()} | {:error, atom() | Ecto.Changeset.t()}
|
||||||
defp create_comment_or_discussion(object_data) do
|
defp create_comment_or_discussion(object_data) do
|
||||||
if is_data_for_comment_or_discussion?(object_data) do
|
if data_for_comment_or_discussion?(object_data) do
|
||||||
Logger.debug("Chosing to create a regular comment")
|
Logger.debug("Chosing to create a regular comment")
|
||||||
Actions.Create.create(:comment, object_data, false)
|
Actions.Create.create(:comment, object_data, false)
|
||||||
else
|
else
|
||||||
|
@ -1248,7 +1244,7 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_group_being_gone(actor, actor_url, object_id) do
|
defp handle_group_being_gone(actor, actor_url, object_id) do
|
||||||
case is_group_object_gone(object_id) do
|
case group_object_gone_check(object_id) do
|
||||||
# The group object is no longer there, we can remove the element
|
# The group object is no longer there, we can remove the element
|
||||||
{:ok, entity} ->
|
{:ok, entity} ->
|
||||||
if Utils.origin_check_from_id?(actor_url, object_id) ||
|
if Utils.origin_check_from_id?(actor_url, object_id) ||
|
||||||
|
|
|
@ -93,7 +93,7 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Members do
|
||||||
atom()
|
atom()
|
||||||
) :: boolean
|
) :: boolean
|
||||||
defp check_admins_left?(member_id, group_id, current_role, updated_role) do
|
defp check_admins_left?(member_id, group_id, current_role, updated_role) do
|
||||||
Actors.is_only_administrator?(member_id, group_id) && current_role == :administrator &&
|
Actors.only_administrator?(member_id, group_id) && current_role == :administrator &&
|
||||||
updated_role != :administrator
|
updated_role != :administrator
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,17 +14,17 @@ defmodule Mobilizon.Federation.ActivityPub.Visibility do
|
||||||
|
|
||||||
@public "https://www.w3.org/ns/activitystreams#Public"
|
@public "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
||||||
@spec is_public?(Activity.t() | map()) :: boolean()
|
@spec public?(Activity.t() | map()) :: boolean()
|
||||||
def is_public?(%{data: %{"type" => "Tombstone"}}), do: false
|
def public?(%{data: %{"type" => "Tombstone"}}), do: false
|
||||||
def is_public?(%{data: data}), do: is_public?(data)
|
def public?(%{data: data}), do: public?(data)
|
||||||
def is_public?(%Activity{data: data}), do: is_public?(data)
|
def public?(%Activity{data: data}), do: public?(data)
|
||||||
|
|
||||||
def is_public?(data) when is_map(data) do
|
def public?(data) when is_map(data) do
|
||||||
@public in make_list(Map.get(data, "to", []))
|
@public in make_list(Map.get(data, "to", []))
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_public?(%Comment{deleted_at: deleted_at}), do: !is_nil(deleted_at)
|
def public?(%Comment{deleted_at: deleted_at}), do: !is_nil(deleted_at)
|
||||||
def is_public?(err), do: raise(ArgumentError, message: "Invalid argument #{inspect(err)}")
|
def public?(err), do: raise(ArgumentError, message: "Invalid argument #{inspect(err)}")
|
||||||
|
|
||||||
defp make_list(data) when is_list(data), do: data
|
defp make_list(data) when is_list(data), do: data
|
||||||
defp make_list(data), do: [data]
|
defp make_list(data), do: [data]
|
||||||
|
|
|
@ -76,14 +76,13 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Actor do
|
||||||
def as_to_model_data(_), do: {:error, :actor_not_allowed_type}
|
def as_to_model_data(_), do: {:error, :actor_not_allowed_type}
|
||||||
|
|
||||||
defp add_endpoints_to_model(actor, data) do
|
defp add_endpoints_to_model(actor, data) do
|
||||||
# TODO: Remove fallbacks in 3.0
|
|
||||||
endpoints = %{
|
endpoints = %{
|
||||||
members_url: get_in(data, ["endpoints", "members"]) || data["members"],
|
members_url: get_in(data, ["endpoints", "members"]),
|
||||||
resources_url: get_in(data, ["endpoints", "resources"]) || data["resources"],
|
resources_url: get_in(data, ["endpoints", "resources"]),
|
||||||
todos_url: get_in(data, ["endpoints", "todos"]) || data["todos"],
|
todos_url: get_in(data, ["endpoints", "todos"]),
|
||||||
events_url: get_in(data, ["endpoints", "events"]) || data["events"],
|
events_url: get_in(data, ["endpoints", "events"]),
|
||||||
posts_url: get_in(data, ["endpoints", "posts"]) || data["posts"],
|
posts_url: get_in(data, ["endpoints", "posts"]),
|
||||||
discussions_url: get_in(data, ["endpoints", "discussions"]) || data["discussions"],
|
discussions_url: get_in(data, ["endpoints", "discussions"]),
|
||||||
shared_inbox_url: data["endpoints"]["sharedInbox"]
|
shared_inbox_url: data["endpoints"]["sharedInbox"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Comment do
|
||||||
tags: fetch_tags(tag_object),
|
tags: fetch_tags(tag_object),
|
||||||
mentions: fetch_mentions(tag_object),
|
mentions: fetch_mentions(tag_object),
|
||||||
local: is_nil(actor_domain),
|
local: is_nil(actor_domain),
|
||||||
visibility: if(Visibility.is_public?(object), do: :public, else: :private),
|
visibility: if(Visibility.public?(object), do: :public, else: :private),
|
||||||
published_at: object["published"],
|
published_at: object["published"],
|
||||||
is_announcement: Map.get(object, "isAnnouncement", false)
|
is_announcement: Map.get(object, "isAnnouncement", false)
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
category: Categories.get_category(object["category"]),
|
category: Categories.get_category(object["category"]),
|
||||||
visibility: visibility,
|
visibility: visibility,
|
||||||
join_options: Map.get(object, "joinMode", "free"),
|
join_options: Map.get(object, "joinMode", "free"),
|
||||||
local: is_local?(object["id"]),
|
local: local?(object["id"]),
|
||||||
external_participation_url: object["externalParticipationUrl"],
|
external_participation_url: object["externalParticipationUrl"],
|
||||||
options: options,
|
options: options,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
@ -305,8 +305,8 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_local?(String.t()) :: boolean()
|
@spec local?(String.t()) :: boolean()
|
||||||
defp is_local?(url) do
|
defp local?(url) do
|
||||||
%URI{host: url_domain} = URI.parse(url)
|
%URI{host: url_domain} = URI.parse(url)
|
||||||
%URI{host: local_domain} = URI.parse(Endpoint.url())
|
%URI{host: local_domain} = URI.parse(Endpoint.url())
|
||||||
url_domain == local_domain
|
url_domain == local_domain
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule Mobilizon.Federation.NodeInfo do
|
||||||
|
|
||||||
alias Mobilizon.Service.HTTP.WebfingerClient
|
alias Mobilizon.Service.HTTP.WebfingerClient
|
||||||
require Logger
|
require Logger
|
||||||
import Mobilizon.Service.HTTP.Utils, only: [is_content_type?: 2]
|
import Mobilizon.Service.HTTP.Utils, only: [content_type_matches?: 2]
|
||||||
|
|
||||||
@application_uri "https://www.w3.org/ns/activitystreams#Application"
|
@application_uri "https://www.w3.org/ns/activitystreams#Application"
|
||||||
@nodeinfo_rel_2_0 "http://nodeinfo.diaspora.software/ns/schema/2.0"
|
@nodeinfo_rel_2_0 "http://nodeinfo.diaspora.software/ns/schema/2.0"
|
||||||
|
@ -110,7 +110,7 @@ defmodule Mobilizon.Federation.NodeInfo do
|
||||||
{:ok, String.t()} | {:error, :bad_content_type | :body_not_json}
|
{:ok, String.t()} | {:error, :bad_content_type | :body_not_json}
|
||||||
defp validate_json_response(body, headers) do
|
defp validate_json_response(body, headers) do
|
||||||
cond do
|
cond do
|
||||||
!is_content_type?(headers, "application/json") ->
|
!content_type_matches?(headers, "application/json") ->
|
||||||
{:error, :bad_content_type}
|
{:error, :bad_content_type}
|
||||||
|
|
||||||
!is_map(body) ->
|
!is_map(body) ->
|
||||||
|
|
|
@ -25,8 +25,8 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
# Some URLs could be domain.tld/@username, so keep this condition above
|
# Some URLs could be domain.tld/@username, so keep this condition above
|
||||||
# the `is_handle` function
|
# the `handle?` function
|
||||||
is_url(term) ->
|
url?(term) ->
|
||||||
# skip, if it's not an actor
|
# skip, if it's not an actor
|
||||||
case process_from_url(term) do
|
case process_from_url(term) do
|
||||||
%Page{total: _total, elements: [%Actor{} = _actor]} = page ->
|
%Page{total: _total, elements: [%Actor{} = _actor]} = page ->
|
||||||
|
@ -36,11 +36,11 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
{:ok, %{total: 0, elements: []}}
|
{:ok, %{total: 0, elements: []}}
|
||||||
end
|
end
|
||||||
|
|
||||||
is_handle(term) ->
|
handle?(term) ->
|
||||||
{:ok, process_from_username(term)}
|
{:ok, process_from_username(term)}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
if is_global_search(args) do
|
if global_search?(args) do
|
||||||
service = GlobalSearch.service()
|
service = GlobalSearch.service()
|
||||||
|
|
||||||
{:ok, service.search_groups(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
{:ok, service.search_groups(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
||||||
|
@ -75,7 +75,7 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
def search_events(%{term: term} = args, page \\ 1, limit \\ 10) do
|
def search_events(%{term: term} = args, page \\ 1, limit \\ 10) do
|
||||||
term = String.trim(term)
|
term = String.trim(term)
|
||||||
|
|
||||||
if is_url(term) do
|
if url?(term) do
|
||||||
# skip, if it's not an event
|
# skip, if it's not an event
|
||||||
case process_from_url(term) do
|
case process_from_url(term) do
|
||||||
%Page{total: _total, elements: [%Event{} = event]} = page ->
|
%Page{total: _total, elements: [%Event{} = event]} = page ->
|
||||||
|
@ -89,7 +89,7 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
{:ok, %{total: 0, elements: []}}
|
{:ok, %{total: 0, elements: []}}
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if is_global_search(args) do
|
if global_search?(args) do
|
||||||
service = GlobalSearch.service()
|
service = GlobalSearch.service()
|
||||||
|
|
||||||
{:ok, service.search_events(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
{:ok, service.search_events(Keyword.new(args, fn {k, v} -> {k, v} end))}
|
||||||
|
@ -140,17 +140,17 @@ defmodule Mobilizon.GraphQL.API.Search do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_url(String.t()) :: boolean
|
@spec url?(String.t()) :: boolean
|
||||||
defp is_url(search), do: String.starts_with?(search, ["http://", "https://"])
|
defp url?(search), do: String.starts_with?(search, ["http://", "https://"])
|
||||||
|
|
||||||
@spec is_handle(String.t()) :: boolean
|
@spec handle?(String.t()) :: boolean
|
||||||
defp is_handle(search), do: String.match?(search, ~r/@/)
|
defp handle?(search), do: String.match?(search, ~r/@/)
|
||||||
|
|
||||||
defp is_global_search(%{search_target: :global}) do
|
defp global_search?(%{search_target: :global}) do
|
||||||
global_search_enabled?()
|
global_search_enabled?()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_global_search(_), do: global_search_enabled?() && global_search_default?()
|
defp global_search?(_), do: global_search_enabled?() && global_search_default?()
|
||||||
|
|
||||||
defp global_search_enabled? do
|
defp global_search_enabled? do
|
||||||
Application.get_env(:mobilizon, :search) |> get_in([:global]) |> get_in([:is_enabled])
|
Application.get_env(:mobilizon, :search) |> get_in([:global]) |> get_in([:is_enabled])
|
||||||
|
|
|
@ -68,6 +68,6 @@ defmodule Mobilizon.GraphQL.API.Utils do
|
||||||
|
|
||||||
@spec check_actor_owns_media?(integer() | String.t(), integer() | String.t()) :: boolean()
|
@spec check_actor_owns_media?(integer() | String.t(), integer() | String.t()) :: boolean()
|
||||||
defp check_actor_owns_media?(actor_id, media_actor_id) do
|
defp check_actor_owns_media?(actor_id, media_actor_id) do
|
||||||
actor_id == media_actor_id || Mobilizon.Actors.is_member?(media_actor_id, actor_id)
|
actor_id == media_actor_id || Mobilizon.Actors.member?(media_actor_id, actor_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,8 +5,8 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
alias __MODULE__
|
alias __MODULE__
|
||||||
alias Mobilizon.Web.Gettext, as: GettextBackend
|
|
||||||
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
import Mobilizon.Web.Gettext, only: [dgettext: 2]
|
||||||
|
import Mobilizon.Storage.Ecto, only: [convert_ecto_errors: 1]
|
||||||
|
|
||||||
@type t :: %{code: atom(), message: String.t(), status_code: pos_integer(), field: atom()}
|
@type t :: %{code: atom(), message: String.t(), status_code: pos_integer(), field: atom()}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
|
|
||||||
defp handle(%Ecto.Changeset{} = changeset) do
|
defp handle(%Ecto.Changeset{} = changeset) do
|
||||||
changeset
|
changeset
|
||||||
|> Ecto.Changeset.traverse_errors(&translate_error/1)
|
|> convert_ecto_errors()
|
||||||
|> Enum.map(fn {k, v} ->
|
|> Enum.map(fn {k, v} ->
|
||||||
%Error{
|
%Error{
|
||||||
code: :validation,
|
code: :validation,
|
||||||
|
@ -126,27 +126,4 @@ defmodule Mobilizon.GraphQL.Error do
|
||||||
Logger.warning("Unhandled error code: #{inspect(code)}")
|
Logger.warning("Unhandled error code: #{inspect(code)}")
|
||||||
{422, to_string(code)}
|
{422, to_string(code)}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Translates an error message using gettext.
|
|
||||||
defp translate_error({msg, opts}) do
|
|
||||||
# Because error messages were defined within Ecto, we must
|
|
||||||
# call the Gettext module passing our Gettext backend. We
|
|
||||||
# also use the "errors" domain as translations are placed
|
|
||||||
# in the errors.po file.
|
|
||||||
# Ecto will pass the :count keyword if the error message is
|
|
||||||
# meant to be pluralized.
|
|
||||||
# On your own code and templates, depending on whether you
|
|
||||||
# need the message to be pluralized or not, this could be
|
|
||||||
# written simply as:
|
|
||||||
#
|
|
||||||
# dngettext "errors", "1 file", "%{count} files", count
|
|
||||||
# dgettext "errors", "is invalid"
|
|
||||||
#
|
|
||||||
|
|
||||||
if count = opts[:count] do
|
|
||||||
Gettext.dngettext(GettextBackend, "errors", msg, msg, count, opts)
|
|
||||||
else
|
|
||||||
Gettext.dgettext(GettextBackend, "errors", msg, opts)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Activity do
|
||||||
def group_activity(%Actor{type: :Group, id: group_id}, %{page: page, limit: limit} = args, %{
|
def group_activity(%Actor{type: :Group, id: group_id}, %{page: page, limit: limit} = args, %{
|
||||||
context: %{current_user: %User{role: role}, current_actor: %Actor{id: actor_id}}
|
context: %{current_user: %User{role: role}, current_actor: %Actor{id: actor_id}}
|
||||||
}) do
|
}) do
|
||||||
if Actors.is_member?(actor_id, group_id) or is_moderator(role) do
|
if Actors.member?(actor_id, group_id) or is_moderator(role) do
|
||||||
%Page{total: total, elements: elements} =
|
%Page{total: total, elements: elements} =
|
||||||
Activities.list_group_activities_for_member(
|
Activities.list_group_activities_for_member(
|
||||||
group_id,
|
group_id,
|
||||||
|
|
|
@ -26,7 +26,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
when not is_nil(attributed_to_id) do
|
when not is_nil(attributed_to_id) do
|
||||||
if Actors.is_member?(actor_id, attributed_to_id) do
|
if Actors.member?(actor_id, attributed_to_id) do
|
||||||
{:ok,
|
{:ok,
|
||||||
event_id
|
event_id
|
||||||
|> Conversations.find_conversations_for_event(attributed_to_id, page, limit)
|
|> Conversations.find_conversations_for_event(attributed_to_id, page, limit)
|
||||||
|
@ -103,7 +103,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
|
||||||
{:error, :not_found}
|
{:error, :not_found}
|
||||||
|
|
||||||
%ConversationParticipant{actor_id: actor_id} = conversation_participant ->
|
%ConversationParticipant{actor_id: actor_id} = conversation_participant ->
|
||||||
if actor_id == performing_actor_id or Actors.is_member?(performing_actor_id, actor_id) do
|
if actor_id == performing_actor_id or Actors.member?(performing_actor_id, actor_id) do
|
||||||
{:ok, conversation_participant_to_view(conversation_participant)}
|
{:ok, conversation_participant_to_view(conversation_participant)}
|
||||||
else
|
else
|
||||||
{:error, :not_found}
|
{:error, :not_found}
|
||||||
|
@ -121,7 +121,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
if conversation_actor_id == performing_actor_id or
|
if conversation_actor_id == performing_actor_id or
|
||||||
Actors.is_member?(performing_actor_id, conversation_actor_id) do
|
Actors.member?(performing_actor_id, conversation_actor_id) do
|
||||||
{:ok,
|
{:ok,
|
||||||
Mobilizon.Discussions.get_comments_in_reply_to_comment_id(origin_comment_id, page, limit)}
|
Mobilizon.Discussions.get_comments_in_reply_to_comment_id(origin_comment_id, page, limit)}
|
||||||
else
|
else
|
||||||
|
@ -184,7 +184,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
|
||||||
{:valid_actor, true} <-
|
{:valid_actor, true} <-
|
||||||
{:valid_actor,
|
{:valid_actor,
|
||||||
actor_id == current_actor_id or
|
actor_id == current_actor_id or
|
||||||
Actors.is_member?(current_actor_id, actor_id)},
|
Actors.member?(current_actor_id, actor_id)},
|
||||||
{:ok, %ConversationParticipant{} = conversation_participant} <-
|
{:ok, %ConversationParticipant{} = conversation_participant} <-
|
||||||
Conversations.update_conversation_participant(conversation_participant, %{
|
Conversations.update_conversation_participant(conversation_participant, %{
|
||||||
unread: !read
|
unread: !read
|
||||||
|
@ -269,7 +269,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Conversation do
|
||||||
|
|
||||||
to_string(current_actor_id) in participant_ids or
|
to_string(current_actor_id) in participant_ids or
|
||||||
Enum.any?(participant_ids, fn participant_id ->
|
Enum.any?(participant_ids, fn participant_id ->
|
||||||
Actors.is_member?(current_actor_id, participant_id) and
|
Actors.member?(current_actor_id, participant_id) and
|
||||||
attributed_to_id == participant_id
|
attributed_to_id == participant_id
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, %Actor{type: :Group} = group} <- Actors.get_group_by_actor_id(group_id) do
|
{:ok, %Actor{type: :Group} = group} <- Actors.get_group_by_actor_id(group_id) do
|
||||||
{:ok, Discussions.find_discussions_for_actor(group, page, limit)}
|
{:ok, Discussions.find_discussions_for_actor(group, page, limit)}
|
||||||
else
|
else
|
||||||
|
@ -45,7 +45,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}) do
|
}) do
|
||||||
case Discussions.get_discussion(id) do
|
case Discussions.get_discussion(id) do
|
||||||
%Discussion{actor_id: actor_id} = discussion ->
|
%Discussion{actor_id: actor_id} = discussion ->
|
||||||
if Actors.is_member?(creator_id, actor_id) do
|
if Actors.member?(creator_id, actor_id) do
|
||||||
{:ok, discussion}
|
{:ok, discussion}
|
||||||
else
|
else
|
||||||
{:error, :unauthorized}
|
{:error, :unauthorized}
|
||||||
|
@ -63,7 +63,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}) do
|
}) do
|
||||||
with %Discussion{actor_id: actor_id} = discussion <-
|
with %Discussion{actor_id: actor_id} = discussion <-
|
||||||
Discussions.get_discussion_by_slug(slug),
|
Discussions.get_discussion_by_slug(slug),
|
||||||
{:member, true} <- {:member, Actors.is_member?(creator_id, actor_id)} do
|
{:member, true} <- {:member, Actors.member?(creator_id, actor_id)} do
|
||||||
{:ok, discussion}
|
{:ok, discussion}
|
||||||
else
|
else
|
||||||
nil -> {:error, dgettext("errors", "Discussion not found")}
|
nil -> {:error, dgettext("errors", "Discussion not found")}
|
||||||
|
@ -105,7 +105,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
if Actors.is_member?(creator_id, group_id) do
|
if Actors.member?(creator_id, group_id) do
|
||||||
case Comments.create_discussion(%{
|
case Comments.create_discussion(%{
|
||||||
title: title,
|
title: title,
|
||||||
text: text,
|
text: text,
|
||||||
|
@ -150,7 +150,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}
|
}
|
||||||
} = _discussion} <-
|
} = _discussion} <-
|
||||||
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(creator_id, actor_id)},
|
{:member, true} <- {:member, Actors.member?(creator_id, actor_id)},
|
||||||
{:ok, _activity, %Discussion{} = discussion} <-
|
{:ok, _activity, %Discussion{} = discussion} <-
|
||||||
Comments.create_discussion(%{
|
Comments.create_discussion(%{
|
||||||
text: text,
|
text: text,
|
||||||
|
@ -183,7 +183,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
) do
|
) do
|
||||||
with {:no_discussion, %Discussion{actor_id: actor_id} = discussion} <-
|
with {:no_discussion, %Discussion{actor_id: actor_id} = discussion} <-
|
||||||
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(creator_id, actor_id)},
|
{:member, true} <- {:member, Actors.member?(creator_id, actor_id)},
|
||||||
{:ok, _activity, %Discussion{} = discussion} <-
|
{:ok, _activity, %Discussion{} = discussion} <-
|
||||||
Actions.Update.update(
|
Actions.Update.update(
|
||||||
discussion,
|
discussion,
|
||||||
|
@ -213,7 +213,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Discussion do
|
||||||
}) do
|
}) do
|
||||||
with {:no_discussion, %Discussion{actor_id: actor_id} = discussion} <-
|
with {:no_discussion, %Discussion{actor_id: actor_id} = discussion} <-
|
||||||
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
{:no_discussion, Discussions.get_discussion(discussion_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(creator_id, actor_id)},
|
{:member, true} <- {:member, Actors.member?(creator_id, actor_id)},
|
||||||
{:ok, _activity, %Discussion{} = discussion} <-
|
{:ok, _activity, %Discussion{} = discussion} <-
|
||||||
Actions.Delete.delete(discussion, actor) do
|
Actions.Delete.delete(discussion, actor) do
|
||||||
{:ok, discussion}
|
{:ok, discussion}
|
||||||
|
|
|
@ -36,7 +36,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||||
when not is_nil(attributed_to_id) do
|
when not is_nil(attributed_to_id) do
|
||||||
with %Actor{id: group_id} <- Actors.get_actor(attributed_to_id),
|
with %Actor{id: group_id} <- Actors.get_actor(attributed_to_id),
|
||||||
{:member, true} <-
|
{:member, true} <-
|
||||||
{:member, Actors.is_member?(actor_id, group_id) or is_moderator(user_role)},
|
{:member, Actors.member?(actor_id, group_id) or is_moderator(user_role)},
|
||||||
%Actor{} = actor <- Actors.get_actor(organizer_actor_id) do
|
%Actor{} = actor <- Actors.get_actor(organizer_actor_id) do
|
||||||
{:ok, actor}
|
{:ok, actor}
|
||||||
else
|
else
|
||||||
|
@ -176,7 +176,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||||
_args,
|
_args,
|
||||||
%{context: %{current_user: %User{id: user_id} = _user}} = _resolution
|
%{context: %{current_user: %User{id: user_id} = _user}} = _resolution
|
||||||
) do
|
) do
|
||||||
if Events.is_user_moderator_for_event?(user_id, event_id) do
|
if Events.user_moderator_for_event?(user_id, event_id) do
|
||||||
{:ok,
|
{:ok,
|
||||||
Map.put(
|
Map.put(
|
||||||
stats,
|
stats,
|
||||||
|
@ -256,7 +256,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||||
{:can_create_event, true} <- can_create_event(args),
|
{:can_create_event, true} <- can_create_event(args),
|
||||||
{:event_external, true} <- edit_event_external_checker(args),
|
{:event_external, true} <- edit_event_external_checker(args),
|
||||||
{:organizer_group_member, true} <-
|
{:organizer_group_member, true} <-
|
||||||
{:organizer_group_member, is_organizer_group_member?(args)},
|
{:organizer_group_member, organizer_group_member?(args)},
|
||||||
args_with_organizer <-
|
args_with_organizer <-
|
||||||
args |> Map.put(:organizer_actor, organizer_actor) |> extract_timezone(user.id),
|
args |> Map.put(:organizer_actor, organizer_actor) |> extract_timezone(user.id),
|
||||||
{:askismet, :ham} <-
|
{:askismet, :ham} <-
|
||||||
|
@ -447,17 +447,17 @@ defmodule Mobilizon.GraphQL.Resolvers.Event do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_organizer_group_member?(map()) :: boolean()
|
@spec organizer_group_member?(map()) :: boolean()
|
||||||
defp is_organizer_group_member?(%{
|
defp organizer_group_member?(%{
|
||||||
attributed_to_id: attributed_to_id,
|
attributed_to_id: attributed_to_id,
|
||||||
organizer_actor_id: organizer_actor_id
|
organizer_actor_id: organizer_actor_id
|
||||||
})
|
})
|
||||||
when not is_nil(attributed_to_id) do
|
when not is_nil(attributed_to_id) do
|
||||||
Actors.is_member?(organizer_actor_id, attributed_to_id) &&
|
Actors.member?(organizer_actor_id, attributed_to_id) &&
|
||||||
Permission.can_create_group_object?(organizer_actor_id, attributed_to_id, %Event{})
|
Permission.can_create_group_object?(organizer_actor_id, attributed_to_id, %Event{})
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_organizer_group_member?(_), do: true
|
defp organizer_group_member?(_), do: true
|
||||||
|
|
||||||
@spec verify_profile_change(map(), Event.t(), User.t(), Actor.t()) :: {:ok, map()}
|
@spec verify_profile_change(map(), Event.t(), User.t(), Actor.t()) :: {:ok, map()}
|
||||||
defp verify_profile_change(
|
defp verify_profile_change(
|
||||||
|
|
|
@ -23,7 +23,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Followers do
|
||||||
) do
|
) do
|
||||||
followers = group_followers(group, args)
|
followers = group_followers(group, args)
|
||||||
|
|
||||||
if Actors.is_moderator?(actor_id, group_id) or is_moderator(user_role) do
|
if Actors.moderator?(actor_id, group_id) or is_moderator(user_role) do
|
||||||
{:ok, followers}
|
{:ok, followers}
|
||||||
else
|
else
|
||||||
{:ok, %Page{followers | elements: []}}
|
{:ok, %Page{followers | elements: []}}
|
||||||
|
@ -48,7 +48,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Followers do
|
||||||
with %Follower{target_actor: %Actor{type: :Group, id: group_id}} = follower <-
|
with %Follower{target_actor: %Actor{type: :Group, id: group_id}} = follower <-
|
||||||
Actors.get_follower(follower_id),
|
Actors.get_follower(follower_id),
|
||||||
{:member, true} <-
|
{:member, true} <-
|
||||||
{:member, Actors.is_moderator?(actor_id, group_id)},
|
{:member, Actors.moderator?(actor_id, group_id)},
|
||||||
{:ok, _activity, %Follower{} = follower} <-
|
{:ok, _activity, %Follower{} = follower} <-
|
||||||
(if approved do
|
(if approved do
|
||||||
Actions.Accept.accept(:follow, follower)
|
Actions.Accept.accept(:follow, follower)
|
||||||
|
|
|
@ -36,7 +36,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
) do
|
) do
|
||||||
case ActivityPubActor.find_or_make_group_from_nickname(name) do
|
case ActivityPubActor.find_or_make_group_from_nickname(name) do
|
||||||
{:ok, %Actor{id: group_id, suspended: false} = group} ->
|
{:ok, %Actor{id: group_id, suspended: false} = group} ->
|
||||||
if Actors.is_member?(actor_id, group_id) do
|
if Actors.member?(actor_id, group_id) do
|
||||||
{:ok, group}
|
{:ok, group}
|
||||||
else
|
else
|
||||||
find_group(parent, args, nil)
|
find_group(parent, args, nil)
|
||||||
|
@ -72,7 +72,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
}
|
}
|
||||||
}) do
|
}) do
|
||||||
with %Actor{suspended: false, id: group_id} = group <- Actors.get_actor_with_preload(id),
|
with %Actor{suspended: false, id: group_id} = group <- Actors.get_actor_with_preload(id),
|
||||||
true <- Actors.is_member?(actor_id, group_id) do
|
true <- Actors.member?(actor_id, group_id) do
|
||||||
{:ok, group}
|
{:ok, group}
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -215,7 +215,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
if Actors.is_administrator?(updater_actor.id, group_id) do
|
if Actors.administrator?(updater_actor.id, group_id) do
|
||||||
args = Map.put(args, :updater_actor, updater_actor)
|
args = Map.put(args, :updater_actor, updater_actor)
|
||||||
|
|
||||||
case save_attached_pictures(args) do
|
case save_attached_pictures(args) do
|
||||||
|
@ -265,7 +265,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
) do
|
) do
|
||||||
with {:ok, %Actor{} = group} <- Actors.get_group_by_actor_id(group_id),
|
with {:ok, %Actor{} = group} <- Actors.get_group_by_actor_id(group_id),
|
||||||
{:ok, %Member{} = member} <- Actors.get_member(actor_id, group.id),
|
{:ok, %Member{} = member} <- Actors.get_member(actor_id, group.id),
|
||||||
{:is_admin, true} <- {:is_admin, Member.is_administrator(member)},
|
{:is_admin, true} <- {:is_admin, Member.administrator?(member)},
|
||||||
{:ok, _activity, group} <- Actions.Delete.delete(group, actor, true) do
|
{:ok, _activity, group} <- Actions.Delete.delete(group, actor, true) do
|
||||||
{:ok, %{id: group.id}}
|
{:ok, %{id: group.id}}
|
||||||
else
|
else
|
||||||
|
@ -448,7 +448,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Group do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) do
|
) do
|
||||||
if Actors.is_member?(actor_id, group_id) do
|
if Actors.member?(actor_id, group_id) do
|
||||||
{:ok,
|
{:ok,
|
||||||
Events.list_organized_events_for_group(
|
Events.list_organized_events_for_group(
|
||||||
group,
|
group,
|
||||||
|
|
|
@ -26,7 +26,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Member do
|
||||||
context: %{current_user: %User{role: user_role}, current_actor: %Actor{id: actor_id}}
|
context: %{current_user: %User{role: user_role}, current_actor: %Actor{id: actor_id}}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
if Actors.is_member?(actor_id, group_id) or is_moderator(user_role) do
|
if Actors.member?(actor_id, group_id) or is_moderator(user_role) do
|
||||||
roles =
|
roles =
|
||||||
case roles do
|
case roles do
|
||||||
"" ->
|
"" ->
|
||||||
|
|
|
@ -384,7 +384,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Participant do
|
||||||
with {:member, true} <-
|
with {:member, true} <-
|
||||||
{:member,
|
{:member,
|
||||||
to_string(current_actor_id) == to_string(actor_id) or
|
to_string(current_actor_id) == to_string(actor_id) or
|
||||||
Actors.is_member?(current_actor_id, actor_id)},
|
Actors.member?(current_actor_id, actor_id)},
|
||||||
{:ok, _activity, %Conversation{} = conversation} <- Comments.create_conversation(args) do
|
{:ok, _activity, %Conversation{} = conversation} <- Comments.create_conversation(args) do
|
||||||
{:ok, conversation_to_view(conversation, Actors.get_actor(actor_id))}
|
{:ok, conversation_to_view(conversation, Actors.get_actor(actor_id))}
|
||||||
else
|
else
|
||||||
|
|
|
@ -32,7 +32,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
|
||||||
}
|
}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
if Actors.is_member?(actor_id, group_id) or is_moderator(user_role) do
|
if Actors.member?(actor_id, group_id) or is_moderator(user_role) do
|
||||||
%Page{} = page = Posts.get_posts_for_group(group, page, limit)
|
%Page{} = page = Posts.get_posts_for_group(group, page, limit)
|
||||||
{:ok, page}
|
{:ok, page}
|
||||||
else
|
else
|
||||||
|
@ -111,7 +111,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
|
||||||
}
|
}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
%Actor{} = group <- Actors.get_actor(group_id),
|
%Actor{} = group <- Actors.get_actor(group_id),
|
||||||
args <-
|
args <-
|
||||||
Map.update(args, :picture, nil, fn picture ->
|
Map.update(args, :picture, nil, fn picture ->
|
||||||
|
@ -160,7 +160,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
|
||||||
process_picture(picture, group)
|
process_picture(picture, group)
|
||||||
end),
|
end),
|
||||||
args <- extract_pictures_from_post_body(args, actor_id),
|
args <- extract_pictures_from_post_body(args, actor_id),
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %Post{} = post} <-
|
{:ok, _, %Post{} = post} <-
|
||||||
Actions.Update.update(post, args, true, %{"actor" => actor_url}) do
|
Actions.Update.update(post, args, true, %{"actor" => actor_url}) do
|
||||||
{:ok, post}
|
{:ok, post}
|
||||||
|
@ -194,7 +194,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Post do
|
||||||
with {:uuid, {:ok, _uuid}} <- {:uuid, Ecto.UUID.cast(post_id)},
|
with {:uuid, {:ok, _uuid}} <- {:uuid, Ecto.UUID.cast(post_id)},
|
||||||
{:post, %Post{attributed_to: %Actor{id: group_id}} = post} <-
|
{:post, %Post{attributed_to: %Actor{id: group_id}} = post} <-
|
||||||
{:post, Posts.get_post_with_preloads(post_id)},
|
{:post, Posts.get_post_with_preloads(post_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %Post{} = post} <-
|
{:ok, _, %Post{} = post} <-
|
||||||
Actions.Delete.delete(post, actor) do
|
Actions.Delete.delete(post, actor) do
|
||||||
{:ok, post}
|
{:ok, post}
|
||||||
|
|
|
@ -32,7 +32,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
}
|
}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
%Page{} = page <- Resources.get_resources_for_group(group, page, limit) do
|
%Page{} = page <- Resources.get_resources_for_group(group, page, limit) do
|
||||||
{:ok, page}
|
{:ok, page}
|
||||||
else
|
else
|
||||||
|
@ -60,7 +60,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
}
|
}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
%Page{} = page <- Resources.get_resources_for_folder(parent, page, limit) do
|
%Page{} = page <- Resources.get_resources_for_folder(parent, page, limit) do
|
||||||
{:ok, page}
|
{:ok, page}
|
||||||
end
|
end
|
||||||
|
@ -83,7 +83,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
Logger.debug("Getting resource for group with username #{username}")
|
Logger.debug("Getting resource for group with username #{username}")
|
||||||
|
|
||||||
with {:group, %Actor{id: group_id}} <- {:group, Actors.get_actor_by_name(username, :Group)},
|
with {:group, %Actor{id: group_id}} <- {:group, Actors.get_actor_by_name(username, :Group)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:resource, %Resource{} = resource} <-
|
{:resource, %Resource{} = resource} <-
|
||||||
{:resource, Resources.get_resource_by_group_and_path_with_preloads(group_id, path)} do
|
{:resource, Resources.get_resource_by_group_and_path_with_preloads(group_id, path)} do
|
||||||
{:ok, resource}
|
{:ok, resource}
|
||||||
|
@ -109,7 +109,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
}
|
}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
if Actors.is_member?(actor_id, group_id) do
|
if Actors.member?(actor_id, group_id) do
|
||||||
parent = get_eventual_parent(args)
|
parent = get_eventual_parent(args)
|
||||||
|
|
||||||
if check_resource_owned_by_group(parent, group_id) do
|
if check_resource_owned_by_group(parent, group_id) do
|
||||||
|
@ -155,7 +155,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
) do
|
) do
|
||||||
case Resources.get_resource_with_preloads(resource_id) do
|
case Resources.get_resource_with_preloads(resource_id) do
|
||||||
%Resource{actor_id: group_id} = resource ->
|
%Resource{actor_id: group_id} = resource ->
|
||||||
if Actors.is_member?(actor_id, group_id) do
|
if Actors.member?(actor_id, group_id) do
|
||||||
case Actions.Update.update(resource, args, true, %{"actor" => actor_url}) do
|
case Actions.Update.update(resource, args, true, %{"actor" => actor_url}) do
|
||||||
{:ok, _, %Resource{} = resource} ->
|
{:ok, _, %Resource{} = resource} ->
|
||||||
{:ok, resource}
|
{:ok, resource}
|
||||||
|
@ -192,7 +192,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do
|
||||||
) do
|
) do
|
||||||
with {:resource, %Resource{parent_id: _parent_id, actor_id: group_id} = resource} <-
|
with {:resource, %Resource{parent_id: _parent_id, actor_id: group_id} = resource} <-
|
||||||
{:resource, Resources.get_resource_with_preloads(resource_id)},
|
{:resource, Resources.get_resource_with_preloads(resource_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %Resource{} = resource} <-
|
{:ok, _, %Resource{} = resource} <-
|
||||||
Actions.Delete.delete(resource, actor) do
|
Actions.Delete.delete(resource, actor) do
|
||||||
{:ok, resource}
|
{:ok, resource}
|
||||||
|
|
|
@ -26,7 +26,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
context: %{current_actor: %Actor{id: actor_id}}
|
context: %{current_actor: %Actor{id: actor_id}}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
%Page{} = page <- Todos.get_todo_lists_for_group(group, page, limit) do
|
%Page{} = page <- Todos.get_todo_lists_for_group(group, page, limit) do
|
||||||
{:ok, page}
|
{:ok, page}
|
||||||
else
|
else
|
||||||
|
@ -50,7 +50,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
context: %{current_actor: %Actor{id: actor_id}}
|
context: %{current_actor: %Actor{id: actor_id}}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
%Page{} = page <- Todos.get_todos_for_todo_list(todo_list, page, limit) do
|
%Page{} = page <- Todos.get_todos_for_todo_list(todo_list, page, limit) do
|
||||||
{:ok, page}
|
{:ok, page}
|
||||||
else
|
else
|
||||||
|
@ -70,7 +70,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
) do
|
) do
|
||||||
with {:todo, %TodoList{actor_id: group_id} = todo} <-
|
with {:todo, %TodoList{actor_id: group_id} = todo} <-
|
||||||
{:todo, Todos.get_todo_list(todo_list_id)},
|
{:todo, Todos.get_todo_list(todo_list_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)} do
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)} do
|
||||||
{:ok, todo}
|
{:ok, todo}
|
||||||
else
|
else
|
||||||
{:todo, nil} ->
|
{:todo, nil} ->
|
||||||
|
@ -93,7 +93,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
context: %{current_actor: %Actor{id: actor_id}}
|
context: %{current_actor: %Actor{id: actor_id}}
|
||||||
} = _resolution
|
} = _resolution
|
||||||
) do
|
) do
|
||||||
with {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
with {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %TodoList{} = todo_list} <-
|
{:ok, _, %TodoList{} = todo_list} <-
|
||||||
Actions.Create.create(
|
Actions.Create.create(
|
||||||
:todo_list,
|
:todo_list,
|
||||||
|
@ -121,7 +121,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
# with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
# with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
||||||
# {:todo_list, %TodoList{actor_id: group_id} = todo_list} <-
|
# {:todo_list, %TodoList{actor_id: group_id} = todo_list} <-
|
||||||
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
# {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
# {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
# {:ok, _, %TodoList{} = todo} <-
|
# {:ok, _, %TodoList{} = todo} <-
|
||||||
# Actions.Update.update_todo_list(todo_list, actor, true, %{}) do
|
# Actions.Update.update_todo_list(todo_list, actor, true, %{}) do
|
||||||
# {:ok, todo}
|
# {:ok, todo}
|
||||||
|
@ -144,7 +144,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
# with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
# with {:is_owned, %Actor{} = actor} <- User.owns_actor(user, actor_id),
|
||||||
# {:todo_list, %TodoList{actor_id: group_id} = todo_list} <-
|
# {:todo_list, %TodoList{actor_id: group_id} = todo_list} <-
|
||||||
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
# {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
# {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
# {:ok, _, %TodoList{} = todo} <-
|
# {:ok, _, %TodoList{} = todo} <-
|
||||||
# Actions.Delete.delete_todo_list(todo_list, actor, true, %{}) do
|
# Actions.Delete.delete_todo_list(todo_list, actor, true, %{}) do
|
||||||
# {:ok, todo}
|
# {:ok, todo}
|
||||||
|
@ -169,7 +169,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
{:todo, Todos.get_todo(todo_id)},
|
{:todo, Todos.get_todo(todo_id)},
|
||||||
{:todo_list, %TodoList{actor_id: group_id}} <-
|
{:todo_list, %TodoList{actor_id: group_id}} <-
|
||||||
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)} do
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)} do
|
||||||
{:ok, todo}
|
{:ok, todo}
|
||||||
else
|
else
|
||||||
{:todo, nil} ->
|
{:todo, nil} ->
|
||||||
|
@ -194,7 +194,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
) do
|
) do
|
||||||
with {:todo_list, %TodoList{actor_id: group_id} = _todo_list} <-
|
with {:todo_list, %TodoList{actor_id: group_id} = _todo_list} <-
|
||||||
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %Todo{} = todo} <-
|
{:ok, _, %Todo{} = todo} <-
|
||||||
Actions.Create.create(
|
Actions.Create.create(
|
||||||
:todo,
|
:todo,
|
||||||
|
@ -228,7 +228,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
{:todo, Todos.get_todo(todo_id)},
|
{:todo, Todos.get_todo(todo_id)},
|
||||||
{:todo_list, %TodoList{actor_id: group_id}} <-
|
{:todo_list, %TodoList{actor_id: group_id}} <-
|
||||||
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
{:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
{:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
{:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
{:ok, _, %Todo{} = todo} <-
|
{:ok, _, %Todo{} = todo} <-
|
||||||
Actions.Update.update(todo, args, true, %{}) do
|
Actions.Update.update(todo, args, true, %{}) do
|
||||||
{:ok, todo}
|
{:ok, todo}
|
||||||
|
@ -259,7 +259,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Todos do
|
||||||
# {:todo, Todos.get_todo(todo_id)},
|
# {:todo, Todos.get_todo(todo_id)},
|
||||||
# {:todo_list, %TodoList{actor_id: group_id}} <-
|
# {:todo_list, %TodoList{actor_id: group_id}} <-
|
||||||
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
# {:todo_list, Todos.get_todo_list(todo_list_id)},
|
||||||
# {:member, true} <- {:member, Actors.is_member?(actor_id, group_id)},
|
# {:member, true} <- {:member, Actors.member?(actor_id, group_id)},
|
||||||
# {:ok, _, %Todo{} = todo} <-
|
# {:ok, _, %Todo{} = todo} <-
|
||||||
# Actions.Delete.delete_todo(todo, actor, true, %{}) do
|
# Actions.Delete.delete_todo(todo, actor, true, %{}) do
|
||||||
# {:ok, todo}
|
# {:ok, todo}
|
||||||
|
|
|
@ -209,8 +209,8 @@ defmodule Mobilizon.Actors.Actor do
|
||||||
@doc """
|
@doc """
|
||||||
Checks whether actor visibility is public.
|
Checks whether actor visibility is public.
|
||||||
"""
|
"""
|
||||||
@spec is_public_visibility?(t) :: boolean
|
@spec public_visibility?(t) :: boolean
|
||||||
def is_public_visibility?(%__MODULE__{visibility: visibility}) do
|
def public_visibility?(%__MODULE__{visibility: visibility}) do
|
||||||
visibility in [:public, :unlisted]
|
visibility in [:public, :unlisted]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -710,8 +710,8 @@ defmodule Mobilizon.Actors do
|
||||||
@doc """
|
@doc """
|
||||||
Returns whether the `actor_id` is a confirmed member for the group `parent_id`
|
Returns whether the `actor_id` is a confirmed member for the group `parent_id`
|
||||||
"""
|
"""
|
||||||
@spec is_member?(integer | String.t(), integer | String.t()) :: boolean()
|
@spec member?(integer | String.t(), integer | String.t()) :: boolean()
|
||||||
def is_member?(actor_id, parent_id) do
|
def member?(actor_id, parent_id) do
|
||||||
match?(
|
match?(
|
||||||
{:ok, %Member{}},
|
{:ok, %Member{}},
|
||||||
get_member(actor_id, parent_id, @member_roles)
|
get_member(actor_id, parent_id, @member_roles)
|
||||||
|
@ -721,8 +721,8 @@ defmodule Mobilizon.Actors do
|
||||||
@doc """
|
@doc """
|
||||||
Returns whether the `actor_id` is a moderator for the group `parent_id`
|
Returns whether the `actor_id` is a moderator for the group `parent_id`
|
||||||
"""
|
"""
|
||||||
@spec is_moderator?(integer | String.t(), integer | String.t()) :: boolean()
|
@spec moderator?(integer | String.t(), integer | String.t()) :: boolean()
|
||||||
def is_moderator?(actor_id, parent_id) do
|
def moderator?(actor_id, parent_id) do
|
||||||
match?(
|
match?(
|
||||||
{:ok, %Member{}},
|
{:ok, %Member{}},
|
||||||
get_member(actor_id, parent_id, @moderator_roles)
|
get_member(actor_id, parent_id, @moderator_roles)
|
||||||
|
@ -732,8 +732,8 @@ defmodule Mobilizon.Actors do
|
||||||
@doc """
|
@doc """
|
||||||
Returns whether the `actor_id` is an administrator for the group `parent_id`
|
Returns whether the `actor_id` is an administrator for the group `parent_id`
|
||||||
"""
|
"""
|
||||||
@spec is_administrator?(integer | String.t(), integer | String.t()) :: boolean()
|
@spec administrator?(integer | String.t(), integer | String.t()) :: boolean()
|
||||||
def is_administrator?(actor_id, parent_id) do
|
def administrator?(actor_id, parent_id) do
|
||||||
match?(
|
match?(
|
||||||
{:ok, %Member{}},
|
{:ok, %Member{}},
|
||||||
get_member(actor_id, parent_id, @administrator_roles)
|
get_member(actor_id, parent_id, @administrator_roles)
|
||||||
|
@ -922,8 +922,8 @@ defmodule Mobilizon.Actors do
|
||||||
@doc """
|
@doc """
|
||||||
Returns whether the member is the last administrator for a group
|
Returns whether the member is the last administrator for a group
|
||||||
"""
|
"""
|
||||||
@spec is_only_administrator?(integer | String.t(), integer | String.t()) :: boolean()
|
@spec only_administrator?(integer | String.t(), integer | String.t()) :: boolean()
|
||||||
def is_only_administrator?(member_id, group_id) do
|
def only_administrator?(member_id, group_id) do
|
||||||
Member
|
Member
|
||||||
|> where(
|
|> where(
|
||||||
[m],
|
[m],
|
||||||
|
|
|
@ -55,9 +55,10 @@ defmodule Mobilizon.Actors.Member do
|
||||||
@doc """
|
@doc """
|
||||||
Checks whether the member is an administrator (admin or creator) of the group.
|
Checks whether the member is an administrator (admin or creator) of the group.
|
||||||
"""
|
"""
|
||||||
def is_administrator(%__MODULE__{role: :administrator}), do: true
|
@spec administrator?(t()) :: boolean()
|
||||||
def is_administrator(%__MODULE__{role: :creator}), do: true
|
def administrator?(%__MODULE__{role: :administrator}), do: true
|
||||||
def is_administrator(%__MODULE__{}), do: false
|
def administrator?(%__MODULE__{role: :creator}), do: true
|
||||||
|
def administrator?(%__MODULE__{}), do: false
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||||
|
|
|
@ -77,7 +77,7 @@ defmodule Mobilizon.Discussions do
|
||||||
|> join(:left, [c], r in Comment, on: r.origin_comment_id == c.id)
|
|> join(:left, [c], r in Comment, on: r.origin_comment_id == c.id)
|
||||||
|> where([c, _], is_nil(c.in_reply_to_comment_id))
|
|> where([c, _], is_nil(c.in_reply_to_comment_id))
|
||||||
|> where([c], c.visibility in ^@public_visibility)
|
|> where([c], c.visibility in ^@public_visibility)
|
||||||
# TODO: This was added because we don't want to count deleted comments in total_replies.
|
# This was added because we don't want to count deleted comments in total_replies.
|
||||||
# However, it also excludes all top-level comments with deleted replies from being selected
|
# However, it also excludes all top-level comments with deleted replies from being selected
|
||||||
# |> where([_, r], is_nil(r.deleted_at))
|
# |> where([_, r], is_nil(r.deleted_at))
|
||||||
|> group_by([c], c.id)
|
|> group_by([c], c.id)
|
||||||
|
|
|
@ -515,8 +515,8 @@ defmodule Mobilizon.Events do
|
||||||
|> Page.build_page(page, limit)
|
|> Page.build_page(page, limit)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_user_moderator_for_event?(integer | String.t(), integer | String.t()) :: boolean
|
@spec user_moderator_for_event?(integer | String.t(), integer | String.t()) :: boolean
|
||||||
def is_user_moderator_for_event?(user_id, event_id) do
|
def user_moderator_for_event?(user_id, event_id) do
|
||||||
Participant
|
Participant
|
||||||
|> join(:inner, [p], a in Actor, on: p.actor_id == a.id)
|
|> join(:inner, [p], a in Actor, on: p.actor_id == a.id)
|
||||||
|> where([p, _a], p.event_id == ^event_id)
|
|> where([p, _a], p.event_id == ^event_id)
|
||||||
|
@ -1492,14 +1492,14 @@ defmodule Mobilizon.Events do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec filter_online(Ecto.Query.t(), map()) :: Ecto.Query.t()
|
@spec filter_online(Ecto.Query.t(), map()) :: Ecto.Query.t()
|
||||||
defp filter_online(query, %{type: :online}), do: is_online_fragment(query, true)
|
defp filter_online(query, %{type: :online}), do: online_fragment_check(query, true)
|
||||||
|
|
||||||
defp filter_online(query, %{type: :in_person}), do: is_online_fragment(query, false)
|
defp filter_online(query, %{type: :in_person}), do: online_fragment_check(query, false)
|
||||||
|
|
||||||
defp filter_online(query, _), do: query
|
defp filter_online(query, _), do: query
|
||||||
|
|
||||||
@spec is_online_fragment(Ecto.Query.t(), boolean()) :: Ecto.Query.t()
|
@spec online_fragment_check(Ecto.Query.t(), boolean()) :: Ecto.Query.t()
|
||||||
defp is_online_fragment(query, value) do
|
defp online_fragment_check(query, value) do
|
||||||
where(query, [q], fragment("(?->>'is_online')::bool = ?", q.options, ^value))
|
where(query, [q], fragment("(?->>'is_online')::bool = ?", q.options, ^value))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ defmodule Mobilizon.Events.Participant do
|
||||||
We start by fetching the list of organizers and if there's only one of them
|
We start by fetching the list of organizers and if there's only one of them
|
||||||
and that it's the actor requesting leaving the event we return true.
|
and that it's the actor requesting leaving the event we return true.
|
||||||
"""
|
"""
|
||||||
@spec is_not_only_organizer(integer | String.t(), integer | String.t()) :: boolean
|
@spec not_only_organizer?(integer | String.t(), integer | String.t()) :: boolean
|
||||||
def is_not_only_organizer(event_id, actor_id) do
|
def not_only_organizer?(event_id, actor_id) do
|
||||||
case Events.list_organizers_participants_for_event(event_id) do
|
case Events.list_organizers_participants_for_event(event_id) do
|
||||||
[%__MODULE__{actor: %Actor{id: participant_actor_id}}] ->
|
[%__MODULE__{actor: %Actor{id: participant_actor_id}}] ->
|
||||||
participant_actor_id == actor_id
|
participant_actor_id == actor_id
|
||||||
|
|
|
@ -34,6 +34,10 @@ defmodule Mobilizon.Instances.InstanceActor do
|
||||||
instance_actor
|
instance_actor
|
||||||
|> cast(attrs, @attrs)
|
|> cast(attrs, @attrs)
|
||||||
|> validate_required(@required_attrs)
|
|> validate_required(@required_attrs)
|
||||||
|
|> validate_length(:domain, max: 254)
|
||||||
|
|> validate_length(:instance_name, max: 254)
|
||||||
|
|> validate_length(:software, max: 254)
|
||||||
|
|> validate_length(:software_version, max: 254)
|
||||||
|> unique_constraint(:domain)
|
|> unique_constraint(:domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ defmodule Mobilizon.Instances do
|
||||||
"""
|
"""
|
||||||
alias Ecto.Adapters.SQL
|
alias Ecto.Adapters.SQL
|
||||||
alias Mobilizon.Actors.{Actor, Follower}
|
alias Mobilizon.Actors.{Actor, Follower}
|
||||||
|
alias Mobilizon.Federation.ActivityPub.Relay
|
||||||
alias Mobilizon.Instances.{Instance, InstanceActor}
|
alias Mobilizon.Instances.{Instance, InstanceActor}
|
||||||
alias Mobilizon.Storage.{Page, Repo}
|
alias Mobilizon.Storage.{Page, Repo}
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
@ -22,11 +23,15 @@ defmodule Mobilizon.Instances do
|
||||||
|
|
||||||
order_by_options = Keyword.new([{direction, order_by}])
|
order_by_options = Keyword.new([{direction, order_by}])
|
||||||
|
|
||||||
|
%Actor{id: relay_id} = Relay.get_actor()
|
||||||
|
|
||||||
query =
|
query =
|
||||||
Instance
|
Instance
|
||||||
|> join(:left, [i], ia in InstanceActor, on: i.domain == ia.domain)
|
|> join(:left, [i], ia in InstanceActor, on: i.domain == ia.domain)
|
||||||
|> join(:left, [_i, ia], a in Actor, on: ia.actor_id == a.id)
|
|> join(:left, [_i, ia], a in Actor, on: ia.actor_id == a.id)
|
||||||
|
# following
|
||||||
|> join(:left, [_i, _ia, a], f1 in Follower, on: f1.target_actor_id == a.id)
|
|> join(:left, [_i, _ia, a], f1 in Follower, on: f1.target_actor_id == a.id)
|
||||||
|
# followed
|
||||||
|> join(:left, [_i, _ia, a], f2 in Follower, on: f2.actor_id == a.id)
|
|> join(:left, [_i, _ia, a], f2 in Follower, on: f2.actor_id == a.id)
|
||||||
|> select([i, ia, a, f1, f2], %{
|
|> select([i, ia, a, f1, f2], %{
|
||||||
instance: i,
|
instance: i,
|
||||||
|
@ -45,14 +50,27 @@ defmodule Mobilizon.Instances do
|
||||||
if is_nil(filter_domain) or filter_domain == "" do
|
if is_nil(filter_domain) or filter_domain == "" do
|
||||||
query
|
query
|
||||||
else
|
else
|
||||||
where(query, [i], like(i.domain, ^"%#{filter_domain}%"))
|
where(
|
||||||
|
query,
|
||||||
|
[i, ia],
|
||||||
|
like(i.domain, ^"%#{filter_domain}%") or like(ia.instance_name, ^"%#{filter_domain}%")
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
query =
|
query =
|
||||||
case follow_status do
|
case follow_status do
|
||||||
:following -> where(query, [i, s], s.following == true)
|
:following ->
|
||||||
:followed -> where(query, [i, s], s.follower == true)
|
where(query, [_i, _ia, _a, f1], f1.actor_id == ^relay_id and f1.approved == true)
|
||||||
:all -> query
|
|
||||||
|
:followed ->
|
||||||
|
where(
|
||||||
|
query,
|
||||||
|
[_i, _ia, _a, _f1, f2],
|
||||||
|
f2.target_actor_id == ^relay_id and f2.approved == true
|
||||||
|
)
|
||||||
|
|
||||||
|
:all ->
|
||||||
|
query
|
||||||
end
|
end
|
||||||
|
|
||||||
%Page{elements: elements} = paged_instances = Page.build_page(query, page, limit, :domain)
|
%Page{elements: elements} = paged_instances = Page.build_page(query, page, limit, :domain)
|
||||||
|
|
|
@ -214,7 +214,7 @@ defmodule Mobilizon.Medias do
|
||||||
query
|
query
|
||||||
|> Repo.all(timeout: :infinity)
|
|> Repo.all(timeout: :infinity)
|
||||||
|> Enum.filter(fn %Media{file: %File{url: url}} ->
|
|> Enum.filter(fn %Media{file: %File{url: url}} ->
|
||||||
!url_is_also_a_profile_file?(url) && is_all_media_orphan?(url, expiration_date)
|
!url_is_also_a_profile_file?(url) && all_media_orphan?(url, expiration_date)
|
||||||
end)
|
end)
|
||||||
|> Enum.chunk_by(fn %Media{file: %File{url: url}} ->
|
|> Enum.chunk_by(fn %Media{file: %File{url: url}} ->
|
||||||
url
|
url
|
||||||
|
@ -223,14 +223,14 @@ defmodule Mobilizon.Medias do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp is_all_media_orphan?(url, expiration_date) do
|
defp all_media_orphan?(url, expiration_date) do
|
||||||
url
|
url
|
||||||
|> get_all_media_by_url()
|
|> get_all_media_by_url()
|
||||||
|> Enum.all?(&is_media_orphan?(&1, expiration_date))
|
|> Enum.all?(&media_orphan?(&1, expiration_date))
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_media_orphan?(Media.t(), DateTime.t()) :: boolean()
|
@spec media_orphan?(Media.t(), DateTime.t()) :: boolean()
|
||||||
defp is_media_orphan?(%Media{id: media_id}, expiration_date) do
|
defp media_orphan?(%Media{id: media_id}, expiration_date) do
|
||||||
media_query =
|
media_query =
|
||||||
from(m in Media,
|
from(m in Media,
|
||||||
as: :media,
|
as: :media,
|
||||||
|
|
|
@ -7,6 +7,7 @@ defmodule Mobilizon.Storage.Ecto do
|
||||||
import Ecto.Changeset, only: [fetch_change: 2, put_change: 3, get_field: 2]
|
import Ecto.Changeset, only: [fetch_change: 2, put_change: 3, get_field: 2]
|
||||||
alias Ecto.{Changeset, Query}
|
alias Ecto.{Changeset, Query}
|
||||||
alias Mobilizon.Web.Endpoint
|
alias Mobilizon.Web.Endpoint
|
||||||
|
alias Mobilizon.Web.Gettext, as: GettextBackend
|
||||||
alias Mobilizon.Web.Router.Helpers, as: Routes
|
alias Mobilizon.Web.Router.Helpers, as: Routes
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -56,4 +57,30 @@ defmodule Mobilizon.Storage.Ecto do
|
||||||
changeset
|
changeset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def convert_ecto_errors(%Ecto.Changeset{} = changeset),
|
||||||
|
do: Ecto.Changeset.traverse_errors(changeset, &translate_error/1)
|
||||||
|
|
||||||
|
# Translates an error message using gettext.
|
||||||
|
defp translate_error({msg, opts}) do
|
||||||
|
# Because error messages were defined within Ecto, we must
|
||||||
|
# call the Gettext module passing our Gettext backend. We
|
||||||
|
# also use the "errors" domain as translations are placed
|
||||||
|
# in the errors.po file.
|
||||||
|
# Ecto will pass the :count keyword if the error message is
|
||||||
|
# meant to be pluralized.
|
||||||
|
# On your own code and templates, depending on whether you
|
||||||
|
# need the message to be pluralized or not, this could be
|
||||||
|
# written simply as:
|
||||||
|
#
|
||||||
|
# dngettext "errors", "1 file", "%{count} files", count
|
||||||
|
# dgettext "errors", "is invalid"
|
||||||
|
#
|
||||||
|
|
||||||
|
if count = opts[:count] do
|
||||||
|
Gettext.dngettext(GettextBackend, "errors", msg, msg, count, opts)
|
||||||
|
else
|
||||||
|
Gettext.dgettext(GettextBackend, "errors", msg, opts)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,14 +55,14 @@ defmodule Mobilizon.Service.DateTime do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_first_day_of_week(Date.t(), String.t()) :: boolean()
|
@spec first_day_of_week?(Date.t(), String.t()) :: boolean()
|
||||||
defp is_first_day_of_week(%Date{} = date, locale) do
|
defp first_day_of_week?(%Date{} = date, locale) do
|
||||||
Date.day_of_week(date) == Cldr.Calendar.first_day_for_locale(locale)
|
Date.day_of_week(date) == Cldr.Calendar.first_day_for_locale(locale)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec calculate_first_day_of_week(Date.t(), String.t()) :: Date.t()
|
@spec calculate_first_day_of_week(Date.t(), String.t()) :: Date.t()
|
||||||
def calculate_first_day_of_week(%Date{} = date, locale \\ "en") do
|
def calculate_first_day_of_week(%Date{} = date, locale \\ "en") do
|
||||||
if is_first_day_of_week(date, locale),
|
if first_day_of_week?(date, locale),
|
||||||
do: date,
|
do: date,
|
||||||
else: calculate_first_day_of_week(Date.add(date, -1), locale)
|
else: calculate_first_day_of_week(Date.add(date, -1), locale)
|
||||||
end
|
end
|
||||||
|
@ -204,11 +204,11 @@ defmodule Mobilizon.Service.DateTime do
|
||||||
compare_to_day = Keyword.get(options, :compare_to_day, Date.utc_today())
|
compare_to_day = Keyword.get(options, :compare_to_day, Date.utc_today())
|
||||||
locale = Keyword.get(options, :locale, "en")
|
locale = Keyword.get(options, :locale, "en")
|
||||||
|
|
||||||
is_first_day_of_week(compare_to_day, locale) && is_between_hours?(options)
|
first_day_of_week?(compare_to_day, locale) && is_between_hours?(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_delay_ok_since_last_notification_sent?(DateTime.t(), pos_integer()) :: boolean()
|
@spec delay_ok_since_last_notification_sent?(DateTime.t(), pos_integer()) :: boolean()
|
||||||
def is_delay_ok_since_last_notification_sent?(
|
def delay_ok_since_last_notification_sent?(
|
||||||
%DateTime{} = last_notification_sent,
|
%DateTime{} = last_notification_sent,
|
||||||
delay \\ 3_600
|
delay \\ 3_600
|
||||||
) do
|
) do
|
||||||
|
@ -216,8 +216,8 @@ defmodule Mobilizon.Service.DateTime do
|
||||||
:lt
|
:lt
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_same_day?(DateTime.t(), DateTime.t()) :: boolean()
|
@spec same_day?(DateTime.t(), DateTime.t()) :: boolean()
|
||||||
def is_same_day?(%DateTime{} = one, %DateTime{} = two) do
|
def same_day?(%DateTime{} = one, %DateTime{} = two) do
|
||||||
DateTime.to_date(one) == DateTime.to_date(two)
|
DateTime.to_date(one) == DateTime.to_date(two)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ defmodule Mobilizon.Service.Export.Common do
|
||||||
def fetch_actor_event_feed(name, limit) do
|
def fetch_actor_event_feed(name, limit) do
|
||||||
case Actors.get_actor_by_name(name) do
|
case Actors.get_actor_by_name(name) do
|
||||||
%Actor{} = actor ->
|
%Actor{} = actor ->
|
||||||
if Actor.is_public_visibility?(actor) do
|
if Actor.public_visibility?(actor) do
|
||||||
%Page{elements: events} = Events.list_public_upcoming_events_for_actor(actor, 1, limit)
|
%Page{elements: events} = Events.list_public_upcoming_events_for_actor(actor, 1, limit)
|
||||||
%Page{elements: posts} = Posts.get_public_posts_for_group(actor, 1, limit)
|
%Page{elements: posts} = Posts.get_public_posts_for_group(actor, 1, limit)
|
||||||
{:ok, actor, events, posts}
|
{:ok, actor, events, posts}
|
||||||
|
|
|
@ -265,7 +265,7 @@ defmodule Mobilizon.Service.Export.Feed do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp clear_actor_feed(%Actor{preferred_username: preferred_username} = actor) do
|
defp clear_actor_feed(%Actor{preferred_username: preferred_username} = actor) do
|
||||||
if Actor.is_public_visibility?(actor) do
|
if Actor.public_visibility?(actor) do
|
||||||
Cachex.del(:feed, "actor_#{preferred_username}")
|
Cachex.del(:feed, "actor_#{preferred_username}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -216,7 +216,7 @@ defmodule Mobilizon.Service.Export.ICalendar do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp clear_actor_feed(%Actor{preferred_username: preferred_username} = actor) do
|
defp clear_actor_feed(%Actor{preferred_username: preferred_username} = actor) do
|
||||||
if Actor.is_public_visibility?(actor) do
|
if Actor.public_visibility?(actor) do
|
||||||
Cachex.del(:ics, "actor_#{preferred_username}")
|
Cachex.del(:ics, "actor_#{preferred_username}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,8 +13,8 @@ defmodule Mobilizon.Service.HTTP.Utils do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_content_type?(Enum.t(), String.t() | list(String.t())) :: boolean
|
@spec content_type_matches?(Enum.t(), String.t() | list(String.t())) :: boolean
|
||||||
def is_content_type?(headers, content_type) do
|
def content_type_matches?(headers, content_type) do
|
||||||
headers
|
headers
|
||||||
|> get_header("Content-Type")
|
|> get_header("Content-Type")
|
||||||
|> content_type_header_matches(content_type)
|
|> content_type_header_matches(content_type)
|
||||||
|
|
|
@ -12,8 +12,8 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||||
|
|
||||||
import Mobilizon.Service.DateTime,
|
import Mobilizon.Service.DateTime,
|
||||||
only: [
|
only: [
|
||||||
is_delay_ok_since_last_notification_sent?: 1,
|
delay_ok_since_last_notification_sent?: 1,
|
||||||
is_delay_ok_since_last_notification_sent?: 2
|
delay_ok_since_last_notification_sent?: 2
|
||||||
]
|
]
|
||||||
|
|
||||||
require Logger
|
require Logger
|
||||||
|
@ -129,7 +129,7 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||||
|
|
||||||
# Delay ok since last notification
|
# Delay ok since last notification
|
||||||
defp match_group_notifications_setting(:one_hour, _, %DateTime{} = last_notification_sent, _) do
|
defp match_group_notifications_setting(:one_hour, _, %DateTime{} = last_notification_sent, _) do
|
||||||
is_delay_ok_since_last_notification_sent?(last_notification_sent)
|
delay_ok_since_last_notification_sent?(last_notification_sent)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Delay ok since last notification
|
# Delay ok since last notification
|
||||||
|
@ -139,7 +139,7 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||||
%DateTime{} = last_notification_sent,
|
%DateTime{} = last_notification_sent,
|
||||||
options
|
options
|
||||||
) do
|
) do
|
||||||
is_delay_ok_since_last_notification_sent?(last_notification_sent, 3_600 * 23) and
|
delay_ok_since_last_notification_sent?(last_notification_sent, 3_600 * 23) and
|
||||||
Keyword.get(options, :recap, false) != false
|
Keyword.get(options, :recap, false) != false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ defmodule Mobilizon.Service.Notifier.Email do
|
||||||
%DateTime{} = last_notification_sent,
|
%DateTime{} = last_notification_sent,
|
||||||
options
|
options
|
||||||
) do
|
) do
|
||||||
is_delay_ok_since_last_notification_sent?(last_notification_sent, 3_600 * 24 * 6) and
|
delay_ok_since_last_notification_sent?(last_notification_sent, 3_600 * 24 * 6) and
|
||||||
Keyword.get(options, :recap, false) != false
|
Keyword.get(options, :recap, false) != false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,7 @@ defmodule Mobilizon.Service.RichMedia.Parser do
|
||||||
max_body: 2_000_000,
|
max_body: 2_000_000,
|
||||||
timeout: 10_000,
|
timeout: 10_000,
|
||||||
recv_timeout: 20_000,
|
recv_timeout: 20_000,
|
||||||
follow_redirect: true,
|
follow_redirect: true
|
||||||
# TODO: Remove me once Hackney/HTTPoison fixes their issue with TLS1.3 and OTP 23
|
|
||||||
ssl: [{:versions, [:"tlsv1.2"]}]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
alias Mobilizon.Config
|
alias Mobilizon.Config
|
||||||
|
@ -75,7 +73,7 @@ defmodule Mobilizon.Service.RichMedia.Parser do
|
||||||
opts: @options
|
opts: @options
|
||||||
)},
|
)},
|
||||||
{:is_html, _response_headers, true} <-
|
{:is_html, _response_headers, true} <-
|
||||||
{:is_html, response_headers, is_html?(response_headers)} do
|
{:is_html, response_headers, html?(response_headers)} do
|
||||||
body
|
body
|
||||||
|> convert_utf8(response_headers)
|
|> convert_utf8(response_headers)
|
||||||
|> maybe_parse()
|
|> maybe_parse()
|
||||||
|
@ -108,21 +106,21 @@ defmodule Mobilizon.Service.RichMedia.Parser do
|
||||||
defp get_data_for_media(response_headers, url) do
|
defp get_data_for_media(response_headers, url) do
|
||||||
data = %{title: get_filename_from_headers(response_headers) || get_filename_from_url(url)}
|
data = %{title: get_filename_from_headers(response_headers) || get_filename_from_url(url)}
|
||||||
|
|
||||||
if is_image?(response_headers) do
|
if image?(response_headers) do
|
||||||
Map.put(data, :image_remote_url, url)
|
Map.put(data, :image_remote_url, url)
|
||||||
else
|
else
|
||||||
data
|
data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_html?(Enum.t()) :: boolean
|
@spec html?(Enum.t()) :: boolean
|
||||||
defp is_html?(headers) do
|
defp html?(headers) do
|
||||||
is_content_type?(headers, ["text/html", "application/xhtml"])
|
content_type_matches?(headers, ["text/html", "application/xhtml"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_image?(Enum.t()) :: boolean
|
@spec image?(Enum.t()) :: boolean
|
||||||
defp is_image?(headers) do
|
defp image?(headers) do
|
||||||
is_content_type?(headers, ["image/"])
|
content_type_matches?(headers, ["image/"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec get_filename_from_headers(Enum.t()) :: String.t() | nil
|
@spec get_filename_from_headers(Enum.t()) :: String.t() | nil
|
||||||
|
|
|
@ -81,7 +81,7 @@ defmodule Mobilizon.Service.Workers.LegacyNotifierBuilder do
|
||||||
options
|
options
|
||||||
) do
|
) do
|
||||||
mentionned_actor_ids
|
mentionned_actor_ids
|
||||||
|> Enum.filter(&Actors.is_member?(&1, Keyword.fetch!(options, :group_id)))
|
|> Enum.filter(&Actors.member?(&1, Keyword.fetch!(options, :group_id)))
|
||||||
|> users_from_actor_ids(Keyword.fetch!(options, :author_id))
|
|> users_from_actor_ids(Keyword.fetch!(options, :author_id))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ defmodule Mobilizon.Service.Workers.RefreshInstances do
|
||||||
alias Mobilizon.Instances.{Instance, InstanceActor}
|
alias Mobilizon.Instances.{Instance, InstanceActor}
|
||||||
alias Oban.Job
|
alias Oban.Job
|
||||||
require Logger
|
require Logger
|
||||||
|
import Mobilizon.Storage.Ecto, only: [convert_ecto_errors: 1]
|
||||||
|
|
||||||
@impl Oban.Worker
|
@impl Oban.Worker
|
||||||
@spec perform(Oban.Job.t()) :: :ok
|
@spec perform(Oban.Job.t()) :: :ok
|
||||||
|
@ -56,6 +57,10 @@ defmodule Mobilizon.Service.Workers.RefreshInstances do
|
||||||
Instances.create_instance_actor(args) do
|
Instances.create_instance_actor(args) do
|
||||||
Logger.info("Saved instance actor details for domain #{host}")
|
Logger.info("Saved instance actor details for domain #{host}")
|
||||||
else
|
else
|
||||||
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
|
Logger.error("Unable to save instance \"#{domain}\" metadata")
|
||||||
|
Logger.debug(convert_ecto_errors(changeset))
|
||||||
|
|
||||||
err ->
|
err ->
|
||||||
Logger.error(inspect(err))
|
Logger.error(inspect(err))
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ defmodule Mobilizon.Service.Workers.SendActivityRecapWorker do
|
||||||
only: [
|
only: [
|
||||||
is_between_hours?: 1,
|
is_between_hours?: 1,
|
||||||
is_between_hours_on_first_day?: 1,
|
is_between_hours_on_first_day?: 1,
|
||||||
is_delay_ok_since_last_notification_sent?: 1
|
delay_ok_since_last_notification_sent?: 1
|
||||||
]
|
]
|
||||||
|
|
||||||
@impl Oban.Worker
|
@impl Oban.Worker
|
||||||
|
@ -108,7 +108,7 @@ defmodule Mobilizon.Service.Workers.SendActivityRecapWorker do
|
||||||
"Testing if it's less than an hour since the last time we sent an activity recap"
|
"Testing if it's less than an hour since the last time we sent an activity recap"
|
||||||
)
|
)
|
||||||
|
|
||||||
is_delay_ok_since_last_notification_sent?(last_notification_sent)
|
delay_ok_since_last_notification_sent?(last_notification_sent)
|
||||||
end
|
end
|
||||||
|
|
||||||
# If we're between notification hours
|
# If we're between notification hours
|
||||||
|
|
|
@ -173,26 +173,26 @@ defmodule Mobilizon.Web.PageController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_visible?(map) :: boolean()
|
@spec visible?(map) :: boolean()
|
||||||
defp is_visible?(%{visibility: v}), do: v in [:public, :unlisted]
|
defp visible?(%{visibility: v}), do: v in [:public, :unlisted]
|
||||||
defp is_visible?(%Tombstone{}), do: true
|
defp visible?(%Tombstone{}), do: true
|
||||||
defp is_visible?(_), do: true
|
defp visible?(_), do: true
|
||||||
|
|
||||||
@spec ok_status?(cache_status) :: boolean()
|
@spec ok_status?(cache_status) :: boolean()
|
||||||
defp ok_status?(status), do: status in [:ok, :commit]
|
defp ok_status?(status), do: status in [:ok, :commit]
|
||||||
|
|
||||||
@typep cache_status :: :ok | :commit | :ignore
|
@typep cache_status :: :ok | :commit | :ignore
|
||||||
|
|
||||||
@spec ok_status_and_is_visible?(Plug.Conn.t(), cache_status, map()) :: boolean()
|
@spec ok_status_and_visible?(Plug.Conn.t(), cache_status, map()) :: boolean()
|
||||||
defp ok_status_and_is_visible?(_conn, status, o),
|
defp ok_status_and_visible?(_conn, status, o),
|
||||||
do: ok_status?(status) and is_visible?(o)
|
do: ok_status?(status) and visible?(o)
|
||||||
|
|
||||||
defp checks?(conn, status, o) do
|
defp checks?(conn, status, o) do
|
||||||
cond do
|
cond do
|
||||||
ok_status_and_is_visible?(conn, status, o) ->
|
ok_status_and_visible?(conn, status, o) ->
|
||||||
if is_local?(o) == :remote && get_format(conn) == "activity-json", do: :remote, else: true
|
if local?(o) == :remote && get_format(conn) == "activity-json", do: :remote, else: true
|
||||||
|
|
||||||
is_person?(o) && get_format(conn) == "activity-json" ->
|
person?(o) && get_format(conn) == "activity-json" ->
|
||||||
true
|
true
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
|
@ -200,9 +200,9 @@ defmodule Mobilizon.Web.PageController do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_local?(map()) :: boolean | :remote
|
@spec local?(map()) :: boolean | :remote
|
||||||
defp is_local?(%{local: local}), do: if(local, do: true, else: :remote)
|
defp local?(%{local: local}), do: if(local, do: true, else: :remote)
|
||||||
defp is_local?(_), do: false
|
defp local?(_), do: false
|
||||||
|
|
||||||
@spec maybe_add_noindex_header(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
@spec maybe_add_noindex_header(Plug.Conn.t(), map()) :: Plug.Conn.t()
|
||||||
defp maybe_add_noindex_header(conn, %{visibility: visibility})
|
defp maybe_add_noindex_header(conn, %{visibility: visibility})
|
||||||
|
@ -212,9 +212,9 @@ defmodule Mobilizon.Web.PageController do
|
||||||
|
|
||||||
defp maybe_add_noindex_header(conn, _), do: conn
|
defp maybe_add_noindex_header(conn, _), do: conn
|
||||||
|
|
||||||
@spec is_person?(Actor.t()) :: boolean()
|
@spec person?(Actor.t()) :: boolean()
|
||||||
defp is_person?(%Actor{type: :Person}), do: true
|
defp person?(%Actor{type: :Person}), do: true
|
||||||
defp is_person?(_), do: false
|
defp person?(_), do: false
|
||||||
|
|
||||||
defp maybe_add_content_type_header(conn) do
|
defp maybe_add_content_type_header(conn) do
|
||||||
case get_format(conn) do
|
case get_format(conn) do
|
||||||
|
|
|
@ -87,8 +87,6 @@ defmodule Mobilizon.Web.Email.Group do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO : def send_confirmation_to_inviter()
|
|
||||||
|
|
||||||
@member_roles [:administrator, :moderator, :member]
|
@member_roles [:administrator, :moderator, :member]
|
||||||
@spec send_group_suspension_notification(Member.t()) :: :ok
|
@spec send_group_suspension_notification(Member.t()) :: :ok
|
||||||
def send_group_suspension_notification(%Member{actor: %Actor{user_id: nil}}), do: :ok
|
def send_group_suspension_notification(%Member{actor: %Actor{user_id: nil}}), do: :ok
|
||||||
|
|
|
@ -124,6 +124,4 @@ defmodule Mobilizon.Web.Email.Member do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO : def send_confirmation_to_inviter()
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -71,13 +71,7 @@ defmodule Mobilizon.Web.MediaProxy do
|
||||||
@compile {:no_warn_undefined, {:crypto, :mac, 4}}
|
@compile {:no_warn_undefined, {:crypto, :mac, 4}}
|
||||||
@compile {:no_warn_undefined, {:crypto, :hmac, 3}}
|
@compile {:no_warn_undefined, {:crypto, :hmac, 3}}
|
||||||
defp sha_hmac(key, url) do
|
defp sha_hmac(key, url) do
|
||||||
# :crypto.hmac was removed in OTP24, but :crypto.mac was added in OTP 22.1
|
|
||||||
# TODO: Remove me when we don't support OTP 21/22 anymore
|
|
||||||
if function_exported?(:crypto, :mac, 4) do
|
|
||||||
:crypto.mac(:hmac, :sha, key, url)
|
:crypto.mac(:hmac, :sha, key, url)
|
||||||
else
|
|
||||||
:crypto.hmac(:sha, key, url)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec filename(String.t()) :: String.t() | nil
|
@spec filename(String.t()) :: String.t() | nil
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
timezone: @timezone,
|
timezone: @timezone,
|
||||||
locale: @locale
|
locale: @locale
|
||||||
) %>
|
) %>
|
||||||
<% is_same_day?(@start_date, @end_date) -> %>
|
<% same_day?(@start_date, @end_date) -> %>
|
||||||
<strong>
|
<strong>
|
||||||
<%= gettext("On %{date} from %{start_time} to %{end_time}",
|
<%= gettext("On %{date} from %{start_time} to %{end_time}",
|
||||||
date: datetime_to_date_string(@start_date, @locale),
|
date: datetime_to_date_string(@start_date, @locale),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<%= cond do %><% @end_date == nil -> %><%= render("date/event_tz_date.text", date: @start_date, event: @event, timezone: @timezone, locale: @locale) %><% is_same_day?(@start_date, @end_date) -> %><%= gettext "On %{date} from %{start_time} to %{end_time}", date: datetime_to_date_string(@start_date, @locale), start_time: datetime_to_time_string(@start_date, @locale), end_time: datetime_to_time_string(@end_date, @locale) %><%= if @event.options.timezone != @timezone do %> <%= gettext "🌐 %{timezone} %{offset}", timezone: @event.options.timezone, offset: Cldr.DateTime.Formatter.zone_gmt(@start_date) %><% end %><% true -> %><%= gettext "From the %{start} to the %{end}", start: datetime_to_string(@start_date, @locale, :short), end: datetime_to_string(@end_date, @locale, :short) %><%= if @event.options.timezone != @timezone do %> <%= gettext "🌐 %{timezone} %{offset}", timezone: @event.options.timezone, offset: Cldr.DateTime.Formatter.zone_gmt(@start_date) %><% end %><% end %>
|
<%= cond do %><% @end_date == nil -> %><%= render("date/event_tz_date.text", date: @start_date, event: @event, timezone: @timezone, locale: @locale) %><% same_day?(@start_date, @end_date) -> %><%= gettext "On %{date} from %{start_time} to %{end_time}", date: datetime_to_date_string(@start_date, @locale), start_time: datetime_to_time_string(@start_date, @locale), end_time: datetime_to_time_string(@end_date, @locale) %><%= if @event.options.timezone != @timezone do %> <%= gettext "🌐 %{timezone} %{offset}", timezone: @event.options.timezone, offset: Cldr.DateTime.Formatter.zone_gmt(@start_date) %><% end %><% true -> %><%= gettext "From the %{start} to the %{end}", start: datetime_to_string(@start_date, @locale, :short), end: datetime_to_string(@end_date, @locale, :short) %><%= if @event.options.timezone != @timezone do %> <%= gettext "🌐 %{timezone} %{offset}", timezone: @event.options.timezone, offset: Cldr.DateTime.Formatter.zone_gmt(@start_date) %><% end %><% end %>
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.classList.remove('dark')
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<%= if is_root(assigns) do %>
|
<%= if root?(assigns) do %>
|
||||||
<link rel="preload" href="/img/shape-1.svg" as="image" />
|
<link rel="preload" href="/img/shape-1.svg" as="image" />
|
||||||
<link rel="preload" href="/img/shape-2.svg" as="image" />
|
<link rel="preload" href="/img/shape-2.svg" as="image" />
|
||||||
<link rel="preload" href="/img/shape-3.svg" as="image" />
|
<link rel="preload" href="/img/shape-3.svg" as="image" />
|
||||||
|
|
|
@ -25,7 +25,7 @@ defmodule Mobilizon.Web.EmailView do
|
||||||
defdelegate datetime_tz_convert(datetime, timezone), to: DateTimeRenderer
|
defdelegate datetime_tz_convert(datetime, timezone), to: DateTimeRenderer
|
||||||
defdelegate datetime_relative(datetime, locale \\ "en"), to: DateTimeRenderer
|
defdelegate datetime_relative(datetime, locale \\ "en"), to: DateTimeRenderer
|
||||||
defdelegate render_address(address), to: Address
|
defdelegate render_address(address), to: Address
|
||||||
defdelegate is_same_day?(one, two), to: DateTimeRenderer
|
defdelegate same_day?(one, two), to: DateTimeRenderer
|
||||||
defdelegate display_name(actor), to: Actor
|
defdelegate display_name(actor), to: Actor
|
||||||
defdelegate preferred_username_and_domain(actor), to: Actor
|
defdelegate preferred_username_and_domain(actor), to: Actor
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,8 @@ defmodule Mobilizon.Web.PageView do
|
||||||
assigns |> Map.get(:locale, "en") |> get_language_direction()
|
assigns |> Map.get(:locale, "en") |> get_language_direction()
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec is_root(map()) :: boolean()
|
@spec root?(map()) :: boolean()
|
||||||
def is_root(assigns) do
|
def root?(assigns) do
|
||||||
assigns |> Map.get(:conn, %{request_path: "/"}) |> Map.get(:request_path, "/") == "/"
|
assigns |> Map.get(:conn, %{request_path: "/"}) |> Map.get(:request_path, "/") == "/"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
"**/*.{js,ts,vue}": [
|
"**/*.{js,ts,vue}": [
|
||||||
"eslint --fix",
|
"eslint --fix",
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"**/*.{ex,exs,eex,heex}": [
|
||||||
|
"mix format",
|
||||||
|
"mix credo"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
defmodule Mobilizon.Storage.Repo.Migrations.ChangeActorInstanceDescriptionTypeToText do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def up do
|
||||||
|
alter table(:instance_actors) do
|
||||||
|
modify(:instance_description, :text)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down do
|
||||||
|
alter table(:instance_actors) do
|
||||||
|
modify(:instance_description, :string)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1641,5 +1641,6 @@
|
||||||
"Announcements for {eventTitle}": "Announcements for {eventTitle}",
|
"Announcements for {eventTitle}": "Announcements for {eventTitle}",
|
||||||
"Visit {instance_domain}": "Visit {instance_domain}",
|
"Visit {instance_domain}": "Visit {instance_domain}",
|
||||||
"Software details: {software_details}": "Software details: {software_details}",
|
"Software details: {software_details}": "Software details: {software_details}",
|
||||||
"Only instances with an application actor can be followed": "Only instances with an application actor can be followed"
|
"Only instances with an application actor can be followed": "Only instances with an application actor can be followed",
|
||||||
|
"Domain or instance name": "Domain or instance name"
|
||||||
}
|
}
|
|
@ -1635,5 +1635,6 @@
|
||||||
"Announcements for {eventTitle}": "Annonces pour {eventTitle}",
|
"Announcements for {eventTitle}": "Annonces pour {eventTitle}",
|
||||||
"Visit {instance_domain}": "Visiter {instance_domain}",
|
"Visit {instance_domain}": "Visiter {instance_domain}",
|
||||||
"Software details: {software_details}": "Détails du logiciel : {software_details}",
|
"Software details: {software_details}": "Détails du logiciel : {software_details}",
|
||||||
"Only instances with an application actor can be followed": "Seules les instances avec un acteur application peuvent être suivies"
|
"Only instances with an application actor can be followed": "Seules les instances avec un acteur application peuvent être suivies",
|
||||||
|
"Domain or instance name": "Domaine ou nom de l'instance"
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,15 +54,14 @@
|
||||||
>
|
>
|
||||||
</o-field>
|
</o-field>
|
||||||
<o-field
|
<o-field
|
||||||
:label="t('Domain')"
|
:label="t('Domain or instance name')"
|
||||||
label-for="domain-filter"
|
label-for="domain-filter"
|
||||||
class="flex-auto"
|
class="flex-auto"
|
||||||
>
|
>
|
||||||
<o-input
|
<o-input
|
||||||
id="domain-filter"
|
id="domain-filter"
|
||||||
:placeholder="t('mobilizon-instance.tld')"
|
:placeholder="t('mobilizon-instance.tld')"
|
||||||
:value="filterDomain"
|
v-model="filterDomain"
|
||||||
@input="debouncedUpdateDomainFilter"
|
|
||||||
/>
|
/>
|
||||||
</o-field>
|
</o-field>
|
||||||
</div>
|
</div>
|
||||||
|
@ -223,7 +222,6 @@ import { Paginate } from "@/types/paginate";
|
||||||
import RouteName from "../../router/name";
|
import RouteName from "../../router/name";
|
||||||
import { IInstance } from "@/types/instance.model";
|
import { IInstance } from "@/types/instance.model";
|
||||||
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
||||||
import debounce from "lodash/debounce";
|
|
||||||
import {
|
import {
|
||||||
InstanceFilterFollowStatus,
|
InstanceFilterFollowStatus,
|
||||||
InstanceFollowStatus,
|
InstanceFollowStatus,
|
||||||
|
@ -254,12 +252,16 @@ const followStatus = useRouteQuery(
|
||||||
|
|
||||||
const { result: instancesResult } = useQuery<{
|
const { result: instancesResult } = useQuery<{
|
||||||
instances: Paginate<IInstance>;
|
instances: Paginate<IInstance>;
|
||||||
}>(INSTANCES, () => ({
|
}>(
|
||||||
|
INSTANCES,
|
||||||
|
() => ({
|
||||||
page: instancePage.value,
|
page: instancePage.value,
|
||||||
limit: INSTANCES_PAGE_LIMIT,
|
limit: INSTANCES_PAGE_LIMIT,
|
||||||
filterDomain: filterDomain.value,
|
filterDomain: filterDomain.value,
|
||||||
filterFollowStatus: followStatus.value,
|
filterFollowStatus: followStatus.value,
|
||||||
}));
|
}),
|
||||||
|
{ debounce: 500 }
|
||||||
|
);
|
||||||
|
|
||||||
const instances = computed(() => instancesResult.value?.instances);
|
const instances = computed(() => instancesResult.value?.instances);
|
||||||
|
|
||||||
|
@ -276,13 +278,6 @@ const newRelayAddress = ref("");
|
||||||
|
|
||||||
// relayFollowers: Paginate<IFollower> = { elements: [], total: 0 };
|
// relayFollowers: Paginate<IFollower> = { elements: [], total: 0 };
|
||||||
|
|
||||||
const updateDomainFilter = (event: InputEvent) => {
|
|
||||||
const newValue = (event.target as HTMLInputElement).value;
|
|
||||||
filterDomain.value = newValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
const debouncedUpdateDomainFilter = debounce(updateDomainFilter, 500);
|
|
||||||
|
|
||||||
const hasFilter = computed((): boolean => {
|
const hasFilter = computed((): boolean => {
|
||||||
return (
|
return (
|
||||||
followStatus.value !== InstanceFilterFollowStatus.ALL ||
|
followStatus.value !== InstanceFilterFollowStatus.ALL ||
|
||||||
|
|
|
@ -179,7 +179,7 @@ defmodule Mix.Tasks.Mobilizon.Actors.NewTest do
|
||||||
assert %Actor{name: @group_name, preferred_username: @group_username, id: group_id} =
|
assert %Actor{name: @group_name, preferred_username: @group_username, id: group_id} =
|
||||||
Actors.get_group_by_title(@group_username)
|
Actors.get_group_by_title(@group_username)
|
||||||
|
|
||||||
assert Actors.is_administrator?(admin_id, group_id)
|
assert Actors.administrator?(admin_id, group_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue