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
2576 post(conn, "/api/pleroma/admin/config", %{
2579 "group" => ":pleroma",
2580 "key" => "Pleroma.Captcha.NotReal",
2582 %{"tuple" => [":enabled", false]},
2583 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2584 %{"tuple" => [":seconds_valid", 60]},
2585 %{"tuple" => [":path", ""]},
2586 %{"tuple" => [":key1", nil]},
2587 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2588 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2589 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2590 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2591 %{"tuple" => [":name", "Pleroma"]}
2597 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2599 assert json_response(conn, 200) == %{
2602 "group" => ":pleroma",
2603 "key" => "Pleroma.Captcha.NotReal",
2605 %{"tuple" => [":enabled", false]},
2606 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2607 %{"tuple" => [":seconds_valid", 60]},
2608 %{"tuple" => [":path", ""]},
2609 %{"tuple" => [":key1", nil]},
2610 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2611 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2612 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2613 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2614 %{"tuple" => [":name", "Pleroma"]}
2633 test "tuples with more than two values", %{conn: conn} do
2635 post(conn, "/api/pleroma/admin/config", %{
2638 "group" => ":pleroma",
2639 "key" => "Pleroma.Web.Endpoint.NotReal",
2655 "/api/v1/streaming",
2656 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2663 "Phoenix.Endpoint.CowboyWebSocket",
2666 "Phoenix.Transports.WebSocket",
2669 "Pleroma.Web.Endpoint",
2670 "Pleroma.Web.UserSocket",
2681 "Phoenix.Endpoint.Cowboy2Handler",
2682 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2699 assert json_response(conn, 200) == %{
2702 "group" => ":pleroma",
2703 "key" => "Pleroma.Web.Endpoint.NotReal",
2719 "/api/v1/streaming",
2720 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2727 "Phoenix.Endpoint.CowboyWebSocket",
2730 "Phoenix.Transports.WebSocket",
2733 "Pleroma.Web.Endpoint",
2734 "Pleroma.Web.UserSocket",
2745 "Phoenix.Endpoint.Cowboy2Handler",
2746 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2765 test "settings with nesting map", %{conn: conn} do
2767 post(conn, "/api/pleroma/admin/config", %{
2770 "group" => ":pleroma",
2773 %{"tuple" => [":key2", "some_val"]},
2778 ":max_options" => 20,
2779 ":max_option_chars" => 200,
2780 ":min_expiration" => 0,
2781 ":max_expiration" => 31_536_000,
2783 ":max_options" => 20,
2784 ":max_option_chars" => 200,
2785 ":min_expiration" => 0,
2786 ":max_expiration" => 31_536_000
2796 assert json_response(conn, 200) ==
2800 "group" => ":pleroma",
2803 %{"tuple" => [":key2", "some_val"]},
2808 ":max_expiration" => 31_536_000,
2809 ":max_option_chars" => 200,
2810 ":max_options" => 20,
2811 ":min_expiration" => 0,
2813 ":max_expiration" => 31_536_000,
2814 ":max_option_chars" => 200,
2815 ":max_options" => 20,
2816 ":min_expiration" => 0
2822 "db" => [":key2", ":key3"]
2828 test "value as map", %{conn: conn} do
2830 post(conn, "/api/pleroma/admin/config", %{
2833 "group" => ":pleroma",
2835 "value" => %{"key" => "some_val"}
2840 assert json_response(conn, 200) ==
2844 "group" => ":pleroma",
2846 "value" => %{"key" => "some_val"},
2853 test "queues key as atom", %{conn: conn} do
2855 post(conn, "/api/pleroma/admin/config", %{
2861 %{"tuple" => [":federator_incoming", 50]},
2862 %{"tuple" => [":federator_outgoing", 50]},
2863 %{"tuple" => [":web_push", 50]},
2864 %{"tuple" => [":mailer", 10]},
2865 %{"tuple" => [":transmogrifier", 20]},
2866 %{"tuple" => [":scheduled_activities", 10]},
2867 %{"tuple" => [":background", 5]}
2873 assert json_response(conn, 200) == %{
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]}
2888 ":federator_incoming",
2889 ":federator_outgoing",
2893 ":scheduled_activities",
2901 test "delete part of settings by atom subkeys", %{conn: conn} do
2905 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2909 post(conn, "/api/pleroma/admin/config", %{
2912 group: config.group,
2914 subkeys: [":subkey1", ":subkey3"],
2920 assert json_response(conn, 200) == %{
2923 "group" => ":pleroma",
2925 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2926 "db" => [":subkey2"]
2932 test "proxy tuple localhost", %{conn: conn} do
2934 post(conn, "/api/pleroma/admin/config", %{
2940 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2941 %{"tuple" => [":send_user_agent", false]}
2947 assert json_response(conn, 200) == %{
2950 "group" => ":pleroma",
2953 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2954 %{"tuple" => [":send_user_agent", false]}
2956 "db" => [":proxy_url", ":send_user_agent"]
2962 test "proxy tuple domain", %{conn: conn} do
2964 post(conn, "/api/pleroma/admin/config", %{
2970 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2971 %{"tuple" => [":send_user_agent", false]}
2977 assert json_response(conn, 200) == %{
2980 "group" => ":pleroma",
2983 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2984 %{"tuple" => [":send_user_agent", false]}
2986 "db" => [":proxy_url", ":send_user_agent"]
2992 test "proxy tuple ip", %{conn: conn} do
2994 post(conn, "/api/pleroma/admin/config", %{
3000 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
3001 %{"tuple" => [":send_user_agent", false]}
3007 assert json_response(conn, 200) == %{
3010 "group" => ":pleroma",
3013 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
3014 %{"tuple" => [":send_user_agent", false]}
3016 "db" => [":proxy_url", ":send_user_agent"]
3023 describe "GET /api/pleroma/admin/restart" do
3024 setup do: clear_config(:configurable_from_database, true)
3026 test "pleroma restarts", %{conn: conn} do
3028 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
3029 end) =~ "pleroma restarted"
3031 refute Restarter.Pleroma.need_reboot?()
3035 describe "GET /api/pleroma/admin/statuses" do
3036 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
3037 blocked = insert(:user)
3038 user = insert(:user)
3039 User.block(admin, blocked)
3042 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
3044 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
3045 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
3046 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
3047 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
3051 |> get("/api/pleroma/admin/statuses")
3052 |> json_response(200)
3054 refute "private" in Enum.map(response, & &1["visibility"])
3055 assert length(response) == 3
3058 test "returns only local statuses with local_only on", %{conn: conn} do
3059 user = insert(:user)
3060 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
3061 insert(:note_activity, user: user, local: true)
3062 insert(:note_activity, user: remote_user, local: false)
3066 |> get("/api/pleroma/admin/statuses?local_only=true")
3067 |> json_response(200)
3069 assert length(response) == 1
3072 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
3073 user = insert(:user)
3076 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
3078 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
3079 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
3080 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
3081 assert json_response(conn, 200) |> length() == 3
3085 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3087 user = insert(:user)
3089 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3090 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3091 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3093 insert(:note_activity, user: user, published: date1)
3094 insert(:note_activity, user: user, published: date2)
3095 insert(:note_activity, user: user, published: date3)
3100 test "renders user's statuses", %{conn: conn, user: user} do
3101 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3103 assert json_response(conn, 200) |> length() == 3
3106 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3107 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3109 assert json_response(conn, 200) |> length() == 2
3112 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3113 {:ok, _private_status} =
3114 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3116 {:ok, _public_status} =
3117 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3119 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3121 assert json_response(conn, 200) |> length() == 4
3124 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3125 {:ok, _private_status} =
3126 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3128 {:ok, _public_status} =
3129 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3131 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3133 assert json_response(conn, 200) |> length() == 5
3136 test "excludes reblogs by default", %{conn: conn, user: user} do
3137 other_user = insert(:user)
3138 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3139 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3141 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3142 assert json_response(conn_res, 200) |> length() == 0
3145 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3147 assert json_response(conn_res, 200) |> length() == 1
3151 describe "GET /api/pleroma/admin/moderation_log" do
3153 moderator = insert(:user, is_moderator: true)
3155 %{moderator: moderator}
3158 test "returns the log", %{conn: conn, admin: admin} do
3159 Repo.insert(%ModerationLog{
3163 "nickname" => admin.nickname,
3166 action: "relay_follow",
3167 target: "https://example.org/relay"
3169 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3172 Repo.insert(%ModerationLog{
3176 "nickname" => admin.nickname,
3179 action: "relay_unfollow",
3180 target: "https://example.org/relay"
3182 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3185 conn = get(conn, "/api/pleroma/admin/moderation_log")
3187 response = json_response(conn, 200)
3188 [first_entry, second_entry] = response["items"]
3190 assert response["total"] == 2
3191 assert first_entry["data"]["action"] == "relay_unfollow"
3193 assert first_entry["message"] ==
3194 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3196 assert second_entry["data"]["action"] == "relay_follow"
3198 assert second_entry["message"] ==
3199 "@#{admin.nickname} followed relay: https://example.org/relay"
3202 test "returns the log with pagination", %{conn: conn, admin: admin} do
3203 Repo.insert(%ModerationLog{
3207 "nickname" => admin.nickname,
3210 action: "relay_follow",
3211 target: "https://example.org/relay"
3213 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3216 Repo.insert(%ModerationLog{
3220 "nickname" => admin.nickname,
3223 action: "relay_unfollow",
3224 target: "https://example.org/relay"
3226 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3229 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3231 response1 = json_response(conn1, 200)
3232 [first_entry] = response1["items"]
3234 assert response1["total"] == 2
3235 assert response1["items"] |> length() == 1
3236 assert first_entry["data"]["action"] == "relay_unfollow"
3238 assert first_entry["message"] ==
3239 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3241 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3243 response2 = json_response(conn2, 200)
3244 [second_entry] = response2["items"]
3246 assert response2["total"] == 2
3247 assert response2["items"] |> length() == 1
3248 assert second_entry["data"]["action"] == "relay_follow"
3250 assert second_entry["message"] ==
3251 "@#{admin.nickname} followed relay: https://example.org/relay"
3254 test "filters log by date", %{conn: conn, admin: admin} do
3255 first_date = "2017-08-15T15:47:06Z"
3256 second_date = "2017-08-20T15:47:06Z"
3258 Repo.insert(%ModerationLog{
3262 "nickname" => admin.nickname,
3265 action: "relay_follow",
3266 target: "https://example.org/relay"
3268 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3271 Repo.insert(%ModerationLog{
3275 "nickname" => admin.nickname,
3278 action: "relay_unfollow",
3279 target: "https://example.org/relay"
3281 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3287 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3290 response1 = json_response(conn1, 200)
3291 [first_entry] = response1["items"]
3293 assert response1["total"] == 1
3294 assert first_entry["data"]["action"] == "relay_unfollow"
3296 assert first_entry["message"] ==
3297 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3300 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3301 Repo.insert(%ModerationLog{
3305 "nickname" => admin.nickname,
3308 action: "relay_follow",
3309 target: "https://example.org/relay"
3313 Repo.insert(%ModerationLog{
3316 "id" => moderator.id,
3317 "nickname" => moderator.nickname,
3320 action: "relay_unfollow",
3321 target: "https://example.org/relay"
3325 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3327 response1 = json_response(conn1, 200)
3328 [first_entry] = response1["items"]
3330 assert response1["total"] == 1
3331 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3334 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3335 ModerationLog.insert_log(%{
3337 action: "relay_follow",
3338 target: "https://example.org/relay"
3341 ModerationLog.insert_log(%{
3343 action: "relay_unfollow",
3344 target: "https://example.org/relay"
3347 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3349 response1 = json_response(conn1, 200)
3350 [first_entry] = response1["items"]
3352 assert response1["total"] == 1
3354 assert get_in(first_entry, ["data", "message"]) ==
3355 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3359 describe "PATCH /users/:nickname/force_password_reset" do
3360 test "sets password_reset_pending to true", %{conn: conn} do
3361 user = insert(:user)
3362 assert user.password_reset_pending == false
3365 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3367 assert json_response(conn, 204) == ""
3369 ObanHelpers.perform_all()
3371 assert User.get_by_id(user.id).password_reset_pending == true
3375 describe "relays" do
3376 test "POST /relay", %{conn: conn, admin: admin} do
3378 post(conn, "/api/pleroma/admin/relay", %{
3379 relay_url: "http://mastodon.example.org/users/admin"
3382 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3384 log_entry = Repo.one(ModerationLog)
3386 assert ModerationLog.get_log_entry_message(log_entry) ==
3387 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3390 test "GET /relay", %{conn: conn} do
3391 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3393 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3394 |> Enum.each(fn ap_id ->
3395 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3396 User.follow(relay_user, user)
3399 conn = get(conn, "/api/pleroma/admin/relay")
3401 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3404 test "DELETE /relay", %{conn: conn, admin: admin} do
3405 post(conn, "/api/pleroma/admin/relay", %{
3406 relay_url: "http://mastodon.example.org/users/admin"
3410 delete(conn, "/api/pleroma/admin/relay", %{
3411 relay_url: "http://mastodon.example.org/users/admin"
3414 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3416 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3418 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3419 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3421 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3422 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3426 describe "instances" do
3427 test "GET /instances/:instance/statuses", %{conn: conn} do
3428 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3429 user2 = insert(:user, local: false, nickname: "test@test.com")
3430 insert_pair(:note_activity, user: user)
3431 activity = insert(:note_activity, user: user2)
3433 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3435 response = json_response(ret_conn, 200)
3437 assert length(response) == 2
3439 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3441 response = json_response(ret_conn, 200)
3443 assert length(response) == 1
3445 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3447 response = json_response(ret_conn, 200)
3449 assert Enum.empty?(response)
3451 CommonAPI.repeat(activity.id, user)
3453 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3454 response = json_response(ret_conn, 200)
3455 assert length(response) == 2
3457 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3458 response = json_response(ret_conn, 200)
3459 assert length(response) == 3
3463 describe "PATCH /confirm_email" do
3464 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3465 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3467 assert first_user.confirmation_pending == true
3468 assert second_user.confirmation_pending == true
3471 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3473 first_user.nickname,
3474 second_user.nickname
3478 assert ret_conn.status == 200
3480 assert first_user.confirmation_pending == true
3481 assert second_user.confirmation_pending == true
3483 log_entry = Repo.one(ModerationLog)
3485 assert ModerationLog.get_log_entry_message(log_entry) ==
3486 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3487 second_user.nickname
3492 describe "PATCH /resend_confirmation_email" do
3493 test "it resend emails for two users", %{conn: conn, admin: admin} do
3494 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3497 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3499 first_user.nickname,
3500 second_user.nickname
3504 assert ret_conn.status == 200
3506 log_entry = Repo.one(ModerationLog)
3508 assert ModerationLog.get_log_entry_message(log_entry) ==
3509 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3510 second_user.nickname
3515 describe "POST /reports/:id/notes" do
3516 setup %{conn: conn, admin: admin} do
3517 [reporter, target_user] = insert_pair(:user)
3518 activity = insert(:note_activity, user: target_user)
3520 {:ok, %{id: report_id}} =
3521 CommonAPI.report(reporter, %{
3522 "account_id" => target_user.id,
3523 "comment" => "I feel offended",
3524 "status_ids" => [activity.id]
3527 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3528 content: "this is disgusting!"
3531 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3532 content: "this is disgusting2!"
3537 report_id: report_id
3541 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3542 [note, _] = Repo.all(ReportNote)
3545 activity_id: ^report_id,
3546 content: "this is disgusting!",
3551 test "it returns reports with notes", %{conn: conn, admin: admin} do
3552 conn = get(conn, "/api/pleroma/admin/reports")
3554 response = json_response(conn, 200)
3555 notes = hd(response["reports"])["notes"]
3558 assert note["user"]["nickname"] == admin.nickname
3559 assert note["content"] == "this is disgusting!"
3560 assert note["created_at"]
3561 assert response["total"] == 1
3564 test "it deletes the note", %{conn: conn, report_id: report_id} do
3565 assert ReportNote |> Repo.all() |> length() == 2
3567 [note, _] = Repo.all(ReportNote)
3569 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3571 assert ReportNote |> Repo.all() |> length() == 1
3575 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3576 admin = insert(:user, is_admin: true)
3579 assign(conn, :user, admin)
3580 |> get("/api/pleroma/admin/config/descriptions")
3582 assert [child | _others] = json_response(conn, 200)
3584 assert child["children"]
3586 assert String.starts_with?(child["group"], ":")
3587 assert child["description"]
3590 describe "/api/pleroma/admin/stats" do
3591 test "status visibility count", %{conn: conn} do
3592 admin = insert(:user, is_admin: true)
3593 user = insert(:user)
3594 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3595 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3596 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3600 |> assign(:user, admin)
3601 |> get("/api/pleroma/admin/stats")
3602 |> json_response(200)
3604 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3605 response["status_visibility"]
3610 # Needed for testing
3611 defmodule Pleroma.Web.Endpoint.NotReal do
3614 defmodule Pleroma.Captcha.NotReal do