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