From 6e4f52f8a2e510273149acbaf629521d1b4aec2e Mon Sep 17 00:00:00 2001
From: lain <lain@soykaf.club>
Date: Wed, 16 Oct 2019 16:16:39 +0200
Subject: [PATCH] Introduce new ingestion pipeline structure, implement
 internal Likes with it.

---
 lib/pleroma/web/activity_pub/activity_pub.ex  | 35 ++++++++++++
 lib/pleroma/web/activity_pub/builder.ex       | 43 ++++++++++++++
 .../web/activity_pub/object_validator.ex      | 57 +++++++++++++++++++
 lib/pleroma/web/activity_pub/side_effects.ex  | 28 +++++++++
 lib/pleroma/web/common_api/common_api.ex      | 29 ++++++++--
 .../controllers/status_controller.ex          |  6 +-
 test/notification_test.exs                    |  8 +--
 test/object_test.exs                          |  3 +-
 test/tasks/database_test.exs                  |  2 +-
 test/user_test.exs                            |  4 +-
 .../activity_pub/activity_validator_test.exs  | 21 +++++++
 test/web/activity_pub/side_effects_test.exs   | 32 +++++++++++
 test/web/activity_pub/transmogrifier_test.exs |  2 +-
 .../activity_pub/views/object_view_test.exs   |  2 +-
 test/web/common_api/common_api_test.exs       | 11 ++--
 .../notification_controller_test.exs          |  2 +-
 .../controllers/status_controller_test.exs    | 16 +++---
 .../views/notification_view_test.exs          |  2 +-
 test/web/ostatus/ostatus_controller_test.exs  |  4 +-
 .../controllers/account_controller_test.exs   | 16 +++---
 test/web/push/impl_test.exs                   |  2 +-
 test/web/streamer/streamer_test.exs           |  6 +-
 22 files changed, 284 insertions(+), 47 deletions(-)
 create mode 100644 lib/pleroma/web/activity_pub/builder.ex
 create mode 100644 lib/pleroma/web/activity_pub/object_validator.ex
 create mode 100644 lib/pleroma/web/activity_pub/side_effects.ex
 create mode 100644 test/web/activity_pub/activity_validator_test.exs
 create mode 100644 test/web/activity_pub/side_effects_test.exs

diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 364452b5d..f4fc45926 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -18,6 +18,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   alias Pleroma.Web.ActivityPub.MRF
   alias Pleroma.Web.ActivityPub.Transmogrifier
   alias Pleroma.Web.ActivityPub.Utils
+  alias Pleroma.Web.ActivityPub.ObjectValidator
+  alias Pleroma.Web.ActivityPub.SideEffects
   alias Pleroma.Web.Streamer
   alias Pleroma.Web.WebFinger
   alias Pleroma.Workers.BackgroundWorker
@@ -123,6 +125,38 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
 
   def increase_poll_votes_if_vote(_create_data), do: :noop
 
