don't use async with global mocks
[akkoma] / test / web / admin_api / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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 import ExUnit.CaptureLog
10 import Mock
11 import Pleroma.Factory
12
13 alias Pleroma.Activity
14 alias Pleroma.Config
15 alias Pleroma.ConfigDB
16 alias Pleroma.HTML
17 alias Pleroma.MFA
18 alias Pleroma.ModerationLog
19 alias Pleroma.Repo
20 alias Pleroma.ReportNote
21 alias Pleroma.Tests.ObanHelpers
22 alias Pleroma.User
23 alias Pleroma.UserInviteToken
24 alias Pleroma.Web
25 alias Pleroma.Web.ActivityPub.Relay
26 alias Pleroma.Web.CommonAPI
27 alias Pleroma.Web.MediaProxy
28
29 setup_all do
30 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
31
32 :ok
33 end
34
35 setup do
36 admin = insert(:user, is_admin: true)
37 token = insert(:oauth_admin_token, user: admin)
38
39 conn =
40 build_conn()
41 |> assign(:user, admin)
42 |> assign(:token, token)
43
44 {:ok, %{admin: admin, token: token, conn: conn}}
45 end
46
47 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
48 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
49
50 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
51 %{admin: admin} do
52 user = insert(:user)
53 url = "/api/pleroma/admin/users/#{user.nickname}"
54
55 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
56 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
57 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
58
59 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
60 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
61 bad_token3 = nil
62
63 for good_token <- [good_token1, good_token2, good_token3] do
64 conn =
65 build_conn()
66 |> assign(:user, admin)
67 |> assign(:token, good_token)
68 |> get(url)
69
70 assert json_response(conn, 200)
71 end
72
73 for good_token <- [good_token1, good_token2, good_token3] do
74 conn =
75 build_conn()
76 |> assign(:user, nil)
77 |> assign(:token, good_token)
78 |> get(url)
79
80 assert json_response(conn, :forbidden)
81 end
82
83 for bad_token <- [bad_token1, bad_token2, bad_token3] do
84 conn =
85 build_conn()
86 |> assign(:user, admin)
87 |> assign(:token, bad_token)
88 |> get(url)
89
90 assert json_response(conn, :forbidden)
91 end
92 end
93 end
94
95 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
96 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
97
98 test "GET /api/pleroma/admin/users/:nickname requires " <>
99 "read:accounts or admin:read:accounts or broader scope",
100 %{admin: admin} do
101 user = insert(:user)
102 url = "/api/pleroma/admin/users/#{user.nickname}"
103
104 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
105 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
106 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
107 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
108 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
109
110 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
111
112 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
113 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
114 bad_token3 = nil
115
116 for good_token <- good_tokens do
117 conn =
118 build_conn()
119 |> assign(:user, admin)
120 |> assign(:token, good_token)
121 |> get(url)
122
123 assert json_response(conn, 200)
124 end
125
126 for good_token <- good_tokens do
127 conn =
128 build_conn()
129 |> assign(:user, nil)
130 |> assign(:token, good_token)
131 |> get(url)
132
133 assert json_response(conn, :forbidden)
134 end
135
136 for bad_token <- [bad_token1, bad_token2, bad_token3] do
137 conn =
138 build_conn()
139 |> assign(:user, admin)
140 |> assign(:token, bad_token)
141 |> get(url)
142
143 assert json_response(conn, :forbidden)
144 end
145 end
146 end
147
148 describe "DELETE /api/pleroma/admin/users" do
149 test "single user", %{admin: admin, conn: conn} do
150 user = insert(:user)
151
152 with_mock Pleroma.Web.Federator,
153 publish: fn _ -> nil end do
154 conn =
155 conn
156 |> put_req_header("accept", "application/json")
157 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
158
159 ObanHelpers.perform_all()
160
161 assert User.get_by_nickname(user.nickname).deactivated
162
163 log_entry = Repo.one(ModerationLog)
164
165 assert ModerationLog.get_log_entry_message(log_entry) ==
166 "@#{admin.nickname} deleted users: @#{user.nickname}"
167
168 assert json_response(conn, 200) == [user.nickname]
169
170 assert called(Pleroma.Web.Federator.publish(:_))
171 end
172 end
173
174 test "multiple users", %{admin: admin, conn: conn} do
175 user_one = insert(:user)
176 user_two = insert(:user)
177
178 conn =
179 conn
180 |> put_req_header("accept", "application/json")
181 |> delete("/api/pleroma/admin/users", %{
182 nicknames: [user_one.nickname, user_two.nickname]
183 })
184
185 log_entry = Repo.one(ModerationLog)
186
187 assert ModerationLog.get_log_entry_message(log_entry) ==
188 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
189
190 response = json_response(conn, 200)
191 assert response -- [user_one.nickname, user_two.nickname] == []
192 end
193 end
194
195 describe "/api/pleroma/admin/users" do
196 test "Create", %{conn: conn} do
197 conn =
198 conn
199 |> put_req_header("accept", "application/json")
200 |> post("/api/pleroma/admin/users", %{
201 "users" => [
202 %{
203 "nickname" => "lain",
204 "email" => "lain@example.org",
205 "password" => "test"
206 },
207 %{
208 "nickname" => "lain2",
209 "email" => "lain2@example.org",
210 "password" => "test"
211 }
212 ]
213 })
214
215 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
216 assert response == ["success", "success"]
217
218 log_entry = Repo.one(ModerationLog)
219
220 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
221 end
222
223 test "Cannot create user with existing email", %{conn: conn} do
224 user = insert(:user)
225
226 conn =
227 conn
228 |> put_req_header("accept", "application/json")
229 |> post("/api/pleroma/admin/users", %{
230 "users" => [
231 %{
232 "nickname" => "lain",
233 "email" => user.email,
234 "password" => "test"
235 }
236 ]
237 })
238
239 assert json_response(conn, 409) == [
240 %{
241 "code" => 409,
242 "data" => %{
243 "email" => user.email,
244 "nickname" => "lain"
245 },
246 "error" => "email has already been taken",
247 "type" => "error"
248 }
249 ]
250 end
251
252 test "Cannot create user with existing nickname", %{conn: conn} do
253 user = insert(:user)
254
255 conn =
256 conn
257 |> put_req_header("accept", "application/json")
258 |> post("/api/pleroma/admin/users", %{
259 "users" => [
260 %{
261 "nickname" => user.nickname,
262 "email" => "someuser@plerama.social",
263 "password" => "test"
264 }
265 ]
266 })
267
268 assert json_response(conn, 409) == [
269 %{
270 "code" => 409,
271 "data" => %{
272 "email" => "someuser@plerama.social",
273 "nickname" => user.nickname
274 },
275 "error" => "nickname has already been taken",
276 "type" => "error"
277 }
278 ]
279 end
280
281 test "Multiple user creation works in transaction", %{conn: conn} do
282 user = insert(:user)
283
284 conn =
285 conn
286 |> put_req_header("accept", "application/json")
287 |> post("/api/pleroma/admin/users", %{
288 "users" => [
289 %{
290 "nickname" => "newuser",
291 "email" => "newuser@pleroma.social",
292 "password" => "test"
293 },
294 %{
295 "nickname" => "lain",
296 "email" => user.email,
297 "password" => "test"
298 }
299 ]
300 })
301
302 assert json_response(conn, 409) == [
303 %{
304 "code" => 409,
305 "data" => %{
306 "email" => user.email,
307 "nickname" => "lain"
308 },
309 "error" => "email has already been taken",
310 "type" => "error"
311 },
312 %{
313 "code" => 409,
314 "data" => %{
315 "email" => "newuser@pleroma.social",
316 "nickname" => "newuser"
317 },
318 "error" => "",
319 "type" => "error"
320 }
321 ]
322
323 assert User.get_by_nickname("newuser") === nil
324 end
325 end
326
327 describe "/api/pleroma/admin/users/:nickname" do
328 test "Show", %{conn: conn} do
329 user = insert(:user)
330
331 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
332
333 expected = %{
334 "deactivated" => false,
335 "id" => to_string(user.id),
336 "local" => true,
337 "nickname" => user.nickname,
338 "roles" => %{"admin" => false, "moderator" => false},
339 "tags" => [],
340 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
341 "display_name" => HTML.strip_tags(user.name || user.nickname),
342 "confirmation_pending" => false
343 }
344
345 assert expected == json_response(conn, 200)
346 end
347
348 test "when the user doesn't exist", %{conn: conn} do
349 user = build(:user)
350
351 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
352
353 assert "Not found" == json_response(conn, 404)
354 end
355 end
356
357 describe "/api/pleroma/admin/users/follow" do
358 test "allows to force-follow another user", %{admin: admin, conn: conn} do
359 user = insert(:user)
360 follower = insert(:user)
361
362 conn
363 |> put_req_header("accept", "application/json")
364 |> post("/api/pleroma/admin/users/follow", %{
365 "follower" => follower.nickname,
366 "followed" => user.nickname
367 })
368
369 user = User.get_cached_by_id(user.id)
370 follower = User.get_cached_by_id(follower.id)
371
372 assert User.following?(follower, user)
373
374 log_entry = Repo.one(ModerationLog)
375
376 assert ModerationLog.get_log_entry_message(log_entry) ==
377 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
378 end
379 end
380
381 describe "/api/pleroma/admin/users/unfollow" do
382 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
383 user = insert(:user)
384 follower = insert(:user)
385
386 User.follow(follower, user)
387
388 conn
389 |> put_req_header("accept", "application/json")
390 |> post("/api/pleroma/admin/users/unfollow", %{
391 "follower" => follower.nickname,
392 "followed" => user.nickname
393 })
394
395 user = User.get_cached_by_id(user.id)
396 follower = User.get_cached_by_id(follower.id)
397
398 refute User.following?(follower, user)
399
400 log_entry = Repo.one(ModerationLog)
401
402 assert ModerationLog.get_log_entry_message(log_entry) ==
403 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
404 end
405 end
406
407 describe "PUT /api/pleroma/admin/users/tag" do
408 setup %{conn: conn} do
409 user1 = insert(:user, %{tags: ["x"]})
410 user2 = insert(:user, %{tags: ["y"]})
411 user3 = insert(:user, %{tags: ["unchanged"]})
412
413 conn =
414 conn
415 |> put_req_header("accept", "application/json")
416 |> put(
417 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
418 "#{user2.nickname}&tags[]=foo&tags[]=bar"
419 )
420
421 %{conn: conn, user1: user1, user2: user2, user3: user3}
422 end
423
424 test "it appends specified tags to users with specified nicknames", %{
425 conn: conn,
426 admin: admin,
427 user1: user1,
428 user2: user2
429 } do
430 assert json_response(conn, :no_content)
431 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
432 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
433
434 log_entry = Repo.one(ModerationLog)
435
436 users =
437 [user1.nickname, user2.nickname]
438 |> Enum.map(&"@#{&1}")
439 |> Enum.join(", ")
440
441 tags = ["foo", "bar"] |> Enum.join(", ")
442
443 assert ModerationLog.get_log_entry_message(log_entry) ==
444 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
445 end
446
447 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
448 assert json_response(conn, :no_content)
449 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
450 end
451 end
452
453 describe "DELETE /api/pleroma/admin/users/tag" do
454 setup %{conn: conn} do
455 user1 = insert(:user, %{tags: ["x"]})
456 user2 = insert(:user, %{tags: ["y", "z"]})
457 user3 = insert(:user, %{tags: ["unchanged"]})
458
459 conn =
460 conn
461 |> put_req_header("accept", "application/json")
462 |> delete(
463 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
464 "#{user2.nickname}&tags[]=x&tags[]=z"
465 )
466
467 %{conn: conn, user1: user1, user2: user2, user3: user3}
468 end
469
470 test "it removes specified tags from users with specified nicknames", %{
471 conn: conn,
472 admin: admin,
473 user1: user1,
474 user2: user2
475 } do
476 assert json_response(conn, :no_content)
477 assert User.get_cached_by_id(user1.id).tags == []
478 assert User.get_cached_by_id(user2.id).tags == ["y"]
479
480 log_entry = Repo.one(ModerationLog)
481
482 users =
483 [user1.nickname, user2.nickname]
484 |> Enum.map(&"@#{&1}")
485 |> Enum.join(", ")
486
487 tags = ["x", "z"] |> Enum.join(", ")
488
489 assert ModerationLog.get_log_entry_message(log_entry) ==
490 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
491 end
492
493 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
494 assert json_response(conn, :no_content)
495 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
496 end
497 end
498
499 describe "/api/pleroma/admin/users/:nickname/permission_group" do
500 test "GET is giving user_info", %{admin: admin, conn: conn} do
501 conn =
502 conn
503 |> put_req_header("accept", "application/json")
504 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
505
506 assert json_response(conn, 200) == %{
507 "is_admin" => true,
508 "is_moderator" => false
509 }
510 end
511
512 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
513 user = insert(:user)
514
515 conn =
516 conn
517 |> put_req_header("accept", "application/json")
518 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
519
520 assert json_response(conn, 200) == %{
521 "is_admin" => true
522 }
523
524 log_entry = Repo.one(ModerationLog)
525
526 assert ModerationLog.get_log_entry_message(log_entry) ==
527 "@#{admin.nickname} made @#{user.nickname} admin"
528 end
529
530 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
531 user_one = insert(:user)
532 user_two = insert(:user)
533
534 conn =
535 conn
536 |> put_req_header("accept", "application/json")
537 |> post("/api/pleroma/admin/users/permission_group/admin", %{
538 nicknames: [user_one.nickname, user_two.nickname]
539 })
540
541 assert json_response(conn, 200) == %{"is_admin" => true}
542
543 log_entry = Repo.one(ModerationLog)
544
545 assert ModerationLog.get_log_entry_message(log_entry) ==
546 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
547 end
548
549 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
550 user = insert(:user, is_admin: true)
551
552 conn =
553 conn
554 |> put_req_header("accept", "application/json")
555 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
556
557 assert json_response(conn, 200) == %{"is_admin" => false}
558
559 log_entry = Repo.one(ModerationLog)
560
561 assert ModerationLog.get_log_entry_message(log_entry) ==
562 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
563 end
564
565 test "/:right DELETE, can remove from a permission group (multiple)", %{
566 admin: admin,
567 conn: conn
568 } do
569 user_one = insert(:user, is_admin: true)
570 user_two = insert(:user, is_admin: true)
571
572 conn =
573 conn
574 |> put_req_header("accept", "application/json")
575 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
576 nicknames: [user_one.nickname, user_two.nickname]
577 })
578
579 assert json_response(conn, 200) == %{"is_admin" => false}
580
581 log_entry = Repo.one(ModerationLog)
582
583 assert ModerationLog.get_log_entry_message(log_entry) ==
584 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
585 user_two.nickname
586 }"
587 end
588 end
589
590 describe "POST /api/pleroma/admin/email_invite, with valid config" do
591 setup do: clear_config([:instance, :registrations_open], false)
592 setup do: clear_config([:instance, :invites_enabled], true)
593
594 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
595 recipient_email = "foo@bar.com"
596 recipient_name = "J. D."
597
598 conn =
599 post(
600 conn,
601 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
602 )
603
604 assert json_response(conn, :no_content)
605
606 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
607 assert token_record
608 refute token_record.used
609
610 notify_email = Config.get([:instance, :notify_email])
611 instance_name = Config.get([:instance, :name])
612
613 email =
614 Pleroma.Emails.UserEmail.user_invitation_email(
615 admin,
616 token_record,
617 recipient_email,
618 recipient_name
619 )
620
621 Swoosh.TestAssertions.assert_email_sent(
622 from: {instance_name, notify_email},
623 to: {recipient_name, recipient_email},
624 html_body: email.html_body
625 )
626 end
627
628 test "it returns 403 if requested by a non-admin" do
629 non_admin_user = insert(:user)
630 token = insert(:oauth_token, user: non_admin_user)
631
632 conn =
633 build_conn()
634 |> assign(:user, non_admin_user)
635 |> assign(:token, token)
636 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
637
638 assert json_response(conn, :forbidden)
639 end
640
641 test "email with +", %{conn: conn, admin: admin} do
642 recipient_email = "foo+bar@baz.com"
643
644 conn
645 |> put_req_header("content-type", "application/json;charset=utf-8")
646 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
647 |> json_response(:no_content)
648
649 token_record =
650 Pleroma.UserInviteToken
651 |> Repo.all()
652 |> List.last()
653
654 assert token_record
655 refute token_record.used
656
657 notify_email = Config.get([:instance, :notify_email])
658 instance_name = Config.get([:instance, :name])
659
660 email =
661 Pleroma.Emails.UserEmail.user_invitation_email(
662 admin,
663 token_record,
664 recipient_email
665 )
666
667 Swoosh.TestAssertions.assert_email_sent(
668 from: {instance_name, notify_email},
669 to: recipient_email,
670 html_body: email.html_body
671 )
672 end
673 end
674
675 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
676 setup do: clear_config([:instance, :registrations_open])
677 setup do: clear_config([:instance, :invites_enabled])
678
679 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
680 Config.put([:instance, :registrations_open], false)
681 Config.put([:instance, :invites_enabled], false)
682
683 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
684
685 assert json_response(conn, :bad_request) ==
686 "To send invites you need to set the `invites_enabled` option to true."
687 end
688
689 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
690 Config.put([:instance, :registrations_open], true)
691 Config.put([:instance, :invites_enabled], true)
692
693 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
694
695 assert json_response(conn, :bad_request) ==
696 "To send invites you need to set the `registrations_open` option to false."
697 end
698 end
699
700 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
701 user = insert(:user)
702
703 conn =
704 conn
705 |> put_req_header("accept", "application/json")
706 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
707
708 resp = json_response(conn, 200)
709
710 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
711 end
712
713 describe "GET /api/pleroma/admin/users" do
714 test "renders users array for the first page", %{conn: conn, admin: admin} do
715 user = insert(:user, local: false, tags: ["foo", "bar"])
716 conn = get(conn, "/api/pleroma/admin/users?page=1")
717
718 users =
719 [
720 %{
721 "deactivated" => admin.deactivated,
722 "id" => admin.id,
723 "nickname" => admin.nickname,
724 "roles" => %{"admin" => true, "moderator" => false},
725 "local" => true,
726 "tags" => [],
727 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
728 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
729 "confirmation_pending" => false
730 },
731 %{
732 "deactivated" => user.deactivated,
733 "id" => user.id,
734 "nickname" => user.nickname,
735 "roles" => %{"admin" => false, "moderator" => false},
736 "local" => false,
737 "tags" => ["foo", "bar"],
738 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
739 "display_name" => HTML.strip_tags(user.name || user.nickname),
740 "confirmation_pending" => false
741 }
742 ]
743 |> Enum.sort_by(& &1["nickname"])
744
745 assert json_response(conn, 200) == %{
746 "count" => 2,
747 "page_size" => 50,
748 "users" => users
749 }
750 end
751
752 test "pagination works correctly with service users", %{conn: conn} do
753 service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
754 service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
755 insert_list(25, :user)
756
757 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
758 conn
759 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
760 |> json_response(200)
761
762 assert Enum.count(users1) == 10
763 assert service1 not in [users1]
764 assert service2 not in [users1]
765
766 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
767 conn
768 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
769 |> json_response(200)
770
771 assert Enum.count(users2) == 10
772 assert service1 not in [users2]
773 assert service2 not in [users2]
774
775 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
776 conn
777 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
778 |> json_response(200)
779
780 assert Enum.count(users3) == 6
781 assert service1 not in [users3]
782 assert service2 not in [users3]
783 end
784
785 test "renders empty array for the second page", %{conn: conn} do
786 insert(:user)
787
788 conn = get(conn, "/api/pleroma/admin/users?page=2")
789
790 assert json_response(conn, 200) == %{
791 "count" => 2,
792 "page_size" => 50,
793 "users" => []
794 }
795 end
796
797 test "regular search", %{conn: conn} do
798 user = insert(:user, nickname: "bob")
799
800 conn = get(conn, "/api/pleroma/admin/users?query=bo")
801
802 assert json_response(conn, 200) == %{
803 "count" => 1,
804 "page_size" => 50,
805 "users" => [
806 %{
807 "deactivated" => user.deactivated,
808 "id" => user.id,
809 "nickname" => user.nickname,
810 "roles" => %{"admin" => false, "moderator" => false},
811 "local" => true,
812 "tags" => [],
813 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
814 "display_name" => HTML.strip_tags(user.name || user.nickname),
815 "confirmation_pending" => false
816 }
817 ]
818 }
819 end
820
821 test "search by domain", %{conn: conn} do
822 user = insert(:user, nickname: "nickname@domain.com")
823 insert(:user)
824
825 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
826
827 assert json_response(conn, 200) == %{
828 "count" => 1,
829 "page_size" => 50,
830 "users" => [
831 %{
832 "deactivated" => user.deactivated,
833 "id" => user.id,
834 "nickname" => user.nickname,
835 "roles" => %{"admin" => false, "moderator" => false},
836 "local" => true,
837 "tags" => [],
838 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
839 "display_name" => HTML.strip_tags(user.name || user.nickname),
840 "confirmation_pending" => false
841 }
842 ]
843 }
844 end
845
846 test "search by full nickname", %{conn: conn} do
847 user = insert(:user, nickname: "nickname@domain.com")
848 insert(:user)
849
850 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
851
852 assert json_response(conn, 200) == %{
853 "count" => 1,
854 "page_size" => 50,
855 "users" => [
856 %{
857 "deactivated" => user.deactivated,
858 "id" => user.id,
859 "nickname" => user.nickname,
860 "roles" => %{"admin" => false, "moderator" => false},
861 "local" => true,
862 "tags" => [],
863 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
864 "display_name" => HTML.strip_tags(user.name || user.nickname),
865 "confirmation_pending" => false
866 }
867 ]
868 }
869 end
870
871 test "search by display name", %{conn: conn} do
872 user = insert(:user, name: "Display name")
873 insert(:user)
874
875 conn = get(conn, "/api/pleroma/admin/users?name=display")
876
877 assert json_response(conn, 200) == %{
878 "count" => 1,
879 "page_size" => 50,
880 "users" => [
881 %{
882 "deactivated" => user.deactivated,
883 "id" => user.id,
884 "nickname" => user.nickname,
885 "roles" => %{"admin" => false, "moderator" => false},
886 "local" => true,
887 "tags" => [],
888 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
889 "display_name" => HTML.strip_tags(user.name || user.nickname),
890 "confirmation_pending" => false
891 }
892 ]
893 }
894 end
895
896 test "search by email", %{conn: conn} do
897 user = insert(:user, email: "email@example.com")
898 insert(:user)
899
900 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
901
902 assert json_response(conn, 200) == %{
903 "count" => 1,
904 "page_size" => 50,
905 "users" => [
906 %{
907 "deactivated" => user.deactivated,
908 "id" => user.id,
909 "nickname" => user.nickname,
910 "roles" => %{"admin" => false, "moderator" => false},
911 "local" => true,
912 "tags" => [],
913 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
914 "display_name" => HTML.strip_tags(user.name || user.nickname),
915 "confirmation_pending" => false
916 }
917 ]
918 }
919 end
920
921 test "regular search with page size", %{conn: conn} do
922 user = insert(:user, nickname: "aalice")
923 user2 = insert(:user, nickname: "alice")
924
925 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
926
927 assert json_response(conn1, 200) == %{
928 "count" => 2,
929 "page_size" => 1,
930 "users" => [
931 %{
932 "deactivated" => user.deactivated,
933 "id" => user.id,
934 "nickname" => user.nickname,
935 "roles" => %{"admin" => false, "moderator" => false},
936 "local" => true,
937 "tags" => [],
938 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
939 "display_name" => HTML.strip_tags(user.name || user.nickname),
940 "confirmation_pending" => false
941 }
942 ]
943 }
944
945 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
946
947 assert json_response(conn2, 200) == %{
948 "count" => 2,
949 "page_size" => 1,
950 "users" => [
951 %{
952 "deactivated" => user2.deactivated,
953 "id" => user2.id,
954 "nickname" => user2.nickname,
955 "roles" => %{"admin" => false, "moderator" => false},
956 "local" => true,
957 "tags" => [],
958 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
959 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
960 "confirmation_pending" => false
961 }
962 ]
963 }
964 end
965
966 test "only local users" do
967 admin = insert(:user, is_admin: true, nickname: "john")
968 token = insert(:oauth_admin_token, user: admin)
969 user = insert(:user, nickname: "bob")
970
971 insert(:user, nickname: "bobb", local: false)
972
973 conn =
974 build_conn()
975 |> assign(:user, admin)
976 |> assign(:token, token)
977 |> get("/api/pleroma/admin/users?query=bo&filters=local")
978
979 assert json_response(conn, 200) == %{
980 "count" => 1,
981 "page_size" => 50,
982 "users" => [
983 %{
984 "deactivated" => user.deactivated,
985 "id" => user.id,
986 "nickname" => user.nickname,
987 "roles" => %{"admin" => false, "moderator" => false},
988 "local" => true,
989 "tags" => [],
990 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
991 "display_name" => HTML.strip_tags(user.name || user.nickname),
992 "confirmation_pending" => false
993 }
994 ]
995 }
996 end
997
998 test "only local users with no query", %{conn: conn, admin: old_admin} do
999 admin = insert(:user, is_admin: true, nickname: "john")
1000 user = insert(:user, nickname: "bob")
1001
1002 insert(:user, nickname: "bobb", local: false)
1003
1004 conn = get(conn, "/api/pleroma/admin/users?filters=local")
1005
1006 users =
1007 [
1008 %{
1009 "deactivated" => user.deactivated,
1010 "id" => user.id,
1011 "nickname" => user.nickname,
1012 "roles" => %{"admin" => false, "moderator" => false},
1013 "local" => true,
1014 "tags" => [],
1015 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1016 "display_name" => HTML.strip_tags(user.name || user.nickname),
1017 "confirmation_pending" => false
1018 },
1019 %{
1020 "deactivated" => admin.deactivated,
1021 "id" => admin.id,
1022 "nickname" => admin.nickname,
1023 "roles" => %{"admin" => true, "moderator" => false},
1024 "local" => true,
1025 "tags" => [],
1026 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1027 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1028 "confirmation_pending" => false
1029 },
1030 %{
1031 "deactivated" => false,
1032 "id" => old_admin.id,
1033 "local" => true,
1034 "nickname" => old_admin.nickname,
1035 "roles" => %{"admin" => true, "moderator" => false},
1036 "tags" => [],
1037 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1038 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1039 "confirmation_pending" => false
1040 }
1041 ]
1042 |> Enum.sort_by(& &1["nickname"])
1043
1044 assert json_response(conn, 200) == %{
1045 "count" => 3,
1046 "page_size" => 50,
1047 "users" => users
1048 }
1049 end
1050
1051 test "load only admins", %{conn: conn, admin: admin} do
1052 second_admin = insert(:user, is_admin: true)
1053 insert(:user)
1054 insert(:user)
1055
1056 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1057
1058 users =
1059 [
1060 %{
1061 "deactivated" => false,
1062 "id" => admin.id,
1063 "nickname" => admin.nickname,
1064 "roles" => %{"admin" => true, "moderator" => false},
1065 "local" => admin.local,
1066 "tags" => [],
1067 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1068 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1069 "confirmation_pending" => false
1070 },
1071 %{
1072 "deactivated" => false,
1073 "id" => second_admin.id,
1074 "nickname" => second_admin.nickname,
1075 "roles" => %{"admin" => true, "moderator" => false},
1076 "local" => second_admin.local,
1077 "tags" => [],
1078 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1079 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1080 "confirmation_pending" => false
1081 }
1082 ]
1083 |> Enum.sort_by(& &1["nickname"])
1084
1085 assert json_response(conn, 200) == %{
1086 "count" => 2,
1087 "page_size" => 50,
1088 "users" => users
1089 }
1090 end
1091
1092 test "load only moderators", %{conn: conn} do
1093 moderator = insert(:user, is_moderator: true)
1094 insert(:user)
1095 insert(:user)
1096
1097 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1098
1099 assert json_response(conn, 200) == %{
1100 "count" => 1,
1101 "page_size" => 50,
1102 "users" => [
1103 %{
1104 "deactivated" => false,
1105 "id" => moderator.id,
1106 "nickname" => moderator.nickname,
1107 "roles" => %{"admin" => false, "moderator" => true},
1108 "local" => moderator.local,
1109 "tags" => [],
1110 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1111 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1112 "confirmation_pending" => false
1113 }
1114 ]
1115 }
1116 end
1117
1118 test "load users with tags list", %{conn: conn} do
1119 user1 = insert(:user, tags: ["first"])
1120 user2 = insert(:user, tags: ["second"])
1121 insert(:user)
1122 insert(:user)
1123
1124 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1125
1126 users =
1127 [
1128 %{
1129 "deactivated" => false,
1130 "id" => user1.id,
1131 "nickname" => user1.nickname,
1132 "roles" => %{"admin" => false, "moderator" => false},
1133 "local" => user1.local,
1134 "tags" => ["first"],
1135 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1136 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1137 "confirmation_pending" => false
1138 },
1139 %{
1140 "deactivated" => false,
1141 "id" => user2.id,
1142 "nickname" => user2.nickname,
1143 "roles" => %{"admin" => false, "moderator" => false},
1144 "local" => user2.local,
1145 "tags" => ["second"],
1146 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1147 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1148 "confirmation_pending" => false
1149 }
1150 ]
1151 |> Enum.sort_by(& &1["nickname"])
1152
1153 assert json_response(conn, 200) == %{
1154 "count" => 2,
1155 "page_size" => 50,
1156 "users" => users
1157 }
1158 end
1159
1160 test "it works with multiple filters" do
1161 admin = insert(:user, nickname: "john", is_admin: true)
1162 token = insert(:oauth_admin_token, user: admin)
1163 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1164
1165 insert(:user, nickname: "ken", local: true, deactivated: true)
1166 insert(:user, nickname: "bobb", local: false, deactivated: false)
1167
1168 conn =
1169 build_conn()
1170 |> assign(:user, admin)
1171 |> assign(:token, token)
1172 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1173
1174 assert json_response(conn, 200) == %{
1175 "count" => 1,
1176 "page_size" => 50,
1177 "users" => [
1178 %{
1179 "deactivated" => user.deactivated,
1180 "id" => user.id,
1181 "nickname" => user.nickname,
1182 "roles" => %{"admin" => false, "moderator" => false},
1183 "local" => user.local,
1184 "tags" => [],
1185 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1186 "display_name" => HTML.strip_tags(user.name || user.nickname),
1187 "confirmation_pending" => false
1188 }
1189 ]
1190 }
1191 end
1192
1193 test "it omits relay user", %{admin: admin, conn: conn} do
1194 assert %User{} = Relay.get_actor()
1195
1196 conn = get(conn, "/api/pleroma/admin/users")
1197
1198 assert json_response(conn, 200) == %{
1199 "count" => 1,
1200 "page_size" => 50,
1201 "users" => [
1202 %{
1203 "deactivated" => admin.deactivated,
1204 "id" => admin.id,
1205 "nickname" => admin.nickname,
1206 "roles" => %{"admin" => true, "moderator" => false},
1207 "local" => true,
1208 "tags" => [],
1209 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1210 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1211 "confirmation_pending" => false
1212 }
1213 ]
1214 }
1215 end
1216 end
1217
1218 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1219 user_one = insert(:user, deactivated: true)
1220 user_two = insert(:user, deactivated: true)
1221
1222 conn =
1223 patch(
1224 conn,
1225 "/api/pleroma/admin/users/activate",
1226 %{nicknames: [user_one.nickname, user_two.nickname]}
1227 )
1228
1229 response = json_response(conn, 200)
1230 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1231
1232 log_entry = Repo.one(ModerationLog)
1233
1234 assert ModerationLog.get_log_entry_message(log_entry) ==
1235 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1236 end
1237
1238 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1239 user_one = insert(:user, deactivated: false)
1240 user_two = insert(:user, deactivated: false)
1241
1242 conn =
1243 patch(
1244 conn,
1245 "/api/pleroma/admin/users/deactivate",
1246 %{nicknames: [user_one.nickname, user_two.nickname]}
1247 )
1248
1249 response = json_response(conn, 200)
1250 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1251
1252 log_entry = Repo.one(ModerationLog)
1253
1254 assert ModerationLog.get_log_entry_message(log_entry) ==
1255 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1256 end
1257
1258 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1259 user = insert(:user)
1260
1261 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1262
1263 assert json_response(conn, 200) ==
1264 %{
1265 "deactivated" => !user.deactivated,
1266 "id" => user.id,
1267 "nickname" => user.nickname,
1268 "roles" => %{"admin" => false, "moderator" => false},
1269 "local" => true,
1270 "tags" => [],
1271 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1272 "display_name" => HTML.strip_tags(user.name || user.nickname),
1273 "confirmation_pending" => false
1274 }
1275
1276 log_entry = Repo.one(ModerationLog)
1277
1278 assert ModerationLog.get_log_entry_message(log_entry) ==
1279 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1280 end
1281
1282 describe "PUT disable_mfa" do
1283 test "returns 200 and disable 2fa", %{conn: conn} do
1284 user =
1285 insert(:user,
1286 multi_factor_authentication_settings: %MFA.Settings{
1287 enabled: true,
1288 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1289 }
1290 )
1291
1292 response =
1293 conn
1294 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1295 |> json_response(200)
1296
1297 assert response == user.nickname
1298 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1299
1300 refute mfa_settings.enabled
1301 refute mfa_settings.totp.confirmed
1302 end
1303
1304 test "returns 404 if user not found", %{conn: conn} do
1305 response =
1306 conn
1307 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1308 |> json_response(404)
1309
1310 assert response == "Not found"
1311 end
1312 end
1313
1314 describe "POST /api/pleroma/admin/users/invite_token" do
1315 test "without options", %{conn: conn} do
1316 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1317
1318 invite_json = json_response(conn, 200)
1319 invite = UserInviteToken.find_by_token!(invite_json["token"])
1320 refute invite.used
1321 refute invite.expires_at
1322 refute invite.max_use
1323 assert invite.invite_type == "one_time"
1324 end
1325
1326 test "with expires_at", %{conn: conn} do
1327 conn =
1328 post(conn, "/api/pleroma/admin/users/invite_token", %{
1329 "expires_at" => Date.to_string(Date.utc_today())
1330 })
1331
1332 invite_json = json_response(conn, 200)
1333 invite = UserInviteToken.find_by_token!(invite_json["token"])
1334
1335 refute invite.used
1336 assert invite.expires_at == Date.utc_today()
1337 refute invite.max_use
1338 assert invite.invite_type == "date_limited"
1339 end
1340
1341 test "with max_use", %{conn: conn} do
1342 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1343
1344 invite_json = json_response(conn, 200)
1345 invite = UserInviteToken.find_by_token!(invite_json["token"])
1346 refute invite.used
1347 refute invite.expires_at
1348 assert invite.max_use == 150
1349 assert invite.invite_type == "reusable"
1350 end
1351
1352 test "with max use and expires_at", %{conn: conn} do
1353 conn =
1354 post(conn, "/api/pleroma/admin/users/invite_token", %{
1355 "max_use" => 150,
1356 "expires_at" => Date.to_string(Date.utc_today())
1357 })
1358
1359 invite_json = json_response(conn, 200)
1360 invite = UserInviteToken.find_by_token!(invite_json["token"])
1361 refute invite.used
1362 assert invite.expires_at == Date.utc_today()
1363 assert invite.max_use == 150
1364 assert invite.invite_type == "reusable_date_limited"
1365 end
1366 end
1367
1368 describe "GET /api/pleroma/admin/users/invites" do
1369 test "no invites", %{conn: conn} do
1370 conn = get(conn, "/api/pleroma/admin/users/invites")
1371
1372 assert json_response(conn, 200) == %{"invites" => []}
1373 end
1374
1375 test "with invite", %{conn: conn} do
1376 {:ok, invite} = UserInviteToken.create_invite()
1377
1378 conn = get(conn, "/api/pleroma/admin/users/invites")
1379
1380 assert json_response(conn, 200) == %{
1381 "invites" => [
1382 %{
1383 "expires_at" => nil,
1384 "id" => invite.id,
1385 "invite_type" => "one_time",
1386 "max_use" => nil,
1387 "token" => invite.token,
1388 "used" => false,
1389 "uses" => 0
1390 }
1391 ]
1392 }
1393 end
1394 end
1395
1396 describe "POST /api/pleroma/admin/users/revoke_invite" do
1397 test "with token", %{conn: conn} do
1398 {:ok, invite} = UserInviteToken.create_invite()
1399
1400 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1401
1402 assert json_response(conn, 200) == %{
1403 "expires_at" => nil,
1404 "id" => invite.id,
1405 "invite_type" => "one_time",
1406 "max_use" => nil,
1407 "token" => invite.token,
1408 "used" => true,
1409 "uses" => 0
1410 }
1411 end
1412
1413 test "with invalid token", %{conn: conn} do
1414 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1415
1416 assert json_response(conn, :not_found) == "Not found"
1417 end
1418 end
1419
1420 describe "GET /api/pleroma/admin/reports/:id" do
1421 test "returns report by its id", %{conn: conn} do
1422 [reporter, target_user] = insert_pair(:user)
1423 activity = insert(:note_activity, user: target_user)
1424
1425 {:ok, %{id: report_id}} =
1426 CommonAPI.report(reporter, %{
1427 account_id: target_user.id,
1428 comment: "I feel offended",
1429 status_ids: [activity.id]
1430 })
1431
1432 response =
1433 conn
1434 |> get("/api/pleroma/admin/reports/#{report_id}")
1435 |> json_response(:ok)
1436
1437 assert response["id"] == report_id
1438 end
1439
1440 test "returns 404 when report id is invalid", %{conn: conn} do
1441 conn = get(conn, "/api/pleroma/admin/reports/test")
1442
1443 assert json_response(conn, :not_found) == "Not found"
1444 end
1445 end
1446
1447 describe "PATCH /api/pleroma/admin/reports" do
1448 setup do
1449 [reporter, target_user] = insert_pair(:user)
1450 activity = insert(:note_activity, user: target_user)
1451
1452 {:ok, %{id: report_id}} =
1453 CommonAPI.report(reporter, %{
1454 account_id: target_user.id,
1455 comment: "I feel offended",
1456 status_ids: [activity.id]
1457 })
1458
1459 {:ok, %{id: second_report_id}} =
1460 CommonAPI.report(reporter, %{
1461 account_id: target_user.id,
1462 comment: "I feel very offended",
1463 status_ids: [activity.id]
1464 })
1465
1466 %{
1467 id: report_id,
1468 second_report_id: second_report_id
1469 }
1470 end
1471
1472 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1473 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1474 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1475
1476 response =
1477 conn
1478 |> assign(:token, read_token)
1479 |> patch("/api/pleroma/admin/reports", %{
1480 "reports" => [%{"state" => "resolved", "id" => id}]
1481 })
1482 |> json_response(403)
1483
1484 assert response == %{
1485 "error" => "Insufficient permissions: admin:write:reports."
1486 }
1487
1488 conn
1489 |> assign(:token, write_token)
1490 |> patch("/api/pleroma/admin/reports", %{
1491 "reports" => [%{"state" => "resolved", "id" => id}]
1492 })
1493 |> json_response(:no_content)
1494 end
1495
1496 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1497 conn
1498 |> patch("/api/pleroma/admin/reports", %{
1499 "reports" => [
1500 %{"state" => "resolved", "id" => id}
1501 ]
1502 })
1503 |> json_response(:no_content)
1504
1505 activity = Activity.get_by_id(id)
1506 assert activity.data["state"] == "resolved"
1507
1508 log_entry = Repo.one(ModerationLog)
1509
1510 assert ModerationLog.get_log_entry_message(log_entry) ==
1511 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1512 end
1513
1514 test "closes report", %{conn: conn, id: id, admin: admin} do
1515 conn
1516 |> patch("/api/pleroma/admin/reports", %{
1517 "reports" => [
1518 %{"state" => "closed", "id" => id}
1519 ]
1520 })
1521 |> json_response(:no_content)
1522
1523 activity = Activity.get_by_id(id)
1524 assert activity.data["state"] == "closed"
1525
1526 log_entry = Repo.one(ModerationLog)
1527
1528 assert ModerationLog.get_log_entry_message(log_entry) ==
1529 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1530 end
1531
1532 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1533 conn =
1534 conn
1535 |> patch("/api/pleroma/admin/reports", %{
1536 "reports" => [
1537 %{"state" => "test", "id" => id}
1538 ]
1539 })
1540
1541 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1542 end
1543
1544 test "returns 404 when report is not exist", %{conn: conn} do
1545 conn =
1546 conn
1547 |> patch("/api/pleroma/admin/reports", %{
1548 "reports" => [
1549 %{"state" => "closed", "id" => "test"}
1550 ]
1551 })
1552
1553 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1554 end
1555
1556 test "updates state of multiple reports", %{
1557 conn: conn,
1558 id: id,
1559 admin: admin,
1560 second_report_id: second_report_id
1561 } do
1562 conn
1563 |> patch("/api/pleroma/admin/reports", %{
1564 "reports" => [
1565 %{"state" => "resolved", "id" => id},
1566 %{"state" => "closed", "id" => second_report_id}
1567 ]
1568 })
1569 |> json_response(:no_content)
1570
1571 activity = Activity.get_by_id(id)
1572 second_activity = Activity.get_by_id(second_report_id)
1573 assert activity.data["state"] == "resolved"
1574 assert second_activity.data["state"] == "closed"
1575
1576 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1577
1578 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1579 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1580
1581 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1582 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1583 end
1584 end
1585
1586 describe "GET /api/pleroma/admin/reports" do
1587 test "returns empty response when no reports created", %{conn: conn} do
1588 response =
1589 conn
1590 |> get("/api/pleroma/admin/reports")
1591 |> json_response(:ok)
1592
1593 assert Enum.empty?(response["reports"])
1594 assert response["total"] == 0
1595 end
1596
1597 test "returns reports", %{conn: conn} do
1598 [reporter, target_user] = insert_pair(:user)
1599 activity = insert(:note_activity, user: target_user)
1600
1601 {:ok, %{id: report_id}} =
1602 CommonAPI.report(reporter, %{
1603 account_id: target_user.id,
1604 comment: "I feel offended",
1605 status_ids: [activity.id]
1606 })
1607
1608 response =
1609 conn
1610 |> get("/api/pleroma/admin/reports")
1611 |> json_response(:ok)
1612
1613 [report] = response["reports"]
1614
1615 assert length(response["reports"]) == 1
1616 assert report["id"] == report_id
1617
1618 assert response["total"] == 1
1619 end
1620
1621 test "returns reports with specified state", %{conn: conn} do
1622 [reporter, target_user] = insert_pair(:user)
1623 activity = insert(:note_activity, user: target_user)
1624
1625 {:ok, %{id: first_report_id}} =
1626 CommonAPI.report(reporter, %{
1627 account_id: target_user.id,
1628 comment: "I feel offended",
1629 status_ids: [activity.id]
1630 })
1631
1632 {:ok, %{id: second_report_id}} =
1633 CommonAPI.report(reporter, %{
1634 account_id: target_user.id,
1635 comment: "I don't like this user"
1636 })
1637
1638 CommonAPI.update_report_state(second_report_id, "closed")
1639
1640 response =
1641 conn
1642 |> get("/api/pleroma/admin/reports", %{
1643 "state" => "open"
1644 })
1645 |> json_response(:ok)
1646
1647 [open_report] = response["reports"]
1648
1649 assert length(response["reports"]) == 1
1650 assert open_report["id"] == first_report_id
1651
1652 assert response["total"] == 1
1653
1654 response =
1655 conn
1656 |> get("/api/pleroma/admin/reports", %{
1657 "state" => "closed"
1658 })
1659 |> json_response(:ok)
1660
1661 [closed_report] = response["reports"]
1662
1663 assert length(response["reports"]) == 1
1664 assert closed_report["id"] == second_report_id
1665
1666 assert response["total"] == 1
1667
1668 response =
1669 conn
1670 |> get("/api/pleroma/admin/reports", %{
1671 "state" => "resolved"
1672 })
1673 |> json_response(:ok)
1674
1675 assert Enum.empty?(response["reports"])
1676 assert response["total"] == 0
1677 end
1678
1679 test "returns 403 when requested by a non-admin" do
1680 user = insert(:user)
1681 token = insert(:oauth_token, user: user)
1682
1683 conn =
1684 build_conn()
1685 |> assign(:user, user)
1686 |> assign(:token, token)
1687 |> get("/api/pleroma/admin/reports")
1688
1689 assert json_response(conn, :forbidden) ==
1690 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1691 end
1692
1693 test "returns 403 when requested by anonymous" do
1694 conn = get(build_conn(), "/api/pleroma/admin/reports")
1695
1696 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1697 end
1698 end
1699
1700 describe "GET /api/pleroma/admin/statuses/:id" do
1701 test "not found", %{conn: conn} do
1702 assert conn
1703 |> get("/api/pleroma/admin/statuses/not_found")
1704 |> json_response(:not_found)
1705 end
1706
1707 test "shows activity", %{conn: conn} do
1708 activity = insert(:note_activity)
1709
1710 response =
1711 conn
1712 |> get("/api/pleroma/admin/statuses/#{activity.id}")
1713 |> json_response(200)
1714
1715 assert response["id"] == activity.id
1716 end
1717 end
1718
1719 describe "PUT /api/pleroma/admin/statuses/:id" do
1720 setup do
1721 activity = insert(:note_activity)
1722
1723 %{id: activity.id}
1724 end
1725
1726 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1727 response =
1728 conn
1729 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1730 |> json_response(:ok)
1731
1732 assert response["sensitive"]
1733
1734 log_entry = Repo.one(ModerationLog)
1735
1736 assert ModerationLog.get_log_entry_message(log_entry) ==
1737 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1738
1739 response =
1740 conn
1741 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1742 |> json_response(:ok)
1743
1744 refute response["sensitive"]
1745 end
1746
1747 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1748 response =
1749 conn
1750 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1751 |> json_response(:ok)
1752
1753 assert response["visibility"] == "public"
1754
1755 log_entry = Repo.one(ModerationLog)
1756
1757 assert ModerationLog.get_log_entry_message(log_entry) ==
1758 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1759
1760 response =
1761 conn
1762 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1763 |> json_response(:ok)
1764
1765 assert response["visibility"] == "private"
1766
1767 response =
1768 conn
1769 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1770 |> json_response(:ok)
1771
1772 assert response["visibility"] == "unlisted"
1773 end
1774
1775 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1776 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1777
1778 assert json_response(conn, :bad_request) == "Unsupported visibility"
1779 end
1780 end
1781
1782 describe "DELETE /api/pleroma/admin/statuses/:id" do
1783 setup do
1784 activity = insert(:note_activity)
1785
1786 %{id: activity.id}
1787 end
1788
1789 test "deletes status", %{conn: conn, id: id, admin: admin} do
1790 conn
1791 |> delete("/api/pleroma/admin/statuses/#{id}")
1792 |> json_response(:ok)
1793
1794 refute Activity.get_by_id(id)
1795
1796 log_entry = Repo.one(ModerationLog)
1797
1798 assert ModerationLog.get_log_entry_message(log_entry) ==
1799 "@#{admin.nickname} deleted status ##{id}"
1800 end
1801
1802 test "returns 404 when the status does not exist", %{conn: conn} do
1803 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1804
1805 assert json_response(conn, :not_found) == "Not found"
1806 end
1807 end
1808
1809 describe "GET /api/pleroma/admin/config" do
1810 setup do: clear_config(:configurable_from_database, true)
1811
1812 test "when configuration from database is off", %{conn: conn} do
1813 Config.put(:configurable_from_database, false)
1814 conn = get(conn, "/api/pleroma/admin/config")
1815
1816 assert json_response(conn, 400) ==
1817 "To use this endpoint you need to enable configuration from database."
1818 end
1819
1820 test "with settings only in db", %{conn: conn} do
1821 config1 = insert(:config)
1822 config2 = insert(:config)
1823
1824 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1825
1826 %{
1827 "configs" => [
1828 %{
1829 "group" => ":pleroma",
1830 "key" => key1,
1831 "value" => _
1832 },
1833 %{
1834 "group" => ":pleroma",
1835 "key" => key2,
1836 "value" => _
1837 }
1838 ]
1839 } = json_response(conn, 200)
1840
1841 assert key1 == config1.key
1842 assert key2 == config2.key
1843 end
1844
1845 test "db is added to settings that are in db", %{conn: conn} do
1846 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1847
1848 %{"configs" => configs} =
1849 conn
1850 |> get("/api/pleroma/admin/config")
1851 |> json_response(200)
1852
1853 [instance_config] =
1854 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1855 group == ":pleroma" and key == ":instance"
1856 end)
1857
1858 assert instance_config["db"] == [":name"]
1859 end
1860
1861 test "merged default setting with db settings", %{conn: conn} do
1862 config1 = insert(:config)
1863 config2 = insert(:config)
1864
1865 config3 =
1866 insert(:config,
1867 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1868 )
1869
1870 %{"configs" => configs} =
1871 conn
1872 |> get("/api/pleroma/admin/config")
1873 |> json_response(200)
1874
1875 assert length(configs) > 3
1876
1877 received_configs =
1878 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1879 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1880 end)
1881
1882 assert length(received_configs) == 3
1883
1884 db_keys =
1885 config3.value
1886 |> ConfigDB.from_binary()
1887 |> Keyword.keys()
1888 |> ConfigDB.convert()
1889
1890 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1891 assert db in [[config1.key], [config2.key], db_keys]
1892
1893 assert value in [
1894 ConfigDB.from_binary_with_convert(config1.value),
1895 ConfigDB.from_binary_with_convert(config2.value),
1896 ConfigDB.from_binary_with_convert(config3.value)
1897 ]
1898 end)
1899 end
1900
1901 test "subkeys with full update right merge", %{conn: conn} do
1902 config1 =
1903 insert(:config,
1904 key: ":emoji",
1905 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1906 )
1907
1908 config2 =
1909 insert(:config,
1910 key: ":assets",
1911 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1912 )
1913
1914 %{"configs" => configs} =
1915 conn
1916 |> get("/api/pleroma/admin/config")
1917 |> json_response(200)
1918
1919 vals =
1920 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1921 group == ":pleroma" and key in [config1.key, config2.key]
1922 end)
1923
1924 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1925 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1926
1927 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1928 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1929
1930 assert emoji_val[:groups] == [a: 1, b: 2]
1931 assert assets_val[:mascots] == [a: 1, b: 2]
1932 end
1933 end
1934
1935 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1936 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1937
1938 assert json_response(conn, 400) ==
1939 "To use this endpoint you need to enable configuration from database."
1940 end
1941
1942 describe "POST /api/pleroma/admin/config" do
1943 setup do
1944 http = Application.get_env(:pleroma, :http)
1945
1946 on_exit(fn ->
1947 Application.delete_env(:pleroma, :key1)
1948 Application.delete_env(:pleroma, :key2)
1949 Application.delete_env(:pleroma, :key3)
1950 Application.delete_env(:pleroma, :key4)
1951 Application.delete_env(:pleroma, :keyaa1)
1952 Application.delete_env(:pleroma, :keyaa2)
1953 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1954 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1955 Application.put_env(:pleroma, :http, http)
1956 Application.put_env(:tesla, :adapter, Tesla.Mock)
1957 Restarter.Pleroma.refresh()
1958 end)
1959 end
1960
1961 setup do: clear_config(:configurable_from_database, true)
1962
1963 @tag capture_log: true
1964 test "create new config setting in db", %{conn: conn} do
1965 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1966 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1967
1968 conn =
1969 post(conn, "/api/pleroma/admin/config", %{
1970 configs: [
1971 %{group: ":pleroma", key: ":key1", value: "value1"},
1972 %{
1973 group: ":ueberauth",
1974 key: "Ueberauth",
1975 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1976 },
1977 %{
1978 group: ":pleroma",
1979 key: ":key2",
1980 value: %{
1981 ":nested_1" => "nested_value1",
1982 ":nested_2" => [
1983 %{":nested_22" => "nested_value222"},
1984 %{":nested_33" => %{":nested_44" => "nested_444"}}
1985 ]
1986 }
1987 },
1988 %{
1989 group: ":pleroma",
1990 key: ":key3",
1991 value: [
1992 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1993 %{"nested_4" => true}
1994 ]
1995 },
1996 %{
1997 group: ":pleroma",
1998 key: ":key4",
1999 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2000 },
2001 %{
2002 group: ":idna",
2003 key: ":key5",
2004 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2005 }
2006 ]
2007 })
2008
2009 assert json_response(conn, 200) == %{
2010 "configs" => [
2011 %{
2012 "group" => ":pleroma",
2013 "key" => ":key1",
2014 "value" => "value1",
2015 "db" => [":key1"]
2016 },
2017 %{
2018 "group" => ":ueberauth",
2019 "key" => "Ueberauth",
2020 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
2021 "db" => [":consumer_secret"]
2022 },
2023 %{
2024 "group" => ":pleroma",
2025 "key" => ":key2",
2026 "value" => %{
2027 ":nested_1" => "nested_value1",
2028 ":nested_2" => [
2029 %{":nested_22" => "nested_value222"},
2030 %{":nested_33" => %{":nested_44" => "nested_444"}}
2031 ]
2032 },
2033 "db" => [":key2"]
2034 },
2035 %{
2036 "group" => ":pleroma",
2037 "key" => ":key3",
2038 "value" => [
2039 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2040 %{"nested_4" => true}
2041 ],
2042 "db" => [":key3"]
2043 },
2044 %{
2045 "group" => ":pleroma",
2046 "key" => ":key4",
2047 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2048 "db" => [":key4"]
2049 },
2050 %{
2051 "group" => ":idna",
2052 "key" => ":key5",
2053 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2054 "db" => [":key5"]
2055 }
2056 ]
2057 }
2058
2059 assert Application.get_env(:pleroma, :key1) == "value1"
2060
2061 assert Application.get_env(:pleroma, :key2) == %{
2062 nested_1: "nested_value1",
2063 nested_2: [
2064 %{nested_22: "nested_value222"},
2065 %{nested_33: %{nested_44: "nested_444"}}
2066 ]
2067 }
2068
2069 assert Application.get_env(:pleroma, :key3) == [
2070 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2071 %{"nested_4" => true}
2072 ]
2073
2074 assert Application.get_env(:pleroma, :key4) == %{
2075 "endpoint" => "https://example.com",
2076 nested_5: :upload
2077 }
2078
2079 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2080 end
2081
2082 test "save configs setting without explicit key", %{conn: conn} do
2083 level = Application.get_env(:quack, :level)
2084 meta = Application.get_env(:quack, :meta)
2085 webhook_url = Application.get_env(:quack, :webhook_url)
2086
2087 on_exit(fn ->
2088 Application.put_env(:quack, :level, level)
2089 Application.put_env(:quack, :meta, meta)
2090 Application.put_env(:quack, :webhook_url, webhook_url)
2091 end)
2092
2093 conn =
2094 post(conn, "/api/pleroma/admin/config", %{
2095 configs: [
2096 %{
2097 group: ":quack",
2098 key: ":level",
2099 value: ":info"
2100 },
2101 %{
2102 group: ":quack",
2103 key: ":meta",
2104 value: [":none"]
2105 },
2106 %{
2107 group: ":quack",
2108 key: ":webhook_url",
2109 value: "https://hooks.slack.com/services/KEY"
2110 }
2111 ]
2112 })
2113
2114 assert json_response(conn, 200) == %{
2115 "configs" => [
2116 %{
2117 "group" => ":quack",
2118 "key" => ":level",
2119 "value" => ":info",
2120 "db" => [":level"]
2121 },
2122 %{
2123 "group" => ":quack",
2124 "key" => ":meta",
2125 "value" => [":none"],
2126 "db" => [":meta"]
2127 },
2128 %{
2129 "group" => ":quack",
2130 "key" => ":webhook_url",
2131 "value" => "https://hooks.slack.com/services/KEY",
2132 "db" => [":webhook_url"]
2133 }
2134 ]
2135 }
2136
2137 assert Application.get_env(:quack, :level) == :info
2138 assert Application.get_env(:quack, :meta) == [:none]
2139 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2140 end
2141
2142 test "saving config with partial update", %{conn: conn} do
2143 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2144
2145 conn =
2146 post(conn, "/api/pleroma/admin/config", %{
2147 configs: [
2148 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2149 ]
2150 })
2151
2152 assert json_response(conn, 200) == %{
2153 "configs" => [
2154 %{
2155 "group" => ":pleroma",
2156 "key" => ":key1",
2157 "value" => [
2158 %{"tuple" => [":key1", 1]},
2159 %{"tuple" => [":key2", 2]},
2160 %{"tuple" => [":key3", 3]}
2161 ],
2162 "db" => [":key1", ":key2", ":key3"]
2163 }
2164 ]
2165 }
2166 end
2167
2168 test "saving config which need pleroma reboot", %{conn: conn} do
2169 chat = Config.get(:chat)
2170 on_exit(fn -> Config.put(:chat, chat) end)
2171
2172 assert post(
2173 conn,
2174 "/api/pleroma/admin/config",
2175 %{
2176 configs: [
2177 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2178 ]
2179 }
2180 )
2181 |> json_response(200) == %{
2182 "configs" => [
2183 %{
2184 "db" => [":enabled"],
2185 "group" => ":pleroma",
2186 "key" => ":chat",
2187 "value" => [%{"tuple" => [":enabled", true]}]
2188 }
2189 ],
2190 "need_reboot" => true
2191 }
2192
2193 configs =
2194 conn
2195 |> get("/api/pleroma/admin/config")
2196 |> json_response(200)
2197
2198 assert configs["need_reboot"]
2199
2200 capture_log(fn ->
2201 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2202 end) =~ "pleroma restarted"
2203
2204 configs =
2205 conn
2206 |> get("/api/pleroma/admin/config")
2207 |> json_response(200)
2208
2209 assert configs["need_reboot"] == false
2210 end
2211
2212 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2213 chat = Config.get(:chat)
2214 on_exit(fn -> Config.put(:chat, chat) end)
2215
2216 assert post(
2217 conn,
2218 "/api/pleroma/admin/config",
2219 %{
2220 configs: [
2221 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2222 ]
2223 }
2224 )
2225 |> json_response(200) == %{
2226 "configs" => [
2227 %{
2228 "db" => [":enabled"],
2229 "group" => ":pleroma",
2230 "key" => ":chat",
2231 "value" => [%{"tuple" => [":enabled", true]}]
2232 }
2233 ],
2234 "need_reboot" => true
2235 }
2236
2237 assert post(conn, "/api/pleroma/admin/config", %{
2238 configs: [
2239 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2240 ]
2241 })
2242 |> json_response(200) == %{
2243 "configs" => [
2244 %{
2245 "group" => ":pleroma",
2246 "key" => ":key1",
2247 "value" => [
2248 %{"tuple" => [":key3", 3]}
2249 ],
2250 "db" => [":key3"]
2251 }
2252 ],
2253 "need_reboot" => true
2254 }
2255
2256 capture_log(fn ->
2257 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2258 end) =~ "pleroma restarted"
2259
2260 configs =
2261 conn
2262 |> get("/api/pleroma/admin/config")
2263 |> json_response(200)
2264
2265 assert configs["need_reboot"] == false
2266 end
2267
2268 test "saving config with nested merge", %{conn: conn} do
2269 config =
2270 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2271
2272 conn =
2273 post(conn, "/api/pleroma/admin/config", %{
2274 configs: [
2275 %{
2276 group: config.group,
2277 key: config.key,
2278 value: [
2279 %{"tuple" => [":key3", 3]},
2280 %{
2281 "tuple" => [
2282 ":key2",
2283 [
2284 %{"tuple" => [":k2", 1]},
2285 %{"tuple" => [":k3", 3]}
2286 ]
2287 ]
2288 }
2289 ]
2290 }
2291 ]
2292 })
2293
2294 assert json_response(conn, 200) == %{
2295 "configs" => [
2296 %{
2297 "group" => ":pleroma",
2298 "key" => ":key1",
2299 "value" => [
2300 %{"tuple" => [":key1", 1]},
2301 %{"tuple" => [":key3", 3]},
2302 %{
2303 "tuple" => [
2304 ":key2",
2305 [
2306 %{"tuple" => [":k1", 1]},
2307 %{"tuple" => [":k2", 1]},
2308 %{"tuple" => [":k3", 3]}
2309 ]
2310 ]
2311 }
2312 ],
2313 "db" => [":key1", ":key3", ":key2"]
2314 }
2315 ]
2316 }
2317 end
2318
2319 test "saving special atoms", %{conn: conn} do
2320 conn =
2321 post(conn, "/api/pleroma/admin/config", %{
2322 "configs" => [
2323 %{
2324 "group" => ":pleroma",
2325 "key" => ":key1",
2326 "value" => [
2327 %{
2328 "tuple" => [
2329 ":ssl_options",
2330 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2331 ]
2332 }
2333 ]
2334 }
2335 ]
2336 })
2337
2338 assert json_response(conn, 200) == %{
2339 "configs" => [
2340 %{
2341 "group" => ":pleroma",
2342 "key" => ":key1",
2343 "value" => [
2344 %{
2345 "tuple" => [
2346 ":ssl_options",
2347 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2348 ]
2349 }
2350 ],
2351 "db" => [":ssl_options"]
2352 }
2353 ]
2354 }
2355
2356 assert Application.get_env(:pleroma, :key1) == [
2357 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2358 ]
2359 end
2360
2361 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2362 backends = Application.get_env(:logger, :backends)
2363 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2364
2365 config =
2366 insert(:config,
2367 group: ":logger",
2368 key: ":backends",
2369 value: :erlang.term_to_binary([])
2370 )
2371
2372 Pleroma.Config.TransferTask.load_and_update_env([], false)
2373
2374 assert Application.get_env(:logger, :backends) == []
2375
2376 conn =
2377 post(conn, "/api/pleroma/admin/config", %{
2378 configs: [
2379 %{
2380 group: config.group,
2381 key: config.key,
2382 value: [":console"]
2383 }
2384 ]
2385 })
2386
2387 assert json_response(conn, 200) == %{
2388 "configs" => [
2389 %{
2390 "group" => ":logger",
2391 "key" => ":backends",
2392 "value" => [
2393 ":console"
2394 ],
2395 "db" => [":backends"]
2396 }
2397 ]
2398 }
2399
2400 assert Application.get_env(:logger, :backends) == [
2401 :console
2402 ]
2403 end
2404
2405 test "saving full setting if value is not keyword", %{conn: conn} do
2406 config =
2407 insert(:config,
2408 group: ":tesla",
2409 key: ":adapter",
2410 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2411 )
2412
2413 conn =
2414 post(conn, "/api/pleroma/admin/config", %{
2415 configs: [
2416 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2417 ]
2418 })
2419
2420 assert json_response(conn, 200) == %{
2421 "configs" => [
2422 %{
2423 "group" => ":tesla",
2424 "key" => ":adapter",
2425 "value" => "Tesla.Adapter.Httpc",
2426 "db" => [":adapter"]
2427 }
2428 ]
2429 }
2430 end
2431
2432 test "update config setting & delete with fallback to default value", %{
2433 conn: conn,
2434 admin: admin,
2435 token: token
2436 } do
2437 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2438 config1 = insert(:config, key: ":keyaa1")
2439 config2 = insert(:config, key: ":keyaa2")
2440
2441 config3 =
2442 insert(:config,
2443 group: ":ueberauth",
2444 key: "Ueberauth"
2445 )
2446
2447 conn =
2448 post(conn, "/api/pleroma/admin/config", %{
2449 configs: [
2450 %{group: config1.group, key: config1.key, value: "another_value"},
2451 %{group: config2.group, key: config2.key, value: "another_value"}
2452 ]
2453 })
2454
2455 assert json_response(conn, 200) == %{
2456 "configs" => [
2457 %{
2458 "group" => ":pleroma",
2459 "key" => config1.key,
2460 "value" => "another_value",
2461 "db" => [":keyaa1"]
2462 },
2463 %{
2464 "group" => ":pleroma",
2465 "key" => config2.key,
2466 "value" => "another_value",
2467 "db" => [":keyaa2"]
2468 }
2469 ]
2470 }
2471
2472 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2473 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2474 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2475
2476 conn =
2477 build_conn()
2478 |> assign(:user, admin)
2479 |> assign(:token, token)
2480 |> post("/api/pleroma/admin/config", %{
2481 configs: [
2482 %{group: config2.group, key: config2.key, delete: true},
2483 %{
2484 group: ":ueberauth",
2485 key: "Ueberauth",
2486 delete: true
2487 }
2488 ]
2489 })
2490
2491 assert json_response(conn, 200) == %{
2492 "configs" => []
2493 }
2494
2495 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2496 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2497 end
2498
2499 test "common config example", %{conn: conn} do
2500 conn =
2501 post(conn, "/api/pleroma/admin/config", %{
2502 configs: [
2503 %{
2504 "group" => ":pleroma",
2505 "key" => "Pleroma.Captcha.NotReal",
2506 "value" => [
2507 %{"tuple" => [":enabled", false]},
2508 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2509 %{"tuple" => [":seconds_valid", 60]},
2510 %{"tuple" => [":path", ""]},
2511 %{"tuple" => [":key1", nil]},
2512 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2513 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2514 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2515 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2516 %{"tuple" => [":name", "Pleroma"]}
2517 ]
2518 }
2519 ]
2520 })
2521
2522 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2523
2524 assert json_response(conn, 200) == %{
2525 "configs" => [
2526 %{
2527 "group" => ":pleroma",
2528 "key" => "Pleroma.Captcha.NotReal",
2529 "value" => [
2530 %{"tuple" => [":enabled", false]},
2531 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2532 %{"tuple" => [":seconds_valid", 60]},
2533 %{"tuple" => [":path", ""]},
2534 %{"tuple" => [":key1", nil]},
2535 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2536 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2537 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2538 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2539 %{"tuple" => [":name", "Pleroma"]}
2540 ],
2541 "db" => [
2542 ":enabled",
2543 ":method",
2544 ":seconds_valid",
2545 ":path",
2546 ":key1",
2547 ":regex1",
2548 ":regex2",
2549 ":regex3",
2550 ":regex4",
2551 ":name"
2552 ]
2553 }
2554 ]
2555 }
2556 end
2557
2558 test "tuples with more than two values", %{conn: conn} do
2559 conn =
2560 post(conn, "/api/pleroma/admin/config", %{
2561 configs: [
2562 %{
2563 "group" => ":pleroma",
2564 "key" => "Pleroma.Web.Endpoint.NotReal",
2565 "value" => [
2566 %{
2567 "tuple" => [
2568 ":http",
2569 [
2570 %{
2571 "tuple" => [
2572 ":key2",
2573 [
2574 %{
2575 "tuple" => [
2576 ":_",
2577 [
2578 %{
2579 "tuple" => [
2580 "/api/v1/streaming",
2581 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2582 []
2583 ]
2584 },
2585 %{
2586 "tuple" => [
2587 "/websocket",
2588 "Phoenix.Endpoint.CowboyWebSocket",
2589 %{
2590 "tuple" => [
2591 "Phoenix.Transports.WebSocket",
2592 %{
2593 "tuple" => [
2594 "Pleroma.Web.Endpoint",
2595 "Pleroma.Web.UserSocket",
2596 []
2597 ]
2598 }
2599 ]
2600 }
2601 ]
2602 },
2603 %{
2604 "tuple" => [
2605 ":_",
2606 "Phoenix.Endpoint.Cowboy2Handler",
2607 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2608 ]
2609 }
2610 ]
2611 ]
2612 }
2613 ]
2614 ]
2615 }
2616 ]
2617 ]
2618 }
2619 ]
2620 }
2621 ]
2622 })
2623
2624 assert json_response(conn, 200) == %{
2625 "configs" => [
2626 %{
2627 "group" => ":pleroma",
2628 "key" => "Pleroma.Web.Endpoint.NotReal",
2629 "value" => [
2630 %{
2631 "tuple" => [
2632 ":http",
2633 [
2634 %{
2635 "tuple" => [
2636 ":key2",
2637 [
2638 %{
2639 "tuple" => [
2640 ":_",
2641 [
2642 %{
2643 "tuple" => [
2644 "/api/v1/streaming",
2645 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2646 []
2647 ]
2648 },
2649 %{
2650 "tuple" => [
2651 "/websocket",
2652 "Phoenix.Endpoint.CowboyWebSocket",
2653 %{
2654 "tuple" => [
2655 "Phoenix.Transports.WebSocket",
2656 %{
2657 "tuple" => [
2658 "Pleroma.Web.Endpoint",
2659 "Pleroma.Web.UserSocket",
2660 []
2661 ]
2662 }
2663 ]
2664 }
2665 ]
2666 },
2667 %{
2668 "tuple" => [
2669 ":_",
2670 "Phoenix.Endpoint.Cowboy2Handler",
2671 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2672 ]
2673 }
2674 ]
2675 ]
2676 }
2677 ]
2678 ]
2679 }
2680 ]
2681 ]
2682 }
2683 ],
2684 "db" => [":http"]
2685 }
2686 ]
2687 }
2688 end
2689
2690 test "settings with nesting map", %{conn: conn} do
2691 conn =
2692 post(conn, "/api/pleroma/admin/config", %{
2693 configs: [
2694 %{
2695 "group" => ":pleroma",
2696 "key" => ":key1",
2697 "value" => [
2698 %{"tuple" => [":key2", "some_val"]},
2699 %{
2700 "tuple" => [
2701 ":key3",
2702 %{
2703 ":max_options" => 20,
2704 ":max_option_chars" => 200,
2705 ":min_expiration" => 0,
2706 ":max_expiration" => 31_536_000,
2707 "nested" => %{
2708 ":max_options" => 20,
2709 ":max_option_chars" => 200,
2710 ":min_expiration" => 0,
2711 ":max_expiration" => 31_536_000
2712 }
2713 }
2714 ]
2715 }
2716 ]
2717 }
2718 ]
2719 })
2720
2721 assert json_response(conn, 200) ==
2722 %{
2723 "configs" => [
2724 %{
2725 "group" => ":pleroma",
2726 "key" => ":key1",
2727 "value" => [
2728 %{"tuple" => [":key2", "some_val"]},
2729 %{
2730 "tuple" => [
2731 ":key3",
2732 %{
2733 ":max_expiration" => 31_536_000,
2734 ":max_option_chars" => 200,
2735 ":max_options" => 20,
2736 ":min_expiration" => 0,
2737 "nested" => %{
2738 ":max_expiration" => 31_536_000,
2739 ":max_option_chars" => 200,
2740 ":max_options" => 20,
2741 ":min_expiration" => 0
2742 }
2743 }
2744 ]
2745 }
2746 ],
2747 "db" => [":key2", ":key3"]
2748 }
2749 ]
2750 }
2751 end
2752
2753 test "value as map", %{conn: conn} do
2754 conn =
2755 post(conn, "/api/pleroma/admin/config", %{
2756 configs: [
2757 %{
2758 "group" => ":pleroma",
2759 "key" => ":key1",
2760 "value" => %{"key" => "some_val"}
2761 }
2762 ]
2763 })
2764
2765 assert json_response(conn, 200) ==
2766 %{
2767 "configs" => [
2768 %{
2769 "group" => ":pleroma",
2770 "key" => ":key1",
2771 "value" => %{"key" => "some_val"},
2772 "db" => [":key1"]
2773 }
2774 ]
2775 }
2776 end
2777
2778 test "queues key as atom", %{conn: conn} do
2779 conn =
2780 post(conn, "/api/pleroma/admin/config", %{
2781 configs: [
2782 %{
2783 "group" => ":oban",
2784 "key" => ":queues",
2785 "value" => [
2786 %{"tuple" => [":federator_incoming", 50]},
2787 %{"tuple" => [":federator_outgoing", 50]},
2788 %{"tuple" => [":web_push", 50]},
2789 %{"tuple" => [":mailer", 10]},
2790 %{"tuple" => [":transmogrifier", 20]},
2791 %{"tuple" => [":scheduled_activities", 10]},
2792 %{"tuple" => [":background", 5]}
2793 ]
2794 }
2795 ]
2796 })
2797
2798 assert json_response(conn, 200) == %{
2799 "configs" => [
2800 %{
2801 "group" => ":oban",
2802 "key" => ":queues",
2803 "value" => [
2804 %{"tuple" => [":federator_incoming", 50]},
2805 %{"tuple" => [":federator_outgoing", 50]},
2806 %{"tuple" => [":web_push", 50]},
2807 %{"tuple" => [":mailer", 10]},
2808 %{"tuple" => [":transmogrifier", 20]},
2809 %{"tuple" => [":scheduled_activities", 10]},
2810 %{"tuple" => [":background", 5]}
2811 ],
2812 "db" => [
2813 ":federator_incoming",
2814 ":federator_outgoing",
2815 ":web_push",
2816 ":mailer",
2817 ":transmogrifier",
2818 ":scheduled_activities",
2819 ":background"
2820 ]
2821 }
2822 ]
2823 }
2824 end
2825
2826 test "delete part of settings by atom subkeys", %{conn: conn} do
2827 config =
2828 insert(:config,
2829 key: ":keyaa1",
2830 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2831 )
2832
2833 conn =
2834 post(conn, "/api/pleroma/admin/config", %{
2835 configs: [
2836 %{
2837 group: config.group,
2838 key: config.key,
2839 subkeys: [":subkey1", ":subkey3"],
2840 delete: true
2841 }
2842 ]
2843 })
2844
2845 assert json_response(conn, 200) == %{
2846 "configs" => [
2847 %{
2848 "group" => ":pleroma",
2849 "key" => ":keyaa1",
2850 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2851 "db" => [":subkey2"]
2852 }
2853 ]
2854 }
2855 end
2856
2857 test "proxy tuple localhost", %{conn: conn} do
2858 conn =
2859 post(conn, "/api/pleroma/admin/config", %{
2860 configs: [
2861 %{
2862 group: ":pleroma",
2863 key: ":http",
2864 value: [
2865 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}
2866 ]
2867 }
2868 ]
2869 })
2870
2871 assert %{
2872 "configs" => [
2873 %{
2874 "group" => ":pleroma",
2875 "key" => ":http",
2876 "value" => value,
2877 "db" => db
2878 }
2879 ]
2880 } = json_response(conn, 200)
2881
2882 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value
2883 assert ":proxy_url" in db
2884 end
2885
2886 test "proxy tuple domain", %{conn: conn} do
2887 conn =
2888 post(conn, "/api/pleroma/admin/config", %{
2889 configs: [
2890 %{
2891 group: ":pleroma",
2892 key: ":http",
2893 value: [
2894 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}
2895 ]
2896 }
2897 ]
2898 })
2899
2900 assert %{
2901 "configs" => [
2902 %{
2903 "group" => ":pleroma",
2904 "key" => ":http",
2905 "value" => value,
2906 "db" => db
2907 }
2908 ]
2909 } = json_response(conn, 200)
2910
2911 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value
2912 assert ":proxy_url" in db
2913 end
2914
2915 test "proxy tuple ip", %{conn: conn} do
2916 conn =
2917 post(conn, "/api/pleroma/admin/config", %{
2918 configs: [
2919 %{
2920 group: ":pleroma",
2921 key: ":http",
2922 value: [
2923 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}
2924 ]
2925 }
2926 ]
2927 })
2928
2929 assert %{
2930 "configs" => [
2931 %{
2932 "group" => ":pleroma",
2933 "key" => ":http",
2934 "value" => value,
2935 "db" => db
2936 }
2937 ]
2938 } = json_response(conn, 200)
2939
2940 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
2941 assert ":proxy_url" in db
2942 end
2943 end
2944
2945 describe "GET /api/pleroma/admin/restart" do
2946 setup do: clear_config(:configurable_from_database, true)
2947
2948 test "pleroma restarts", %{conn: conn} do
2949 capture_log(fn ->
2950 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2951 end) =~ "pleroma restarted"
2952
2953 refute Restarter.Pleroma.need_reboot?()
2954 end
2955 end
2956
2957 test "need_reboot flag", %{conn: conn} do
2958 assert conn
2959 |> get("/api/pleroma/admin/need_reboot")
2960 |> json_response(200) == %{"need_reboot" => false}
2961
2962 Restarter.Pleroma.need_reboot()
2963
2964 assert conn
2965 |> get("/api/pleroma/admin/need_reboot")
2966 |> json_response(200) == %{"need_reboot" => true}
2967
2968 on_exit(fn -> Restarter.Pleroma.refresh() end)
2969 end
2970
2971 describe "GET /api/pleroma/admin/statuses" do
2972 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2973 blocked = insert(:user)
2974 user = insert(:user)
2975 User.block(admin, blocked)
2976
2977 {:ok, _} =
2978 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2979
2980 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2981 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2982 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2983 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2984
2985 response =
2986 conn
2987 |> get("/api/pleroma/admin/statuses")
2988 |> json_response(200)
2989
2990 refute "private" in Enum.map(response, & &1["visibility"])
2991 assert length(response) == 3
2992 end
2993
2994 test "returns only local statuses with local_only on", %{conn: conn} do
2995 user = insert(:user)
2996 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2997 insert(:note_activity, user: user, local: true)
2998 insert(:note_activity, user: remote_user, local: false)
2999
3000 response =
3001 conn
3002 |> get("/api/pleroma/admin/statuses?local_only=true")
3003 |> json_response(200)
3004
3005 assert length(response) == 1
3006 end
3007
3008 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
3009 user = insert(:user)
3010
3011 {:ok, _} =
3012 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
3013
3014 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
3015 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
3016 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
3017 assert json_response(conn, 200) |> length() == 3
3018 end
3019 end
3020
3021 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3022 setup do
3023 user = insert(:user)
3024
3025 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3026 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3027 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3028
3029 insert(:note_activity, user: user, published: date1)
3030 insert(:note_activity, user: user, published: date2)
3031 insert(:note_activity, user: user, published: date3)
3032
3033 %{user: user}
3034 end
3035
3036 test "renders user's statuses", %{conn: conn, user: user} do
3037 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3038
3039 assert json_response(conn, 200) |> length() == 3
3040 end
3041
3042 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3043 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3044
3045 assert json_response(conn, 200) |> length() == 2
3046 end
3047
3048 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3049 {:ok, _private_status} =
3050 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3051
3052 {:ok, _public_status} =
3053 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3054
3055 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3056
3057 assert json_response(conn, 200) |> length() == 4
3058 end
3059
3060 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3061 {:ok, _private_status} =
3062 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3063
3064 {:ok, _public_status} =
3065 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3066
3067 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3068
3069 assert json_response(conn, 200) |> length() == 5
3070 end
3071
3072 test "excludes reblogs by default", %{conn: conn, user: user} do
3073 other_user = insert(:user)
3074 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3075 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3076
3077 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3078 assert json_response(conn_res, 200) |> length() == 0
3079
3080 conn_res =
3081 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3082
3083 assert json_response(conn_res, 200) |> length() == 1
3084 end
3085 end
3086
3087 describe "GET /api/pleroma/admin/moderation_log" do
3088 setup do
3089 moderator = insert(:user, is_moderator: true)
3090
3091 %{moderator: moderator}
3092 end
3093
3094 test "returns the log", %{conn: conn, admin: admin} do
3095 Repo.insert(%ModerationLog{
3096 data: %{
3097 actor: %{
3098 "id" => admin.id,
3099 "nickname" => admin.nickname,
3100 "type" => "user"
3101 },
3102 action: "relay_follow",
3103 target: "https://example.org/relay"
3104 },
3105 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3106 })
3107
3108 Repo.insert(%ModerationLog{
3109 data: %{
3110 actor: %{
3111 "id" => admin.id,
3112 "nickname" => admin.nickname,
3113 "type" => "user"
3114 },
3115 action: "relay_unfollow",
3116 target: "https://example.org/relay"
3117 },
3118 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3119 })
3120
3121 conn = get(conn, "/api/pleroma/admin/moderation_log")
3122
3123 response = json_response(conn, 200)
3124 [first_entry, second_entry] = response["items"]
3125
3126 assert response["total"] == 2
3127 assert first_entry["data"]["action"] == "relay_unfollow"
3128
3129 assert first_entry["message"] ==
3130 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3131
3132 assert second_entry["data"]["action"] == "relay_follow"
3133
3134 assert second_entry["message"] ==
3135 "@#{admin.nickname} followed relay: https://example.org/relay"
3136 end
3137
3138 test "returns the log with pagination", %{conn: conn, admin: admin} do
3139 Repo.insert(%ModerationLog{
3140 data: %{
3141 actor: %{
3142 "id" => admin.id,
3143 "nickname" => admin.nickname,
3144 "type" => "user"
3145 },
3146 action: "relay_follow",
3147 target: "https://example.org/relay"
3148 },
3149 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3150 })
3151
3152 Repo.insert(%ModerationLog{
3153 data: %{
3154 actor: %{
3155 "id" => admin.id,
3156 "nickname" => admin.nickname,
3157 "type" => "user"
3158 },
3159 action: "relay_unfollow",
3160 target: "https://example.org/relay"
3161 },
3162 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3163 })
3164
3165 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3166
3167 response1 = json_response(conn1, 200)
3168 [first_entry] = response1["items"]
3169
3170 assert response1["total"] == 2
3171 assert response1["items"] |> length() == 1
3172 assert first_entry["data"]["action"] == "relay_unfollow"
3173
3174 assert first_entry["message"] ==
3175 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3176
3177 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3178
3179 response2 = json_response(conn2, 200)
3180 [second_entry] = response2["items"]
3181
3182 assert response2["total"] == 2
3183 assert response2["items"] |> length() == 1
3184 assert second_entry["data"]["action"] == "relay_follow"
3185
3186 assert second_entry["message"] ==
3187 "@#{admin.nickname} followed relay: https://example.org/relay"
3188 end
3189
3190 test "filters log by date", %{conn: conn, admin: admin} do
3191 first_date = "2017-08-15T15:47:06Z"
3192 second_date = "2017-08-20T15:47:06Z"
3193
3194 Repo.insert(%ModerationLog{
3195 data: %{
3196 actor: %{
3197 "id" => admin.id,
3198 "nickname" => admin.nickname,
3199 "type" => "user"
3200 },
3201 action: "relay_follow",
3202 target: "https://example.org/relay"
3203 },
3204 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3205 })
3206
3207 Repo.insert(%ModerationLog{
3208 data: %{
3209 actor: %{
3210 "id" => admin.id,
3211 "nickname" => admin.nickname,
3212 "type" => "user"
3213 },
3214 action: "relay_unfollow",
3215 target: "https://example.org/relay"
3216 },
3217 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3218 })
3219
3220 conn1 =
3221 get(
3222 conn,
3223 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3224 )
3225
3226 response1 = json_response(conn1, 200)
3227 [first_entry] = response1["items"]
3228
3229 assert response1["total"] == 1
3230 assert first_entry["data"]["action"] == "relay_unfollow"
3231
3232 assert first_entry["message"] ==
3233 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3234 end
3235
3236 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3237 Repo.insert(%ModerationLog{
3238 data: %{
3239 actor: %{
3240 "id" => admin.id,
3241 "nickname" => admin.nickname,
3242 "type" => "user"
3243 },
3244 action: "relay_follow",
3245 target: "https://example.org/relay"
3246 }
3247 })
3248
3249 Repo.insert(%ModerationLog{
3250 data: %{
3251 actor: %{
3252 "id" => moderator.id,
3253 "nickname" => moderator.nickname,
3254 "type" => "user"
3255 },
3256 action: "relay_unfollow",
3257 target: "https://example.org/relay"
3258 }
3259 })
3260
3261 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3262
3263 response1 = json_response(conn1, 200)
3264 [first_entry] = response1["items"]
3265
3266 assert response1["total"] == 1
3267 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3268 end
3269
3270 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3271 ModerationLog.insert_log(%{
3272 actor: moderator,
3273 action: "relay_follow",
3274 target: "https://example.org/relay"
3275 })
3276
3277 ModerationLog.insert_log(%{
3278 actor: moderator,
3279 action: "relay_unfollow",
3280 target: "https://example.org/relay"
3281 })
3282
3283 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3284
3285 response1 = json_response(conn1, 200)
3286 [first_entry] = response1["items"]
3287
3288 assert response1["total"] == 1
3289
3290 assert get_in(first_entry, ["data", "message"]) ==
3291 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3292 end
3293 end
3294
3295 describe "GET /users/:nickname/credentials" do
3296 test "gets the user credentials", %{conn: conn} do
3297 user = insert(:user)
3298 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3299
3300 response = assert json_response(conn, 200)
3301 assert response["email"] == user.email
3302 end
3303
3304 test "returns 403 if requested by a non-admin" do
3305 user = insert(:user)
3306
3307 conn =
3308 build_conn()
3309 |> assign(:user, user)
3310 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3311
3312 assert json_response(conn, :forbidden)
3313 end
3314 end
3315
3316 describe "PATCH /users/:nickname/credentials" do
3317 test "changes password and email", %{conn: conn, admin: admin} do
3318 user = insert(:user)
3319 assert user.password_reset_pending == false
3320
3321 conn =
3322 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3323 "password" => "new_password",
3324 "email" => "new_email@example.com",
3325 "name" => "new_name"
3326 })
3327
3328 assert json_response(conn, 200) == %{"status" => "success"}
3329
3330 ObanHelpers.perform_all()
3331
3332 updated_user = User.get_by_id(user.id)
3333
3334 assert updated_user.email == "new_email@example.com"
3335 assert updated_user.name == "new_name"
3336 assert updated_user.password_hash != user.password_hash
3337 assert updated_user.password_reset_pending == true
3338
3339 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3340
3341 assert ModerationLog.get_log_entry_message(log_entry1) ==
3342 "@#{admin.nickname} updated users: @#{user.nickname}"
3343
3344 assert ModerationLog.get_log_entry_message(log_entry2) ==
3345 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3346 end
3347
3348 test "returns 403 if requested by a non-admin" do
3349 user = insert(:user)
3350
3351 conn =
3352 build_conn()
3353 |> assign(:user, user)
3354 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3355 "password" => "new_password",
3356 "email" => "new_email@example.com",
3357 "name" => "new_name"
3358 })
3359
3360 assert json_response(conn, :forbidden)
3361 end
3362 end
3363
3364 describe "PATCH /users/:nickname/force_password_reset" do
3365 test "sets password_reset_pending to true", %{conn: conn} do
3366 user = insert(:user)
3367 assert user.password_reset_pending == false
3368
3369 conn =
3370 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3371
3372 assert json_response(conn, 204) == ""
3373
3374 ObanHelpers.perform_all()
3375
3376 assert User.get_by_id(user.id).password_reset_pending == true
3377 end
3378 end
3379
3380 describe "relays" do
3381 test "POST /relay", %{conn: conn, admin: admin} do
3382 conn =
3383 post(conn, "/api/pleroma/admin/relay", %{
3384 relay_url: "http://mastodon.example.org/users/admin"
3385 })
3386
3387 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3388
3389 log_entry = Repo.one(ModerationLog)
3390
3391 assert ModerationLog.get_log_entry_message(log_entry) ==
3392 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3393 end
3394
3395 test "GET /relay", %{conn: conn} do
3396 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3397
3398 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3399 |> Enum.each(fn ap_id ->
3400 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3401 User.follow(relay_user, user)
3402 end)
3403
3404 conn = get(conn, "/api/pleroma/admin/relay")
3405
3406 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3407 end
3408
3409 test "DELETE /relay", %{conn: conn, admin: admin} do
3410 post(conn, "/api/pleroma/admin/relay", %{
3411 relay_url: "http://mastodon.example.org/users/admin"
3412 })
3413
3414 conn =
3415 delete(conn, "/api/pleroma/admin/relay", %{
3416 relay_url: "http://mastodon.example.org/users/admin"
3417 })
3418
3419 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3420
3421 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3422
3423 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3424 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3425
3426 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3427 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3428 end
3429 end
3430
3431 describe "instances" do
3432 test "GET /instances/:instance/statuses", %{conn: conn} do
3433 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3434 user2 = insert(:user, local: false, nickname: "test@test.com")
3435 insert_pair(:note_activity, user: user)
3436 activity = insert(:note_activity, user: user2)
3437
3438 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3439
3440 response = json_response(ret_conn, 200)
3441
3442 assert length(response) == 2
3443
3444 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3445
3446 response = json_response(ret_conn, 200)
3447
3448 assert length(response) == 1
3449
3450 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3451
3452 response = json_response(ret_conn, 200)
3453
3454 assert Enum.empty?(response)
3455
3456 CommonAPI.repeat(activity.id, user)
3457
3458 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3459 response = json_response(ret_conn, 200)
3460 assert length(response) == 2
3461
3462 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3463 response = json_response(ret_conn, 200)
3464 assert length(response) == 3
3465 end
3466 end
3467
3468 describe "PATCH /confirm_email" do
3469 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3470 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3471
3472 assert first_user.confirmation_pending == true
3473 assert second_user.confirmation_pending == true
3474
3475 ret_conn =
3476 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3477 nicknames: [
3478 first_user.nickname,
3479 second_user.nickname
3480 ]
3481 })
3482
3483 assert ret_conn.status == 200
3484
3485 assert first_user.confirmation_pending == true
3486 assert second_user.confirmation_pending == true
3487
3488 log_entry = Repo.one(ModerationLog)
3489
3490 assert ModerationLog.get_log_entry_message(log_entry) ==
3491 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3492 second_user.nickname
3493 }"
3494 end
3495 end
3496
3497 describe "PATCH /resend_confirmation_email" do
3498 test "it resend emails for two users", %{conn: conn, admin: admin} do
3499 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3500
3501 ret_conn =
3502 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3503 nicknames: [
3504 first_user.nickname,
3505 second_user.nickname
3506 ]
3507 })
3508
3509 assert ret_conn.status == 200
3510
3511 log_entry = Repo.one(ModerationLog)
3512
3513 assert ModerationLog.get_log_entry_message(log_entry) ==
3514 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3515 second_user.nickname
3516 }"
3517 end
3518 end
3519
3520 describe "POST /reports/:id/notes" do
3521 setup %{conn: conn, admin: admin} do
3522 [reporter, target_user] = insert_pair(:user)
3523 activity = insert(:note_activity, user: target_user)
3524
3525 {:ok, %{id: report_id}} =
3526 CommonAPI.report(reporter, %{
3527 account_id: target_user.id,
3528 comment: "I feel offended",
3529 status_ids: [activity.id]
3530 })
3531
3532 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3533 content: "this is disgusting!"
3534 })
3535
3536 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3537 content: "this is disgusting2!"
3538 })
3539
3540 %{
3541 admin_id: admin.id,
3542 report_id: report_id
3543 }
3544 end
3545
3546 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3547 [note, _] = Repo.all(ReportNote)
3548
3549 assert %{
3550 activity_id: ^report_id,
3551 content: "this is disgusting!",
3552 user_id: ^admin_id
3553 } = note
3554 end
3555
3556 test "it returns reports with notes", %{conn: conn, admin: admin} do
3557 conn = get(conn, "/api/pleroma/admin/reports")
3558
3559 response = json_response(conn, 200)
3560 notes = hd(response["reports"])["notes"]
3561 [note, _] = notes
3562
3563 assert note["user"]["nickname"] == admin.nickname
3564 assert note["content"] == "this is disgusting!"
3565 assert note["created_at"]
3566 assert response["total"] == 1
3567 end
3568
3569 test "it deletes the note", %{conn: conn, report_id: report_id} do
3570 assert ReportNote |> Repo.all() |> length() == 2
3571
3572 [note, _] = Repo.all(ReportNote)
3573
3574 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3575
3576 assert ReportNote |> Repo.all() |> length() == 1
3577 end
3578 end
3579
3580 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3581 admin = insert(:user, is_admin: true)
3582
3583 conn =
3584 assign(conn, :user, admin)
3585 |> get("/api/pleroma/admin/config/descriptions")
3586
3587 assert [child | _others] = json_response(conn, 200)
3588
3589 assert child["children"]
3590 assert child["key"]
3591 assert String.starts_with?(child["group"], ":")
3592 assert child["description"]
3593 end
3594
3595 describe "/api/pleroma/admin/stats" do
3596 test "status visibility count", %{conn: conn} do
3597 admin = insert(:user, is_admin: true)
3598 user = insert(:user)
3599 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3600 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3601 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3602
3603 response =
3604 conn
3605 |> assign(:user, admin)
3606 |> get("/api/pleroma/admin/stats")
3607 |> json_response(200)
3608
3609 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3610 response["status_visibility"]
3611 end
3612 end
3613
3614 describe "POST /api/pleroma/admin/oauth_app" do
3615 test "errors", %{conn: conn} do
3616 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3617
3618 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3619 end
3620
3621 test "success", %{conn: conn} do
3622 base_url = Web.base_url()
3623 app_name = "Trusted app"
3624
3625 response =
3626 conn
3627 |> post("/api/pleroma/admin/oauth_app", %{
3628 name: app_name,
3629 redirect_uris: base_url
3630 })
3631 |> json_response(200)
3632
3633 assert %{
3634 "client_id" => _,
3635 "client_secret" => _,
3636 "name" => ^app_name,
3637 "redirect_uri" => ^base_url,
3638 "trusted" => false
3639 } = response
3640 end
3641
3642 test "with trusted", %{conn: conn} do
3643 base_url = Web.base_url()
3644 app_name = "Trusted app"
3645
3646 response =
3647 conn
3648 |> post("/api/pleroma/admin/oauth_app", %{
3649 name: app_name,
3650 redirect_uris: base_url,
3651 trusted: true
3652 })
3653 |> json_response(200)
3654
3655 assert %{
3656 "client_id" => _,
3657 "client_secret" => _,
3658 "name" => ^app_name,
3659 "redirect_uri" => ^base_url,
3660 "trusted" => true
3661 } = response
3662 end
3663 end
3664
3665 describe "GET /api/pleroma/admin/oauth_app" do
3666 setup do
3667 app = insert(:oauth_app)
3668 {:ok, app: app}
3669 end
3670
3671 test "list", %{conn: conn} do
3672 response =
3673 conn
3674 |> get("/api/pleroma/admin/oauth_app")
3675 |> json_response(200)
3676
3677 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3678
3679 assert length(apps) == count
3680 end
3681
3682 test "with page size", %{conn: conn} do
3683 insert(:oauth_app)
3684 page_size = 1
3685
3686 response =
3687 conn
3688 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3689 |> json_response(200)
3690
3691 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3692
3693 assert length(apps) == page_size
3694 end
3695
3696 test "search by client name", %{conn: conn, app: app} do
3697 response =
3698 conn
3699 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3700 |> json_response(200)
3701
3702 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3703
3704 assert returned["client_id"] == app.client_id
3705 assert returned["name"] == app.client_name
3706 end
3707
3708 test "search by client id", %{conn: conn, app: app} do
3709 response =
3710 conn
3711 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3712 |> json_response(200)
3713
3714 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3715
3716 assert returned["client_id"] == app.client_id
3717 assert returned["name"] == app.client_name
3718 end
3719
3720 test "only trusted", %{conn: conn} do
3721 app = insert(:oauth_app, trusted: true)
3722
3723 response =
3724 conn
3725 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3726 |> json_response(200)
3727
3728 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3729
3730 assert returned["client_id"] == app.client_id
3731 assert returned["name"] == app.client_name
3732 end
3733 end
3734
3735 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3736 test "with id", %{conn: conn} do
3737 app = insert(:oauth_app)
3738
3739 response =
3740 conn
3741 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3742 |> json_response(:no_content)
3743
3744 assert response == ""
3745 end
3746
3747 test "with non existance id", %{conn: conn} do
3748 response =
3749 conn
3750 |> delete("/api/pleroma/admin/oauth_app/0")
3751 |> json_response(:bad_request)
3752
3753 assert response == ""
3754 end
3755 end
3756
3757 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3758 test "with id", %{conn: conn} do
3759 app = insert(:oauth_app)
3760
3761 name = "another name"
3762 url = "https://example.com"
3763 scopes = ["admin"]
3764 id = app.id
3765 website = "http://website.com"
3766
3767 response =
3768 conn
3769 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3770 name: name,
3771 trusted: true,
3772 redirect_uris: url,
3773 scopes: scopes,
3774 website: website
3775 })
3776 |> json_response(200)
3777
3778 assert %{
3779 "client_id" => _,
3780 "client_secret" => _,
3781 "id" => ^id,
3782 "name" => ^name,
3783 "redirect_uri" => ^url,
3784 "trusted" => true,
3785 "website" => ^website
3786 } = response
3787 end
3788
3789 test "without id", %{conn: conn} do
3790 response =
3791 conn
3792 |> patch("/api/pleroma/admin/oauth_app/0")
3793 |> json_response(:bad_request)
3794
3795 assert response == ""
3796 end
3797 end
3798 end
3799
3800 # Needed for testing
3801 defmodule Pleroma.Web.Endpoint.NotReal do
3802 end
3803
3804 defmodule Pleroma.Captcha.NotReal do
3805 end