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
24 alias Pleroma.Web.ActivityPub.Relay
25 alias Pleroma.Web.CommonAPI
26 alias Pleroma.Web.MediaProxy
29 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
35 admin = insert(:user, is_admin: true)
36 token = insert(:oauth_admin_token, user: admin)
40 |> assign(:user, admin)
41 |> assign(:token, token)
43 {:ok, %{admin: admin, token: token, conn: conn}}
46 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
47 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
49 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
52 url = "/api/pleroma/admin/users/#{user.nickname}"
54 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
55 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
56 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
58 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
59 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
62 for good_token <- [good_token1, good_token2, good_token3] do
65 |> assign(:user, admin)
66 |> assign(:token, good_token)
69 assert json_response(conn, 200)
72 for good_token <- [good_token1, good_token2, good_token3] do
76 |> assign(:token, good_token)
79 assert json_response(conn, :forbidden)
82 for bad_token <- [bad_token1, bad_token2, bad_token3] do
85 |> assign(:user, admin)
86 |> assign(:token, bad_token)
89 assert json_response(conn, :forbidden)
94 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
95 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
97 test "GET /api/pleroma/admin/users/:nickname requires " <>
98 "read:accounts or admin:read:accounts or broader scope",
101 url = "/api/pleroma/admin/users/#{user.nickname}"
103 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
104 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
105 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
106 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
107 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
109 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
111 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
112 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
115 for good_token <- good_tokens do
118 |> assign(:user, admin)
119 |> assign(:token, good_token)
122 assert json_response(conn, 200)
125 for good_token <- good_tokens do
128 |> assign(:user, nil)
129 |> assign(:token, good_token)
132 assert json_response(conn, :forbidden)
135 for bad_token <- [bad_token1, bad_token2, bad_token3] do
138 |> assign(:user, admin)
139 |> assign(:token, bad_token)
142 assert json_response(conn, :forbidden)
147 describe "DELETE /api/pleroma/admin/users" do
148 test "single user", %{admin: admin, conn: conn} do
150 clear_config([:instance, :federating], true)
152 with_mock Pleroma.Web.Federator,
153 publish: fn _ -> nil end do
156 |> put_req_header("accept", "application/json")
157 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
159 ObanHelpers.perform_all()
161 assert User.get_by_nickname(user.nickname).deactivated
163 log_entry = Repo.one(ModerationLog)
165 assert ModerationLog.get_log_entry_message(log_entry) ==
166 "@#{admin.nickname} deleted users: @#{user.nickname}"
168 assert json_response(conn, 200) == [user.nickname]
170 assert called(Pleroma.Web.Federator.publish(:_))
174 test "multiple users", %{admin: admin, conn: conn} do
175 user_one = insert(:user)
176 user_two = insert(:user)
180 |> put_req_header("accept", "application/json")
181 |> delete("/api/pleroma/admin/users", %{
182 nicknames: [user_one.nickname, user_two.nickname]
185 log_entry = Repo.one(ModerationLog)
187 assert ModerationLog.get_log_entry_message(log_entry) ==
188 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
190 response = json_response(conn, 200)
191 assert response -- [user_one.nickname, user_two.nickname] == []
195 describe "/api/pleroma/admin/users" do
196 test "Create", %{conn: conn} do
199 |> put_req_header("accept", "application/json")
200 |> post("/api/pleroma/admin/users", %{
203 "nickname" => "lain",
204 "email" => "lain@example.org",
208 "nickname" => "lain2",
209 "email" => "lain2@example.org",
215 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
216 assert response == ["success", "success"]
218 log_entry = Repo.one(ModerationLog)
220 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
223 test "Cannot create user with existing email", %{conn: conn} do
228 |> put_req_header("accept", "application/json")
229 |> post("/api/pleroma/admin/users", %{
232 "nickname" => "lain",
233 "email" => user.email,
239 assert json_response(conn, 409) == [
243 "email" => user.email,
246 "error" => "email has already been taken",
252 test "Cannot create user with existing nickname", %{conn: conn} do
257 |> put_req_header("accept", "application/json")
258 |> post("/api/pleroma/admin/users", %{
261 "nickname" => user.nickname,
262 "email" => "someuser@plerama.social",
268 assert json_response(conn, 409) == [
272 "email" => "someuser@plerama.social",
273 "nickname" => user.nickname
275 "error" => "nickname has already been taken",
281 test "Multiple user creation works in transaction", %{conn: conn} do
286 |> put_req_header("accept", "application/json")
287 |> post("/api/pleroma/admin/users", %{
290 "nickname" => "newuser",
291 "email" => "newuser@pleroma.social",
295 "nickname" => "lain",
296 "email" => user.email,
302 assert json_response(conn, 409) == [
306 "email" => user.email,
309 "error" => "email has already been taken",
315 "email" => "newuser@pleroma.social",
316 "nickname" => "newuser"
323 assert User.get_by_nickname("newuser") === nil
327 describe "/api/pleroma/admin/users/:nickname" do
328 test "Show", %{conn: conn} do
331 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
334 "deactivated" => false,
335 "id" => to_string(user.id),
337 "nickname" => user.nickname,
338 "roles" => %{"admin" => false, "moderator" => false},
340 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
341 "display_name" => HTML.strip_tags(user.name || user.nickname),
342 "confirmation_pending" => false
345 assert expected == json_response(conn, 200)
348 test "when the user doesn't exist", %{conn: conn} do
351 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
353 assert %{"error" => "Not found"} == json_response(conn, 404)
357 describe "/api/pleroma/admin/users/follow" do
358 test "allows to force-follow another user", %{admin: admin, conn: conn} do
360 follower = insert(:user)
363 |> put_req_header("accept", "application/json")
364 |> post("/api/pleroma/admin/users/follow", %{
365 "follower" => follower.nickname,
366 "followed" => user.nickname
369 user = User.get_cached_by_id(user.id)
370 follower = User.get_cached_by_id(follower.id)
372 assert User.following?(follower, user)
374 log_entry = Repo.one(ModerationLog)
376 assert ModerationLog.get_log_entry_message(log_entry) ==
377 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
381 describe "/api/pleroma/admin/users/unfollow" do
382 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
384 follower = insert(:user)
386 User.follow(follower, user)
389 |> put_req_header("accept", "application/json")
390 |> post("/api/pleroma/admin/users/unfollow", %{
391 "follower" => follower.nickname,
392 "followed" => user.nickname
395 user = User.get_cached_by_id(user.id)
396 follower = User.get_cached_by_id(follower.id)
398 refute User.following?(follower, user)
400 log_entry = Repo.one(ModerationLog)
402 assert ModerationLog.get_log_entry_message(log_entry) ==
403 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
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"]})
415 |> put_req_header("accept", "application/json")
417 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
418 "#{user2.nickname}&tags[]=foo&tags[]=bar"
421 %{conn: conn, user1: user1, user2: user2, user3: user3}
424 test "it appends specified tags to users with specified nicknames", %{
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"]
434 log_entry = Repo.one(ModerationLog)
437 [user1.nickname, user2.nickname]
438 |> Enum.map(&"@#{&1}")
441 tags = ["foo", "bar"] |> Enum.join(", ")
443 assert ModerationLog.get_log_entry_message(log_entry) ==
444 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
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"]
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"]})
461 |> put_req_header("accept", "application/json")
463 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
464 "#{user2.nickname}&tags[]=x&tags[]=z"
467 %{conn: conn, user1: user1, user2: user2, user3: user3}
470 test "it removes specified tags from users with specified nicknames", %{
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"]
480 log_entry = Repo.one(ModerationLog)
483 [user1.nickname, user2.nickname]
484 |> Enum.map(&"@#{&1}")
487 tags = ["x", "z"] |> Enum.join(", ")
489 assert ModerationLog.get_log_entry_message(log_entry) ==
490 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
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"]
499 describe "/api/pleroma/admin/users/:nickname/permission_group" do
500 test "GET is giving user_info", %{admin: admin, conn: conn} do
503 |> put_req_header("accept", "application/json")
504 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
506 assert json_response(conn, 200) == %{
508 "is_moderator" => false
512 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
517 |> put_req_header("accept", "application/json")
518 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
520 assert json_response(conn, 200) == %{
524 log_entry = Repo.one(ModerationLog)
526 assert ModerationLog.get_log_entry_message(log_entry) ==
527 "@#{admin.nickname} made @#{user.nickname} admin"
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)
536 |> put_req_header("accept", "application/json")
537 |> post("/api/pleroma/admin/users/permission_group/admin", %{
538 nicknames: [user_one.nickname, user_two.nickname]
541 assert json_response(conn, 200) == %{"is_admin" => true}
543 log_entry = Repo.one(ModerationLog)
545 assert ModerationLog.get_log_entry_message(log_entry) ==
546 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
549 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
550 user = insert(:user, is_admin: true)
554 |> put_req_header("accept", "application/json")
555 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
557 assert json_response(conn, 200) == %{"is_admin" => false}
559 log_entry = Repo.one(ModerationLog)
561 assert ModerationLog.get_log_entry_message(log_entry) ==
562 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
565 test "/:right DELETE, can remove from a permission group (multiple)", %{
569 user_one = insert(:user, is_admin: true)
570 user_two = insert(:user, is_admin: true)
574 |> put_req_header("accept", "application/json")
575 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
576 nicknames: [user_one.nickname, user_two.nickname]
579 assert json_response(conn, 200) == %{"is_admin" => false}
581 log_entry = Repo.one(ModerationLog)
583 assert ModerationLog.get_log_entry_message(log_entry) ==
584 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
590 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
595 |> put_req_header("accept", "application/json")
596 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
598 resp = json_response(conn, 200)
600 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
603 describe "GET /api/pleroma/admin/users" do
604 test "renders users array for the first page", %{conn: conn, admin: admin} do
605 user = insert(:user, local: false, tags: ["foo", "bar"])
606 conn = get(conn, "/api/pleroma/admin/users?page=1")
611 "deactivated" => admin.deactivated,
613 "nickname" => admin.nickname,
614 "roles" => %{"admin" => true, "moderator" => false},
617 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
618 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
619 "confirmation_pending" => false
622 "deactivated" => user.deactivated,
624 "nickname" => user.nickname,
625 "roles" => %{"admin" => false, "moderator" => false},
627 "tags" => ["foo", "bar"],
628 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
629 "display_name" => HTML.strip_tags(user.name || user.nickname),
630 "confirmation_pending" => false
633 |> Enum.sort_by(& &1["nickname"])
635 assert json_response(conn, 200) == %{
642 test "pagination works correctly with service users", %{conn: conn} do
643 service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
645 insert_list(25, :user)
647 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
649 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
650 |> json_response(200)
652 assert Enum.count(users1) == 10
653 assert service1 not in users1
655 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
657 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
658 |> json_response(200)
660 assert Enum.count(users2) == 10
661 assert service1 not in users2
663 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
665 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
666 |> json_response(200)
668 assert Enum.count(users3) == 6
669 assert service1 not in users3
672 test "renders empty array for the second page", %{conn: conn} do
675 conn = get(conn, "/api/pleroma/admin/users?page=2")
677 assert json_response(conn, 200) == %{
684 test "regular search", %{conn: conn} do
685 user = insert(:user, nickname: "bob")
687 conn = get(conn, "/api/pleroma/admin/users?query=bo")
689 assert json_response(conn, 200) == %{
694 "deactivated" => user.deactivated,
696 "nickname" => user.nickname,
697 "roles" => %{"admin" => false, "moderator" => false},
700 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
701 "display_name" => HTML.strip_tags(user.name || user.nickname),
702 "confirmation_pending" => false
708 test "search by domain", %{conn: conn} do
709 user = insert(:user, nickname: "nickname@domain.com")
712 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
714 assert json_response(conn, 200) == %{
719 "deactivated" => user.deactivated,
721 "nickname" => user.nickname,
722 "roles" => %{"admin" => false, "moderator" => false},
725 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
726 "display_name" => HTML.strip_tags(user.name || user.nickname),
727 "confirmation_pending" => false
733 test "search by full nickname", %{conn: conn} do
734 user = insert(:user, nickname: "nickname@domain.com")
737 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
739 assert json_response(conn, 200) == %{
744 "deactivated" => user.deactivated,
746 "nickname" => user.nickname,
747 "roles" => %{"admin" => false, "moderator" => false},
750 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
751 "display_name" => HTML.strip_tags(user.name || user.nickname),
752 "confirmation_pending" => false
758 test "search by display name", %{conn: conn} do
759 user = insert(:user, name: "Display name")
762 conn = get(conn, "/api/pleroma/admin/users?name=display")
764 assert json_response(conn, 200) == %{
769 "deactivated" => user.deactivated,
771 "nickname" => user.nickname,
772 "roles" => %{"admin" => false, "moderator" => false},
775 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
776 "display_name" => HTML.strip_tags(user.name || user.nickname),
777 "confirmation_pending" => false
783 test "search by email", %{conn: conn} do
784 user = insert(:user, email: "email@example.com")
787 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
789 assert json_response(conn, 200) == %{
794 "deactivated" => user.deactivated,
796 "nickname" => user.nickname,
797 "roles" => %{"admin" => false, "moderator" => false},
800 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
801 "display_name" => HTML.strip_tags(user.name || user.nickname),
802 "confirmation_pending" => false
808 test "regular search with page size", %{conn: conn} do
809 user = insert(:user, nickname: "aalice")
810 user2 = insert(:user, nickname: "alice")
812 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
814 assert json_response(conn1, 200) == %{
819 "deactivated" => user.deactivated,
821 "nickname" => user.nickname,
822 "roles" => %{"admin" => false, "moderator" => false},
825 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
826 "display_name" => HTML.strip_tags(user.name || user.nickname),
827 "confirmation_pending" => false
832 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
834 assert json_response(conn2, 200) == %{
839 "deactivated" => user2.deactivated,
841 "nickname" => user2.nickname,
842 "roles" => %{"admin" => false, "moderator" => false},
845 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
846 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
847 "confirmation_pending" => false
853 test "only local users" do
854 admin = insert(:user, is_admin: true, nickname: "john")
855 token = insert(:oauth_admin_token, user: admin)
856 user = insert(:user, nickname: "bob")
858 insert(:user, nickname: "bobb", local: false)
862 |> assign(:user, admin)
863 |> assign(:token, token)
864 |> get("/api/pleroma/admin/users?query=bo&filters=local")
866 assert json_response(conn, 200) == %{
871 "deactivated" => user.deactivated,
873 "nickname" => user.nickname,
874 "roles" => %{"admin" => false, "moderator" => false},
877 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
878 "display_name" => HTML.strip_tags(user.name || user.nickname),
879 "confirmation_pending" => false
885 test "only local users with no query", %{conn: conn, admin: old_admin} do
886 admin = insert(:user, is_admin: true, nickname: "john")
887 user = insert(:user, nickname: "bob")
889 insert(:user, nickname: "bobb", local: false)
891 conn = get(conn, "/api/pleroma/admin/users?filters=local")
896 "deactivated" => user.deactivated,
898 "nickname" => user.nickname,
899 "roles" => %{"admin" => false, "moderator" => false},
902 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
903 "display_name" => HTML.strip_tags(user.name || user.nickname),
904 "confirmation_pending" => false
907 "deactivated" => admin.deactivated,
909 "nickname" => admin.nickname,
910 "roles" => %{"admin" => true, "moderator" => false},
913 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
914 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
915 "confirmation_pending" => false
918 "deactivated" => false,
919 "id" => old_admin.id,
921 "nickname" => old_admin.nickname,
922 "roles" => %{"admin" => true, "moderator" => false},
924 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
925 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
926 "confirmation_pending" => false
929 |> Enum.sort_by(& &1["nickname"])
931 assert json_response(conn, 200) == %{
938 test "load only admins", %{conn: conn, admin: admin} do
939 second_admin = insert(:user, is_admin: true)
943 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
948 "deactivated" => false,
950 "nickname" => admin.nickname,
951 "roles" => %{"admin" => true, "moderator" => false},
952 "local" => admin.local,
954 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
955 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
956 "confirmation_pending" => false
959 "deactivated" => false,
960 "id" => second_admin.id,
961 "nickname" => second_admin.nickname,
962 "roles" => %{"admin" => true, "moderator" => false},
963 "local" => second_admin.local,
965 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
966 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
967 "confirmation_pending" => false
970 |> Enum.sort_by(& &1["nickname"])
972 assert json_response(conn, 200) == %{
979 test "load only moderators", %{conn: conn} do
980 moderator = insert(:user, is_moderator: true)
984 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
986 assert json_response(conn, 200) == %{
991 "deactivated" => false,
992 "id" => moderator.id,
993 "nickname" => moderator.nickname,
994 "roles" => %{"admin" => false, "moderator" => true},
995 "local" => moderator.local,
997 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
998 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
999 "confirmation_pending" => false
1005 test "load users with tags list", %{conn: conn} do
1006 user1 = insert(:user, tags: ["first"])
1007 user2 = insert(:user, tags: ["second"])
1011 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1016 "deactivated" => false,
1018 "nickname" => user1.nickname,
1019 "roles" => %{"admin" => false, "moderator" => false},
1020 "local" => user1.local,
1021 "tags" => ["first"],
1022 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1023 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1024 "confirmation_pending" => false
1027 "deactivated" => false,
1029 "nickname" => user2.nickname,
1030 "roles" => %{"admin" => false, "moderator" => false},
1031 "local" => user2.local,
1032 "tags" => ["second"],
1033 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1034 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1035 "confirmation_pending" => false
1038 |> Enum.sort_by(& &1["nickname"])
1040 assert json_response(conn, 200) == %{
1047 test "it works with multiple filters" do
1048 admin = insert(:user, nickname: "john", is_admin: true)
1049 token = insert(:oauth_admin_token, user: admin)
1050 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1052 insert(:user, nickname: "ken", local: true, deactivated: true)
1053 insert(:user, nickname: "bobb", local: false, deactivated: false)
1057 |> assign(:user, admin)
1058 |> assign(:token, token)
1059 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1061 assert json_response(conn, 200) == %{
1066 "deactivated" => user.deactivated,
1068 "nickname" => user.nickname,
1069 "roles" => %{"admin" => false, "moderator" => false},
1070 "local" => user.local,
1072 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1073 "display_name" => HTML.strip_tags(user.name || user.nickname),
1074 "confirmation_pending" => false
1080 test "it omits relay user", %{admin: admin, conn: conn} do
1081 assert %User{} = Relay.get_actor()
1083 conn = get(conn, "/api/pleroma/admin/users")
1085 assert json_response(conn, 200) == %{
1090 "deactivated" => admin.deactivated,
1092 "nickname" => admin.nickname,
1093 "roles" => %{"admin" => true, "moderator" => false},
1096 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1097 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1098 "confirmation_pending" => false
1105 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1106 user_one = insert(:user, deactivated: true)
1107 user_two = insert(:user, deactivated: true)
1112 "/api/pleroma/admin/users/activate",
1113 %{nicknames: [user_one.nickname, user_two.nickname]}
1116 response = json_response(conn, 200)
1117 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1119 log_entry = Repo.one(ModerationLog)
1121 assert ModerationLog.get_log_entry_message(log_entry) ==
1122 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1125 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1126 user_one = insert(:user, deactivated: false)
1127 user_two = insert(:user, deactivated: false)
1132 "/api/pleroma/admin/users/deactivate",
1133 %{nicknames: [user_one.nickname, user_two.nickname]}
1136 response = json_response(conn, 200)
1137 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1139 log_entry = Repo.one(ModerationLog)
1141 assert ModerationLog.get_log_entry_message(log_entry) ==
1142 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1145 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1146 user = insert(:user)
1148 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1150 assert json_response(conn, 200) ==
1152 "deactivated" => !user.deactivated,
1154 "nickname" => user.nickname,
1155 "roles" => %{"admin" => false, "moderator" => false},
1158 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1159 "display_name" => HTML.strip_tags(user.name || user.nickname),
1160 "confirmation_pending" => false
1163 log_entry = Repo.one(ModerationLog)
1165 assert ModerationLog.get_log_entry_message(log_entry) ==
1166 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1169 describe "PUT disable_mfa" do
1170 test "returns 200 and disable 2fa", %{conn: conn} do
1173 multi_factor_authentication_settings: %MFA.Settings{
1175 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1181 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1182 |> json_response(200)
1184 assert response == user.nickname
1185 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1187 refute mfa_settings.enabled
1188 refute mfa_settings.totp.confirmed
1191 test "returns 404 if user not found", %{conn: conn} do
1194 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1195 |> json_response(404)
1197 assert response == %{"error" => "Not found"}
1201 describe "GET /api/pleroma/admin/reports/:id" do
1202 test "returns report by its id", %{conn: conn} do
1203 [reporter, target_user] = insert_pair(:user)
1204 activity = insert(:note_activity, user: target_user)
1206 {:ok, %{id: report_id}} =
1207 CommonAPI.report(reporter, %{
1208 account_id: target_user.id,
1209 comment: "I feel offended",
1210 status_ids: [activity.id]
1215 |> get("/api/pleroma/admin/reports/#{report_id}")
1216 |> json_response(:ok)
1218 assert response["id"] == report_id
1221 test "returns 404 when report id is invalid", %{conn: conn} do
1222 conn = get(conn, "/api/pleroma/admin/reports/test")
1224 assert json_response(conn, :not_found) == %{"error" => "Not found"}
1228 describe "PATCH /api/pleroma/admin/reports" do
1230 [reporter, target_user] = insert_pair(:user)
1231 activity = insert(:note_activity, user: target_user)
1233 {:ok, %{id: report_id}} =
1234 CommonAPI.report(reporter, %{
1235 account_id: target_user.id,
1236 comment: "I feel offended",
1237 status_ids: [activity.id]
1240 {:ok, %{id: second_report_id}} =
1241 CommonAPI.report(reporter, %{
1242 account_id: target_user.id,
1243 comment: "I feel very offended",
1244 status_ids: [activity.id]
1249 second_report_id: second_report_id
1253 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1254 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1255 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1259 |> assign(:token, read_token)
1260 |> patch("/api/pleroma/admin/reports", %{
1261 "reports" => [%{"state" => "resolved", "id" => id}]
1263 |> json_response(403)
1265 assert response == %{
1266 "error" => "Insufficient permissions: admin:write:reports."
1270 |> assign(:token, write_token)
1271 |> patch("/api/pleroma/admin/reports", %{
1272 "reports" => [%{"state" => "resolved", "id" => id}]
1274 |> json_response(:no_content)
1277 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1279 |> patch("/api/pleroma/admin/reports", %{
1281 %{"state" => "resolved", "id" => id}
1284 |> json_response(:no_content)
1286 activity = Activity.get_by_id(id)
1287 assert activity.data["state"] == "resolved"
1289 log_entry = Repo.one(ModerationLog)
1291 assert ModerationLog.get_log_entry_message(log_entry) ==
1292 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1295 test "closes report", %{conn: conn, id: id, admin: admin} do
1297 |> patch("/api/pleroma/admin/reports", %{
1299 %{"state" => "closed", "id" => id}
1302 |> json_response(:no_content)
1304 activity = Activity.get_by_id(id)
1305 assert activity.data["state"] == "closed"
1307 log_entry = Repo.one(ModerationLog)
1309 assert ModerationLog.get_log_entry_message(log_entry) ==
1310 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1313 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1316 |> patch("/api/pleroma/admin/reports", %{
1318 %{"state" => "test", "id" => id}
1322 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1325 test "returns 404 when report is not exist", %{conn: conn} do
1328 |> patch("/api/pleroma/admin/reports", %{
1330 %{"state" => "closed", "id" => "test"}
1334 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1337 test "updates state of multiple reports", %{
1341 second_report_id: second_report_id
1344 |> patch("/api/pleroma/admin/reports", %{
1346 %{"state" => "resolved", "id" => id},
1347 %{"state" => "closed", "id" => second_report_id}
1350 |> json_response(:no_content)
1352 activity = Activity.get_by_id(id)
1353 second_activity = Activity.get_by_id(second_report_id)
1354 assert activity.data["state"] == "resolved"
1355 assert second_activity.data["state"] == "closed"
1357 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1359 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1360 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1362 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1363 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1367 describe "GET /api/pleroma/admin/reports" do
1368 test "returns empty response when no reports created", %{conn: conn} do
1371 |> get("/api/pleroma/admin/reports")
1372 |> json_response(:ok)
1374 assert Enum.empty?(response["reports"])
1375 assert response["total"] == 0
1378 test "returns reports", %{conn: conn} do
1379 [reporter, target_user] = insert_pair(:user)
1380 activity = insert(:note_activity, user: target_user)
1382 {:ok, %{id: report_id}} =
1383 CommonAPI.report(reporter, %{
1384 account_id: target_user.id,
1385 comment: "I feel offended",
1386 status_ids: [activity.id]
1391 |> get("/api/pleroma/admin/reports")
1392 |> json_response(:ok)
1394 [report] = response["reports"]
1396 assert length(response["reports"]) == 1
1397 assert report["id"] == report_id
1399 assert response["total"] == 1
1402 test "returns reports with specified state", %{conn: conn} do
1403 [reporter, target_user] = insert_pair(:user)
1404 activity = insert(:note_activity, user: target_user)
1406 {:ok, %{id: first_report_id}} =
1407 CommonAPI.report(reporter, %{
1408 account_id: target_user.id,
1409 comment: "I feel offended",
1410 status_ids: [activity.id]
1413 {:ok, %{id: second_report_id}} =
1414 CommonAPI.report(reporter, %{
1415 account_id: target_user.id,
1416 comment: "I don't like this user"
1419 CommonAPI.update_report_state(second_report_id, "closed")
1423 |> get("/api/pleroma/admin/reports", %{
1426 |> json_response(:ok)
1428 [open_report] = response["reports"]
1430 assert length(response["reports"]) == 1
1431 assert open_report["id"] == first_report_id
1433 assert response["total"] == 1
1437 |> get("/api/pleroma/admin/reports", %{
1440 |> json_response(:ok)
1442 [closed_report] = response["reports"]
1444 assert length(response["reports"]) == 1
1445 assert closed_report["id"] == second_report_id
1447 assert response["total"] == 1
1451 |> get("/api/pleroma/admin/reports", %{
1452 "state" => "resolved"
1454 |> json_response(:ok)
1456 assert Enum.empty?(response["reports"])
1457 assert response["total"] == 0
1460 test "returns 403 when requested by a non-admin" do
1461 user = insert(:user)
1462 token = insert(:oauth_token, user: user)
1466 |> assign(:user, user)
1467 |> assign(:token, token)
1468 |> get("/api/pleroma/admin/reports")
1470 assert json_response(conn, :forbidden) ==
1471 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1474 test "returns 403 when requested by anonymous" do
1475 conn = get(build_conn(), "/api/pleroma/admin/reports")
1477 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1481 describe "GET /api/pleroma/admin/config" do
1482 setup do: clear_config(:configurable_from_database, true)
1484 test "when configuration from database is off", %{conn: conn} do
1485 Config.put(:configurable_from_database, false)
1486 conn = get(conn, "/api/pleroma/admin/config")
1488 assert json_response(conn, 400) ==
1490 "error" => "To use this endpoint you need to enable configuration from database."
1494 test "with settings only in db", %{conn: conn} do
1495 config1 = insert(:config)
1496 config2 = insert(:config)
1498 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1503 "group" => ":pleroma",
1508 "group" => ":pleroma",
1513 } = json_response(conn, 200)
1515 assert key1 == config1.key
1516 assert key2 == config2.key
1519 test "db is added to settings that are in db", %{conn: conn} do
1520 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1522 %{"configs" => configs} =
1524 |> get("/api/pleroma/admin/config")
1525 |> json_response(200)
1528 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1529 group == ":pleroma" and key == ":instance"
1532 assert instance_config["db"] == [":name"]
1535 test "merged default setting with db settings", %{conn: conn} do
1536 config1 = insert(:config)
1537 config2 = insert(:config)
1541 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1544 %{"configs" => configs} =
1546 |> get("/api/pleroma/admin/config")
1547 |> json_response(200)
1549 assert length(configs) > 3
1552 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1553 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1556 assert length(received_configs) == 3
1560 |> ConfigDB.from_binary()
1562 |> ConfigDB.convert()
1564 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1565 assert db in [[config1.key], [config2.key], db_keys]
1568 ConfigDB.from_binary_with_convert(config1.value),
1569 ConfigDB.from_binary_with_convert(config2.value),
1570 ConfigDB.from_binary_with_convert(config3.value)
1575 test "subkeys with full update right merge", %{conn: conn} do
1579 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1585 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1588 %{"configs" => configs} =
1590 |> get("/api/pleroma/admin/config")
1591 |> json_response(200)
1594 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1595 group == ":pleroma" and key in [config1.key, config2.key]
1598 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1599 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1601 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1602 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1604 assert emoji_val[:groups] == [a: 1, b: 2]
1605 assert assets_val[:mascots] == [a: 1, b: 2]
1609 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1610 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1612 assert json_response(conn, 400) ==
1613 %{"error" => "To use this endpoint you need to enable configuration from database."}
1616 describe "POST /api/pleroma/admin/config" do
1618 http = Application.get_env(:pleroma, :http)
1621 Application.delete_env(:pleroma, :key1)
1622 Application.delete_env(:pleroma, :key2)
1623 Application.delete_env(:pleroma, :key3)
1624 Application.delete_env(:pleroma, :key4)
1625 Application.delete_env(:pleroma, :keyaa1)
1626 Application.delete_env(:pleroma, :keyaa2)
1627 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1628 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1629 Application.put_env(:pleroma, :http, http)
1630 Application.put_env(:tesla, :adapter, Tesla.Mock)
1631 Restarter.Pleroma.refresh()
1635 setup do: clear_config(:configurable_from_database, true)
1637 @tag capture_log: true
1638 test "create new config setting in db", %{conn: conn} do
1639 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1640 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1643 post(conn, "/api/pleroma/admin/config", %{
1645 %{group: ":pleroma", key: ":key1", value: "value1"},
1647 group: ":ueberauth",
1649 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1655 ":nested_1" => "nested_value1",
1657 %{":nested_22" => "nested_value222"},
1658 %{":nested_33" => %{":nested_44" => "nested_444"}}
1666 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1667 %{"nested_4" => true}
1673 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1678 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1683 assert json_response(conn, 200) == %{
1686 "group" => ":pleroma",
1688 "value" => "value1",
1692 "group" => ":ueberauth",
1693 "key" => "Ueberauth",
1694 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1695 "db" => [":consumer_secret"]
1698 "group" => ":pleroma",
1701 ":nested_1" => "nested_value1",
1703 %{":nested_22" => "nested_value222"},
1704 %{":nested_33" => %{":nested_44" => "nested_444"}}
1710 "group" => ":pleroma",
1713 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1714 %{"nested_4" => true}
1719 "group" => ":pleroma",
1721 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
1727 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
1733 assert Application.get_env(:pleroma, :key1) == "value1"
1735 assert Application.get_env(:pleroma, :key2) == %{
1736 nested_1: "nested_value1",
1738 %{nested_22: "nested_value222"},
1739 %{nested_33: %{nested_44: "nested_444"}}
1743 assert Application.get_env(:pleroma, :key3) == [
1744 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
1745 %{"nested_4" => true}
1748 assert Application.get_env(:pleroma, :key4) == %{
1749 "endpoint" => "https://example.com",
1753 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
1756 test "save configs setting without explicit key", %{conn: conn} do
1757 level = Application.get_env(:quack, :level)
1758 meta = Application.get_env(:quack, :meta)
1759 webhook_url = Application.get_env(:quack, :webhook_url)
1762 Application.put_env(:quack, :level, level)
1763 Application.put_env(:quack, :meta, meta)
1764 Application.put_env(:quack, :webhook_url, webhook_url)
1768 post(conn, "/api/pleroma/admin/config", %{
1782 key: ":webhook_url",
1783 value: "https://hooks.slack.com/services/KEY"
1788 assert json_response(conn, 200) == %{
1791 "group" => ":quack",
1797 "group" => ":quack",
1799 "value" => [":none"],
1803 "group" => ":quack",
1804 "key" => ":webhook_url",
1805 "value" => "https://hooks.slack.com/services/KEY",
1806 "db" => [":webhook_url"]
1811 assert Application.get_env(:quack, :level) == :info
1812 assert Application.get_env(:quack, :meta) == [:none]
1813 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
1816 test "saving config with partial update", %{conn: conn} do
1817 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
1820 post(conn, "/api/pleroma/admin/config", %{
1822 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
1826 assert json_response(conn, 200) == %{
1829 "group" => ":pleroma",
1832 %{"tuple" => [":key1", 1]},
1833 %{"tuple" => [":key2", 2]},
1834 %{"tuple" => [":key3", 3]}
1836 "db" => [":key1", ":key2", ":key3"]
1842 test "saving config which need pleroma reboot", %{conn: conn} do
1843 chat = Config.get(:chat)
1844 on_exit(fn -> Config.put(:chat, chat) end)
1848 "/api/pleroma/admin/config",
1851 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
1855 |> json_response(200) == %{
1858 "db" => [":enabled"],
1859 "group" => ":pleroma",
1861 "value" => [%{"tuple" => [":enabled", true]}]
1864 "need_reboot" => true
1869 |> get("/api/pleroma/admin/config")
1870 |> json_response(200)
1872 assert configs["need_reboot"]
1875 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1876 end) =~ "pleroma restarted"
1880 |> get("/api/pleroma/admin/config")
1881 |> json_response(200)
1883 assert configs["need_reboot"] == false
1886 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
1887 chat = Config.get(:chat)
1888 on_exit(fn -> Config.put(:chat, chat) end)
1892 "/api/pleroma/admin/config",
1895 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
1899 |> json_response(200) == %{
1902 "db" => [":enabled"],
1903 "group" => ":pleroma",
1905 "value" => [%{"tuple" => [":enabled", true]}]
1908 "need_reboot" => true
1911 assert post(conn, "/api/pleroma/admin/config", %{
1913 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
1916 |> json_response(200) == %{
1919 "group" => ":pleroma",
1922 %{"tuple" => [":key3", 3]}
1927 "need_reboot" => true
1931 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1932 end) =~ "pleroma restarted"
1936 |> get("/api/pleroma/admin/config")
1937 |> json_response(200)
1939 assert configs["need_reboot"] == false
1942 test "saving config with nested merge", %{conn: conn} do
1944 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
1947 post(conn, "/api/pleroma/admin/config", %{
1950 group: config.group,
1953 %{"tuple" => [":key3", 3]},
1958 %{"tuple" => [":k2", 1]},
1959 %{"tuple" => [":k3", 3]}
1968 assert json_response(conn, 200) == %{
1971 "group" => ":pleroma",
1974 %{"tuple" => [":key1", 1]},
1975 %{"tuple" => [":key3", 3]},
1980 %{"tuple" => [":k1", 1]},
1981 %{"tuple" => [":k2", 1]},
1982 %{"tuple" => [":k3", 3]}
1987 "db" => [":key1", ":key3", ":key2"]
1993 test "saving special atoms", %{conn: conn} do
1995 post(conn, "/api/pleroma/admin/config", %{
1998 "group" => ":pleroma",
2004 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2012 assert json_response(conn, 200) == %{
2015 "group" => ":pleroma",
2021 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2025 "db" => [":ssl_options"]
2030 assert Application.get_env(:pleroma, :key1) == [
2031 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2035 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2036 backends = Application.get_env(:logger, :backends)
2037 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2043 value: :erlang.term_to_binary([])
2046 Pleroma.Config.TransferTask.load_and_update_env([], false)
2048 assert Application.get_env(:logger, :backends) == []
2051 post(conn, "/api/pleroma/admin/config", %{
2054 group: config.group,
2061 assert json_response(conn, 200) == %{
2064 "group" => ":logger",
2065 "key" => ":backends",
2069 "db" => [":backends"]
2074 assert Application.get_env(:logger, :backends) == [
2079 test "saving full setting if value is not keyword", %{conn: conn} do
2084 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2088 post(conn, "/api/pleroma/admin/config", %{
2090 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2094 assert json_response(conn, 200) == %{
2097 "group" => ":tesla",
2098 "key" => ":adapter",
2099 "value" => "Tesla.Adapter.Httpc",
2100 "db" => [":adapter"]
2106 test "update config setting & delete with fallback to default value", %{
2111 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2112 config1 = insert(:config, key: ":keyaa1")
2113 config2 = insert(:config, key: ":keyaa2")
2117 group: ":ueberauth",
2122 post(conn, "/api/pleroma/admin/config", %{
2124 %{group: config1.group, key: config1.key, value: "another_value"},
2125 %{group: config2.group, key: config2.key, value: "another_value"}
2129 assert json_response(conn, 200) == %{
2132 "group" => ":pleroma",
2133 "key" => config1.key,
2134 "value" => "another_value",
2138 "group" => ":pleroma",
2139 "key" => config2.key,
2140 "value" => "another_value",
2146 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2147 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2148 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2152 |> assign(:user, admin)
2153 |> assign(:token, token)
2154 |> post("/api/pleroma/admin/config", %{
2156 %{group: config2.group, key: config2.key, delete: true},
2158 group: ":ueberauth",
2165 assert json_response(conn, 200) == %{
2169 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2170 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2173 test "common config example", %{conn: conn} do
2175 post(conn, "/api/pleroma/admin/config", %{
2178 "group" => ":pleroma",
2179 "key" => "Pleroma.Captcha.NotReal",
2181 %{"tuple" => [":enabled", false]},
2182 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2183 %{"tuple" => [":seconds_valid", 60]},
2184 %{"tuple" => [":path", ""]},
2185 %{"tuple" => [":key1", nil]},
2186 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2187 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2188 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2189 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2190 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2191 %{"tuple" => [":name", "Pleroma"]}
2197 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2199 assert json_response(conn, 200) == %{
2202 "group" => ":pleroma",
2203 "key" => "Pleroma.Captcha.NotReal",
2205 %{"tuple" => [":enabled", false]},
2206 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2207 %{"tuple" => [":seconds_valid", 60]},
2208 %{"tuple" => [":path", ""]},
2209 %{"tuple" => [":key1", nil]},
2210 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2211 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2212 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2213 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2214 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2215 %{"tuple" => [":name", "Pleroma"]}
2235 test "tuples with more than two values", %{conn: conn} do
2237 post(conn, "/api/pleroma/admin/config", %{
2240 "group" => ":pleroma",
2241 "key" => "Pleroma.Web.Endpoint.NotReal",
2257 "/api/v1/streaming",
2258 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2265 "Phoenix.Endpoint.CowboyWebSocket",
2268 "Phoenix.Transports.WebSocket",
2271 "Pleroma.Web.Endpoint",
2272 "Pleroma.Web.UserSocket",
2283 "Phoenix.Endpoint.Cowboy2Handler",
2284 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2301 assert json_response(conn, 200) == %{
2304 "group" => ":pleroma",
2305 "key" => "Pleroma.Web.Endpoint.NotReal",
2321 "/api/v1/streaming",
2322 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2329 "Phoenix.Endpoint.CowboyWebSocket",
2332 "Phoenix.Transports.WebSocket",
2335 "Pleroma.Web.Endpoint",
2336 "Pleroma.Web.UserSocket",
2347 "Phoenix.Endpoint.Cowboy2Handler",
2348 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2367 test "settings with nesting map", %{conn: conn} do
2369 post(conn, "/api/pleroma/admin/config", %{
2372 "group" => ":pleroma",
2375 %{"tuple" => [":key2", "some_val"]},
2380 ":max_options" => 20,
2381 ":max_option_chars" => 200,
2382 ":min_expiration" => 0,
2383 ":max_expiration" => 31_536_000,
2385 ":max_options" => 20,
2386 ":max_option_chars" => 200,
2387 ":min_expiration" => 0,
2388 ":max_expiration" => 31_536_000
2398 assert json_response(conn, 200) ==
2402 "group" => ":pleroma",
2405 %{"tuple" => [":key2", "some_val"]},
2410 ":max_expiration" => 31_536_000,
2411 ":max_option_chars" => 200,
2412 ":max_options" => 20,
2413 ":min_expiration" => 0,
2415 ":max_expiration" => 31_536_000,
2416 ":max_option_chars" => 200,
2417 ":max_options" => 20,
2418 ":min_expiration" => 0
2424 "db" => [":key2", ":key3"]
2430 test "value as map", %{conn: conn} do
2432 post(conn, "/api/pleroma/admin/config", %{
2435 "group" => ":pleroma",
2437 "value" => %{"key" => "some_val"}
2442 assert json_response(conn, 200) ==
2446 "group" => ":pleroma",
2448 "value" => %{"key" => "some_val"},
2455 test "queues key as atom", %{conn: conn} do
2457 post(conn, "/api/pleroma/admin/config", %{
2463 %{"tuple" => [":federator_incoming", 50]},
2464 %{"tuple" => [":federator_outgoing", 50]},
2465 %{"tuple" => [":web_push", 50]},
2466 %{"tuple" => [":mailer", 10]},
2467 %{"tuple" => [":transmogrifier", 20]},
2468 %{"tuple" => [":scheduled_activities", 10]},
2469 %{"tuple" => [":background", 5]}
2475 assert json_response(conn, 200) == %{
2481 %{"tuple" => [":federator_incoming", 50]},
2482 %{"tuple" => [":federator_outgoing", 50]},
2483 %{"tuple" => [":web_push", 50]},
2484 %{"tuple" => [":mailer", 10]},
2485 %{"tuple" => [":transmogrifier", 20]},
2486 %{"tuple" => [":scheduled_activities", 10]},
2487 %{"tuple" => [":background", 5]}
2490 ":federator_incoming",
2491 ":federator_outgoing",
2495 ":scheduled_activities",
2503 test "delete part of settings by atom subkeys", %{conn: conn} do
2507 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2511 post(conn, "/api/pleroma/admin/config", %{
2514 group: config.group,
2516 subkeys: [":subkey1", ":subkey3"],
2522 assert json_response(conn, 200) == %{
2525 "group" => ":pleroma",
2527 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2528 "db" => [":subkey2"]
2534 test "proxy tuple localhost", %{conn: conn} do
2536 post(conn, "/api/pleroma/admin/config", %{
2542 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}
2551 "group" => ":pleroma",
2557 } = json_response(conn, 200)
2559 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value
2560 assert ":proxy_url" in db
2563 test "proxy tuple domain", %{conn: conn} do
2565 post(conn, "/api/pleroma/admin/config", %{
2571 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}
2580 "group" => ":pleroma",
2586 } = json_response(conn, 200)
2588 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value
2589 assert ":proxy_url" in db
2592 test "proxy tuple ip", %{conn: conn} do
2594 post(conn, "/api/pleroma/admin/config", %{
2600 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}
2609 "group" => ":pleroma",
2615 } = json_response(conn, 200)
2617 assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
2618 assert ":proxy_url" in db
2621 @tag capture_log: true
2622 test "doesn't set keys not in the whitelist", %{conn: conn} do
2623 clear_config(:database_config_whitelist, [
2626 {:pleroma, Pleroma.Captcha.NotReal},
2630 post(conn, "/api/pleroma/admin/config", %{
2632 %{group: ":pleroma", key: ":key1", value: "value1"},
2633 %{group: ":pleroma", key: ":key2", value: "value2"},
2634 %{group: ":pleroma", key: ":key3", value: "value3"},
2635 %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
2636 %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
2637 %{group: ":not_real", key: ":anything", value: "value6"}
2641 assert Application.get_env(:pleroma, :key1) == "value1"
2642 assert Application.get_env(:pleroma, :key2) == "value2"
2643 assert Application.get_env(:pleroma, :key3) == nil
2644 assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
2645 assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
2646 assert Application.get_env(:not_real, :anything) == "value6"
2650 describe "GET /api/pleroma/admin/restart" do
2651 setup do: clear_config(:configurable_from_database, true)
2653 test "pleroma restarts", %{conn: conn} do
2655 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2656 end) =~ "pleroma restarted"
2658 refute Restarter.Pleroma.need_reboot?()
2662 test "need_reboot flag", %{conn: conn} do
2664 |> get("/api/pleroma/admin/need_reboot")
2665 |> json_response(200) == %{"need_reboot" => false}
2667 Restarter.Pleroma.need_reboot()
2670 |> get("/api/pleroma/admin/need_reboot")
2671 |> json_response(200) == %{"need_reboot" => true}
2673 on_exit(fn -> Restarter.Pleroma.refresh() end)
2676 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2678 user = insert(:user)
2680 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2681 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2682 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2684 insert(:note_activity, user: user, published: date1)
2685 insert(:note_activity, user: user, published: date2)
2686 insert(:note_activity, user: user, published: date3)
2691 test "renders user's statuses", %{conn: conn, user: user} do
2692 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2694 assert json_response(conn, 200) |> length() == 3
2697 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2698 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2700 assert json_response(conn, 200) |> length() == 2
2703 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2704 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
2706 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
2708 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2710 assert json_response(conn, 200) |> length() == 4
2713 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2714 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
2716 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
2718 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2720 assert json_response(conn, 200) |> length() == 5
2723 test "excludes reblogs by default", %{conn: conn, user: user} do
2724 other_user = insert(:user)
2725 {:ok, activity} = CommonAPI.post(user, %{status: "."})
2726 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
2728 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2729 assert json_response(conn_res, 200) |> length() == 0
2732 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2734 assert json_response(conn_res, 200) |> length() == 1
2738 describe "GET /api/pleroma/admin/moderation_log" do
2740 moderator = insert(:user, is_moderator: true)
2742 %{moderator: moderator}
2745 test "returns the log", %{conn: conn, admin: admin} do
2746 Repo.insert(%ModerationLog{
2750 "nickname" => admin.nickname,
2753 action: "relay_follow",
2754 target: "https://example.org/relay"
2756 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2759 Repo.insert(%ModerationLog{
2763 "nickname" => admin.nickname,
2766 action: "relay_unfollow",
2767 target: "https://example.org/relay"
2769 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2772 conn = get(conn, "/api/pleroma/admin/moderation_log")
2774 response = json_response(conn, 200)
2775 [first_entry, second_entry] = response["items"]
2777 assert response["total"] == 2
2778 assert first_entry["data"]["action"] == "relay_unfollow"
2780 assert first_entry["message"] ==
2781 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2783 assert second_entry["data"]["action"] == "relay_follow"
2785 assert second_entry["message"] ==
2786 "@#{admin.nickname} followed relay: https://example.org/relay"
2789 test "returns the log with pagination", %{conn: conn, admin: admin} do
2790 Repo.insert(%ModerationLog{
2794 "nickname" => admin.nickname,
2797 action: "relay_follow",
2798 target: "https://example.org/relay"
2800 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2803 Repo.insert(%ModerationLog{
2807 "nickname" => admin.nickname,
2810 action: "relay_unfollow",
2811 target: "https://example.org/relay"
2813 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2816 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
2818 response1 = json_response(conn1, 200)
2819 [first_entry] = response1["items"]
2821 assert response1["total"] == 2
2822 assert response1["items"] |> length() == 1
2823 assert first_entry["data"]["action"] == "relay_unfollow"
2825 assert first_entry["message"] ==
2826 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2828 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
2830 response2 = json_response(conn2, 200)
2831 [second_entry] = response2["items"]
2833 assert response2["total"] == 2
2834 assert response2["items"] |> length() == 1
2835 assert second_entry["data"]["action"] == "relay_follow"
2837 assert second_entry["message"] ==
2838 "@#{admin.nickname} followed relay: https://example.org/relay"
2841 test "filters log by date", %{conn: conn, admin: admin} do
2842 first_date = "2017-08-15T15:47:06Z"
2843 second_date = "2017-08-20T15:47:06Z"
2845 Repo.insert(%ModerationLog{
2849 "nickname" => admin.nickname,
2852 action: "relay_follow",
2853 target: "https://example.org/relay"
2855 inserted_at: NaiveDateTime.from_iso8601!(first_date)
2858 Repo.insert(%ModerationLog{
2862 "nickname" => admin.nickname,
2865 action: "relay_unfollow",
2866 target: "https://example.org/relay"
2868 inserted_at: NaiveDateTime.from_iso8601!(second_date)
2874 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
2877 response1 = json_response(conn1, 200)
2878 [first_entry] = response1["items"]
2880 assert response1["total"] == 1
2881 assert first_entry["data"]["action"] == "relay_unfollow"
2883 assert first_entry["message"] ==
2884 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2887 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
2888 Repo.insert(%ModerationLog{
2892 "nickname" => admin.nickname,
2895 action: "relay_follow",
2896 target: "https://example.org/relay"
2900 Repo.insert(%ModerationLog{
2903 "id" => moderator.id,
2904 "nickname" => moderator.nickname,
2907 action: "relay_unfollow",
2908 target: "https://example.org/relay"
2912 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
2914 response1 = json_response(conn1, 200)
2915 [first_entry] = response1["items"]
2917 assert response1["total"] == 1
2918 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
2921 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
2922 ModerationLog.insert_log(%{
2924 action: "relay_follow",
2925 target: "https://example.org/relay"
2928 ModerationLog.insert_log(%{
2930 action: "relay_unfollow",
2931 target: "https://example.org/relay"
2934 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
2936 response1 = json_response(conn1, 200)
2937 [first_entry] = response1["items"]
2939 assert response1["total"] == 1
2941 assert get_in(first_entry, ["data", "message"]) ==
2942 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
2946 describe "GET /users/:nickname/credentials" do
2947 test "gets the user credentials", %{conn: conn} do
2948 user = insert(:user)
2949 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
2951 response = assert json_response(conn, 200)
2952 assert response["email"] == user.email
2955 test "returns 403 if requested by a non-admin" do
2956 user = insert(:user)
2960 |> assign(:user, user)
2961 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
2963 assert json_response(conn, :forbidden)
2967 describe "PATCH /users/:nickname/credentials" do
2969 user = insert(:user)
2973 test "changes password and email", %{conn: conn, admin: admin, user: user} do
2974 assert user.password_reset_pending == false
2977 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
2978 "password" => "new_password",
2979 "email" => "new_email@example.com",
2980 "name" => "new_name"
2983 assert json_response(conn, 200) == %{"status" => "success"}
2985 ObanHelpers.perform_all()
2987 updated_user = User.get_by_id(user.id)
2989 assert updated_user.email == "new_email@example.com"
2990 assert updated_user.name == "new_name"
2991 assert updated_user.password_hash != user.password_hash
2992 assert updated_user.password_reset_pending == true
2994 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
2996 assert ModerationLog.get_log_entry_message(log_entry1) ==
2997 "@#{admin.nickname} updated users: @#{user.nickname}"
2999 assert ModerationLog.get_log_entry_message(log_entry2) ==
3000 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3003 test "returns 403 if requested by a non-admin", %{user: user} do
3006 |> assign(:user, user)
3007 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3008 "password" => "new_password",
3009 "email" => "new_email@example.com",
3010 "name" => "new_name"
3013 assert json_response(conn, :forbidden)
3016 test "changes actor type from permitted list", %{conn: conn, user: user} do
3017 assert user.actor_type == "Person"
3019 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3020 "actor_type" => "Service"
3022 |> json_response(200) == %{"status" => "success"}
3024 updated_user = User.get_by_id(user.id)
3026 assert updated_user.actor_type == "Service"
3028 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3029 "actor_type" => "Application"
3031 |> json_response(200) == %{"errors" => %{"actor_type" => "is invalid"}}
3034 test "update non existing user", %{conn: conn} do
3035 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
3036 "password" => "new_password"
3038 |> json_response(200) == %{"error" => "Unable to update user."}
3042 describe "PATCH /users/:nickname/force_password_reset" do
3043 test "sets password_reset_pending to true", %{conn: conn} do
3044 user = insert(:user)
3045 assert user.password_reset_pending == false
3048 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3050 assert json_response(conn, 204) == ""
3052 ObanHelpers.perform_all()
3054 assert User.get_by_id(user.id).password_reset_pending == true
3058 describe "relays" do
3059 test "POST /relay", %{conn: conn, admin: admin} do
3061 post(conn, "/api/pleroma/admin/relay", %{
3062 relay_url: "http://mastodon.example.org/users/admin"
3065 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3067 log_entry = Repo.one(ModerationLog)
3069 assert ModerationLog.get_log_entry_message(log_entry) ==
3070 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3073 test "GET /relay", %{conn: conn} do
3074 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3076 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3077 |> Enum.each(fn ap_id ->
3078 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3079 User.follow(relay_user, user)
3082 conn = get(conn, "/api/pleroma/admin/relay")
3084 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3087 test "DELETE /relay", %{conn: conn, admin: admin} do
3088 post(conn, "/api/pleroma/admin/relay", %{
3089 relay_url: "http://mastodon.example.org/users/admin"
3093 delete(conn, "/api/pleroma/admin/relay", %{
3094 relay_url: "http://mastodon.example.org/users/admin"
3097 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3099 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3101 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3102 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3104 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3105 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3109 describe "instances" do
3110 test "GET /instances/:instance/statuses", %{conn: conn} do
3111 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3112 user2 = insert(:user, local: false, nickname: "test@test.com")
3113 insert_pair(:note_activity, user: user)
3114 activity = insert(:note_activity, user: user2)
3116 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3118 response = json_response(ret_conn, 200)
3120 assert length(response) == 2
3122 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3124 response = json_response(ret_conn, 200)
3126 assert length(response) == 1
3128 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3130 response = json_response(ret_conn, 200)
3132 assert Enum.empty?(response)
3134 CommonAPI.repeat(activity.id, user)
3136 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3137 response = json_response(ret_conn, 200)
3138 assert length(response) == 2
3140 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3141 response = json_response(ret_conn, 200)
3142 assert length(response) == 3
3146 describe "PATCH /confirm_email" do
3147 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3148 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3150 assert first_user.confirmation_pending == true
3151 assert second_user.confirmation_pending == true
3154 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3156 first_user.nickname,
3157 second_user.nickname
3161 assert ret_conn.status == 200
3163 assert first_user.confirmation_pending == true
3164 assert second_user.confirmation_pending == true
3166 log_entry = Repo.one(ModerationLog)
3168 assert ModerationLog.get_log_entry_message(log_entry) ==
3169 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3170 second_user.nickname
3175 describe "PATCH /resend_confirmation_email" do
3176 test "it resend emails for two users", %{conn: conn, admin: admin} do
3177 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3180 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3182 first_user.nickname,
3183 second_user.nickname
3187 assert ret_conn.status == 200
3189 log_entry = Repo.one(ModerationLog)
3191 assert ModerationLog.get_log_entry_message(log_entry) ==
3192 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3193 second_user.nickname
3198 describe "POST /reports/:id/notes" do
3199 setup %{conn: conn, admin: admin} do
3200 [reporter, target_user] = insert_pair(:user)
3201 activity = insert(:note_activity, user: target_user)
3203 {:ok, %{id: report_id}} =
3204 CommonAPI.report(reporter, %{
3205 account_id: target_user.id,
3206 comment: "I feel offended",
3207 status_ids: [activity.id]
3210 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3211 content: "this is disgusting!"
3214 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3215 content: "this is disgusting2!"
3220 report_id: report_id
3224 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3225 [note, _] = Repo.all(ReportNote)
3228 activity_id: ^report_id,
3229 content: "this is disgusting!",
3234 test "it returns reports with notes", %{conn: conn, admin: admin} do
3235 conn = get(conn, "/api/pleroma/admin/reports")
3237 response = json_response(conn, 200)
3238 notes = hd(response["reports"])["notes"]
3241 assert note["user"]["nickname"] == admin.nickname
3242 assert note["content"] == "this is disgusting!"
3243 assert note["created_at"]
3244 assert response["total"] == 1
3247 test "it deletes the note", %{conn: conn, report_id: report_id} do
3248 assert ReportNote |> Repo.all() |> length() == 2
3250 [note, _] = Repo.all(ReportNote)
3252 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3254 assert ReportNote |> Repo.all() |> length() == 1
3258 describe "GET /api/pleroma/admin/config/descriptions" do
3259 test "structure", %{conn: conn} do
3260 admin = insert(:user, is_admin: true)
3263 assign(conn, :user, admin)
3264 |> get("/api/pleroma/admin/config/descriptions")
3266 assert [child | _others] = json_response(conn, 200)
3268 assert child["children"]
3270 assert String.starts_with?(child["group"], ":")
3271 assert child["description"]
3274 test "filters by database configuration whitelist", %{conn: conn} do
3275 clear_config(:database_config_whitelist, [
3276 {:pleroma, :instance},
3277 {:pleroma, :activitypub},
3278 {:pleroma, Pleroma.Upload},
3282 admin = insert(:user, is_admin: true)
3285 assign(conn, :user, admin)
3286 |> get("/api/pleroma/admin/config/descriptions")
3288 children = json_response(conn, 200)
3290 assert length(children) == 4
3292 assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
3294 instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
3295 assert instance["children"]
3297 activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
3298 assert activitypub["children"]
3300 web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
3301 assert web_endpoint["children"]
3303 esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
3304 assert esshd["children"]
3308 describe "/api/pleroma/admin/stats" do
3309 test "status visibility count", %{conn: conn} do
3310 admin = insert(:user, is_admin: true)
3311 user = insert(:user)
3312 CommonAPI.post(user, %{visibility: "public", status: "hey"})
3313 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3314 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
3318 |> assign(:user, admin)
3319 |> get("/api/pleroma/admin/stats")
3320 |> json_response(200)
3322 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3323 response["status_visibility"]
3328 # Needed for testing
3329 defmodule Pleroma.Web.Endpoint.NotReal do
3332 defmodule Pleroma.Captcha.NotReal do