+  @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
+  def common_pipeline(object, meta) do
+    with {_, {:ok, validated_object, meta}} <-
+           {:validate_object, ObjectValidator.validate(object, meta)},
+         {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
+         {_, {:ok, %Activity{} = activity, meta}} <-
+           {:persist_object, persist(mrfd_object, meta)},
+         {_, {:ok, %Activity{} = activity, meta}} <-
+           {:execute_side_effects, SideEffects.handle(activity, meta)} do
+      {:ok, activity, meta}
+    else
+      e -> {:error, e}
+    end
+  end
+
+  # TODO rewrite in with style
+  @spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
+  def persist(object, meta) do
+    local = Keyword.get(meta, :local)
+    {recipients, _, _} = get_recipients(object)
+
+    {:ok, activity} =
+      Repo.insert(%Activity{
+        data: object,
+        local: local,
+        recipients: recipients,
+        actor: object["actor"]
+      })
+
+    {:ok, activity, meta}
+  end
+
   def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
     with nil <- Activity.normalize(map),
          map <- lazy_put_activity_defaults(map, fake),
@@ -130,6 +164,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
          {_, true} <- {:remote_limit_error, check_remote_limit(map)},
          {:ok, map} <- MRF.filter(map),
          {recipients, _, _} = get_recipients(map),
+         # ???
          {:fake, false, map, recipients} <- {:fake, fake, map, recipients},
          :ok <- Containment.contain_child(map),
          {:ok, map, object} <- insert_full_object(map) do
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
new file mode 100644
index 000000000..1787f1510
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -0,0 +1,43 @@
+defmodule Pleroma.Web.ActivityPub.Builder do
+  @moduledoc """
+  This module builds the objects. Meant to be used for creating local objects.
+
+  This module encodes our addressing policies and general shape of our objects.
+  """
+
+  alias Pleroma.Web.ActivityPub.Utils
+  alias Pleroma.Web.ActivityPub.Visibility
+  alias Pleroma.User
+  alias Pleroma.Object
+
+  @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
+  def like(actor, object) do
+    object_actor = User.get_cached_by_ap_id(object.data["actor"])
+
+    # Address the actor of the object, and our actor's follower collection if the post is public.
+    to =
+      if Visibility.is_public?(object) do
+        [actor.follower_address, object.data["actor"]]
+      else
+        [object.data["actor"]]
+      end
+
+    # CC everyone who's been addressed in the object, except ourself and the object actor's
+    # follower collection
+    cc =
+      (object.data["to"] ++ (object.data["cc"] || []))
+      |> List.delete(actor.ap_id)
+      |> List.delete(object_actor.follower_address)
+
+    {:ok,
+     %{
+       "id" => Utils.generate_activity_id(),
+       "actor" => actor.ap_id,
+       "type" => "Like",
+       "object" => object.data["id"],
+       "to" => to,
+       "cc" => cc,
+       "context" => object.data["context"]
+     }, []}
+  end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
new file mode 100644
index 000000000..8ecad0dec
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -0,0 +1,57 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidator do
+  @moduledoc """
+  This module is responsible for validating an object (which can be an activity)
+  and checking if it is both well formed and also compatible with our view of
+  the system.
+  """
+
+  alias Pleroma.User
+  alias Pleroma.Object
+  alias Pleroma.Web.ActivityPub.Utils
+
+  def validate_id(object, meta) do
+    with {_, true} <- {:id_presence, Map.has_key?(object, "id")} do
+      {:ok, object, meta}
+    else
+      e -> {:error, e}
+    end
+  end
+
+  def validate_actor(object, meta) do
+    with {_, %User{}} <- {:actor_validation, User.get_cached_by_ap_id(object["actor"])} do
+      {:ok, object, meta}
+    else
+      e -> {:error, e}
+    end
+  end
+
+  def common_validations(object, meta) do
+    with {_, {:ok, object, meta}} <- {:validate_id, validate_id(object, meta)},
+      {_, {:ok, object, meta}} <- {:validate_actor, validate_actor(object, meta)} do
+      {:ok, object, meta}
+    else
+      e -> {:error, e}
+    end
+  end
+
+  @spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
+  def validate(object, meta)
+
+  def validate(%{"type" => "Like"} = object, meta) do
+    with {:ok, object, meta} <- common_validations(object, meta),
+         {_, %Object{} = liked_object} <- {:find_liked_object, Object.normalize(object["object"])},
+         {_, nil} <- {:existing_like, Utils.get_existing_like(object["actor"], liked_object)} do
+      {:ok, object, meta}
+    else
+      e -> {:error, e}
+    end
+  end
+
+  def validate(object, meta) do
+    common_validations(object, meta)
+  end
+end
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
new file mode 100644
index 000000000..6d3e77a62
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -0,0 +1,28 @@
+defmodule Pleroma.Web.ActivityPub.SideEffects do
+  @moduledoc """
+  This module looks at an inserted object and executes the side effects that it
+  implies. For example, a `Like` activity will increase the like count on the
+  liked object, a `Follow` activity will add the user to the follower
+  collection, and so on.
+  """
+  alias Pleroma.Web.ActivityPub.Utils
+  alias Pleroma.Object
+  alias Pleroma.Notification
+
+  def handle(object, meta \\ [])
+
+  # Tasks this handles:
+  # - Add like to object
+  # - Set up notification
+  def handle(%{data: %{"type" => "Like"}} = object, meta) do
+    liked_object = Object.get_by_ap_id(object.data["object"])
+    Utils.add_like_to_object(object, liked_object)
+    Notification.create_notifications(object)
+    {:ok, object, meta}
+  end
+
+  # Nothing to do
+  def handle(object, meta) do
+    {:ok, object, meta}
+  end
+end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 386408d51..466beb724 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -10,6 +10,7 @@ defmodule Pleroma.Web.CommonAPI do
   alias Pleroma.ThreadMute
   alias Pleroma.User
   alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.Builder
   alias Pleroma.Web.ActivityPub.Utils
   alias Pleroma.Web.ActivityPub.Visibility
 
@@ -17,6 +18,7 @@ defmodule Pleroma.Web.CommonAPI do
   import Pleroma.Web.CommonAPI.Utils
 
   require Pleroma.Constants
+  require Logger
 
   def follow(follower, followed) do
     timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
@@ -98,16 +100,31 @@ defmodule Pleroma.Web.CommonAPI do
     end
   end
 
-  def favorite(id_or_ap_id, user) do
-    with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
-         object <- Object.normalize(activity),
-         nil <- Utils.get_existing_like(user.ap_id, object) do
-      ActivityPub.like(user, object)
+  @spec favorite(User.t(), binary()) :: {:ok, Activity.t()} | {:error, any()}
+  def favorite(%User{} = user, id) do
+    with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
+         {_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
+         {_, {:ok, %Activity{} = activity, _meta}} <-
+           {:common_pipeline,
+            ActivityPub.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+      {:ok, activity}
     else
-      _ -> {:error, dgettext("errors", "Could not favorite")}
+      e ->
+        Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+        {:error, dgettext("errors", "Could not favorite")}
     end
   end
 
+  # def favorite(id_or_ap_id, user) do
+  #   with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
+  #        object <- Object.normalize(activity),
+  #        nil <- Utils.get_existing_like(user.ap_id, object) do
+  #     ActivityPub.like(user, object)
+  #   else
+  #     _ -> {:error, dgettext("errors", "Could not favorite")}
+  #   end
+  # end
+
   def unfavorite(id_or_ap_id, user) do
     with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do
       object = Object.normalize(activity)
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index e5d016f63..4b4482aa8 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -201,9 +201,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
   end
 
   @doc "POST /api/v1/statuses/:id/favourite"
-  def favourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
-    with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
-         %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+  def favourite(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
+    with {:ok, _fav} <- CommonAPI.favorite(user, activity_id),
+         %Activity{} = activity <- Activity.get_by_id(activity_id) do
       try_render(conn, "show.json", activity: activity, for: user, as: :activity)
     end
   end
diff --git a/test/notification_test.exs b/test/notification_test.exs
index 54c0f9877..940913aa6 100644
--- a/test/notification_test.exs
+++ b/test/notification_test.exs
@@ -431,7 +431,7 @@ defmodule Pleroma.NotificationTest do
           "status" => "hey @#{other_user.nickname}!"
         })
 
-      {:ok, activity_two, _} = CommonAPI.favorite(activity_one.id, third_user)
+      {:ok, activity_two} = CommonAPI.favorite(third_user, activity_one.id)
 
       assert other_user not in Notification.get_notified_from_activity(activity_two)
     end
@@ -461,7 +461,7 @@ defmodule Pleroma.NotificationTest do
 
       assert Enum.empty?(Notification.for_user(user))
 
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       assert length(Notification.for_user(user)) == 1
 
@@ -478,7 +478,7 @@ defmodule Pleroma.NotificationTest do
 
       assert Enum.empty?(Notification.for_user(user))
 
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       assert length(Notification.for_user(user)) == 1
 
@@ -533,7 +533,7 @@ defmodule Pleroma.NotificationTest do
 
       assert Enum.empty?(Notification.for_user(user))
 
-      {:error, _} = CommonAPI.favorite(activity.id, other_user)
+      {:error, _} = CommonAPI.favorite(other_user, activity.id)
 
       assert Enum.empty?(Notification.for_user(user))
     end
diff --git a/test/object_test.exs b/test/object_test.exs
index dd228c32f..353bc388d 100644
--- a/test/object_test.exs
+++ b/test/object_test.exs
@@ -182,7 +182,8 @@ defmodule Pleroma.ObjectTest do
 
       user = insert(:user)
       activity = Activity.get_create_by_object_ap_id(object.data["id"])
-      {:ok, _activity, object} = CommonAPI.favorite(activity.id, user)
+      {:ok, activity} = CommonAPI.favorite(user, activity.id)
+      object = Object.get_by_ap_id(activity.data["object"])
 
       assert object.data["like_count"] == 1
 
diff --git a/test/tasks/database_test.exs b/test/tasks/database_test.exs
index b63dcac00..c0a313863 100644
--- a/test/tasks/database_test.exs
+++ b/test/tasks/database_test.exs
@@ -102,7 +102,7 @@ defmodule Mix.Tasks.Pleroma.DatabaseTest do
       {:ok, %{id: id, object: object}} = CommonAPI.post(user, %{"status" => "test"})
       {:ok, %{object: object2}} = CommonAPI.post(user, %{"status" => "test test"})
 
-      CommonAPI.favorite(id, user2)
+      CommonAPI.favorite(user2, id)
 
       likes = %{
         "first" =>
diff --git a/test/user_test.exs b/test/user_test.exs
index 019e7b400..49c1eb02a 100644
--- a/test/user_test.exs
+++ b/test/user_test.exs
@@ -1059,8 +1059,8 @@ defmodule Pleroma.UserTest do
       object_two = insert(:note, user: follower)
       activity_two = insert(:note_activity, user: follower, note: object_two)
 
-      {:ok, like, _} = CommonAPI.favorite(activity_two.id, user)
-      {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
+      {:ok, like} = CommonAPI.favorite(user, activity_two.id)
+      {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
       {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
 
       {:ok, job} = User.delete(user)
diff --git a/test/web/activity_pub/activity_validator_test.exs b/test/web/activity_pub/activity_validator_test.exs
new file mode 100644
index 000000000..cb0895a81
--- /dev/null
+++ b/test/web/activity_pub/activity_validator_test.exs
@@ -0,0 +1,21 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
+  use Pleroma.DataCase
+
+  import Pleroma.Factory
+
+  describe "likes" do
+    test "it is well formed" do
+      _required_fields = [
+        "id",
+        "actor",
+        "object"
+      ]
+
+      _user = insert(:user)
+    end
+  end
+end
diff --git a/test/web/activity_pub/side_effects_test.exs b/test/web/activity_pub/side_effects_test.exs
new file mode 100644
index 000000000..e505ab4dd
--- /dev/null
+++ b/test/web/activity_pub/side_effects_test.exs
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
+  use Pleroma.DataCase
+  alias Pleroma.Object
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.ActivityPub.Builder
+  alias Pleroma.Web.ActivityPub.ActivityPub
+  alias Pleroma.Web.ActivityPub.SideEffects
+
+  import Pleroma.Factory
+  describe "like objects" do
+    setup do
+      user = insert(:user)
+      {:ok, post} = CommonAPI.post(user, %{"status" => "hey"})
+
+      {:ok, like_data, _meta} = Builder.like(user, post.object)
+      {:ok, like, _meta} = ActivityPub.persist(like_data, [])
+
+      %{like: like, user: user}
+    end
+
+    test "add the like to the original object", %{like: like, user: user} do
+      {:ok, like, _} = SideEffects.handle(like)
+      object = Object.get_by_ap_id(like.data["object"])
+      assert object.data["like_count"] == 1
+      assert user.ap_id in object.data["likes"]
+    end
+  end
+end
diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs
index 6c35a6f4d..28edc5508 100644
--- a/test/web/activity_pub/transmogrifier_test.exs
+++ b/test/web/activity_pub/transmogrifier_test.exs
@@ -1187,7 +1187,7 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
 
       user = insert(:user)
 
-      {:ok, activity, _} = CommonAPI.favorite(referent_activity.id, user)
+      {:ok, activity} = CommonAPI.favorite(user, referent_activity.id)
       {:ok, modified} = Transmogrifier.prepare_outgoing(activity.data)
 
       assert modified["object"] == "http://gs.example.org:4040/index.php/notice/29"
diff --git a/test/web/activity_pub/views/object_view_test.exs b/test/web/activity_pub/views/object_view_test.exs
index 13447dc29..998247c5c 100644
--- a/test/web/activity_pub/views/object_view_test.exs
+++ b/test/web/activity_pub/views/object_view_test.exs
@@ -41,7 +41,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectViewTest do
     object = Object.normalize(note)
     user = insert(:user)
 
-    {:ok, like_activity, _} = CommonAPI.favorite(note.id, user)
+    {:ok, like_activity} = CommonAPI.favorite(user, note.id)
 
     result = ObjectView.render("object.json", %{object: like_activity})
 
diff --git a/test/web/common_api/common_api_test.exs b/test/web/common_api/common_api_test.exs
index 83df44c36..d46a361c5 100644
--- a/test/web/common_api/common_api_test.exs
+++ b/test/web/common_api/common_api_test.exs
@@ -251,9 +251,12 @@ defmodule Pleroma.Web.CommonAPITest do
       user = insert(:user)
       other_user = insert(:user)
 
-      {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
+      {:ok, post_activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
 
-      {:ok, %Activity{}, _} = CommonAPI.favorite(activity.id, user)
+      {:ok, %Activity{data: data}} = CommonAPI.favorite(user, post_activity.id)
+      assert data["type"] == "Like"
+      assert data["actor"] == user.ap_id
+      assert data["object"] == post_activity.data["object"]
     end
 
     test "retweeting a status twice returns an error" do
@@ -270,8 +273,8 @@ defmodule Pleroma.Web.CommonAPITest do
       other_user = insert(:user)
 
       {:ok, activity} = CommonAPI.post(other_user, %{"status" => "cofe"})
-      {:ok, %Activity{}, _object} = CommonAPI.favorite(activity.id, user)
-      {:error, _} = CommonAPI.favorite(activity.id, user)
+      {:ok, %Activity{}} = CommonAPI.favorite(user, activity.id)
+      {:error, _} = CommonAPI.favorite(user, activity.id)
     end
   end
 
diff --git a/test/web/mastodon_api/controllers/notification_controller_test.exs b/test/web/mastodon_api/controllers/notification_controller_test.exs
index e4137e92c..6eadccb8e 100644
--- a/test/web/mastodon_api/controllers/notification_controller_test.exs
+++ b/test/web/mastodon_api/controllers/notification_controller_test.exs
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do
 
     {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
     {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
-    {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
+    {:ok, favorite_activity} = CommonAPI.favorite(other_user, create_activity.id)
     {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
     {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
 
diff --git a/test/web/mastodon_api/controllers/status_controller_test.exs b/test/web/mastodon_api/controllers/status_controller_test.exs
index 2de2725e0..1414d9fed 100644
--- a/test/web/mastodon_api/controllers/status_controller_test.exs
+++ b/test/web/mastodon_api/controllers/status_controller_test.exs
@@ -589,7 +589,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
       user1 = insert(:user)
       user2 = insert(:user)
       user3 = insert(:user)
-      CommonAPI.favorite(activity.id, user2)
+      {:ok, _} = CommonAPI.favorite(user2, activity.id)
       {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
       {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
       {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
@@ -695,7 +695,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
       activity = insert(:note_activity)
       user = insert(:user)
 
-      {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+      {:ok, _} = CommonAPI.favorite(user, activity.id)
 
       conn =
         conn
@@ -1047,7 +1047,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
 
     test "returns users who have favorited the status", %{conn: conn, activity: activity} do
       other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       response =
         conn
@@ -1078,7 +1078,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
       other_user = insert(:user)
       {:ok, user} = User.block(user, other_user)
 
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       response =
         conn
@@ -1091,7 +1091,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
 
     test "does not fail on an unauthenticated request", %{conn: conn, activity: activity} do
       other_user = insert(:user)
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       response =
         conn
@@ -1112,7 +1112,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
           "visibility" => "direct"
         })
 
-      {:ok, _, _} = CommonAPI.favorite(activity.id, other_user)
+      {:ok, _} = CommonAPI.favorite(other_user, activity.id)
 
       conn
       |> assign(:user, nil)
@@ -1269,7 +1269,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
     {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
     {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
 
-    {:ok, _, _} = CommonAPI.favorite(activity.id, user)
+    {:ok, _} = CommonAPI.favorite(user, activity.id)
 
     first_conn =
       conn
@@ -1289,7 +1289,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
           "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
       })
 
-    {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
+    {:ok, _} = CommonAPI.favorite(user, second_activity.id)
 
     last_like = status["id"]
 
diff --git a/test/web/mastodon_api/views/notification_view_test.exs b/test/web/mastodon_api/views/notification_view_test.exs
index c9043a69a..d06809268 100644
--- a/test/web/mastodon_api/views/notification_view_test.exs
+++ b/test/web/mastodon_api/views/notification_view_test.exs
@@ -42,7 +42,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
     user = insert(:user)
     another_user = insert(:user)
     {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
-    {:ok, favorite_activity, _object} = CommonAPI.favorite(create_activity.id, another_user)
+    {:ok, favorite_activity} = CommonAPI.favorite(another_user, create_activity.id)
     {:ok, [notification]} = Notification.create_notifications(favorite_activity)
     create_activity = Activity.get_by_id(create_activity.id)
 
diff --git a/test/web/ostatus/ostatus_controller_test.exs b/test/web/ostatus/ostatus_controller_test.exs
index b1af918d8..7aee16e2c 100644
--- a/test/web/ostatus/ostatus_controller_test.exs
+++ b/test/web/ostatus/ostatus_controller_test.exs
@@ -271,7 +271,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
 
       user = insert(:user)
 
-      {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
+      {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
       url = "/notice/#{like_activity.id}"
 
       assert like_activity.data["type"] == "Like"
@@ -298,7 +298,7 @@ defmodule Pleroma.Web.OStatus.OStatusControllerTest do
 
       user = insert(:user)
 
-      {:ok, like_activity, _} = CommonAPI.favorite(note_activity.id, user)
+      {:ok, like_activity} = CommonAPI.favorite(user, note_activity.id)
 
       assert like_activity.data["type"] == "Like"
 
diff --git a/test/web/pleroma_api/controllers/account_controller_test.exs b/test/web/pleroma_api/controllers/account_controller_test.exs
index 3b4665afd..6a6135d02 100644
--- a/test/web/pleroma_api/controllers/account_controller_test.exs
+++ b/test/web/pleroma_api/controllers/account_controller_test.exs
@@ -165,7 +165,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
       user: user
     } do
       [activity | _] = insert_pair(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+      CommonAPI.favorite(user, activity.id)
 
       response =
         conn
@@ -184,7 +184,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
       user: user
     } do
       activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+      CommonAPI.favorite(user, activity.id)
 
       response =
         conn
@@ -205,7 +205,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
           "visibility" => "direct"
         })
 
-      CommonAPI.favorite(direct.id, user)
+      CommonAPI.favorite(user, direct.id)
 
       response =
         conn
@@ -236,7 +236,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
           "visibility" => "direct"
         })
 
-      CommonAPI.favorite(direct.id, user)
+      CommonAPI.favorite(user, direct.id)
 
       response =
         conn
@@ -255,7 +255,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
       activities = insert_list(10, :note_activity)
 
       Enum.each(activities, fn activity ->
-        CommonAPI.favorite(activity.id, user)
+        CommonAPI.favorite(user, activity.id)
       end)
 
       third_activity = Enum.at(activities, 2)
@@ -283,7 +283,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
       7
       |> insert_list(:note_activity)
       |> Enum.each(fn activity ->
-        CommonAPI.favorite(activity.id, user)
+        CommonAPI.favorite(user, activity.id)
       end)
 
       response =
@@ -321,7 +321,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
     } do
       user = insert(:user, %{info: %{hide_favorites: true}})
       activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+      CommonAPI.favorite(user, activity.id)
 
       conn =
         conn
@@ -334,7 +334,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountControllerTest do
     test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
       user = insert(:user)
       activity = insert(:note_activity)
-      CommonAPI.favorite(activity.id, user)
+      CommonAPI.favorite(user, activity.id)
 
       conn =
         conn
diff --git a/test/web/push/impl_test.exs b/test/web/push/impl_test.exs
index 2f6ce4bd2..36c69c7c9 100644
--- a/test/web/push/impl_test.exs
+++ b/test/web/push/impl_test.exs
@@ -152,7 +152,7 @@ defmodule Pleroma.Web.Push.ImplTest do
           "<span>Lorem ipsum dolor sit amet</span>, consectetur :firefox: adipiscing elit. Fusce sagittis finibus turpis."
       })
 
-    {:ok, activity, _} = CommonAPI.favorite(activity.id, user)
+    {:ok, activity} = CommonAPI.favorite(user, activity.id)
     object = Object.normalize(activity)
 
     assert Impl.format_body(%{activity: activity}, user, object) == "@Bob has favorited your post"
diff --git a/test/web/streamer/streamer_test.exs b/test/web/streamer/streamer_test.exs
index d33eb1e42..b363935a2 100644
--- a/test/web/streamer/streamer_test.exs
+++ b/test/web/streamer/streamer_test.exs
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.StreamerTest do
       )
 
       {:ok, activity} = CommonAPI.post(user, %{"status" => ":("})
-      {:ok, notif, _} = CommonAPI.favorite(activity.id, blocked)
+      {:ok, notif} = CommonAPI.favorite(blocked, activity.id)
 
       Streamer.stream("user:notification", notif)
       Task.await(task)
@@ -87,7 +87,7 @@ defmodule Pleroma.Web.StreamerTest do
 
       {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
       {:ok, activity} = CommonAPI.add_mute(user, activity)
-      {:ok, notif, _} = CommonAPI.favorite(activity.id, user2)
+      {:ok, notif} = CommonAPI.favorite(user2, activity.id)
       Streamer.stream("user:notification", notif)
       Task.await(task)
     end
@@ -105,7 +105,7 @@ defmodule Pleroma.Web.StreamerTest do
 
       {:ok, user} = User.block_domain(user, "hecking-lewd-place.com")
       {:ok, activity} = CommonAPI.post(user, %{"status" => "super hot take"})
-      {:ok, notif, _} = CommonAPI.favorite(activity.id, user2)
+      {:ok, notif} = CommonAPI.favorite(user2, activity.id)
 
       Streamer.stream("user:notification", notif)
       Task.await(task)
-- 
2.49.0