Merge pull request 'Check that the signature matches the creator' (#230) from domain...
[akkoma] / test / pleroma / web / common_api_test.exs
index ace0131526ffca2d856ab0e70429daf07a419820..2b7a34be23f6ef12ef994275a39de6cbdd56276c 100644 (file)
@@ -7,13 +7,11 @@ defmodule Pleroma.Web.CommonAPITest do
   use Pleroma.DataCase
 
   alias Pleroma.Activity
   use Pleroma.DataCase
 
   alias Pleroma.Activity
-  alias Pleroma.Chat
   alias Pleroma.Conversation.Participation
   alias Pleroma.Notification
   alias Pleroma.Object
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.Conversation.Participation
   alias Pleroma.Notification
   alias Pleroma.Object
   alias Pleroma.Repo
   alias Pleroma.User
-  alias Pleroma.Web.ActivityPub.ActivityPub
   alias Pleroma.Web.ActivityPub.Transmogrifier
   alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.AdminAPI.AccountView
   alias Pleroma.Web.ActivityPub.Transmogrifier
   alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.AdminAPI.AccountView
@@ -26,6 +24,13 @@ defmodule Pleroma.Web.CommonAPITest do
 
   require Pleroma.Constants
 
 
   require Pleroma.Constants
 
+  setup_all do
+    clear_config([Pleroma.Upload, :uploader], Pleroma.Uploaders.Local)
+    clear_config([Pleroma.Uploaders.Local, :uploads], "uploads")
+    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
   setup do: clear_config([:instance, :safe_dm_mentions])
   setup do: clear_config([:instance, :limit])
   setup do: clear_config([:instance, :max_pinned_statuses])
   setup do: clear_config([:instance, :safe_dm_mentions])
   setup do: clear_config([:instance, :limit])
   setup do: clear_config([:instance, :max_pinned_statuses])
@@ -56,9 +61,11 @@ defmodule Pleroma.Web.CommonAPITest do
   describe "blocking" do
     setup do
       blocker = insert(:user)
   describe "blocking" do
     setup do
       blocker = insert(:user)
-      blocked = insert(:user)
-      User.follow(blocker, blocked)
-      User.follow(blocked, blocker)
+      blocked = insert(:user, local: false)
+      CommonAPI.follow(blocker, blocked)
+      CommonAPI.follow(blocked, blocker)
+      CommonAPI.accept_follow_request(blocker, blocked)
+      CommonAPI.accept_follow_request(blocked, blocked)
       %{blocker: blocker, blocked: blocked}
     end
 
       %{blocker: blocker, blocked: blocked}
     end
 
@@ -67,6 +74,9 @@ defmodule Pleroma.Web.CommonAPITest do
 
       with_mock Pleroma.Web.Federator,
         publish: fn _ -> nil end do
 
       with_mock Pleroma.Web.Federator,
         publish: fn _ -> nil end do
+        assert User.get_follow_state(blocker, blocked) == :follow_accept
+        refute is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked))
+
         assert {:ok, block} = CommonAPI.block(blocker, blocked)
 
         assert block.local
         assert {:ok, block} = CommonAPI.block(blocker, blocked)
 
         assert block.local
@@ -74,6 +84,11 @@ defmodule Pleroma.Web.CommonAPITest do
         refute User.following?(blocker, blocked)
         refute User.following?(blocked, blocker)
 
         refute User.following?(blocker, blocked)
         refute User.following?(blocked, blocker)
 
+        refute User.get_follow_state(blocker, blocked)
+
+        assert %{data: %{"state" => "reject"}} =
+                 Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(blocker, blocked)
+
         assert called(Pleroma.Web.Federator.publish(block))
       end
     end
         assert called(Pleroma.Web.Federator.publish(block))
       end
     end
@@ -99,175 +114,6 @@ defmodule Pleroma.Web.CommonAPITest do
     end
   end
 
     end
   end
 
