From 7ecfb953316d718235042e60a58b464ccdd764f0 Mon Sep 17 00:00:00 2001 From: Ekaterina Vaartis Date: Fri, 13 Jun 2025 22:47:32 +0300 Subject: [PATCH] Handle the Dislike activity by transforming into a thumbs-down emote --- changelog.d/dislike-activity.add | 1 + lib/pleroma/constants.ex | 2 + .../web/activity_pub/transmogrifier.ex | 18 +++++ test/fixtures/friendica-dislike-undo.json | 76 +++++++++++++++++++ test/fixtures/friendica-dislike.json | 56 ++++++++++++++ .../transmogrifier/like_handling_test.exs | 36 +++++++++ 6 files changed, 189 insertions(+) create mode 100644 changelog.d/dislike-activity.add create mode 100644 test/fixtures/friendica-dislike-undo.json create mode 100644 test/fixtures/friendica-dislike.json diff --git a/changelog.d/dislike-activity.add b/changelog.d/dislike-activity.add new file mode 100644 index 000000000..1fcbda78b --- /dev/null +++ b/changelog.d/dislike-activity.add @@ -0,0 +1 @@ +Support Dislike activity, as sent by Mitra and Friendica, by changing it into a thumbs-down EmojiReact \ No newline at end of file diff --git a/lib/pleroma/constants.ex b/lib/pleroma/constants.ex index 3762c0035..92ca11494 100644 --- a/lib/pleroma/constants.ex +++ b/lib/pleroma/constants.ex @@ -100,6 +100,7 @@ defmodule Pleroma.Constants do "Add", "Remove", "Like", + "Dislike", "Announce", "Undo", "Flag", @@ -115,6 +116,7 @@ defmodule Pleroma.Constants do "Flag", "Follow", "Like", + "Dislike", "EmojiReact", "Announce" ] diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 6517f5eff..8819e1596 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -664,6 +664,24 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do end end + # Rewrite dislikes into the thumbs down emoji + defp handle_incoming_normalized(%{"type" => "Dislike"} = data, options) do + data + |> Map.put("type", "EmojiReact") + |> Map.put("content", "👎") + |> handle_incoming_normalized(options) + end + + defp handle_incoming_normalized( + %{"type" => "Undo", "object" => %{"type" => "Dislike"}} = data, + options + ) do + data + |> put_in(["object", "type"], "EmojiReact") + |> put_in(["object", "content"], "👎") + |> handle_incoming_normalized(options) + end + defp handle_incoming_normalized(_, _), do: :error @spec get_obj_helper(String.t(), Keyword.t()) :: {:ok, Object.t()} | nil diff --git a/test/fixtures/friendica-dislike-undo.json b/test/fixtures/friendica-dislike-undo.json new file mode 100644 index 000000000..b258e00be --- /dev/null +++ b/test/fixtures/friendica-dislike-undo.json @@ -0,0 +1,76 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Hashtag": "as:Hashtag", + "PropertyValue": "schema:PropertyValue", + "conversation": "ostatus:conversation", + "dfrn": "http://purl.org/macgirvin/dfrn/1.0/", + "diaspora": "https://diasporafoundation.org/ns/", + "directMessage": "litepub:directMessage", + "discoverable": "toot:discoverable", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "litepub": "http://litepub.social/ns#", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "ostatus": "http://ostatus.org#", + "quoteUrl": "as:quoteUrl", + "schema": "http://schema.org#", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "value": "schema:value", + "vcard": "http://www.w3.org/2006/vcard/ns#" + } + ], + "actor": "https://my-place.social/profile/vaartis", + "cc": [ + "https://my-place.social/followers/vaartis" + ], + "id": "https://my-place.social/objects/e599373b-1368-4b20-cd24-837166957182/Undo", + "instrument": { + "id": "https://my-place.social/friendica", + "name": "Friendica 'Interrupted Fern' 2024.12-1576", + "type": "Application", + "url": "https://my-place.social" + }, + "object": { + "actor": "https://my-place.social/profile/vaartis", + "cc": [ + "https://my-place.social/followers/vaartis" + ], + "diaspora:guid": "e599373b-1968-4b20-cd24-80d340160302", + "diaspora:like": "{\"author\":\"vaartis@my-place.social\",\"guid\":\"e599373b-1968-4b20-cd24-80d340160302\",\"parent_guid\":\"cd36feba-c31f3ed3fd5c064a-17c31593\",\"parent_type\":\"Post\",\"positive\":\"false\",\"author_signature\":\"xR2zLJNfc9Nhx1n8LLMWM1kde12my4cqamIsrH\\/UntKzuDwO4DuHBL0fkFhgC\\/dylxm4HqsHD45MQbtwQCVGq6WhC96TrbMuYEK61HIO23dTr3m+qJVtfdH4wyhUNHgiiYPhZpkLDfnR1JiRWmFTlmZC8q8JEkOB5IQsrWia2eOR6IsqDcdKO\\/Urgns9\\/BdQi8KnchBKSEFc1iUtcOEruvhunKGyW5zI\\/Rltfdz3xGH8tlw+YlMXeWXPnqgOJ9GzNA0lwG4U421L6yylYagW7oxIznnBLB4bO46vYZbgXZV1hiI9ZyveHOinLMY1QkmTj5CNvnx3\\/VJwLovd0v+0Nr2vu\\/3ftbpBXc6L1bsNjlRqtsfwJlcgl+tH1DC4W8tKf+Y3tdtzVw0CHXCuacxHLyq5wZd\\/5YfYR9SJQ\\/jInU4PHA5+hIE3PGqNUp5QfFE0umq56H7MQKsIPgM5mMV4fPAA8OpltuMVDvQYUxalrnvoTf00k90x1wCTK71\\/jQGh7r7PmGvSdfPr+65eVTjITD8\\/lTGIb8850v1fl3\\/i2R8Dv17jQIRyX5o9MXPSO6jHo4Swma5RzPA\\/0bRj6qRTyPkM1L9qEIr+2H2I7KKhT2ZE5GhAU7yI9A3VLBWzpTrUPMGbfpd1OjVTEqXAdMjpLDYI3Mh5zQ58p8xCzt+W+t0=\"}", + "id": "https://my-place.social/objects/e599373b-1368-4b20-cd24-837166957182", + "instrument": { + "id": "https://my-place.social/friendica", + "name": "Friendica 'Interrupted Fern' 2024.12-1576", + "type": "Application", + "url": "https://my-place.social" + }, + "object": "https://pl.kotobank.ch/objects/301bce65-8a1b-4c49-a65c-fe2ce861a213", + "published": "2025-06-12T18:47:41Z", + "to": [ + "https://pl.kotobank.ch/users/vaartis", + "https://mitra.social/users/silverpill", + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Dislike" + }, + "published": "2025-06-12T18:41:25Z", + "signature": { + "created": "2025-06-12T18:44:16Z", + "creator": "https://my-place.social/profile/vaartis#main-key", + "nonce": "2d67847d4bd4b1b83a30d61eac6cdc7ad6b980df06a8b9b97217e1d8f7b6cf20", + "signatureValue": "LnoRMZuQGDvTICkShGBq28ynaj2lF1bViJFGS6n4gKn3IbxPWATHxao43gxWRc+HCTrHNg7quzgaW4+PYM7UVUz3jO+bjNKsN845nijOVdyFrPOXbuaij3KQh2OoHhFJWoV/ZQQTFF0kRK1qT4BwG+P8NqOOKAMv+Cw7ruQH+f2w7uDgcNIbCD1gLcwb6cw7WVe5qu8yMkKqp2kBdqW3RCsI85RmmFgwehDgH5nrX7ER1qbeLWrqy7echwD9/fO3rqAu13xDNyiGZHDT7JB3RUt0AyMm0XCfjbwSQ0n+MkYXgE4asvFz81+iiPCLt+6gePWAFc5odF1FxdySBpSuUOs4p92NzP9OhQ0c0qrqrzYI7aYklY7oMfxjkva+X+0bm3up+2IRJdnZa/pXlmwdcqTpyMr1sgzaexMUNBp3dq7zA51eEaakLDX3i2onXJowfmze3+6XgPAFHYamR+pRNtuEoY4uyYEK3fj5GgwJ4RtFJMYVoEs/Q8h3OgYRcK1FE9UlDjSqbQ7QIRn2Ib4wjgmkeM0vrHIwh/1CtqA/M/6WuYFzCaJBc8O9ykpK9ZMbw64ToQXKf2SqhZsDoyTWRWTO1PXOk1XCAAElUh8/WCyeghvgqLXn0LHov4lmBsHA5iMUcLqBKD3GJIHd+ExrOFxMZs4mBLLGyz0p5joJ3NY=", + "type": "RsaSignature2017" + }, + "to": [ + "https://pl.kotobank.ch/users/vaartis", + "https://mitra.social/users/silverpill", + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Undo" +} diff --git a/test/fixtures/friendica-dislike.json b/test/fixtures/friendica-dislike.json new file mode 100644 index 000000000..c75939073 --- /dev/null +++ b/test/fixtures/friendica-dislike.json @@ -0,0 +1,56 @@ +{ + "@context": [ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "Hashtag": "as:Hashtag", + "PropertyValue": "schema:PropertyValue", + "conversation": "ostatus:conversation", + "dfrn": "http://purl.org/macgirvin/dfrn/1.0/", + "diaspora": "https://diasporafoundation.org/ns/", + "directMessage": "litepub:directMessage", + "discoverable": "toot:discoverable", + "featured": { + "@id": "toot:featured", + "@type": "@id" + }, + "litepub": "http://litepub.social/ns#", + "manuallyApprovesFollowers": "as:manuallyApprovesFollowers", + "ostatus": "http://ostatus.org#", + "quoteUrl": "as:quoteUrl", + "schema": "http://schema.org#", + "sensitive": "as:sensitive", + "toot": "http://joinmastodon.org/ns#", + "value": "schema:value", + "vcard": "http://www.w3.org/2006/vcard/ns#" + } + ], + "actor": "https://my-place.social/profile/vaartis", + "cc": [ + "https://my-place.social/followers/vaartis" + ], + "diaspora:guid": "e599373b-1968-4b20-cd24-80d340160302", + "diaspora:like": "{\"author\":\"vaartis@my-place.social\",\"guid\":\"e599373b-1968-4b20-cd24-80d340160302\",\"parent_guid\":\"cd36feba-c31f3ed3fd5c064a-17c31593\",\"parent_type\":\"Post\",\"positive\":\"false\",\"author_signature\":\"xR2zLJNfc9Nhx1n8LLMWM1kde12my4cqamIsrH\\/UntKzuDwO4DuHBL0fkFhgC\\/dylxm4HqsHD45MQbtwQCVGq6WhC96TrbMuYEK61HIO23dTr3m+qJVtfdH4wyhUNHgiiYPhZpkLDfnR1JiRWmFTlmZC8q8JEkOB5IQsrWia2eOR6IsqDcdKO\\/Urgns9\\/BdQi8KnchBKSEFc1iUtcOEruvhunKGyW5zI\\/Rltfdz3xGH8tlw+YlMXeWXPnqgOJ9GzNA0lwG4U421L6yylYagW7oxIznnBLB4bO46vYZbgXZV1hiI9ZyveHOinLMY1QkmTj5CNvnx3\\/VJwLovd0v+0Nr2vu\\/3ftbpBXc6L1bsNjlRqtsfwJlcgl+tH1DC4W8tKf+Y3tdtzVw0CHXCuacxHLyq5wZd\\/5YfYR9SJQ\\/jInU4PHA5+hIE3PGqNUp5QfFE0umq56H7MQKsIPgM5mMV4fPAA8OpltuMVDvQYUxalrnvoTf00k90x1wCTK71\\/jQGh7r7PmGvSdfPr+65eVTjITD8\\/lTGIb8850v1fl3\\/i2R8Dv17jQIRyX5o9MXPSO6jHo4Swma5RzPA\\/0bRj6qRTyPkM1L9qEIr+2H2I7KKhT2ZE5GhAU7yI9A3VLBWzpTrUPMGbfpd1OjVTEqXAdMjpLDYI3Mh5zQ58p8xCzt+W+t0=\"}", + "id": "https://my-place.social/objects/e599373b-1368-4b20-cd24-837166957182", + "instrument": { + "id": "https://my-place.social/friendica", + "name": "Friendica 'Interrupted Fern' 2024.12-1576", + "type": "Application", + "url": "https://my-place.social" + }, + "object": "https://pl.kotobank.ch/objects/301bce65-8a1b-4c49-a65c-fe2ce861a213", + "published": "2025-06-12T18:47:41Z", + "signature": { + "created": "2025-06-12T18:47:42Z", + "creator": "https://my-place.social/profile/vaartis#main-key", + "nonce": "84e496f80b09d7a299c5cc89e8cadd13abf621b3a0a321684fa74278b68a6dd8", + "signatureValue": "qe2WxY+j7daIYLRadCctgal6A1s9XgoiMfM/8KjJm15w0sSizYYqruyQ5gS44e+cj5GHc9v5gP2ieod5v7eHAPzlcDI4bfkcyHVapAXTqU67ZebW+v6Q+21IMDgqrkYCv5TbV7LTxltW59dlqovpHE4TEe/M7xLKWJ3vVchRUcWqH9kDmak0nacoqYVAb5E9jYnQhUWPTCfPV82qQpeWQPOZ4iIvPw6rDkSSY5jL6bCogBZblHGpUjXfe/FPlacaCWiTQdoga3yOBXB1RYPw9nh5FI5Xkv/oi+52WmJrECinlD6AL8/BpiYvKz236zy7p/TR4BXlCx9RR/msjOnSabkQ4kmYFrRr80UDCGF+CdkdzLl8K9rSE3PbF1+nEqD7X0GOWn/DdtixqXJw6IR4bh32YW2SlcrSRBvI1p82Mv68BeqRaYqL6FAhKFwLhX5JpXngZ3k0g7rWWxc498voPWnFZDyCTRNxO9VIIUavDDEQ0BdFk6WDb8zx9tsAg8JoK57eVDcFly7tfVQffYiHpve06d8ag1DtzipqguRsURmuqpGNMq28XBTxwtrP2LnXXHKxoYN/YQ9cDnCKclbx7/uKmOVMLkLZlM0wAVoZpm5z2fG4voKqFiGZ1PoiFY2sN4URMArJtygV3PlTX4ASAQrak0ksvEo9msrBUD0Su9c=", + "type": "RsaSignature2017" + }, + "to": [ + "https://pl.kotobank.ch/users/vaartis", + "https://mitra.social/users/silverpill", + "https://www.w3.org/ns/activitystreams#Public" + ], + "type": "Dislike" +} diff --git a/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs index fc04c1391..27f8522ce 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/like_handling_test.exs @@ -143,4 +143,40 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.LikeHandlingTest do assert {:ok, activity} = Transmogrifier.handle_incoming(data) assert activity.data["type"] == "Like" end + + test "it changes incoming dislikes into emoji reactions" do + user = insert(:user) + + {:ok, activity} = CommonAPI.post(user, %{status: "hello"}) + + data = + File.read!("test/fixtures/friendica-dislike.json") + |> Jason.decode!() + |> Map.put("object", activity.data["object"]) + + _actor = insert(:user, ap_id: data["actor"], local: false) + + {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data) + + refute Enum.empty?(activity.recipients) + + assert data["actor"] == "https://my-place.social/profile/vaartis" + assert data["type"] == "EmojiReact" + assert data["content"] == "👎" + assert data["id"] == "https://my-place.social/objects/e599373b-1368-4b20-cd24-837166957182" + assert data["object"] == activity.data["object"] + + data = + File.read!("test/fixtures/friendica-dislike-undo.json") + |> Jason.decode!() + |> put_in(["object", "object"], activity.data["object"]) + + {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data) + + assert data["actor"] == "https://my-place.social/profile/vaartis" + assert data["type"] == "Undo" + + assert data["object"] == + "https://my-place.social/objects/e599373b-1368-4b20-cd24-837166957182" + end end