Merge remote-tracking branch 'remotes/origin/develop' into restricted-relations-embedding
[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 %{"tuple" => [":send_user_agent", false]}
2867 ]
2868 }
2869 ]
2870 })
2871
2872 assert json_response(conn, 200) == %{
2873 "configs" => [
2874 %{
2875 "group" => ":pleroma",
2876 "key" => ":http",
2877 "value" => [
2878 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2879 %{"tuple" => [":send_user_agent", false]}
2880 ],
2881 "db" => [":proxy_url", ":send_user_agent"]
2882 }
2883 ]
2884 }
2885 end
2886
2887 test "proxy tuple domain", %{conn: conn} do
2888 conn =
2889 post(conn, "/api/pleroma/admin/config", %{
2890 configs: [
2891 %{
2892 group: ":pleroma",
2893 key: ":http",
2894 value: [
2895 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2896 %{"tuple" => [":send_user_agent", false]}
2897 ]
2898 }
2899 ]
2900 })
2901
2902 assert json_response(conn, 200) == %{
2903 "configs" => [
2904 %{
2905 "group" => ":pleroma",
2906 "key" => ":http",
2907 "value" => [
2908 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2909 %{"tuple" => [":send_user_agent", false]}
2910 ],
2911 "db" => [":proxy_url", ":send_user_agent"]
2912 }
2913 ]
2914 }
2915 end
2916
2917 test "proxy tuple ip", %{conn: conn} do
2918 conn =
2919 post(conn, "/api/pleroma/admin/config", %{
2920 configs: [
2921 %{
2922 group: ":pleroma",
2923 key: ":http",
2924 value: [
2925 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2926 %{"tuple" => [":send_user_agent", false]}
2927 ]
2928 }
2929 ]
2930 })
2931
2932 assert json_response(conn, 200) == %{
2933 "configs" => [
2934 %{
2935 "group" => ":pleroma",
2936 "key" => ":http",
2937 "value" => [
2938 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2939 %{"tuple" => [":send_user_agent", false]}
2940 ],
2941 "db" => [":proxy_url", ":send_user_agent"]
2942 }
2943 ]
2944 }
2945 end
2946 end
2947
2948 describe "GET /api/pleroma/admin/restart" do
2949 setup do: clear_config(:configurable_from_database, true)
2950
2951 test "pleroma restarts", %{conn: conn} do
2952 capture_log(fn ->
2953 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2954 end) =~ "pleroma restarted"
2955
2956 refute Restarter.Pleroma.need_reboot?()
2957 end
2958 end
2959
2960 test "need_reboot flag", %{conn: conn} do
2961 assert conn
2962 |> get("/api/pleroma/admin/need_reboot")
2963 |> json_response(200) == %{"need_reboot" => false}
2964
2965 Restarter.Pleroma.need_reboot()
2966
2967 assert conn
2968 |> get("/api/pleroma/admin/need_reboot")
2969 |> json_response(200) == %{"need_reboot" => true}
2970
2971 on_exit(fn -> Restarter.Pleroma.refresh() end)
2972 end
2973
2974 describe "GET /api/pleroma/admin/statuses" do
2975 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2976 blocked = insert(:user)
2977 user = insert(:user)
2978 User.block(admin, blocked)
2979
2980 {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
2981
2982 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
2983 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
2984 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
2985 {:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"})
2986
2987 response =
2988 conn
2989 |> get("/api/pleroma/admin/statuses")
2990 |> json_response(200)
2991
2992 refute "private" in Enum.map(response, & &1["visibility"])
2993 assert length(response) == 3
2994 end
2995
2996 test "returns only local statuses with local_only on", %{conn: conn} do
2997 user = insert(:user)
2998 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2999 insert(:note_activity, user: user, local: true)
3000 insert(:note_activity, user: remote_user, local: false)
3001
3002 response =
3003 conn
3004 |> get("/api/pleroma/admin/statuses?local_only=true")
3005 |> json_response(200)
3006
3007 assert length(response) == 1
3008 end
3009
3010 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
3011 user = insert(:user)
3012
3013 {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
3014
3015 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
3016 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
3017 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
3018 assert json_response(conn, 200) |> length() == 3
3019 end
3020 end
3021
3022 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3023 setup do
3024 user = insert(:user)
3025
3026 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3027 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3028 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3029
3030 insert(:note_activity, user: user, published: date1)
3031 insert(:note_activity, user: user, published: date2)
3032 insert(:note_activity, user: user, published: date3)
3033
3034 %{user: user}
3035 end
3036
3037 test "renders user's statuses", %{conn: conn, user: user} do
3038 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3039
3040 assert json_response(conn, 200) |> length() == 3
3041 end
3042
3043 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3044 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3045
3046 assert json_response(conn, 200) |> length() == 2
3047 end
3048
3049 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3050 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
3051
3052 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
3053
3054 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3055
3056 assert json_response(conn, 200) |> length() == 4
3057 end
3058
3059 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3060 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
3061
3062 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
3063
3064 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3065
3066 assert json_response(conn, 200) |> length() == 5
3067 end
3068
3069 test "excludes reblogs by default", %{conn: conn, user: user} do
3070 other_user = insert(:user)
3071 {:ok, activity} = CommonAPI.post(user, %{status: "."})
3072 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3073
3074 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3075 assert json_response(conn_res, 200) |> length() == 0
3076
3077 conn_res =
3078 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3079
3080 assert json_response(conn_res, 200) |> length() == 1
3081 end
3082 end
3083
3084 describe "GET /api/pleroma/admin/moderation_log" do
3085 setup do
3086 moderator = insert(:user, is_moderator: true)
3087
3088 %{moderator: moderator}
3089 end
3090
3091 test "returns the log", %{conn: conn, admin: admin} do
3092 Repo.insert(%ModerationLog{
3093 data: %{
3094 actor: %{
3095 "id" => admin.id,
3096 "nickname" => admin.nickname,
3097 "type" => "user"
3098 },
3099 action: "relay_follow",
3100 target: "https://example.org/relay"
3101 },
3102 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3103 })
3104
3105 Repo.insert(%ModerationLog{
3106 data: %{
3107 actor: %{
3108 "id" => admin.id,
3109 "nickname" => admin.nickname,
3110 "type" => "user"
3111 },
3112 action: "relay_unfollow",
3113 target: "https://example.org/relay"
3114 },
3115 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3116 })
3117
3118 conn = get(conn, "/api/pleroma/admin/moderation_log")
3119
3120 response = json_response(conn, 200)
3121 [first_entry, second_entry] = response["items"]
3122
3123 assert response["total"] == 2
3124 assert first_entry["data"]["action"] == "relay_unfollow"
3125
3126 assert first_entry["message"] ==
3127 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3128
3129 assert second_entry["data"]["action"] == "relay_follow"
3130
3131 assert second_entry["message"] ==
3132 "@#{admin.nickname} followed relay: https://example.org/relay"
3133 end
3134
3135 test "returns the log with pagination", %{conn: conn, admin: admin} do
3136 Repo.insert(%ModerationLog{
3137 data: %{
3138 actor: %{
3139 "id" => admin.id,
3140 "nickname" => admin.nickname,
3141 "type" => "user"
3142 },
3143 action: "relay_follow",
3144 target: "https://example.org/relay"
3145 },
3146 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3147 })
3148
3149 Repo.insert(%ModerationLog{
3150 data: %{
3151 actor: %{
3152 "id" => admin.id,
3153 "nickname" => admin.nickname,
3154 "type" => "user"
3155 },
3156 action: "relay_unfollow",
3157 target: "https://example.org/relay"
3158 },
3159 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3160 })
3161
3162 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3163
3164 response1 = json_response(conn1, 200)
3165 [first_entry] = response1["items"]
3166
3167 assert response1["total"] == 2
3168 assert response1["items"] |> length() == 1
3169 assert first_entry["data"]["action"] == "relay_unfollow"
3170
3171 assert first_entry["message"] ==
3172 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3173
3174 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3175
3176 response2 = json_response(conn2, 200)
3177 [second_entry] = response2["items"]
3178
3179 assert response2["total"] == 2
3180 assert response2["items"] |> length() == 1
3181 assert second_entry["data"]["action"] == "relay_follow"
3182
3183 assert second_entry["message"] ==
3184 "@#{admin.nickname} followed relay: https://example.org/relay"
3185 end
3186
3187 test "filters log by date", %{conn: conn, admin: admin} do
3188 first_date = "2017-08-15T15:47:06Z"
3189 second_date = "2017-08-20T15:47:06Z"
3190
3191 Repo.insert(%ModerationLog{
3192 data: %{
3193 actor: %{
3194 "id" => admin.id,
3195 "nickname" => admin.nickname,
3196 "type" => "user"
3197 },
3198 action: "relay_follow",
3199 target: "https://example.org/relay"
3200 },
3201 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3202 })
3203
3204 Repo.insert(%ModerationLog{
3205 data: %{
3206 actor: %{
3207 "id" => admin.id,
3208 "nickname" => admin.nickname,
3209 "type" => "user"
3210 },
3211 action: "relay_unfollow",
3212 target: "https://example.org/relay"
3213 },
3214 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3215 })
3216
3217 conn1 =
3218 get(
3219 conn,
3220 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3221 )
3222
3223 response1 = json_response(conn1, 200)
3224 [first_entry] = response1["items"]
3225
3226 assert response1["total"] == 1
3227 assert first_entry["data"]["action"] == "relay_unfollow"
3228
3229 assert first_entry["message"] ==
3230 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3231 end
3232
3233 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3234 Repo.insert(%ModerationLog{
3235 data: %{
3236 actor: %{
3237 "id" => admin.id,
3238 "nickname" => admin.nickname,
3239 "type" => "user"
3240 },
3241 action: "relay_follow",
3242 target: "https://example.org/relay"
3243 }
3244 })
3245
3246 Repo.insert(%ModerationLog{
3247 data: %{
3248 actor: %{
3249 "id" => moderator.id,
3250 "nickname" => moderator.nickname,
3251 "type" => "user"
3252 },
3253 action: "relay_unfollow",
3254 target: "https://example.org/relay"
3255 }
3256 })
3257
3258 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3259
3260 response1 = json_response(conn1, 200)
3261 [first_entry] = response1["items"]
3262
3263 assert response1["total"] == 1
3264 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3265 end
3266
3267 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3268 ModerationLog.insert_log(%{
3269 actor: moderator,
3270 action: "relay_follow",
3271 target: "https://example.org/relay"
3272 })
3273
3274 ModerationLog.insert_log(%{
3275 actor: moderator,
3276 action: "relay_unfollow",
3277 target: "https://example.org/relay"
3278 })
3279
3280 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3281
3282 response1 = json_response(conn1, 200)
3283 [first_entry] = response1["items"]
3284
3285 assert response1["total"] == 1
3286
3287 assert get_in(first_entry, ["data", "message"]) ==
3288 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3289 end
3290 end
3291
3292 describe "GET /users/:nickname/credentials" do
3293 test "gets the user credentials", %{conn: conn} do
3294 user = insert(:user)
3295 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3296
3297 response = assert json_response(conn, 200)
3298 assert response["email"] == user.email
3299 end
3300
3301 test "returns 403 if requested by a non-admin" do
3302 user = insert(:user)
3303
3304 conn =
3305 build_conn()
3306 |> assign(:user, user)
3307 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3308
3309 assert json_response(conn, :forbidden)
3310 end
3311 end
3312
3313 describe "PATCH /users/:nickname/credentials" do
3314 test "changes password and email", %{conn: conn, admin: admin} do
3315 user = insert(:user)
3316 assert user.password_reset_pending == false
3317
3318 conn =
3319 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3320 "password" => "new_password",
3321 "email" => "new_email@example.com",
3322 "name" => "new_name"
3323 })
3324
3325 assert json_response(conn, 200) == %{"status" => "success"}
3326
3327 ObanHelpers.perform_all()
3328
3329 updated_user = User.get_by_id(user.id)
3330
3331 assert updated_user.email == "new_email@example.com"
3332 assert updated_user.name == "new_name"
3333 assert updated_user.password_hash != user.password_hash
3334 assert updated_user.password_reset_pending == true
3335
3336 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3337
3338 assert ModerationLog.get_log_entry_message(log_entry1) ==
3339 "@#{admin.nickname} updated users: @#{user.nickname}"
3340
3341 assert ModerationLog.get_log_entry_message(log_entry2) ==
3342 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3343 end
3344
3345 test "returns 403 if requested by a non-admin" do
3346 user = insert(:user)
3347
3348 conn =
3349 build_conn()
3350 |> assign(:user, user)
3351 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3352 "password" => "new_password",
3353 "email" => "new_email@example.com",
3354 "name" => "new_name"
3355 })
3356
3357 assert json_response(conn, :forbidden)
3358 end
3359 end
3360
3361 describe "PATCH /users/:nickname/force_password_reset" do
3362 test "sets password_reset_pending to true", %{conn: conn} do
3363 user = insert(:user)
3364 assert user.password_reset_pending == false
3365
3366 conn =
3367 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3368
3369 assert json_response(conn, 204) == ""
3370
3371 ObanHelpers.perform_all()
3372
3373 assert User.get_by_id(user.id).password_reset_pending == true
3374 end
3375 end
3376
3377 describe "relays" do
3378 test "POST /relay", %{conn: conn, admin: admin} do
3379 conn =
3380 post(conn, "/api/pleroma/admin/relay", %{
3381 relay_url: "http://mastodon.example.org/users/admin"
3382 })
3383
3384 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3385
3386 log_entry = Repo.one(ModerationLog)
3387
3388 assert ModerationLog.get_log_entry_message(log_entry) ==
3389 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3390 end
3391
3392 test "GET /relay", %{conn: conn} do
3393 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3394
3395 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3396 |> Enum.each(fn ap_id ->
3397 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3398 User.follow(relay_user, user)
3399 end)
3400
3401 conn = get(conn, "/api/pleroma/admin/relay")
3402
3403 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3404 end
3405
3406 test "DELETE /relay", %{conn: conn, admin: admin} do
3407 post(conn, "/api/pleroma/admin/relay", %{
3408 relay_url: "http://mastodon.example.org/users/admin"
3409 })
3410
3411 conn =
3412 delete(conn, "/api/pleroma/admin/relay", %{
3413 relay_url: "http://mastodon.example.org/users/admin"
3414 })
3415
3416 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3417
3418 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3419
3420 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3421 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3422
3423 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3424 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3425 end
3426 end
3427
3428 describe "instances" do
3429 test "GET /instances/:instance/statuses", %{conn: conn} do
3430 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3431 user2 = insert(:user, local: false, nickname: "test@test.com")
3432 insert_pair(:note_activity, user: user)
3433 activity = insert(:note_activity, user: user2)
3434
3435 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3436
3437 response = json_response(ret_conn, 200)
3438
3439 assert length(response) == 2
3440
3441 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3442
3443 response = json_response(ret_conn, 200)
3444
3445 assert length(response) == 1
3446
3447 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3448
3449 response = json_response(ret_conn, 200)
3450
3451 assert Enum.empty?(response)
3452
3453 CommonAPI.repeat(activity.id, user)
3454
3455 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3456 response = json_response(ret_conn, 200)
3457 assert length(response) == 2
3458
3459 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3460 response = json_response(ret_conn, 200)
3461 assert length(response) == 3
3462 end
3463 end
3464
3465 describe "PATCH /confirm_email" do
3466 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3467 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3468
3469 assert first_user.confirmation_pending == true
3470 assert second_user.confirmation_pending == true
3471
3472 ret_conn =
3473 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3474 nicknames: [
3475 first_user.nickname,
3476 second_user.nickname
3477 ]
3478 })
3479
3480 assert ret_conn.status == 200
3481
3482 assert first_user.confirmation_pending == true
3483 assert second_user.confirmation_pending == true
3484
3485 log_entry = Repo.one(ModerationLog)
3486
3487 assert ModerationLog.get_log_entry_message(log_entry) ==
3488 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3489 second_user.nickname
3490 }"
3491 end
3492 end
3493
3494 describe "PATCH /resend_confirmation_email" do
3495 test "it resend emails for two users", %{conn: conn, admin: admin} do
3496 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3497
3498 ret_conn =
3499 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3500 nicknames: [
3501 first_user.nickname,
3502 second_user.nickname
3503 ]
3504 })
3505
3506 assert ret_conn.status == 200
3507
3508 log_entry = Repo.one(ModerationLog)
3509
3510 assert ModerationLog.get_log_entry_message(log_entry) ==
3511 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3512 second_user.nickname
3513 }"
3514 end
3515 end
3516
3517 describe "POST /reports/:id/notes" do
3518 setup %{conn: conn, admin: admin} do
3519 [reporter, target_user] = insert_pair(:user)
3520 activity = insert(:note_activity, user: target_user)
3521
3522 {:ok, %{id: report_id}} =
3523 CommonAPI.report(reporter, %{
3524 account_id: target_user.id,
3525 comment: "I feel offended",
3526 status_ids: [activity.id]
3527 })
3528
3529 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3530 content: "this is disgusting!"
3531 })
3532
3533 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3534 content: "this is disgusting2!"
3535 })
3536
3537 %{
3538 admin_id: admin.id,
3539 report_id: report_id
3540 }
3541 end
3542
3543 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3544 [note, _] = Repo.all(ReportNote)
3545
3546 assert %{
3547 activity_id: ^report_id,
3548 content: "this is disgusting!",
3549 user_id: ^admin_id
3550 } = note
3551 end
3552
3553 test "it returns reports with notes", %{conn: conn, admin: admin} do
3554 conn = get(conn, "/api/pleroma/admin/reports")
3555
3556 response = json_response(conn, 200)
3557 notes = hd(response["reports"])["notes"]
3558 [note, _] = notes
3559
3560 assert note["user"]["nickname"] == admin.nickname
3561 assert note["content"] == "this is disgusting!"
3562 assert note["created_at"]
3563 assert response["total"] == 1
3564 end
3565
3566 test "it deletes the note", %{conn: conn, report_id: report_id} do
3567 assert ReportNote |> Repo.all() |> length() == 2
3568
3569 [note, _] = Repo.all(ReportNote)
3570
3571 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3572
3573 assert ReportNote |> Repo.all() |> length() == 1
3574 end
3575 end
3576
3577 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3578 admin = insert(:user, is_admin: true)
3579
3580 conn =
3581 assign(conn, :user, admin)
3582 |> get("/api/pleroma/admin/config/descriptions")
3583
3584 assert [child | _others] = json_response(conn, 200)
3585
3586 assert child["children"]
3587 assert child["key"]
3588 assert String.starts_with?(child["group"], ":")
3589 assert child["description"]
3590 end
3591
3592 describe "/api/pleroma/admin/stats" do
3593 test "status visibility count", %{conn: conn} do
3594 admin = insert(:user, is_admin: true)
3595 user = insert(:user)
3596 CommonAPI.post(user, %{visibility: "public", status: "hey"})
3597 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3598 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3599
3600 response =
3601 conn
3602 |> assign(:user, admin)
3603 |> get("/api/pleroma/admin/stats")
3604 |> json_response(200)
3605
3606 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3607 response["status_visibility"]
3608 end
3609 end
3610
3611 describe "POST /api/pleroma/admin/oauth_app" do
3612 test "errors", %{conn: conn} do
3613 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3614
3615 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3616 end
3617
3618 test "success", %{conn: conn} do
3619 base_url = Web.base_url()
3620 app_name = "Trusted app"
3621
3622 response =
3623 conn
3624 |> post("/api/pleroma/admin/oauth_app", %{
3625 name: app_name,
3626 redirect_uris: base_url
3627 })
3628 |> json_response(200)
3629
3630 assert %{
3631 "client_id" => _,
3632 "client_secret" => _,
3633 "name" => ^app_name,
3634 "redirect_uri" => ^base_url,
3635 "trusted" => false
3636 } = response
3637 end
3638
3639 test "with trusted", %{conn: conn} do
3640 base_url = Web.base_url()
3641 app_name = "Trusted app"
3642
3643 response =
3644 conn
3645 |> post("/api/pleroma/admin/oauth_app", %{
3646 name: app_name,
3647 redirect_uris: base_url,
3648 trusted: true
3649 })
3650 |> json_response(200)
3651
3652 assert %{
3653 "client_id" => _,
3654 "client_secret" => _,
3655 "name" => ^app_name,
3656 "redirect_uri" => ^base_url,
3657 "trusted" => true
3658 } = response
3659 end
3660 end
3661
3662 describe "GET /api/pleroma/admin/oauth_app" do
3663 setup do
3664 app = insert(:oauth_app)
3665 {:ok, app: app}
3666 end
3667
3668 test "list", %{conn: conn} do
3669 response =
3670 conn
3671 |> get("/api/pleroma/admin/oauth_app")
3672 |> json_response(200)
3673
3674 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3675
3676 assert length(apps) == count
3677 end
3678
3679 test "with page size", %{conn: conn} do
3680 insert(:oauth_app)
3681 page_size = 1
3682
3683 response =
3684 conn
3685 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3686 |> json_response(200)
3687
3688 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3689
3690 assert length(apps) == page_size
3691 end
3692
3693 test "search by client name", %{conn: conn, app: app} do
3694 response =
3695 conn
3696 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3697 |> json_response(200)
3698
3699 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3700
3701 assert returned["client_id"] == app.client_id
3702 assert returned["name"] == app.client_name
3703 end
3704
3705 test "search by client id", %{conn: conn, app: app} do
3706 response =
3707 conn
3708 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3709 |> json_response(200)
3710
3711 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3712
3713 assert returned["client_id"] == app.client_id
3714 assert returned["name"] == app.client_name
3715 end
3716
3717 test "only trusted", %{conn: conn} do
3718 app = insert(:oauth_app, trusted: true)
3719
3720 response =
3721 conn
3722 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3723 |> json_response(200)
3724
3725 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3726
3727 assert returned["client_id"] == app.client_id
3728 assert returned["name"] == app.client_name
3729 end
3730 end
3731
3732 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3733 test "with id", %{conn: conn} do
3734 app = insert(:oauth_app)
3735
3736 response =
3737 conn
3738 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3739 |> json_response(:no_content)
3740
3741 assert response == ""
3742 end
3743
3744 test "with non existance id", %{conn: conn} do
3745 response =
3746 conn
3747 |> delete("/api/pleroma/admin/oauth_app/0")
3748 |> json_response(:bad_request)
3749
3750 assert response == ""
3751 end
3752 end
3753
3754 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3755 test "with id", %{conn: conn} do
3756 app = insert(:oauth_app)
3757
3758 name = "another name"
3759 url = "https://example.com"
3760 scopes = ["admin"]
3761 id = app.id
3762 website = "http://website.com"
3763
3764 response =
3765 conn
3766 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3767 name: name,
3768 trusted: true,
3769 redirect_uris: url,
3770 scopes: scopes,
3771 website: website
3772 })
3773 |> json_response(200)
3774
3775 assert %{
3776 "client_id" => _,
3777 "client_secret" => _,
3778 "id" => ^id,
3779 "name" => ^name,
3780 "redirect_uri" => ^url,
3781 "trusted" => true,
3782 "website" => ^website
3783 } = response
3784 end
3785
3786 test "without id", %{conn: conn} do
3787 response =
3788 conn
3789 |> patch("/api/pleroma/admin/oauth_app/0")
3790 |> json_response(:bad_request)
3791
3792 assert response == ""
3793 end
3794 end
3795 end
3796
3797 # Needed for testing
3798 defmodule Pleroma.Web.Endpoint.NotReal do
3799 end
3800
3801 defmodule Pleroma.Captcha.NotReal do
3802 end