diff options
Diffstat (limited to 'lib/pleroma/web/activity_pub')
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 130 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub_controller.ex | 6 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf.ex | 24 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/drop_policy.ex | 2 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/noop_policy.ex | 3 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/mrf/simple_policy.ex | 46 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 133 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 133 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/views/user_view.ex | 47 |
9 files changed, 443 insertions, 81 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3ddc009a1..8485a8009 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1,6 +1,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do alias Pleroma.{Activity, Repo, Object, Upload, User, Notification} - alias Pleroma.Web.ActivityPub.Transmogrifier + alias Pleroma.Web.ActivityPub.{Transmogrifier, MRF} alias Pleroma.Web.WebFinger alias Pleroma.Web.Federator alias Pleroma.Web.OStatus @@ -11,16 +11,29 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do @httpoison Application.get_env(:pleroma, :httpoison) @instance Application.get_env(:pleroma, :instance) - @rewrite_policy Keyword.get(@instance, :rewrite_policy) def get_recipients(data) do (data["to"] || []) ++ (data["cc"] || []) end + defp check_actor_is_active(actor) do + if not is_nil(actor) do + with user <- User.get_cached_by_ap_id(actor), + nil <- user.info["deactivated"] do + :ok + else + _e -> :reject + end + else + :ok + end + end + def insert(map, local \\ true) when is_map(map) do with nil <- Activity.get_by_ap_id(map["id"]), map <- lazy_put_activity_defaults(map), - {:ok, map} <- @rewrite_policy.filter(map), + :ok <- check_actor_is_active(map["actor"]), + {:ok, map} <- MRF.filter(map), :ok <- insert_full_object(map) do {:ok, activity} = Repo.insert(%Activity{ @@ -66,7 +79,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do ), {:ok, activity} <- insert(create_data, local), :ok <- maybe_federate(activity), - {:ok, actor} <- User.increase_note_count(actor) do + {:ok, _actor} <- User.increase_note_count(actor) do {:ok, activity} end end @@ -118,11 +131,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def unlike(%User{} = actor, %Object{} = object) do - with %Activity{} = activity <- get_existing_like(actor.ap_id, object), - {:ok, _activity} <- Repo.delete(activity), - {:ok, object} <- remove_like_from_object(activity, object) do - {:ok, object} + def unlike( + %User{} = actor, + %Object{} = object, + activity_id \\ nil, + local \\ true + ) do + with %Activity{} = like_activity <- get_existing_like(actor.ap_id, object), + unlike_data <- make_unlike_data(actor, like_activity, activity_id), + {:ok, unlike_activity} <- insert(unlike_data, local), + {:ok, _activity} <- Repo.delete(like_activity), + {:ok, object} <- remove_like_from_object(like_activity, object), + :ok <- maybe_federate(unlike_activity) do + {:ok, unlike_activity, like_activity, object} else _e -> {:ok, object} end @@ -145,6 +166,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + def unannounce( + %User{} = actor, + %Object{} = object, + activity_id \\ nil, + local \\ true + ) do + with %Activity{} = announce_activity <- get_existing_announce(actor.ap_id, object), + unannounce_data <- make_unannounce_data(actor, announce_activity, activity_id), + {:ok, unannounce_activity} <- insert(unannounce_data, local), + :ok <- maybe_federate(unannounce_activity), + {:ok, _activity} <- Repo.delete(announce_activity), + {:ok, object} <- remove_announce_from_object(announce_activity, object) do + {:ok, unannounce_activity, announce_activity, object} + else + _e -> {:ok, object} + end + end + def follow(follower, followed, activity_id \\ nil, local \\ true) do with data <- make_follow_data(follower, followed, activity_id), {:ok, activity} <- insert(data, local), @@ -153,12 +192,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def unfollow(follower, followed, local \\ true) do + def unfollow(follower, followed, activity_id \\ nil, local \\ true) do with %Activity{} = follow_activity <- fetch_latest_follow(follower, followed), - unfollow_data <- make_unfollow_data(follower, followed, follow_activity), + unfollow_data <- make_unfollow_data(follower, followed, follow_activity, activity_id), {:ok, activity} <- insert(unfollow_data, local), - :ok, - maybe_federate(activity) do + :ok <- maybe_federate(activity) do {:ok, activity} end end @@ -177,7 +215,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Repo.delete_all(Activity.all_non_create_by_object_ap_id_q(id)), {:ok, activity} <- insert(data, local), :ok <- maybe_federate(activity), - {:ok, actor} <- User.decrease_note_count(user) do + {:ok, _actor} <- User.decrease_note_count(user) do + {:ok, activity} + end + end + + def block(blocker, blocked, activity_id \\ nil, local \\ true) do + follow_activity = fetch_latest_follow(blocker, blocked) + + if follow_activity do + unfollow(blocker, blocked, nil, local) + end + + with block_data <- make_block_data(blocker, blocked, activity_id), + {:ok, activity} <- insert(block_data, local), + :ok <- maybe_federate(activity) do + {:ok, activity} + end + end + + def unblock(blocker, blocked, activity_id \\ nil, local \\ true) do + with %Activity{} = block_activity <- fetch_latest_block(blocker, blocked), + unblock_data <- make_unblock_data(blocker, blocked, block_activity, activity_id), + {:ok, activity} <- insert(unblock_data, local), + :ok <- maybe_federate(activity) do {:ok, activity} end end @@ -212,15 +273,34 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Repo.all(query) end - # TODO: Make this work properly with unlisted. def fetch_public_activities(opts \\ %{}) do q = fetch_activities_query(["https://www.w3.org/ns/activitystreams#Public"], opts) q + |> restrict_unlisted() |> Repo.all() |> Enum.reverse() end + def fetch_user_activities(user, reading_user, params \\ %{}) do + params = + params + |> Map.put("type", ["Create", "Announce"]) + |> Map.put("actor_id", user.ap_id) + |> Map.put("whole_db", true) + + recipients = + if reading_user do + ["https://www.w3.org/ns/activitystreams#Public"] ++ + [reading_user.ap_id | reading_user.following] + else + ["https://www.w3.org/ns/activitystreams#Public"] + end + + fetch_activities(recipients, params) + |> Enum.reverse() + end + defp restrict_since(query, %{"since_id" => since_id}) do from(activity in query, where: activity.id > ^since_id) end @@ -236,7 +316,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_tag(query, _), do: query - defp restrict_recipients(query, [], user), do: query + defp restrict_recipients(query, [], _user), do: query defp restrict_recipients(query, recipients, nil) do from(activity in query, where: fragment("? && ?", ^recipients, activity.recipients)) @@ -323,6 +403,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_blocked(query, _), do: query + defp restrict_unlisted(query) do + from( + activity in query, + where: + fragment( + "not (coalesce(?->'cc', '{}'::jsonb) \\?| ?)", + activity.data, + ^["https://www.w3.org/ns/activitystreams#Public"] + ) + ) + end + def fetch_activities_query(recipients, opts \\ %{}) do base_query = from( @@ -372,6 +464,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do "url" => [%{"href" => data["image"]["url"]}] } + data = Transmogrifier.maybe_fix_user_object(data) + user_data = %{ ap_id: data["id"], info: %{ @@ -400,7 +494,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end def make_user_from_ap_id(ap_id) do - if user = User.get_by_ap_id(ap_id) do + if _user = User.get_by_ap_id(ap_id) do Transmogrifier.upgrade_user_from_ap_id(ap_id) else with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id) do @@ -496,7 +590,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do object = %Object{} -> {:ok, object} - e -> + _e -> Logger.info("Couldn't get object via AP, trying out OStatus fetching...") case OStatus.fetch_activity_from_url(id) do diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex index 12f61f5f0..c7d50893f 100644 --- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex +++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex @@ -1,7 +1,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do use Pleroma.Web, :controller - alias Pleroma.{User, Repo, Object, Activity} - alias Pleroma.Web.ActivityPub.{ObjectView, UserView, Transmogrifier} + alias Pleroma.{User, Object} + alias Pleroma.Web.ActivityPub.{ObjectView, UserView} alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.Federator @@ -93,7 +93,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do Logger.info("Signature not from author, relayed message, fetching from source") ActivityPub.fetch_object_from_id(params["object"]["id"]) else - Logger.info("Signature error") + Logger.info("Signature error - make sure you are forwarding the HTTP Host header!") Logger.info("Could not validate #{params["actor"]}") Logger.info(inspect(conn.req_headers)) end diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex new file mode 100644 index 000000000..0a4e2bf80 --- /dev/null +++ b/lib/pleroma/web/activity_pub/mrf.ex @@ -0,0 +1,24 @@ +defmodule Pleroma.Web.ActivityPub.MRF do + @callback filter(Map.t()) :: {:ok | :reject, Map.t()} + + def filter(object) do + get_policies() + |> Enum.reduce({:ok, object}, fn + policy, {:ok, object} -> + policy.filter(object) + + _, error -> + error + end) + end + + def get_policies() do + Application.get_env(:pleroma, :instance, []) + |> Keyword.get(:rewrite_policy, []) + |> get_policies() + end + + defp get_policies(policy) when is_atom(policy), do: [policy] + defp get_policies(policies) when is_list(policies), do: policies + defp get_policies(_), do: [] +end diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex index 4333bca28..811947943 100644 --- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex @@ -1,6 +1,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do require Logger + @behaviour Pleroma.Web.ActivityPub.MRF + @impl true def filter(object) do Logger.info("REJECTING #{inspect(object)}") {:reject, object} diff --git a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex index 9dd3acb04..e26f60d26 100644 --- a/lib/pleroma/web/activity_pub/mrf/noop_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/noop_policy.ex @@ -1,4 +1,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.NoOpPolicy do + @behaviour Pleroma.Web.ActivityPub.MRF + + @impl true def filter(object) do {:ok, object} end diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex index ea1af0f4d..8d770387d 100644 --- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex @@ -1,5 +1,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do alias Pleroma.User + @behaviour Pleroma.Web.ActivityPub.MRF @mrf_policy Application.get_env(:pleroma, :mrf_simple) @@ -17,9 +18,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do if actor_info.host in @media_removal do child_object = Map.delete(object["object"], "attachment") object = Map.put(object, "object", child_object) + {:ok, object} + else + {:ok, object} end - - {:ok, object} end @media_nsfw Keyword.get(@mrf_policy, :media_nsfw) @@ -32,9 +34,10 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do child_object = Map.put(child_object, "tags", tags) child_object = Map.put(child_object, "sensitive", true) object = Map.put(object, "object", child_object) + {:ok, object} + else + {:ok, object} end - - {:ok, object} end @ftl_removal Keyword.get(@mrf_policy, :federated_timeline_removal) @@ -43,24 +46,31 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do user = User.get_by_ap_id(object["actor"]) # flip to/cc relationship to make the post unlisted - if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and - user.follower_address in object["cc"] do - to = - List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++ - [user.follower_address] + object = + if "https://www.w3.org/ns/activitystreams#Public" in object["to"] and + user.follower_address in object["cc"] do + to = + List.delete(object["to"], "https://www.w3.org/ns/activitystreams#Public") ++ + [user.follower_address] - cc = - List.delete(object["cc"], user.follower_address) ++ - ["https://www.w3.org/ns/activitystreams#Public"] + cc = + List.delete(object["cc"], user.follower_address) ++ + ["https://www.w3.org/ns/activitystreams#Public"] - object = Map.put(object, "to", to) - object = Map.put(object, "cc", cc) - end - end + object + |> Map.put("to", to) + |> Map.put("cc", cc) + else + object + end - {:ok, object} + {:ok, object} + else + {:ok, object} + end end + @impl true def filter(object) do actor_info = URI.parse(object["actor"]) @@ -70,7 +80,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do {:ok, object} <- check_ftl_removal(actor_info, object) do {:ok, object} else - e -> {:reject, nil} + _e -> {:reject, nil} end end end diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 2871a2544..803445011 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -72,9 +72,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> Enum.reduce(%{}, fn data, mapping -> name = data["name"] - if String.starts_with?(name, ":") do - name = name |> String.slice(1..-2) - end + name = + if String.starts_with?(name, ":") do + name |> String.slice(1..-2) + else + name + end mapping |> Map.put(name, data["icon"]["url"]) end) @@ -143,12 +146,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def handle_incoming( - %{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = data + %{"type" => "Like", "object" => object_id, "actor" => actor, "id" => id} = _data ) do with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), - {:ok, activity, object} <- ActivityPub.like(actor, object, id, false) do + {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do {:ok, activity} else _e -> :error @@ -156,12 +159,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end def handle_incoming( - %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = data + %{"type" => "Announce", "object" => object_id, "actor" => actor, "id" => id} = _data ) do with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), - {:ok, activity, object} <- ActivityPub.announce(actor, object, id, false) do + {:ok, activity, _object} <- ActivityPub.announce(actor, object, id, false) do {:ok, activity} else _e -> :error @@ -202,7 +205,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do # TODO: Make secure. def handle_incoming( - %{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => id} = data + %{"type" => "Delete", "object" => object_id, "actor" => actor, "id" => _id} = _data ) do object_id = case object_id do @@ -210,19 +213,104 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do id -> id end - with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + with %User{} = _actor <- User.get_or_fetch_by_ap_id(actor), {:ok, object} <- get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), {:ok, activity} <- ActivityPub.delete(object, false) do {:ok, activity} else + _e -> :error + end + end + + def handle_incoming( + %{ + "type" => "Undo", + "object" => %{"type" => "Announce", "object" => object_id}, + "actor" => actor, + "id" => id + } = _data + ) do + with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, object} <- + get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), + {:ok, activity, _, _} <- ActivityPub.unannounce(actor, object, id, false) do + {:ok, activity} + else + _e -> :error + end + end + + def handle_incoming( + %{ + "type" => "Undo", + "object" => %{"type" => "Follow", "object" => followed}, + "actor" => follower, + "id" => id + } = _data + ) do + with %User{local: true} = followed <- User.get_cached_by_ap_id(followed), + %User{} = follower <- User.get_or_fetch_by_ap_id(follower), + {:ok, activity} <- ActivityPub.unfollow(follower, followed, id, false) do + User.unfollow(follower, followed) + {:ok, activity} + else e -> :error end end + def handle_incoming( + %{ + "type" => "Undo", + "object" => %{"type" => "Block", "object" => blocked}, + "actor" => blocker, + "id" => id + } = _data + ) do + with %User{local: true} = blocked <- User.get_cached_by_ap_id(blocked), + %User{} = blocker <- User.get_or_fetch_by_ap_id(blocker), + {:ok, activity} <- ActivityPub.unblock(blocker, blocked, id, false) do + User.unblock(blocker, blocked) + {:ok, activity} + else + e -> :error + end + end + + def handle_incoming( + %{"type" => "Block", "object" => blocked, "actor" => blocker, "id" => id} = data + ) do + with %User{local: true} = blocked = User.get_cached_by_ap_id(blocked), + %User{} = blocker = User.get_or_fetch_by_ap_id(blocker), + {:ok, activity} <- ActivityPub.block(blocker, blocked, id, false) do + User.unfollow(blocker, blocked) + User.block(blocker, blocked) + {:ok, activity} + else + e -> :error + end + end + + def handle_incoming( + %{ + "type" => "Undo", + "object" => %{"type" => "Like", "object" => object_id}, + "actor" => actor, + "id" => id + } = _data + ) do + with %User{} = actor <- User.get_or_fetch_by_ap_id(actor), + {:ok, object} <- + get_obj_helper(object_id) || ActivityPub.fetch_object_from_id(object_id), + {:ok, activity, _, _} <- ActivityPub.unlike(actor, object, id, false) do + {:ok, activity} + else + _e -> :error + end + end + # TODO # Accept - # Undo def handle_incoming(_), do: :error @@ -254,10 +342,10 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> set_reply_to_uri end - @doc - """ - internal -> Mastodon - """ + # @doc + # """ + # internal -> Mastodon + # """ def prepare_outgoing(%{"type" => "Create", "object" => %{"type" => "Note"} = object} = data) do object = @@ -272,7 +360,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do {:ok, data} end - def prepare_outgoing(%{"type" => type} = data) do + def prepare_outgoing(%{"type" => _type} = data) do data = data |> maybe_fix_object_url @@ -286,7 +374,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do case ActivityPub.fetch_object_from_id(data["object"]) do {:ok, relative_object} -> if relative_object.data["external_url"] do - data = + _data = data |> Map.put("object", relative_object.data["external_url"]) else @@ -474,4 +562,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do Repo.delete_all(q) end end + + def maybe_fix_user_url(data) do + if is_map(data["url"]) do + Map.put(data, "url", data["url"]["href"]) + else + data + end + end + + def maybe_fix_user_object(data) do + data + |> maybe_fix_user_url + end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 7b2bf8fa7..831e13b7e 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -5,6 +5,22 @@ defmodule Pleroma.Web.ActivityPub.Utils do alias Ecto.{Changeset, UUID} import Ecto.Query + # Some implementations send the actor URI as the actor field, others send the entire actor object, + # so figure out what the actor's URI is based on what we have. + def normalize_actor(actor) do + cond do + is_binary(actor) -> + actor + + is_map(actor) -> + actor["id"] + end + end + + def normalize_params(params) do + Map.put(params, "actor", normalize_actor(params["actor"])) + end + def make_json_ld_header do %{ "@context" => [ @@ -226,8 +242,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do fragment( "? @> ?", activity.data, - ^%{type: "Follow", actor: follower_id, object: followed_id} + ^%{type: "Follow", object: followed_id} ), + where: activity.actor == ^follower_id, order_by: [desc: :id], limit: 1 ) @@ -238,6 +255,28 @@ defmodule Pleroma.Web.ActivityPub.Utils do #### Announce-related helpers @doc """ + Retruns an existing announce activity if the notice has already been announced + """ + def get_existing_announce(actor, %{data: %{"id" => id}}) do + query = + from( + activity in Activity, + where: activity.actor == ^actor, + # this is to use the index + where: + fragment( + "coalesce((?)->'object'->>'id', (?)->>'object') = ?", + activity.data, + activity.data, + ^id + ), + where: fragment("(?)->>'type' = 'Announce'", activity.data) + ) + + Repo.one(query) + end + + @doc """ Make announce activity data for the given actor and object """ def make_announce_data( @@ -257,21 +296,107 @@ defmodule Pleroma.Web.ActivityPub.Utils do if activity_id, do: Map.put(data, "id", activity_id), else: data end + @doc """ + Make unannounce activity data for the given actor and object + """ + def make_unannounce_data( + %User{ap_id: ap_id} = user, + %Activity{data: %{"context" => context}} = activity, + activity_id + ) do + data = %{ + "type" => "Undo", + "actor" => ap_id, + "object" => activity.data, + "to" => [user.follower_address, activity.data["actor"]], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "context" => context + } + + if activity_id, do: Map.put(data, "id", activity_id), else: data + end + + def make_unlike_data( + %User{ap_id: ap_id} = user, + %Activity{data: %{"context" => context}} = activity, + activity_id + ) do + data = %{ + "type" => "Undo", + "actor" => ap_id, + "object" => activity.data, + "to" => [user.follower_address, activity.data["actor"]], + "cc" => ["https://www.w3.org/ns/activitystreams#Public"], + "context" => context + } + + if activity_id, do: Map.put(data, "id", activity_id), else: data + end + def add_announce_to_object(%Activity{data: %{"actor" => actor}}, object) do with announcements <- [actor | object.data["announcements"] || []] |> Enum.uniq() do update_element_in_object("announcement", announcements, object) end end + def remove_announce_from_object(%Activity{data: %{"actor" => actor}}, object) do + with announcements <- (object.data["announcements"] || []) |> List.delete(actor) do + update_element_in_object("announcement", announcements, object) + end + end + #### Unfollow-related helpers - def make_unfollow_data(follower, followed, follow_activity) do - %{ + def make_unfollow_data(follower, followed, follow_activity, activity_id) do + data = %{ "type" => "Undo", "actor" => follower.ap_id, "to" => [followed.ap_id], - "object" => follow_activity.data["id"] + "object" => follow_activity.data + } + + if activity_id, do: Map.put(data, "id", activity_id), else: data + end + + #### Block-related helpers + def fetch_latest_block(%User{ap_id: blocker_id}, %User{ap_id: blocked_id}) do + query = + from( + activity in Activity, + where: + fragment( + "? @> ?", + activity.data, + ^%{type: "Block", object: blocked_id} + ), + where: activity.actor == ^blocker_id, + order_by: [desc: :id], + limit: 1 + ) + + Repo.one(query) + end + + def make_block_data(blocker, blocked, activity_id) do + data = %{ + "type" => "Block", + "actor" => blocker.ap_id, + "to" => [blocked.ap_id], + "object" => blocked.ap_id + } + + if activity_id, do: Map.put(data, "id", activity_id), else: data + end + + def make_unblock_data(blocker, blocked, block_activity, activity_id) do + data = %{ + "type" => "Undo", + "actor" => blocker.ap_id, + "to" => [blocked.ap_id], + "object" => block_activity.data } + + if activity_id, do: Map.put(data, "id", activity_id), else: data end #### Create-related helpers diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index 92afd0872..ffd76b529 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -47,25 +47,6 @@ defmodule Pleroma.Web.ActivityPub.UserView do |> Map.merge(Utils.make_json_ld_header()) end - def collection(collection, iri, page, total \\ nil) do - offset = (page - 1) * 10 - items = Enum.slice(collection, offset, 10) - items = Enum.map(items, fn user -> user.ap_id end) - total = total || length(collection) - - map = %{ - "id" => "#{iri}?page=#{page}", - "type" => "OrderedCollectionPage", - "partOf" => iri, - "totalItems" => length(collection), - "orderedItems" => items - } - - if offset < length(collection) do - Map.put(map, "next", "#{iri}?page=#{page + 1}") - end - end - def render("following.json", %{user: user, page: page}) do query = User.get_friends_query(user) query = from(user in query, select: [:ap_id]) @@ -123,9 +104,12 @@ defmodule Pleroma.Web.ActivityPub.UserView do "limit" => "10" } - if max_qid != nil do - params = Map.put(params, "max_id", max_qid) - end + params = + if max_qid != nil do + Map.put(params, "max_id", max_qid) + else + params + end activities = ActivityPub.fetch_public_activities(params) min_id = Enum.at(activities, 0).id @@ -162,4 +146,23 @@ defmodule Pleroma.Web.ActivityPub.UserView do page |> Map.merge(Utils.make_json_ld_header()) end end + + def collection(collection, iri, page, total \\ nil) do + offset = (page - 1) * 10 + items = Enum.slice(collection, offset, 10) + items = Enum.map(items, fn user -> user.ap_id end) + total = total || length(collection) + + map = %{ + "id" => "#{iri}?page=#{page}", + "type" => "OrderedCollectionPage", + "partOf" => iri, + "totalItems" => total, + "orderedItems" => items + } + + if offset < total do + Map.put(map, "next", "#{iri}?page=#{page + 1}") + end + end end |