From 5aa3c8a06e9b62f5fa6a90ae319c7a75cbbac4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Mon, 23 Mar 2026 11:50:31 +0100 Subject: [PATCH] Federate `votersCount` correctly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk Assisted-by: your mother Signed-off-by: nicole mikołajczyk --- changelog.d/poll-voters-count.fix | 1 + lib/pleroma/object.ex | 8 ++++++++ .../object_validators/question_validator.ex | 1 + .../web/activity_pub/transmogrifier.ex | 7 +++++++ .../web/mastodon_api/views/poll_view.ex | 2 ++ .../transmogrifier/question_handling_test.exs | 19 +++++++++++++++++++ .../web/mastodon_api/views/poll_view_test.exs | 9 ++++++++- 7 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 changelog.d/poll-voters-count.fix diff --git a/changelog.d/poll-voters-count.fix b/changelog.d/poll-voters-count.fix new file mode 100644 index 000000000..2dbc81b5d --- /dev/null +++ b/changelog.d/poll-voters-count.fix @@ -0,0 +1 @@ +Federate `votersCount` correctly diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index d0cb16b79..f1e07a257 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -374,10 +374,18 @@ defmodule Pleroma.Object do voters = [actor | object.data["voters"] || []] |> Enum.uniq() + voters_count = + if Map.has_key?(object.data, "votersCount") do + object.data["votersCount"] + 1 + else + length(voters) + end + data = object.data |> Map.put(key, options) |> Map.put("voters", voters) + |> Map.put("votersCount", voters_count) object |> Object.change(%{data: data}) diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex index 21940f4f1..065c75910 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex @@ -28,6 +28,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do end field(:closed, ObjectValidators.DateTime) + field(:votersCount, :integer) field(:voters, {:array, ObjectValidators.ObjectID}, default: []) field(:nonAnonymous, :boolean) embeds_many(:anyOf, QuestionOptionsValidator) diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 6af5ee89d..4421da26c 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -783,6 +783,12 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def set_replies(obj_data), do: obj_data + defp set_voters_count(%{"voters" => [_ | _] = voters} = obj) do + Map.merge(obj, %{"votersCount" => length(voters)}) + end + + defp set_voters_count(obj), do: obj + # Prepares and sanitizes the object for federation. def prepare_object(object) do object @@ -795,6 +801,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do |> set_reply_to_uri |> set_quote_url |> set_replies + |> set_voters_count |> CommonFixes.maybe_add_content_map() |> strip_internal_fields |> strip_internal_tags diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex index 1e3c9f36d..3b4271227 100644 --- a/lib/pleroma/web/mastodon_api/views/poll_view.ex +++ b/lib/pleroma/web/mastodon_api/views/poll_view.ex @@ -75,6 +75,8 @@ defmodule Pleroma.Web.MastodonAPI.PollView do length(voters) end + defp voters_count(%{data: %{"votersCount" => voters}}), do: voters + defp voters_count(_), do: 0 defp voted_and_own_votes(%{object: object} = params, options) do diff --git a/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs index d31070546..2a4e78cf0 100644 --- a/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs +++ b/test/pleroma/web/activity_pub/transmogrifier/question_handling_test.exs @@ -170,4 +170,23 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.QuestionHandlingTest do assert {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data) end + + test "it displays voters count for a poll" do + user = insert(:user) + other_user = insert(:user) + + {:ok, activity} = + CommonAPI.post(user, %{ + status: "???", + poll: %{expires_in: 10, options: ["yes", "no"]} + }) + + object = Object.normalize(activity, fetch: false) + {:ok, _, _} = CommonAPI.vote(object, other_user, [1]) + + {:ok, modified} = Transmogrifier.prepare_activity(activity.data) + + refute Map.has_key?(modified["object"], "voters") + assert modified["object"]["votersCount"] == 1 + end end diff --git a/test/pleroma/web/mastodon_api/views/poll_view_test.exs b/test/pleroma/web/mastodon_api/views/poll_view_test.exs index 6de001421..16281393d 100644 --- a/test/pleroma/web/mastodon_api/views/poll_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/poll_view_test.exs @@ -167,7 +167,14 @@ defmodule Pleroma.Web.MastodonAPI.PollViewTest do } = PollView.render("show.json", %{object: object}) end - test "that poll is non anonymous" do + test "displays correct voters count" do + object = Object.normalize("https://friends.grishka.me/posts/54642", fetch: true) + result = PollView.render("show.json", %{object: object}) + + assert result[:voters_count] == 14 + end + + test "detects that poll is non anonymous" do object = Object.normalize("https://friends.grishka.me/posts/54642", fetch: true) result = PollView.render("show.json", %{object: object})