fed/out: also represent emoji as anonymous objects in reactions
All checks were successful
ci/woodpecker/pr/test/2 Pipeline was successful
ci/woodpecker/pr/test/1 Pipeline was successful

It did not use the same Emoji object template as other occurrences.
This also fixes an issue with the icon URL not being properly encoded
as well as an inconsistency regarding the domain part of remote
reactions in retractions. All places use the image URL domain
except the query to find the activity to retract relie on the id.
Even before this change this made it impossible to retract remote
emoji reactions if the remote either doesn't send emoji IDs or
doesn't store images on the ActivityPub domain.

Addresses omission in 4ff5293093

Fixes: #1042
This commit is contained in:
Oneric 2026-01-04 00:00:00 +00:00
commit 80817ac65e
6 changed files with 41 additions and 44 deletions

View file

@ -57,6 +57,17 @@ defmodule Pleroma.Web.ActivityPub.Builder do
{:ok, data, []}
end
@spec emoji_object!({String.t(), String.t()}) :: map()
def emoji_object!({name, url}) do
# TODO: we should probably send mtime instead of unix epoch time for updated
%{
"icon" => %{"url" => "#{URI.encode(url)}", "type" => "Image"},
"name" => Emoji.maybe_quote(name),
"type" => "Emoji",
"updated" => "1970-01-01T00:00:00Z"
}
end
defp unicode_emoji_react(_object, data, emoji) do
data
|> Map.put("content", emoji)
@ -67,18 +78,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
data
|> Map.put("content", Emoji.maybe_quote(emoji))
|> Map.put("type", "EmojiReact")
|> Map.put("tag", [
%{}
|> Map.put("id", url)
|> Map.put("type", "Emoji")
|> Map.put("name", Emoji.maybe_quote(emoji))
|> Map.put(
"icon",
%{}
|> Map.put("type", "Image")
|> Map.put("url", url)
)
])
|> Map.put("tag", [emoji_object!({emoji, url})])
end
defp remote_custom_emoji_react(

View file

@ -1028,29 +1028,19 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def take_emoji_tags(%User{emoji: emoji}) do
emoji
|> Map.to_list()
|> Enum.map(&build_emoji_tag/1)
|> Enum.map(&Builder.emoji_object!/1)
end
# TODO: we should probably send mtime instead of unix epoch time for updated
def add_emoji_tags(%{"emoji" => emoji} = object) do
tags = object["tag"] || []
out = Enum.map(emoji, &build_emoji_tag/1)
out = Enum.map(emoji, &Builder.emoji_object!/1)
Map.put(object, "tag", tags ++ out)
end
def add_emoji_tags(object), do: object
defp build_emoji_tag({name, url}) do
%{
"icon" => %{"url" => "#{URI.encode(url)}", "type" => "Image"},
"name" => ":" <> name <> ":",
"type" => "Emoji",
"updated" => "1970-01-01T00:00:00Z"
}
end
def set_conversation(object) do
Map.put(object, "conversation", object["context"])
end

View file

@ -516,7 +516,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> where([activity], fragment("?->>'content' = ?
AND EXISTS (
SELECT FROM jsonb_array_elements(?->'tag') elem
WHERE elem->>'id' ILIKE ?
WHERE COALESCE(elem->'icon'->>'url', '') ILIKE ?
)", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
else
query

View file

@ -62,21 +62,29 @@ defmodule Pleroma.Web.ActivityPub.BuilderTest do
user = insert(:user)
note = insert(:note)
assert {:ok,
%{
"content" => ":dinosaur:",
"type" => "EmojiReact",
"tag" => [
%{
"name" => ":dinosaur:",
"id" => "http://localhost:4001/emoji/dino walking.gif",
"icon" => %{
"type" => "Image",
"url" => "http://localhost:4001/emoji/dino walking.gif"
}
}
]
}, []} = Builder.emoji_react(user, note, ":dinosaur:")
{:ok, %{} = data, []} = Builder.emoji_react(user, note, ":dinosaur:")
assert match?(
%{
"content" => ":dinosaur:",
"type" => "EmojiReact",
"tag" => [
%{
"type" => "Emoji",
"name" => ":dinosaur:",
"icon" => %{
"type" => "Image",
"url" => "http://localhost:4001/emoji/dino%20walking.gif"
}
}
]
},
data
)
emoji = hd(data["tag"])
refute emoji["id"]
end
test "remote custom emoji" do
@ -95,7 +103,6 @@ defmodule Pleroma.Web.ActivityPub.BuilderTest do
"tag" => [
%{
"name" => ":wow:",
"id" => "https://remote/emoji/wow",
"icon" => %{
"type" => "Image",
"url" => "https://remote/emoji/wow"

View file

@ -58,7 +58,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
count: 2,
me: false,
name: "dinosaur",
url: "http://localhost:4001/emoji/dino walking.gif",
url: "http://localhost:4001/emoji/dino%20walking.gif",
account_ids: [other_user.id, user.id]
},
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]},
@ -75,7 +75,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
count: 2,
me: true,
name: "dinosaur",
url: "http://localhost:4001/emoji/dino walking.gif",
url: "http://localhost:4001/emoji/dino%20walking.gif",
account_ids: [other_user.id, user.id]
},
%{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}

View file

@ -95,7 +95,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
"name" => "dinosaur",
"count" => 1,
"me" => true,
"url" => "http://localhost:4001/emoji/dino walking.gif",
"url" => "http://localhost:4001/emoji/dino%20walking.gif",
"account_ids" => [other_user.id]
}
]