1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
9 import ExUnit.CaptureLog
11 import Pleroma.Factory
13 alias Pleroma.Activity
15 alias Pleroma.ConfigDB
18 alias Pleroma.ModerationLog
20 alias Pleroma.ReportNote
21 alias Pleroma.Tests.ObanHelpers
23 alias Pleroma.UserInviteToken
25 alias Pleroma.Web.ActivityPub.Relay
26 alias Pleroma.Web.CommonAPI
27 alias Pleroma.Web.MediaProxy
30 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
36 admin = insert(:user, is_admin: true)
37 token = insert(:oauth_admin_token, user: admin)
41 |> assign(:user, admin)
42 |> assign(:token, token)
44 {:ok, %{admin: admin, token: token, conn: conn}}
47 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
48 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
50 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
53 url = "/api/pleroma/admin/users/#{user.nickname}"
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"])
59 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
60 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
63 for good_token <- [good_token1, good_token2, good_token3] do
66 |> assign(:user, admin)
67 |> assign(:token, good_token)
70 assert json_response(conn, 200)
73 for good_token <- [good_token1, good_token2, good_token3] do
77 |> assign(:token, good_token)
80 assert json_response(conn, :forbidden)
83 for bad_token <- [bad_token1, bad_token2, bad_token3] do
86 |> assign(:user, admin)
87 |> assign(:token, bad_token)
90 assert json_response(conn, :forbidden)
95 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
96 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
98 test "GET /api/pleroma/admin/users/:nickname requires " <>
99 "read:accounts or admin:read:accounts or broader scope",
102 url = "/api/pleroma/admin/users/#{user.nickname}"
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"])
110 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
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"])
116 for good_token <- good_tokens do
119 |> assign(:user, admin)
120 |> assign(:token, good_token)
123 assert json_response(conn, 200)
126 for good_token <- good_tokens do
129 |> assign(:user, nil)
130 |> assign(:token, good_token)
133 assert json_response(conn, :forbidden)
136 for bad_token <- [bad_token1, bad_token2, bad_token3] do
139 |> assign(:user, admin)
140 |> assign(:token, bad_token)
143 assert json_response(conn, :forbidden)
148 describe "DELETE /api/pleroma/admin/users" do
149 test "single user", %{admin: admin, conn: conn} do
151 clear_config([:instance, :federating], true)
153 with_mock Pleroma.Web.Federator,
154 publish: fn _ -> nil end do
157 |> put_req_header("accept", "application/json")
158 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
160 ObanHelpers.perform_all()
162 assert User.get_by_nickname(user.nickname).deactivated
164 log_entry = Repo.one(ModerationLog)
166 assert ModerationLog.get_log_entry_message(log_entry) ==
167 "@#{admin.nickname} deleted users: @#{user.nickname}"
169 assert json_response(conn, 200) == [user.nickname]
171 assert called(Pleroma.Web.Federator.publish(:_))
175 test "multiple users", %{admin: admin, conn: conn} do
176 user_one = insert(:user)
177 user_two = insert(:user)
181 |> put_req_header("accept", "application/json")
182 |> delete("/api/pleroma/admin/users", %{
183 nicknames: [user_one.nickname, user_two.nickname]
186 log_entry = Repo.one(ModerationLog)
188 assert ModerationLog.get_log_entry_message(log_entry) ==
189 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
191 response = json_response(conn, 200)
192 assert response -- [user_one.nickname, user_two.nickname] == []
196 describe "/api/pleroma/admin/users" do
197 test "Create", %{conn: conn} do
200 |> put_req_header("accept", "application/json")
201 |> post("/api/pleroma/admin/users", %{
204 "nickname" => "lain",
205 "email" => "lain@example.org",
209 "nickname" => "lain2",
210 "email" => "lain2@example.org",
216 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
217 assert response == ["success", "success"]
219 log_entry = Repo.one(ModerationLog)
221 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
224 test "Cannot create user with existing email", %{conn: conn} do
229 |> put_req_header("accept", "application/json")
230 |> post("/api/pleroma/admin/users", %{
233 "nickname" => "lain",
234 "email" => user.email,
240 assert json_response(conn, 409) == [
244 "email" => user.email,
247 "error" => "email has already been taken",
253 test "Cannot create user with existing nickname", %{conn: conn} do
258 |> put_req_header("accept", "application/json")
259 |> post("/api/pleroma/admin/users", %{
262 "nickname" => user.nickname,
263 "email" => "someuser@plerama.social",
269 assert json_response(conn, 409) == [
273 "email" => "someuser@plerama.social",
274 "nickname" => user.nickname
276 "error" => "nickname has already been taken",
282 test "Multiple user creation works in transaction", %{conn: conn} do
287 |> put_req_header("accept", "application/json")
288 |> post("/api/pleroma/admin/users", %{
291 "nickname" => "newuser",
292 "email" => "newuser@pleroma.social",
296 "nickname" => "lain",
297 "email" => user.email,
303 assert json_response(conn, 409) == [
307 "email" => user.email,
310 "error" => "email has already been taken",
316 "email" => "newuser@pleroma.social",
317 "nickname" => "newuser"
324 assert User.get_by_nickname("newuser") === nil
328 describe "/api/pleroma/admin/users/:nickname" do
329 test "Show", %{conn: conn} do
332 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
335 "deactivated" => false,
336 "id" => to_string(user.id),
338 "nickname" => user.nickname,
339 "roles" => %{"admin" => false, "moderator" => false},
341 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
342 "display_name" => HTML.strip_tags(user.name || user.nickname),
343 "confirmation_pending" => false
346 assert expected == json_response(conn, 200)
349 test "when the user doesn't exist", %{conn: conn} do
352 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
354 assert "Not found" == json_response(conn, 404)
358 describe "/api/pleroma/admin/users/follow" do
359 test "allows to force-follow another user", %{admin: admin, conn: conn} do
361 follower = insert(:user)
364 |> put_req_header("accept", "application/json")
365 |> post("/api/pleroma/admin/users/follow", %{
366 "follower" => follower.nickname,
367 "followed" => user.nickname
370 user = User.get_cached_by_id(user.id)
371 follower = User.get_cached_by_id(follower.id)
373 assert User.following?(follower, user)
375 log_entry = Repo.one(ModerationLog)
377 assert ModerationLog.get_log_entry_message(log_entry) ==
378 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
382 describe "/api/pleroma/admin/users/unfollow" do
383 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
385 follower = insert(:user)
387 User.follow(follower, user)
390 |> put_req_header("accept", "application/json")
391 |> post("/api/pleroma/admin/users/unfollow", %{
392 "follower" => follower.nickname,
393 "followed" => user.nickname
396 user = User.get_cached_by_id(user.id)
397 follower = User.get_cached_by_id(follower.id)
399 refute User.following?(follower, user)
401 log_entry = Repo.one(ModerationLog)
403 assert ModerationLog.get_log_entry_message(log_entry) ==
404 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
408 describe "PUT /api/pleroma/admin/users/tag" do
409 setup %{conn: conn} do
410 user1 = insert(:user, %{tags: ["x"]})
411 user2 = insert(:user, %{tags: ["y"]})
412 user3 = insert(:user, %{tags: ["unchanged"]})
416 |> put_req_header("accept", "application/json")
418 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
419 "#{user2.nickname}&tags[]=foo&tags[]=bar"
422 %{conn: conn, user1: user1, user2: user2, user3: user3}
425 test "it appends specified tags to users with specified nicknames", %{
431 assert json_response(conn, :no_content)
432 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
433 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
435 log_entry = Repo.one(ModerationLog)
438 [user1.nickname, user2.nickname]
439 |> Enum.map(&"@#{&1}")
442 tags = ["foo", "bar"] |> Enum.join(", ")
444 assert ModerationLog.get_log_entry_message(log_entry) ==
445 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
448 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
449 assert json_response(conn, :no_content)
450 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
454 describe "DELETE /api/pleroma/admin/users/tag" do
455 setup %{conn: conn} do
456 user1 = insert(:user, %{tags: ["x"]})
457 user2 = insert(:user, %{tags: ["y", "z"]})
458 user3 = insert(:user, %{tags: ["unchanged"]})
462 |> put_req_header("accept", "application/json")
464 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
465 "#{user2.nickname}&tags[]=x&tags[]=z"
468 %{conn: conn, user1: user1, user2: user2, user3: user3}
471 test "it removes specified tags from users with specified nicknames", %{
477 assert json_response(conn, :no_content)
478 assert User.get_cached_by_id(user1.id).tags == []
479 assert User.get_cached_by_id(user2.id).tags == ["y"]
481 log_entry = Repo.one(ModerationLog)
484 [user1.nickname, user2.nickname]
485 |> Enum.map(&"@#{&1}")
488 tags = ["x", "z"] |> Enum.join(", ")
490 assert ModerationLog.get_log_entry_message(log_entry) ==
491 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
494 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
495 assert json_response(conn, :no_content)
496 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
500 describe "/api/pleroma/admin/users/:nickname/permission_group" do
501 test "GET is giving user_info", %{admin: admin, conn: conn} do
504 |> put_req_header("accept", "application/json")
505 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
507 assert json_response(conn, 200) == %{
509 "is_moderator" => false
513 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
518 |> put_req_header("accept", "application/json")
519 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
521 assert json_response(conn, 200) == %{
525 log_entry = Repo.one(ModerationLog)
527 assert ModerationLog.get_log_entry_message(log_entry) ==
528 "@#{admin.nickname} made @#{user.nickname} admin"
531 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
532 user_one = insert(:user)
533 user_two = insert(:user)
537 |> put_req_header("accept", "application/json")
538 |> post("/api/pleroma/admin/users/permission_group/admin", %{
539 nicknames: [user_one.nickname, user_two.nickname]
542 assert json_response(conn, 200) == %{"is_admin" => true}
544 log_entry = Repo.one(ModerationLog)
546 assert ModerationLog.get_log_entry_message(log_entry) ==
547 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
550 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
551 user = insert(:user, is_admin: true)
555 |> put_req_header("accept", "application/json")
556 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
558 assert json_response(conn, 200) == %{"is_admin" => false}
560 log_entry = Repo.one(ModerationLog)
562 assert ModerationLog.get_log_entry_message(log_entry) ==
563 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
566 test "/:right DELETE, can remove from a permission group (multiple)", %{
570 user_one = insert(:user, is_admin: true)
571 user_two = insert(:user, is_admin: true)
575 |> put_req_header("accept", "application/json")
576 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
577 nicknames: [user_one.nickname, user_two.nickname]
580 assert json_response(conn, 200) == %{"is_admin" => false}
582 log_entry = Repo.one(ModerationLog)
584 assert ModerationLog.get_log_entry_message(log_entry) ==
585 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
591 describe "POST /api/pleroma/admin/email_invite, with valid config" do
592 setup do: clear_config([:instance, :registrations_open], false)
593 setup do: clear_config([:instance, :invites_enabled], true)
595 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
596 recipient_email = "foo@bar.com"
597 recipient_name = "J. D."
602 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
605 assert json_response(conn, :no_content)
607 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
609 refute token_record.used
611 notify_email = Config.get([:instance, :notify_email])
612 instance_name = Config.get([:instance, :name])
615 Pleroma.Emails.UserEmail.user_invitation_email(
622 Swoosh.TestAssertions.assert_email_sent(
623 from: {instance_name, notify_email},
624 to: {recipient_name, recipient_email},
625 html_body: email.html_body
629 test "it returns 403 if requested by a non-admin" do
630 non_admin_user = insert(:user)
631 token = insert(:oauth_token, user: non_admin_user)
635 |> assign(:user, non_admin_user)
636 |> assign(:token, token)
637 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
639 assert json_response(conn, :forbidden)
642 test "email with +", %{conn: conn, admin: admin} do
643 recipient_email = "foo+bar@baz.com"
646 |> put_req_header("content-type", "application/json;charset=utf-8")
647 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
648 |> json_response(:no_content)
651 Pleroma.UserInviteToken
656 refute token_record.used
658 notify_email = Config.get([:instance, :notify_email])
659 instance_name = Config.get([:instance, :name])
662 Pleroma.Emails.UserEmail.user_invitation_email(
668 Swoosh.TestAssertions.assert_email_sent(
669 from: {instance_name, notify_email},
671 html_body: email.html_body
676 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
677 setup do: clear_config([:instance, :registrations_open])
678 setup do: clear_config([:instance, :invites_enabled])
680 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
681 Config.put([:instance, :registrations_open], false)
682 Config.put([:instance, :invites_enabled], false)
684 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
686 assert json_response(conn, :bad_request) ==
687 "To send invites you need to set the `invites_enabled` option to true."
690 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
691 Config.put([:instance, :registrations_open], true)
692 Config.put([:instance, :invites_enabled], true)
694 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
696 assert json_response(conn, :bad_request) ==
697 "To send invites you need to set the `registrations_open` option to false."
701 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
706 |> put_req_header("accept", "application/json")
707 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
709 resp = json_response(conn, 200)
711 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
714 describe "GET /api/pleroma/admin/users" do
715 test "renders users array for the first page", %{conn: conn, admin: admin} do
716 user = insert(:user, local: false, tags: ["foo", "bar"])
717 conn = get(conn, "/api/pleroma/admin/users?page=1")
722 "deactivated" => admin.deactivated,
724 "nickname" => admin.nickname,
725 "roles" => %{"admin" => true, "moderator" => false},
728 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
729 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
730 "confirmation_pending" => false
733 "deactivated" => user.deactivated,
735 "nickname" => user.nickname,
736 "roles" => %{"admin" => false, "moderator" => false},
738 "tags" => ["foo", "bar"],
739 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
740 "display_name" => HTML.strip_tags(user.name || user.nickname),
741 "confirmation_pending" => false
744 |> Enum.sort_by(& &1["nickname"])
746 assert json_response(conn, 200) == %{
753 test "pagination works correctly with service users", %{conn: conn} do
754 service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
755 service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
756 insert_list(25, :user)
758 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
760 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
761 |> json_response(200)
763 assert Enum.count(users1) == 10
764 assert service1 not in [users1]
765 assert service2 not in [users1]
767 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
769 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
770 |> json_response(200)
772 assert Enum.count(users2) == 10
773 assert service1 not in [users2]
774 assert service2 not in [users2]
776 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
778 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
779 |> json_response(200)
781 assert Enum.count(users3) == 6
782 assert service1 not in [users3]
783 assert service2 not in [users3]
786 test "renders empty array for the second page", %{conn: conn} do
789 conn = get(conn, "/api/pleroma/admin/users?page=2")
791 assert json_response(conn, 200) == %{
798 test "regular search", %{conn: conn} do
799 user = insert(:user, nickname: "bob")
801 conn = get(conn, "/api/pleroma/admin/users?query=bo")
803 assert json_response(conn, 200) == %{
808 "deactivated" => user.deactivated,
810 "nickname" => user.nickname,
811 "roles" => %{"admin" => false, "moderator" => false},
814 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
815 "display_name" => HTML.strip_tags(user.name || user.nickname),
816 "confirmation_pending" => false
822 test "search by domain", %{conn: conn} do
823 user = insert(:user, nickname: "nickname@domain.com")
826 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
828 assert json_response(conn, 200) == %{
833 "deactivated" => user.deactivated,
835 "nickname" => user.nickname,
836 "roles" => %{"admin" => false, "moderator" => false},
839 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
840 "display_name" => HTML.strip_tags(user.name || user.nickname),
841 "confirmation_pending" => false
847 test "search by full nickname", %{conn: conn} do
848 user = insert(:user, nickname: "nickname@domain.com")
851 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
853 assert json_response(conn, 200) == %{
858 "deactivated" => user.deactivated,
860 "nickname" => user.nickname,
861 "roles" => %{"admin" => false, "moderator" => false},
864 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
865 "display_name" => HTML.strip_tags(user.name || user.nickname),
866 "confirmation_pending" => false
872 test "search by display name", %{conn: conn} do
873 user = insert(:user, name: "Display name")
876 conn = get(conn, "/api/pleroma/admin/users?name=display")
878 assert json_response(conn, 200) == %{
883 "deactivated" => user.deactivated,
885 "nickname" => user.nickname,
886 "roles" => %{"admin" => false, "moderator" => false},
889 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
890 "display_name" => HTML.strip_tags(user.name || user.nickname),
891 "confirmation_pending" => false
897 test "search by email", %{conn: conn} do
898 user = insert(:user, email: "email@example.com")
901 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
903 assert json_response(conn, 200) == %{
908 "deactivated" => user.deactivated,
910 "nickname" => user.nickname,
911 "roles" => %{"admin" => false, "moderator" => false},
914 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
915 "display_name" => HTML.strip_tags(user.name || user.nickname),
916 "confirmation_pending" => false
922 test "regular search with page size", %{conn: conn} do
923 user = insert(:user, nickname: "aalice")
924 user2 = insert(:user, nickname: "alice")
926 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
928 assert json_response(conn1, 200) == %{
933 "deactivated" => user.deactivated,
935 "nickname" => user.nickname,
936 "roles" => %{"admin" => false, "moderator" => false},
939 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
940 "display_name" => HTML.strip_tags(user.name || user.nickname),
941 "confirmation_pending" => false
946 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
948 assert json_response(conn2, 200) == %{
953 "deactivated" => user2.deactivated,
955 "nickname" => user2.nickname,
956 "roles" => %{"admin" => false, "moderator" => false},
959 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
960 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
961 "confirmation_pending" => false
967 test "only local users" do
968 admin = insert(:user, is_admin: true, nickname: "john")
969 token = insert(:oauth_admin_token, user: admin)
970 user = insert(:user, nickname: "bob")
972 insert(:user, nickname: "bobb", local: false)
976 |> assign(:user, admin)
977 |> assign(:token, token)
978 |> get("/api/pleroma/admin/users?query=bo&filters=local")
980 assert json_response(conn, 200) == %{
985 "deactivated" => user.deactivated,
987 "nickname" => user.nickname,
988 "roles" => %{"admin" => false, "moderator" => false},
991 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
992 "display_name" => HTML.strip_tags(user.name || user.nickname),
993 "confirmation_pending" => false
999 test "only local users with no query", %{conn: conn, admin: old_admin} do
1000 admin = insert(:user, is_admin: true, nickname: "john")
1001 user = insert(:user, nickname: "bob")
1003 insert(:user, nickname: "bobb", local: false)
1005 conn = get(conn, "/api/pleroma/admin/users?filters=local")
1010 "deactivated" => user.deactivated,
1012 "nickname" => user.nickname,
1013 "roles" => %{"admin" => false, "moderator" => false},
1016 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1017 "display_name" => HTML.strip_tags(user.name || user.nickname),
1018 "confirmation_pending" => false
1021 "deactivated" => admin.deactivated,
1023 "nickname" => admin.nickname,
1024 "roles" => %{"admin" => true, "moderator" => false},
1027 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1028 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1029 "confirmation_pending" => false
1032 "deactivated" => false,
1033 "id" => old_admin.id,
1035 "nickname" => old_admin.nickname,
1036 "roles" => %{"admin" => true, "moderator" => false},
1038 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1039 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1040 "confirmation_pending" => false
1043 |> Enum.sort_by(& &1["nickname"])
1045 assert json_response(conn, 200) == %{
1052 test "load only admins", %{conn: conn, admin: admin} do
1053 second_admin = insert(:user, is_admin: true)
1057 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1062 "deactivated" => false,
1064 "nickname" => admin.nickname,
1065 "roles" => %{"admin" => true, "moderator" => false},
1066 "local" => admin.local,
1068 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1069 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1070 "confirmation_pending" => false
1073 "deactivated" => false,
1074 "id" => second_admin.id,
1075 "nickname" => second_admin.nickname,
1076 "roles" => %{"admin" => true, "moderator" => false},
1077 "local" => second_admin.local,
1079 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1080 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1081 "confirmation_pending" => false
1084 |> Enum.sort_by(& &1["nickname"])
1086 assert json_response(conn, 200) == %{
1093 test "load only moderators", %{conn: conn} do
1094 moderator = insert(:user, is_moderator: true)
1098 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1100 assert json_response(conn, 200) == %{
1105 "deactivated" => false,
1106 "id" => moderator.id,
1107 "nickname" => moderator.nickname,
1108 "roles" => %{"admin" => false, "moderator" => true},
1109 "local" => moderator.local,
1111 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1112 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1113 "confirmation_pending" => false
1119 test "load users with tags list", %{conn: conn} do
1120 user1 = insert(:user, tags: ["first"])
1121 user2 = insert(:user, tags: ["second"])
1125 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1130 "deactivated" => false,
1132 "nickname" => user1.nickname,
1133 "roles" => %{"admin" => false, "moderator" => false},
1134 "local" => user1.local,
1135 "tags" => ["first"],
1136 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1137 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1138 "confirmation_pending" => false
1141 "deactivated" => false,
1143 "nickname" => user2.nickname,
1144 "roles" => %{"admin" => false, "moderator" => false},
1145 "local" => user2.local,
1146 "tags" => ["second"],
1147 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1148 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1149 "confirmation_pending" => false
1152 |> Enum.sort_by(& &1["nickname"])
1154 assert json_response(conn, 200) == %{
1161 test "it works with multiple filters" do
1162 admin = insert(:user, nickname: "john", is_admin: true)
1163 token = insert(:oauth_admin_token, user: admin)
1164 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1166 insert(:user, nickname: "ken", local: true, deactivated: true)
1167 insert(:user, nickname: "bobb", local: false, deactivated: false)
1171 |> assign(:user, admin)
1172 |> assign(:token, token)
1173 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1175 assert json_response(conn, 200) == %{
1180 "deactivated" => user.deactivated,
1182 "nickname" => user.nickname,
1183 "roles" => %{"admin" => false, "moderator" => false},
1184 "local" => user.local,
1186 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1187 "display_name" => HTML.strip_tags(user.name || user.nickname),
1188 "confirmation_pending" => false
1194 test "it omits relay user", %{admin: admin, conn: conn} do
1195 assert %User{} = Relay.get_actor()
1197 conn = get(conn, "/api/pleroma/admin/users")
1199 assert json_response(conn, 200) == %{
1204 "deactivated" => admin.deactivated,
1206 "nickname" => admin.nickname,
1207 "roles" => %{"admin" => true, "moderator" => false},
1210 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1211 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1212 "confirmation_pending" => false
1219 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1220 user_one = insert(:user, deactivated: true)
1221 user_two = insert(:user, deactivated: true)
1226 "/api/pleroma/admin/users/activate",
1227 %{nicknames: [user_one.nickname, user_two.nickname]}
1230 response = json_response(conn, 200)
1231 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1233 log_entry = Repo.one(ModerationLog)
1235 assert ModerationLog.get_log_entry_message(log_entry) ==
1236 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1239 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1240 user_one = insert(:user, deactivated: false)
1241 user_two = insert(:user, deactivated: false)
1246 "/api/pleroma/admin/users/deactivate",
1247 %{nicknames: [user_one.nickname, user_two.nickname]}
1250 response = json_response(conn, 200)
1251 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1253 log_entry = Repo.one(ModerationLog)
1255 assert ModerationLog.get_log_entry_message(log_entry) ==
1256 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1259 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1260 user = insert(:user)
1262 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1264 assert json_response(conn, 200) ==
1266 "deactivated" => !user.deactivated,
1268 "nickname" => user.nickname,
1269 "roles" => %{"admin" => false, "moderator" => false},
1272 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1273 "display_name" => HTML.strip_tags(user.name || user.nickname),
1274 "confirmation_pending" => false
1277 log_entry = Repo.one(ModerationLog)
1279 assert ModerationLog.get_log_entry_message(log_entry) ==
1280 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1283 describe "PUT disable_mfa" do
1284 test "returns 200 and disable 2fa", %{conn: conn} do
1287 multi_factor_authentication_settings: %MFA.Settings{
1289 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1295 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1296 |> json_response(200)
1298 assert response == user.nickname
1299 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1301 refute mfa_settings.enabled
1302 refute mfa_settings.totp.confirmed
1305 test "returns 404 if user not found", %{conn: conn} do
1308 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1309 |> json_response(404)
1311 assert response == "Not found"
1315 describe "POST /api/pleroma/admin/users/invite_token" do
1316 test "without options", %{conn: conn} do
1317 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1319 invite_json = json_response(conn, 200)
1320 invite = UserInviteToken.find_by_token!(invite_json["token"])
1322 refute invite.expires_at
1323 refute invite.max_use
1324 assert invite.invite_type == "one_time"
1327 test "with expires_at", %{conn: conn} do
1329 post(conn, "/api/pleroma/admin/users/invite_token", %{
1330 "expires_at" => Date.to_string(Date.utc_today())
1333 invite_json = json_response(conn, 200)
1334 invite = UserInviteToken.find_by_token!(invite_json["token"])
1337 assert invite.expires_at == Date.utc_today()
1338 refute invite.max_use
1339 assert invite.invite_type == "date_limited"
1342 test "with max_use", %{conn: conn} do
1343 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1345 invite_json = json_response(conn, 200)
1346 invite = UserInviteToken.find_by_token!(invite_json["token"])
1348 refute invite.expires_at
1349 assert invite.max_use == 150
1350 assert invite.invite_type == "reusable"
1353 test "with max use and expires_at", %{conn: conn} do
1355 post(conn, "/api/pleroma/admin/users/invite_token", %{
1357 "expires_at" => Date.to_string(Date.utc_today())
1360 invite_json = json_response(conn, 200)
1361 invite = UserInviteToken.find_by_token!(invite_json["token"])
1363 assert invite.expires_at == Date.utc_today()
1364 assert invite.max_use == 150
1365 assert invite.invite_type == "reusable_date_limited"
1369 describe "GET /api/pleroma/admin/users/invites" do
1370 test "no invites", %{conn: conn} do
1371 conn = get(conn, "/api/pleroma/admin/users/invites")
1373 assert json_response(conn, 200) == %{"invites" => []}
1376 test "with invite", %{conn: conn} do
1377 {:ok, invite} = UserInviteToken.create_invite()
1379 conn = get(conn, "/api/pleroma/admin/users/invites")
1381 assert json_response(conn, 200) == %{
1384 "expires_at" => nil,
1386 "invite_type" => "one_time",
1388 "token" => invite.token,
1397 describe "POST /api/pleroma/admin/users/revoke_invite" do
1398 test "with token", %{conn: conn} do
1399 {:ok, invite} = UserInviteToken.create_invite()
1401 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1403 assert json_response(conn, 200) == %{
1404 "expires_at" => nil,
1406 "invite_type" => "one_time",
1408 "token" => invite.token,
1414 test "with invalid token", %{conn: conn} do
1415 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1417 assert json_response(conn, :not_found) == "Not found"
1421 describe "GET /api/pleroma/admin/reports/:id" do
1422 test "returns report by its id", %{conn: conn} do
1423 [reporter, target_user] = insert_pair(:user)
1424 activity = insert(:note_activity, user: target_user)
1426 {:ok, %{id: report_id}} =
1427 CommonAPI.report(reporter, %{
1428 account_id: target_user.id,
1429 comment: "I feel offended",
1430 status_ids: [activity.id]
1435 |> get("/api/pleroma/admin/reports/#{report_id}")
1436 |> json_response(:ok)
1438 assert response["id"] == report_id
1441 test "returns 404 when report id is invalid", %{conn: conn} do
1442 conn = get(conn, "/api/pleroma/admin/reports/test")
1444 assert json_response(conn, :not_found) == "Not found"
1448 describe "PATCH /api/pleroma/admin/reports" do
1450 [reporter, target_user] = insert_pair(:user)
1451 activity = insert(:note_activity, user: target_user)
1453 {:ok, %{id: report_id}} =
1454 CommonAPI.report(reporter, %{
1455 account_id: target_user.id,
1456 comment: "I feel offended",
1457 status_ids: [activity.id]
1460 {:ok, %{id: second_report_id}} =
1461 CommonAPI.report(reporter, %{
1462 account_id: target_user.id,
1463 comment: "I feel very offended",
1464 status_ids: [activity.id]
1469 second_report_id: second_report_id
1473 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1474 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1475 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1479 |> assign(:token, read_token)
1480 |> patch("/api/pleroma/admin/reports", %{
1481 "reports" => [%{"state" => "resolved", "id" => id}]
1483 |> json_response(403)
1485 assert response == %{
1486 "error" => "Insufficient permissions: admin:write:reports."
1490 |> assign(:token, write_token)
1491 |> patch("/api/pleroma/admin/reports", %{
1492 "reports" => [%{"state" => "resolved", "id" => id}]
1494 |> json_response(:no_content)
1497 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1499 |> patch("/api/pleroma/admin/reports", %{
1501 %{"state" => "resolved", "id" => id}
1504 |> json_response(:no_content)
1506 activity = Activity.get_by_id(id)
1507 assert activity.data["state"] == "resolved"
1509 log_entry = Repo.one(ModerationLog)
1511 assert ModerationLog.get_log_entry_message(log_entry) ==
1512 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1515 test "closes report", %{conn: conn, id: id, admin: admin} do
1517 |> patch("/api/pleroma/admin/reports", %{
1519 %{"state" => "closed", "id" => id}
1522 |> json_response(:no_content)
1524 activity = Activity.get_by_id(id)
1525 assert activity.data["state"] == "closed"
1527 log_entry = Repo.one(ModerationLog)
1529 assert ModerationLog.get_log_entry_message(log_entry) ==
1530 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1533 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1536 |> patch("/api/pleroma/admin/reports", %{
1538 %{"state" => "test", "id" => id}
1542 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1545 test "returns 404 when report is not exist", %{conn: conn} do
1548 |> patch("/api/pleroma/admin/reports", %{
1550 %{"state" => "closed", "id" => "test"}
1554 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1557 test "updates state of multiple reports", %{
1561 second_report_id: second_report_id
1564 |> patch("/api/pleroma/admin/reports", %{
1566 %{"state" => "resolved", "id" => id},
1567 %{"state" => "closed", "id" => second_report_id}
1570 |> json_response(:no_content)
1572 activity = Activity.get_by_id(id)
1573 second_activity = Activity.get_by_id(second_report_id)
1574 assert activity.data["state"] == "resolved"
1575 assert second_activity.data["state"] == "closed"
1577 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1579 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1580 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1582 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1583 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1587 describe "GET /api/pleroma/admin/reports" do
1588 test "returns empty response when no reports created", %{conn: conn} do
1591 |> get("/api/pleroma/admin/reports")
1592 |> json_response(:ok)
1594 assert Enum.empty?(response["reports"])
1595 assert response["total"] == 0
1598 test "returns reports", %{conn: conn} do
1599 [reporter, target_user] = insert_pair(:user)
1600 activity = insert(:note_activity, user: target_user)
1602 {:ok, %{id: report_id}} =
1603 CommonAPI.report(reporter, %{
1604 account_id: target_user.id,
1605 comment: "I feel offended",
1606 status_ids: [activity.id]
1611 |> get("/api/pleroma/admin/reports")
1612 |> json_response(:ok)
1614 [report] = response["reports"]
1616 assert length(response["reports"]) == 1
1617 assert report["id"] == report_id
1619 assert response["total"] == 1
1622 test "returns reports with specified state", %{conn: conn} do
1623 [reporter, target_user] = insert_pair(:user)
1624 activity = insert(:note_activity, user: target_user)
1626 {:ok, %{id: first_report_id}} =
1627 CommonAPI.report(reporter, %{
1628 account_id: target_user.id,
1629 comment: "I feel offended",
1630 status_ids: [activity.id]
1633 {:ok, %{id: second_report_id}} =
1634 CommonAPI.report(reporter, %{
1635 account_id: target_user.id,
1636 comment: "I don't like this user"
1639 CommonAPI.update_report_state(second_report_id, "closed")
1643 |> get("/api/pleroma/admin/reports", %{
1646 |> json_response(:ok)
1648 [open_report] = response["reports"]
1650 assert length(response["reports"]) == 1
1651 assert open_report["id"] == first_report_id
1653 assert response["total"] == 1
1657 |> get("/api/pleroma/admin/reports", %{
1660 |> json_response(:ok)
1662 [closed_report] = response["reports"]
1664 assert length(response["reports"]) == 1
1665 assert closed_report["id"] == second_report_id
1667 assert response["total"] == 1
1671 |> get("/api/pleroma/admin/reports", %{
1672 "state" => "resolved"
1674 |> json_response(:ok)
1676 assert Enum.empty?(response["reports"])
1677 assert response["total"] == 0
1680 test "returns 403 when requested by a non-admin" do
1681 user = insert(:user)
1682 token = insert(:oauth_token, user: user)
1686 |> assign(:user, user)
1687 |> assign(:token, token)
1688 |> get("/api/pleroma/admin/reports")
1690 assert json_response(conn, :forbidden) ==
1691 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1694 test "returns 403 when requested by anonymous" do
1695 conn = get(build_conn(), "/api/pleroma/admin/reports")
1697 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1701 describe "GET /api/pleroma/admin/statuses/:id" do
1702 test "not found", %{conn: conn} do
1704 |> get("/api/pleroma/admin/statuses/not_found")
1705 |> json_response(:not_found)
1708 test "shows activity", %{conn: conn} do
1709 activity = insert(:note_activity)
1713 |> get("/api/pleroma/admin/statuses/#{activity.id}")
1714 |> json_response(200)
1716 assert response["id"] == activity.id
1720 describe "PUT /api/pleroma/admin/statuses/:id" do
1722 activity = insert(:note_activity)
1727 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1730 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1731 |> json_response(:ok)
1733 assert response["sensitive"]
1735 log_entry = Repo.one(ModerationLog)
1737 assert ModerationLog.get_log_entry_message(log_entry) ==
1738 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1742 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1743 |> json_response(:ok)
1745 refute response["sensitive"]
1748 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1751 |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "public"})
1752 |> json_response(:ok)
1754 assert response["visibility"] == "public"
1756 log_entry = Repo.one(ModerationLog)
1758 assert ModerationLog.get_log_entry_message(log_entry) ==
1759 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1763 |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "private"})
1764 |> json_response(:ok)
1766 assert response["visibility"] == "private"
1770 |> put("/api/pleroma/admin/statuses/#{id}", %{visibility: "unlisted"})
1771 |> json_response(:ok)
1773 assert response["visibility"] == "unlisted"
1776 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1777 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{visibility: "test"})
1779 assert json_response(conn, :bad_request) == "Unsupported visibility"
1783 describe "DELETE /api/pleroma/admin/statuses/:id" do
1785 activity = insert(:note_activity)
1790 test "deletes status", %{conn: conn, id: id, admin: admin} do
1792 |> delete("/api/pleroma/admin/statuses/#{id}")
1793 |> json_response(:ok)
1795 refute Activity.get_by_id(id)
1797 log_entry = Repo.one(ModerationLog)
1799 assert ModerationLog.get_log_entry_message(log_entry) ==
1800 "@#{admin.nickname} deleted status ##{id}"
1803 test "returns 404 when the status does not exist", %{conn: conn} do
1804 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1806 assert json_response(conn, :not_found) == "Not found"
1810 describe "GET /api/pleroma/admin/config" do
1811 setup do: clear_config(:configurable_from_database, true)
1813 test "when configuration from database is off", %{conn: conn} do
1814 Config.put(:configurable_from_database, false)
1815 conn = get(conn, "/api/pleroma/admin/config")
1817 assert json_response(conn, 400) ==
1818 "To use this endpoint you need to enable configuration from database."
1821 test "with settings only in db", %{conn: conn} do
1822 config1 = insert(:config)
1823 config2 = insert(:config)
1825 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1830 "group" => ":pleroma",
1835 "group" => ":pleroma",
1840 } = json_response(conn, 200)
1842 assert key1 == config1.key
1843 assert key2 == config2.key
1846 test "db is added to settings that are in db", %{conn: conn} do
1847 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1849 %{"configs" => configs} =
1851 |> get("/api/pleroma/admin/config")
1852 |> json_response(200)
1855 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1856 group == ":pleroma" and key == ":instance"
1859 assert instance_config["db"] == [":name"]
1862 test "merged default setting with db settings", %{conn: conn} do
1863 config1 = insert(:config)
1864 config2 = insert(:config)
1868 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1871 %{"configs" => configs} =
1873 |> get("/api/pleroma/admin/config")
1874 |> json_response(200)
1876 assert length(configs) > 3
1879 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1880 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1883 assert length(received_configs) == 3
1887 |> ConfigDB.from_binary()
1889 |> ConfigDB.convert()
1891 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1892 assert db in [[config1.key], [config2.key], db_keys]
1895 ConfigDB.from_binary_with_convert(config1.value),
1896 ConfigDB.from_binary_with_convert(config2.value),
1897 ConfigDB.from_binary_with_convert(config3.value)
1902 test "subkeys with full update right merge", %{conn: conn} do
1906 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1912 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1915 %{"configs" => configs} =
1917 |> get("/api/pleroma/admin/config")
1918 |> json_response(200)
1921 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1922 group == ":pleroma" and key in [config1.key, config2.key]
1925 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1926 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1928 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1929 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1931 assert emoji_val[:groups] == [a: 1, b: 2]
1932 assert assets_val[:mascots] == [a: 1, b: 2]
1936 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1937 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1939 assert json_response(conn, 400) ==
1940 "To use this endpoint you need to enable configuration from database."
1943 describe "POST /api/pleroma/admin/config" do
1945 http = Application.get_env(:pleroma, :http)
1948 Application.delete_env(:pleroma, :key1)
1949 Application.delete_env(:pleroma, :key2)
1950 Application.delete_env(:pleroma, :key3)
1951 Application.delete_env(:pleroma, :key4)
1952 Application.delete_env(:pleroma, :keyaa1)
1953 Application.delete_env(:pleroma, :keyaa2)
1954 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1955 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1956 Application.put_env(:pleroma, :http, http)
1957 Application.put_env(:tesla, :adapter, Tesla.Mock)
1958 Restarter.Pleroma.refresh()
1962 setup do: clear_config(:configurable_from_database, true)
1964 @tag capture_log: true
1965 test "create new config setting in db", %{conn: conn} do
1966 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1967 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1970 post(conn, "/api/pleroma/admin/config", %{
1972 %{group: ":pleroma", key: ":key1", value: "value1"},
1974 group: ":ueberauth",
1976 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1982 ":nested_1" => "nested_value1",
1984 %{":nested_22" => "nested_value222"},
1985 %{":nested_33" => %{":nested_44" => "nested_444"}}
1993 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1994 %{"nested_4" => true}
2000 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2005 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2010 assert json_response(conn, 200) == %{
2013 "group" => ":pleroma",
2015 "value" => "value1",
2019 "group" => ":ueberauth",
2020 "key" => "Ueberauth",
2021 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
2022 "db" => [":consumer_secret"]
2025 "group" => ":pleroma",
2028 ":nested_1" => "nested_value1",
2030 %{":nested_22" => "nested_value222"},
2031 %{":nested_33" => %{":nested_44" => "nested_444"}}
2037 "group" => ":pleroma",
2040 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2041 %{"nested_4" => true}
2046 "group" => ":pleroma",
2048 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2054 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2060 assert Application.get_env(:pleroma, :key1) == "value1"
2062 assert Application.get_env(:pleroma, :key2) == %{
2063 nested_1: "nested_value1",
2065 %{nested_22: "nested_value222"},
2066 %{nested_33: %{nested_44: "nested_444"}}
2070 assert Application.get_env(:pleroma, :key3) == [
2071 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2072 %{"nested_4" => true}
2075 assert Application.get_env(:pleroma, :key4) == %{
2076 "endpoint" => "https://example.com",
2080 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2083 test "save configs setting without explicit key", %{conn: conn} do
2084 level = Application.get_env(:quack, :level)
2085 meta = Application.get_env(:quack, :meta)
2086 webhook_url = Application.get_env(:quack, :webhook_url)
2089 Application.put_env(:quack, :level, level)
2090 Application.put_env(:quack, :meta, meta)
2091 Application.put_env(:quack, :webhook_url, webhook_url)
2095 post(conn, "/api/pleroma/admin/config", %{
2109 key: ":webhook_url",
2110 value: "https://hooks.slack.com/services/KEY"
2115 assert json_response(conn, 200) == %{
2118 "group" => ":quack",
2124 "group" => ":quack",
2126 "value" => [":none"],
2130 "group" => ":quack",
2131 "key" => ":webhook_url",
2132 "value" => "https://hooks.slack.com/services/KEY",
2133 "db" => [":webhook_url"]
2138 assert Application.get_env(:quack, :level) == :info
2139 assert Application.get_env(:quack, :meta) == [:none]
2140 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2143 test "saving config with partial update", %{conn: conn} do
2144 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2147 post(conn, "/api/pleroma/admin/config", %{
2149 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2153 assert json_response(conn, 200) == %{
2156 "group" => ":pleroma",
2159 %{"tuple" => [":key1", 1]},
2160 %{"tuple" => [":key2", 2]},
2161 %{"tuple" => [":key3", 3]}
2163 "db" => [":key1", ":key2", ":key3"]
2169 test "saving config which need pleroma reboot", %{conn: conn} do
2170 chat = Config.get(:chat)
2171 on_exit(fn -> Config.put(:chat, chat) end)
2175 "/api/pleroma/admin/config",
2178 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2182 |> json_response(200) == %{
2185 "db" => [":enabled"],
2186 "group" => ":pleroma",
2188 "value" => [%{"tuple" => [":enabled", true]}]
2191 "need_reboot" => true
2196 |> get("/api/pleroma/admin/config")
2197 |> json_response(200)
2199 assert configs["need_reboot"]
2202 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2203 end) =~ "pleroma restarted"
2207 |> get("/api/pleroma/admin/config")
2208 |> json_response(200)
2210 assert configs["need_reboot"] == false
2213 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2214 chat = Config.get(:chat)
2215 on_exit(fn -> Config.put(:chat, chat) end)
2219 "/api/pleroma/admin/config",
2222 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2226 |> json_response(200) == %{
2229 "db" => [":enabled"],
2230 "group" => ":pleroma",
2232 "value" => [%{"tuple" => [":enabled", true]}]
2235 "need_reboot" => true
2238 assert post(conn, "/api/pleroma/admin/config", %{
2240 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2243 |> json_response(200) == %{
2246 "group" => ":pleroma",
2249 %{"tuple" => [":key3", 3]}
2254 "need_reboot" => true
2258 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2259 end) =~ "pleroma restarted"
2263 |> get("/api/pleroma/admin/config")
2264 |> json_response(200)
2266 assert configs["need_reboot"] == false
2269 test "saving config with nested merge", %{conn: conn} do
2271 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2274 post(conn, "/api/pleroma/admin/config", %{
2277 group: config.group,
2280 %{"tuple" => [":key3", 3]},
2285 %{"tuple" => [":k2", 1]},
2286 %{"tuple" => [":k3", 3]}
2295 assert json_response(conn, 200) == %{
2298 "group" => ":pleroma",
2301 %{"tuple" => [":key1", 1]},
2302 %{"tuple" => [":key3", 3]},
2307 %{"tuple" => [":k1", 1]},
2308 %{"tuple" => [":k2", 1]},
2309 %{"tuple" => [":k3", 3]}
2314 "db" => [":key1", ":key3", ":key2"]
2320 test "saving special atoms", %{conn: conn} do
2322 post(conn, "/api/pleroma/admin/config", %{
2325 "group" => ":pleroma",
2331 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2339 assert json_response(conn, 200) == %{
2342 "group" => ":pleroma",
2348 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2352 "db" => [":ssl_options"]
2357 assert Application.get_env(:pleroma, :key1) == [
2358 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2362 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2363 backends = Application.get_env(:logger, :backends)
2364 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2370 value: :erlang.term_to_binary([])
2373 Pleroma.Config.TransferTask.load_and_update_env([], false)
2375 assert Application.get_env(:logger, :backends) == []
2378 post(conn, "/api/pleroma/admin/config", %{
2381 group: config.group,
2388 assert json_response(conn, 200) == %{
2391 "group" => ":logger",
2392 "key" => ":backends",
2396 "db" => [":backends"]
2401 assert Application.get_env(:logger, :backends) == [
2406 test "saving full setting if value is not keyword", %{conn: conn} do
2411 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2415 post(conn, "/api/pleroma/admin/config", %{
2417 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2421 assert json_response(conn, 200) == %{
2424 "group" => ":tesla",
2425 "key" => ":adapter",
2426 "value" => "Tesla.Adapter.Httpc",
2427 "db" => [":adapter"]
2433 test "update config setting & delete with fallback to default value", %{
2438 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2439 config1 = insert(:config, key: ":keyaa1")
2440 config2 = insert(:config, key: ":keyaa2")
2444 group: ":ueberauth",
2449 post(conn, "/api/pleroma/admin/config", %{
2451 %{group: config1.group, key: config1.key, value: "another_value"},
2452 %{group: config2.group, key: config2.key, value: "another_value"}
2456 assert json_response(conn, 200) == %{
2459 "group" => ":pleroma",
2460 "key" => config1.key,
2461 "value" => "another_value",
2465 "group" => ":pleroma",
2466 "key" => config2.key,
2467 "value" => "another_value",
2473 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2474 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2475 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2479 |> assign(:user, admin)
2480 |> assign(:token, token)
2481 |> post("/api/pleroma/admin/config", %{
2483 %{group: config2.group, key: config2.key, delete: true},
2485 group: ":ueberauth",
2492 assert json_response(conn, 200) == %{
2496 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2497 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2500 test "common config example", %{conn: conn} do
2502 post(conn, "/api/pleroma/admin/config", %{
2505 "group" => ":pleroma",
2506 "key" => "Pleroma.Captcha.NotReal",
2508 %{"tuple" => [":enabled", false]},
2509 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2510 %{"tuple" => [":seconds_valid", 60]},
2511 %{"tuple" => [":path", ""]},
2512 %{"tuple" => [":key1", nil]},
2513 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2514 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2515 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2516 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2517 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2518 %{"tuple" => [":name", "Pleroma"]}
2524 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2526 assert json_response(conn, 200) == %{
2529 "group" => ":pleroma",
2530 "key" => "Pleroma.Captcha.NotReal",
2532 %{"tuple" => [":enabled", false]},
2533 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2534 %{"tuple" => [":seconds_valid", 60]},
2535 %{"tuple" => [":path", ""]},
2536 %{"tuple" => [":key1", nil]},
2537 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2538 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2539 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2540 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2541 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2542 %{"tuple" => [":name", "Pleroma"]}
2562 test "tuples with more than two values", %{conn: conn} do
2564 post(conn, "/api/pleroma/admin/config", %{
2567 "group" => ":pleroma",
2568 "key" => "Pleroma.Web.Endpoint.NotReal",
2584 "/api/v1/streaming",
2585 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2592 "Phoenix.Endpoint.CowboyWebSocket",
2595 "Phoenix.Transports.WebSocket",
2598 "Pleroma.Web.Endpoint",
2599 "Pleroma.Web.UserSocket",
2610 "Phoenix.Endpoint.Cowboy2Handler",
2611 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2628 assert json_response(conn, 200) == %{
2631 "group" => ":pleroma",
2632 "key" => "Pleroma.Web.Endpoint.NotReal",
2648 "/api/v1/streaming",
2649 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2656 "Phoenix.Endpoint.CowboyWebSocket",
2659 "Phoenix.Transports.WebSocket",
2662 "Pleroma.Web.Endpoint",
2663 "Pleroma.Web.UserSocket",
2674 "Phoenix.Endpoint.Cowboy2Handler",
2675 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2694 test "settings with nesting map", %{conn: conn} do
2696 post(conn, "/api/pleroma/admin/config", %{
2699 "group" => ":pleroma",
2702 %{"tuple" => [":key2", "some_val"]},
2707 ":max_options" => 20,
2708 ":max_option_chars" => 200,
2709 ":min_expiration" => 0,
2710 ":max_expiration" => 31_536_000,
2712 ":max_options" => 20,
2713 ":max_option_chars" => 200,
2714 ":min_expiration" => 0,
2715 ":max_expiration" => 31_536_000
2725 assert json_response(conn, 200) ==
2729 "group" => ":pleroma",
2732 %{"tuple" => [":key2", "some_val"]},
2737 ":max_expiration" => 31_536_000,
2738 ":max_option_chars" => 200,
2739 ":max_options" => 20,
2740 ":min_expiration" => 0,
2742 ":max_expiration" => 31_536_000,
2743 ":max_option_chars" => 200,
2744 ":max_options" => 20,
2745 ":min_expiration" => 0
2751 "db" => [":key2", ":key3"]
2757 test "value as map", %{conn: conn} do
2759 post(conn, "/api/pleroma/admin/config", %{
2762 "group" => ":pleroma",
2764 "value" => %{"key" => "some_val"}
2769 assert json_response(conn, 200) ==
2773 "group" => ":pleroma",
2775 "value" => %{"key" => "some_val"},
2782 test "queues key as atom", %{conn: conn} do
2784 post(conn, "/api/pleroma/admin/config", %{
2790 %{"tuple" => [":federator_incoming", 50]},
2791 %{"tuple" => [":federator_outgoing", 50]},
2792 %{"tuple" => [":web_push", 50]},
2793 %{"tuple" => [":mailer", 10]},
2794 %{"tuple" => [":transmogrifier", 20]},
2795 %{"tuple" => [":scheduled_activities", 10]},
2796 %{"tuple" => [":background", 5]}
2802 assert json_response(conn, 200) == %{
2808 %{"tuple" => [":federator_incoming", 50]},
2809 %{"tuple" => [":federator_outgoing", 50]},
2810 %{"tuple" => [":web_push", 50]},
2811 %{"tuple" => [":mailer", 10]},
2812 %{"tuple" => [":transmogrifier", 20]},
2813 %{"tuple" => [":scheduled_activities", 10]},
2814 %{"tuple" => [":background", 5]}
2817 ":federator_incoming",
2818 ":federator_outgoing",
2822 ":scheduled_activities",
2830 test "delete part of settings by atom subkeys", %{conn: conn} do
2834 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2838 post(conn, "/api/pleroma/admin/config", %{
2841 group: config.group,
2843 subkeys: [":subkey1", ":subkey3"],
2849 assert json_response(conn, 200) == %{
2852 "group" => ":pleroma",
2854 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2855 "db" => [":subkey2"]
2861 test "proxy tuple localhost", %{conn: conn} do
2863 post(conn, "/api/pleroma/admin/config", %{
2869 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}
2878 "group" => ":pleroma",
2884 } = json_response(conn, 200)
2886 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value
2887 assert ":proxy_url" in db
2890 test "proxy tuple domain", %{conn: conn} do
2892 post(conn, "/api/pleroma/admin/config", %{
2898 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}
2907 "group" => ":pleroma",
2913 } = json_response(conn, 200)
2915 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value
2916 assert ":proxy_url" in db
2919 test "proxy tuple ip", %{conn: conn} do
2921 post(conn, "/api/pleroma/admin/config", %{
2927 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}
2936 "group" => ":pleroma",
2942 } = json_response(conn, 200)
2944 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
2945 assert ":proxy_url" in db
2948 @tag capture_log: true
2949 test "doesn't set keys not in the whitelist", %{conn: conn} do
2950 clear_config(:database_config_whitelist, [
2953 {:pleroma, Pleroma.Captcha.NotReal},
2957 post(conn, "/api/pleroma/admin/config", %{
2959 %{group: ":pleroma", key: ":key1", value: "value1"},
2960 %{group: ":pleroma", key: ":key2", value: "value2"},
2961 %{group: ":pleroma", key: ":key3", value: "value3"},
2962 %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
2963 %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
2964 %{group: ":not_real", key: ":anything", value: "value6"}
2968 assert Application.get_env(:pleroma, :key1) == "value1"
2969 assert Application.get_env(:pleroma, :key2) == "value2"
2970 assert Application.get_env(:pleroma, :key3) == nil
2971 assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
2972 assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
2973 assert Application.get_env(:not_real, :anything) == "value6"
2977 describe "GET /api/pleroma/admin/restart" do
2978 setup do: clear_config(:configurable_from_database, true)
2980 test "pleroma restarts", %{conn: conn} do
2982 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2983 end) =~ "pleroma restarted"
2985 refute Restarter.Pleroma.need_reboot?()
2989 test "need_reboot flag", %{conn: conn} do
2991 |> get("/api/pleroma/admin/need_reboot")
2992 |> json_response(200) == %{"need_reboot" => false}
2994 Restarter.Pleroma.need_reboot()
2997 |> get("/api/pleroma/admin/need_reboot")
2998 |> json_response(200) == %{"need_reboot" => true}
3000 on_exit(fn -> Restarter.Pleroma.refresh() end)
3003 describe "GET /api/pleroma/admin/statuses" do
3004 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
3005 blocked = insert(:user)
3006 user = insert(:user)
3007 User.block(admin, blocked)
3009 {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
3011 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
3012 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
3013 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
3014 {:ok, _} = CommonAPI.post(blocked, %{status: ".", visibility: "public"})
3018 |> get("/api/pleroma/admin/statuses")
3019 |> json_response(200)
3021 refute "private" in Enum.map(response, & &1["visibility"])
3022 assert length(response) == 3
3025 test "returns only local statuses with local_only on", %{conn: conn} do
3026 user = insert(:user)
3027 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
3028 insert(:note_activity, user: user, local: true)
3029 insert(:note_activity, user: remote_user, local: false)
3033 |> get("/api/pleroma/admin/statuses?local_only=true")
3034 |> json_response(200)
3036 assert length(response) == 1
3039 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
3040 user = insert(:user)
3042 {:ok, _} = CommonAPI.post(user, %{status: "@#{admin.nickname}", visibility: "direct"})
3044 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "private"})
3045 {:ok, _} = CommonAPI.post(user, %{status: ".", visibility: "public"})
3046 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
3047 assert json_response(conn, 200) |> length() == 3
3051 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3053 user = insert(:user)
3055 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3056 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3057 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3059 insert(:note_activity, user: user, published: date1)
3060 insert(:note_activity, user: user, published: date2)
3061 insert(:note_activity, user: user, published: date3)
3066 test "renders user's statuses", %{conn: conn, user: user} do
3067 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3069 assert json_response(conn, 200) |> length() == 3
3072 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3073 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3075 assert json_response(conn, 200) |> length() == 2
3078 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3079 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
3081 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
3083 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3085 assert json_response(conn, 200) |> length() == 4
3088 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3089 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
3091 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
3093 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3095 assert json_response(conn, 200) |> length() == 5
3098 test "excludes reblogs by default", %{conn: conn, user: user} do
3099 other_user = insert(:user)
3100 {:ok, activity} = CommonAPI.post(user, %{status: "."})
3101 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
3103 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3104 assert json_response(conn_res, 200) |> length() == 0
3107 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3109 assert json_response(conn_res, 200) |> length() == 1
3113 describe "GET /api/pleroma/admin/moderation_log" do
3115 moderator = insert(:user, is_moderator: true)
3117 %{moderator: moderator}
3120 test "returns the log", %{conn: conn, admin: admin} do
3121 Repo.insert(%ModerationLog{
3125 "nickname" => admin.nickname,
3128 action: "relay_follow",
3129 target: "https://example.org/relay"
3131 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3134 Repo.insert(%ModerationLog{
3138 "nickname" => admin.nickname,
3141 action: "relay_unfollow",
3142 target: "https://example.org/relay"
3144 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3147 conn = get(conn, "/api/pleroma/admin/moderation_log")
3149 response = json_response(conn, 200)
3150 [first_entry, second_entry] = response["items"]
3152 assert response["total"] == 2
3153 assert first_entry["data"]["action"] == "relay_unfollow"
3155 assert first_entry["message"] ==
3156 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3158 assert second_entry["data"]["action"] == "relay_follow"
3160 assert second_entry["message"] ==
3161 "@#{admin.nickname} followed relay: https://example.org/relay"
3164 test "returns the log with pagination", %{conn: conn, admin: admin} do
3165 Repo.insert(%ModerationLog{
3169 "nickname" => admin.nickname,
3172 action: "relay_follow",
3173 target: "https://example.org/relay"
3175 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3178 Repo.insert(%ModerationLog{
3182 "nickname" => admin.nickname,
3185 action: "relay_unfollow",
3186 target: "https://example.org/relay"
3188 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3191 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3193 response1 = json_response(conn1, 200)
3194 [first_entry] = response1["items"]
3196 assert response1["total"] == 2
3197 assert response1["items"] |> length() == 1
3198 assert first_entry["data"]["action"] == "relay_unfollow"
3200 assert first_entry["message"] ==
3201 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3203 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3205 response2 = json_response(conn2, 200)
3206 [second_entry] = response2["items"]
3208 assert response2["total"] == 2
3209 assert response2["items"] |> length() == 1
3210 assert second_entry["data"]["action"] == "relay_follow"
3212 assert second_entry["message"] ==
3213 "@#{admin.nickname} followed relay: https://example.org/relay"
3216 test "filters log by date", %{conn: conn, admin: admin} do
3217 first_date = "2017-08-15T15:47:06Z"
3218 second_date = "2017-08-20T15:47:06Z"
3220 Repo.insert(%ModerationLog{
3224 "nickname" => admin.nickname,
3227 action: "relay_follow",
3228 target: "https://example.org/relay"
3230 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3233 Repo.insert(%ModerationLog{
3237 "nickname" => admin.nickname,
3240 action: "relay_unfollow",
3241 target: "https://example.org/relay"
3243 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3249 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3252 response1 = json_response(conn1, 200)
3253 [first_entry] = response1["items"]
3255 assert response1["total"] == 1
3256 assert first_entry["data"]["action"] == "relay_unfollow"
3258 assert first_entry["message"] ==
3259 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3262 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3263 Repo.insert(%ModerationLog{
3267 "nickname" => admin.nickname,
3270 action: "relay_follow",
3271 target: "https://example.org/relay"
3275 Repo.insert(%ModerationLog{
3278 "id" => moderator.id,
3279 "nickname" => moderator.nickname,
3282 action: "relay_unfollow",
3283 target: "https://example.org/relay"
3287 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3289 response1 = json_response(conn1, 200)
3290 [first_entry] = response1["items"]
3292 assert response1["total"] == 1
3293 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3296 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3297 ModerationLog.insert_log(%{
3299 action: "relay_follow",
3300 target: "https://example.org/relay"
3303 ModerationLog.insert_log(%{
3305 action: "relay_unfollow",
3306 target: "https://example.org/relay"
3309 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3311 response1 = json_response(conn1, 200)
3312 [first_entry] = response1["items"]
3314 assert response1["total"] == 1
3316 assert get_in(first_entry, ["data", "message"]) ==
3317 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3321 describe "GET /users/:nickname/credentials" do
3322 test "gets the user credentials", %{conn: conn} do
3323 user = insert(:user)
3324 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3326 response = assert json_response(conn, 200)
3327 assert response["email"] == user.email
3330 test "returns 403 if requested by a non-admin" do
3331 user = insert(:user)
3335 |> assign(:user, user)
3336 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3338 assert json_response(conn, :forbidden)
3342 describe "PATCH /users/:nickname/credentials" do
3343 test "changes password and email", %{conn: conn, admin: admin} do
3344 user = insert(:user)
3345 assert user.password_reset_pending == false
3348 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3349 "password" => "new_password",
3350 "email" => "new_email@example.com",
3351 "name" => "new_name"
3354 assert json_response(conn, 200) == %{"status" => "success"}
3356 ObanHelpers.perform_all()
3358 updated_user = User.get_by_id(user.id)
3360 assert updated_user.email == "new_email@example.com"
3361 assert updated_user.name == "new_name"
3362 assert updated_user.password_hash != user.password_hash
3363 assert updated_user.password_reset_pending == true
3365 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3367 assert ModerationLog.get_log_entry_message(log_entry1) ==
3368 "@#{admin.nickname} updated users: @#{user.nickname}"
3370 assert ModerationLog.get_log_entry_message(log_entry2) ==
3371 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3374 test "returns 403 if requested by a non-admin" do
3375 user = insert(:user)
3379 |> assign(:user, user)
3380 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3381 "password" => "new_password",
3382 "email" => "new_email@example.com",
3383 "name" => "new_name"
3386 assert json_response(conn, :forbidden)
3390 describe "PATCH /users/:nickname/force_password_reset" do
3391 test "sets password_reset_pending to true", %{conn: conn} do
3392 user = insert(:user)
3393 assert user.password_reset_pending == false
3396 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3398 assert json_response(conn, 204) == ""
3400 ObanHelpers.perform_all()
3402 assert User.get_by_id(user.id).password_reset_pending == true
3406 describe "relays" do
3407 test "POST /relay", %{conn: conn, admin: admin} do
3409 post(conn, "/api/pleroma/admin/relay", %{
3410 relay_url: "http://mastodon.example.org/users/admin"
3413 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3415 log_entry = Repo.one(ModerationLog)
3417 assert ModerationLog.get_log_entry_message(log_entry) ==
3418 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3421 test "GET /relay", %{conn: conn} do
3422 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3424 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3425 |> Enum.each(fn ap_id ->
3426 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3427 User.follow(relay_user, user)
3430 conn = get(conn, "/api/pleroma/admin/relay")
3432 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3435 test "DELETE /relay", %{conn: conn, admin: admin} do
3436 post(conn, "/api/pleroma/admin/relay", %{
3437 relay_url: "http://mastodon.example.org/users/admin"
3441 delete(conn, "/api/pleroma/admin/relay", %{
3442 relay_url: "http://mastodon.example.org/users/admin"
3445 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3447 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3449 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3450 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3452 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3453 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3457 describe "instances" do
3458 test "GET /instances/:instance/statuses", %{conn: conn} do
3459 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3460 user2 = insert(:user, local: false, nickname: "test@test.com")
3461 insert_pair(:note_activity, user: user)
3462 activity = insert(:note_activity, user: user2)
3464 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3466 response = json_response(ret_conn, 200)
3468 assert length(response) == 2
3470 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3472 response = json_response(ret_conn, 200)
3474 assert length(response) == 1
3476 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3478 response = json_response(ret_conn, 200)
3480 assert Enum.empty?(response)
3482 CommonAPI.repeat(activity.id, user)
3484 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3485 response = json_response(ret_conn, 200)
3486 assert length(response) == 2
3488 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3489 response = json_response(ret_conn, 200)
3490 assert length(response) == 3
3494 describe "PATCH /confirm_email" do
3495 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3496 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3498 assert first_user.confirmation_pending == true
3499 assert second_user.confirmation_pending == true
3502 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3504 first_user.nickname,
3505 second_user.nickname
3509 assert ret_conn.status == 200
3511 assert first_user.confirmation_pending == true
3512 assert second_user.confirmation_pending == true
3514 log_entry = Repo.one(ModerationLog)
3516 assert ModerationLog.get_log_entry_message(log_entry) ==
3517 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3518 second_user.nickname
3523 describe "PATCH /resend_confirmation_email" do
3524 test "it resend emails for two users", %{conn: conn, admin: admin} do
3525 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3528 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3530 first_user.nickname,
3531 second_user.nickname
3535 assert ret_conn.status == 200
3537 log_entry = Repo.one(ModerationLog)
3539 assert ModerationLog.get_log_entry_message(log_entry) ==
3540 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3541 second_user.nickname
3546 describe "POST /reports/:id/notes" do
3547 setup %{conn: conn, admin: admin} do
3548 [reporter, target_user] = insert_pair(:user)
3549 activity = insert(:note_activity, user: target_user)
3551 {:ok, %{id: report_id}} =
3552 CommonAPI.report(reporter, %{
3553 account_id: target_user.id,
3554 comment: "I feel offended",
3555 status_ids: [activity.id]
3558 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3559 content: "this is disgusting!"
3562 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3563 content: "this is disgusting2!"
3568 report_id: report_id
3572 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3573 [note, _] = Repo.all(ReportNote)
3576 activity_id: ^report_id,
3577 content: "this is disgusting!",
3582 test "it returns reports with notes", %{conn: conn, admin: admin} do
3583 conn = get(conn, "/api/pleroma/admin/reports")
3585 response = json_response(conn, 200)
3586 notes = hd(response["reports"])["notes"]
3589 assert note["user"]["nickname"] == admin.nickname
3590 assert note["content"] == "this is disgusting!"
3591 assert note["created_at"]
3592 assert response["total"] == 1
3595 test "it deletes the note", %{conn: conn, report_id: report_id} do
3596 assert ReportNote |> Repo.all() |> length() == 2
3598 [note, _] = Repo.all(ReportNote)
3600 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3602 assert ReportNote |> Repo.all() |> length() == 1
3606 describe "GET /api/pleroma/admin/config/descriptions" do
3607 test "structure", %{conn: conn} do
3608 admin = insert(:user, is_admin: true)
3611 assign(conn, :user, admin)
3612 |> get("/api/pleroma/admin/config/descriptions")
3614 assert [child | _others] = json_response(conn, 200)
3616 assert child["children"]
3618 assert String.starts_with?(child["group"], ":")
3619 assert child["description"]
3622 test "filters by database configuration whitelist", %{conn: conn} do
3623 clear_config(:database_config_whitelist, [
3624 {:pleroma, :instance},
3625 {:pleroma, :activitypub},
3626 {:pleroma, Pleroma.Upload},
3630 admin = insert(:user, is_admin: true)
3633 assign(conn, :user, admin)
3634 |> get("/api/pleroma/admin/config/descriptions")
3636 children = json_response(conn, 200)
3638 assert length(children) == 4
3640 assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
3642 instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
3643 assert instance["children"]
3645 activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
3646 assert activitypub["children"]
3648 web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
3649 assert web_endpoint["children"]
3651 esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
3652 assert esshd["children"]
3656 describe "/api/pleroma/admin/stats" do
3657 test "status visibility count", %{conn: conn} do
3658 admin = insert(:user, is_admin: true)
3659 user = insert(:user)
3660 CommonAPI.post(user, %{visibility: "public", status: "hey"})
3661 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3662 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3666 |> assign(:user, admin)
3667 |> get("/api/pleroma/admin/stats")
3668 |> json_response(200)
3670 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3671 response["status_visibility"]
3675 describe "POST /api/pleroma/admin/oauth_app" do
3676 test "errors", %{conn: conn} do
3677 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3679 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3682 test "success", %{conn: conn} do
3683 base_url = Web.base_url()
3684 app_name = "Trusted app"
3688 |> post("/api/pleroma/admin/oauth_app", %{
3690 redirect_uris: base_url
3692 |> json_response(200)
3696 "client_secret" => _,
3697 "name" => ^app_name,
3698 "redirect_uri" => ^base_url,
3703 test "with trusted", %{conn: conn} do
3704 base_url = Web.base_url()
3705 app_name = "Trusted app"
3709 |> post("/api/pleroma/admin/oauth_app", %{
3711 redirect_uris: base_url,
3714 |> json_response(200)
3718 "client_secret" => _,
3719 "name" => ^app_name,
3720 "redirect_uri" => ^base_url,
3726 describe "GET /api/pleroma/admin/oauth_app" do
3728 app = insert(:oauth_app)
3732 test "list", %{conn: conn} do
3735 |> get("/api/pleroma/admin/oauth_app")
3736 |> json_response(200)
3738 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3740 assert length(apps) == count
3743 test "with page size", %{conn: conn} do
3749 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3750 |> json_response(200)
3752 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3754 assert length(apps) == page_size
3757 test "search by client name", %{conn: conn, app: app} do
3760 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3761 |> json_response(200)
3763 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3765 assert returned["client_id"] == app.client_id
3766 assert returned["name"] == app.client_name
3769 test "search by client id", %{conn: conn, app: app} do
3772 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3773 |> json_response(200)
3775 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3777 assert returned["client_id"] == app.client_id
3778 assert returned["name"] == app.client_name
3781 test "only trusted", %{conn: conn} do
3782 app = insert(:oauth_app, trusted: true)
3786 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3787 |> json_response(200)
3789 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3791 assert returned["client_id"] == app.client_id
3792 assert returned["name"] == app.client_name
3796 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3797 test "with id", %{conn: conn} do
3798 app = insert(:oauth_app)
3802 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3803 |> json_response(:no_content)
3805 assert response == ""
3808 test "with non existance id", %{conn: conn} do
3811 |> delete("/api/pleroma/admin/oauth_app/0")
3812 |> json_response(:bad_request)
3814 assert response == ""
3818 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3819 test "with id", %{conn: conn} do
3820 app = insert(:oauth_app)
3822 name = "another name"
3823 url = "https://example.com"
3826 website = "http://website.com"
3830 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3837 |> json_response(200)
3841 "client_secret" => _,
3844 "redirect_uri" => ^url,
3846 "website" => ^website
3850 test "without id", %{conn: conn} do
3853 |> patch("/api/pleroma/admin/oauth_app/0")
3854 |> json_response(:bad_request)
3856 assert response == ""
3861 # Needed for testing
3862 defmodule Pleroma.Web.Endpoint.NotReal do
3865 defmodule Pleroma.Captcha.NotReal do