Extract poll actions from `MastodonAPIController` to `PollController`
authorEgor Kislitsyn <egor@kislitsyn.com>
Tue, 1 Oct 2019 04:44:34 +0000 (11:44 +0700)
committerEgor Kislitsyn <egor@kislitsyn.com>
Tue, 1 Oct 2019 04:44:34 +0000 (11:44 +0700)
lib/pleroma/web/controller_helper.ex
lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
lib/pleroma/web/mastodon_api/controllers/poll_controller.ex [new file with mode: 0644]
lib/pleroma/web/mastodon_api/controllers/status_controller.ex
lib/pleroma/web/mastodon_api/views/poll_view.ex [new file with mode: 0644]
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/router.ex
test/web/mastodon_api/controllers/poll_controller_test.exs [new file with mode: 0644]
test/web/mastodon_api/mastodon_api_controller_test.exs
test/web/mastodon_api/views/poll_view_test.exs [new file with mode: 0644]
test/web/mastodon_api/views/status_view_test.exs

index 83b884ba9734ffd05b0825f2564153addebea34c..9a4e322c920e24b7a7e655c45177fac53cb5cbc8 100644 (file)
@@ -75,4 +75,16 @@ defmodule Pleroma.Web.ControllerHelper do
       nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
     end
   end
+
+  def try_render(conn, target, params)
+      when is_binary(target) do
+    case render(conn, target, params) do
+      nil -> render_error(conn, :not_implemented, "Can't display this activity")
+      res -> res
+    end
+  end
+
+  def try_render(conn, _, _) do
+    render_error(conn, :not_implemented, "Can't display this activity")
+  end
 end
index 1484a017472d55432721a91b0f33d0cbbe2cf03e..912dd181f4056a93d59ecad9dbc4841b93fdefde 100644 (file)
@@ -7,7 +7,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
 
   import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
 
-  alias Pleroma.Activity
   alias Pleroma.Bookmark
   alias Pleroma.Config
   alias Pleroma.HTTP
@@ -19,7 +18,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
   alias Pleroma.User
   alias Pleroma.Web
   alias Pleroma.Web.ActivityPub.ActivityPub
-  alias Pleroma.Web.ActivityPub.Visibility
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.MastodonAPI.AccountView
   alias Pleroma.Web.MastodonAPI.AppView
@@ -117,56 +115,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     json(conn, mastodon_emoji)
   end
 