-  describe "posting chat messages" do
-    setup do: clear_config([:instance, :chat_limit])
-
-    test "it posts a self-chat" do
-      author = insert(:user)
-      recipient = author
-
-      {:ok, activity} =
-        CommonAPI.post_chat_message(
-          author,
-          recipient,
-          "remember to buy milk when milk truk arive"
-        )
-
-      assert activity.data["type"] == "Create"
-    end
-
-    test "it posts a chat message without content but with an attachment" do
-      author = insert(:user)
-      recipient = insert(:user)
-
-      file = %Plug.Upload{
-        content_type: "image/jpeg",
-        path: Path.absname("test/fixtures/image.jpg"),
-        filename: "an_image.jpg"
-      }
-
-      {:ok, upload} = ActivityPub.upload(file, actor: author.ap_id)
-
-      with_mocks([
-        {
-          Pleroma.Web.Streamer,
-          [],
-          [
-            stream: fn _, _ ->
-              nil
-            end
-          ]
-        },
-        {
-          Pleroma.Web.Push,
-          [],
-          [
-            send: fn _ -> nil end
-          ]
-        }
-      ]) do
-        {:ok, activity} =
-          CommonAPI.post_chat_message(
-            author,
-            recipient,
-            nil,
-            media_id: upload.id
-          )
-
-        notification =
-          Notification.for_user_and_activity(recipient, activity)
-          |> Repo.preload(:activity)
-
-        assert called(Pleroma.Web.Push.send(notification))
-        assert called(Pleroma.Web.Streamer.stream(["user", "user:notification"], notification))
-        assert called(Pleroma.Web.Streamer.stream(["user", "user:pleroma_chat"], :_))
-
-        assert activity
-      end
-    end
-
-    test "it adds html newlines" do
-      author = insert(:user)
-      recipient = insert(:user)
-
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post_chat_message(
-          author,
-          recipient,
-          "uguu\nuguuu"
-        )
-
-      assert other_user.ap_id not in activity.recipients
-
-      object = Object.normalize(activity, fetch: false)
-
-      assert object.data["content"] == "uguu<br/>uguuu"
-    end
-
-    test "it linkifies" do
-      author = insert(:user)
-      recipient = insert(:user)
-
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post_chat_message(
-          author,
-          recipient,
-          "https://example.org is the site of @#{other_user.nickname} #2hu"
-        )
-
-      assert other_user.ap_id not in activity.recipients
-
-      object = Object.normalize(activity, fetch: false)
-
-      assert object.data["content"] ==
-               "<a href=\"https://example.org\" rel=\"ugc\">https://example.org</a> is the site of <span class=\"h-card\"><a class=\"u-url mention\" data-user=\"#{
-                 other_user.id
-               }\" href=\"#{other_user.ap_id}\" rel=\"ugc\">@<span>#{other_user.nickname}</span></a></span> <a class=\"hashtag\" data-tag=\"2hu\" href=\"http://localhost:4001/tag/2hu\">#2hu</a>"
-    end
-
-    test "it posts a chat message" do
-      author = insert(:user)
-      recipient = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post_chat_message(
-          author,
-          recipient,
-          "a test message <script>alert('uuu')</script> :firefox:"
-        )
-
-      assert activity.data["type"] == "Create"
-      assert activity.local
-      object = Object.normalize(activity, fetch: false)
-
-      assert object.data["type"] == "ChatMessage"
-      assert object.data["to"] == [recipient.ap_id]
-
-      assert object.data["content"] ==
-               "a test message &lt;script&gt;alert(&#39;uuu&#39;)&lt;/script&gt; :firefox:"
-
-      assert object.data["emoji"] == %{
-               "firefox" => "http://localhost:4001/emoji/Firefox.gif"
-             }
-
-      assert Chat.get(author.id, recipient.ap_id)
-      assert Chat.get(recipient.id, author.ap_id)
-
-      assert :ok == Pleroma.Web.Federator.perform(:publish, activity)
-    end
-
-    test "it reject messages over the local limit" do
-      clear_config([:instance, :chat_limit], 2)
-
-      author = insert(:user)
-      recipient = insert(:user)
-
-      {:error, message} =
-        CommonAPI.post_chat_message(
-          author,
-          recipient,
-          "123"
-        )
-
-      assert message == :content_too_long
-    end
-
-    test "it reject messages via MRF" do
-      clear_config([:mrf_keyword, :reject], ["GNO"])
-      clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
-
-      author = insert(:user)
-      recipient = insert(:user)
-
-      assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
-               CommonAPI.post_chat_message(author, recipient, "GNO/Linux")
-    end
-  end
-
   describe "unblocking" do
     test "it works even without an existing block activity" do
       blocked = insert(:user)
   describe "unblocking" do
     test "it works even without an existing block activity" do
       blocked = insert(:user)
