From dfe5c958eb94326f5a7743c9de0de073260db926 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 2 Oct 2019 15:08:20 +0200 Subject: [PATCH] ActivityPub: Add undo for emoji reactions. --- lib/pleroma/web/activity_pub/activity_pub.ex | 13 +++++++--- lib/pleroma/web/activity_pub/utils.ex | 37 ++++++++++++++++++++++++++++ lib/pleroma/web/router.ex | 2 -- test/web/activity_pub/activity_pub_test.exs | 32 +++++++++++++++++++++--- 4 files changed, 75 insertions(+), 9 deletions(-) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index a9e53141d..458d3590d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -319,11 +319,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end - def unreact_with_emoji(user, reaction_id, option \\ []) do + def unreact_with_emoji(user, reaction_id, options \\ []) do with local <- Keyword.get(options, :local, true), activity_id <- Keyword.get(options, :activity_id, nil), - %Activity{actor: ^user.ap_id} = reaction_activity <- Activity.get_by_ap_id(reaction_id), - unreact_data + 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. diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 4c146fd86..7807fa9cd 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -337,6 +337,24 @@ defmodule Pleroma.Web.ActivityPub.Utils do update_element_in_object("reaction", new_reactions, object) end + def remove_emoji_reaction_from_object( + %Activity{data: %{"content" => emoji, "actor" => actor}}, + object + ) do + reactions = object.data["reactions"] || %{} + emoji_actors = reactions[emoji] || [] + new_emoji_actors = List.delete(emoji_actors, actor) + + new_reactions = + if new_emoji_actors == [] do + Map.delete(reactions, emoji) + else + Map.put(reactions, emoji, new_emoji_actors) + end + + update_element_in_object("reaction", new_reactions, object) + end + @spec add_like_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_like_to_object(%Activity{data: %{"actor" => actor}}, object) do @@ -522,6 +540,25 @@ defmodule Pleroma.Web.ActivityPub.Utils do |> maybe_put("id", activity_id) end + def make_undo_data( + %User{ap_id: actor, follower_address: follower_address}, + %Activity{ + data: %{"id" => undone_activity_id, "context" => context}, + actor: undone_activity_actor + }, + activity_id \\ nil + ) do + %{ + "type" => "Undo", + "actor" => actor, + "object" => undone_activity_id, + "to" => [follower_address, undone_activity_actor], + "cc" => [Pleroma.Constants.as_public()], + "context" => context + } + |> maybe_put("id", activity_id) + end + @spec add_announce_to_object(Activity.t(), Object.t()) :: {:ok, Object.t()} | {:error, Ecto.Changeset.t()} def add_announce_to_object( diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index eae1f676b..ff3dc273e 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -293,8 +293,6 @@ defmodule Pleroma.Web.Router do end scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do - pipe_through(:authenticated_api) - scope [] do pipe_through(:authenticated_api) pipe_through(:oauth_read) diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 8c9c2c89e..36a82d6a1 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -761,16 +761,40 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do end describe "unreacting to an object" do - test "adds an emoji reaction activity to the db" do + test_with_mock "sends an activity to federation", Pleroma.Web.Federator, [:passthrough], [] do + Pleroma.Config.put([:instance, :federating], true) user = insert(:user) reactor = insert(:user) {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) assert object = Object.normalize(activity) - {:ok, reaction_activity, object} = ActivityPub.react_with_emoji(reactor, object, "🔥") - {:ok, unreaction_activity} = ActivityPub.unreact_with_emoji(reactor, reaction_activity.id) + {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥") - IO.inspect(object) + assert called(Pleroma.Web.Federator.publish(reaction_activity)) + + {:ok, unreaction_activity, _object} = + ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"]) + + assert called(Pleroma.Web.Federator.publish(unreaction_activity)) + end + + test "adds an undo activity to the db" do + user = insert(:user) + reactor = insert(:user) + {:ok, activity} = CommonAPI.post(user, %{"status" => "YASSSS queen slay"}) + assert object = Object.normalize(activity) + + {:ok, reaction_activity, _object} = ActivityPub.react_with_emoji(reactor, object, "🔥") + + {:ok, unreaction_activity, _object} = + ActivityPub.unreact_with_emoji(reactor, reaction_activity.data["id"]) + + assert unreaction_activity.actor == reactor.ap_id + assert unreaction_activity.data["object"] == reaction_activity.data["id"] + + object = Object.get_by_ap_id(object.data["id"]) + assert object.data["reaction_count"] == 0 + assert object.data["reactions"] == %{} end end