Merge branch '1521-admin-report-test-fix' into 'develop'
[akkoma] / test / web / admin_api / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 alias Pleroma.Activity
10 alias Pleroma.HTML
11 alias Pleroma.ModerationLog
12 alias Pleroma.Repo
13 alias Pleroma.ReportNote
14 alias Pleroma.Tests.ObanHelpers
15 alias Pleroma.User
16 alias Pleroma.UserInviteToken
17 alias Pleroma.Web.ActivityPub.Relay
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.MastodonAPI.StatusView
20 alias Pleroma.Web.MediaProxy
21 import Pleroma.Factory
22
23 setup_all do
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
25
26 :ok
27 end
28
29 setup do
30 admin = insert(:user, is_admin: true)
31 token = insert(:oauth_admin_token, user: admin)
32
33 conn =
34 build_conn()
35 |> assign(:user, admin)
36 |> assign(:token, token)
37
38 {:ok, %{admin: admin, token: token, conn: conn}}
39 end
40
41 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
42 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
43 Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
44 end
45
46 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
47 %{admin: admin} do
48 user = insert(:user)
49 url = "/api/pleroma/admin/users/#{user.nickname}"
50
51 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
52 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
53 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
54
55 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
56 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
57 bad_token3 = nil
58
59 for good_token <- [good_token1, good_token2, good_token3] do
60 conn =
61 build_conn()
62 |> assign(:user, admin)
63 |> assign(:token, good_token)
64 |> get(url)
65
66 assert json_response(conn, 200)
67 end
68
69 for good_token <- [good_token1, good_token2, good_token3] do
70 conn =
71 build_conn()
72 |> assign(:user, nil)
73 |> assign(:token, good_token)
74 |> get(url)
75
76 assert json_response(conn, :forbidden)
77 end
78
79 for bad_token <- [bad_token1, bad_token2, bad_token3] do
80 conn =
81 build_conn()
82 |> assign(:user, admin)
83 |> assign(:token, bad_token)
84 |> get(url)
85
86 assert json_response(conn, :forbidden)
87 end
88 end
89 end
90
91 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
92 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
93 Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
94 end
95
96 test "GET /api/pleroma/admin/users/:nickname requires " <>
97 "read:accounts or admin:read:accounts or broader scope",
98 %{admin: admin} do
99 user = insert(:user)
100 url = "/api/pleroma/admin/users/#{user.nickname}"
101
102 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
103 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
104 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
105 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
106 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
107
108 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
109
110 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
111 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
112 bad_token3 = nil
113
114 for good_token <- good_tokens do
115 conn =
116 build_conn()
117 |> assign(:user, admin)
118 |> assign(:token, good_token)
119 |> get(url)
120
121 assert json_response(conn, 200)
122 end
123
124 for good_token <- good_tokens do
125 conn =
126 build_conn()
127 |> assign(:user, nil)
128 |> assign(:token, good_token)
129 |> get(url)
130
131 assert json_response(conn, :forbidden)
132 end
133
134 for bad_token <- [bad_token1, bad_token2, bad_token3] do
135 conn =
136 build_conn()
137 |> assign(:user, admin)
138 |> assign(:token, bad_token)
139 |> get(url)
140
141 assert json_response(conn, :forbidden)
142 end
143 end
144 end
145
146 describe "DELETE /api/pleroma/admin/users" do
147 test "single user", %{admin: admin, conn: conn} do
148 user = insert(:user)
149
150 conn =
151 conn
152 |> put_req_header("accept", "application/json")
153 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
154
155 log_entry = Repo.one(ModerationLog)
156
157 assert ModerationLog.get_log_entry_message(log_entry) ==
158 "@#{admin.nickname} deleted users: @#{user.nickname}"
159
160 assert json_response(conn, 200) == user.nickname
161 end
162
163 test "multiple users", %{admin: admin, conn: conn} do
164 user_one = insert(:user)
165 user_two = insert(:user)
166
167 conn =
168 conn
169 |> put_req_header("accept", "application/json")
170 |> delete("/api/pleroma/admin/users", %{
171 nicknames: [user_one.nickname, user_two.nickname]
172 })
173
174 log_entry = Repo.one(ModerationLog)
175
176 assert ModerationLog.get_log_entry_message(log_entry) ==
177 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
178
179 response = json_response(conn, 200)
180 assert response -- [user_one.nickname, user_two.nickname] == []
181 end
182 end
183
184 describe "/api/pleroma/admin/users" do
185 test "Create", %{conn: conn} do
186 conn =
187 conn
188 |> put_req_header("accept", "application/json")
189 |> post("/api/pleroma/admin/users", %{
190 "users" => [
191 %{
192 "nickname" => "lain",
193 "email" => "lain@example.org",
194 "password" => "test"
195 },
196 %{
197 "nickname" => "lain2",
198 "email" => "lain2@example.org",
199 "password" => "test"
200 }
201 ]
202 })
203
204 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
205 assert response == ["success", "success"]
206
207 log_entry = Repo.one(ModerationLog)
208
209 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
210 end
211
212 test "Cannot create user with existing email", %{conn: conn} do
213 user = insert(:user)
214
215 conn =
216 conn
217 |> put_req_header("accept", "application/json")
218 |> post("/api/pleroma/admin/users", %{
219 "users" => [
220 %{
221 "nickname" => "lain",
222 "email" => user.email,
223 "password" => "test"
224 }
225 ]
226 })
227
228 assert json_response(conn, 409) == [
229 %{
230 "code" => 409,
231 "data" => %{
232 "email" => user.email,
233 "nickname" => "lain"
234 },
235 "error" => "email has already been taken",
236 "type" => "error"
237 }
238 ]
239 end
240
241 test "Cannot create user with existing nickname", %{conn: conn} do
242 user = insert(:user)
243
244 conn =
245 conn
246 |> put_req_header("accept", "application/json")
247 |> post("/api/pleroma/admin/users", %{
248 "users" => [
249 %{
250 "nickname" => user.nickname,
251 "email" => "someuser@plerama.social",
252 "password" => "test"
253 }
254 ]
255 })
256
257 assert json_response(conn, 409) == [
258 %{
259 "code" => 409,
260 "data" => %{
261 "email" => "someuser@plerama.social",
262 "nickname" => user.nickname
263 },
264 "error" => "nickname has already been taken",
265 "type" => "error"
266 }
267 ]
268 end
269
270 test "Multiple user creation works in transaction", %{conn: conn} do
271 user = insert(:user)
272
273 conn =
274 conn
275 |> put_req_header("accept", "application/json")
276 |> post("/api/pleroma/admin/users", %{
277 "users" => [
278 %{
279 "nickname" => "newuser",
280 "email" => "newuser@pleroma.social",
281 "password" => "test"
282 },
283 %{
284 "nickname" => "lain",
285 "email" => user.email,
286 "password" => "test"
287 }
288 ]
289 })
290
291 assert json_response(conn, 409) == [
292 %{
293 "code" => 409,
294 "data" => %{
295 "email" => user.email,
296 "nickname" => "lain"
297 },
298 "error" => "email has already been taken",
299 "type" => "error"
300 },
301 %{
302 "code" => 409,
303 "data" => %{
304 "email" => "newuser@pleroma.social",
305 "nickname" => "newuser"
306 },
307 "error" => "",
308 "type" => "error"
309 }
310 ]
311
312 assert User.get_by_nickname("newuser") === nil
313 end
314 end
315
316 describe "/api/pleroma/admin/users/:nickname" do
317 test "Show", %{conn: conn} do
318 user = insert(:user)
319
320 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
321
322 expected = %{
323 "deactivated" => false,
324 "id" => to_string(user.id),
325 "local" => true,
326 "nickname" => user.nickname,
327 "roles" => %{"admin" => false, "moderator" => false},
328 "tags" => [],
329 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
330 "display_name" => HTML.strip_tags(user.name || user.nickname),
331 "confirmation_pending" => false
332 }
333
334 assert expected == json_response(conn, 200)
335 end
336
337 test "when the user doesn't exist", %{conn: conn} do
338 user = build(:user)
339
340 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
341
342 assert "Not found" == json_response(conn, 404)
343 end
344 end
345
346 describe "/api/pleroma/admin/users/follow" do
347 test "allows to force-follow another user", %{admin: admin, conn: conn} do
348 user = insert(:user)
349 follower = insert(:user)
350
351 conn
352 |> put_req_header("accept", "application/json")
353 |> post("/api/pleroma/admin/users/follow", %{
354 "follower" => follower.nickname,
355 "followed" => user.nickname
356 })
357
358 user = User.get_cached_by_id(user.id)
359 follower = User.get_cached_by_id(follower.id)
360
361 assert User.following?(follower, user)
362
363 log_entry = Repo.one(ModerationLog)
364
365 assert ModerationLog.get_log_entry_message(log_entry) ==
366 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
367 end
368 end
369
370 describe "/api/pleroma/admin/users/unfollow" do
371 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
372 user = insert(:user)
373 follower = insert(:user)
374
375 User.follow(follower, user)
376
377 conn
378 |> put_req_header("accept", "application/json")
379 |> post("/api/pleroma/admin/users/unfollow", %{
380 "follower" => follower.nickname,
381 "followed" => user.nickname
382 })
383
384 user = User.get_cached_by_id(user.id)
385 follower = User.get_cached_by_id(follower.id)
386
387 refute User.following?(follower, user)
388
389 log_entry = Repo.one(ModerationLog)
390
391 assert ModerationLog.get_log_entry_message(log_entry) ==
392 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
393 end
394 end
395
396 describe "PUT /api/pleroma/admin/users/tag" do
397 setup %{conn: conn} do
398 user1 = insert(:user, %{tags: ["x"]})
399 user2 = insert(:user, %{tags: ["y"]})
400 user3 = insert(:user, %{tags: ["unchanged"]})
401
402 conn =
403 conn
404 |> put_req_header("accept", "application/json")
405 |> put(
406 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
407 "#{user2.nickname}&tags[]=foo&tags[]=bar"
408 )
409
410 %{conn: conn, user1: user1, user2: user2, user3: user3}
411 end
412
413 test "it appends specified tags to users with specified nicknames", %{
414 conn: conn,
415 admin: admin,
416 user1: user1,
417 user2: user2
418 } do
419 assert json_response(conn, :no_content)
420 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
421 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
422
423 log_entry = Repo.one(ModerationLog)
424
425 users =
426 [user1.nickname, user2.nickname]
427 |> Enum.map(&"@#{&1}")
428 |> Enum.join(", ")
429
430 tags = ["foo", "bar"] |> Enum.join(", ")
431
432 assert ModerationLog.get_log_entry_message(log_entry) ==
433 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
434 end
435
436 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
437 assert json_response(conn, :no_content)
438 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
439 end
440 end
441
442 describe "DELETE /api/pleroma/admin/users/tag" do
443 setup %{conn: conn} do
444 user1 = insert(:user, %{tags: ["x"]})
445 user2 = insert(:user, %{tags: ["y", "z"]})
446 user3 = insert(:user, %{tags: ["unchanged"]})
447
448 conn =
449 conn
450 |> put_req_header("accept", "application/json")
451 |> delete(
452 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
453 "#{user2.nickname}&tags[]=x&tags[]=z"
454 )
455
456 %{conn: conn, user1: user1, user2: user2, user3: user3}
457 end
458
459 test "it removes specified tags from users with specified nicknames", %{
460 conn: conn,
461 admin: admin,
462 user1: user1,
463 user2: user2
464 } do
465 assert json_response(conn, :no_content)
466 assert User.get_cached_by_id(user1.id).tags == []
467 assert User.get_cached_by_id(user2.id).tags == ["y"]
468
469 log_entry = Repo.one(ModerationLog)
470
471 users =
472 [user1.nickname, user2.nickname]
473 |> Enum.map(&"@#{&1}")
474 |> Enum.join(", ")
475
476 tags = ["x", "z"] |> Enum.join(", ")
477
478 assert ModerationLog.get_log_entry_message(log_entry) ==
479 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
480 end
481
482 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
483 assert json_response(conn, :no_content)
484 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
485 end
486 end
487
488 describe "/api/pleroma/admin/users/:nickname/permission_group" do
489 test "GET is giving user_info", %{admin: admin, conn: conn} do
490 conn =
491 conn
492 |> put_req_header("accept", "application/json")
493 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
494
495 assert json_response(conn, 200) == %{
496 "is_admin" => true,
497 "is_moderator" => false
498 }
499 end
500
501 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
502 user = insert(:user)
503
504 conn =
505 conn
506 |> put_req_header("accept", "application/json")
507 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
508
509 assert json_response(conn, 200) == %{
510 "is_admin" => true
511 }
512
513 log_entry = Repo.one(ModerationLog)
514
515 assert ModerationLog.get_log_entry_message(log_entry) ==
516 "@#{admin.nickname} made @#{user.nickname} admin"
517 end
518
519 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
520 user_one = insert(:user)
521 user_two = insert(:user)
522
523 conn =
524 conn
525 |> put_req_header("accept", "application/json")
526 |> post("/api/pleroma/admin/users/permission_group/admin", %{
527 nicknames: [user_one.nickname, user_two.nickname]
528 })
529
530 assert json_response(conn, 200) == %{"is_admin" => true}
531
532 log_entry = Repo.one(ModerationLog)
533
534 assert ModerationLog.get_log_entry_message(log_entry) ==
535 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
536 end
537
538 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
539 user = insert(:user, is_admin: true)
540
541 conn =
542 conn
543 |> put_req_header("accept", "application/json")
544 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
545
546 assert json_response(conn, 200) == %{"is_admin" => false}
547
548 log_entry = Repo.one(ModerationLog)
549
550 assert ModerationLog.get_log_entry_message(log_entry) ==
551 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
552 end
553
554 test "/:right DELETE, can remove from a permission group (multiple)", %{
555 admin: admin,
556 conn: conn
557 } do
558 user_one = insert(:user, is_admin: true)
559 user_two = insert(:user, is_admin: true)
560
561 conn =
562 conn
563 |> put_req_header("accept", "application/json")
564 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
565 nicknames: [user_one.nickname, user_two.nickname]
566 })
567
568 assert json_response(conn, 200) == %{"is_admin" => false}
569
570 log_entry = Repo.one(ModerationLog)
571
572 assert ModerationLog.get_log_entry_message(log_entry) ==
573 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
574 user_two.nickname
575 }"
576 end
577 end
578
579 describe "POST /api/pleroma/admin/email_invite, with valid config" do
580 clear_config([:instance, :registrations_open]) do
581 Pleroma.Config.put([:instance, :registrations_open], false)
582 end
583
584 clear_config([:instance, :invites_enabled]) do
585 Pleroma.Config.put([:instance, :invites_enabled], true)
586 end
587
588 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
589 recipient_email = "foo@bar.com"
590 recipient_name = "J. D."
591
592 conn =
593 post(
594 conn,
595 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
596 )
597
598 assert json_response(conn, :no_content)
599
600 token_record = List.last(Pleroma.Repo.all(Pleroma.UserInviteToken))
601 assert token_record
602 refute token_record.used
603
604 notify_email = Pleroma.Config.get([:instance, :notify_email])
605 instance_name = Pleroma.Config.get([:instance, :name])
606
607 email =
608 Pleroma.Emails.UserEmail.user_invitation_email(
609 admin,
610 token_record,
611 recipient_email,
612 recipient_name
613 )
614
615 Swoosh.TestAssertions.assert_email_sent(
616 from: {instance_name, notify_email},
617 to: {recipient_name, recipient_email},
618 html_body: email.html_body
619 )
620 end
621
622 test "it returns 403 if requested by a non-admin" do
623 non_admin_user = insert(:user)
624 token = insert(:oauth_token, user: non_admin_user)
625
626 conn =
627 build_conn()
628 |> assign(:user, non_admin_user)
629 |> assign(:token, token)
630 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
631
632 assert json_response(conn, :forbidden)
633 end
634 end
635
636 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
637 clear_config([:instance, :registrations_open])
638 clear_config([:instance, :invites_enabled])
639
640 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
641 Pleroma.Config.put([:instance, :registrations_open], false)
642 Pleroma.Config.put([:instance, :invites_enabled], false)
643
644 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
645
646 assert json_response(conn, :internal_server_error)
647 end
648
649 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
650 Pleroma.Config.put([:instance, :registrations_open], true)
651 Pleroma.Config.put([:instance, :invites_enabled], true)
652
653 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
654
655 assert json_response(conn, :internal_server_error)
656 end
657 end
658
659 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
660 user = insert(:user)
661
662 conn =
663 conn
664 |> put_req_header("accept", "application/json")
665 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
666
667 resp = json_response(conn, 200)
668
669 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
670 end
671
672 describe "GET /api/pleroma/admin/users" do
673 test "renders users array for the first page", %{conn: conn, admin: admin} do
674 user = insert(:user, local: false, tags: ["foo", "bar"])
675 conn = get(conn, "/api/pleroma/admin/users?page=1")
676
677 users =
678 [
679 %{
680 "deactivated" => admin.deactivated,
681 "id" => admin.id,
682 "nickname" => admin.nickname,
683 "roles" => %{"admin" => true, "moderator" => false},
684 "local" => true,
685 "tags" => [],
686 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
687 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
688 "confirmation_pending" => false
689 },
690 %{
691 "deactivated" => user.deactivated,
692 "id" => user.id,
693 "nickname" => user.nickname,
694 "roles" => %{"admin" => false, "moderator" => false},
695 "local" => false,
696 "tags" => ["foo", "bar"],
697 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
698 "display_name" => HTML.strip_tags(user.name || user.nickname),
699 "confirmation_pending" => false
700 }
701 ]
702 |> Enum.sort_by(& &1["nickname"])
703
704 assert json_response(conn, 200) == %{
705 "count" => 2,
706 "page_size" => 50,
707 "users" => users
708 }
709 end
710
711 test "renders empty array for the second page", %{conn: conn} do
712 insert(:user)
713
714 conn = get(conn, "/api/pleroma/admin/users?page=2")
715
716 assert json_response(conn, 200) == %{
717 "count" => 2,
718 "page_size" => 50,
719 "users" => []
720 }
721 end
722
723 test "regular search", %{conn: conn} do
724 user = insert(:user, nickname: "bob")
725
726 conn = get(conn, "/api/pleroma/admin/users?query=bo")
727
728 assert json_response(conn, 200) == %{
729 "count" => 1,
730 "page_size" => 50,
731 "users" => [
732 %{
733 "deactivated" => user.deactivated,
734 "id" => user.id,
735 "nickname" => user.nickname,
736 "roles" => %{"admin" => false, "moderator" => false},
737 "local" => true,
738 "tags" => [],
739 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
740 "display_name" => HTML.strip_tags(user.name || user.nickname),
741 "confirmation_pending" => false
742 }
743 ]
744 }
745 end
746
747 test "search by domain", %{conn: conn} do
748 user = insert(:user, nickname: "nickname@domain.com")
749 insert(:user)
750
751 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
752
753 assert json_response(conn, 200) == %{
754 "count" => 1,
755 "page_size" => 50,
756 "users" => [
757 %{
758 "deactivated" => user.deactivated,
759 "id" => user.id,
760 "nickname" => user.nickname,
761 "roles" => %{"admin" => false, "moderator" => false},
762 "local" => true,
763 "tags" => [],
764 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
765 "display_name" => HTML.strip_tags(user.name || user.nickname),
766 "confirmation_pending" => false
767 }
768 ]
769 }
770 end
771
772 test "search by full nickname", %{conn: conn} do
773 user = insert(:user, nickname: "nickname@domain.com")
774 insert(:user)
775
776 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
777
778 assert json_response(conn, 200) == %{
779 "count" => 1,
780 "page_size" => 50,
781 "users" => [
782 %{
783 "deactivated" => user.deactivated,
784 "id" => user.id,
785 "nickname" => user.nickname,
786 "roles" => %{"admin" => false, "moderator" => false},
787 "local" => true,
788 "tags" => [],
789 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
790 "display_name" => HTML.strip_tags(user.name || user.nickname),
791 "confirmation_pending" => false
792 }
793 ]
794 }
795 end
796
797 test "search by display name", %{conn: conn} do
798 user = insert(:user, name: "Display name")
799 insert(:user)
800
801 conn = get(conn, "/api/pleroma/admin/users?name=display")
802
803 assert json_response(conn, 200) == %{
804 "count" => 1,
805 "page_size" => 50,
806 "users" => [
807 %{
808 "deactivated" => user.deactivated,
809 "id" => user.id,
810 "nickname" => user.nickname,
811 "roles" => %{"admin" => false, "moderator" => false},
812 "local" => true,
813 "tags" => [],
814 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
815 "display_name" => HTML.strip_tags(user.name || user.nickname),
816 "confirmation_pending" => false
817 }
818 ]
819 }
820 end
821
822 test "search by email", %{conn: conn} do
823 user = insert(:user, email: "email@example.com")
824 insert(:user)
825
826 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
827
828 assert json_response(conn, 200) == %{
829 "count" => 1,
830 "page_size" => 50,
831 "users" => [
832 %{
833 "deactivated" => user.deactivated,
834 "id" => user.id,
835 "nickname" => user.nickname,
836 "roles" => %{"admin" => false, "moderator" => false},
837 "local" => true,
838 "tags" => [],
839 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
840 "display_name" => HTML.strip_tags(user.name || user.nickname),
841 "confirmation_pending" => false
842 }
843 ]
844 }
845 end
846
847 test "regular search with page size", %{conn: conn} do
848 user = insert(:user, nickname: "aalice")
849 user2 = insert(:user, nickname: "alice")
850
851 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
852
853 assert json_response(conn1, 200) == %{
854 "count" => 2,
855 "page_size" => 1,
856 "users" => [
857 %{
858 "deactivated" => user.deactivated,
859 "id" => user.id,
860 "nickname" => user.nickname,
861 "roles" => %{"admin" => false, "moderator" => false},
862 "local" => true,
863 "tags" => [],
864 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
865 "display_name" => HTML.strip_tags(user.name || user.nickname),
866 "confirmation_pending" => false
867 }
868 ]
869 }
870
871 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
872
873 assert json_response(conn2, 200) == %{
874 "count" => 2,
875 "page_size" => 1,
876 "users" => [
877 %{
878 "deactivated" => user2.deactivated,
879 "id" => user2.id,
880 "nickname" => user2.nickname,
881 "roles" => %{"admin" => false, "moderator" => false},
882 "local" => true,
883 "tags" => [],
884 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
885 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
886 "confirmation_pending" => false
887 }
888 ]
889 }
890 end
891
892 test "only local users" do
893 admin = insert(:user, is_admin: true, nickname: "john")
894 token = insert(:oauth_admin_token, user: admin)
895 user = insert(:user, nickname: "bob")
896
897 insert(:user, nickname: "bobb", local: false)
898
899 conn =
900 build_conn()
901 |> assign(:user, admin)
902 |> assign(:token, token)
903 |> get("/api/pleroma/admin/users?query=bo&filters=local")
904
905 assert json_response(conn, 200) == %{
906 "count" => 1,
907 "page_size" => 50,
908 "users" => [
909 %{
910 "deactivated" => user.deactivated,
911 "id" => user.id,
912 "nickname" => user.nickname,
913 "roles" => %{"admin" => false, "moderator" => false},
914 "local" => true,
915 "tags" => [],
916 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
917 "display_name" => HTML.strip_tags(user.name || user.nickname),
918 "confirmation_pending" => false
919 }
920 ]
921 }
922 end
923
924 test "only local users with no query", %{conn: conn, admin: old_admin} do
925 admin = insert(:user, is_admin: true, nickname: "john")
926 user = insert(:user, nickname: "bob")
927
928 insert(:user, nickname: "bobb", local: false)
929
930 conn = get(conn, "/api/pleroma/admin/users?filters=local")
931
932 users =
933 [
934 %{
935 "deactivated" => user.deactivated,
936 "id" => user.id,
937 "nickname" => user.nickname,
938 "roles" => %{"admin" => false, "moderator" => false},
939 "local" => true,
940 "tags" => [],
941 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
942 "display_name" => HTML.strip_tags(user.name || user.nickname),
943 "confirmation_pending" => false
944 },
945 %{
946 "deactivated" => admin.deactivated,
947 "id" => admin.id,
948 "nickname" => admin.nickname,
949 "roles" => %{"admin" => true, "moderator" => false},
950 "local" => true,
951 "tags" => [],
952 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
953 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
954 "confirmation_pending" => false
955 },
956 %{
957 "deactivated" => false,
958 "id" => old_admin.id,
959 "local" => true,
960 "nickname" => old_admin.nickname,
961 "roles" => %{"admin" => true, "moderator" => false},
962 "tags" => [],
963 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
964 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
965 "confirmation_pending" => false
966 }
967 ]
968 |> Enum.sort_by(& &1["nickname"])
969
970 assert json_response(conn, 200) == %{
971 "count" => 3,
972 "page_size" => 50,
973 "users" => users
974 }
975 end
976
977 test "load only admins", %{conn: conn, admin: admin} do
978 second_admin = insert(:user, is_admin: true)
979 insert(:user)
980 insert(:user)
981
982 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
983
984 users =
985 [
986 %{
987 "deactivated" => false,
988 "id" => admin.id,
989 "nickname" => admin.nickname,
990 "roles" => %{"admin" => true, "moderator" => false},
991 "local" => admin.local,
992 "tags" => [],
993 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
994 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
995 "confirmation_pending" => false
996 },
997 %{
998 "deactivated" => false,
999 "id" => second_admin.id,
1000 "nickname" => second_admin.nickname,
1001 "roles" => %{"admin" => true, "moderator" => false},
1002 "local" => second_admin.local,
1003 "tags" => [],
1004 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1005 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1006 "confirmation_pending" => false
1007 }
1008 ]
1009 |> Enum.sort_by(& &1["nickname"])
1010
1011 assert json_response(conn, 200) == %{
1012 "count" => 2,
1013 "page_size" => 50,
1014 "users" => users
1015 }
1016 end
1017
1018 test "load only moderators", %{conn: conn} do
1019 moderator = insert(:user, is_moderator: true)
1020 insert(:user)
1021 insert(:user)
1022
1023 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1024
1025 assert json_response(conn, 200) == %{
1026 "count" => 1,
1027 "page_size" => 50,
1028 "users" => [
1029 %{
1030 "deactivated" => false,
1031 "id" => moderator.id,
1032 "nickname" => moderator.nickname,
1033 "roles" => %{"admin" => false, "moderator" => true},
1034 "local" => moderator.local,
1035 "tags" => [],
1036 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1037 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1038 "confirmation_pending" => false
1039 }
1040 ]
1041 }
1042 end
1043
1044 test "load users with tags list", %{conn: conn} do
1045 user1 = insert(:user, tags: ["first"])
1046 user2 = insert(:user, tags: ["second"])
1047 insert(:user)
1048 insert(:user)
1049
1050 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1051
1052 users =
1053 [
1054 %{
1055 "deactivated" => false,
1056 "id" => user1.id,
1057 "nickname" => user1.nickname,
1058 "roles" => %{"admin" => false, "moderator" => false},
1059 "local" => user1.local,
1060 "tags" => ["first"],
1061 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1062 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1063 "confirmation_pending" => false
1064 },
1065 %{
1066 "deactivated" => false,
1067 "id" => user2.id,
1068 "nickname" => user2.nickname,
1069 "roles" => %{"admin" => false, "moderator" => false},
1070 "local" => user2.local,
1071 "tags" => ["second"],
1072 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1073 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1074 "confirmation_pending" => false
1075 }
1076 ]
1077 |> Enum.sort_by(& &1["nickname"])
1078
1079 assert json_response(conn, 200) == %{
1080 "count" => 2,
1081 "page_size" => 50,
1082 "users" => users
1083 }
1084 end
1085
1086 test "it works with multiple filters" do
1087 admin = insert(:user, nickname: "john", is_admin: true)
1088 token = insert(:oauth_admin_token, user: admin)
1089 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1090
1091 insert(:user, nickname: "ken", local: true, deactivated: true)
1092 insert(:user, nickname: "bobb", local: false, deactivated: false)
1093
1094 conn =
1095 build_conn()
1096 |> assign(:user, admin)
1097 |> assign(:token, token)
1098 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1099
1100 assert json_response(conn, 200) == %{
1101 "count" => 1,
1102 "page_size" => 50,
1103 "users" => [
1104 %{
1105 "deactivated" => user.deactivated,
1106 "id" => user.id,
1107 "nickname" => user.nickname,
1108 "roles" => %{"admin" => false, "moderator" => false},
1109 "local" => user.local,
1110 "tags" => [],
1111 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1112 "display_name" => HTML.strip_tags(user.name || user.nickname),
1113 "confirmation_pending" => false
1114 }
1115 ]
1116 }
1117 end
1118
1119 test "it omits relay user", %{admin: admin, conn: conn} do
1120 assert %User{} = Relay.get_actor()
1121
1122 conn = get(conn, "/api/pleroma/admin/users")
1123
1124 assert json_response(conn, 200) == %{
1125 "count" => 1,
1126 "page_size" => 50,
1127 "users" => [
1128 %{
1129 "deactivated" => admin.deactivated,
1130 "id" => admin.id,
1131 "nickname" => admin.nickname,
1132 "roles" => %{"admin" => true, "moderator" => false},
1133 "local" => true,
1134 "tags" => [],
1135 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1136 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1137 "confirmation_pending" => false
1138 }
1139 ]
1140 }
1141 end
1142 end
1143
1144 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1145 user_one = insert(:user, deactivated: true)
1146 user_two = insert(:user, deactivated: true)
1147
1148 conn =
1149 patch(
1150 conn,
1151 "/api/pleroma/admin/users/activate",
1152 %{nicknames: [user_one.nickname, user_two.nickname]}
1153 )
1154
1155 response = json_response(conn, 200)
1156 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1157
1158 log_entry = Repo.one(ModerationLog)
1159
1160 assert ModerationLog.get_log_entry_message(log_entry) ==
1161 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1162 end
1163
1164 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1165 user_one = insert(:user, deactivated: false)
1166 user_two = insert(:user, deactivated: false)
1167
1168 conn =
1169 patch(
1170 conn,
1171 "/api/pleroma/admin/users/deactivate",
1172 %{nicknames: [user_one.nickname, user_two.nickname]}
1173 )
1174
1175 response = json_response(conn, 200)
1176 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1177
1178 log_entry = Repo.one(ModerationLog)
1179
1180 assert ModerationLog.get_log_entry_message(log_entry) ==
1181 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1182 end
1183
1184 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1185 user = insert(:user)
1186
1187 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1188
1189 assert json_response(conn, 200) ==
1190 %{
1191 "deactivated" => !user.deactivated,
1192 "id" => user.id,
1193 "nickname" => user.nickname,
1194 "roles" => %{"admin" => false, "moderator" => false},
1195 "local" => true,
1196 "tags" => [],
1197 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1198 "display_name" => HTML.strip_tags(user.name || user.nickname),
1199 "confirmation_pending" => false
1200 }
1201
1202 log_entry = Repo.one(ModerationLog)
1203
1204 assert ModerationLog.get_log_entry_message(log_entry) ==
1205 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1206 end
1207
1208 describe "POST /api/pleroma/admin/users/invite_token" do
1209 test "without options", %{conn: conn} do
1210 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1211
1212 invite_json = json_response(conn, 200)
1213 invite = UserInviteToken.find_by_token!(invite_json["token"])
1214 refute invite.used
1215 refute invite.expires_at
1216 refute invite.max_use
1217 assert invite.invite_type == "one_time"
1218 end
1219
1220 test "with expires_at", %{conn: conn} do
1221 conn =
1222 post(conn, "/api/pleroma/admin/users/invite_token", %{
1223 "expires_at" => Date.to_string(Date.utc_today())
1224 })
1225
1226 invite_json = json_response(conn, 200)
1227 invite = UserInviteToken.find_by_token!(invite_json["token"])
1228
1229 refute invite.used
1230 assert invite.expires_at == Date.utc_today()
1231 refute invite.max_use
1232 assert invite.invite_type == "date_limited"
1233 end
1234
1235 test "with max_use", %{conn: conn} do
1236 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1237
1238 invite_json = json_response(conn, 200)
1239 invite = UserInviteToken.find_by_token!(invite_json["token"])
1240 refute invite.used
1241 refute invite.expires_at
1242 assert invite.max_use == 150
1243 assert invite.invite_type == "reusable"
1244 end
1245
1246 test "with max use and expires_at", %{conn: conn} do
1247 conn =
1248 post(conn, "/api/pleroma/admin/users/invite_token", %{
1249 "max_use" => 150,
1250 "expires_at" => Date.to_string(Date.utc_today())
1251 })
1252
1253 invite_json = json_response(conn, 200)
1254 invite = UserInviteToken.find_by_token!(invite_json["token"])
1255 refute invite.used
1256 assert invite.expires_at == Date.utc_today()
1257 assert invite.max_use == 150
1258 assert invite.invite_type == "reusable_date_limited"
1259 end
1260 end
1261
1262 describe "GET /api/pleroma/admin/users/invites" do
1263 test "no invites", %{conn: conn} do
1264 conn = get(conn, "/api/pleroma/admin/users/invites")
1265
1266 assert json_response(conn, 200) == %{"invites" => []}
1267 end
1268
1269 test "with invite", %{conn: conn} do
1270 {:ok, invite} = UserInviteToken.create_invite()
1271
1272 conn = get(conn, "/api/pleroma/admin/users/invites")
1273
1274 assert json_response(conn, 200) == %{
1275 "invites" => [
1276 %{
1277 "expires_at" => nil,
1278 "id" => invite.id,
1279 "invite_type" => "one_time",
1280 "max_use" => nil,
1281 "token" => invite.token,
1282 "used" => false,
1283 "uses" => 0
1284 }
1285 ]
1286 }
1287 end
1288 end
1289
1290 describe "POST /api/pleroma/admin/users/revoke_invite" do
1291 test "with token", %{conn: conn} do
1292 {:ok, invite} = UserInviteToken.create_invite()
1293
1294 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1295
1296 assert json_response(conn, 200) == %{
1297 "expires_at" => nil,
1298 "id" => invite.id,
1299 "invite_type" => "one_time",
1300 "max_use" => nil,
1301 "token" => invite.token,
1302 "used" => true,
1303 "uses" => 0
1304 }
1305 end
1306
1307 test "with invalid token", %{conn: conn} do
1308 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1309
1310 assert json_response(conn, :not_found) == "Not found"
1311 end
1312 end
1313
1314 describe "GET /api/pleroma/admin/reports/:id" do
1315 test "returns report by its id", %{conn: conn} do
1316 [reporter, target_user] = insert_pair(:user)
1317 activity = insert(:note_activity, user: target_user)
1318
1319 {:ok, %{id: report_id}} =
1320 CommonAPI.report(reporter, %{
1321 "account_id" => target_user.id,
1322 "comment" => "I feel offended",
1323 "status_ids" => [activity.id]
1324 })
1325
1326 response =
1327 conn
1328 |> get("/api/pleroma/admin/reports/#{report_id}")
1329 |> json_response(:ok)
1330
1331 assert response["id"] == report_id
1332 end
1333
1334 test "returns 404 when report id is invalid", %{conn: conn} do
1335 conn = get(conn, "/api/pleroma/admin/reports/test")
1336
1337 assert json_response(conn, :not_found) == "Not found"
1338 end
1339 end
1340
1341 describe "PATCH /api/pleroma/admin/reports" do
1342 setup do
1343 [reporter, target_user] = insert_pair(:user)
1344 activity = insert(:note_activity, user: target_user)
1345
1346 {:ok, %{id: report_id}} =
1347 CommonAPI.report(reporter, %{
1348 "account_id" => target_user.id,
1349 "comment" => "I feel offended",
1350 "status_ids" => [activity.id]
1351 })
1352
1353 {:ok, %{id: second_report_id}} =
1354 CommonAPI.report(reporter, %{
1355 "account_id" => target_user.id,
1356 "comment" => "I feel very offended",
1357 "status_ids" => [activity.id]
1358 })
1359
1360 %{
1361 id: report_id,
1362 second_report_id: second_report_id
1363 }
1364 end
1365
1366 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1367 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1368 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1369
1370 response =
1371 conn
1372 |> assign(:token, read_token)
1373 |> patch("/api/pleroma/admin/reports", %{
1374 "reports" => [%{"state" => "resolved", "id" => id}]
1375 })
1376 |> json_response(403)
1377
1378 assert response == %{
1379 "error" => "Insufficient permissions: admin:write:reports."
1380 }
1381
1382 conn
1383 |> assign(:token, write_token)
1384 |> patch("/api/pleroma/admin/reports", %{
1385 "reports" => [%{"state" => "resolved", "id" => id}]
1386 })
1387 |> json_response(:no_content)
1388 end
1389
1390 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1391 conn
1392 |> patch("/api/pleroma/admin/reports", %{
1393 "reports" => [
1394 %{"state" => "resolved", "id" => id}
1395 ]
1396 })
1397 |> json_response(:no_content)
1398
1399 activity = Activity.get_by_id(id)
1400 assert activity.data["state"] == "resolved"
1401
1402 log_entry = Repo.one(ModerationLog)
1403
1404 assert ModerationLog.get_log_entry_message(log_entry) ==
1405 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1406 end
1407
1408 test "closes report", %{conn: conn, id: id, admin: admin} do
1409 conn
1410 |> patch("/api/pleroma/admin/reports", %{
1411 "reports" => [
1412 %{"state" => "closed", "id" => id}
1413 ]
1414 })
1415 |> json_response(:no_content)
1416
1417 activity = Activity.get_by_id(id)
1418 assert activity.data["state"] == "closed"
1419
1420 log_entry = Repo.one(ModerationLog)
1421
1422 assert ModerationLog.get_log_entry_message(log_entry) ==
1423 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1424 end
1425
1426 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1427 conn =
1428 conn
1429 |> patch("/api/pleroma/admin/reports", %{
1430 "reports" => [
1431 %{"state" => "test", "id" => id}
1432 ]
1433 })
1434
1435 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1436 end
1437
1438 test "returns 404 when report is not exist", %{conn: conn} do
1439 conn =
1440 conn
1441 |> patch("/api/pleroma/admin/reports", %{
1442 "reports" => [
1443 %{"state" => "closed", "id" => "test"}
1444 ]
1445 })
1446
1447 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1448 end
1449
1450 test "updates state of multiple reports", %{
1451 conn: conn,
1452 id: id,
1453 admin: admin,
1454 second_report_id: second_report_id
1455 } do
1456 conn
1457 |> patch("/api/pleroma/admin/reports", %{
1458 "reports" => [
1459 %{"state" => "resolved", "id" => id},
1460 %{"state" => "closed", "id" => second_report_id}
1461 ]
1462 })
1463 |> json_response(:no_content)
1464
1465 activity = Activity.get_by_id(id)
1466 second_activity = Activity.get_by_id(second_report_id)
1467 assert activity.data["state"] == "resolved"
1468 assert second_activity.data["state"] == "closed"
1469
1470 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1471
1472 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1473 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1474
1475 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1476 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1477 end
1478 end
1479
1480 describe "GET /api/pleroma/admin/reports" do
1481 test "returns empty response when no reports created", %{conn: conn} do
1482 response =
1483 conn
1484 |> get("/api/pleroma/admin/reports")
1485 |> json_response(:ok)
1486
1487 assert Enum.empty?(response["reports"])
1488 assert response["total"] == 0
1489 end
1490
1491 test "returns reports", %{conn: conn} do
1492 [reporter, target_user] = insert_pair(:user)
1493 activity = insert(:note_activity, user: target_user)
1494
1495 {:ok, %{id: report_id}} =
1496 CommonAPI.report(reporter, %{
1497 "account_id" => target_user.id,
1498 "comment" => "I feel offended",
1499 "status_ids" => [activity.id]
1500 })
1501
1502 response =
1503 conn
1504 |> get("/api/pleroma/admin/reports")
1505 |> json_response(:ok)
1506
1507 [report] = response["reports"]
1508
1509 assert length(response["reports"]) == 1
1510 assert report["id"] == report_id
1511
1512 assert response["total"] == 1
1513 end
1514
1515 test "returns reports with specified state", %{conn: conn} do
1516 [reporter, target_user] = insert_pair(:user)
1517 activity = insert(:note_activity, user: target_user)
1518
1519 {:ok, %{id: first_report_id}} =
1520 CommonAPI.report(reporter, %{
1521 "account_id" => target_user.id,
1522 "comment" => "I feel offended",
1523 "status_ids" => [activity.id]
1524 })
1525
1526 {:ok, %{id: second_report_id}} =
1527 CommonAPI.report(reporter, %{
1528 "account_id" => target_user.id,
1529 "comment" => "I don't like this user"
1530 })
1531
1532 CommonAPI.update_report_state(second_report_id, "closed")
1533
1534 response =
1535 conn
1536 |> get("/api/pleroma/admin/reports", %{
1537 "state" => "open"
1538 })
1539 |> json_response(:ok)
1540
1541 [open_report] = response["reports"]
1542
1543 assert length(response["reports"]) == 1
1544 assert open_report["id"] == first_report_id
1545
1546 assert response["total"] == 1
1547
1548 response =
1549 conn
1550 |> get("/api/pleroma/admin/reports", %{
1551 "state" => "closed"
1552 })
1553 |> json_response(:ok)
1554
1555 [closed_report] = response["reports"]
1556
1557 assert length(response["reports"]) == 1
1558 assert closed_report["id"] == second_report_id
1559
1560 assert response["total"] == 1
1561
1562 response =
1563 conn
1564 |> get("/api/pleroma/admin/reports", %{
1565 "state" => "resolved"
1566 })
1567 |> json_response(:ok)
1568
1569 assert Enum.empty?(response["reports"])
1570 assert response["total"] == 0
1571 end
1572
1573 test "returns 403 when requested by a non-admin" do
1574 user = insert(:user)
1575 token = insert(:oauth_token, user: user)
1576
1577 conn =
1578 build_conn()
1579 |> assign(:user, user)
1580 |> assign(:token, token)
1581 |> get("/api/pleroma/admin/reports")
1582
1583 assert json_response(conn, :forbidden) ==
1584 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1585 end
1586
1587 test "returns 403 when requested by anonymous" do
1588 conn = get(build_conn(), "/api/pleroma/admin/reports")
1589
1590 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1591 end
1592 end
1593
1594 describe "GET /api/pleroma/admin/grouped_reports" do
1595 setup do
1596 [reporter, target_user] = insert_pair(:user)
1597
1598 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1599 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1600 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1601
1602 first_status =
1603 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1604
1605 second_status =
1606 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1607
1608 third_status =
1609 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1610
1611 {:ok, first_report} =
1612 CommonAPI.report(reporter, %{
1613 "account_id" => target_user.id,
1614 "status_ids" => [first_status.id, second_status.id, third_status.id]
1615 })
1616
1617 {:ok, second_report} =
1618 CommonAPI.report(reporter, %{
1619 "account_id" => target_user.id,
1620 "status_ids" => [first_status.id, second_status.id]
1621 })
1622
1623 {:ok, third_report} =
1624 CommonAPI.report(reporter, %{
1625 "account_id" => target_user.id,
1626 "status_ids" => [first_status.id]
1627 })
1628
1629 %{
1630 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1631 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1632 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1633 first_report: first_report,
1634 first_status_reports: [first_report, second_report, third_report],
1635 second_status_reports: [first_report, second_report],
1636 third_status_reports: [first_report],
1637 target_user: target_user,
1638 reporter: reporter
1639 }
1640 end
1641
1642 test "returns reports grouped by status", %{
1643 conn: conn,
1644 first_status: first_status,
1645 second_status: second_status,
1646 third_status: third_status,
1647 first_status_reports: first_status_reports,
1648 second_status_reports: second_status_reports,
1649 third_status_reports: third_status_reports,
1650 target_user: target_user,
1651 reporter: reporter
1652 } do
1653 response =
1654 conn
1655 |> get("/api/pleroma/admin/grouped_reports")
1656 |> json_response(:ok)
1657
1658 assert length(response["reports"]) == 3
1659
1660 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1661
1662 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1663
1664 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1665
1666 assert length(first_group["reports"]) == 3
1667 assert length(second_group["reports"]) == 2
1668 assert length(third_group["reports"]) == 1
1669
1670 assert first_group["date"] ==
1671 Enum.max_by(first_status_reports, fn act ->
1672 NaiveDateTime.from_iso8601!(act.data["published"])
1673 end).data["published"]
1674
1675 assert first_group["status"] ==
1676 Map.put(
1677 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1678 "deleted",
1679 false
1680 )
1681
1682 assert(first_group["account"]["id"] == target_user.id)
1683
1684 assert length(first_group["actors"]) == 1
1685 assert hd(first_group["actors"])["id"] == reporter.id
1686
1687 assert Enum.map(first_group["reports"], & &1["id"]) --
1688 Enum.map(first_status_reports, & &1.id) == []
1689
1690 assert second_group["date"] ==
1691 Enum.max_by(second_status_reports, fn act ->
1692 NaiveDateTime.from_iso8601!(act.data["published"])
1693 end).data["published"]
1694
1695 assert second_group["status"] ==
1696 Map.put(
1697 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1698 "deleted",
1699 false
1700 )
1701
1702 assert second_group["account"]["id"] == target_user.id
1703
1704 assert length(second_group["actors"]) == 1
1705 assert hd(second_group["actors"])["id"] == reporter.id
1706
1707 assert Enum.map(second_group["reports"], & &1["id"]) --
1708 Enum.map(second_status_reports, & &1.id) == []
1709
1710 assert third_group["date"] ==
1711 Enum.max_by(third_status_reports, fn act ->
1712 NaiveDateTime.from_iso8601!(act.data["published"])
1713 end).data["published"]
1714
1715 assert third_group["status"] ==
1716 Map.put(
1717 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1718 "deleted",
1719 false
1720 )
1721
1722 assert third_group["account"]["id"] == target_user.id
1723
1724 assert length(third_group["actors"]) == 1
1725 assert hd(third_group["actors"])["id"] == reporter.id
1726
1727 assert Enum.map(third_group["reports"], & &1["id"]) --
1728 Enum.map(third_status_reports, & &1.id) == []
1729 end
1730
1731 test "reopened report renders status data", %{
1732 conn: conn,
1733 first_report: first_report,
1734 first_status: first_status
1735 } do
1736 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1737
1738 response =
1739 conn
1740 |> get("/api/pleroma/admin/grouped_reports")
1741 |> json_response(:ok)
1742
1743 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1744
1745 assert first_group["status"] ==
1746 Map.put(
1747 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1748 "deleted",
1749 false
1750 )
1751 end
1752
1753 test "reopened report does not render status data if status has been deleted", %{
1754 conn: conn,
1755 first_report: first_report,
1756 first_status: first_status,
1757 target_user: target_user
1758 } do
1759 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1760 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1761
1762 refute Activity.get_by_ap_id(first_status.id)
1763
1764 response =
1765 conn
1766 |> get("/api/pleroma/admin/grouped_reports")
1767 |> json_response(:ok)
1768
1769 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1770 "deleted"
1771 ] == true
1772
1773 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1774 end
1775
1776 test "account not empty if status was deleted", %{
1777 conn: conn,
1778 first_report: first_report,
1779 first_status: first_status,
1780 target_user: target_user
1781 } do
1782 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1783 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1784
1785 refute Activity.get_by_ap_id(first_status.id)
1786
1787 response =
1788 conn
1789 |> get("/api/pleroma/admin/grouped_reports")
1790 |> json_response(:ok)
1791
1792 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
1793 end
1794 end
1795
1796 describe "PUT /api/pleroma/admin/statuses/:id" do
1797 setup do
1798 activity = insert(:note_activity)
1799
1800 %{id: activity.id}
1801 end
1802
1803 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1804 response =
1805 conn
1806 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1807 |> json_response(:ok)
1808
1809 assert response["sensitive"]
1810
1811 log_entry = Repo.one(ModerationLog)
1812
1813 assert ModerationLog.get_log_entry_message(log_entry) ==
1814 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1815
1816 response =
1817 conn
1818 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1819 |> json_response(:ok)
1820
1821 refute response["sensitive"]
1822 end
1823
1824 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1825 response =
1826 conn
1827 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1828 |> json_response(:ok)
1829
1830 assert response["visibility"] == "public"
1831
1832 log_entry = Repo.one(ModerationLog)
1833
1834 assert ModerationLog.get_log_entry_message(log_entry) ==
1835 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1836
1837 response =
1838 conn
1839 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1840 |> json_response(:ok)
1841
1842 assert response["visibility"] == "private"
1843
1844 response =
1845 conn
1846 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1847 |> json_response(:ok)
1848
1849 assert response["visibility"] == "unlisted"
1850 end
1851
1852 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1853 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1854
1855 assert json_response(conn, :bad_request) == "Unsupported visibility"
1856 end
1857 end
1858
1859 describe "DELETE /api/pleroma/admin/statuses/:id" do
1860 setup do
1861 activity = insert(:note_activity)
1862
1863 %{id: activity.id}
1864 end
1865
1866 test "deletes status", %{conn: conn, id: id, admin: admin} do
1867 conn
1868 |> delete("/api/pleroma/admin/statuses/#{id}")
1869 |> json_response(:ok)
1870
1871 refute Activity.get_by_id(id)
1872
1873 log_entry = Repo.one(ModerationLog)
1874
1875 assert ModerationLog.get_log_entry_message(log_entry) ==
1876 "@#{admin.nickname} deleted status ##{id}"
1877 end
1878
1879 test "returns error when status is not exist", %{conn: conn} do
1880 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1881
1882 assert json_response(conn, :bad_request) == "Could not delete"
1883 end
1884 end
1885
1886 describe "GET /api/pleroma/admin/config" do
1887 test "without any settings in db", %{conn: conn} do
1888 conn = get(conn, "/api/pleroma/admin/config")
1889
1890 assert json_response(conn, 200) == %{"configs" => []}
1891 end
1892
1893 test "with settings in db", %{conn: conn} do
1894 config1 = insert(:config)
1895 config2 = insert(:config)
1896
1897 conn = get(conn, "/api/pleroma/admin/config")
1898
1899 %{
1900 "configs" => [
1901 %{
1902 "key" => key1,
1903 "value" => _
1904 },
1905 %{
1906 "key" => key2,
1907 "value" => _
1908 }
1909 ]
1910 } = json_response(conn, 200)
1911
1912 assert key1 == config1.key
1913 assert key2 == config2.key
1914 end
1915 end
1916
1917 describe "POST /api/pleroma/admin/config" do
1918 setup do
1919 temp_file = "config/test.exported_from_db.secret.exs"
1920
1921 on_exit(fn ->
1922 Application.delete_env(:pleroma, :key1)
1923 Application.delete_env(:pleroma, :key2)
1924 Application.delete_env(:pleroma, :key3)
1925 Application.delete_env(:pleroma, :key4)
1926 Application.delete_env(:pleroma, :keyaa1)
1927 Application.delete_env(:pleroma, :keyaa2)
1928 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1929 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1930 :ok = File.rm(temp_file)
1931 end)
1932 end
1933
1934 clear_config([:instance, :dynamic_configuration]) do
1935 Pleroma.Config.put([:instance, :dynamic_configuration], true)
1936 end
1937
1938 @tag capture_log: true
1939 test "create new config setting in db", %{conn: conn} do
1940 conn =
1941 post(conn, "/api/pleroma/admin/config", %{
1942 configs: [
1943 %{group: "pleroma", key: "key1", value: "value1"},
1944 %{
1945 group: "ueberauth",
1946 key: "Ueberauth.Strategy.Twitter.OAuth",
1947 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1948 },
1949 %{
1950 group: "pleroma",
1951 key: "key2",
1952 value: %{
1953 ":nested_1" => "nested_value1",
1954 ":nested_2" => [
1955 %{":nested_22" => "nested_value222"},
1956 %{":nested_33" => %{":nested_44" => "nested_444"}}
1957 ]
1958 }
1959 },
1960 %{
1961 group: "pleroma",
1962 key: "key3",
1963 value: [
1964 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1965 %{"nested_4" => true}
1966 ]
1967 },
1968 %{
1969 group: "pleroma",
1970 key: "key4",
1971 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1972 },
1973 %{
1974 group: "idna",
1975 key: "key5",
1976 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1977 }
1978 ]
1979 })
1980
1981 assert json_response(conn, 200) == %{
1982 "configs" => [
1983 %{
1984 "group" => "pleroma",
1985 "key" => "key1",
1986 "value" => "value1"
1987 },
1988 %{
1989 "group" => "ueberauth",
1990 "key" => "Ueberauth.Strategy.Twitter.OAuth",
1991 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}]
1992 },
1993 %{
1994 "group" => "pleroma",
1995 "key" => "key2",
1996 "value" => %{
1997 ":nested_1" => "nested_value1",
1998 ":nested_2" => [
1999 %{":nested_22" => "nested_value222"},
2000 %{":nested_33" => %{":nested_44" => "nested_444"}}
2001 ]
2002 }
2003 },
2004 %{
2005 "group" => "pleroma",
2006 "key" => "key3",
2007 "value" => [
2008 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2009 %{"nested_4" => true}
2010 ]
2011 },
2012 %{
2013 "group" => "pleroma",
2014 "key" => "key4",
2015 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
2016 },
2017 %{
2018 "group" => "idna",
2019 "key" => "key5",
2020 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2021 }
2022 ]
2023 }
2024
2025 assert Application.get_env(:pleroma, :key1) == "value1"
2026
2027 assert Application.get_env(:pleroma, :key2) == %{
2028 nested_1: "nested_value1",
2029 nested_2: [
2030 %{nested_22: "nested_value222"},
2031 %{nested_33: %{nested_44: "nested_444"}}
2032 ]
2033 }
2034
2035 assert Application.get_env(:pleroma, :key3) == [
2036 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2037 %{"nested_4" => true}
2038 ]
2039
2040 assert Application.get_env(:pleroma, :key4) == %{
2041 "endpoint" => "https://example.com",
2042 nested_5: :upload
2043 }
2044
2045 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2046 end
2047
2048 test "update config setting & delete", %{conn: conn} do
2049 config1 = insert(:config, key: "keyaa1")
2050 config2 = insert(:config, key: "keyaa2")
2051
2052 insert(:config,
2053 group: "ueberauth",
2054 key: "Ueberauth.Strategy.Microsoft.OAuth",
2055 value: :erlang.term_to_binary([])
2056 )
2057
2058 conn =
2059 post(conn, "/api/pleroma/admin/config", %{
2060 configs: [
2061 %{group: config1.group, key: config1.key, value: "another_value"},
2062 %{group: config2.group, key: config2.key, delete: "true"},
2063 %{
2064 group: "ueberauth",
2065 key: "Ueberauth.Strategy.Microsoft.OAuth",
2066 delete: "true"
2067 }
2068 ]
2069 })
2070
2071 assert json_response(conn, 200) == %{
2072 "configs" => [
2073 %{
2074 "group" => "pleroma",
2075 "key" => config1.key,
2076 "value" => "another_value"
2077 }
2078 ]
2079 }
2080
2081 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2082 refute Application.get_env(:pleroma, :keyaa2)
2083 end
2084
2085 test "common config example", %{conn: conn} do
2086 conn =
2087 post(conn, "/api/pleroma/admin/config", %{
2088 configs: [
2089 %{
2090 "group" => "pleroma",
2091 "key" => "Pleroma.Captcha.NotReal",
2092 "value" => [
2093 %{"tuple" => [":enabled", false]},
2094 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2095 %{"tuple" => [":seconds_valid", 60]},
2096 %{"tuple" => [":path", ""]},
2097 %{"tuple" => [":key1", nil]},
2098 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2099 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2100 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2101 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2102 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}
2103 ]
2104 }
2105 ]
2106 })
2107
2108 assert json_response(conn, 200) == %{
2109 "configs" => [
2110 %{
2111 "group" => "pleroma",
2112 "key" => "Pleroma.Captcha.NotReal",
2113 "value" => [
2114 %{"tuple" => [":enabled", false]},
2115 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2116 %{"tuple" => [":seconds_valid", 60]},
2117 %{"tuple" => [":path", ""]},
2118 %{"tuple" => [":key1", nil]},
2119 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2120 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2121 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2122 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2123 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}
2124 ]
2125 }
2126 ]
2127 }
2128 end
2129
2130 test "tuples with more than two values", %{conn: conn} do
2131 conn =
2132 post(conn, "/api/pleroma/admin/config", %{
2133 configs: [
2134 %{
2135 "group" => "pleroma",
2136 "key" => "Pleroma.Web.Endpoint.NotReal",
2137 "value" => [
2138 %{
2139 "tuple" => [
2140 ":http",
2141 [
2142 %{
2143 "tuple" => [
2144 ":key2",
2145 [
2146 %{
2147 "tuple" => [
2148 ":_",
2149 [
2150 %{
2151 "tuple" => [
2152 "/api/v1/streaming",
2153 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2154 []
2155 ]
2156 },
2157 %{
2158 "tuple" => [
2159 "/websocket",
2160 "Phoenix.Endpoint.CowboyWebSocket",
2161 %{
2162 "tuple" => [
2163 "Phoenix.Transports.WebSocket",
2164 %{
2165 "tuple" => [
2166 "Pleroma.Web.Endpoint",
2167 "Pleroma.Web.UserSocket",
2168 []
2169 ]
2170 }
2171 ]
2172 }
2173 ]
2174 },
2175 %{
2176 "tuple" => [
2177 ":_",
2178 "Phoenix.Endpoint.Cowboy2Handler",
2179 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2180 ]
2181 }
2182 ]
2183 ]
2184 }
2185 ]
2186 ]
2187 }
2188 ]
2189 ]
2190 }
2191 ]
2192 }
2193 ]
2194 })
2195
2196 assert json_response(conn, 200) == %{
2197 "configs" => [
2198 %{
2199 "group" => "pleroma",
2200 "key" => "Pleroma.Web.Endpoint.NotReal",
2201 "value" => [
2202 %{
2203 "tuple" => [
2204 ":http",
2205 [
2206 %{
2207 "tuple" => [
2208 ":key2",
2209 [
2210 %{
2211 "tuple" => [
2212 ":_",
2213 [
2214 %{
2215 "tuple" => [
2216 "/api/v1/streaming",
2217 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2218 []
2219 ]
2220 },
2221 %{
2222 "tuple" => [
2223 "/websocket",
2224 "Phoenix.Endpoint.CowboyWebSocket",
2225 %{
2226 "tuple" => [
2227 "Phoenix.Transports.WebSocket",
2228 %{
2229 "tuple" => [
2230 "Pleroma.Web.Endpoint",
2231 "Pleroma.Web.UserSocket",
2232 []
2233 ]
2234 }
2235 ]
2236 }
2237 ]
2238 },
2239 %{
2240 "tuple" => [
2241 ":_",
2242 "Phoenix.Endpoint.Cowboy2Handler",
2243 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2244 ]
2245 }
2246 ]
2247 ]
2248 }
2249 ]
2250 ]
2251 }
2252 ]
2253 ]
2254 }
2255 ]
2256 }
2257 ]
2258 }
2259 end
2260
2261 test "settings with nesting map", %{conn: conn} do
2262 conn =
2263 post(conn, "/api/pleroma/admin/config", %{
2264 configs: [
2265 %{
2266 "group" => "pleroma",
2267 "key" => ":key1",
2268 "value" => [
2269 %{"tuple" => [":key2", "some_val"]},
2270 %{
2271 "tuple" => [
2272 ":key3",
2273 %{
2274 ":max_options" => 20,
2275 ":max_option_chars" => 200,
2276 ":min_expiration" => 0,
2277 ":max_expiration" => 31_536_000,
2278 "nested" => %{
2279 ":max_options" => 20,
2280 ":max_option_chars" => 200,
2281 ":min_expiration" => 0,
2282 ":max_expiration" => 31_536_000
2283 }
2284 }
2285 ]
2286 }
2287 ]
2288 }
2289 ]
2290 })
2291
2292 assert json_response(conn, 200) ==
2293 %{
2294 "configs" => [
2295 %{
2296 "group" => "pleroma",
2297 "key" => ":key1",
2298 "value" => [
2299 %{"tuple" => [":key2", "some_val"]},
2300 %{
2301 "tuple" => [
2302 ":key3",
2303 %{
2304 ":max_expiration" => 31_536_000,
2305 ":max_option_chars" => 200,
2306 ":max_options" => 20,
2307 ":min_expiration" => 0,
2308 "nested" => %{
2309 ":max_expiration" => 31_536_000,
2310 ":max_option_chars" => 200,
2311 ":max_options" => 20,
2312 ":min_expiration" => 0
2313 }
2314 }
2315 ]
2316 }
2317 ]
2318 }
2319 ]
2320 }
2321 end
2322
2323 test "value as map", %{conn: conn} do
2324 conn =
2325 post(conn, "/api/pleroma/admin/config", %{
2326 configs: [
2327 %{
2328 "group" => "pleroma",
2329 "key" => ":key1",
2330 "value" => %{"key" => "some_val"}
2331 }
2332 ]
2333 })
2334
2335 assert json_response(conn, 200) ==
2336 %{
2337 "configs" => [
2338 %{
2339 "group" => "pleroma",
2340 "key" => ":key1",
2341 "value" => %{"key" => "some_val"}
2342 }
2343 ]
2344 }
2345 end
2346
2347 test "dispatch setting", %{conn: conn} do
2348 conn =
2349 post(conn, "/api/pleroma/admin/config", %{
2350 configs: [
2351 %{
2352 "group" => "pleroma",
2353 "key" => "Pleroma.Web.Endpoint.NotReal",
2354 "value" => [
2355 %{
2356 "tuple" => [
2357 ":http",
2358 [
2359 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2360 %{"tuple" => [":dispatch", ["{:_,
2361 [
2362 {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
2363 {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
2364 {Phoenix.Transports.WebSocket,
2365 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
2366 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
2367 ]}"]]}
2368 ]
2369 ]
2370 }
2371 ]
2372 }
2373 ]
2374 })
2375
2376 dispatch_string =
2377 "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
2378 "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
2379 "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
2380 "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
2381
2382 assert json_response(conn, 200) == %{
2383 "configs" => [
2384 %{
2385 "group" => "pleroma",
2386 "key" => "Pleroma.Web.Endpoint.NotReal",
2387 "value" => [
2388 %{
2389 "tuple" => [
2390 ":http",
2391 [
2392 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2393 %{
2394 "tuple" => [
2395 ":dispatch",
2396 [
2397 dispatch_string
2398 ]
2399 ]
2400 }
2401 ]
2402 ]
2403 }
2404 ]
2405 }
2406 ]
2407 }
2408 end
2409
2410 test "queues key as atom", %{conn: conn} do
2411 conn =
2412 post(conn, "/api/pleroma/admin/config", %{
2413 configs: [
2414 %{
2415 "group" => "oban",
2416 "key" => ":queues",
2417 "value" => [
2418 %{"tuple" => [":federator_incoming", 50]},
2419 %{"tuple" => [":federator_outgoing", 50]},
2420 %{"tuple" => [":web_push", 50]},
2421 %{"tuple" => [":mailer", 10]},
2422 %{"tuple" => [":transmogrifier", 20]},
2423 %{"tuple" => [":scheduled_activities", 10]},
2424 %{"tuple" => [":background", 5]}
2425 ]
2426 }
2427 ]
2428 })
2429
2430 assert json_response(conn, 200) == %{
2431 "configs" => [
2432 %{
2433 "group" => "oban",
2434 "key" => ":queues",
2435 "value" => [
2436 %{"tuple" => [":federator_incoming", 50]},
2437 %{"tuple" => [":federator_outgoing", 50]},
2438 %{"tuple" => [":web_push", 50]},
2439 %{"tuple" => [":mailer", 10]},
2440 %{"tuple" => [":transmogrifier", 20]},
2441 %{"tuple" => [":scheduled_activities", 10]},
2442 %{"tuple" => [":background", 5]}
2443 ]
2444 }
2445 ]
2446 }
2447 end
2448
2449 test "delete part of settings by atom subkeys", %{conn: conn} do
2450 config =
2451 insert(:config,
2452 key: "keyaa1",
2453 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2454 )
2455
2456 conn =
2457 post(conn, "/api/pleroma/admin/config", %{
2458 configs: [
2459 %{
2460 group: config.group,
2461 key: config.key,
2462 subkeys: [":subkey1", ":subkey3"],
2463 delete: "true"
2464 }
2465 ]
2466 })
2467
2468 assert(
2469 json_response(conn, 200) == %{
2470 "configs" => [
2471 %{
2472 "group" => "pleroma",
2473 "key" => "keyaa1",
2474 "value" => [%{"tuple" => [":subkey2", "val2"]}]
2475 }
2476 ]
2477 }
2478 )
2479 end
2480 end
2481
2482 describe "config mix tasks run" do
2483 setup do
2484 temp_file = "config/test.exported_from_db.secret.exs"
2485
2486 Mix.shell(Mix.Shell.Quiet)
2487
2488 on_exit(fn ->
2489 Mix.shell(Mix.Shell.IO)
2490 :ok = File.rm(temp_file)
2491 end)
2492
2493 :ok
2494 end
2495
2496 clear_config([:instance, :dynamic_configuration]) do
2497 Pleroma.Config.put([:instance, :dynamic_configuration], true)
2498 end
2499
2500 clear_config([:feed, :post_title]) do
2501 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
2502 end
2503
2504 test "transfer settings to DB and to file", %{conn: conn} do
2505 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2506 ret_conn = get(conn, "/api/pleroma/admin/config/migrate_to_db")
2507 assert json_response(ret_conn, 200) == %{}
2508 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0
2509
2510 ret_conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
2511
2512 assert json_response(ret_conn, 200) == %{}
2513 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2514 end
2515 end
2516
2517 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2518 setup do
2519 user = insert(:user)
2520
2521 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2522 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2523 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2524
2525 insert(:note_activity, user: user, published: date1)
2526 insert(:note_activity, user: user, published: date2)
2527 insert(:note_activity, user: user, published: date3)
2528
2529 %{user: user}
2530 end
2531
2532 test "renders user's statuses", %{conn: conn, user: user} do
2533 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2534
2535 assert json_response(conn, 200) |> length() == 3
2536 end
2537
2538 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2539 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2540
2541 assert json_response(conn, 200) |> length() == 2
2542 end
2543
2544 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2545 {:ok, _private_status} =
2546 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2547
2548 {:ok, _public_status} =
2549 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2550
2551 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2552
2553 assert json_response(conn, 200) |> length() == 4
2554 end
2555
2556 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2557 {:ok, _private_status} =
2558 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2559
2560 {:ok, _public_status} =
2561 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2562
2563 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2564
2565 assert json_response(conn, 200) |> length() == 5
2566 end
2567 end
2568
2569 describe "GET /api/pleroma/admin/moderation_log" do
2570 setup do
2571 moderator = insert(:user, is_moderator: true)
2572
2573 %{moderator: moderator}
2574 end
2575
2576 test "returns the log", %{conn: conn, admin: admin} do
2577 Repo.insert(%ModerationLog{
2578 data: %{
2579 actor: %{
2580 "id" => admin.id,
2581 "nickname" => admin.nickname,
2582 "type" => "user"
2583 },
2584 action: "relay_follow",
2585 target: "https://example.org/relay"
2586 },
2587 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2588 })
2589
2590 Repo.insert(%ModerationLog{
2591 data: %{
2592 actor: %{
2593 "id" => admin.id,
2594 "nickname" => admin.nickname,
2595 "type" => "user"
2596 },
2597 action: "relay_unfollow",
2598 target: "https://example.org/relay"
2599 },
2600 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2601 })
2602
2603 conn = get(conn, "/api/pleroma/admin/moderation_log")
2604
2605 response = json_response(conn, 200)
2606 [first_entry, second_entry] = response["items"]
2607
2608 assert response["total"] == 2
2609 assert first_entry["data"]["action"] == "relay_unfollow"
2610
2611 assert first_entry["message"] ==
2612 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2613
2614 assert second_entry["data"]["action"] == "relay_follow"
2615
2616 assert second_entry["message"] ==
2617 "@#{admin.nickname} followed relay: https://example.org/relay"
2618 end
2619
2620 test "returns the log with pagination", %{conn: conn, admin: admin} do
2621 Repo.insert(%ModerationLog{
2622 data: %{
2623 actor: %{
2624 "id" => admin.id,
2625 "nickname" => admin.nickname,
2626 "type" => "user"
2627 },
2628 action: "relay_follow",
2629 target: "https://example.org/relay"
2630 },
2631 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2632 })
2633
2634 Repo.insert(%ModerationLog{
2635 data: %{
2636 actor: %{
2637 "id" => admin.id,
2638 "nickname" => admin.nickname,
2639 "type" => "user"
2640 },
2641 action: "relay_unfollow",
2642 target: "https://example.org/relay"
2643 },
2644 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2645 })
2646
2647 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
2648
2649 response1 = json_response(conn1, 200)
2650 [first_entry] = response1["items"]
2651
2652 assert response1["total"] == 2
2653 assert response1["items"] |> length() == 1
2654 assert first_entry["data"]["action"] == "relay_unfollow"
2655
2656 assert first_entry["message"] ==
2657 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2658
2659 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
2660
2661 response2 = json_response(conn2, 200)
2662 [second_entry] = response2["items"]
2663
2664 assert response2["total"] == 2
2665 assert response2["items"] |> length() == 1
2666 assert second_entry["data"]["action"] == "relay_follow"
2667
2668 assert second_entry["message"] ==
2669 "@#{admin.nickname} followed relay: https://example.org/relay"
2670 end
2671
2672 test "filters log by date", %{conn: conn, admin: admin} do
2673 first_date = "2017-08-15T15:47:06Z"
2674 second_date = "2017-08-20T15:47:06Z"
2675
2676 Repo.insert(%ModerationLog{
2677 data: %{
2678 actor: %{
2679 "id" => admin.id,
2680 "nickname" => admin.nickname,
2681 "type" => "user"
2682 },
2683 action: "relay_follow",
2684 target: "https://example.org/relay"
2685 },
2686 inserted_at: NaiveDateTime.from_iso8601!(first_date)
2687 })
2688
2689 Repo.insert(%ModerationLog{
2690 data: %{
2691 actor: %{
2692 "id" => admin.id,
2693 "nickname" => admin.nickname,
2694 "type" => "user"
2695 },
2696 action: "relay_unfollow",
2697 target: "https://example.org/relay"
2698 },
2699 inserted_at: NaiveDateTime.from_iso8601!(second_date)
2700 })
2701
2702 conn1 =
2703 get(
2704 conn,
2705 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
2706 )
2707
2708 response1 = json_response(conn1, 200)
2709 [first_entry] = response1["items"]
2710
2711 assert response1["total"] == 1
2712 assert first_entry["data"]["action"] == "relay_unfollow"
2713
2714 assert first_entry["message"] ==
2715 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2716 end
2717
2718 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
2719 Repo.insert(%ModerationLog{
2720 data: %{
2721 actor: %{
2722 "id" => admin.id,
2723 "nickname" => admin.nickname,
2724 "type" => "user"
2725 },
2726 action: "relay_follow",
2727 target: "https://example.org/relay"
2728 }
2729 })
2730
2731 Repo.insert(%ModerationLog{
2732 data: %{
2733 actor: %{
2734 "id" => moderator.id,
2735 "nickname" => moderator.nickname,
2736 "type" => "user"
2737 },
2738 action: "relay_unfollow",
2739 target: "https://example.org/relay"
2740 }
2741 })
2742
2743 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
2744
2745 response1 = json_response(conn1, 200)
2746 [first_entry] = response1["items"]
2747
2748 assert response1["total"] == 1
2749 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
2750 end
2751
2752 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
2753 ModerationLog.insert_log(%{
2754 actor: moderator,
2755 action: "relay_follow",
2756 target: "https://example.org/relay"
2757 })
2758
2759 ModerationLog.insert_log(%{
2760 actor: moderator,
2761 action: "relay_unfollow",
2762 target: "https://example.org/relay"
2763 })
2764
2765 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
2766
2767 response1 = json_response(conn1, 200)
2768 [first_entry] = response1["items"]
2769
2770 assert response1["total"] == 1
2771
2772 assert get_in(first_entry, ["data", "message"]) ==
2773 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
2774 end
2775 end
2776
2777 describe "PATCH /users/:nickname/force_password_reset" do
2778 test "sets password_reset_pending to true", %{conn: conn} do
2779 user = insert(:user)
2780 assert user.password_reset_pending == false
2781
2782 conn =
2783 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
2784
2785 assert json_response(conn, 204) == ""
2786
2787 ObanHelpers.perform_all()
2788
2789 assert User.get_by_id(user.id).password_reset_pending == true
2790 end
2791 end
2792
2793 describe "relays" do
2794 test "POST /relay", %{conn: conn, admin: admin} do
2795 conn =
2796 post(conn, "/api/pleroma/admin/relay", %{
2797 relay_url: "http://mastodon.example.org/users/admin"
2798 })
2799
2800 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2801
2802 log_entry = Repo.one(ModerationLog)
2803
2804 assert ModerationLog.get_log_entry_message(log_entry) ==
2805 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2806 end
2807
2808 test "GET /relay", %{conn: conn} do
2809 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
2810
2811 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
2812 |> Enum.each(fn ap_id ->
2813 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
2814 User.follow(relay_user, user)
2815 end)
2816
2817 conn = get(conn, "/api/pleroma/admin/relay")
2818
2819 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
2820 end
2821
2822 test "DELETE /relay", %{conn: conn, admin: admin} do
2823 post(conn, "/api/pleroma/admin/relay", %{
2824 relay_url: "http://mastodon.example.org/users/admin"
2825 })
2826
2827 conn =
2828 delete(conn, "/api/pleroma/admin/relay", %{
2829 relay_url: "http://mastodon.example.org/users/admin"
2830 })
2831
2832 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2833
2834 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
2835
2836 assert ModerationLog.get_log_entry_message(log_entry_one) ==
2837 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2838
2839 assert ModerationLog.get_log_entry_message(log_entry_two) ==
2840 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
2841 end
2842 end
2843
2844 describe "instances" do
2845 test "GET /instances/:instance/statuses", %{conn: conn} do
2846 user = insert(:user, local: false, nickname: "archaeme@archae.me")
2847 user2 = insert(:user, local: false, nickname: "test@test.com")
2848 insert_pair(:note_activity, user: user)
2849 insert(:note_activity, user: user2)
2850
2851 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
2852
2853 response = json_response(ret_conn, 200)
2854
2855 assert length(response) == 2
2856
2857 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
2858
2859 response = json_response(ret_conn, 200)
2860
2861 assert length(response) == 1
2862
2863 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
2864
2865 response = json_response(ret_conn, 200)
2866
2867 assert Enum.empty?(response)
2868 end
2869 end
2870
2871 describe "PATCH /confirm_email" do
2872 test "it confirms emails of two users", %{conn: conn, admin: admin} do
2873 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2874
2875 assert first_user.confirmation_pending == true
2876 assert second_user.confirmation_pending == true
2877
2878 ret_conn =
2879 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
2880 nicknames: [
2881 first_user.nickname,
2882 second_user.nickname
2883 ]
2884 })
2885
2886 assert ret_conn.status == 200
2887
2888 assert first_user.confirmation_pending == true
2889 assert second_user.confirmation_pending == true
2890
2891 log_entry = Repo.one(ModerationLog)
2892
2893 assert ModerationLog.get_log_entry_message(log_entry) ==
2894 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
2895 second_user.nickname
2896 }"
2897 end
2898 end
2899
2900 describe "PATCH /resend_confirmation_email" do
2901 test "it resend emails for two users", %{conn: conn, admin: admin} do
2902 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2903
2904 ret_conn =
2905 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
2906 nicknames: [
2907 first_user.nickname,
2908 second_user.nickname
2909 ]
2910 })
2911
2912 assert ret_conn.status == 200
2913
2914 log_entry = Repo.one(ModerationLog)
2915
2916 assert ModerationLog.get_log_entry_message(log_entry) ==
2917 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
2918 second_user.nickname
2919 }"
2920 end
2921 end
2922
2923 describe "POST /reports/:id/notes" do
2924 setup %{conn: conn, admin: admin} do
2925 [reporter, target_user] = insert_pair(:user)
2926 activity = insert(:note_activity, user: target_user)
2927
2928 {:ok, %{id: report_id}} =
2929 CommonAPI.report(reporter, %{
2930 "account_id" => target_user.id,
2931 "comment" => "I feel offended",
2932 "status_ids" => [activity.id]
2933 })
2934
2935 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
2936 content: "this is disgusting!"
2937 })
2938
2939 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
2940 content: "this is disgusting2!"
2941 })
2942
2943 %{
2944 admin_id: admin.id,
2945 report_id: report_id
2946 }
2947 end
2948
2949 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
2950 [note, _] = Repo.all(ReportNote)
2951
2952 assert %{
2953 activity_id: ^report_id,
2954 content: "this is disgusting!",
2955 user_id: ^admin_id
2956 } = note
2957 end
2958
2959 test "it returns reports with notes", %{conn: conn, admin: admin} do
2960 conn = get(conn, "/api/pleroma/admin/reports")
2961
2962 response = json_response(conn, 200)
2963 notes = hd(response["reports"])["notes"]
2964 [note, _] = notes
2965
2966 assert note["user"]["nickname"] == admin.nickname
2967 assert note["content"] == "this is disgusting!"
2968 assert note["created_at"]
2969 assert response["total"] == 1
2970 end
2971
2972 test "it deletes the note", %{conn: conn, report_id: report_id} do
2973 assert ReportNote |> Repo.all() |> length() == 2
2974
2975 [note, _] = Repo.all(ReportNote)
2976
2977 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
2978
2979 assert ReportNote |> Repo.all() |> length() == 1
2980 end
2981 end
2982 end
2983
2984 # Needed for testing
2985 defmodule Pleroma.Web.Endpoint.NotReal do
2986 end
2987
2988 defmodule Pleroma.Captcha.NotReal do
2989 end