-  def get_poll(%{assigns: %{user: user}} = conn, %{"id" => id}) do
-    with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
-         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
-         true <- Visibility.visible_for_user?(activity, user) do
-      conn
-      |> put_view(StatusView)
-      |> try_render("poll.json", %{object: object, for: user})
-    else
-      error when is_nil(error) or error == false ->
-        render_error(conn, :not_found, "Record not found")
-    end
-  end
-
-  defp get_cached_vote_or_vote(user, object, choices) do
-    idempotency_key = "polls:#{user.id}:#{object.data["id"]}"
-
-    {_, res} =
-      Cachex.fetch(:idempotency_cache, idempotency_key, fn _ ->
-        case CommonAPI.vote(user, object, choices) do
-          {:error, _message} = res -> {:ignore, res}
-          res -> {:commit, res}
-        end
-      end)
-
-    res
-  end
-
-  def poll_vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do
-    with %Object{} = object <- Object.get_by_id(id),
-         true <- object.data["type"] == "Question",
-         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
-         true <- Visibility.visible_for_user?(activity, user),
-         {:ok, _activities, object} <- get_cached_vote_or_vote(user, object, choices) do
-      conn
-      |> put_view(StatusView)
-      |> try_render("poll.json", %{object: object, for: user})
-    else
-      nil ->
-        render_error(conn, :not_found, "Record not found")
-
-      false ->
-        render_error(conn, :not_found, "Record not found")
-
-      {:error, message} ->
-        conn
-        |> put_status(:unprocessable_entity)
-        |> json(%{error: message})
-    end
-  end
-
   def update_media(
         %{assigns: %{user: user}} = conn,
         %{"id" => id, "description" => description} = _
@@ -511,18 +459,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
     end
   end
 
-  def try_render(conn, target, params)
-      when is_binary(target) do
-    case render(conn, target, params) do
-      nil -> render_error(conn, :not_implemented, "Can't display this activity")
-      res -> res
-    end
-  end
-
-  def try_render(conn, _, _) do
-    render_error(conn, :not_implemented, "Can't display this activity")
-  end
-
   defp present?(nil), do: false
   defp present?(false), do: false
   defp present?(_), do: true
diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
new file mode 100644 (file)
index 0000000..fbf7f86
--- /dev/null
@@ -0,0 +1,53 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.PollController do
+  use Pleroma.Web, :controller
+
+  import Pleroma.Web.ControllerHelper, only: [try_render: 3, json_response: 3]
+
+  alias Pleroma.Activity
+  alias Pleroma.Object
+  alias Pleroma.Web.ActivityPub.Visibility
+  alias Pleroma.Web.CommonAPI
+
+  action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
+
+  @doc "GET /api/v1/polls/:id"
+  def show(%{assigns: %{user: user}} = conn, %{"id" => id}) do
+    with %Object{} = object <- Object.get_by_id_and_maybe_refetch(id, interval: 60),
+         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
+         true <- Visibility.visible_for_user?(activity, user) do
+      try_render(conn, "show.json", %{object: object, for: user})
+    else
+      error when is_nil(error) or error == false ->
+        render_error(conn, :not_found, "Record not found")
+    end
+  end
+
+  @doc "POST /api/v1/polls/:id/votes"
+  def vote(%{assigns: %{user: user}} = conn, %{"id" => id, "choices" => choices}) do
+    with %Object{data: %{"type" => "Question"}} = object <- Object.get_by_id(id),
+         %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
+         true <- Visibility.visible_for_user?(activity, user),
+         {:ok, _activities, object} <- get_cached_vote_or_vote(user, object, choices) do
+      try_render(conn, "show.json", %{object: object, for: user})
+    else
+      nil -> render_error(conn, :not_found, "Record not found")
+      false -> render_error(conn, :not_found, "Record not found")
+      {:error, message} -> json_response(conn, :unprocessable_entity, %{error: message})
+    end
+  end
+
+  defp get_cached_vote_or_vote(user, object, choices) do
+    idempotency_key = "polls:#{user.id}:#{object.data["id"]}"
+
+    Cachex.fetch!(:idempotency_cache, idempotency_key, fn ->
+      case CommonAPI.vote(user, object, choices) do
+        {:error, _message} = res -> {:ignore, res}
+        res -> {:commit, res}
+      end
+    end)
+  end
+end
index 3c6987a5ff6a7a0b1233cc28c2ecd515b6899bc4..fb6fd76768c379294081bc85fa7de9d3e40ab449 100644 (file)
@@ -5,7 +5,7 @@
 defmodule Pleroma.Web.MastodonAPI.StatusController do
   use Pleroma.Web, :controller
 
-  import Pleroma.Web.MastodonAPI.MastodonAPIController, only: [try_render: 3]
+  import Pleroma.Web.ControllerHelper, only: [try_render: 3]
 
   require Ecto.Query
 
diff --git a/lib/pleroma/web/mastodon_api/views/poll_view.ex b/lib/pleroma/web/mastodon_api/views/poll_view.ex
new file mode 100644 (file)
index 0000000..753039d
--- /dev/null
@@ -0,0 +1,74 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.PollView do
+  use Pleroma.Web, :view
+
+  alias Pleroma.HTML
+  alias Pleroma.Web.CommonAPI.Utils
+
+  def render("show.json", %{object: object, multiple: multiple, options: options} = params) do
+    {end_time, expired} = end_time_and_expired(object)
+    {options, votes_count} = options_and_votes_count(options)
+
+    %{
+      # 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),
+      expires_at: end_time,
+      expired: expired,
+      multiple: multiple,
+      votes_count: votes_count,
+      options: options,
+      voted: voted?(params),
+      emojis: Pleroma.Web.MastodonAPI.StatusView.build_emojis(object.data["emoji"])
+    }
+  end
+
+  def render("show.json", %{object: object} = params) do
+    case object.data do
+      %{"anyOf" => options} when is_list(options) ->
+        render(__MODULE__, "show.json", Map.merge(params, %{multiple: true, options: options}))
+
+      %{"oneOf" => options} when is_list(options) ->
+        render(__MODULE__, "show.json", Map.merge(params, %{multiple: false, options: options}))
+
+      _ ->
+        nil
+    end
+  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
+
+        {Utils.to_masto_date(end_time), expired}
+
+      _ ->
+        {nil, false}
+    end
+  end
+
+  defp options_and_votes_count(options) do
+    Enum.map_reduce(options, 0, fn %{"name" => name} = option, count ->
+      current_count = option["replies"]["totalItems"] || 0
+
+      {%{
+         title: HTML.strip_tags(name),
+         votes_count: current_count
+       }, current_count + count}
+    end)
+  end
+
+  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"]
+    else
+      false
+    end
+  end
+end
index bc527ad1bcaddf5cad03bc8b8f49ac46d3ccfa0f..3262427eca9df144419a0f00baeda764cfb16fe6 100644 (file)
@@ -18,6 +18,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   alias Pleroma.Web.CommonAPI
   alias Pleroma.Web.CommonAPI.Utils
   alias Pleroma.Web.MastodonAPI.AccountView
+  alias Pleroma.Web.MastodonAPI.PollView
   alias Pleroma.Web.MastodonAPI.StatusView
   alias Pleroma.Web.MediaProxy
 
@@ -277,7 +278,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
       spoiler_text: summary_html,
       visibility: get_visibility(object),
       media_attachments: attachments,
-      poll: render("poll.json", %{object: object, for: opts[:for]}),
+      poll: render(PollView, "show.json", object: object, for: opts[:for]),
       mentions: mentions,
       tags: build_tags(tags),
       application: %{
@@ -389,75 +390,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     safe_render_many(opts.activities, StatusView, "listen.json", opts)
   end
 
-  def render("poll.json", %{object: object} = opts) do
-    {multiple, options} =
-      case object.data do
-        %{"anyOf" => options} when is_list(options) -> {true, options}
-        %{"oneOf" => options} when is_list(options) -> {false, options}
-        _ -> {nil, nil}
-      end
-
-    if options do
-      {end_time, expired} =
-        case object.data["closed"] || object.data["endTime"] do
-          end_time when is_binary(end_time) ->
-            end_time =
-              (object.data["closed"] || object.data["endTime"])
-              |> NaiveDateTime.from_iso8601!()
-
-            expired =
-              end_time
-              |> NaiveDateTime.compare(NaiveDateTime.utc_now())
-              |> case do
-                :lt -> true
-                _ -> false
-              end
-
-            end_time = Utils.to_masto_date(end_time)
-
-            {end_time, expired}
-
-          _ ->
-            {nil, false}
-        end
-
-      voted =
-        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"]
-        else
-          false
-        end
-
-      {options, votes_count} =
-        Enum.map_reduce(options, 0, fn %{"name" => name} = option, count ->
-          current_count = option["replies"]["totalItems"] || 0
-
-          {%{
-             title: HTML.strip_tags(name),
-             votes_count: current_count
-           }, current_count + count}
-        end)
-
-      %{
-        # 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),
-        expires_at: end_time,
-        expired: expired,
-        multiple: multiple,
-        votes_count: votes_count,
-        options: options,
-        voted: voted,
-        emojis: build_emojis(object.data["emoji"])
-      }
-    else
-      nil
-    end
-  end
-
   def render("context.json", %{activity: activity, activities: activities, user: user}) do
     %{ancestors: ancestors, descendants: descendants} =
       activities
index eab55a27c09d06b2c5c2def59640773573bf84d6..7af44c6be879eb5999014e8336a72512c1eb013c 100644 (file)
@@ -403,7 +403,7 @@ defmodule Pleroma.Web.Router do
       put("/scheduled_statuses/:id", ScheduledActivityController, :update)
       delete("/scheduled_statuses/:id", ScheduledActivityController, :delete)
 
-      post("/polls/:id/votes", MastodonAPIController, :poll_vote)
+      post("/polls/:id/votes", PollController, :vote)
 
       post("/media", MastodonAPIController, :upload)
       put("/media/:id", MastodonAPIController, :update_media)
@@ -488,7 +488,7 @@ defmodule Pleroma.Web.Router do
       get("/statuses/:id", StatusController, :show)
       get("/statuses/:id/context", StatusController, :context)
 
-      get("/polls/:id", MastodonAPIController, :get_poll)
+      get("/polls/:id", PollController, :show)
 
       get("/accounts/:id/statuses", AccountController, :statuses)
       get("/accounts/:id/followers", AccountController, :followers)
diff --git a/test/web/mastodon_api/controllers/poll_controller_test.exs b/test/web/mastodon_api/controllers/poll_controller_test.exs
new file mode 100644 (file)
index 0000000..40cf3e8
--- /dev/null
@@ -0,0 +1,184 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
+  use Pleroma.Web.ConnCase
+
+  alias Pleroma.Object
+  alias Pleroma.Web.CommonAPI
+
+  import Pleroma.Factory
+
+  describe "GET /api/v1/polls/:id" do
+    test "returns poll entity for object id", %{conn: conn} do
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "Pleroma does",
+          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
+        })
+
+      object = Object.normalize(activity)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> get("/api/v1/polls/#{object.id}")
+
+      response = json_response(conn, 200)
+      id = to_string(object.id)
+      assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
+    end
+
+    test "does not expose polls for private statuses", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "Pleroma does",
+          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
+          "visibility" => "private"
+        })
+
+      object = Object.normalize(activity)
+
+      conn =
+        conn
+        |> assign(:user, other_user)
+        |> get("/api/v1/polls/#{object.id}")
+
+      assert json_response(conn, 404)
+    end
+  end
+
+  describe "POST /api/v1/polls/:id/votes" do
+    test "votes are added to the poll", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "A very delicious sandwich",
+          "poll" => %{
+            "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
+            "expires_in" => 20,
+            "multiple" => true
+          }
+        })
+
+      object = Object.normalize(activity)
+
+      conn =
+        conn
+        |> assign(:user, other_user)
+        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
+
+      assert json_response(conn, 200)
+      object = Object.get_by_id(object.id)
+
+      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
+               total_items == 1
+             end)
+    end
+
+    test "author can't vote", %{conn: conn} do
+      user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "Am I cute?",
+          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
+        })
+
+      object = Object.normalize(activity)
+
+      assert conn
+             |> assign(:user, user)
+             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
+             |> json_response(422) == %{"error" => "Poll's author can't vote"}
+
+      object = Object.get_by_id(object.id)
+
+      refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
+    end
+
+    test "does not allow multiple choices on a single-choice question", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "The glass is",
+          "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
+        })
+
+      object = Object.normalize(activity)
+
+      assert conn
+             |> assign(:user, other_user)
+             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
+             |> json_response(422) == %{"error" => "Too many choices"}
+
+      object = Object.get_by_id(object.id)
+
+      refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
+               total_items == 1
+             end)
+    end
+
+    test "does not allow choice index to be greater than options count", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "Am I cute?",
+          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
+        })
+
+      object = Object.normalize(activity)
+
+      conn =
+        conn
+        |> assign(:user, other_user)
+        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
+
+      assert json_response(conn, 422) == %{"error" => "Invalid indices"}
+    end
+
+    test "returns 404 error when object is not exist", %{conn: conn} do
+      user = insert(:user)
+
+      conn =
+        conn
+        |> assign(:user, user)
+        |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
+
+      assert json_response(conn, 404) == %{"error" => "Record not found"}
+    end
+
+    test "returns 404 when poll is private and not available for user", %{conn: conn} do
+      user = insert(:user)
+      other_user = insert(:user)
+
+      {:ok, activity} =
+        CommonAPI.post(user, %{
+          "status" => "Am I cute?",
+          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
+          "visibility" => "private"
+        })
+
+      object = Object.normalize(activity)
+
+      conn =
+        conn
+        |> assign(:user, other_user)
+        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
+
+      assert json_response(conn, 404) == %{"error" => "Record not found"}
+    end
+  end
+end
index feeaf079bb09be9a1ff27b824b435e2aff02198f..2ec46bc90bdb8fd25126279b718e3aae92c26b99 100644 (file)
@@ -417,178 +417,6 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
     end
   end
 