@@ -500,7 +346,7 @@ defmodule Pleroma.Web.CommonAPITest do
 
     object = Object.normalize(activity, fetch: false)
 
 
     object = Object.normalize(activity, fetch: false)
 
-    assert object.data["tag"] == ["2hu"]
+    assert Object.tags(object) == ["2hu"]
   end
 
   test "it adds emoji in the object" do
   end
 
   test "it adds emoji in the object" do
@@ -521,7 +367,28 @@ defmodule Pleroma.Web.CommonAPITest do
       {:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
 
       assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
       {:ok, activity} = CommonAPI.post(user, %{status: "hey :blank:"})
 
       assert %{"blank" => url} = Object.normalize(activity).data["emoji"]
-      assert url == "#{Pleroma.Web.base_url()}/emoji/blank.png"
+      assert url == "#{Pleroma.Web.Endpoint.url()}/emoji/blank.png"
+    end
+
+    test "it copies emoji from the subject of the parent post" do
+      %Object{} =
+        object =
+        Object.normalize("https://patch.cx/objects/a399c28e-c821-4820-bc3e-4afeb044c16f",
+          fetch: true
+        )
+
+      activity = Activity.get_create_by_object_ap_id(object.data["id"])
+      user = insert(:user)
+
+      {:ok, reply_activity} =
+        CommonAPI.post(user, %{
+          in_reply_to_id: activity.id,
+          status: ":joker_disapprove:",
+          spoiler_text: ":joker_smile:"
+        })
+
+      assert Object.normalize(reply_activity).data["emoji"]["joker_smile"]
+      refute Object.normalize(reply_activity).data["emoji"]["joker_disapprove"]
     end
 
     test "deactivated users can't post" do
     end
 
     test "deactivated users can't post" do
@@ -562,7 +429,11 @@ defmodule Pleroma.Web.CommonAPITest do
       object = Object.normalize(activity, fetch: false)
 
       assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
       object = Object.normalize(activity, fetch: false)
 
       assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
-      assert object.data["source"] == post
+
+      assert object.data["source"] == %{
+               "mediaType" => "text/html",
+               "content" => post
+             }
     end
 
     test "it filters out obviously bad tags when accepting a post as Markdown" do
     end
 
     test "it filters out obviously bad tags when accepting a post as Markdown" do
@@ -578,8 +449,12 @@ defmodule Pleroma.Web.CommonAPITest do
 
       object = Object.normalize(activity, fetch: false)
 
 
       object = Object.normalize(activity, fetch: false)
 
-      assert object.data["content"] == "<p><b>2hu</b></p>alert(&#39;xss&#39;)"
-      assert object.data["source"] == post
+      assert object.data["content"] == "<p><b>2hu</b></p>"
+
+      assert object.data["source"] == %{
+               "mediaType" => "text/markdown",
+               "content" => post
+             }
     end
 
     test "it does not allow replies to direct messages that are not direct messages themselves" do
     end
 
     test "it does not allow replies to direct messages that are not direct messages themselves" do
@@ -808,13 +683,17 @@ defmodule Pleroma.Web.CommonAPITest do
       [user: user, activity: activity]
     end
 
       [user: user, activity: activity]
     end
 
+    test "activity not found error", %{user: user} do
+      assert {:error, :not_found} = CommonAPI.pin("id", user)
+    end
+
     test "pin status", %{user: user, activity: activity} do
       assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
 
     test "pin status", %{user: user, activity: activity} do
       assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
 
-      id = activity.id
+      %{data: %{"id" => object_id}} = Object.normalize(activity)
       user = refresh_record(user)
 
       user = refresh_record(user)
 
-      assert %User{pinned_activities: [^id]} = user
+      assert user.pinned_objects |> Map.keys() == [object_id]
     end
 
     test "pin poll", %{user: user} do
     end
 
     test "pin poll", %{user: user} do
@@ -826,10 +705,11 @@ defmodule Pleroma.Web.CommonAPITest do
 
       assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
 
 
       assert {:ok, ^activity} = CommonAPI.pin(activity.id, user)
 
-      id = activity.id
+      %{data: %{"id" => object_id}} = Object.normalize(activity)
+
       user = refresh_record(user)
 
       user = refresh_record(user)
 
-      assert %User{pinned_activities: [^id]} = user
+      assert user.pinned_objects |> Map.keys() == [object_id]
     end
 
     test "unlisted statuses can be pinned", %{user: user} do
     end
 
     test "unlisted statuses can be pinned", %{user: user} do
@@ -840,7 +720,7 @@ defmodule Pleroma.Web.CommonAPITest do
     test "only self-authored can be pinned", %{activity: activity} do
       user = insert(:user)
 
     test "only self-authored can be pinned", %{activity: activity} do
       user = insert(:user)
 
-      assert {:error, "Could not pin"} = CommonAPI.pin(activity.id, user)
+      assert {:error, :ownership_error} = CommonAPI.pin(activity.id, user)
     end
 
     test "max pinned statuses", %{user: user, activity: activity_one} do
     end
 
     test "max pinned statuses", %{user: user, activity: activity_one} do
@@ -850,8 +730,12 @@ defmodule Pleroma.Web.CommonAPITest do
 
       user = refresh_record(user)
 
 
       user = refresh_record(user)
 
-      assert {:error, "You have already pinned the maximum number of statuses"} =
-               CommonAPI.pin(activity_two.id, user)
+      assert {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity_two.id, user)
+    end
+
+    test "only public can be pinned", %{user: user} do
+      {:ok, activity} = CommonAPI.post(user, %{status: "private status", visibility: "private"})
+      {:error, :visibility_error} = CommonAPI.pin(activity.id, user)
     end
 
     test "unpin status", %{user: user, activity: activity} do
     end
 
     test "unpin status", %{user: user, activity: activity} do
@@ -865,7 +749,7 @@ defmodule Pleroma.Web.CommonAPITest do
 
       user = refresh_record(user)
 
 
       user = refresh_record(user)
 
-      assert %User{pinned_activities: []} = user
+      assert user.pinned_objects == %{}
     end
 
     test "should unpin when deleting a status", %{user: user, activity: activity} do
     end
 
     test "should unpin when deleting a status", %{user: user, activity: activity} do
@@ -877,7 +761,40 @@ defmodule Pleroma.Web.CommonAPITest do
 
       user = refresh_record(user)
 
 
       user = refresh_record(user)
 
-      assert %User{pinned_activities: []} = user
+      assert user.pinned_objects == %{}
+    end
+
+    test "ephemeral activity won't be deleted if was pinned", %{user: user} do
+      {:ok, activity} = CommonAPI.post(user, %{status: "Hello!", expires_in: 601})
+
+      assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+
+      {:ok, _activity} = CommonAPI.pin(activity.id, user)
+      refute Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+
+      user = refresh_record(user)
+      {:ok, _} = CommonAPI.unpin(activity.id, user)
+
+      # recreates expiration job on unpin
+      assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity.id)
+    end
+
+    test "ephemeral activity deletion job won't be deleted on pinning error", %{
+      user: user,
+      activity: activity
+    } do
+      clear_config([:instance, :max_pinned_statuses], 1)
+
+      {:ok, _activity} = CommonAPI.pin(activity.id, user)
+
+      {:ok, activity2} = CommonAPI.post(user, %{status: "another status", expires_in: 601})
+
+      assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
+
+      user = refresh_record(user)
+      {:error, :pinned_statuses_limit_reached} = CommonAPI.pin(activity2.id, user)
+
+      assert Pleroma.Workers.PurgeExpiredActivity.get_expiration(activity2.id)
     end
   end
 
     end
   end
 
