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
23 alias Pleroma.Web.ActivityPub.Relay
24 alias Pleroma.Web.CommonAPI
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)
630 test "email with +", %{conn: conn, admin: admin} do
631 recipient_email = "foo+bar@baz.com"
634 |> put_req_header("content-type", "application/json;charset=utf-8")
635 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
636 |> json_response(:no_content)
639 Pleroma.UserInviteToken
644 refute token_record.used
646 notify_email = Config.get([:instance, :notify_email])
647 instance_name = Config.get([:instance, :name])
650 Pleroma.Emails.UserEmail.user_invitation_email(
656 Swoosh.TestAssertions.assert_email_sent(
657 from: {instance_name, notify_email},
659 html_body: email.html_body
664 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
665 setup do: clear_config([:instance, :registrations_open])
666 setup do: clear_config([:instance, :invites_enabled])
668 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
669 Config.put([:instance, :registrations_open], false)
670 Config.put([:instance, :invites_enabled], false)
672 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
674 assert json_response(conn, :bad_request) ==
675 "To send invites you need to set the `invites_enabled` option to true."
678 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
679 Config.put([:instance, :registrations_open], true)
680 Config.put([:instance, :invites_enabled], true)
682 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
684 assert json_response(conn, :bad_request) ==
685 "To send invites you need to set the `registrations_open` option to false."
689 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
694 |> put_req_header("accept", "application/json")
695 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
697 resp = json_response(conn, 200)
699 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
702 describe "GET /api/pleroma/admin/users" do
703 test "renders users array for the first page", %{conn: conn, admin: admin} do
704 user = insert(:user, local: false, tags: ["foo", "bar"])
705 conn = get(conn, "/api/pleroma/admin/users?page=1")
710 "deactivated" => admin.deactivated,
712 "nickname" => admin.nickname,
713 "roles" => %{"admin" => true, "moderator" => false},
716 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
717 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
718 "confirmation_pending" => false
721 "deactivated" => user.deactivated,
723 "nickname" => user.nickname,
724 "roles" => %{"admin" => false, "moderator" => false},
726 "tags" => ["foo", "bar"],
727 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
728 "display_name" => HTML.strip_tags(user.name || user.nickname),
729 "confirmation_pending" => false
732 |> Enum.sort_by(& &1["nickname"])
734 assert json_response(conn, 200) == %{
741 test "pagination works correctly with service users", %{conn: conn} do
742 service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
743 service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
744 insert_list(25, :user)
746 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
748 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
749 |> json_response(200)
751 assert Enum.count(users1) == 10
752 assert service1 not in [users1]
753 assert service2 not in [users1]
755 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
757 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
758 |> json_response(200)
760 assert Enum.count(users2) == 10
761 assert service1 not in [users2]
762 assert service2 not in [users2]
764 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
766 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
767 |> json_response(200)
769 assert Enum.count(users3) == 6
770 assert service1 not in [users3]
771 assert service2 not in [users3]
774 test "renders empty array for the second page", %{conn: conn} do
777 conn = get(conn, "/api/pleroma/admin/users?page=2")
779 assert json_response(conn, 200) == %{
786 test "regular search", %{conn: conn} do
787 user = insert(:user, nickname: "bob")
789 conn = get(conn, "/api/pleroma/admin/users?query=bo")
791 assert json_response(conn, 200) == %{
796 "deactivated" => user.deactivated,
798 "nickname" => user.nickname,
799 "roles" => %{"admin" => false, "moderator" => false},
802 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
803 "display_name" => HTML.strip_tags(user.name || user.nickname),
804 "confirmation_pending" => false
810 test "search by domain", %{conn: conn} do
811 user = insert(:user, nickname: "nickname@domain.com")
814 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
816 assert json_response(conn, 200) == %{
821 "deactivated" => user.deactivated,
823 "nickname" => user.nickname,
824 "roles" => %{"admin" => false, "moderator" => false},
827 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
828 "display_name" => HTML.strip_tags(user.name || user.nickname),
829 "confirmation_pending" => false
835 test "search by full nickname", %{conn: conn} do
836 user = insert(:user, nickname: "nickname@domain.com")
839 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
841 assert json_response(conn, 200) == %{
846 "deactivated" => user.deactivated,
848 "nickname" => user.nickname,
849 "roles" => %{"admin" => false, "moderator" => false},
852 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
853 "display_name" => HTML.strip_tags(user.name || user.nickname),
854 "confirmation_pending" => false
860 test "search by display name", %{conn: conn} do
861 user = insert(:user, name: "Display name")
864 conn = get(conn, "/api/pleroma/admin/users?name=display")
866 assert json_response(conn, 200) == %{
871 "deactivated" => user.deactivated,
873 "nickname" => user.nickname,
874 "roles" => %{"admin" => false, "moderator" => false},
877 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
878 "display_name" => HTML.strip_tags(user.name || user.nickname),
879 "confirmation_pending" => false
885 test "search by email", %{conn: conn} do
886 user = insert(:user, email: "email@example.com")
889 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
891 assert json_response(conn, 200) == %{
896 "deactivated" => user.deactivated,
898 "nickname" => user.nickname,
899 "roles" => %{"admin" => false, "moderator" => false},
902 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
903 "display_name" => HTML.strip_tags(user.name || user.nickname),
904 "confirmation_pending" => false
910 test "regular search with page size", %{conn: conn} do
911 user = insert(:user, nickname: "aalice")
912 user2 = insert(:user, nickname: "alice")
914 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
916 assert json_response(conn1, 200) == %{
921 "deactivated" => user.deactivated,
923 "nickname" => user.nickname,
924 "roles" => %{"admin" => false, "moderator" => false},
927 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
928 "display_name" => HTML.strip_tags(user.name || user.nickname),
929 "confirmation_pending" => false
934 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
936 assert json_response(conn2, 200) == %{
941 "deactivated" => user2.deactivated,
943 "nickname" => user2.nickname,
944 "roles" => %{"admin" => false, "moderator" => false},
947 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
948 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
949 "confirmation_pending" => false
955 test "only local users" do
956 admin = insert(:user, is_admin: true, nickname: "john")
957 token = insert(:oauth_admin_token, user: admin)
958 user = insert(:user, nickname: "bob")
960 insert(:user, nickname: "bobb", local: false)
964 |> assign(:user, admin)
965 |> assign(:token, token)
966 |> get("/api/pleroma/admin/users?query=bo&filters=local")
968 assert json_response(conn, 200) == %{
973 "deactivated" => user.deactivated,
975 "nickname" => user.nickname,
976 "roles" => %{"admin" => false, "moderator" => false},
979 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
980 "display_name" => HTML.strip_tags(user.name || user.nickname),
981 "confirmation_pending" => false
987 test "only local users with no query", %{conn: conn, admin: old_admin} do
988 admin = insert(:user, is_admin: true, nickname: "john")
989 user = insert(:user, nickname: "bob")
991 insert(:user, nickname: "bobb", local: false)
993 conn = get(conn, "/api/pleroma/admin/users?filters=local")
998 "deactivated" => user.deactivated,
1000 "nickname" => user.nickname,
1001 "roles" => %{"admin" => false, "moderator" => false},
1004 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1005 "display_name" => HTML.strip_tags(user.name || user.nickname),
1006 "confirmation_pending" => false
1009 "deactivated" => admin.deactivated,
1011 "nickname" => admin.nickname,
1012 "roles" => %{"admin" => true, "moderator" => false},
1015 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1016 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1017 "confirmation_pending" => false
1020 "deactivated" => false,
1021 "id" => old_admin.id,
1023 "nickname" => old_admin.nickname,
1024 "roles" => %{"admin" => true, "moderator" => false},
1026 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1027 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1028 "confirmation_pending" => false
1031 |> Enum.sort_by(& &1["nickname"])
1033 assert json_response(conn, 200) == %{
1040 test "load only admins", %{conn: conn, admin: admin} do
1041 second_admin = insert(:user, is_admin: true)
1045 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1050 "deactivated" => false,
1052 "nickname" => admin.nickname,
1053 "roles" => %{"admin" => true, "moderator" => false},
1054 "local" => admin.local,
1056 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1057 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1058 "confirmation_pending" => false
1061 "deactivated" => false,
1062 "id" => second_admin.id,
1063 "nickname" => second_admin.nickname,
1064 "roles" => %{"admin" => true, "moderator" => false},
1065 "local" => second_admin.local,
1067 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1068 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1069 "confirmation_pending" => false
1072 |> Enum.sort_by(& &1["nickname"])
1074 assert json_response(conn, 200) == %{
1081 test "load only moderators", %{conn: conn} do
1082 moderator = insert(:user, is_moderator: true)
1086 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1088 assert json_response(conn, 200) == %{
1093 "deactivated" => false,
1094 "id" => moderator.id,
1095 "nickname" => moderator.nickname,
1096 "roles" => %{"admin" => false, "moderator" => true},
1097 "local" => moderator.local,
1099 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1100 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1101 "confirmation_pending" => false
1107 test "load users with tags list", %{conn: conn} do
1108 user1 = insert(:user, tags: ["first"])
1109 user2 = insert(:user, tags: ["second"])
1113 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1118 "deactivated" => false,
1120 "nickname" => user1.nickname,
1121 "roles" => %{"admin" => false, "moderator" => false},
1122 "local" => user1.local,
1123 "tags" => ["first"],
1124 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1125 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1126 "confirmation_pending" => false
1129 "deactivated" => false,
1131 "nickname" => user2.nickname,
1132 "roles" => %{"admin" => false, "moderator" => false},
1133 "local" => user2.local,
1134 "tags" => ["second"],
1135 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1136 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1137 "confirmation_pending" => false
1140 |> Enum.sort_by(& &1["nickname"])
1142 assert json_response(conn, 200) == %{
1149 test "it works with multiple filters" do
1150 admin = insert(:user, nickname: "john", is_admin: true)
1151 token = insert(:oauth_admin_token, user: admin)
1152 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1154 insert(:user, nickname: "ken", local: true, deactivated: true)
1155 insert(:user, nickname: "bobb", local: false, deactivated: false)
1159 |> assign(:user, admin)
1160 |> assign(:token, token)
1161 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1163 assert json_response(conn, 200) == %{
1168 "deactivated" => user.deactivated,
1170 "nickname" => user.nickname,
1171 "roles" => %{"admin" => false, "moderator" => false},
1172 "local" => user.local,
1174 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1175 "display_name" => HTML.strip_tags(user.name || user.nickname),
1176 "confirmation_pending" => false
1182 test "it omits relay user", %{admin: admin, conn: conn} do
1183 assert %User{} = Relay.get_actor()
1185 conn = get(conn, "/api/pleroma/admin/users")
1187 assert json_response(conn, 200) == %{
1192 "deactivated" => admin.deactivated,
1194 "nickname" => admin.nickname,
1195 "roles" => %{"admin" => true, "moderator" => false},
1198 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1199 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1200 "confirmation_pending" => false
1207 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1208 user_one = insert(:user, deactivated: true)
1209 user_two = insert(:user, deactivated: true)
1214 "/api/pleroma/admin/users/activate",
1215 %{nicknames: [user_one.nickname, user_two.nickname]}
1218 response = json_response(conn, 200)
1219 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1221 log_entry = Repo.one(ModerationLog)
1223 assert ModerationLog.get_log_entry_message(log_entry) ==
1224 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1227 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1228 user_one = insert(:user, deactivated: false)
1229 user_two = insert(:user, deactivated: false)
1234 "/api/pleroma/admin/users/deactivate",
1235 %{nicknames: [user_one.nickname, user_two.nickname]}
1238 response = json_response(conn, 200)
1239 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1241 log_entry = Repo.one(ModerationLog)
1243 assert ModerationLog.get_log_entry_message(log_entry) ==
1244 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1247 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1248 user = insert(:user)
1250 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1252 assert json_response(conn, 200) ==
1254 "deactivated" => !user.deactivated,
1256 "nickname" => user.nickname,
1257 "roles" => %{"admin" => false, "moderator" => false},
1260 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1261 "display_name" => HTML.strip_tags(user.name || user.nickname),
1262 "confirmation_pending" => false
1265 log_entry = Repo.one(ModerationLog)
1267 assert ModerationLog.get_log_entry_message(log_entry) ==
1268 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1271 describe "POST /api/pleroma/admin/users/invite_token" do
1272 test "without options", %{conn: conn} do
1273 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1275 invite_json = json_response(conn, 200)
1276 invite = UserInviteToken.find_by_token!(invite_json["token"])
1278 refute invite.expires_at
1279 refute invite.max_use
1280 assert invite.invite_type == "one_time"
1283 test "with expires_at", %{conn: conn} do
1285 post(conn, "/api/pleroma/admin/users/invite_token", %{
1286 "expires_at" => Date.to_string(Date.utc_today())
1289 invite_json = json_response(conn, 200)
1290 invite = UserInviteToken.find_by_token!(invite_json["token"])
1293 assert invite.expires_at == Date.utc_today()
1294 refute invite.max_use
1295 assert invite.invite_type == "date_limited"
1298 test "with max_use", %{conn: conn} do
1299 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1301 invite_json = json_response(conn, 200)
1302 invite = UserInviteToken.find_by_token!(invite_json["token"])
1304 refute invite.expires_at
1305 assert invite.max_use == 150
1306 assert invite.invite_type == "reusable"
1309 test "with max use and expires_at", %{conn: conn} do
1311 post(conn, "/api/pleroma/admin/users/invite_token", %{
1313 "expires_at" => Date.to_string(Date.utc_today())
1316 invite_json = json_response(conn, 200)
1317 invite = UserInviteToken.find_by_token!(invite_json["token"])
1319 assert invite.expires_at == Date.utc_today()
1320 assert invite.max_use == 150
1321 assert invite.invite_type == "reusable_date_limited"
1325 describe "GET /api/pleroma/admin/users/invites" do
1326 test "no invites", %{conn: conn} do
1327 conn = get(conn, "/api/pleroma/admin/users/invites")
1329 assert json_response(conn, 200) == %{"invites" => []}
1332 test "with invite", %{conn: conn} do
1333 {:ok, invite} = UserInviteToken.create_invite()
1335 conn = get(conn, "/api/pleroma/admin/users/invites")
1337 assert json_response(conn, 200) == %{
1340 "expires_at" => nil,
1342 "invite_type" => "one_time",
1344 "token" => invite.token,
1353 describe "POST /api/pleroma/admin/users/revoke_invite" do
1354 test "with token", %{conn: conn} do
1355 {:ok, invite} = UserInviteToken.create_invite()
1357 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1359 assert json_response(conn, 200) == %{
1360 "expires_at" => nil,
1362 "invite_type" => "one_time",
1364 "token" => invite.token,
1370 test "with invalid token", %{conn: conn} do
1371 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1373 assert json_response(conn, :not_found) == "Not found"
1377 describe "GET /api/pleroma/admin/reports/:id" do
1378 test "returns report by its id", %{conn: conn} do
1379 [reporter, target_user] = insert_pair(:user)
1380 activity = insert(:note_activity, user: target_user)
1382 {:ok, %{id: report_id}} =
1383 CommonAPI.report(reporter, %{
1384 account_id: target_user.id,
1385 comment: "I feel offended",
1386 status_ids: [activity.id]
1391 |> get("/api/pleroma/admin/reports/#{report_id}")
1392 |> json_response(:ok)
1394 assert response["id"] == report_id
1397 test "returns 404 when report id is invalid", %{conn: conn} do
1398 conn = get(conn, "/api/pleroma/admin/reports/test")
1400 assert json_response(conn, :not_found) == "Not found"
1404 describe "PATCH /api/pleroma/admin/reports" do
1406 [reporter, target_user] = insert_pair(:user)
1407 activity = insert(:note_activity, user: target_user)
1409 {:ok, %{id: report_id}} =
1410 CommonAPI.report(reporter, %{
1411 account_id: target_user.id,
1412 comment: "I feel offended",
1413 status_ids: [activity.id]
1416 {:ok, %{id: second_report_id}} =
1417 CommonAPI.report(reporter, %{
1418 account_id: target_user.id,
1419 comment: "I feel very offended",
1420 status_ids: [activity.id]
1425 second_report_id: second_report_id
1429 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1430 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1431 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1435 |> assign(:token, read_token)
1436 |> patch("/api/pleroma/admin/reports", %{
1437 "reports" => [%{"state" => "resolved", "id" => id}]
1439 |> json_response(403)
1441 assert response == %{
1442 "error" => "Insufficient permissions: admin:write:reports."
1446 |> assign(:token, write_token)
1447 |> patch("/api/pleroma/admin/reports", %{
1448 "reports" => [%{"state" => "resolved", "id" => id}]
1450 |> json_response(:no_content)
1453 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1455 |> patch("/api/pleroma/admin/reports", %{
1457 %{"state" => "resolved", "id" => id}
1460 |> json_response(:no_content)
1462 activity = Activity.get_by_id(id)
1463 assert activity.data["state"] == "resolved"
1465 log_entry = Repo.one(ModerationLog)
1467 assert ModerationLog.get_log_entry_message(log_entry) ==
1468 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1471 test "closes report", %{conn: conn, id: id, admin: admin} do
1473 |> patch("/api/pleroma/admin/reports", %{
1475 %{"state" => "closed", "id" => id}
1478 |> json_response(:no_content)
1480 activity = Activity.get_by_id(id)
1481 assert activity.data["state"] == "closed"
1483 log_entry = Repo.one(ModerationLog)
1485 assert ModerationLog.get_log_entry_message(log_entry) ==
1486 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1489 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1492 |> patch("/api/pleroma/admin/reports", %{
1494 %{"state" => "test", "id" => id}
1498 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1501 test "returns 404 when report is not exist", %{conn: conn} do
1504 |> patch("/api/pleroma/admin/reports", %{
1506 %{"state" => "closed", "id" => "test"}
1510 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1513 test "updates state of multiple reports", %{
1517 second_report_id: second_report_id
1520 |> patch("/api/pleroma/admin/reports", %{
1522 %{"state" => "resolved", "id" => id},
1523 %{"state" => "closed", "id" => second_report_id}
1526 |> json_response(:no_content)
1528 activity = Activity.get_by_id(id)
1529 second_activity = Activity.get_by_id(second_report_id)
1530 assert activity.data["state"] == "resolved"
1531 assert second_activity.data["state"] == "closed"
1533 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1535 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1536 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1538 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1539 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1543 describe "GET /api/pleroma/admin/reports" do
1544 test "returns empty response when no reports created", %{conn: conn} do
1547 |> get("/api/pleroma/admin/reports")
1548 |> json_response(:ok)
1550 assert Enum.empty?(response["reports"])
1551 assert response["total"] == 0
1554 test "returns reports", %{conn: conn} do
1555 [reporter, target_user] = insert_pair(:user)
1556 activity = insert(:note_activity, user: target_user)
1558 {:ok, %{id: report_id}} =
1559 CommonAPI.report(reporter, %{
1560 account_id: target_user.id,
1561 comment: "I feel offended",
1562 status_ids: [activity.id]
1567 |> get("/api/pleroma/admin/reports")
1568 |> json_response(:ok)
1570 [report] = response["reports"]
1572 assert length(response["reports"]) == 1
1573 assert report["id"] == report_id
1575 assert response["total"] == 1
1578 test "returns reports with specified state", %{conn: conn} do
1579 [reporter, target_user] = insert_pair(:user)
1580 activity = insert(:note_activity, user: target_user)
1582 {:ok, %{id: first_report_id}} =
1583 CommonAPI.report(reporter, %{
1584 account_id: target_user.id,
1585 comment: "I feel offended",
1586 status_ids: [activity.id]
1589 {:ok, %{id: second_report_id}} =
1590 CommonAPI.report(reporter, %{
1591 account_id: target_user.id,
1592 comment: "I don't like this user"
1595 CommonAPI.update_report_state(second_report_id, "closed")
1599 |> get("/api/pleroma/admin/reports", %{
1602 |> json_response(:ok)
1604 [open_report] = response["reports"]
1606 assert length(response["reports"]) == 1
1607 assert open_report["id"] == first_report_id
1609 assert response["total"] == 1
1613 |> get("/api/pleroma/admin/reports", %{
1616 |> json_response(:ok)
1618 [closed_report] = response["reports"]
1620 assert length(response["reports"]) == 1
1621 assert closed_report["id"] == second_report_id
1623 assert response["total"] == 1
1627 |> get("/api/pleroma/admin/reports", %{
1628 "state" => "resolved"
1630 |> json_response(:ok)
1632 assert Enum.empty?(response["reports"])
1633 assert response["total"] == 0
1636 test "returns 403 when requested by a non-admin" do
1637 user = insert(:user)
1638 token = insert(:oauth_token, user: user)
1642 |> assign(:user, user)
1643 |> assign(:token, token)
1644 |> get("/api/pleroma/admin/reports")
1646 assert json_response(conn, :forbidden) ==
1647 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1650 test "returns 403 when requested by anonymous" do
1651 conn = get(build_conn(), "/api/pleroma/admin/reports")
1653 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1657 describe "GET /api/pleroma/admin/statuses/:id" do
1658 test "not found", %{conn: conn} do
1660 |> get("/api/pleroma/admin/statuses/not_found")
1661 |> json_response(:not_found)
1664 test "shows activity", %{conn: conn} do
1665 activity = insert(:note_activity)
1669 |> get("/api/pleroma/admin/statuses/#{activity.id}")
1670 |> json_response(200)
1672 assert response["id"] == activity.id
1676 describe "PUT /api/pleroma/admin/statuses/:id" do
1678 activity = insert(:note_activity)
1683 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1686 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1687 |> json_response(:ok)
1689 assert response["sensitive"]
1691 log_entry = Repo.one(ModerationLog)
1693 assert ModerationLog.get_log_entry_message(log_entry) ==
1694 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1698 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1699 |> json_response(:ok)
1701 refute response["sensitive"]
1704 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1707 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1708 |> json_response(:ok)
1710 assert response["visibility"] == "public"
1712 log_entry = Repo.one(ModerationLog)
1714 assert ModerationLog.get_log_entry_message(log_entry) ==
1715 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1719 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1720 |> json_response(:ok)
1722 assert response["visibility"] == "private"
1726 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1727 |> json_response(:ok)
1729 assert response["visibility"] == "unlisted"
1732 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1733 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1735 assert json_response(conn, :bad_request) == "Unsupported visibility"
1739 describe "DELETE /api/pleroma/admin/statuses/:id" do
1741 activity = insert(:note_activity)
1746 test "deletes status", %{conn: conn, id: id, admin: admin} do
1748 |> delete("/api/pleroma/admin/statuses/#{id}")
1749 |> json_response(:ok)
1751 refute Activity.get_by_id(id)
1753 log_entry = Repo.one(ModerationLog)
1755 assert ModerationLog.get_log_entry_message(log_entry) ==
1756 "@#{admin.nickname} deleted status ##{id}"
1759 test "returns 404 when the status does not exist", %{conn: conn} do
1760 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1762 assert json_response(conn, :not_found) == "Not found"
1766 describe "GET /api/pleroma/admin/config" do
1767 setup do: clear_config(:configurable_from_database, true)
1769 test "when configuration from database is off", %{conn: conn} do
1770 Config.put(:configurable_from_database, false)
1771 conn = get(conn, "/api/pleroma/admin/config")
1773 assert json_response(conn, 400) ==
1774 "To use this endpoint you need to enable configuration from database."
1777 test "with settings only in db", %{conn: conn} do
1778 config1 = insert(:config)
1779 config2 = insert(:config)
1781 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1786 "group" => ":pleroma",
1791 "group" => ":pleroma",
1796 } = json_response(conn, 200)
1798 assert key1 == config1.key
1799 assert key2 == config2.key
1802 test "db is added to settings that are in db", %{conn: conn} do
1803 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1805 %{"configs" => configs} =
1807 |> get("/api/pleroma/admin/config")
1808 |> json_response(200)
1811 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1812 group == ":pleroma" and key == ":instance"
1815 assert instance_config["db"] == [":name"]
1818 test "merged default setting with db settings", %{conn: conn} do
1819 config1 = insert(:config)
1820 config2 = insert(:config)
1824 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1827 %{"configs" => configs} =
1829 |> get("/api/pleroma/admin/config")
1830 |> json_response(200)
1832 assert length(configs) > 3
1835 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1836 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1839 assert length(received_configs) == 3
1843 |> ConfigDB.from_binary()
1845 |> ConfigDB.convert()
1847 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1848 assert db in [[config1.key], [config2.key], db_keys]
1851 ConfigDB.from_binary_with_convert(config1.value),
1852 ConfigDB.from_binary_with_convert(config2.value),
1853 ConfigDB.from_binary_with_convert(config3.value)
1858 test "subkeys with full update right merge", %{conn: conn} do
1862 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1868 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1871 %{"configs" => configs} =
1873 |> get("/api/pleroma/admin/config")
1874 |> json_response(200)
1877 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1878 group == ":pleroma" and key in [config1.key, config2.key]
1881 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1882 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1884 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1885 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1887 assert emoji_val[:groups] == [a: 1, b: 2]
1888 assert assets_val[:mascots] == [a: 1, b: 2]
1892 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1893 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1895 assert json_response(conn, 400) ==
1896 "To use this endpoint you need to enable configuration from database."
1899 describe "POST /api/pleroma/admin/config" do
1901 http = Application.get_env(:pleroma, :http)
1904 Application.delete_env(:pleroma, :key1)
1905 Application.delete_env(:pleroma, :key2)
1906 Application.delete_env(:pleroma, :key3)
1907 Application.delete_env(:pleroma, :key4)
1908 Application.delete_env(:pleroma, :keyaa1)
1909 Application.delete_env(:pleroma, :keyaa2)
1910 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1911 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1912 Application.put_env(:pleroma, :http, http)
1913 Application.put_env(:tesla, :adapter, Tesla.Mock)
1914 Restarter.Pleroma.refresh()
1918 setup do: clear_config(:configurable_from_database, true)
1920 @tag capture_log: true
1921 test "create new config setting in db", %{conn: conn} do
1922 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1923 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1926 post(conn, "/api/pleroma/admin/config", %{
1928 %{group: ":pleroma", key: ":key1", value: "value1"},
1930 group: ":ueberauth",
1932 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1938 ":nested_1" => "nested_value1",
1940 %{":nested_22" => "nested_value222"},
1941 %{":nested_33" => %{":nested_44" => "nested_444"}}
1949 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1950 %{"nested_4" => true}
1956 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1961 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1966 assert json_response(conn, 200) == %{
1969 "group" => ":pleroma",
1971 "value" => "value1",
1975 "group" => ":ueberauth",
1976 "key" => "Ueberauth",
1977 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1978 "db" => [":consumer_secret"]
1981 "group" => ":pleroma",
1984 ":nested_1" => "nested_value1",
1986 %{":nested_22" => "nested_value222"},
1987 %{":nested_33" => %{":nested_44" => "nested_444"}}
1993 "group" => ":pleroma",
1996 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1997 %{"nested_4" => true}
2002 "group" => ":pleroma",
2004 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2010 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2016 assert Application.get_env(:pleroma, :key1) == "value1"
2018 assert Application.get_env(:pleroma, :key2) == %{
2019 nested_1: "nested_value1",
2021 %{nested_22: "nested_value222"},
2022 %{nested_33: %{nested_44: "nested_444"}}
2026 assert Application.get_env(:pleroma, :key3) == [
2027 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2028 %{"nested_4" => true}
2031 assert Application.get_env(:pleroma, :key4) == %{
2032 "endpoint" => "https://example.com",
2036 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2039 test "save configs setting without explicit key", %{conn: conn} do
2040 level = Application.get_env(:quack, :level)
2041 meta = Application.get_env(:quack, :meta)
2042 webhook_url = Application.get_env(:quack, :webhook_url)
2045 Application.put_env(:quack, :level, level)
2046 Application.put_env(:quack, :meta, meta)
2047 Application.put_env(:quack, :webhook_url, webhook_url)
2051 post(conn, "/api/pleroma/admin/config", %{
2065 key: ":webhook_url",
2066 value: "https://hooks.slack.com/services/KEY"
2071 assert json_response(conn, 200) == %{
2074 "group" => ":quack",
2080 "group" => ":quack",
2082 "value" => [":none"],
2086 "group" => ":quack",
2087 "key" => ":webhook_url",
2088 "value" => "https://hooks.slack.com/services/KEY",
2089 "db" => [":webhook_url"]
2094 assert Application.get_env(:quack, :level) == :info
2095 assert Application.get_env(:quack, :meta) == [:none]
2096 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2099 test "saving config with partial update", %{conn: conn} do
2100 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2103 post(conn, "/api/pleroma/admin/config", %{
2105 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2109 assert json_response(conn, 200) == %{
2112 "group" => ":pleroma",
2115 %{"tuple" => [":key1", 1]},
2116 %{"tuple" => [":key2", 2]},
2117 %{"tuple" => [":key3", 3]}
2119 "db" => [":key1", ":key2", ":key3"]
2125 test "saving config which need pleroma reboot", %{conn: conn} do
2126 chat = Config.get(:chat)
2127 on_exit(fn -> Config.put(:chat, chat) end)
2131 "/api/pleroma/admin/config",
2134 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2138 |> json_response(200) == %{
2141 "db" => [":enabled"],
2142 "group" => ":pleroma",
2144 "value" => [%{"tuple" => [":enabled", true]}]
2147 "need_reboot" => true
2152 |> get("/api/pleroma/admin/config")
2153 |> json_response(200)
2155 assert configs["need_reboot"]
2158 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2159 end) =~ "pleroma restarted"
2163 |> get("/api/pleroma/admin/config")
2164 |> json_response(200)
2166 assert configs["need_reboot"] == false
2169 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2170 chat = Config.get(:chat)
2171 on_exit(fn -> Config.put(:chat, chat) end)
2175 "/api/pleroma/admin/config",
2178 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2182 |> json_response(200) == %{
2185 "db" => [":enabled"],
2186 "group" => ":pleroma",
2188 "value" => [%{"tuple" => [":enabled", true]}]
2191 "need_reboot" => true
2194 assert post(conn, "/api/pleroma/admin/config", %{
2196 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2199 |> json_response(200) == %{
2202 "group" => ":pleroma",
2205 %{"tuple" => [":key3", 3]}
2210 "need_reboot" => true
2214 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2215 end) =~ "pleroma restarted"
2219 |> get("/api/pleroma/admin/config")
2220 |> json_response(200)
2222 assert configs["need_reboot"] == false
2225 test "saving config with nested merge", %{conn: conn} do
2227 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2230 post(conn, "/api/pleroma/admin/config", %{
2233 group: config.group,
2236 %{"tuple" => [":key3", 3]},
2241 %{"tuple" => [":k2", 1]},
2242 %{"tuple" => [":k3", 3]}
2251 assert json_response(conn, 200) == %{
2254 "group" => ":pleroma",
2257 %{"tuple" => [":key1", 1]},
2258 %{"tuple" => [":key3", 3]},
2263 %{"tuple" => [":k1", 1]},
2264 %{"tuple" => [":k2", 1]},
2265 %{"tuple" => [":k3", 3]}
2270 "db" => [":key1", ":key3", ":key2"]
2276 test "saving special atoms", %{conn: conn} do
2278 post(conn, "/api/pleroma/admin/config", %{
2281 "group" => ":pleroma",
2287 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2295 assert json_response(conn, 200) == %{
2298 "group" => ":pleroma",
2304 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2308 "db" => [":ssl_options"]
2313 assert Application.get_env(:pleroma, :key1) == [
2314 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2318 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2319 backends = Application.get_env(:logger, :backends)
2320 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2326 value: :erlang.term_to_binary([])
2329 Pleroma.Config.TransferTask.load_and_update_env([], false)
2331 assert Application.get_env(:logger, :backends) == []
2334 post(conn, "/api/pleroma/admin/config", %{
2337 group: config.group,
2344 assert json_response(conn, 200) == %{
2347 "group" => ":logger",
2348 "key" => ":backends",
2352 "db" => [":backends"]
2357 assert Application.get_env(:logger, :backends) == [
2362 test "saving full setting if value is not keyword", %{conn: conn} do
2367 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2371 post(conn, "/api/pleroma/admin/config", %{
2373 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2377 assert json_response(conn, 200) == %{
2380 "group" => ":tesla",
2381 "key" => ":adapter",
2382 "value" => "Tesla.Adapter.Httpc",
2383 "db" => [":adapter"]
2389 test "update config setting & delete with fallback to default value", %{
2394 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2395 config1 = insert(:config, key: ":keyaa1")
2396 config2 = insert(:config, key: ":keyaa2")
2400 group: ":ueberauth",
2405 post(conn, "/api/pleroma/admin/config", %{
2407 %{group: config1.group, key: config1.key, value: "another_value"},
2408 %{group: config2.group, key: config2.key, value: "another_value"}
2412 assert json_response(conn, 200) == %{
2415 "group" => ":pleroma",
2416 "key" => config1.key,
2417 "value" => "another_value",
2421 "group" => ":pleroma",
2422 "key" => config2.key,
2423 "value" => "another_value",
2429 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2430 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2431 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2435 |> assign(:user, admin)
2436 |> assign(:token, token)
2437 |> post("/api/pleroma/admin/config", %{
2439 %{group: config2.group, key: config2.key, delete: true},
2441 group: ":ueberauth",
2448 assert json_response(conn, 200) == %{
2452 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2453 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2456 test "common config example", %{conn: conn} do
2458 post(conn, "/api/pleroma/admin/config", %{
2461 "group" => ":pleroma",
2462 "key" => "Pleroma.Captcha.NotReal",
2464 %{"tuple" => [":enabled", false]},
2465 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2466 %{"tuple" => [":seconds_valid", 60]},
2467 %{"tuple" => [":path", ""]},
2468 %{"tuple" => [":key1", nil]},
2469 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2470 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2471 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2472 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2473 %{"tuple" => [":name", "Pleroma"]}
2479 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2481 assert json_response(conn, 200) == %{
2484 "group" => ":pleroma",
2485 "key" => "Pleroma.Captcha.NotReal",
2487 %{"tuple" => [":enabled", false]},
2488 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2489 %{"tuple" => [":seconds_valid", 60]},
2490 %{"tuple" => [":path", ""]},
2491 %{"tuple" => [":key1", nil]},
2492 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2493 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2494 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2495 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2496 %{"tuple" => [":name", "Pleroma"]}
2515 test "tuples with more than two values", %{conn: conn} do
2517 post(conn, "/api/pleroma/admin/config", %{
2520 "group" => ":pleroma",
2521 "key" => "Pleroma.Web.Endpoint.NotReal",
2537 "/api/v1/streaming",
2538 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2545 "Phoenix.Endpoint.CowboyWebSocket",
2548 "Phoenix.Transports.WebSocket",
2551 "Pleroma.Web.Endpoint",
2552 "Pleroma.Web.UserSocket",
2563 "Phoenix.Endpoint.Cowboy2Handler",
2564 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2581 assert json_response(conn, 200) == %{
2584 "group" => ":pleroma",
2585 "key" => "Pleroma.Web.Endpoint.NotReal",
2601 "/api/v1/streaming",
2602 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2609 "Phoenix.Endpoint.CowboyWebSocket",
2612 "Phoenix.Transports.WebSocket",
2615 "Pleroma.Web.Endpoint",
2616 "Pleroma.Web.UserSocket",
2627 "Phoenix.Endpoint.Cowboy2Handler",
2628 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2647 test "settings with nesting map", %{conn: conn} do
2649 post(conn, "/api/pleroma/admin/config", %{
2652 "group" => ":pleroma",
2655 %{"tuple" => [":key2", "some_val"]},
2660 ":max_options" => 20,
2661 ":max_option_chars" => 200,
2662 ":min_expiration" => 0,
2663 ":max_expiration" => 31_536_000,
2665 ":max_options" => 20,
2666 ":max_option_chars" => 200,
2667 ":min_expiration" => 0,
2668 ":max_expiration" => 31_536_000
2678 assert json_response(conn, 200) ==
2682 "group" => ":pleroma",
2685 %{"tuple" => [":key2", "some_val"]},
2690 ":max_expiration" => 31_536_000,
2691 ":max_option_chars" => 200,
2692 ":max_options" => 20,
2693 ":min_expiration" => 0,
2695 ":max_expiration" => 31_536_000,
2696 ":max_option_chars" => 200,
2697 ":max_options" => 20,
2698 ":min_expiration" => 0
2704 "db" => [":key2", ":key3"]
2710 test "value as map", %{conn: conn} do
2712 post(conn, "/api/pleroma/admin/config", %{
2715 "group" => ":pleroma",
2717 "value" => %{"key" => "some_val"}
2722 assert json_response(conn, 200) ==
2726 "group" => ":pleroma",
2728 "value" => %{"key" => "some_val"},
2735 test "queues key as atom", %{conn: conn} do
2737 post(conn, "/api/pleroma/admin/config", %{
2743 %{"tuple" => [":federator_incoming", 50]},
2744 %{"tuple" => [":federator_outgoing", 50]},
2745 %{"tuple" => [":web_push", 50]},
2746 %{"tuple" => [":mailer", 10]},
2747 %{"tuple" => [":transmogrifier", 20]},
2748 %{"tuple" => [":scheduled_activities", 10]},
2749 %{"tuple" => [":background", 5]}
2755 assert json_response(conn, 200) == %{
2761 %{"tuple" => [":federator_incoming", 50]},
2762 %{"tuple" => [":federator_outgoing", 50]},
2763 %{"tuple" => [":web_push", 50]},
2764 %{"tuple" => [":mailer", 10]},
2765 %{"tuple" => [":transmogrifier", 20]},
2766 %{"tuple" => [":scheduled_activities", 10]},
2767 %{"tuple" => [":background", 5]}
2770 ":federator_incoming",
2771 ":federator_outgoing",
2775 ":scheduled_activities",
2783 test "delete part of settings by atom subkeys", %{conn: conn} do
2787 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2791 post(conn, "/api/pleroma/admin/config", %{
2794 group: config.group,
2796 subkeys: [":subkey1", ":subkey3"],
2802 assert json_response(conn, 200) == %{
2805 "group" => ":pleroma",
2807 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2808 "db" => [":subkey2"]
2814 test "proxy tuple localhost", %{conn: conn} do
2816 post(conn, "/api/pleroma/admin/config", %{
2822 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2823 %{"tuple" => [":send_user_agent", false]}
2829 assert json_response(conn, 200) == %{
2832 "group" => ":pleroma",
2835 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2836 %{"tuple" => [":send_user_agent", false]}
2838 "db" => [":proxy_url", ":send_user_agent"]
2844 test "proxy tuple domain", %{conn: conn} do
2846 post(conn, "/api/pleroma/admin/config", %{
2852 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2853 %{"tuple" => [":send_user_agent", false]}
2859 assert json_response(conn, 200) == %{
2862 "group" => ":pleroma",
2865 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2866 %{"tuple" => [":send_user_agent", false]}
2868 "db" => [":proxy_url", ":send_user_agent"]
2874 test "proxy tuple ip", %{conn: conn} do
2876 post(conn, "/api/pleroma/admin/config", %{
2882 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2883 %{"tuple" => [":send_user_agent", false]}
2889 assert json_response(conn, 200) == %{
2892 "group" => ":pleroma",
2895 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2896 %{"tuple" => [":send_user_agent", false]}
2898 "db" => [":proxy_url", ":send_user_agent"]
2905 describe "GET /api/pleroma/admin/restart" do
2906 setup do: clear_config(:configurable_from_database, true)
2908 test "pleroma restarts", %{conn: conn} do
2910 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2911 end) =~ "pleroma restarted"
2913 refute Restarter.Pleroma.need_reboot?()
2917 test "need_reboot flag", %{conn: conn} do
2919 |> get("/api/pleroma/admin/need_reboot")
2920 |> json_response(200) == %{"need_reboot" => false}
2922 Restarter.Pleroma.need_reboot()
2925 |> get("/api/pleroma/admin/need_reboot")
2926 |> json_response(200) == %{"need_reboot" => true}
2928 on_exit(fn -> Restarter.Pleroma.refresh() end)
2931 describe "GET /api/pleroma/admin/statuses" do
2932 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2933 blocked = insert(:user)
2934 user = insert(:user)
2935 User.block(admin, blocked)
2938 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2940 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2941 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2942 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2943 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2947 |> get("/api/pleroma/admin/statuses")
2948 |> json_response(200)
2950 refute "private" in Enum.map(response, & &1["visibility"])
2951 assert length(response) == 3
2954 test "returns only local statuses with local_only on", %{conn: conn} do
2955 user = insert(:user)
2956 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2957 insert(:note_activity, user: user, local: true)
2958 insert(:note_activity, user: remote_user, local: false)
2962 |> get("/api/pleroma/admin/statuses?local_only=true")
2963 |> json_response(200)
2965 assert length(response) == 1
2968 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2969 user = insert(:user)
2972 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2974 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2975 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2976 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2977 assert json_response(conn, 200) |> length() == 3
2981 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2983 user = insert(:user)
2985 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2986 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2987 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2989 insert(:note_activity, user: user, published: date1)
2990 insert(:note_activity, user: user, published: date2)
2991 insert(:note_activity, user: user, published: date3)
2996 test "renders user's statuses", %{conn: conn, user: user} do
2997 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2999 assert json_response(conn, 200) |> length() == 3
3002 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3003 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3005 assert json_response(conn, 200) |> length() == 2
3008 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3009 {:ok, _private_status} =
3010 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3012 {:ok, _public_status} =
3013 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3015 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3017 assert json_response(conn, 200) |> length() == 4
3020 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3021 {:ok, _private_status} =
3022 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3024 {:ok, _public_status} =
3025 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3027 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3029 assert json_response(conn, 200) |> length() == 5
3032 test "excludes reblogs by default", %{conn: conn, user: user} do
3033 other_user = insert(:user)
3034 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3035 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3037 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3038 assert json_response(conn_res, 200) |> length() == 0
3041 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3043 assert json_response(conn_res, 200) |> length() == 1
3047 describe "GET /api/pleroma/admin/moderation_log" do
3049 moderator = insert(:user, is_moderator: true)
3051 %{moderator: moderator}
3054 test "returns the log", %{conn: conn, admin: admin} do
3055 Repo.insert(%ModerationLog{
3059 "nickname" => admin.nickname,
3062 action: "relay_follow",
3063 target: "https://example.org/relay"
3065 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3068 Repo.insert(%ModerationLog{
3072 "nickname" => admin.nickname,
3075 action: "relay_unfollow",
3076 target: "https://example.org/relay"
3078 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3081 conn = get(conn, "/api/pleroma/admin/moderation_log")
3083 response = json_response(conn, 200)
3084 [first_entry, second_entry] = response["items"]
3086 assert response["total"] == 2
3087 assert first_entry["data"]["action"] == "relay_unfollow"
3089 assert first_entry["message"] ==
3090 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3092 assert second_entry["data"]["action"] == "relay_follow"
3094 assert second_entry["message"] ==
3095 "@#{admin.nickname} followed relay: https://example.org/relay"
3098 test "returns the log with pagination", %{conn: conn, admin: admin} do
3099 Repo.insert(%ModerationLog{
3103 "nickname" => admin.nickname,
3106 action: "relay_follow",
3107 target: "https://example.org/relay"
3109 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3112 Repo.insert(%ModerationLog{
3116 "nickname" => admin.nickname,
3119 action: "relay_unfollow",
3120 target: "https://example.org/relay"
3122 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3125 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3127 response1 = json_response(conn1, 200)
3128 [first_entry] = response1["items"]
3130 assert response1["total"] == 2
3131 assert response1["items"] |> length() == 1
3132 assert first_entry["data"]["action"] == "relay_unfollow"
3134 assert first_entry["message"] ==
3135 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3137 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3139 response2 = json_response(conn2, 200)
3140 [second_entry] = response2["items"]
3142 assert response2["total"] == 2
3143 assert response2["items"] |> length() == 1
3144 assert second_entry["data"]["action"] == "relay_follow"
3146 assert second_entry["message"] ==
3147 "@#{admin.nickname} followed relay: https://example.org/relay"
3150 test "filters log by date", %{conn: conn, admin: admin} do
3151 first_date = "2017-08-15T15:47:06Z"
3152 second_date = "2017-08-20T15:47:06Z"
3154 Repo.insert(%ModerationLog{
3158 "nickname" => admin.nickname,
3161 action: "relay_follow",
3162 target: "https://example.org/relay"
3164 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3167 Repo.insert(%ModerationLog{
3171 "nickname" => admin.nickname,
3174 action: "relay_unfollow",
3175 target: "https://example.org/relay"
3177 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3183 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3186 response1 = json_response(conn1, 200)
3187 [first_entry] = response1["items"]
3189 assert response1["total"] == 1
3190 assert first_entry["data"]["action"] == "relay_unfollow"
3192 assert first_entry["message"] ==
3193 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3196 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3197 Repo.insert(%ModerationLog{
3201 "nickname" => admin.nickname,
3204 action: "relay_follow",
3205 target: "https://example.org/relay"
3209 Repo.insert(%ModerationLog{
3212 "id" => moderator.id,
3213 "nickname" => moderator.nickname,
3216 action: "relay_unfollow",
3217 target: "https://example.org/relay"
3221 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3223 response1 = json_response(conn1, 200)
3224 [first_entry] = response1["items"]
3226 assert response1["total"] == 1
3227 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3230 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3231 ModerationLog.insert_log(%{
3233 action: "relay_follow",
3234 target: "https://example.org/relay"
3237 ModerationLog.insert_log(%{
3239 action: "relay_unfollow",
3240 target: "https://example.org/relay"
3243 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3245 response1 = json_response(conn1, 200)
3246 [first_entry] = response1["items"]
3248 assert response1["total"] == 1
3250 assert get_in(first_entry, ["data", "message"]) ==
3251 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3255 describe "GET /users/:nickname/credentials" do
3256 test "gets the user credentials", %{conn: conn} do
3257 user = insert(:user)
3258 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3260 response = assert json_response(conn, 200)
3261 assert response["email"] == user.email
3264 test "returns 403 if requested by a non-admin" do
3265 user = insert(:user)
3269 |> assign(:user, user)
3270 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3272 assert json_response(conn, :forbidden)
3276 describe "PATCH /users/:nickname/credentials" do
3277 test "changes password and email", %{conn: conn, admin: admin} do
3278 user = insert(:user)
3279 assert user.password_reset_pending == false
3282 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3283 "password" => "new_password",
3284 "email" => "new_email@example.com",
3285 "name" => "new_name"
3288 assert json_response(conn, 200) == %{"status" => "success"}
3290 ObanHelpers.perform_all()
3292 updated_user = User.get_by_id(user.id)
3294 assert updated_user.email == "new_email@example.com"
3295 assert updated_user.name == "new_name"
3296 assert updated_user.password_hash != user.password_hash
3297 assert updated_user.password_reset_pending == true
3299 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3301 assert ModerationLog.get_log_entry_message(log_entry1) ==
3302 "@#{admin.nickname} updated users: @#{user.nickname}"
3304 assert ModerationLog.get_log_entry_message(log_entry2) ==
3305 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3308 test "returns 403 if requested by a non-admin" do
3309 user = insert(:user)
3313 |> assign(:user, user)
3314 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3315 "password" => "new_password",
3316 "email" => "new_email@example.com",
3317 "name" => "new_name"
3320 assert json_response(conn, :forbidden)
3324 describe "PATCH /users/:nickname/force_password_reset" do
3325 test "sets password_reset_pending to true", %{conn: conn} do
3326 user = insert(:user)
3327 assert user.password_reset_pending == false
3330 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3332 assert json_response(conn, 204) == ""
3334 ObanHelpers.perform_all()
3336 assert User.get_by_id(user.id).password_reset_pending == true
3340 describe "relays" do
3341 test "POST /relay", %{conn: conn, admin: admin} do
3343 post(conn, "/api/pleroma/admin/relay", %{
3344 relay_url: "http://mastodon.example.org/users/admin"
3347 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3349 log_entry = Repo.one(ModerationLog)
3351 assert ModerationLog.get_log_entry_message(log_entry) ==
3352 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3355 test "GET /relay", %{conn: conn} do
3356 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3358 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3359 |> Enum.each(fn ap_id ->
3360 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3361 User.follow(relay_user, user)
3364 conn = get(conn, "/api/pleroma/admin/relay")
3366 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3369 test "DELETE /relay", %{conn: conn, admin: admin} do
3370 post(conn, "/api/pleroma/admin/relay", %{
3371 relay_url: "http://mastodon.example.org/users/admin"
3375 delete(conn, "/api/pleroma/admin/relay", %{
3376 relay_url: "http://mastodon.example.org/users/admin"
3379 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3381 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3383 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3384 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3386 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3387 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3391 describe "instances" do
3392 test "GET /instances/:instance/statuses", %{conn: conn} do
3393 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3394 user2 = insert(:user, local: false, nickname: "test@test.com")
3395 insert_pair(:note_activity, user: user)
3396 activity = insert(:note_activity, user: user2)
3398 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3400 response = json_response(ret_conn, 200)
3402 assert length(response) == 2
3404 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3406 response = json_response(ret_conn, 200)
3408 assert length(response) == 1
3410 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3412 response = json_response(ret_conn, 200)
3414 assert Enum.empty?(response)
3416 CommonAPI.repeat(activity.id, user)
3418 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3419 response = json_response(ret_conn, 200)
3420 assert length(response) == 2
3422 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3423 response = json_response(ret_conn, 200)
3424 assert length(response) == 3
3428 describe "PATCH /confirm_email" do
3429 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3430 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3432 assert first_user.confirmation_pending == true
3433 assert second_user.confirmation_pending == true
3436 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3438 first_user.nickname,
3439 second_user.nickname
3443 assert ret_conn.status == 200
3445 assert first_user.confirmation_pending == true
3446 assert second_user.confirmation_pending == true
3448 log_entry = Repo.one(ModerationLog)
3450 assert ModerationLog.get_log_entry_message(log_entry) ==
3451 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3452 second_user.nickname
3457 describe "PATCH /resend_confirmation_email" do
3458 test "it resend emails for two users", %{conn: conn, admin: admin} do
3459 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3462 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3464 first_user.nickname,
3465 second_user.nickname
3469 assert ret_conn.status == 200
3471 log_entry = Repo.one(ModerationLog)
3473 assert ModerationLog.get_log_entry_message(log_entry) ==
3474 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3475 second_user.nickname
3480 describe "POST /reports/:id/notes" do
3481 setup %{conn: conn, admin: admin} do
3482 [reporter, target_user] = insert_pair(:user)
3483 activity = insert(:note_activity, user: target_user)
3485 {:ok, %{id: report_id}} =
3486 CommonAPI.report(reporter, %{
3487 account_id: target_user.id,
3488 comment: "I feel offended",
3489 status_ids: [activity.id]
3492 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3493 content: "this is disgusting!"
3496 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3497 content: "this is disgusting2!"
3502 report_id: report_id
3506 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3507 [note, _] = Repo.all(ReportNote)
3510 activity_id: ^report_id,
3511 content: "this is disgusting!",
3516 test "it returns reports with notes", %{conn: conn, admin: admin} do
3517 conn = get(conn, "/api/pleroma/admin/reports")
3519 response = json_response(conn, 200)
3520 notes = hd(response["reports"])["notes"]
3523 assert note["user"]["nickname"] == admin.nickname
3524 assert note["content"] == "this is disgusting!"
3525 assert note["created_at"]
3526 assert response["total"] == 1
3529 test "it deletes the note", %{conn: conn, report_id: report_id} do
3530 assert ReportNote |> Repo.all() |> length() == 2
3532 [note, _] = Repo.all(ReportNote)
3534 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3536 assert ReportNote |> Repo.all() |> length() == 1
3540 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3541 admin = insert(:user, is_admin: true)
3544 assign(conn, :user, admin)
3545 |> get("/api/pleroma/admin/config/descriptions")
3547 assert [child | _others] = json_response(conn, 200)
3549 assert child["children"]
3551 assert String.starts_with?(child["group"], ":")
3552 assert child["description"]
3555 describe "/api/pleroma/admin/stats" do
3556 test "status visibility count", %{conn: conn} do
3557 admin = insert(:user, is_admin: true)
3558 user = insert(:user)
3559 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3560 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3561 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3565 |> assign(:user, admin)
3566 |> get("/api/pleroma/admin/stats")
3567 |> json_response(200)
3569 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3570 response["status_visibility"]
3574 describe "POST /api/pleroma/admin/oauth_app" do
3575 test "errors", %{conn: conn} do
3576 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3578 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3581 test "success", %{conn: conn} do
3582 base_url = Web.base_url()
3583 app_name = "Trusted app"
3587 |> post("/api/pleroma/admin/oauth_app", %{
3589 redirect_uris: base_url
3591 |> json_response(200)
3595 "client_secret" => _,
3596 "name" => ^app_name,
3597 "redirect_uri" => ^base_url,
3602 test "with trusted", %{conn: conn} do
3603 base_url = Web.base_url()
3604 app_name = "Trusted app"
3608 |> post("/api/pleroma/admin/oauth_app", %{
3610 redirect_uris: base_url,
3613 |> json_response(200)
3617 "client_secret" => _,
3618 "name" => ^app_name,
3619 "redirect_uri" => ^base_url,
3625 describe "GET /api/pleroma/admin/oauth_app" do
3627 app = insert(:oauth_app)
3631 test "list", %{conn: conn} do
3634 |> get("/api/pleroma/admin/oauth_app")
3635 |> json_response(200)
3637 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3639 assert length(apps) == count
3642 test "with page size", %{conn: conn} do
3648 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3649 |> json_response(200)
3651 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3653 assert length(apps) == page_size
3656 test "search by client name", %{conn: conn, app: app} do
3659 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3660 |> json_response(200)
3662 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3664 assert returned["client_id"] == app.client_id
3665 assert returned["name"] == app.client_name
3668 test "search by client id", %{conn: conn, app: app} do
3671 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3672 |> json_response(200)
3674 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3676 assert returned["client_id"] == app.client_id
3677 assert returned["name"] == app.client_name
3680 test "only trusted", %{conn: conn} do
3681 app = insert(:oauth_app, trusted: true)
3685 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3686 |> json_response(200)
3688 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3690 assert returned["client_id"] == app.client_id
3691 assert returned["name"] == app.client_name
3695 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3696 test "with id", %{conn: conn} do
3697 app = insert(:oauth_app)
3701 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3702 |> json_response(:no_content)
3704 assert response == ""
3707 test "with non existance id", %{conn: conn} do
3710 |> delete("/api/pleroma/admin/oauth_app/0")
3711 |> json_response(:bad_request)
3713 assert response == ""
3717 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3718 test "with id", %{conn: conn} do
3719 app = insert(:oauth_app)
3721 name = "another name"
3722 url = "https://example.com"
3725 website = "http://website.com"
3729 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3736 |> json_response(200)
3740 "client_secret" => _,
3743 "redirect_uri" => ^url,
3745 "website" => ^website
3749 test "without id", %{conn: conn} do
3752 |> patch("/api/pleroma/admin/oauth_app/0")
3753 |> json_response(:bad_request)
3755 assert response == ""
3760 # Needed for testing
3761 defmodule Pleroma.Web.Endpoint.NotReal do
3764 defmodule Pleroma.Captcha.NotReal do