ActivityPub: Add undo for emoji reactions.
authorlain <lain@soykaf.club>
Wed, 2 Oct 2019 13:08:20 +0000 (15:08 +0200)
committerlain <lain@soykaf.club>
Wed, 2 Oct 2019 13:08:20 +0000 (15:08 +0200)
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/utils.ex
lib/pleroma/web/router.ex
test/web/activity_pub/activity_pub_test.exs

index a9e53141dd6054bc761d134b666b68aedd0bff3c..458d3590d8354d8f832636c80e99d721a93e5f21 100644 (file)
@@ -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.
index 4c146fd86260313df4c28748bbcaf4a8eead7bea..7807fa9cdf08dafc85da0457aa250e94e8fbd7e7 100644 (file)
@@ -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(
index eae1f676bb1edd05ef3d83d2dcc2cf290c50f2d7..ff3dc273ee817e121579ae6ff1120ddb62516d1d 100644 (file)
@@ -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)
index 8c9c2c89ec013042205836c090a6955c764d03eb..36a82d6a1a9ef1fec8063b903f0fd22d066ec61b 100644 (file)
@@ -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, "🔥")
+
+      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"]
 
-      IO.inspect(object)
+      object = Object.get_by_ap_id(object.data["id"])
+      assert object.data["reaction_count"] == 0
+      assert object.data["reactions"] == %{}
     end
   end