@@ -1141,24 +1058,23 @@ defmodule Pleroma.Web.CommonAPITest do
       refute User.subscribed_to?(follower, followed)
     end
 
       refute User.subscribed_to?(follower, followed)
     end
 
-    test "cancels a pending follow for a local user" do
+    test "removes a pending follow for a local user" do
       follower = insert(:user)
       followed = insert(:user, is_locked: true)
 
       follower = insert(:user)
       followed = insert(:user, is_locked: true)
 
-      assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
+      assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
                CommonAPI.follow(follower, followed)
 
       assert User.get_follow_state(follower, followed) == :follow_pending
       assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
       assert User.get_follow_state(follower, followed) == nil
 
                CommonAPI.follow(follower, followed)
 
       assert User.get_follow_state(follower, followed) == :follow_pending
       assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
       assert User.get_follow_state(follower, followed) == nil
 
-      assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
-               Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
+      assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
 
       assert %{
                data: %{
                  "type" => "Undo",
 
       assert %{
                data: %{
                  "type" => "Undo",
-                 "object" => %{"type" => "Follow", "state" => "cancelled"}
+                 "object" => %{"type" => "Follow"}
                }
              } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
     end
                }
              } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
     end
@@ -1167,20 +1083,19 @@ defmodule Pleroma.Web.CommonAPITest do
       follower = insert(:user)
       followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
 
       follower = insert(:user)
       followed = insert(:user, is_locked: true, local: false, ap_enabled: true)
 
