total rebase
[anni] / test / pleroma / web / admin_api / controllers / report_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
6   use Pleroma.Web.ConnCase, async: false
7
8   import Pleroma.Factory
9
10   alias Pleroma.Activity
11   alias Pleroma.ModerationLog
12   alias Pleroma.Repo
13   alias Pleroma.ReportNote
14   alias Pleroma.Web.CommonAPI
15
16   setup do
17     admin = insert(:user, is_admin: true)
18     token = insert(:oauth_admin_token, user: admin)
19
20     conn =
21       build_conn()
22       |> assign(:user, admin)
23       |> assign(:token, token)
24
25     {:ok, %{admin: admin, token: token, conn: conn}}
26   end
27
28   describe "GET /api/pleroma/admin/reports/:id" do
29     setup do
30       clear_config([:instance, :admin_privileges], [:reports_manage_reports])
31     end
32
33     test "returns 403 if not privileged with :reports_manage_reports", %{conn: conn} do
34       clear_config([:instance, :admin_privileges], [])
35
36       conn =
37         conn
38         |> get("/api/pleroma/admin/reports/report_id")
39
40       assert json_response(conn, :forbidden)
41     end
42
43     test "returns report by its id", %{conn: conn} do
44       [reporter, target_user] = insert_pair(:user)
45       activity = insert(:note_activity, user: target_user)
46
47       {:ok, %{id: report_id}} =
48         CommonAPI.report(reporter, %{
49           account_id: target_user.id,
50           comment: "I feel offended",
51           status_ids: [activity.id]
52         })
53
54       conn
55       |> put_req_header("content-type", "application/json")
56       |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
57         content: "this is an admin note"
58       })
59
60       response =
61         conn
62         |> get("/api/pleroma/admin/reports/#{report_id}")
63         |> json_response_and_validate_schema(:ok)
64
65       assert response["id"] == report_id
66
67       [notes] = response["notes"]
68       assert notes["content"] == "this is an admin note"
69     end
70
71     test "renders reported content even if the status is deleted", %{conn: conn} do
72       [reporter, target_user] = insert_pair(:user)
73       activity = insert(:note_activity, user: target_user)
74       activity = Activity.normalize(activity)
75
76       {:ok, %{id: report_id}} =
77         CommonAPI.report(reporter, %{
78           account_id: target_user.id,
79           comment: "I feel offended",
80           status_ids: [activity.id]
81         })
82
83       CommonAPI.delete(activity.id, target_user)
84
85       response =
86         conn
87         |> get("/api/pleroma/admin/reports/#{report_id}")
88         |> json_response_and_validate_schema(:ok)
89
90       assert response["id"] == report_id
91
92       assert [status] = response["statuses"]
93       assert activity.object.data["id"] == status["uri"]
94       assert activity.object.data["content"] == status["content"]
95     end
96
97     test "returns 404 when report id is invalid", %{conn: conn} do
98       conn = get(conn, "/api/pleroma/admin/reports/test")
99
100       assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"}
101     end
102   end
103
104   describe "PATCH /api/pleroma/admin/reports" do
105     setup do
106       clear_config([:instance, :admin_privileges], [:reports_manage_reports])
107
108       [reporter, target_user] = insert_pair(:user)
109       activity = insert(:note_activity, user: target_user)
110
111       {:ok, %{id: report_id}} =
112         CommonAPI.report(reporter, %{
113           account_id: target_user.id,
114           comment: "I feel offended",
115           status_ids: [activity.id]
116         })
117
118       {:ok, %{id: second_report_id}} =
119         CommonAPI.report(reporter, %{
120           account_id: target_user.id,
121           comment: "I feel very offended",
122           status_ids: [activity.id]
123         })
124
125       %{
126         reporter: reporter,
127         id: report_id,
128         second_report_id: second_report_id
129       }
130     end
131
132     test "returns 403 if not privileged with :reports_manage_reports", %{
133       conn: conn,
134       id: id,
135       admin: admin
136     } do
137       clear_config([:instance, :admin_privileges], [])
138
139       conn =
140         conn
141         |> assign(:token, insert(:oauth_token, user: admin, scopes: ["admin:write:reports"]))
142         |> put_req_header("content-type", "application/json")
143         |> patch("/api/pleroma/admin/reports", %{
144           "reports" => [%{"state" => "resolved", "id" => id}]
145         })
146
147       assert json_response(conn, :forbidden)
148     end
149
150     test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
151       read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
152       write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
153
154       response =
155         conn
156         |> assign(:token, read_token)
157         |> put_req_header("content-type", "application/json")
158         |> patch("/api/pleroma/admin/reports", %{
159           "reports" => [%{"state" => "resolved", "id" => id}]
160         })
161         |> json_response_and_validate_schema(403)
162
163       assert response == %{
164                "error" => "Insufficient permissions: admin:write:reports."
165              }
166
167       conn
168       |> assign(:token, write_token)
169       |> put_req_header("content-type", "application/json")
170       |> patch("/api/pleroma/admin/reports", %{
171         "reports" => [%{"state" => "resolved", "id" => id}]
172       })
173       |> json_response_and_validate_schema(:no_content)
174     end
175
176     test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
177       conn
178       |> put_req_header("content-type", "application/json")
179       |> patch("/api/pleroma/admin/reports", %{
180         "reports" => [
181           %{"state" => "resolved", "id" => id}
182         ]
183       })
184       |> json_response_and_validate_schema(:no_content)
185
186       activity = Activity.get_by_id_with_user_actor(id)
187       assert activity.data["state"] == "resolved"
188
189       log_entry = Repo.one(ModerationLog)
190
191       assert ModerationLog.get_log_entry_message(log_entry) ==
192                "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
193     end
194
195     test "closes report", %{conn: conn, id: id, admin: admin} do
196       conn
197       |> put_req_header("content-type", "application/json")
198       |> patch("/api/pleroma/admin/reports", %{
199         "reports" => [
200           %{"state" => "closed", "id" => id}
201         ]
202       })
203       |> json_response_and_validate_schema(:no_content)
204
205       activity = Activity.get_by_id_with_user_actor(id)
206       assert activity.data["state"] == "closed"
207
208       log_entry = Repo.one(ModerationLog)
209
210       assert ModerationLog.get_log_entry_message(log_entry) ==
211                "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'closed' state"
212     end
213
214     test "returns 400 when state is unknown", %{conn: conn, id: id} do
215       conn =
216         conn
217         |> put_req_header("content-type", "application/json")
218         |> patch("/api/pleroma/admin/reports", %{
219           "reports" => [
220             %{"state" => "test", "id" => id}
221           ]
222         })
223
224       assert "Unsupported state" =
225                hd(json_response_and_validate_schema(conn, :bad_request))["error"]
226     end
227
228     test "returns 404 when report is not exist", %{conn: conn} do
229       conn =
230         conn
231         |> put_req_header("content-type", "application/json")
232         |> patch("/api/pleroma/admin/reports", %{
233           "reports" => [
234             %{"state" => "closed", "id" => "test"}
235           ]
236         })
237
238       assert hd(json_response_and_validate_schema(conn, :bad_request))["error"] == "not_found"
239     end
240
241     test "updates state of multiple reports", %{
242       conn: conn,
243       id: id,
244       admin: admin,
245       second_report_id: second_report_id
246     } do
247       conn
248       |> put_req_header("content-type", "application/json")
249       |> patch("/api/pleroma/admin/reports", %{
250         "reports" => [
251           %{"state" => "resolved", "id" => id},
252           %{"state" => "closed", "id" => second_report_id}
253         ]
254       })
255       |> json_response_and_validate_schema(:no_content)
256
257       activity = Activity.get_by_id_with_user_actor(id)
258       second_activity = Activity.get_by_id_with_user_actor(second_report_id)
259       assert activity.data["state"] == "resolved"
260       assert second_activity.data["state"] == "closed"
261
262       [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
263
264       assert ModerationLog.get_log_entry_message(first_log_entry) ==
265                "@#{admin.nickname} updated report ##{id} (on user @#{activity.user_actor.nickname}) with 'resolved' state"
266
267       assert ModerationLog.get_log_entry_message(second_log_entry) ==
268                "@#{admin.nickname} updated report ##{second_report_id} (on user @#{second_activity.user_actor.nickname}) with 'closed' state"
269     end
270
271     test "works if reporter is deactivated", %{
272       conn: conn,
273       id: id,
274       reporter: reporter
275     } do
276       Pleroma.User.set_activation(reporter, false)
277
278       conn
279       |> put_req_header("content-type", "application/json")
280       |> patch("/api/pleroma/admin/reports", %{
281         "reports" => [
282           %{"state" => "resolved", "id" => id}
283         ]
284       })
285       |> json_response_and_validate_schema(:no_content)
286
287       activity = Activity.get_by_id_with_user_actor(id)
288       assert activity.data["state"] == "resolved"
289     end
290   end
291
292   describe "GET /api/pleroma/admin/reports" do
293     setup do
294       clear_config([:instance, :admin_privileges], [:reports_manage_reports])
295     end
296
297     test "returns 403 if not privileged with :reports_manage_reports", %{conn: conn} do
298       clear_config([:instance, :admin_privileges], [])
299
300       conn =
301         conn
302         |> get(report_path(conn, :index))
303
304       assert json_response(conn, :forbidden)
305     end
306
307     test "returns empty response when no reports created", %{conn: conn} do
308       response =
309         conn
310         |> get(report_path(conn, :index))
311         |> json_response_and_validate_schema(:ok)
312
313       assert Enum.empty?(response["reports"])
314       assert response["total"] == 0
315     end
316
317     test "returns reports", %{conn: conn} do
318       [reporter, target_user] = insert_pair(:user)
319       activity = insert(:note_activity, user: target_user)
320
321       {:ok, %{id: report_id}} =
322         CommonAPI.report(reporter, %{
323           account_id: target_user.id,
324           comment: "I feel offended",
325           status_ids: [activity.id]
326         })
327
328       response =
329         conn
330         |> get(report_path(conn, :index))
331         |> json_response_and_validate_schema(:ok)
332
333       [report] = response["reports"]
334
335       assert length(response["reports"]) == 1
336       assert report["id"] == report_id
337
338       assert response["total"] == 1
339     end
340
341     test "returns reports with specified state", %{conn: conn} do
342       [reporter, target_user] = insert_pair(:user)
343       activity = insert(:note_activity, user: target_user)
344
345       {:ok, %{id: first_report_id}} =
346         CommonAPI.report(reporter, %{
347           account_id: target_user.id,
348           comment: "I feel offended",
349           status_ids: [activity.id]
350         })
351
352       {:ok, %{id: second_report_id}} =
353         CommonAPI.report(reporter, %{
354           account_id: target_user.id,
355           comment: "I don't like this user"
356         })
357
358       CommonAPI.update_report_state(second_report_id, "closed")
359
360       response =
361         conn
362         |> get(report_path(conn, :index, %{state: "open"}))
363         |> json_response_and_validate_schema(:ok)
364
365       assert [open_report] = response["reports"]
366
367       assert length(response["reports"]) == 1
368       assert open_report["id"] == first_report_id
369
370       assert response["total"] == 1
371
372       response =
373         conn
374         |> get(report_path(conn, :index, %{state: "closed"}))
375         |> json_response_and_validate_schema(:ok)
376
377       assert [closed_report] = response["reports"]
378
379       assert length(response["reports"]) == 1
380       assert closed_report["id"] == second_report_id
381
382       assert response["total"] == 1
383
384       assert %{"total" => 0, "reports" => []} ==
385                conn
386                |> get(report_path(conn, :index, %{state: "resolved"}))
387                |> json_response_and_validate_schema(:ok)
388     end
389
390     test "renders content correctly", %{conn: conn} do
391       [reporter, target_user] = insert_pair(:user)
392       note = insert(:note, user: target_user, data: %{"content" => "mew 1"})
393       note2 = insert(:note, user: target_user, data: %{"content" => "mew 2"})
394       activity = insert(:note_activity, user: target_user, note: note)
395       activity2 = insert(:note_activity, user: target_user, note: note2)
396
397       {:ok, _report} =
398         CommonAPI.report(reporter, %{
399           account_id: target_user.id,
400           comment: "I feel offended",
401           status_ids: [activity.id, activity2.id]
402         })
403
404       CommonAPI.delete(activity.id, target_user)
405       CommonAPI.delete(activity2.id, target_user)
406
407       response =
408         conn
409         |> get(report_path(conn, :index))
410         |> json_response_and_validate_schema(:ok)
411
412       assert [open_report] = response["reports"]
413       assert %{"statuses" => [s1, s2]} = open_report
414       assert "mew 1" in [s1["content"], s2["content"]]
415       assert "mew 2" in [s1["content"], s2["content"]]
416     end
417
418     test "returns 403 when requested by a non-admin" do
419       user = insert(:user)
420       token = insert(:oauth_token, user: user)
421
422       conn =
423         build_conn()
424         |> assign(:user, user)
425         |> assign(:token, token)
426         |> get("/api/pleroma/admin/reports")
427
428       assert json_response(conn, :forbidden) ==
429                %{"error" => "User is not a staff member."}
430     end
431
432     test "returns 403 when requested by anonymous" do
433       conn = get(build_conn(), "/api/pleroma/admin/reports")
434
435       assert json_response(conn, :forbidden) == %{
436                "error" => "Invalid credentials."
437              }
438     end
439   end
440
441   describe "POST /api/pleroma/admin/reports/:id/notes" do
442     setup %{conn: conn, admin: admin} do
443       clear_config([:instance, :admin_privileges], [:reports_manage_reports])
444
445       [reporter, target_user] = insert_pair(:user)
446       activity = insert(:note_activity, user: target_user)
447
448       {:ok, %{id: report_id}} =
449         CommonAPI.report(reporter, %{
450           account_id: target_user.id,
451           comment: "I feel offended",
452           status_ids: [activity.id]
453         })
454
455       conn
456       |> put_req_header("content-type", "application/json")
457       |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
458         content: "this is disgusting!"
459       })
460
461       conn
462       |> put_req_header("content-type", "application/json")
463       |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
464         content: "this is disgusting2!"
465       })
466
467       %{
468         admin_id: admin.id,
469         report_id: report_id
470       }
471     end
472
473     test "returns 403 if not privileged with :reports_manage_reports", %{
474       conn: conn,
475       report_id: report_id
476     } do
477       clear_config([:instance, :admin_privileges], [])
478
479       post_conn =
480         conn
481         |> put_req_header("content-type", "application/json")
482         |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{
483           content: "this is disgusting2!"
484         })
485
486       delete_conn = delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/note.id")
487
488       assert json_response(post_conn, :forbidden)
489       assert json_response(delete_conn, :forbidden)
490     end
491
492     test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
493       assert [note, _] = Repo.all(ReportNote)
494
495       assert %{
496                activity_id: ^report_id,
497                content: "this is disgusting!",
498                user_id: ^admin_id
499              } = note
500     end
501
502     test "it returns reports with notes", %{conn: conn, admin: admin} do
503       conn = get(conn, "/api/pleroma/admin/reports")
504
505       response = json_response_and_validate_schema(conn, 200)
506       notes = hd(response["reports"])["notes"]
507       [note, _] = notes
508
509       assert note["user"]["nickname"] == admin.nickname
510       # We use '=~' because the order of the notes isn't guaranteed
511       assert note["content"] =~ "this is disgusting"
512       assert note["created_at"]
513       assert response["total"] == 1
514     end
515
516     test "it deletes the note", %{conn: conn, report_id: report_id} do
517       assert ReportNote |> Repo.all() |> length() == 2
518       assert [note, _] = Repo.all(ReportNote)
519
520       delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
521
522       assert ReportNote |> Repo.all() |> length() == 1
523     end
524   end
525 end