-  describe "GET /api/v1/polls/:id" do
-    test "returns poll entity for object id", %{conn: conn} do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Pleroma does",
-          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20}
-        })
-
-      object = Object.normalize(activity)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> get("/api/v1/polls/#{object.id}")
-
-      response = json_response(conn, 200)
-      id = to_string(object.id)
-      assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
-    end
-
-    test "does not expose polls for private statuses", %{conn: conn} do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Pleroma does",
-          "poll" => %{"options" => ["what Mastodon't", "n't what Mastodoes"], "expires_in" => 20},
-          "visibility" => "private"
-        })
-
-      object = Object.normalize(activity)
-
-      conn =
-        conn
-        |> assign(:user, other_user)
-        |> get("/api/v1/polls/#{object.id}")
-
-      assert json_response(conn, 404)
-    end
-  end
-
-  describe "POST /api/v1/polls/:id/votes" do
-    test "votes are added to the poll", %{conn: conn} do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "A very delicious sandwich",
-          "poll" => %{
-            "options" => ["Lettuce", "Grilled Bacon", "Tomato"],
-            "expires_in" => 20,
-            "multiple" => true
-          }
-        })
-
-      object = Object.normalize(activity)
-
-      conn =
-        conn
-        |> assign(:user, other_user)
-        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
-
-      assert json_response(conn, 200)
-      object = Object.get_by_id(object.id)
-
-      assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
-               total_items == 1
-             end)
-    end
-
-    test "author can't vote", %{conn: conn} do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Am I cute?",
-          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
-        })
-
-      object = Object.normalize(activity)
-
-      assert conn
-             |> assign(:user, user)
-             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
-             |> json_response(422) == %{"error" => "Poll's author can't vote"}
-
-      object = Object.get_by_id(object.id)
-
-      refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
-    end
-
-    test "does not allow multiple choices on a single-choice question", %{conn: conn} do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "The glass is",
-          "poll" => %{"options" => ["half empty", "half full"], "expires_in" => 20}
-        })
-
-      object = Object.normalize(activity)
-
-      assert conn
-             |> assign(:user, other_user)
-             |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
-             |> json_response(422) == %{"error" => "Too many choices"}
-
-      object = Object.get_by_id(object.id)
-
-      refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
-               total_items == 1
-             end)
-    end
-
-    test "does not allow choice index to be greater than options count", %{conn: conn} do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Am I cute?",
-          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20}
-        })
-
-      object = Object.normalize(activity)
-
-      conn =
-        conn
-        |> assign(:user, other_user)
-        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
-
-      assert json_response(conn, 422) == %{"error" => "Invalid indices"}
-    end
-
-    test "returns 404 error when object is not exist", %{conn: conn} do
-      user = insert(:user)
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
-
-      assert json_response(conn, 404) == %{"error" => "Record not found"}
-    end
-
-    test "returns 404 when poll is private and not available for user", %{conn: conn} do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Am I cute?",
-          "poll" => %{"options" => ["Yes", "No"], "expires_in" => 20},
-          "visibility" => "private"
-        })
-
-      object = Object.normalize(activity)
-
-      conn =
-        conn
-        |> assign(:user, other_user)
-        |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
-
-      assert json_response(conn, 404) == %{"error" => "Record not found"}
-    end
-  end
-
   describe "POST /auth/password, with valid parameters" do
     setup %{conn: conn} do
       user = insert(:user)
