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