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
10 import ExUnit.CaptureLog
12 alias Pleroma.Activity
14 alias Pleroma.ConfigDB
16 alias Pleroma.ModerationLog
18 alias Pleroma.ReportNote
19 alias Pleroma.Tests.ObanHelpers
21 alias Pleroma.UserInviteToken
22 alias Pleroma.Web.ActivityPub.Relay
23 alias Pleroma.Web.CommonAPI
24 alias Pleroma.Web.MastodonAPI.StatusView
25 alias Pleroma.Web.MediaProxy
28 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
34 admin = insert(:user, is_admin: true)
35 token = insert(:oauth_admin_token, user: admin)
39 |> assign(:user, admin)
40 |> assign(:token, token)
42 {:ok, %{admin: admin, token: token, conn: conn}}
45 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
46 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
48 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
51 url = "/api/pleroma/admin/users/#{user.nickname}"
53 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
54 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
55 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
57 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
58 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
61 for good_token <- [good_token1, good_token2, good_token3] do
64 |> assign(:user, admin)
65 |> assign(:token, good_token)
68 assert json_response(conn, 200)
71 for good_token <- [good_token1, good_token2, good_token3] do
75 |> assign(:token, good_token)
78 assert json_response(conn, :forbidden)
81 for bad_token <- [bad_token1, bad_token2, bad_token3] do
84 |> assign(:user, admin)
85 |> assign(:token, bad_token)
88 assert json_response(conn, :forbidden)
93 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
94 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
96 test "GET /api/pleroma/admin/users/:nickname requires " <>
97 "read:accounts or admin:read:accounts or broader scope",
100 url = "/api/pleroma/admin/users/#{user.nickname}"
102 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
103 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
104 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
105 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
106 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
108 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
110 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
111 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
114 for good_token <- good_tokens do
117 |> assign(:user, admin)
118 |> assign(:token, good_token)
121 assert json_response(conn, 200)
124 for good_token <- good_tokens do
127 |> assign(:user, nil)
128 |> assign(:token, good_token)
131 assert json_response(conn, :forbidden)
134 for bad_token <- [bad_token1, bad_token2, bad_token3] do
137 |> assign(:user, admin)
138 |> assign(:token, bad_token)
141 assert json_response(conn, :forbidden)
146 describe "DELETE /api/pleroma/admin/users" do
147 test "single user", %{admin: admin, conn: conn} do
152 |> put_req_header("accept", "application/json")
153 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
155 log_entry = Repo.one(ModerationLog)
157 assert ModerationLog.get_log_entry_message(log_entry) ==
158 "@#{admin.nickname} deleted users: @#{user.nickname}"
160 assert json_response(conn, 200) == user.nickname
163 test "multiple users", %{admin: admin, conn: conn} do
164 user_one = insert(:user)
165 user_two = insert(:user)
169 |> put_req_header("accept", "application/json")
170 |> delete("/api/pleroma/admin/users", %{
171 nicknames: [user_one.nickname, user_two.nickname]
174 log_entry = Repo.one(ModerationLog)
176 assert ModerationLog.get_log_entry_message(log_entry) ==
177 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
179 response = json_response(conn, 200)
180 assert response -- [user_one.nickname, user_two.nickname] == []
184 describe "/api/pleroma/admin/users" do
185 test "Create", %{conn: conn} do
188 |> put_req_header("accept", "application/json")
189 |> post("/api/pleroma/admin/users", %{
192 "nickname" => "lain",
193 "email" => "lain@example.org",
197 "nickname" => "lain2",
198 "email" => "lain2@example.org",
204 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
205 assert response == ["success", "success"]
207 log_entry = Repo.one(ModerationLog)
209 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
212 test "Cannot create user with existing email", %{conn: conn} do
217 |> put_req_header("accept", "application/json")
218 |> post("/api/pleroma/admin/users", %{
221 "nickname" => "lain",
222 "email" => user.email,
228 assert json_response(conn, 409) == [
232 "email" => user.email,
235 "error" => "email has already been taken",
241 test "Cannot create user with existing nickname", %{conn: conn} do
246 |> put_req_header("accept", "application/json")
247 |> post("/api/pleroma/admin/users", %{
250 "nickname" => user.nickname,
251 "email" => "someuser@plerama.social",
257 assert json_response(conn, 409) == [
261 "email" => "someuser@plerama.social",
262 "nickname" => user.nickname
264 "error" => "nickname has already been taken",
270 test "Multiple user creation works in transaction", %{conn: conn} do
275 |> put_req_header("accept", "application/json")
276 |> post("/api/pleroma/admin/users", %{
279 "nickname" => "newuser",
280 "email" => "newuser@pleroma.social",
284 "nickname" => "lain",
285 "email" => user.email,
291 assert json_response(conn, 409) == [
295 "email" => user.email,
298 "error" => "email has already been taken",
304 "email" => "newuser@pleroma.social",
305 "nickname" => "newuser"
312 assert User.get_by_nickname("newuser") === nil
316 describe "/api/pleroma/admin/users/:nickname" do
317 test "Show", %{conn: conn} do
320 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
323 "deactivated" => false,
324 "id" => to_string(user.id),
326 "nickname" => user.nickname,
327 "roles" => %{"admin" => false, "moderator" => false},
329 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
330 "display_name" => HTML.strip_tags(user.name || user.nickname),
331 "confirmation_pending" => false
334 assert expected == json_response(conn, 200)
337 test "when the user doesn't exist", %{conn: conn} do
340 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
342 assert "Not found" == json_response(conn, 404)
346 describe "/api/pleroma/admin/users/follow" do
347 test "allows to force-follow another user", %{admin: admin, conn: conn} do
349 follower = insert(:user)
352 |> put_req_header("accept", "application/json")
353 |> post("/api/pleroma/admin/users/follow", %{
354 "follower" => follower.nickname,
355 "followed" => user.nickname
358 user = User.get_cached_by_id(user.id)
359 follower = User.get_cached_by_id(follower.id)
361 assert User.following?(follower, user)
363 log_entry = Repo.one(ModerationLog)
365 assert ModerationLog.get_log_entry_message(log_entry) ==
366 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
370 describe "/api/pleroma/admin/users/unfollow" do
371 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
373 follower = insert(:user)
375 User.follow(follower, user)
378 |> put_req_header("accept", "application/json")
379 |> post("/api/pleroma/admin/users/unfollow", %{
380 "follower" => follower.nickname,
381 "followed" => user.nickname
384 user = User.get_cached_by_id(user.id)
385 follower = User.get_cached_by_id(follower.id)
387 refute User.following?(follower, user)
389 log_entry = Repo.one(ModerationLog)
391 assert ModerationLog.get_log_entry_message(log_entry) ==
392 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
396 describe "PUT /api/pleroma/admin/users/tag" do
397 setup %{conn: conn} do
398 user1 = insert(:user, %{tags: ["x"]})
399 user2 = insert(:user, %{tags: ["y"]})
400 user3 = insert(:user, %{tags: ["unchanged"]})
404 |> put_req_header("accept", "application/json")
406 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
407 "#{user2.nickname}&tags[]=foo&tags[]=bar"
410 %{conn: conn, user1: user1, user2: user2, user3: user3}
413 test "it appends specified tags to users with specified nicknames", %{
419 assert json_response(conn, :no_content)
420 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
421 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
423 log_entry = Repo.one(ModerationLog)
426 [user1.nickname, user2.nickname]
427 |> Enum.map(&"@#{&1}")
430 tags = ["foo", "bar"] |> Enum.join(", ")
432 assert ModerationLog.get_log_entry_message(log_entry) ==
433 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
436 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
437 assert json_response(conn, :no_content)
438 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
442 describe "DELETE /api/pleroma/admin/users/tag" do
443 setup %{conn: conn} do
444 user1 = insert(:user, %{tags: ["x"]})
445 user2 = insert(:user, %{tags: ["y", "z"]})
446 user3 = insert(:user, %{tags: ["unchanged"]})
450 |> put_req_header("accept", "application/json")
452 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
453 "#{user2.nickname}&tags[]=x&tags[]=z"
456 %{conn: conn, user1: user1, user2: user2, user3: user3}
459 test "it removes specified tags from users with specified nicknames", %{
465 assert json_response(conn, :no_content)
466 assert User.get_cached_by_id(user1.id).tags == []
467 assert User.get_cached_by_id(user2.id).tags == ["y"]
469 log_entry = Repo.one(ModerationLog)
472 [user1.nickname, user2.nickname]
473 |> Enum.map(&"@#{&1}")
476 tags = ["x", "z"] |> Enum.join(", ")
478 assert ModerationLog.get_log_entry_message(log_entry) ==
479 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
482 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
483 assert json_response(conn, :no_content)
484 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
488 describe "/api/pleroma/admin/users/:nickname/permission_group" do
489 test "GET is giving user_info", %{admin: admin, conn: conn} do
492 |> put_req_header("accept", "application/json")
493 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
495 assert json_response(conn, 200) == %{
497 "is_moderator" => false
501 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
506 |> put_req_header("accept", "application/json")
507 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
509 assert json_response(conn, 200) == %{
513 log_entry = Repo.one(ModerationLog)
515 assert ModerationLog.get_log_entry_message(log_entry) ==
516 "@#{admin.nickname} made @#{user.nickname} admin"
519 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
520 user_one = insert(:user)
521 user_two = insert(:user)
525 |> put_req_header("accept", "application/json")
526 |> post("/api/pleroma/admin/users/permission_group/admin", %{
527 nicknames: [user_one.nickname, user_two.nickname]
530 assert json_response(conn, 200) == %{"is_admin" => true}
532 log_entry = Repo.one(ModerationLog)
534 assert ModerationLog.get_log_entry_message(log_entry) ==
535 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
538 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
539 user = insert(:user, is_admin: true)
543 |> put_req_header("accept", "application/json")
544 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
546 assert json_response(conn, 200) == %{"is_admin" => false}
548 log_entry = Repo.one(ModerationLog)
550 assert ModerationLog.get_log_entry_message(log_entry) ==
551 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
554 test "/:right DELETE, can remove from a permission group (multiple)", %{
558 user_one = insert(:user, is_admin: true)
559 user_two = insert(:user, is_admin: true)
563 |> put_req_header("accept", "application/json")
564 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
565 nicknames: [user_one.nickname, user_two.nickname]
568 assert json_response(conn, 200) == %{"is_admin" => false}
570 log_entry = Repo.one(ModerationLog)
572 assert ModerationLog.get_log_entry_message(log_entry) ==
573 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
579 describe "POST /api/pleroma/admin/email_invite, with valid config" do
580 setup do: clear_config([:instance, :registrations_open], false)
581 setup do: clear_config([:instance, :invites_enabled], true)
583 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
584 recipient_email = "foo@bar.com"
585 recipient_name = "J. D."
590 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
593 assert json_response(conn, :no_content)
595 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
597 refute token_record.used
599 notify_email = Config.get([:instance, :notify_email])
600 instance_name = Config.get([:instance, :name])
603 Pleroma.Emails.UserEmail.user_invitation_email(
610 Swoosh.TestAssertions.assert_email_sent(
611 from: {instance_name, notify_email},
612 to: {recipient_name, recipient_email},
613 html_body: email.html_body
617 test "it returns 403 if requested by a non-admin" do
618 non_admin_user = insert(:user)
619 token = insert(:oauth_token, user: non_admin_user)
623 |> assign(:user, non_admin_user)
624 |> assign(:token, token)
625 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
627 assert json_response(conn, :forbidden)
631 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
632 setup do: clear_config([:instance, :registrations_open])
633 setup do: clear_config([:instance, :invites_enabled])
635 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
636 Config.put([:instance, :registrations_open], false)
637 Config.put([:instance, :invites_enabled], false)
639 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
641 assert json_response(conn, :internal_server_error)
644 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
645 Config.put([:instance, :registrations_open], true)
646 Config.put([:instance, :invites_enabled], true)
648 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
650 assert json_response(conn, :internal_server_error)
654 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
659 |> put_req_header("accept", "application/json")
660 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
662 resp = json_response(conn, 200)
664 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
667 describe "GET /api/pleroma/admin/users" do
668 test "renders users array for the first page", %{conn: conn, admin: admin} do
669 user = insert(:user, local: false, tags: ["foo", "bar"])
670 conn = get(conn, "/api/pleroma/admin/users?page=1")
675 "deactivated" => admin.deactivated,
677 "nickname" => admin.nickname,
678 "roles" => %{"admin" => true, "moderator" => false},
681 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
682 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
683 "confirmation_pending" => false
686 "deactivated" => user.deactivated,
688 "nickname" => user.nickname,
689 "roles" => %{"admin" => false, "moderator" => false},
691 "tags" => ["foo", "bar"],
692 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
693 "display_name" => HTML.strip_tags(user.name || user.nickname),
694 "confirmation_pending" => false
697 |> Enum.sort_by(& &1["nickname"])
699 assert json_response(conn, 200) == %{
706 test "renders empty array for the second page", %{conn: conn} do
709 conn = get(conn, "/api/pleroma/admin/users?page=2")
711 assert json_response(conn, 200) == %{
718 test "regular search", %{conn: conn} do
719 user = insert(:user, nickname: "bob")
721 conn = get(conn, "/api/pleroma/admin/users?query=bo")
723 assert json_response(conn, 200) == %{
728 "deactivated" => user.deactivated,
730 "nickname" => user.nickname,
731 "roles" => %{"admin" => false, "moderator" => false},
734 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
735 "display_name" => HTML.strip_tags(user.name || user.nickname),
736 "confirmation_pending" => false
742 test "search by domain", %{conn: conn} do
743 user = insert(:user, nickname: "nickname@domain.com")
746 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
748 assert json_response(conn, 200) == %{
753 "deactivated" => user.deactivated,
755 "nickname" => user.nickname,
756 "roles" => %{"admin" => false, "moderator" => false},
759 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
760 "display_name" => HTML.strip_tags(user.name || user.nickname),
761 "confirmation_pending" => false
767 test "search by full nickname", %{conn: conn} do
768 user = insert(:user, nickname: "nickname@domain.com")
771 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
773 assert json_response(conn, 200) == %{
778 "deactivated" => user.deactivated,
780 "nickname" => user.nickname,
781 "roles" => %{"admin" => false, "moderator" => false},
784 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
785 "display_name" => HTML.strip_tags(user.name || user.nickname),
786 "confirmation_pending" => false
792 test "search by display name", %{conn: conn} do
793 user = insert(:user, name: "Display name")
796 conn = get(conn, "/api/pleroma/admin/users?name=display")
798 assert json_response(conn, 200) == %{
803 "deactivated" => user.deactivated,
805 "nickname" => user.nickname,
806 "roles" => %{"admin" => false, "moderator" => false},
809 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
810 "display_name" => HTML.strip_tags(user.name || user.nickname),
811 "confirmation_pending" => false
817 test "search by email", %{conn: conn} do
818 user = insert(:user, email: "email@example.com")
821 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
823 assert json_response(conn, 200) == %{
828 "deactivated" => user.deactivated,
830 "nickname" => user.nickname,
831 "roles" => %{"admin" => false, "moderator" => false},
834 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
835 "display_name" => HTML.strip_tags(user.name || user.nickname),
836 "confirmation_pending" => false
842 test "regular search with page size", %{conn: conn} do
843 user = insert(:user, nickname: "aalice")
844 user2 = insert(:user, nickname: "alice")
846 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
848 assert json_response(conn1, 200) == %{
853 "deactivated" => user.deactivated,
855 "nickname" => user.nickname,
856 "roles" => %{"admin" => false, "moderator" => false},
859 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
860 "display_name" => HTML.strip_tags(user.name || user.nickname),
861 "confirmation_pending" => false
866 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
868 assert json_response(conn2, 200) == %{
873 "deactivated" => user2.deactivated,
875 "nickname" => user2.nickname,
876 "roles" => %{"admin" => false, "moderator" => false},
879 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
880 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
881 "confirmation_pending" => false
887 test "only local users" do
888 admin = insert(:user, is_admin: true, nickname: "john")
889 token = insert(:oauth_admin_token, user: admin)
890 user = insert(:user, nickname: "bob")
892 insert(:user, nickname: "bobb", local: false)
896 |> assign(:user, admin)
897 |> assign(:token, token)
898 |> get("/api/pleroma/admin/users?query=bo&filters=local")
900 assert json_response(conn, 200) == %{
905 "deactivated" => user.deactivated,
907 "nickname" => user.nickname,
908 "roles" => %{"admin" => false, "moderator" => false},
911 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
912 "display_name" => HTML.strip_tags(user.name || user.nickname),
913 "confirmation_pending" => false
919 test "only local users with no query", %{conn: conn, admin: old_admin} do
920 admin = insert(:user, is_admin: true, nickname: "john")
921 user = insert(:user, nickname: "bob")
923 insert(:user, nickname: "bobb", local: false)
925 conn = get(conn, "/api/pleroma/admin/users?filters=local")
930 "deactivated" => user.deactivated,
932 "nickname" => user.nickname,
933 "roles" => %{"admin" => false, "moderator" => false},
936 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
937 "display_name" => HTML.strip_tags(user.name || user.nickname),
938 "confirmation_pending" => false
941 "deactivated" => admin.deactivated,
943 "nickname" => admin.nickname,
944 "roles" => %{"admin" => true, "moderator" => false},
947 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
948 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
949 "confirmation_pending" => false
952 "deactivated" => false,
953 "id" => old_admin.id,
955 "nickname" => old_admin.nickname,
956 "roles" => %{"admin" => true, "moderator" => false},
958 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
959 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
960 "confirmation_pending" => false
963 |> Enum.sort_by(& &1["nickname"])
965 assert json_response(conn, 200) == %{
972 test "load only admins", %{conn: conn, admin: admin} do
973 second_admin = insert(:user, is_admin: true)
977 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
982 "deactivated" => false,
984 "nickname" => admin.nickname,
985 "roles" => %{"admin" => true, "moderator" => false},
986 "local" => admin.local,
988 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
989 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
990 "confirmation_pending" => false
993 "deactivated" => false,
994 "id" => second_admin.id,
995 "nickname" => second_admin.nickname,
996 "roles" => %{"admin" => true, "moderator" => false},
997 "local" => second_admin.local,
999 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1000 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1001 "confirmation_pending" => false
1004 |> Enum.sort_by(& &1["nickname"])
1006 assert json_response(conn, 200) == %{
1013 test "load only moderators", %{conn: conn} do
1014 moderator = insert(:user, is_moderator: true)
1018 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1020 assert json_response(conn, 200) == %{
1025 "deactivated" => false,
1026 "id" => moderator.id,
1027 "nickname" => moderator.nickname,
1028 "roles" => %{"admin" => false, "moderator" => true},
1029 "local" => moderator.local,
1031 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1032 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1033 "confirmation_pending" => false
1039 test "load users with tags list", %{conn: conn} do
1040 user1 = insert(:user, tags: ["first"])
1041 user2 = insert(:user, tags: ["second"])
1045 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1050 "deactivated" => false,
1052 "nickname" => user1.nickname,
1053 "roles" => %{"admin" => false, "moderator" => false},
1054 "local" => user1.local,
1055 "tags" => ["first"],
1056 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1057 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1058 "confirmation_pending" => false
1061 "deactivated" => false,
1063 "nickname" => user2.nickname,
1064 "roles" => %{"admin" => false, "moderator" => false},
1065 "local" => user2.local,
1066 "tags" => ["second"],
1067 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1068 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1069 "confirmation_pending" => false
1072 |> Enum.sort_by(& &1["nickname"])
1074 assert json_response(conn, 200) == %{
1081 test "it works with multiple filters" do
1082 admin = insert(:user, nickname: "john", is_admin: true)
1083 token = insert(:oauth_admin_token, user: admin)
1084 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1086 insert(:user, nickname: "ken", local: true, deactivated: true)
1087 insert(:user, nickname: "bobb", local: false, deactivated: false)
1091 |> assign(:user, admin)
1092 |> assign(:token, token)
1093 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1095 assert json_response(conn, 200) == %{
1100 "deactivated" => user.deactivated,
1102 "nickname" => user.nickname,
1103 "roles" => %{"admin" => false, "moderator" => false},
1104 "local" => user.local,
1106 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1107 "display_name" => HTML.strip_tags(user.name || user.nickname),
1108 "confirmation_pending" => false
1114 test "it omits relay user", %{admin: admin, conn: conn} do
1115 assert %User{} = Relay.get_actor()
1117 conn = get(conn, "/api/pleroma/admin/users")
1119 assert json_response(conn, 200) == %{
1124 "deactivated" => admin.deactivated,
1126 "nickname" => admin.nickname,
1127 "roles" => %{"admin" => true, "moderator" => false},
1130 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1131 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1132 "confirmation_pending" => false
1139 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1140 user_one = insert(:user, deactivated: true)
1141 user_two = insert(:user, deactivated: true)
1146 "/api/pleroma/admin/users/activate",
1147 %{nicknames: [user_one.nickname, user_two.nickname]}
1150 response = json_response(conn, 200)
1151 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1153 log_entry = Repo.one(ModerationLog)
1155 assert ModerationLog.get_log_entry_message(log_entry) ==
1156 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1159 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1160 user_one = insert(:user, deactivated: false)
1161 user_two = insert(:user, deactivated: false)
1166 "/api/pleroma/admin/users/deactivate",
1167 %{nicknames: [user_one.nickname, user_two.nickname]}
1170 response = json_response(conn, 200)
1171 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1173 log_entry = Repo.one(ModerationLog)
1175 assert ModerationLog.get_log_entry_message(log_entry) ==
1176 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1179 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1180 user = insert(:user)
1182 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1184 assert json_response(conn, 200) ==
1186 "deactivated" => !user.deactivated,
1188 "nickname" => user.nickname,
1189 "roles" => %{"admin" => false, "moderator" => false},
1192 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1193 "display_name" => HTML.strip_tags(user.name || user.nickname),
1194 "confirmation_pending" => false
1197 log_entry = Repo.one(ModerationLog)
1199 assert ModerationLog.get_log_entry_message(log_entry) ==
1200 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1203 describe "POST /api/pleroma/admin/users/invite_token" do
1204 test "without options", %{conn: conn} do
1205 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1207 invite_json = json_response(conn, 200)
1208 invite = UserInviteToken.find_by_token!(invite_json["token"])
1210 refute invite.expires_at
1211 refute invite.max_use
1212 assert invite.invite_type == "one_time"
1215 test "with expires_at", %{conn: conn} do
1217 post(conn, "/api/pleroma/admin/users/invite_token", %{
1218 "expires_at" => Date.to_string(Date.utc_today())
1221 invite_json = json_response(conn, 200)
1222 invite = UserInviteToken.find_by_token!(invite_json["token"])
1225 assert invite.expires_at == Date.utc_today()
1226 refute invite.max_use
1227 assert invite.invite_type == "date_limited"
1230 test "with max_use", %{conn: conn} do
1231 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1233 invite_json = json_response(conn, 200)
1234 invite = UserInviteToken.find_by_token!(invite_json["token"])
1236 refute invite.expires_at
1237 assert invite.max_use == 150
1238 assert invite.invite_type == "reusable"
1241 test "with max use and expires_at", %{conn: conn} do
1243 post(conn, "/api/pleroma/admin/users/invite_token", %{
1245 "expires_at" => Date.to_string(Date.utc_today())
1248 invite_json = json_response(conn, 200)
1249 invite = UserInviteToken.find_by_token!(invite_json["token"])
1251 assert invite.expires_at == Date.utc_today()
1252 assert invite.max_use == 150
1253 assert invite.invite_type == "reusable_date_limited"
1257 describe "GET /api/pleroma/admin/users/invites" do
1258 test "no invites", %{conn: conn} do
1259 conn = get(conn, "/api/pleroma/admin/users/invites")
1261 assert json_response(conn, 200) == %{"invites" => []}
1264 test "with invite", %{conn: conn} do
1265 {:ok, invite} = UserInviteToken.create_invite()
1267 conn = get(conn, "/api/pleroma/admin/users/invites")
1269 assert json_response(conn, 200) == %{
1272 "expires_at" => nil,
1274 "invite_type" => "one_time",
1276 "token" => invite.token,
1285 describe "POST /api/pleroma/admin/users/revoke_invite" do
1286 test "with token", %{conn: conn} do
1287 {:ok, invite} = UserInviteToken.create_invite()
1289 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1291 assert json_response(conn, 200) == %{
1292 "expires_at" => nil,
1294 "invite_type" => "one_time",
1296 "token" => invite.token,
1302 test "with invalid token", %{conn: conn} do
1303 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1305 assert json_response(conn, :not_found) == "Not found"
1309 describe "GET /api/pleroma/admin/reports/:id" do
1310 test "returns report by its id", %{conn: conn} do
1311 [reporter, target_user] = insert_pair(:user)
1312 activity = insert(:note_activity, user: target_user)
1314 {:ok, %{id: report_id}} =
1315 CommonAPI.report(reporter, %{
1316 "account_id" => target_user.id,
1317 "comment" => "I feel offended",
1318 "status_ids" => [activity.id]
1323 |> get("/api/pleroma/admin/reports/#{report_id}")
1324 |> json_response(:ok)
1326 assert response["id"] == report_id
1329 test "returns 404 when report id is invalid", %{conn: conn} do
1330 conn = get(conn, "/api/pleroma/admin/reports/test")
1332 assert json_response(conn, :not_found) == "Not found"
1336 describe "PATCH /api/pleroma/admin/reports" do
1338 [reporter, target_user] = insert_pair(:user)
1339 activity = insert(:note_activity, user: target_user)
1341 {:ok, %{id: report_id}} =
1342 CommonAPI.report(reporter, %{
1343 "account_id" => target_user.id,
1344 "comment" => "I feel offended",
1345 "status_ids" => [activity.id]
1348 {:ok, %{id: second_report_id}} =
1349 CommonAPI.report(reporter, %{
1350 "account_id" => target_user.id,
1351 "comment" => "I feel very offended",
1352 "status_ids" => [activity.id]
1357 second_report_id: second_report_id
1361 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1362 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1363 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1367 |> assign(:token, read_token)
1368 |> patch("/api/pleroma/admin/reports", %{
1369 "reports" => [%{"state" => "resolved", "id" => id}]
1371 |> json_response(403)
1373 assert response == %{
1374 "error" => "Insufficient permissions: admin:write:reports."
1378 |> assign(:token, write_token)
1379 |> patch("/api/pleroma/admin/reports", %{
1380 "reports" => [%{"state" => "resolved", "id" => id}]
1382 |> json_response(:no_content)
1385 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1387 |> patch("/api/pleroma/admin/reports", %{
1389 %{"state" => "resolved", "id" => id}
1392 |> json_response(:no_content)
1394 activity = Activity.get_by_id(id)
1395 assert activity.data["state"] == "resolved"
1397 log_entry = Repo.one(ModerationLog)
1399 assert ModerationLog.get_log_entry_message(log_entry) ==
1400 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1403 test "closes report", %{conn: conn, id: id, admin: admin} do
1405 |> patch("/api/pleroma/admin/reports", %{
1407 %{"state" => "closed", "id" => id}
1410 |> json_response(:no_content)
1412 activity = Activity.get_by_id(id)
1413 assert activity.data["state"] == "closed"
1415 log_entry = Repo.one(ModerationLog)
1417 assert ModerationLog.get_log_entry_message(log_entry) ==
1418 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1421 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1424 |> patch("/api/pleroma/admin/reports", %{
1426 %{"state" => "test", "id" => id}
1430 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1433 test "returns 404 when report is not exist", %{conn: conn} do
1436 |> patch("/api/pleroma/admin/reports", %{
1438 %{"state" => "closed", "id" => "test"}
1442 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1445 test "updates state of multiple reports", %{
1449 second_report_id: second_report_id
1452 |> patch("/api/pleroma/admin/reports", %{
1454 %{"state" => "resolved", "id" => id},
1455 %{"state" => "closed", "id" => second_report_id}
1458 |> json_response(:no_content)
1460 activity = Activity.get_by_id(id)
1461 second_activity = Activity.get_by_id(second_report_id)
1462 assert activity.data["state"] == "resolved"
1463 assert second_activity.data["state"] == "closed"
1465 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1467 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1468 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1470 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1471 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1475 describe "GET /api/pleroma/admin/reports" do
1476 test "returns empty response when no reports created", %{conn: conn} do
1479 |> get("/api/pleroma/admin/reports")
1480 |> json_response(:ok)
1482 assert Enum.empty?(response["reports"])
1483 assert response["total"] == 0
1486 test "returns reports", %{conn: conn} do
1487 [reporter, target_user] = insert_pair(:user)
1488 activity = insert(:note_activity, user: target_user)
1490 {:ok, %{id: report_id}} =
1491 CommonAPI.report(reporter, %{
1492 "account_id" => target_user.id,
1493 "comment" => "I feel offended",
1494 "status_ids" => [activity.id]
1499 |> get("/api/pleroma/admin/reports")
1500 |> json_response(:ok)
1502 [report] = response["reports"]
1504 assert length(response["reports"]) == 1
1505 assert report["id"] == report_id
1507 assert response["total"] == 1
1510 test "returns reports with specified state", %{conn: conn} do
1511 [reporter, target_user] = insert_pair(:user)
1512 activity = insert(:note_activity, user: target_user)
1514 {:ok, %{id: first_report_id}} =
1515 CommonAPI.report(reporter, %{
1516 "account_id" => target_user.id,
1517 "comment" => "I feel offended",
1518 "status_ids" => [activity.id]
1521 {:ok, %{id: second_report_id}} =
1522 CommonAPI.report(reporter, %{
1523 "account_id" => target_user.id,
1524 "comment" => "I don't like this user"
1527 CommonAPI.update_report_state(second_report_id, "closed")
1531 |> get("/api/pleroma/admin/reports", %{
1534 |> json_response(:ok)
1536 [open_report] = response["reports"]
1538 assert length(response["reports"]) == 1
1539 assert open_report["id"] == first_report_id
1541 assert response["total"] == 1
1545 |> get("/api/pleroma/admin/reports", %{
1548 |> json_response(:ok)
1550 [closed_report] = response["reports"]
1552 assert length(response["reports"]) == 1
1553 assert closed_report["id"] == second_report_id
1555 assert response["total"] == 1
1559 |> get("/api/pleroma/admin/reports", %{
1560 "state" => "resolved"
1562 |> json_response(:ok)
1564 assert Enum.empty?(response["reports"])
1565 assert response["total"] == 0
1568 test "returns 403 when requested by a non-admin" do
1569 user = insert(:user)
1570 token = insert(:oauth_token, user: user)
1574 |> assign(:user, user)
1575 |> assign(:token, token)
1576 |> get("/api/pleroma/admin/reports")
1578 assert json_response(conn, :forbidden) ==
1579 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1582 test "returns 403 when requested by anonymous" do
1583 conn = get(build_conn(), "/api/pleroma/admin/reports")
1585 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1589 describe "GET /api/pleroma/admin/grouped_reports" do
1591 [reporter, target_user] = insert_pair(:user)
1593 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1594 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1595 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1598 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1601 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1604 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1606 {:ok, first_report} =
1607 CommonAPI.report(reporter, %{
1608 "account_id" => target_user.id,
1609 "status_ids" => [first_status.id, second_status.id, third_status.id]
1612 {:ok, second_report} =
1613 CommonAPI.report(reporter, %{
1614 "account_id" => target_user.id,
1615 "status_ids" => [first_status.id, second_status.id]
1618 {:ok, third_report} =
1619 CommonAPI.report(reporter, %{
1620 "account_id" => target_user.id,
1621 "status_ids" => [first_status.id]
1625 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1626 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1627 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1628 first_report: first_report,
1629 first_status_reports: [first_report, second_report, third_report],
1630 second_status_reports: [first_report, second_report],
1631 third_status_reports: [first_report],
1632 target_user: target_user,
1637 test "returns reports grouped by status", %{
1639 first_status: first_status,
1640 second_status: second_status,
1641 third_status: third_status,
1642 first_status_reports: first_status_reports,
1643 second_status_reports: second_status_reports,
1644 third_status_reports: third_status_reports,
1645 target_user: target_user,
1650 |> get("/api/pleroma/admin/grouped_reports")
1651 |> json_response(:ok)
1653 assert length(response["reports"]) == 3
1655 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1657 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1659 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1661 assert length(first_group["reports"]) == 3
1662 assert length(second_group["reports"]) == 2
1663 assert length(third_group["reports"]) == 1
1665 assert first_group["date"] ==
1666 Enum.max_by(first_status_reports, fn act ->
1667 NaiveDateTime.from_iso8601!(act.data["published"])
1668 end).data["published"]
1670 assert first_group["status"] ==
1672 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1677 assert(first_group["account"]["id"] == target_user.id)
1679 assert length(first_group["actors"]) == 1
1680 assert hd(first_group["actors"])["id"] == reporter.id
1682 assert Enum.map(first_group["reports"], & &1["id"]) --
1683 Enum.map(first_status_reports, & &1.id) == []
1685 assert second_group["date"] ==
1686 Enum.max_by(second_status_reports, fn act ->
1687 NaiveDateTime.from_iso8601!(act.data["published"])
1688 end).data["published"]
1690 assert second_group["status"] ==
1692 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1697 assert second_group["account"]["id"] == target_user.id
1699 assert length(second_group["actors"]) == 1
1700 assert hd(second_group["actors"])["id"] == reporter.id
1702 assert Enum.map(second_group["reports"], & &1["id"]) --
1703 Enum.map(second_status_reports, & &1.id) == []
1705 assert third_group["date"] ==
1706 Enum.max_by(third_status_reports, fn act ->
1707 NaiveDateTime.from_iso8601!(act.data["published"])
1708 end).data["published"]
1710 assert third_group["status"] ==
1712 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1717 assert third_group["account"]["id"] == target_user.id
1719 assert length(third_group["actors"]) == 1
1720 assert hd(third_group["actors"])["id"] == reporter.id
1722 assert Enum.map(third_group["reports"], & &1["id"]) --
1723 Enum.map(third_status_reports, & &1.id) == []
1726 test "reopened report renders status data", %{
1728 first_report: first_report,
1729 first_status: first_status
1731 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1735 |> get("/api/pleroma/admin/grouped_reports")
1736 |> json_response(:ok)
1738 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1740 assert first_group["status"] ==
1742 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1748 test "reopened report does not render status data if status has been deleted", %{
1750 first_report: first_report,
1751 first_status: first_status,
1752 target_user: target_user
1754 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1755 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1757 refute Activity.get_by_ap_id(first_status.id)
1761 |> get("/api/pleroma/admin/grouped_reports")
1762 |> json_response(:ok)
1764 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1768 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1771 test "account not empty if status was deleted", %{
1773 first_report: first_report,
1774 first_status: first_status,
1775 target_user: target_user
1777 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1778 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1780 refute Activity.get_by_ap_id(first_status.id)
1784 |> get("/api/pleroma/admin/grouped_reports")
1785 |> json_response(:ok)
1787 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
1791 describe "PUT /api/pleroma/admin/statuses/:id" do
1793 activity = insert(:note_activity)
1798 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1801 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1802 |> json_response(:ok)
1804 assert response["sensitive"]
1806 log_entry = Repo.one(ModerationLog)
1808 assert ModerationLog.get_log_entry_message(log_entry) ==
1809 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1813 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1814 |> json_response(:ok)
1816 refute response["sensitive"]
1819 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1822 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1823 |> json_response(:ok)
1825 assert response["visibility"] == "public"
1827 log_entry = Repo.one(ModerationLog)
1829 assert ModerationLog.get_log_entry_message(log_entry) ==
1830 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1834 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1835 |> json_response(:ok)
1837 assert response["visibility"] == "private"
1841 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1842 |> json_response(:ok)
1844 assert response["visibility"] == "unlisted"
1847 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1848 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1850 assert json_response(conn, :bad_request) == "Unsupported visibility"
1854 describe "DELETE /api/pleroma/admin/statuses/:id" do
1856 activity = insert(:note_activity)
1861 test "deletes status", %{conn: conn, id: id, admin: admin} do
1863 |> delete("/api/pleroma/admin/statuses/#{id}")
1864 |> json_response(:ok)
1866 refute Activity.get_by_id(id)
1868 log_entry = Repo.one(ModerationLog)
1870 assert ModerationLog.get_log_entry_message(log_entry) ==
1871 "@#{admin.nickname} deleted status ##{id}"
1874 test "returns 404 when the status does not exist", %{conn: conn} do
1875 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1877 assert json_response(conn, :not_found) == "Not found"
1881 describe "GET /api/pleroma/admin/config" do
1882 setup do: clear_config(:configurable_from_database, true)
1884 test "when configuration from database is off", %{conn: conn} do
1885 Config.put(:configurable_from_database, false)
1886 conn = get(conn, "/api/pleroma/admin/config")
1888 assert json_response(conn, 400) ==
1889 "To use this endpoint you need to enable configuration from database."
1892 test "with settings only in db", %{conn: conn} do
1893 config1 = insert(:config)
1894 config2 = insert(:config)
1896 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1901 "group" => ":pleroma",
1906 "group" => ":pleroma",
1911 } = json_response(conn, 200)
1913 assert key1 == config1.key
1914 assert key2 == config2.key
1917 test "db is added to settings that are in db", %{conn: conn} do
1918 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1920 %{"configs" => configs} =
1922 |> get("/api/pleroma/admin/config")
1923 |> json_response(200)
1926 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1927 group == ":pleroma" and key == ":instance"
1930 assert instance_config["db"] == [":name"]
1933 test "merged default setting with db settings", %{conn: conn} do
1934 config1 = insert(:config)
1935 config2 = insert(:config)
1939 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1942 %{"configs" => configs} =
1944 |> get("/api/pleroma/admin/config")
1945 |> json_response(200)
1947 assert length(configs) > 3
1950 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1951 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1954 assert length(received_configs) == 3
1958 |> ConfigDB.from_binary()
1960 |> ConfigDB.convert()
1962 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1963 assert db in [[config1.key], [config2.key], db_keys]
1966 ConfigDB.from_binary_with_convert(config1.value),
1967 ConfigDB.from_binary_with_convert(config2.value),
1968 ConfigDB.from_binary_with_convert(config3.value)
1973 test "subkeys with full update right merge", %{conn: conn} do
1977 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1983 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1986 %{"configs" => configs} =
1988 |> get("/api/pleroma/admin/config")
1989 |> json_response(200)
1992 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1993 group == ":pleroma" and key in [config1.key, config2.key]
1996 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1997 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1999 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
2000 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
2002 assert emoji_val[:groups] == [a: 1, b: 2]
2003 assert assets_val[:mascots] == [a: 1, b: 2]
2007 test "POST /api/pleroma/admin/config error", %{conn: conn} do
2008 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
2010 assert json_response(conn, 400) ==
2011 "To use this endpoint you need to enable configuration from database."
2014 describe "POST /api/pleroma/admin/config" do
2016 http = Application.get_env(:pleroma, :http)
2019 Application.delete_env(:pleroma, :key1)
2020 Application.delete_env(:pleroma, :key2)
2021 Application.delete_env(:pleroma, :key3)
2022 Application.delete_env(:pleroma, :key4)
2023 Application.delete_env(:pleroma, :keyaa1)
2024 Application.delete_env(:pleroma, :keyaa2)
2025 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
2026 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
2027 Application.put_env(:pleroma, :http, http)
2028 Application.put_env(:tesla, :adapter, Tesla.Mock)
2029 Restarter.Pleroma.refresh()
2033 setup do: clear_config(:configurable_from_database, true)
2035 @tag capture_log: true
2036 test "create new config setting in db", %{conn: conn} do
2037 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2038 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
2041 post(conn, "/api/pleroma/admin/config", %{
2043 %{group: ":pleroma", key: ":key1", value: "value1"},
2045 group: ":ueberauth",
2047 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
2053 ":nested_1" => "nested_value1",
2055 %{":nested_22" => "nested_value222"},
2056 %{":nested_33" => %{":nested_44" => "nested_444"}}
2064 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2065 %{"nested_4" => true}
2071 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2076 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2081 assert json_response(conn, 200) == %{
2084 "group" => ":pleroma",
2086 "value" => "value1",
2090 "group" => ":ueberauth",
2091 "key" => "Ueberauth",
2092 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
2093 "db" => [":consumer_secret"]
2096 "group" => ":pleroma",
2099 ":nested_1" => "nested_value1",
2101 %{":nested_22" => "nested_value222"},
2102 %{":nested_33" => %{":nested_44" => "nested_444"}}
2108 "group" => ":pleroma",
2111 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2112 %{"nested_4" => true}
2117 "group" => ":pleroma",
2119 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2125 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2131 assert Application.get_env(:pleroma, :key1) == "value1"
2133 assert Application.get_env(:pleroma, :key2) == %{
2134 nested_1: "nested_value1",
2136 %{nested_22: "nested_value222"},
2137 %{nested_33: %{nested_44: "nested_444"}}
2141 assert Application.get_env(:pleroma, :key3) == [
2142 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2143 %{"nested_4" => true}
2146 assert Application.get_env(:pleroma, :key4) == %{
2147 "endpoint" => "https://example.com",
2151 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2154 test "save configs setting without explicit key", %{conn: conn} do
2155 level = Application.get_env(:quack, :level)
2156 meta = Application.get_env(:quack, :meta)
2157 webhook_url = Application.get_env(:quack, :webhook_url)
2160 Application.put_env(:quack, :level, level)
2161 Application.put_env(:quack, :meta, meta)
2162 Application.put_env(:quack, :webhook_url, webhook_url)
2166 post(conn, "/api/pleroma/admin/config", %{
2180 key: ":webhook_url",
2181 value: "https://hooks.slack.com/services/KEY"
2186 assert json_response(conn, 200) == %{
2189 "group" => ":quack",
2195 "group" => ":quack",
2197 "value" => [":none"],
2201 "group" => ":quack",
2202 "key" => ":webhook_url",
2203 "value" => "https://hooks.slack.com/services/KEY",
2204 "db" => [":webhook_url"]
2209 assert Application.get_env(:quack, :level) == :info
2210 assert Application.get_env(:quack, :meta) == [:none]
2211 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2214 test "saving config with partial update", %{conn: conn} do
2215 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2218 post(conn, "/api/pleroma/admin/config", %{
2220 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2224 assert json_response(conn, 200) == %{
2227 "group" => ":pleroma",
2230 %{"tuple" => [":key1", 1]},
2231 %{"tuple" => [":key2", 2]},
2232 %{"tuple" => [":key3", 3]}
2234 "db" => [":key1", ":key2", ":key3"]
2240 test "saving config which need pleroma reboot", %{conn: conn} do
2241 chat = Config.get(:chat)
2242 on_exit(fn -> Config.put(:chat, chat) end)
2246 "/api/pleroma/admin/config",
2249 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2253 |> json_response(200) == %{
2256 "db" => [":enabled"],
2257 "group" => ":pleroma",
2259 "value" => [%{"tuple" => [":enabled", true]}]
2262 "need_reboot" => true
2267 |> get("/api/pleroma/admin/config")
2268 |> json_response(200)
2270 assert configs["need_reboot"]
2273 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2274 end) =~ "pleroma restarted"
2278 |> get("/api/pleroma/admin/config")
2279 |> json_response(200)
2281 refute Map.has_key?(configs, "need_reboot")
2284 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2285 chat = Config.get(:chat)
2286 on_exit(fn -> Config.put(:chat, chat) end)
2290 "/api/pleroma/admin/config",
2293 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2297 |> json_response(200) == %{
2300 "db" => [":enabled"],
2301 "group" => ":pleroma",
2303 "value" => [%{"tuple" => [":enabled", true]}]
2306 "need_reboot" => true
2309 assert post(conn, "/api/pleroma/admin/config", %{
2311 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2314 |> json_response(200) == %{
2317 "group" => ":pleroma",
2320 %{"tuple" => [":key3", 3]}
2325 "need_reboot" => true
2329 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2330 end) =~ "pleroma restarted"
2334 |> get("/api/pleroma/admin/config")
2335 |> json_response(200)
2337 refute Map.has_key?(configs, "need_reboot")
2340 test "saving config with nested merge", %{conn: conn} do
2342 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2345 post(conn, "/api/pleroma/admin/config", %{
2348 group: config.group,
2351 %{"tuple" => [":key3", 3]},
2356 %{"tuple" => [":k2", 1]},
2357 %{"tuple" => [":k3", 3]}
2366 assert json_response(conn, 200) == %{
2369 "group" => ":pleroma",
2372 %{"tuple" => [":key1", 1]},
2373 %{"tuple" => [":key3", 3]},
2378 %{"tuple" => [":k1", 1]},
2379 %{"tuple" => [":k2", 1]},
2380 %{"tuple" => [":k3", 3]}
2385 "db" => [":key1", ":key3", ":key2"]
2391 test "saving special atoms", %{conn: conn} do
2393 post(conn, "/api/pleroma/admin/config", %{
2396 "group" => ":pleroma",
2402 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2410 assert json_response(conn, 200) == %{
2413 "group" => ":pleroma",
2419 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2423 "db" => [":ssl_options"]
2428 assert Application.get_env(:pleroma, :key1) == [
2429 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2433 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2434 backends = Application.get_env(:logger, :backends)
2435 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2441 value: :erlang.term_to_binary([])
2445 post(conn, "/api/pleroma/admin/config", %{
2448 group: config.group,
2450 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2455 assert json_response(conn, 200) == %{
2458 "group" => ":logger",
2459 "key" => ":backends",
2462 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2464 "db" => [":backends"]
2469 assert Application.get_env(:logger, :backends) == [
2471 {ExSyslogger, :ex_syslogger}
2476 Logger.warn("Ooops...")
2480 test "saving full setting if value is not keyword", %{conn: conn} do
2485 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2489 post(conn, "/api/pleroma/admin/config", %{
2491 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2495 assert json_response(conn, 200) == %{
2498 "group" => ":tesla",
2499 "key" => ":adapter",
2500 "value" => "Tesla.Adapter.Httpc",
2501 "db" => [":adapter"]
2507 test "update config setting & delete with fallback to default value", %{
2512 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2513 config1 = insert(:config, key: ":keyaa1")
2514 config2 = insert(:config, key: ":keyaa2")
2518 group: ":ueberauth",
2523 post(conn, "/api/pleroma/admin/config", %{
2525 %{group: config1.group, key: config1.key, value: "another_value"},
2526 %{group: config2.group, key: config2.key, value: "another_value"}
2530 assert json_response(conn, 200) == %{
2533 "group" => ":pleroma",
2534 "key" => config1.key,
2535 "value" => "another_value",
2539 "group" => ":pleroma",
2540 "key" => config2.key,
2541 "value" => "another_value",
2547 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2548 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2549 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2553 |> assign(:user, admin)
2554 |> assign(:token, token)
2555 |> post("/api/pleroma/admin/config", %{
2557 %{group: config2.group, key: config2.key, delete: true},
2559 group: ":ueberauth",
2566 assert json_response(conn, 200) == %{
2570 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2571 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2574 test "common config example", %{conn: conn} do
2575 adapter = Application.get_env(:tesla, :adapter)
2576 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2579 post(conn, "/api/pleroma/admin/config", %{
2582 "group" => ":pleroma",
2583 "key" => "Pleroma.Captcha.NotReal",
2585 %{"tuple" => [":enabled", false]},
2586 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2587 %{"tuple" => [":seconds_valid", 60]},
2588 %{"tuple" => [":path", ""]},
2589 %{"tuple" => [":key1", nil]},
2590 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2591 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2592 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2593 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2594 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2595 %{"tuple" => [":name", "Pleroma"]}
2599 "group" => ":tesla",
2600 "key" => ":adapter",
2601 "value" => "Tesla.Adapter.Httpc"
2606 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2607 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2609 assert json_response(conn, 200) == %{
2612 "group" => ":pleroma",
2613 "key" => "Pleroma.Captcha.NotReal",
2615 %{"tuple" => [":enabled", false]},
2616 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2617 %{"tuple" => [":seconds_valid", 60]},
2618 %{"tuple" => [":path", ""]},
2619 %{"tuple" => [":key1", nil]},
2620 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2621 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2622 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2623 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2624 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2625 %{"tuple" => [":name", "Pleroma"]}
2642 "group" => ":tesla",
2643 "key" => ":adapter",
2644 "value" => "Tesla.Adapter.Httpc",
2645 "db" => [":adapter"]
2651 test "tuples with more than two values", %{conn: conn} do
2653 post(conn, "/api/pleroma/admin/config", %{
2656 "group" => ":pleroma",
2657 "key" => "Pleroma.Web.Endpoint.NotReal",
2673 "/api/v1/streaming",
2674 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2681 "Phoenix.Endpoint.CowboyWebSocket",
2684 "Phoenix.Transports.WebSocket",
2687 "Pleroma.Web.Endpoint",
2688 "Pleroma.Web.UserSocket",
2699 "Phoenix.Endpoint.Cowboy2Handler",
2700 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2717 assert json_response(conn, 200) == %{
2720 "group" => ":pleroma",
2721 "key" => "Pleroma.Web.Endpoint.NotReal",
2737 "/api/v1/streaming",
2738 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2745 "Phoenix.Endpoint.CowboyWebSocket",
2748 "Phoenix.Transports.WebSocket",
2751 "Pleroma.Web.Endpoint",
2752 "Pleroma.Web.UserSocket",
2763 "Phoenix.Endpoint.Cowboy2Handler",
2764 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2783 test "settings with nesting map", %{conn: conn} do
2785 post(conn, "/api/pleroma/admin/config", %{
2788 "group" => ":pleroma",
2791 %{"tuple" => [":key2", "some_val"]},
2796 ":max_options" => 20,
2797 ":max_option_chars" => 200,
2798 ":min_expiration" => 0,
2799 ":max_expiration" => 31_536_000,
2801 ":max_options" => 20,
2802 ":max_option_chars" => 200,
2803 ":min_expiration" => 0,
2804 ":max_expiration" => 31_536_000
2814 assert json_response(conn, 200) ==
2818 "group" => ":pleroma",
2821 %{"tuple" => [":key2", "some_val"]},
2826 ":max_expiration" => 31_536_000,
2827 ":max_option_chars" => 200,
2828 ":max_options" => 20,
2829 ":min_expiration" => 0,
2831 ":max_expiration" => 31_536_000,
2832 ":max_option_chars" => 200,
2833 ":max_options" => 20,
2834 ":min_expiration" => 0
2840 "db" => [":key2", ":key3"]
2846 test "value as map", %{conn: conn} do
2848 post(conn, "/api/pleroma/admin/config", %{
2851 "group" => ":pleroma",
2853 "value" => %{"key" => "some_val"}
2858 assert json_response(conn, 200) ==
2862 "group" => ":pleroma",
2864 "value" => %{"key" => "some_val"},
2871 test "queues key as atom", %{conn: conn} do
2873 post(conn, "/api/pleroma/admin/config", %{
2879 %{"tuple" => [":federator_incoming", 50]},
2880 %{"tuple" => [":federator_outgoing", 50]},
2881 %{"tuple" => [":web_push", 50]},
2882 %{"tuple" => [":mailer", 10]},
2883 %{"tuple" => [":transmogrifier", 20]},
2884 %{"tuple" => [":scheduled_activities", 10]},
2885 %{"tuple" => [":background", 5]}
2891 assert json_response(conn, 200) == %{
2897 %{"tuple" => [":federator_incoming", 50]},
2898 %{"tuple" => [":federator_outgoing", 50]},
2899 %{"tuple" => [":web_push", 50]},
2900 %{"tuple" => [":mailer", 10]},
2901 %{"tuple" => [":transmogrifier", 20]},
2902 %{"tuple" => [":scheduled_activities", 10]},
2903 %{"tuple" => [":background", 5]}
2906 ":federator_incoming",
2907 ":federator_outgoing",
2911 ":scheduled_activities",
2919 test "delete part of settings by atom subkeys", %{conn: conn} do
2923 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2927 post(conn, "/api/pleroma/admin/config", %{
2930 group: config.group,
2932 subkeys: [":subkey1", ":subkey3"],
2938 assert json_response(conn, 200) == %{
2941 "group" => ":pleroma",
2943 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2944 "db" => [":subkey2"]
2950 test "proxy tuple localhost", %{conn: conn} do
2952 post(conn, "/api/pleroma/admin/config", %{
2958 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2959 %{"tuple" => [":send_user_agent", false]}
2965 assert json_response(conn, 200) == %{
2968 "group" => ":pleroma",
2971 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2972 %{"tuple" => [":send_user_agent", false]}
2974 "db" => [":proxy_url", ":send_user_agent"]
2980 test "proxy tuple domain", %{conn: conn} do
2982 post(conn, "/api/pleroma/admin/config", %{
2988 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2989 %{"tuple" => [":send_user_agent", false]}
2995 assert json_response(conn, 200) == %{
2998 "group" => ":pleroma",
3001 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
3002 %{"tuple" => [":send_user_agent", false]}
3004 "db" => [":proxy_url", ":send_user_agent"]
3010 test "proxy tuple ip", %{conn: conn} do
3012 post(conn, "/api/pleroma/admin/config", %{
3018 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
3019 %{"tuple" => [":send_user_agent", false]}
3025 assert json_response(conn, 200) == %{
3028 "group" => ":pleroma",
3031 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
3032 %{"tuple" => [":send_user_agent", false]}
3034 "db" => [":proxy_url", ":send_user_agent"]
3041 describe "GET /api/pleroma/admin/restart" do
3042 setup do: clear_config(:configurable_from_database, true)
3044 test "pleroma restarts", %{conn: conn} do
3046 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
3047 end) =~ "pleroma restarted"
3049 refute Restarter.Pleroma.need_reboot?()
3053 describe "GET /api/pleroma/admin/statuses" do
3054 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
3055 blocked = insert(:user)
3056 user = insert(:user)
3057 User.block(admin, blocked)
3060 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
3062 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
3063 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
3064 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
3065 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
3069 |> get("/api/pleroma/admin/statuses")
3070 |> json_response(200)
3072 refute "private" in Enum.map(response, & &1["visibility"])
3073 assert length(response) == 3
3076 test "returns only local statuses with local_only on", %{conn: conn} do
3077 user = insert(:user)
3078 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
3079 insert(:note_activity, user: user, local: true)
3080 insert(:note_activity, user: remote_user, local: false)
3084 |> get("/api/pleroma/admin/statuses?local_only=true")
3085 |> json_response(200)
3087 assert length(response) == 1
3090 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
3091 user = insert(:user)
3094 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
3096 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
3097 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
3098 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
3099 assert json_response(conn, 200) |> length() == 3
3103 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3105 user = insert(:user)
3107 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3108 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3109 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3111 insert(:note_activity, user: user, published: date1)
3112 insert(:note_activity, user: user, published: date2)
3113 insert(:note_activity, user: user, published: date3)
3118 test "renders user's statuses", %{conn: conn, user: user} do
3119 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3121 assert json_response(conn, 200) |> length() == 3
3124 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3125 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3127 assert json_response(conn, 200) |> length() == 2
3130 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3131 {:ok, _private_status} =
3132 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3134 {:ok, _public_status} =
3135 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3137 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3139 assert json_response(conn, 200) |> length() == 4
3142 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3143 {:ok, _private_status} =
3144 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3146 {:ok, _public_status} =
3147 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3149 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3151 assert json_response(conn, 200) |> length() == 5
3154 test "excludes reblogs by default", %{conn: conn, user: user} do
3155 other_user = insert(:user)
3156 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3157 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3159 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3160 assert json_response(conn_res, 200) |> length() == 0
3163 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3165 assert json_response(conn_res, 200) |> length() == 1
3169 describe "GET /api/pleroma/admin/moderation_log" do
3171 moderator = insert(:user, is_moderator: true)
3173 %{moderator: moderator}
3176 test "returns the log", %{conn: conn, admin: admin} do
3177 Repo.insert(%ModerationLog{
3181 "nickname" => admin.nickname,
3184 action: "relay_follow",
3185 target: "https://example.org/relay"
3187 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3190 Repo.insert(%ModerationLog{
3194 "nickname" => admin.nickname,
3197 action: "relay_unfollow",
3198 target: "https://example.org/relay"
3200 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3203 conn = get(conn, "/api/pleroma/admin/moderation_log")
3205 response = json_response(conn, 200)
3206 [first_entry, second_entry] = response["items"]
3208 assert response["total"] == 2
3209 assert first_entry["data"]["action"] == "relay_unfollow"
3211 assert first_entry["message"] ==
3212 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3214 assert second_entry["data"]["action"] == "relay_follow"
3216 assert second_entry["message"] ==
3217 "@#{admin.nickname} followed relay: https://example.org/relay"
3220 test "returns the log with pagination", %{conn: conn, admin: admin} do
3221 Repo.insert(%ModerationLog{
3225 "nickname" => admin.nickname,
3228 action: "relay_follow",
3229 target: "https://example.org/relay"
3231 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3234 Repo.insert(%ModerationLog{
3238 "nickname" => admin.nickname,
3241 action: "relay_unfollow",
3242 target: "https://example.org/relay"
3244 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3247 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3249 response1 = json_response(conn1, 200)
3250 [first_entry] = response1["items"]
3252 assert response1["total"] == 2
3253 assert response1["items"] |> length() == 1
3254 assert first_entry["data"]["action"] == "relay_unfollow"
3256 assert first_entry["message"] ==
3257 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3259 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3261 response2 = json_response(conn2, 200)
3262 [second_entry] = response2["items"]
3264 assert response2["total"] == 2
3265 assert response2["items"] |> length() == 1
3266 assert second_entry["data"]["action"] == "relay_follow"
3268 assert second_entry["message"] ==
3269 "@#{admin.nickname} followed relay: https://example.org/relay"
3272 test "filters log by date", %{conn: conn, admin: admin} do
3273 first_date = "2017-08-15T15:47:06Z"
3274 second_date = "2017-08-20T15:47:06Z"
3276 Repo.insert(%ModerationLog{
3280 "nickname" => admin.nickname,
3283 action: "relay_follow",
3284 target: "https://example.org/relay"
3286 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3289 Repo.insert(%ModerationLog{
3293 "nickname" => admin.nickname,
3296 action: "relay_unfollow",
3297 target: "https://example.org/relay"
3299 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3305 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3308 response1 = json_response(conn1, 200)
3309 [first_entry] = response1["items"]
3311 assert response1["total"] == 1
3312 assert first_entry["data"]["action"] == "relay_unfollow"
3314 assert first_entry["message"] ==
3315 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3318 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3319 Repo.insert(%ModerationLog{
3323 "nickname" => admin.nickname,
3326 action: "relay_follow",
3327 target: "https://example.org/relay"
3331 Repo.insert(%ModerationLog{
3334 "id" => moderator.id,
3335 "nickname" => moderator.nickname,
3338 action: "relay_unfollow",
3339 target: "https://example.org/relay"
3343 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3345 response1 = json_response(conn1, 200)
3346 [first_entry] = response1["items"]
3348 assert response1["total"] == 1
3349 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3352 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3353 ModerationLog.insert_log(%{
3355 action: "relay_follow",
3356 target: "https://example.org/relay"
3359 ModerationLog.insert_log(%{
3361 action: "relay_unfollow",
3362 target: "https://example.org/relay"
3365 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3367 response1 = json_response(conn1, 200)
3368 [first_entry] = response1["items"]
3370 assert response1["total"] == 1
3372 assert get_in(first_entry, ["data", "message"]) ==
3373 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3377 describe "PATCH /users/:nickname/force_password_reset" do
3378 test "sets password_reset_pending to true", %{conn: conn} do
3379 user = insert(:user)
3380 assert user.password_reset_pending == false
3383 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3385 assert json_response(conn, 204) == ""
3387 ObanHelpers.perform_all()
3389 assert User.get_by_id(user.id).password_reset_pending == true
3393 describe "relays" do
3394 test "POST /relay", %{conn: conn, admin: admin} do
3396 post(conn, "/api/pleroma/admin/relay", %{
3397 relay_url: "http://mastodon.example.org/users/admin"
3400 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3402 log_entry = Repo.one(ModerationLog)
3404 assert ModerationLog.get_log_entry_message(log_entry) ==
3405 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3408 test "GET /relay", %{conn: conn} do
3409 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3411 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3412 |> Enum.each(fn ap_id ->
3413 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3414 User.follow(relay_user, user)
3417 conn = get(conn, "/api/pleroma/admin/relay")
3419 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3422 test "DELETE /relay", %{conn: conn, admin: admin} do
3423 post(conn, "/api/pleroma/admin/relay", %{
3424 relay_url: "http://mastodon.example.org/users/admin"
3428 delete(conn, "/api/pleroma/admin/relay", %{
3429 relay_url: "http://mastodon.example.org/users/admin"
3432 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3434 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3436 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3437 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3439 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3440 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3444 describe "instances" do
3445 test "GET /instances/:instance/statuses", %{conn: conn} do
3446 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3447 user2 = insert(:user, local: false, nickname: "test@test.com")
3448 insert_pair(:note_activity, user: user)
3449 activity = insert(:note_activity, user: user2)
3451 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3453 response = json_response(ret_conn, 200)
3455 assert length(response) == 2
3457 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3459 response = json_response(ret_conn, 200)
3461 assert length(response) == 1
3463 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3465 response = json_response(ret_conn, 200)
3467 assert Enum.empty?(response)
3469 CommonAPI.repeat(activity.id, user)
3471 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3472 response = json_response(ret_conn, 200)
3473 assert length(response) == 2
3475 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3476 response = json_response(ret_conn, 200)
3477 assert length(response) == 3
3481 describe "PATCH /confirm_email" do
3482 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3483 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3485 assert first_user.confirmation_pending == true
3486 assert second_user.confirmation_pending == true
3489 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3491 first_user.nickname,
3492 second_user.nickname
3496 assert ret_conn.status == 200
3498 assert first_user.confirmation_pending == true
3499 assert second_user.confirmation_pending == true
3501 log_entry = Repo.one(ModerationLog)
3503 assert ModerationLog.get_log_entry_message(log_entry) ==
3504 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3505 second_user.nickname
3510 describe "PATCH /resend_confirmation_email" do
3511 test "it resend emails for two users", %{conn: conn, admin: admin} do
3512 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3515 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3517 first_user.nickname,
3518 second_user.nickname
3522 assert ret_conn.status == 200
3524 log_entry = Repo.one(ModerationLog)
3526 assert ModerationLog.get_log_entry_message(log_entry) ==
3527 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3528 second_user.nickname
3533 describe "POST /reports/:id/notes" do
3534 setup %{conn: conn, admin: admin} do
3535 [reporter, target_user] = insert_pair(:user)
3536 activity = insert(:note_activity, user: target_user)
3538 {:ok, %{id: report_id}} =
3539 CommonAPI.report(reporter, %{
3540 "account_id" => target_user.id,
3541 "comment" => "I feel offended",
3542 "status_ids" => [activity.id]
3545 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3546 content: "this is disgusting!"
3549 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3550 content: "this is disgusting2!"
3555 report_id: report_id
3559 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3560 [note, _] = Repo.all(ReportNote)
3563 activity_id: ^report_id,
3564 content: "this is disgusting!",
3569 test "it returns reports with notes", %{conn: conn, admin: admin} do
3570 conn = get(conn, "/api/pleroma/admin/reports")
3572 response = json_response(conn, 200)
3573 notes = hd(response["reports"])["notes"]
3576 assert note["user"]["nickname"] == admin.nickname
3577 assert note["content"] == "this is disgusting!"
3578 assert note["created_at"]
3579 assert response["total"] == 1
3582 test "it deletes the note", %{conn: conn, report_id: report_id} do
3583 assert ReportNote |> Repo.all() |> length() == 2
3585 [note, _] = Repo.all(ReportNote)
3587 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3589 assert ReportNote |> Repo.all() |> length() == 1
3593 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3594 admin = insert(:user, is_admin: true)
3597 assign(conn, :user, admin)
3598 |> get("/api/pleroma/admin/config/descriptions")
3600 assert [child | _others] = json_response(conn, 200)
3602 assert child["children"]
3604 assert String.starts_with?(child["group"], ":")
3605 assert child["description"]
3608 describe "/api/pleroma/admin/stats" do
3609 test "status visibility count", %{conn: conn} do
3610 admin = insert(:user, is_admin: true)
3611 user = insert(:user)
3612 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3613 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3614 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3618 |> assign(:user, admin)
3619 |> get("/api/pleroma/admin/stats")
3620 |> json_response(200)
3622 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3623 response["status_visibility"]
3628 # Needed for testing
3629 defmodule Pleroma.Web.Endpoint.NotReal do
3632 defmodule Pleroma.Captcha.NotReal do