diff --git a/test/web/mastodon_api/views/poll_view_test.exs b/test/web/mastodon_api/views/poll_view_test.exs
new file mode 100644 (file)
index 0000000..8cd7636
--- /dev/null
@@ -0,0 +1,126 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.MastodonAPI.PollViewTest do
+  use Pleroma.DataCase
+
+  alias Pleroma.Object
+  alias Pleroma.Web.CommonAPI
+  alias Pleroma.Web.MastodonAPI.PollView
+
+  import Pleroma.Factory
+  import Tesla.Mock
+
+  setup do
+    mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
+    :ok
+  end
+
+  test "renders a poll" do
+    user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "Is Tenshi eating a corndog cute?",
+        "poll" => %{
+          "options" => ["absolutely!", "sure", "yes", "why are you even asking?"],
+          "expires_in" => 20
+        }
+      })
+
+    object = Object.normalize(activity)
+
+    expected = %{
+      emojis: [],
+      expired: false,
+      id: to_string(object.id),
+      multiple: false,
+      options: [
+        %{title: "absolutely!", votes_count: 0},
+        %{title: "sure", votes_count: 0},
+        %{title: "yes", votes_count: 0},
+        %{title: "why are you even asking?", votes_count: 0}
+      ],
+      voted: false,
+      votes_count: 0
+    }
+
+    result = PollView.render("show.json", %{object: object})
+    expires_at = result.expires_at
+    result = Map.delete(result, :expires_at)
+
+    assert result == expected
+
+    expires_at = NaiveDateTime.from_iso8601!(expires_at)
+    assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20
+  end
+
+  test "detects if it is multiple choice" do
+    user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "Which Mastodon developer is your favourite?",
+        "poll" => %{
+          "options" => ["Gargron", "Eugen"],
+          "expires_in" => 20,
+          "multiple" => true
+        }
+      })
+
+    object = Object.normalize(activity)
+
+    assert %{multiple: true} = PollView.render("show.json", %{object: object})
+  end
+
+  test "detects emoji" do
+    user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "What's with the smug face?",
+        "poll" => %{
+          "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"],
+          "expires_in" => 20
+        }
+      })
+
+    object = Object.normalize(activity)
+
+    assert %{emojis: [%{shortcode: "blank"}]} = PollView.render("show.json", %{object: object})
+  end
+
+  test "detects vote status" do
+    user = insert(:user)
+    other_user = insert(:user)
+
+    {:ok, activity} =
+      CommonAPI.post(user, %{
+        "status" => "Which input devices do you use?",
+        "poll" => %{
+          "options" => ["mouse", "trackball", "trackpoint"],
+          "multiple" => true,
+          "expires_in" => 20
+        }
+      })
+
+    object = Object.normalize(activity)
+
+    {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2])
+
+    result = PollView.render("show.json", %{object: object, for: other_user})
+
+    assert result[:voted] == true
+    assert Enum.at(result[:options], 1)[:votes_count] == 1
+    assert Enum.at(result[:options], 2)[:votes_count] == 1
+  end
+
+  test "does not crash on polls with no end date" do
+    object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i")
+    result = PollView.render("show.json", %{object: object})
+
+    assert result[:expires_at] == nil
+    assert result[:expired] == false
+  end
+end
index 8df23d0a88bbd24a981b1edb9d77a3854fec859f..1d5a6e956db95d7be1edbc792c032f2e59145d92 100644 (file)
@@ -451,116 +451,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
     end
   end
 
