X-Git-Url: https://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Factivity_pub%2Factivity_pub.ex;h=f32d0417596e1dac0c5a7ae5608fbf96a58d1b13;hb=cf0c861d0012f27ae555247834187d509d7a7114;hp=364452b5d434d24317a2c260251cc7a7883e8444;hpb=37812740c4c03f0a79d17ff186db644a60414ff7;p=akkoma diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 364452b5d..f32d04175 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.Activity.Ir.Topics alias Pleroma.Config alias Pleroma.Conversation + alias Pleroma.Conversation.Participation alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Object.Containment @@ -68,7 +69,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp check_actor_is_active(actor) do if not is_nil(actor) do with user <- User.get_cached_by_ap_id(actor), - false <- user.info.deactivated do + false <- user.deactivated do true else _e -> false @@ -131,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, map} <- MRF.filter(map), {recipients, _, _} = get_recipients(map), {:fake, false, map, recipients} <- {:fake, fake, map, recipients}, - :ok <- Containment.contain_child(map), + {:containment, :ok} <- {:containment, Containment.contain_child(map)}, {:ok, map, object} <- insert_full_object(map) do {:ok, activity} = Repo.insert(%Activity{ @@ -153,11 +154,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Notification.create_notifications(activity) - participations = - activity - |> Conversation.create_or_bump_for() - |> get_participations() - + conversation = create_or_bump_conversation(activity, map["actor"]) + participations = get_participations(conversation) stream_out(activity) stream_out_participations(participations) {:ok, activity} @@ -182,7 +180,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - defp get_participations({:ok, %{participations: participations}}), do: participations + defp create_or_bump_conversation(activity, actor) do + with {:ok, conversation} <- Conversation.create_or_bump_for(activity), + %User{} = user <- User.get_cached_by_ap_id(actor), + Participation.mark_as_read(user, conversation) do + {:ok, conversation} + end + end + + defp get_participations({:ok, conversation}) do + conversation + |> Repo.preload(:participations, force: true) + |> Map.get(:participations) + end + defp get_participations(_), do: [] def stream_out_participations(participations) do @@ -225,6 +236,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do # only accept false as false value local = !(params[:local] == false) published = params[:published] + quick_insert? = Pleroma.Config.get([:env]) == :benchmark with create_data <- make_create_data( @@ -235,12 +247,14 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:fake, false, activity} <- {:fake, fake, activity}, _ <- increase_replies_count_if_reply(create_data), _ <- increase_poll_votes_if_vote(create_data), - # Changing note count prior to enqueuing federation task in order to avoid - # race conditions on updating user.info + {:quick_insert, false, activity} <- {:quick_insert, quick_insert?, activity}, {:ok, _actor} <- increase_note_count_if_public(actor, activity), :ok <- maybe_federate(activity) do {:ok, activity} else + {:quick_insert, true, activity} -> + {:ok, activity} + {:fake, true, activity} -> {:ok, activity} @@ -308,6 +322,32 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do 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, @@ -429,8 +469,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do {:ok, activity} <- insert(data, local, false), stream_out_participations(object, user), _ <- decrease_replies_count_if_reply(object), - # Changing note count prior to enqueuing federation task in order to avoid - # race conditions on updating user.info {:ok, _actor} <- decrease_note_count_if_public(user, object), :ok <- maybe_federate(activity) do {:ok, activity} @@ -491,7 +529,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do 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) @@ -506,7 +545,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do public = [Pleroma.Constants.as_public()] recipients = - if opts["user"], do: [opts["user"].ap_id | opts["user"].following] ++ public, else: public + if opts["user"], + do: [opts["user"].ap_id | User.following(opts["user"])] ++ public, + else: public from(activity in Activity) |> maybe_preload_objects(opts) @@ -553,7 +594,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> fetch_activities_query(opts) |> restrict_unlisted() |> Pagination.fetch_paginated(opts, pagination) - |> Enum.reverse() end @valid_visibilities ~w[direct unlisted public private] @@ -596,12 +636,55 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_visibility(query, _visibility), do: query + defp exclude_visibility(query, %{"exclude_visibilities" => visibility}) + when is_list(visibility) do + if Enum.all?(visibility, &(&1 in @valid_visibilities)) do + from( + a in query, + where: + not fragment( + "activity_visibility(?, ?, ?) = ANY (?)", + a.actor, + a.recipients, + a.data, + ^visibility + ) + ) + else + Logger.error("Could not exclude visibility to #{visibility}") + query + end + end + + defp exclude_visibility(query, %{"exclude_visibilities" => visibility}) + when visibility in @valid_visibilities do + from( + a in query, + where: + not fragment( + "activity_visibility(?, ?, ?) = ?", + a.actor, + a.recipients, + a.data, + ^visibility + ) + ) + end + + defp exclude_visibility(query, %{"exclude_visibilities" => visibility}) + when visibility not in @valid_visibilities do + Logger.error("Could not exclude visibility to #{visibility}") + query + end + + defp exclude_visibility(query, _visibility), do: query + defp restrict_thread_visibility(query, _, %{skip_thread_containment: true} = _), do: query defp restrict_thread_visibility( query, - %{"user" => %User{info: %{skip_thread_containment: true}}}, + %{"user" => %User{skip_thread_containment: true}}, _ ), do: query @@ -639,7 +722,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Map.put("user", reading_user) |> Map.put("actor_id", user.ap_id) |> Map.put("whole_db", true) - |> Map.put("pinned_activity_ids", user.info.pinned_activities) + |> Map.put("pinned_activity_ids", user.pinned_activities) recipients = user_activities_recipients(%{ @@ -651,13 +734,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> 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 user_activities_recipients(%{"reading_user" => reading_user}) do if reading_user do - [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | reading_user.following] + [Pleroma.Constants.as_public()] ++ [reading_user.ap_id | User.following(reading_user)] else [Pleroma.Constants.as_public()] end @@ -800,8 +894,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted(query, %{"with_muted" => val}) when val in [true, "true", "1"], do: query - defp restrict_muted(query, %{"muting_user" => %User{info: info}} = opts) do - mutes = info.mutes + defp restrict_muted(query, %{"muting_user" => %User{} = user} = opts) do + mutes = user.mutes query = from([activity] in query, @@ -818,9 +912,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_muted(query, _), do: query - defp restrict_blocked(query, %{"blocking_user" => %User{info: info}}) do - blocks = info.blocks || [] - domain_blocks = info.domain_blocks || [] + defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do + blocks = user.blocks || [] + domain_blocks = user.domain_blocks || [] query = if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) @@ -861,8 +955,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_pinned(query, _), do: query - defp restrict_muted_reblogs(query, %{"muting_user" => %User{info: info}}) do - muted_reblogs = info.muted_reblogs || [] + defp restrict_muted_reblogs(query, %{"muting_user" => %User{} = user}) do + muted_reblogs = user.muted_reblogs || [] from( activity in query, @@ -878,6 +972,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do 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 @@ -958,8 +1066,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> restrict_reblogs(opts) |> restrict_pinned(opts) |> restrict_muted_reblogs(opts) + |> restrict_instance(opts) |> Activity.restrict_deactivated_users() |> exclude_poll_votes(opts) + |> exclude_visibility(opts) end def fetch_activities(recipients, opts \\ %{}, pagination \\ :keyset) do @@ -1046,17 +1156,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do locked = data["manuallyApprovesFollowers"] || false data = Transmogrifier.maybe_fix_user_object(data) discoverable = data["discoverable"] || false + invisible = data["invisible"] || false user_data = %{ ap_id: data["id"], - info: %{ - ap_enabled: true, - source_data: data, - banner: banner, - fields: fields, - locked: locked, - discoverable: discoverable - }, + ap_enabled: true, + source_data: data, + banner: banner, + fields: fields, + locked: locked, + discoverable: discoverable, + invisible: invisible, avatar: avatar, name: data["name"], follower_address: data["followers"], @@ -1108,7 +1218,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do with {:enabled, true} <- {:enabled, Pleroma.Config.get([:instance, :external_user_synchronization])}, {:ok, info} <- fetch_follow_information_for_user(data) do - info = Map.merge(data.info, info) + info = Map.merge(data[:info] || %{}, info) Map.put(data, :info, info) else {:enabled, false} -> @@ -1123,13 +1233,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do 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] -> @@ -1144,6 +1254,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do 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 @@ -1159,7 +1271,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do data <- maybe_update_follow_information(data) do {:ok, data} else - e -> Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") + e -> + Logger.error("Could not decode user at fetch #{ap_id}, #{inspect(e)}") + {:error, e} end end