fix count of poll voters
[akkoma] / lib / pleroma / web / mastodon_api / views / poll_view.ex
index 73c990e2ea2800e5ca5c1949273c4c8bd4076eb8..aa6443754f1b31ac440159b2aae02fd6a2d2fe70 100644 (file)
@@ -1,5 +1,5 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.MastodonAPI.PollView do
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
     {end_time, expired} = end_time_and_expired(object)
     {options, votes_count} = options_and_votes_count(options)
 
-    %{
+    poll = %{
       # Mastodon uses separate ids for polls, but an object can't have
       # more than one poll embedded so object id is fine
       id: to_string(object.id),
@@ -19,19 +19,26 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
       expired: expired,
       multiple: multiple,
       votes_count: votes_count,
-      voters_count: (multiple || nil) && voters_count(object),
+      voters_count: voters_count(object),
       options: options,
-      voted: voted?(params),
       emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
     }
+
+    if params[:for] do
+      # when unauthenticated Mastodon doesn't include `voted` & `own_votes` keys in response
+      {voted, own_votes} = voted_and_own_votes(params, options)
+      Map.merge(poll, %{voted: voted, own_votes: own_votes})
+    else
+      poll
+    end
   end
 
   def render("show.json", %{object: object} = params) do
     case object.data do
-      %{"anyOf" => options} when is_list(options) and options != [] ->
+      %{"anyOf" => [_ | _] = options} ->
         render(__MODULE__, "show.json", Map.merge(params, %{multiple: true, options: options}))
 
-      %{"oneOf" => options} when is_list(options) and options != [] ->
+      %{"oneOf" => [_ | _] = options} ->
         render(__MODULE__, "show.json", Map.merge(params, %{multiple: false, options: options}))
 
       _ ->
@@ -40,15 +47,13 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
   end
 
   defp end_time_and_expired(object) do
-    case object.data["closed"] || object.data["endTime"] do
-      end_time when is_binary(end_time) ->
-        end_time = NaiveDateTime.from_iso8601!(end_time)
-        expired = NaiveDateTime.compare(end_time, NaiveDateTime.utc_now()) == :lt
+    if object.data["closed"] do
+      end_time = NaiveDateTime.from_iso8601!(object.data["closed"])
+      expired = NaiveDateTime.compare(end_time, NaiveDateTime.utc_now()) == :lt
 
-        {Utils.to_masto_date(end_time), expired}
-
-      _ ->
-        {nil, false}
+      {Utils.to_masto_date(end_time), expired}
+    else
+      {nil, false}
     end
   end
 
@@ -63,18 +68,35 @@ defmodule Pleroma.Web.MastodonAPI.PollView do
     end)
   end
 
-  defp voters_count(%{data: %{"voters" => [_ | _] = voters}}) do
+  defp voters_count(%{data: %{"voters" => voters}}) when is_list(voters) do
     length(voters)
   end
 
   defp voters_count(_), do: 0
 
-  defp voted?(%{object: object} = opts) do
-    if opts[:for] do
-      existing_votes = Pleroma.Web.ActivityPub.Utils.get_existing_votes(opts[:for].ap_id, object)
-      existing_votes != [] or opts[:for].ap_id == object.data["actor"]
+  defp voted_and_own_votes(%{object: object} = params, options) do
+    if params[:for] do
+      existing_votes =
+        Pleroma.Web.ActivityPub.Utils.get_existing_votes(params[:for].ap_id, object)
+
+      voted = existing_votes != [] or params[:for].ap_id == object.data["actor"]
+
+      own_votes =
+        if voted do
+          titles = Enum.map(options, & &1[:title])
+
+          Enum.reduce(existing_votes, [], fn vote, acc ->
+            data = vote |> Map.get(:object) |> Map.get(:data)
+            index = Enum.find_index(titles, &(&1 == data["name"]))
+            [index | acc]
+          end)
+        else
+          []
+        end
+
+      {voted, own_votes}
     else
-      false
+      {false, []}
     end
   end
 end