-  describe "poll view" do
-    test "renders a poll" do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Is Tenshi eating a corndog cute?",
-          "poll" => %{
-            "options" => ["absolutely!", "sure", "yes", "why are you even asking?"],
-            "expires_in" => 20
-          }
-        })
-
-      object = Object.normalize(activity)
-
-      expected = %{
-        emojis: [],
-        expired: false,
-        id: to_string(object.id),
-        multiple: false,
-        options: [
-          %{title: "absolutely!", votes_count: 0},
-          %{title: "sure", votes_count: 0},
-          %{title: "yes", votes_count: 0},
-          %{title: "why are you even asking?", votes_count: 0}
-        ],
-        voted: false,
-        votes_count: 0
-      }
-
-      result = StatusView.render("poll.json", %{object: object})
-      expires_at = result.expires_at
-      result = Map.delete(result, :expires_at)
-
-      assert result == expected
-
-      expires_at = NaiveDateTime.from_iso8601!(expires_at)
-      assert NaiveDateTime.diff(expires_at, NaiveDateTime.utc_now()) in 15..20
-    end
-
-    test "detects if it is multiple choice" do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Which Mastodon developer is your favourite?",
-          "poll" => %{
-            "options" => ["Gargron", "Eugen"],
-            "expires_in" => 20,
-            "multiple" => true
-          }
-        })
-
-      object = Object.normalize(activity)
-
-      assert %{multiple: true} = StatusView.render("poll.json", %{object: object})
-    end
-
-    test "detects emoji" do
-      user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "What's with the smug face?",
-          "poll" => %{
-            "options" => [":blank: sip", ":blank::blank: sip", ":blank::blank::blank: sip"],
-            "expires_in" => 20
-          }
-        })
-
-      object = Object.normalize(activity)
-
-      assert %{emojis: [%{shortcode: "blank"}]} =
-               StatusView.render("poll.json", %{object: object})
-    end
-
-    test "detects vote status" do
-      user = insert(:user)
-      other_user = insert(:user)
-
-      {:ok, activity} =
-        CommonAPI.post(user, %{
-          "status" => "Which input devices do you use?",
-          "poll" => %{
-            "options" => ["mouse", "trackball", "trackpoint"],
-            "multiple" => true,
-            "expires_in" => 20
-          }
-        })
-
-      object = Object.normalize(activity)
-
-      {:ok, _, object} = CommonAPI.vote(other_user, object, [1, 2])
-
-      result = StatusView.render("poll.json", %{object: object, for: other_user})
-
-      assert result[:voted] == true
-      assert Enum.at(result[:options], 1)[:votes_count] == 1
-      assert Enum.at(result[:options], 2)[:votes_count] == 1
-    end
-
-    test "does not crash on polls with no end date" do
-      object = Object.normalize("https://skippers-bin.com/notes/7x9tmrp97i")
-      result = StatusView.render("poll.json", %{object: object})
-
-      assert result[:expires_at] == nil
-      assert result[:expired] == false
-    end
-  end
-
   test "embeds a relationship in the account" do
     user = insert(:user)
     other_user = insert(:user)