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