From 86988e71f012cf83dae25ce87fd505c9f8fc125b Mon Sep 17 00:00:00 2001 From: Oneric Date: Wed, 6 Aug 2025 00:00:00 +0000 Subject: [PATCH] mix/database/resync_inlined_caches: also resync reactions Relies on the fixups from preceding commits being applied. --- .../docs/administration/CLI_tasks/database.md | 1 + lib/mix/tasks/pleroma/database.ex | 55 ++++++++++++++++++- 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/docs/docs/administration/CLI_tasks/database.md b/docs/docs/administration/CLI_tasks/database.md index b5988929f..f21ad2d40 100644 --- a/docs/docs/administration/CLI_tasks/database.md +++ b/docs/docs/administration/CLI_tasks/database.md @@ -298,4 +298,5 @@ Run this task to detect and fix such desyncs. - `--no-announcements` - Skip fixing announcement counters and lists - `--no-likes` - Skip fixing like counters and lists +- `--no-reactions` - Skip fixing inlined emoji reaction data - `--no-replies-count` - Skip fixing replies counters (purely cosmetic) diff --git a/lib/mix/tasks/pleroma/database.ex b/lib/mix/tasks/pleroma/database.ex index 79df0915e..d896d9e87 100644 --- a/lib/mix/tasks/pleroma/database.ex +++ b/lib/mix/tasks/pleroma/database.ex @@ -530,8 +530,8 @@ def run(["resync_inlined_caches" | args]) do strict: [ replies_count: :boolean, announcements: :boolean, - likes: :boolean - # TODO: reactions (emoji reacts) + likes: :boolean, + reactions: :boolean ] ) @@ -548,6 +548,10 @@ def run(["resync_inlined_caches" | args]) do if Keyword.get(options, :likes, true) do resync_inlined_array("Like", "like") end + + if Keyword.get(options, :reactions, true) do + resync_inlined_reactions() + end end def run(["clean_inlined_replies"]) do @@ -725,4 +729,51 @@ defp resync_inlined_array(activity_type, basename) do Logger.info("Fixed inlined #{basename} array and counter for #{update_cnt} objects.") end + + defp resync_inlined_reactions() do + expanded_ref = + Pleroma.Activity + |> select([a], %{ + apid: selected_as(fragment("?->>'object'", a.data), :apid), + emoji_name: selected_as(fragment("TRIM(?->>'content', ':')", a.data), :emoji_name), + actors: fragment("ARRAY_AGG(DISTINCT ?->>'actor')", a.data), + url: selected_as(fragment("?#>>'{tag,0,icon,url}'", a.data), :url) + }) + |> where( + [a], + fragment("?->>'type' = 'EmojiReact'", a.data) and + fragment("?->>'actor' IS NOT NULL", a.data) and + fragment("TRIM(?->>'content', ':') IS NOT NULL", a.data) + ) + |> group_by([_], [selected_as(:apid), selected_as(:emoji_name), selected_as(:url)]) + + ref = + from(e in subquery(expanded_ref)) + |> select([e], %{ + apid: e.apid, + correct: + fragment( + "jsonb_agg(DISTINCT ARRAY[to_jsonb(?), to_jsonb(?), to_jsonb(?)])", + e.emoji_name, + e.actors, + e.url + ) + }) + |> group_by([e], e.apid) + + {update_cnt, _} = + Pleroma.Object + |> join(:inner, [o], r in subquery(ref), on: r.apid == fragment("?->>'id'", o.data)) + |> where( + [o, r], + not (fragment("? @> (?->'reactions')", r.correct, o.data) and + fragment("? <@ (?->'reactions')", r.correct, o.data)) + ) + |> update([o, r], + set: [data: fragment("jsonb_set(?, '{reactions}', ?)", o.data, r.correct)] + ) + |> Pleroma.Repo.update_all([], timeout: :infinity) + + Logger.info("Fixed inlined emoji reactions for #{update_cnt} objects.") + end end