end
end
+ def react_with_emoji(user, object, emoji, options \\ []) do
+ with local <- Keyword.get(options, :local, true),
+ activity_id <- Keyword.get(options, :activity_id, nil),
+ Pleroma.Emoji.is_unicode_emoji?(emoji),
+ reaction_data <- make_emoji_reaction_data(user, object, emoji, activity_id),
+ {:ok, activity} <- insert(reaction_data, local),
+ {:ok, object} <- add_emoji_reaction_to_object(activity, object),
+ :ok <- maybe_federate(activity) do
+ {:ok, activity, object}
+ end
+ end
+
+ def unreact_with_emoji(user, reaction_id, options \\ []) do
+ with local <- Keyword.get(options, :local, true),
+ activity_id <- Keyword.get(options, :activity_id, nil),
+ user_ap_id <- user.ap_id,
+ %Activity{actor: ^user_ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id),
+ object <- Object.normalize(reaction_activity),
+ unreact_data <- make_undo_data(user, reaction_activity, activity_id),
+ {:ok, activity} <- insert(unreact_data, local),
+ {:ok, object} <- remove_emoji_reaction_from_object(reaction_activity, object),
+ :ok <- maybe_federate(activity) do
+ {:ok, activity, object}
+ end
+ end
+
# TODO: This is weird, maybe we shouldn't check here if we can make the activity.
def like(
%User{ap_id: ap_id} = user,
user = User.get_cached_by_ap_id(actor)
to = (object.data["to"] || []) ++ (object.data["cc"] || [])
- with {:ok, object, activity} <- Object.delete(object),
+ with create_activity <- Activity.get_create_by_object_ap_id(id),
data <-
%{
"type" => "Delete",
"actor" => actor,
"object" => id,
"to" => to,
- "deleted_activity_id" => activity && activity.id
+ "deleted_activity_id" => create_activity && create_activity.id
}
|> maybe_put("id", activity_id),
{:ok, activity} <- insert(data, local, false),
+ {:ok, object, _create_activity} <- Object.delete(object),
stream_out_participations(object, user),
_ <- decrease_replies_count_if_reply(object),
{:ok, _actor} <- decrease_note_count_if_public(user, object),
with flag_data <- make_flag_data(params, additional),
{:ok, activity} <- insert(flag_data, local),
- :ok <- maybe_federate(activity) do
+ {:ok, stripped_activity} <- strip_report_status_data(activity),
+ :ok <- maybe_federate(stripped_activity) do
Enum.each(User.all_superusers(), fn superuser ->
superuser
|> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content)
end
end
+ def move(%User{} = origin, %User{} = target, local \\ true) do
+ params = %{
+ "type" => "Move",
+ "actor" => origin.ap_id,
+ "object" => origin.ap_id,
+ "target" => target.ap_id
+ }
+
+ with true <- origin.ap_id in target.also_known_as,
+ {:ok, activity} <- insert(params, local) do
+ maybe_federate(activity)
+
+ BackgroundWorker.enqueue("move_following", %{
+ "origin_id" => origin.id,
+ "target_id" => target.id
+ })
+
+ {:ok, activity}
+ else
+ false -> {:error, "Target account must have the origin in `alsoKnownAs`"}
+ err -> err
+ end
+ end
+
defp fetch_activities_for_context_query(context, opts) do
public = [Pleroma.Constants.as_public()]
|> fetch_activities_query(opts)
|> restrict_unlisted()
|> Pagination.fetch_paginated(opts, pagination)
- |> Enum.reverse()
end
@valid_visibilities ~w[direct unlisted public private]
|> Map.put("whole_db", true)
|> Map.put("pinned_activity_ids", user.pinned_activities)
+ params =
+ if User.blocks?(reading_user, user) do
+ params
+ else
+ params
+ |> Map.put("blocking_user", reading_user)
+ |> Map.put("muting_user", reading_user)
+ end
+
recipients =
user_activities_recipients(%{
"godmode" => params["godmode"],
|> Enum.reverse()
end
+ def fetch_instance_activities(params) do
+ params =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("instance", params["instance"])
+ |> Map.put("whole_db", true)
+
+ fetch_activities([Pleroma.Constants.as_public()], params, :offset)
+ |> Enum.reverse()
+ end
+
defp user_activities_recipients(%{"godmode" => true}) do
[]
end
defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query
defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do
- mutes = user.mutes
+ mutes = opts["muted_users_ap_ids"] || User.muted_users_ap_ids(user)
query =
from([activity] in query,
defp restrict_muted(query, _), do: query
- defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do
- blocks = user.blocks || []
+ defp restrict_blocked(query, %{"blocking_user" => %User{} = user} = opts) do
+ blocked_ap_ids = opts["blocked_users_ap_ids"] || User.blocked_users_ap_ids(user)
domain_blocks = user.domain_blocks || []
query =
from(
[activity, object: o] in query,
- where: fragment("not (? = ANY(?))", activity.actor, ^blocks),
- where: fragment("not (? && ?)", activity.recipients, ^blocks),
+ where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
+ where: fragment("not (? && ?)", activity.recipients, ^blocked_ap_ids),
where:
fragment(
"not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
activity.data,
activity.data,
- ^blocks
+ ^blocked_ap_ids
),
where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks),
where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks)
defp restrict_pinned(query, _), do: query
- defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do
- muted_reblogs = user.muted_reblogs || []
+ defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user} = opts) do
+ muted_reblogs = opts["reblog_muted_users_ap_ids"] || User.reblog_muted_users_ap_ids(user)
from(
activity in query,
defp restrict_muted_reblogs(query, _), do: query
+ defp restrict_instance(query, %{"instance" => instance}) do
+ users =
+ from(
+ u in User,
+ select: u.ap_id,
+ where: fragment("? LIKE ?", u.nickname, ^"%@#{instance}")
+ )
+ |> Repo.all()
+
+ from(activity in query, where: activity.actor in ^users)
+ end
+
+ defp restrict_instance(query, _), do: query
+
defp exclude_poll_votes(query, %{"include_poll_votes" => true}), do: query
defp exclude_poll_votes(query, _) do
defp maybe_order(query, _), do: query
+ defp fetch_activities_query_ap_ids_ops(opts) do
+ source_user = opts["muting_user"]
+ ap_id_relations = if source_user, do: [:mute, :reblog_mute], else: []
+
+ ap_id_relations =
+ ap_id_relations ++
+ if opts["blocking_user"] && opts["blocking_user"] == source_user do
+ [:block]
+ else
+ []
+ end
+
+ preloaded_ap_ids = User.outgoing_relations_ap_ids(source_user, ap_id_relations)
+
+ restrict_blocked_opts = Map.merge(%{"blocked_users_ap_ids" => preloaded_ap_ids[:block]}, opts)
+ restrict_muted_opts = Map.merge(%{"muted_users_ap_ids" => preloaded_ap_ids[:mute]}, opts)
+
+ restrict_muted_reblogs_opts =
+ Map.merge(%{"reblog_muted_users_ap_ids" => preloaded_ap_ids[:reblog_mute]}, opts)
+
+ {restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts}
+ end
+
def fetch_activities_query(recipients, opts \\ %{}) do
+ {restrict_blocked_opts, restrict_muted_opts, restrict_muted_reblogs_opts} =
+ fetch_activities_query_ap_ids_ops(opts)
+
config = %{
skip_thread_containment: Config.get([:instance, :skip_thread_containment])
}
|> restrict_type(opts)
|> restrict_state(opts)
|> restrict_favorited_by(opts)
- |> restrict_blocked(opts)
- |> restrict_muted(opts)
+ |> restrict_blocked(restrict_blocked_opts)
+ |> restrict_muted(restrict_muted_opts)
|> restrict_media(opts)
|> restrict_visibility(opts)
|> restrict_thread_visibility(opts, config)
|> restrict_replies(opts)
|> restrict_reblogs(opts)
|> restrict_pinned(opts)
- |> restrict_muted_reblogs(opts)
+ |> restrict_muted_reblogs(restrict_muted_reblogs_opts)
+ |> restrict_instance(opts)
|> Activity.restrict_deactivated_users()
|> exclude_poll_votes(opts)
|> exclude_visibility(opts)
name: data["name"],
follower_address: data["followers"],
following_address: data["following"],
- bio: data["summary"]
+ bio: data["summary"],
+ also_known_as: Map.get(data, "alsoKnownAs", [])
}
# nickname can be nil because of virtual actors
end
end
- defp collection_private(data) do
- if is_map(data["first"]) and
- data["first"]["type"] in ["CollectionPage", "OrderedCollectionPage"] do
+ defp collection_private(%{"first" => first}) do
+ if is_map(first) and
+ first["type"] in ["CollectionPage", "OrderedCollectionPage"] do
{:ok, false}
else
with {:ok, %{"type" => type}} when type in ["CollectionPage", "OrderedCollectionPage"] <-
- Fetcher.fetch_and_contain_remote_object_from_id(data["first"]) do
+ Fetcher.fetch_and_contain_remote_object_from_id(first) do
{:ok, false}
else
{:error, {:ok, %{status: code}}} when code in [401, 403] ->
end
end
+ defp collection_private(_data), do: {:ok, true}
+
def user_data_from_user_object(data) do
with {:ok, data} <- MRF.filter(data),
{:ok, data} <- object_to_user_data(data) do