Add timeline visibility options
[akkoma] / test / pleroma / web / mastodon_api / controllers / poll_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.PollControllerTest do
6 use Pleroma.Web.ConnCase, async: true
7
8 alias Pleroma.Object
9 alias Pleroma.Web.CommonAPI
10
11 import Pleroma.Factory
12
13 describe "GET /api/v1/polls/:id" do
14 setup do: oauth_access(["read:statuses"])
15
16 test "returns poll entity for object id", %{user: user, conn: conn} do
17 {:ok, activity} =
18 CommonAPI.post(user, %{
19 status: "Pleroma does",
20 poll: %{options: ["what Mastodon't", "n't what Mastodoes"], expires_in: 20}
21 })
22
23 object = Object.normalize(activity, fetch: false)
24
25 conn = get(conn, "/api/v1/polls/#{object.id}")
26
27 response = json_response_and_validate_schema(conn, 200)
28 id = to_string(object.id)
29 assert %{"id" => ^id, "expired" => false, "multiple" => false} = response
30 end
31
32 test "does not expose polls for private statuses", %{conn: conn} do
33 other_user = insert(:user)
34
35 {:ok, activity} =
36 CommonAPI.post(other_user, %{
37 status: "Pleroma does",
38 poll: %{options: ["what Mastodon't", "n't what Mastodoes"], expires_in: 20},
39 visibility: "private"
40 })
41
42 object = Object.normalize(activity, fetch: false)
43
44 conn = get(conn, "/api/v1/polls/#{object.id}")
45
46 assert json_response_and_validate_schema(conn, 404)
47 end
48 end
49
50 test "own_votes" do
51 %{conn: conn} = oauth_access(["write:statuses", "read:statuses"])
52
53 other_user = insert(:user)
54
55 {:ok, activity} =
56 CommonAPI.post(other_user, %{
57 status: "A very delicious sandwich",
58 poll: %{
59 options: ["Lettuce", "Grilled Bacon", "Tomato"],
60 expires_in: 20,
61 multiple: true
62 }
63 })
64
65 object = Object.normalize(activity, fetch: false)
66
67 conn
68 |> put_req_header("content-type", "application/json")
69 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 2]})
70 |> json_response_and_validate_schema(200)
71
72 object = Object.get_by_id(object.id)
73
74 assert [
75 %{
76 "name" => "Lettuce",
77 "replies" => %{"totalItems" => 1, "type" => "Collection"},
78 "type" => "Note"
79 },
80 %{
81 "name" => "Grilled Bacon",
82 "replies" => %{"totalItems" => 0, "type" => "Collection"},
83 "type" => "Note"
84 },
85 %{
86 "name" => "Tomato",
87 "replies" => %{"totalItems" => 1, "type" => "Collection"},
88 "type" => "Note"
89 }
90 ] == object.data["anyOf"]
91
92 assert %{"replies" => %{"totalItems" => 0}} =
93 Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == "Grilled Bacon" end)
94
95 Enum.each(["Lettuce", "Tomato"], fn title ->
96 %{"replies" => %{"totalItems" => total_items}} =
97 Enum.find(object.data["anyOf"], fn %{"name" => name} -> name == title end)
98
99 assert total_items == 1
100 end)
101
102 assert %{
103 "own_votes" => own_votes,
104 "voted" => true
105 } =
106 conn
107 |> get("/api/v1/polls/#{object.id}")
108 |> json_response_and_validate_schema(200)
109
110 assert 0 in own_votes
111 assert 2 in own_votes
112 # for non authenticated user
113 response =
114 build_conn()
115 |> get("/api/v1/polls/#{object.id}")
116 |> json_response_and_validate_schema(200)
117
118 refute Map.has_key?(response, "own_votes")
119 refute Map.has_key?(response, "voted")
120 end
121
122 describe "POST /api/v1/polls/:id/votes" do
123 setup do: oauth_access(["write:statuses"])
124
125 test "votes are added to the poll", %{conn: conn} do
126 other_user = insert(:user)
127
128 {:ok, activity} =
129 CommonAPI.post(other_user, %{
130 status: "A very delicious sandwich",
131 poll: %{
132 options: ["Lettuce", "Grilled Bacon", "Tomato"],
133 expires_in: 20,
134 multiple: true
135 }
136 })
137
138 object = Object.normalize(activity, fetch: false)
139
140 conn
141 |> put_req_header("content-type", "application/json")
142 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1, 2]})
143 |> json_response_and_validate_schema(200)
144
145 object = Object.get_by_id(object.id)
146
147 assert Enum.all?(object.data["anyOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
148 total_items == 1
149 end)
150 end
151
152 test "author can't vote", %{user: user, conn: conn} do
153 {:ok, activity} =
154 CommonAPI.post(user, %{
155 status: "Am I cute?",
156 poll: %{options: ["Yes", "No"], expires_in: 20}
157 })
158
159 object = Object.normalize(activity, fetch: false)
160
161 assert conn
162 |> put_req_header("content-type", "application/json")
163 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [1]})
164 |> json_response_and_validate_schema(422) == %{"error" => "Poll's author can't vote"}
165
166 object = Object.get_by_id(object.id)
167
168 refute Enum.at(object.data["oneOf"], 1)["replies"]["totalItems"] == 1
169 end
170
171 test "does not allow multiple choices on a single-choice question", %{conn: conn} do
172 other_user = insert(:user)
173
174 {:ok, activity} =
175 CommonAPI.post(other_user, %{
176 status: "The glass is",
177 poll: %{options: ["half empty", "half full"], expires_in: 20}
178 })
179
180 object = Object.normalize(activity, fetch: false)
181
182 assert conn
183 |> put_req_header("content-type", "application/json")
184 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0, 1]})
185 |> json_response_and_validate_schema(422) == %{"error" => "Too many choices"}
186
187 object = Object.get_by_id(object.id)
188
189 refute Enum.any?(object.data["oneOf"], fn %{"replies" => %{"totalItems" => total_items}} ->
190 total_items == 1
191 end)
192 end
193
194 test "does not allow choice index to be greater than options count", %{conn: conn} do
195 other_user = insert(:user)
196
197 {:ok, activity} =
198 CommonAPI.post(other_user, %{
199 status: "Am I cute?",
200 poll: %{options: ["Yes", "No"], expires_in: 20}
201 })
202
203 object = Object.normalize(activity, fetch: false)
204
205 conn =
206 conn
207 |> put_req_header("content-type", "application/json")
208 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [2]})
209
210 assert json_response_and_validate_schema(conn, 422) == %{"error" => "Invalid indices"}
211 end
212
213 test "returns 404 error when object is not exist", %{conn: conn} do
214 conn =
215 conn
216 |> put_req_header("content-type", "application/json")
217 |> post("/api/v1/polls/1/votes", %{"choices" => [0]})
218
219 assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
220 end
221
222 test "returns 404 when poll is private and not available for user", %{conn: conn} do
223 other_user = insert(:user)
224
225 {:ok, activity} =
226 CommonAPI.post(other_user, %{
227 status: "Am I cute?",
228 poll: %{options: ["Yes", "No"], expires_in: 20},
229 visibility: "private"
230 })
231
232 object = Object.normalize(activity, fetch: false)
233
234 conn =
235 conn
236 |> put_req_header("content-type", "application/json")
237 |> post("/api/v1/polls/#{object.id}/votes", %{"choices" => [0]})
238
239 assert json_response_and_validate_schema(conn, 404) == %{"error" => "Record not found"}
240 end
241 end
242 end