-      assert {:ok, follower, followed, %{id: activity_id, data: %{"state" => "pending"}}} =
+      assert {:ok, follower, followed, %{id: _activity_id, data: %{"state" => "pending"}}} =
                CommonAPI.follow(follower, followed)
 
       assert User.get_follow_state(follower, followed) == :follow_pending
       assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
       assert User.get_follow_state(follower, followed) == nil
 
                CommonAPI.follow(follower, followed)
 
       assert User.get_follow_state(follower, followed) == :follow_pending
       assert {:ok, follower} = CommonAPI.unfollow(follower, followed)
       assert User.get_follow_state(follower, followed) == nil
 
-      assert %{id: ^activity_id, data: %{"state" => "cancelled"}} =
-               Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed)
+      assert is_nil(Pleroma.Web.ActivityPub.Utils.fetch_latest_follow(follower, followed))
 
       assert %{
                data: %{
                  "type" => "Undo",
 
       assert %{
                data: %{
                  "type" => "Undo",
-                 "object" => %{"type" => "Follow", "state" => "cancelled"}
+                 "object" => %{"type" => "Follow"}
                }
              } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
     end
                }
              } = Pleroma.Web.ActivityPub.Utils.fetch_latest_undo(follower)
     end
@@ -1255,45 +1170,6 @@ defmodule Pleroma.Web.CommonAPITest do
     end
   end
 
     end
   end
 
-  describe "listen/2" do
-    test "returns a valid activity" do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.listen(user, %{
-          title: "lain radio episode 1",
-          album: "lain radio",
-          artist: "lain",
-          length: 180_000
-        })
-
-      object = Object.normalize(activity, fetch: false)
-
-      assert object.data["title"] == "lain radio episode 1"
-
-      assert Visibility.get_visibility(activity) == "public"
-    end
-
-    test "respects visibility=private" do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.listen(user, %{
-          title: "lain radio episode 1",
-          album: "lain radio",
-          artist: "lain",
-          length: 180_000,
-          visibility: "private"
-        })
-
-      object = Object.normalize(activity, fetch: false)
-
-      assert object.data["title"] == "lain radio episode 1"
-
-      assert Visibility.get_visibility(activity) == "private"
-    end
-  end
-
   describe "get_user/1" do
     test "gets user by ap_id" do
       user = insert(:user)
   describe "get_user/1" do
     test "gets user by ap_id" do
       user = insert(:user)
@@ -1437,4 +1313,128 @@ defmodule Pleroma.Web.CommonAPITest do
       end
     end
   end
       end
     end
   end
+
+  describe "update/3" do
+    test "updates a post" do
+      user = insert(:user)
+      {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1"})
+
+      {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
+
+      updated_object = Object.normalize(updated)
+      assert updated_object.data["content"] == "updated 2"
+      assert Map.get(updated_object.data, "summary", "") == ""
+      assert Map.has_key?(updated_object.data, "updated")
+    end
+
+    test "does not change visibility" do
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1", visibility: "private"})
+
+      {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
+
+      updated_object = Object.normalize(updated)
+      assert updated_object.data["content"] == "updated 2"
+      assert Map.get(updated_object.data, "summary", "") == ""
+      assert Visibility.get_visibility(updated_object) == "private"
+      assert Visibility.get_visibility(updated) == "private"
+    end
+
+    test "updates a post with emoji" do
+      [{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
+
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
+
+      {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
+
+      updated_object = Object.normalize(updated)
+      assert updated_object.data["content"] == "updated 2 :#{emoji2}:"
+      assert %{^emoji2 => _} = updated_object.data["emoji"]
+    end
+
+    test "updates a post with emoji and federate properly" do
+      [{emoji1, _}, {emoji2, _} | _] = Pleroma.Emoji.get_all()
+
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{status: "foo1", spoiler_text: "title 1 :#{emoji1}:"})
+
+      clear_config([:instance, :federating], true)
+
+      with_mock Pleroma.Web.Federator,
+        publish: fn _p -> nil end do
+        {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2 :#{emoji2}:"})
+
+        assert updated.data["object"]["content"] == "updated 2 :#{emoji2}:"
+        assert %{^emoji2 => _} = updated.data["object"]["emoji"]
+
+        assert called(Pleroma.Web.Federator.publish(updated))
+      end
+    end
+
+    test "editing a post that copied a remote title with remote emoji should keep that emoji" do
+      remote_emoji_uri = "https://remote.org/emoji.png"
+
+      note =
+        insert(
+          :note,
+          data: %{
+            "summary" => ":remoteemoji:",
+            "emoji" => %{
+              "remoteemoji" => remote_emoji_uri
+            },
+            "tag" => [
+              %{
+                "type" => "Emoji",
+                "name" => "remoteemoji",
+                "icon" => %{"url" => remote_emoji_uri}
+              }
+            ]
+          }
+        )
+
+      note_activity = insert(:note_activity, note: note)
+
+      user = insert(:user)
+
+      {:ok, reply} =
+        CommonAPI.post(user, %{
+          status: "reply",
+          spoiler_text: ":remoteemoji:",
+          in_reply_to_id: note_activity.id
+        })
+
+      assert reply.object.data["emoji"]["remoteemoji"] == remote_emoji_uri
+
+      {:ok, edit} =
+        CommonAPI.update(user, reply, %{status: "reply mew mew", spoiler_text: ":remoteemoji:"})
+
+      edited_note = Pleroma.Object.normalize(edit)
+
+      assert edited_note.data["emoji"]["remoteemoji"] == remote_emoji_uri
+    end
+
+    test "respects MRF" do
+      user = insert(:user)
+
+      clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+      clear_config([:mrf_keyword, :replace], [{"updated", "mewmew"}])
+
+      {:ok, activity} = CommonAPI.post(user, %{status: "foo1", spoiler_text: "updated 1"})
+      assert Object.normalize(activity).data["summary"] == "mewmew 1"
+
+      {:ok, updated} = CommonAPI.update(user, activity, %{status: "updated 2"})
+
+      updated_object = Object.normalize(updated)
+      assert updated_object.data["content"] == "mewmew 2"
+      assert Map.get(updated_object.data, "summary", "") == ""
+      assert Map.has_key?(updated_object.data, "updated")
+    end
+  end
 end
 end