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.MediaProxy
27 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
33 admin = insert(:user, is_admin: true)
34 token = insert(:oauth_admin_token, user: admin)
38 |> assign(:user, admin)
39 |> assign(:token, token)
41 {:ok, %{admin: admin, token: token, conn: conn}}
44 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
45 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
47 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
50 url = "/api/pleroma/admin/users/#{user.nickname}"
52 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
53 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
54 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
56 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
57 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
60 for good_token <- [good_token1, good_token2, good_token3] do
63 |> assign(:user, admin)
64 |> assign(:token, good_token)
67 assert json_response(conn, 200)
70 for good_token <- [good_token1, good_token2, good_token3] do
74 |> assign(:token, good_token)
77 assert json_response(conn, :forbidden)
80 for bad_token <- [bad_token1, bad_token2, bad_token3] do
83 |> assign(:user, admin)
84 |> assign(:token, bad_token)
87 assert json_response(conn, :forbidden)
92 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
93 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
95 test "GET /api/pleroma/admin/users/:nickname requires " <>
96 "read:accounts or admin:read:accounts or broader scope",
99 url = "/api/pleroma/admin/users/#{user.nickname}"
101 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
102 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
103 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
104 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
105 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
107 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
109 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
110 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
113 for good_token <- good_tokens do
116 |> assign(:user, admin)
117 |> assign(:token, good_token)
120 assert json_response(conn, 200)
123 for good_token <- good_tokens do
126 |> assign(:user, nil)
127 |> assign(:token, good_token)
130 assert json_response(conn, :forbidden)
133 for bad_token <- [bad_token1, bad_token2, bad_token3] do
136 |> assign(:user, admin)
137 |> assign(:token, bad_token)
140 assert json_response(conn, :forbidden)
145 describe "DELETE /api/pleroma/admin/users" do
146 test "single user", %{admin: admin, conn: conn} do
151 |> put_req_header("accept", "application/json")
152 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
154 log_entry = Repo.one(ModerationLog)
156 assert ModerationLog.get_log_entry_message(log_entry) ==
157 "@#{admin.nickname} deleted users: @#{user.nickname}"
159 assert json_response(conn, 200) == user.nickname
162 test "multiple users", %{admin: admin, conn: conn} do
163 user_one = insert(:user)
164 user_two = insert(:user)
168 |> put_req_header("accept", "application/json")
169 |> delete("/api/pleroma/admin/users", %{
170 nicknames: [user_one.nickname, user_two.nickname]
173 log_entry = Repo.one(ModerationLog)
175 assert ModerationLog.get_log_entry_message(log_entry) ==
176 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
178 response = json_response(conn, 200)
179 assert response -- [user_one.nickname, user_two.nickname] == []
183 describe "/api/pleroma/admin/users" do
184 test "Create", %{conn: conn} do
187 |> put_req_header("accept", "application/json")
188 |> post("/api/pleroma/admin/users", %{
191 "nickname" => "lain",
192 "email" => "lain@example.org",
196 "nickname" => "lain2",
197 "email" => "lain2@example.org",
203 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
204 assert response == ["success", "success"]
206 log_entry = Repo.one(ModerationLog)
208 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
211 test "Cannot create user with existing email", %{conn: conn} do
216 |> put_req_header("accept", "application/json")
217 |> post("/api/pleroma/admin/users", %{
220 "nickname" => "lain",
221 "email" => user.email,
227 assert json_response(conn, 409) == [
231 "email" => user.email,
234 "error" => "email has already been taken",
240 test "Cannot create user with existing nickname", %{conn: conn} do
245 |> put_req_header("accept", "application/json")
246 |> post("/api/pleroma/admin/users", %{
249 "nickname" => user.nickname,
250 "email" => "someuser@plerama.social",
256 assert json_response(conn, 409) == [
260 "email" => "someuser@plerama.social",
261 "nickname" => user.nickname
263 "error" => "nickname has already been taken",
269 test "Multiple user creation works in transaction", %{conn: conn} do
274 |> put_req_header("accept", "application/json")
275 |> post("/api/pleroma/admin/users", %{
278 "nickname" => "newuser",
279 "email" => "newuser@pleroma.social",
283 "nickname" => "lain",
284 "email" => user.email,
290 assert json_response(conn, 409) == [
294 "email" => user.email,
297 "error" => "email has already been taken",
303 "email" => "newuser@pleroma.social",
304 "nickname" => "newuser"
311 assert User.get_by_nickname("newuser") === nil
315 describe "/api/pleroma/admin/users/:nickname" do
316 test "Show", %{conn: conn} do
319 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
322 "deactivated" => false,
323 "id" => to_string(user.id),
325 "nickname" => user.nickname,
326 "roles" => %{"admin" => false, "moderator" => false},
328 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
329 "display_name" => HTML.strip_tags(user.name || user.nickname),
330 "confirmation_pending" => false
333 assert expected == json_response(conn, 200)
336 test "when the user doesn't exist", %{conn: conn} do
339 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
341 assert "Not found" == json_response(conn, 404)
345 describe "/api/pleroma/admin/users/follow" do
346 test "allows to force-follow another user", %{admin: admin, conn: conn} do
348 follower = insert(:user)
351 |> put_req_header("accept", "application/json")
352 |> post("/api/pleroma/admin/users/follow", %{
353 "follower" => follower.nickname,
354 "followed" => user.nickname
357 user = User.get_cached_by_id(user.id)
358 follower = User.get_cached_by_id(follower.id)
360 assert User.following?(follower, user)
362 log_entry = Repo.one(ModerationLog)
364 assert ModerationLog.get_log_entry_message(log_entry) ==
365 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
369 describe "/api/pleroma/admin/users/unfollow" do
370 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
372 follower = insert(:user)
374 User.follow(follower, user)
377 |> put_req_header("accept", "application/json")
378 |> post("/api/pleroma/admin/users/unfollow", %{
379 "follower" => follower.nickname,
380 "followed" => user.nickname
383 user = User.get_cached_by_id(user.id)
384 follower = User.get_cached_by_id(follower.id)
386 refute User.following?(follower, user)
388 log_entry = Repo.one(ModerationLog)
390 assert ModerationLog.get_log_entry_message(log_entry) ==
391 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
395 describe "PUT /api/pleroma/admin/users/tag" do
396 setup %{conn: conn} do
397 user1 = insert(:user, %{tags: ["x"]})
398 user2 = insert(:user, %{tags: ["y"]})
399 user3 = insert(:user, %{tags: ["unchanged"]})
403 |> put_req_header("accept", "application/json")
405 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
406 "#{user2.nickname}&tags[]=foo&tags[]=bar"
409 %{conn: conn, user1: user1, user2: user2, user3: user3}
412 test "it appends specified tags to users with specified nicknames", %{
418 assert json_response(conn, :no_content)
419 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
420 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
422 log_entry = Repo.one(ModerationLog)
425 [user1.nickname, user2.nickname]
426 |> Enum.map(&"@#{&1}")
429 tags = ["foo", "bar"] |> Enum.join(", ")
431 assert ModerationLog.get_log_entry_message(log_entry) ==
432 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
435 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
436 assert json_response(conn, :no_content)
437 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
441 describe "DELETE /api/pleroma/admin/users/tag" do
442 setup %{conn: conn} do
443 user1 = insert(:user, %{tags: ["x"]})
444 user2 = insert(:user, %{tags: ["y", "z"]})
445 user3 = insert(:user, %{tags: ["unchanged"]})
449 |> put_req_header("accept", "application/json")
451 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
452 "#{user2.nickname}&tags[]=x&tags[]=z"
455 %{conn: conn, user1: user1, user2: user2, user3: user3}
458 test "it removes specified tags from users with specified nicknames", %{
464 assert json_response(conn, :no_content)
465 assert User.get_cached_by_id(user1.id).tags == []
466 assert User.get_cached_by_id(user2.id).tags == ["y"]
468 log_entry = Repo.one(ModerationLog)
471 [user1.nickname, user2.nickname]
472 |> Enum.map(&"@#{&1}")
475 tags = ["x", "z"] |> Enum.join(", ")
477 assert ModerationLog.get_log_entry_message(log_entry) ==
478 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
481 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
482 assert json_response(conn, :no_content)
483 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
487 describe "/api/pleroma/admin/users/:nickname/permission_group" do
488 test "GET is giving user_info", %{admin: admin, conn: conn} do
491 |> put_req_header("accept", "application/json")
492 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
494 assert json_response(conn, 200) == %{
496 "is_moderator" => false
500 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
505 |> put_req_header("accept", "application/json")
506 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
508 assert json_response(conn, 200) == %{
512 log_entry = Repo.one(ModerationLog)
514 assert ModerationLog.get_log_entry_message(log_entry) ==
515 "@#{admin.nickname} made @#{user.nickname} admin"
518 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
519 user_one = insert(:user)
520 user_two = insert(:user)
524 |> put_req_header("accept", "application/json")
525 |> post("/api/pleroma/admin/users/permission_group/admin", %{
526 nicknames: [user_one.nickname, user_two.nickname]
529 assert json_response(conn, 200) == %{"is_admin" => true}
531 log_entry = Repo.one(ModerationLog)
533 assert ModerationLog.get_log_entry_message(log_entry) ==
534 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
537 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
538 user = insert(:user, is_admin: true)
542 |> put_req_header("accept", "application/json")
543 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
545 assert json_response(conn, 200) == %{"is_admin" => false}
547 log_entry = Repo.one(ModerationLog)
549 assert ModerationLog.get_log_entry_message(log_entry) ==
550 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
553 test "/:right DELETE, can remove from a permission group (multiple)", %{
557 user_one = insert(:user, is_admin: true)
558 user_two = insert(:user, is_admin: true)
562 |> put_req_header("accept", "application/json")
563 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
564 nicknames: [user_one.nickname, user_two.nickname]
567 assert json_response(conn, 200) == %{"is_admin" => false}
569 log_entry = Repo.one(ModerationLog)
571 assert ModerationLog.get_log_entry_message(log_entry) ==
572 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
578 describe "POST /api/pleroma/admin/email_invite, with valid config" do
579 setup do: clear_config([:instance, :registrations_open], false)
580 setup do: clear_config([:instance, :invites_enabled], true)
582 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
583 recipient_email = "foo@bar.com"
584 recipient_name = "J. D."
589 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
592 assert json_response(conn, :no_content)
594 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
596 refute token_record.used
598 notify_email = Config.get([:instance, :notify_email])
599 instance_name = Config.get([:instance, :name])
602 Pleroma.Emails.UserEmail.user_invitation_email(
609 Swoosh.TestAssertions.assert_email_sent(
610 from: {instance_name, notify_email},
611 to: {recipient_name, recipient_email},
612 html_body: email.html_body
616 test "it returns 403 if requested by a non-admin" do
617 non_admin_user = insert(:user)
618 token = insert(:oauth_token, user: non_admin_user)
622 |> assign(:user, non_admin_user)
623 |> assign(:token, token)
624 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
626 assert json_response(conn, :forbidden)
629 test "email with +", %{conn: conn, admin: admin} do
630 recipient_email = "foo+bar@baz.com"
633 |> put_req_header("content-type", "application/json;charset=utf-8")
634 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
635 |> json_response(:no_content)
638 Pleroma.UserInviteToken
643 refute token_record.used
645 notify_email = Config.get([:instance, :notify_email])
646 instance_name = Config.get([:instance, :name])
649 Pleroma.Emails.UserEmail.user_invitation_email(
655 Swoosh.TestAssertions.assert_email_sent(
656 from: {instance_name, notify_email},
658 html_body: email.html_body
663 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
664 setup do: clear_config([:instance, :registrations_open])
665 setup do: clear_config([:instance, :invites_enabled])
667 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
668 Config.put([:instance, :registrations_open], false)
669 Config.put([:instance, :invites_enabled], false)
671 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
673 assert json_response(conn, :bad_request) ==
674 "To send invites you need to set the `invites_enabled` option to true."
677 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
678 Config.put([:instance, :registrations_open], true)
679 Config.put([:instance, :invites_enabled], true)
681 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
683 assert json_response(conn, :bad_request) ==
684 "To send invites you need to set the `registrations_open` option to false."
688 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
693 |> put_req_header("accept", "application/json")
694 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
696 resp = json_response(conn, 200)
698 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
701 describe "GET /api/pleroma/admin/users" do
702 test "renders users array for the first page", %{conn: conn, admin: admin} do
703 user = insert(:user, local: false, tags: ["foo", "bar"])
704 conn = get(conn, "/api/pleroma/admin/users?page=1")
709 "deactivated" => admin.deactivated,
711 "nickname" => admin.nickname,
712 "roles" => %{"admin" => true, "moderator" => false},
715 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
716 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
717 "confirmation_pending" => false
720 "deactivated" => user.deactivated,
722 "nickname" => user.nickname,
723 "roles" => %{"admin" => false, "moderator" => false},
725 "tags" => ["foo", "bar"],
726 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
727 "display_name" => HTML.strip_tags(user.name || user.nickname),
728 "confirmation_pending" => false
731 |> Enum.sort_by(& &1["nickname"])
733 assert json_response(conn, 200) == %{
740 test "renders empty array for the second page", %{conn: conn} do
743 conn = get(conn, "/api/pleroma/admin/users?page=2")
745 assert json_response(conn, 200) == %{
752 test "regular search", %{conn: conn} do
753 user = insert(:user, nickname: "bob")
755 conn = get(conn, "/api/pleroma/admin/users?query=bo")
757 assert json_response(conn, 200) == %{
762 "deactivated" => user.deactivated,
764 "nickname" => user.nickname,
765 "roles" => %{"admin" => false, "moderator" => false},
768 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
769 "display_name" => HTML.strip_tags(user.name || user.nickname),
770 "confirmation_pending" => false
776 test "search by domain", %{conn: conn} do
777 user = insert(:user, nickname: "nickname@domain.com")
780 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
782 assert json_response(conn, 200) == %{
787 "deactivated" => user.deactivated,
789 "nickname" => user.nickname,
790 "roles" => %{"admin" => false, "moderator" => false},
793 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
794 "display_name" => HTML.strip_tags(user.name || user.nickname),
795 "confirmation_pending" => false
801 test "search by full nickname", %{conn: conn} do
802 user = insert(:user, nickname: "nickname@domain.com")
805 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
807 assert json_response(conn, 200) == %{
812 "deactivated" => user.deactivated,
814 "nickname" => user.nickname,
815 "roles" => %{"admin" => false, "moderator" => false},
818 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
819 "display_name" => HTML.strip_tags(user.name || user.nickname),
820 "confirmation_pending" => false
826 test "search by display name", %{conn: conn} do
827 user = insert(:user, name: "Display name")
830 conn = get(conn, "/api/pleroma/admin/users?name=display")
832 assert json_response(conn, 200) == %{
837 "deactivated" => user.deactivated,
839 "nickname" => user.nickname,
840 "roles" => %{"admin" => false, "moderator" => false},
843 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
844 "display_name" => HTML.strip_tags(user.name || user.nickname),
845 "confirmation_pending" => false
851 test "search by email", %{conn: conn} do
852 user = insert(:user, email: "email@example.com")
855 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
857 assert json_response(conn, 200) == %{
862 "deactivated" => user.deactivated,
864 "nickname" => user.nickname,
865 "roles" => %{"admin" => false, "moderator" => false},
868 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
869 "display_name" => HTML.strip_tags(user.name || user.nickname),
870 "confirmation_pending" => false
876 test "regular search with page size", %{conn: conn} do
877 user = insert(:user, nickname: "aalice")
878 user2 = insert(:user, nickname: "alice")
880 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
882 assert json_response(conn1, 200) == %{
887 "deactivated" => user.deactivated,
889 "nickname" => user.nickname,
890 "roles" => %{"admin" => false, "moderator" => false},
893 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
894 "display_name" => HTML.strip_tags(user.name || user.nickname),
895 "confirmation_pending" => false
900 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
902 assert json_response(conn2, 200) == %{
907 "deactivated" => user2.deactivated,
909 "nickname" => user2.nickname,
910 "roles" => %{"admin" => false, "moderator" => false},
913 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
914 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
915 "confirmation_pending" => false
921 test "only local users" do
922 admin = insert(:user, is_admin: true, nickname: "john")
923 token = insert(:oauth_admin_token, user: admin)
924 user = insert(:user, nickname: "bob")
926 insert(:user, nickname: "bobb", local: false)
930 |> assign(:user, admin)
931 |> assign(:token, token)
932 |> get("/api/pleroma/admin/users?query=bo&filters=local")
934 assert json_response(conn, 200) == %{
939 "deactivated" => user.deactivated,
941 "nickname" => user.nickname,
942 "roles" => %{"admin" => false, "moderator" => false},
945 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
946 "display_name" => HTML.strip_tags(user.name || user.nickname),
947 "confirmation_pending" => false
953 test "only local users with no query", %{conn: conn, admin: old_admin} do
954 admin = insert(:user, is_admin: true, nickname: "john")
955 user = insert(:user, nickname: "bob")
957 insert(:user, nickname: "bobb", local: false)
959 conn = get(conn, "/api/pleroma/admin/users?filters=local")
964 "deactivated" => user.deactivated,
966 "nickname" => user.nickname,
967 "roles" => %{"admin" => false, "moderator" => false},
970 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
971 "display_name" => HTML.strip_tags(user.name || user.nickname),
972 "confirmation_pending" => false
975 "deactivated" => admin.deactivated,
977 "nickname" => admin.nickname,
978 "roles" => %{"admin" => true, "moderator" => false},
981 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
982 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
983 "confirmation_pending" => false
986 "deactivated" => false,
987 "id" => old_admin.id,
989 "nickname" => old_admin.nickname,
990 "roles" => %{"admin" => true, "moderator" => false},
992 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
993 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
994 "confirmation_pending" => false
997 |> Enum.sort_by(& &1["nickname"])
999 assert json_response(conn, 200) == %{
1006 test "load only admins", %{conn: conn, admin: admin} do
1007 second_admin = insert(:user, is_admin: true)
1011 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1016 "deactivated" => false,
1018 "nickname" => admin.nickname,
1019 "roles" => %{"admin" => true, "moderator" => false},
1020 "local" => admin.local,
1022 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1023 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1024 "confirmation_pending" => false
1027 "deactivated" => false,
1028 "id" => second_admin.id,
1029 "nickname" => second_admin.nickname,
1030 "roles" => %{"admin" => true, "moderator" => false},
1031 "local" => second_admin.local,
1033 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1034 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1035 "confirmation_pending" => false
1038 |> Enum.sort_by(& &1["nickname"])
1040 assert json_response(conn, 200) == %{
1047 test "load only moderators", %{conn: conn} do
1048 moderator = insert(:user, is_moderator: true)
1052 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1054 assert json_response(conn, 200) == %{
1059 "deactivated" => false,
1060 "id" => moderator.id,
1061 "nickname" => moderator.nickname,
1062 "roles" => %{"admin" => false, "moderator" => true},
1063 "local" => moderator.local,
1065 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1066 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1067 "confirmation_pending" => false
1073 test "load users with tags list", %{conn: conn} do
1074 user1 = insert(:user, tags: ["first"])
1075 user2 = insert(:user, tags: ["second"])
1079 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1084 "deactivated" => false,
1086 "nickname" => user1.nickname,
1087 "roles" => %{"admin" => false, "moderator" => false},
1088 "local" => user1.local,
1089 "tags" => ["first"],
1090 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1091 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1092 "confirmation_pending" => false
1095 "deactivated" => false,
1097 "nickname" => user2.nickname,
1098 "roles" => %{"admin" => false, "moderator" => false},
1099 "local" => user2.local,
1100 "tags" => ["second"],
1101 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1102 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1103 "confirmation_pending" => false
1106 |> Enum.sort_by(& &1["nickname"])
1108 assert json_response(conn, 200) == %{
1115 test "it works with multiple filters" do
1116 admin = insert(:user, nickname: "john", is_admin: true)
1117 token = insert(:oauth_admin_token, user: admin)
1118 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1120 insert(:user, nickname: "ken", local: true, deactivated: true)
1121 insert(:user, nickname: "bobb", local: false, deactivated: false)
1125 |> assign(:user, admin)
1126 |> assign(:token, token)
1127 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1129 assert json_response(conn, 200) == %{
1134 "deactivated" => user.deactivated,
1136 "nickname" => user.nickname,
1137 "roles" => %{"admin" => false, "moderator" => false},
1138 "local" => user.local,
1140 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1141 "display_name" => HTML.strip_tags(user.name || user.nickname),
1142 "confirmation_pending" => false
1148 test "it omits relay user", %{admin: admin, conn: conn} do
1149 assert %User{} = Relay.get_actor()
1151 conn = get(conn, "/api/pleroma/admin/users")
1153 assert json_response(conn, 200) == %{
1158 "deactivated" => admin.deactivated,
1160 "nickname" => admin.nickname,
1161 "roles" => %{"admin" => true, "moderator" => false},
1164 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1165 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1166 "confirmation_pending" => false
1173 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1174 user_one = insert(:user, deactivated: true)
1175 user_two = insert(:user, deactivated: true)
1180 "/api/pleroma/admin/users/activate",
1181 %{nicknames: [user_one.nickname, user_two.nickname]}
1184 response = json_response(conn, 200)
1185 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1187 log_entry = Repo.one(ModerationLog)
1189 assert ModerationLog.get_log_entry_message(log_entry) ==
1190 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1193 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1194 user_one = insert(:user, deactivated: false)
1195 user_two = insert(:user, deactivated: false)
1200 "/api/pleroma/admin/users/deactivate",
1201 %{nicknames: [user_one.nickname, user_two.nickname]}
1204 response = json_response(conn, 200)
1205 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1207 log_entry = Repo.one(ModerationLog)
1209 assert ModerationLog.get_log_entry_message(log_entry) ==
1210 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1213 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1214 user = insert(:user)
1216 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1218 assert json_response(conn, 200) ==
1220 "deactivated" => !user.deactivated,
1222 "nickname" => user.nickname,
1223 "roles" => %{"admin" => false, "moderator" => false},
1226 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1227 "display_name" => HTML.strip_tags(user.name || user.nickname),
1228 "confirmation_pending" => false
1231 log_entry = Repo.one(ModerationLog)
1233 assert ModerationLog.get_log_entry_message(log_entry) ==
1234 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1237 describe "POST /api/pleroma/admin/users/invite_token" do
1238 test "without options", %{conn: conn} do
1239 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1241 invite_json = json_response(conn, 200)
1242 invite = UserInviteToken.find_by_token!(invite_json["token"])
1244 refute invite.expires_at
1245 refute invite.max_use
1246 assert invite.invite_type == "one_time"
1249 test "with expires_at", %{conn: conn} do
1251 post(conn, "/api/pleroma/admin/users/invite_token", %{
1252 "expires_at" => Date.to_string(Date.utc_today())
1255 invite_json = json_response(conn, 200)
1256 invite = UserInviteToken.find_by_token!(invite_json["token"])
1259 assert invite.expires_at == Date.utc_today()
1260 refute invite.max_use
1261 assert invite.invite_type == "date_limited"
1264 test "with max_use", %{conn: conn} do
1265 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1267 invite_json = json_response(conn, 200)
1268 invite = UserInviteToken.find_by_token!(invite_json["token"])
1270 refute invite.expires_at
1271 assert invite.max_use == 150
1272 assert invite.invite_type == "reusable"
1275 test "with max use and expires_at", %{conn: conn} do
1277 post(conn, "/api/pleroma/admin/users/invite_token", %{
1279 "expires_at" => Date.to_string(Date.utc_today())
1282 invite_json = json_response(conn, 200)
1283 invite = UserInviteToken.find_by_token!(invite_json["token"])
1285 assert invite.expires_at == Date.utc_today()
1286 assert invite.max_use == 150
1287 assert invite.invite_type == "reusable_date_limited"
1291 describe "GET /api/pleroma/admin/users/invites" do
1292 test "no invites", %{conn: conn} do
1293 conn = get(conn, "/api/pleroma/admin/users/invites")
1295 assert json_response(conn, 200) == %{"invites" => []}
1298 test "with invite", %{conn: conn} do
1299 {:ok, invite} = UserInviteToken.create_invite()
1301 conn = get(conn, "/api/pleroma/admin/users/invites")
1303 assert json_response(conn, 200) == %{
1306 "expires_at" => nil,
1308 "invite_type" => "one_time",
1310 "token" => invite.token,
1319 describe "POST /api/pleroma/admin/users/revoke_invite" do
1320 test "with token", %{conn: conn} do
1321 {:ok, invite} = UserInviteToken.create_invite()
1323 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1325 assert json_response(conn, 200) == %{
1326 "expires_at" => nil,
1328 "invite_type" => "one_time",
1330 "token" => invite.token,
1336 test "with invalid token", %{conn: conn} do
1337 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1339 assert json_response(conn, :not_found) == "Not found"
1343 describe "GET /api/pleroma/admin/reports/:id" do
1344 test "returns report by its id", %{conn: conn} do
1345 [reporter, target_user] = insert_pair(:user)
1346 activity = insert(:note_activity, user: target_user)
1348 {:ok, %{id: report_id}} =
1349 CommonAPI.report(reporter, %{
1350 "account_id" => target_user.id,
1351 "comment" => "I feel offended",
1352 "status_ids" => [activity.id]
1357 |> get("/api/pleroma/admin/reports/#{report_id}")
1358 |> json_response(:ok)
1360 assert response["id"] == report_id
1363 test "returns 404 when report id is invalid", %{conn: conn} do
1364 conn = get(conn, "/api/pleroma/admin/reports/test")
1366 assert json_response(conn, :not_found) == "Not found"
1370 describe "PATCH /api/pleroma/admin/reports" do
1372 [reporter, target_user] = insert_pair(:user)
1373 activity = insert(:note_activity, user: target_user)
1375 {:ok, %{id: report_id}} =
1376 CommonAPI.report(reporter, %{
1377 "account_id" => target_user.id,
1378 "comment" => "I feel offended",
1379 "status_ids" => [activity.id]
1382 {:ok, %{id: second_report_id}} =
1383 CommonAPI.report(reporter, %{
1384 "account_id" => target_user.id,
1385 "comment" => "I feel very offended",
1386 "status_ids" => [activity.id]
1391 second_report_id: second_report_id
1395 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1396 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1397 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1401 |> assign(:token, read_token)
1402 |> patch("/api/pleroma/admin/reports", %{
1403 "reports" => [%{"state" => "resolved", "id" => id}]
1405 |> json_response(403)
1407 assert response == %{
1408 "error" => "Insufficient permissions: admin:write:reports."
1412 |> assign(:token, write_token)
1413 |> patch("/api/pleroma/admin/reports", %{
1414 "reports" => [%{"state" => "resolved", "id" => id}]
1416 |> json_response(:no_content)
1419 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1421 |> patch("/api/pleroma/admin/reports", %{
1423 %{"state" => "resolved", "id" => id}
1426 |> json_response(:no_content)
1428 activity = Activity.get_by_id(id)
1429 assert activity.data["state"] == "resolved"
1431 log_entry = Repo.one(ModerationLog)
1433 assert ModerationLog.get_log_entry_message(log_entry) ==
1434 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1437 test "closes report", %{conn: conn, id: id, admin: admin} do
1439 |> patch("/api/pleroma/admin/reports", %{
1441 %{"state" => "closed", "id" => id}
1444 |> json_response(:no_content)
1446 activity = Activity.get_by_id(id)
1447 assert activity.data["state"] == "closed"
1449 log_entry = Repo.one(ModerationLog)
1451 assert ModerationLog.get_log_entry_message(log_entry) ==
1452 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1455 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1458 |> patch("/api/pleroma/admin/reports", %{
1460 %{"state" => "test", "id" => id}
1464 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1467 test "returns 404 when report is not exist", %{conn: conn} do
1470 |> patch("/api/pleroma/admin/reports", %{
1472 %{"state" => "closed", "id" => "test"}
1476 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1479 test "updates state of multiple reports", %{
1483 second_report_id: second_report_id
1486 |> patch("/api/pleroma/admin/reports", %{
1488 %{"state" => "resolved", "id" => id},
1489 %{"state" => "closed", "id" => second_report_id}
1492 |> json_response(:no_content)
1494 activity = Activity.get_by_id(id)
1495 second_activity = Activity.get_by_id(second_report_id)
1496 assert activity.data["state"] == "resolved"
1497 assert second_activity.data["state"] == "closed"
1499 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1501 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1502 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1504 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1505 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1509 describe "GET /api/pleroma/admin/reports" do
1510 test "returns empty response when no reports created", %{conn: conn} do
1513 |> get("/api/pleroma/admin/reports")
1514 |> json_response(:ok)
1516 assert Enum.empty?(response["reports"])
1517 assert response["total"] == 0
1520 test "returns reports", %{conn: conn} do
1521 [reporter, target_user] = insert_pair(:user)
1522 activity = insert(:note_activity, user: target_user)
1524 {:ok, %{id: report_id}} =
1525 CommonAPI.report(reporter, %{
1526 "account_id" => target_user.id,
1527 "comment" => "I feel offended",
1528 "status_ids" => [activity.id]
1533 |> get("/api/pleroma/admin/reports")
1534 |> json_response(:ok)
1536 [report] = response["reports"]
1538 assert length(response["reports"]) == 1
1539 assert report["id"] == report_id
1541 assert response["total"] == 1
1544 test "returns reports with specified state", %{conn: conn} do
1545 [reporter, target_user] = insert_pair(:user)
1546 activity = insert(:note_activity, user: target_user)
1548 {:ok, %{id: first_report_id}} =
1549 CommonAPI.report(reporter, %{
1550 "account_id" => target_user.id,
1551 "comment" => "I feel offended",
1552 "status_ids" => [activity.id]
1555 {:ok, %{id: second_report_id}} =
1556 CommonAPI.report(reporter, %{
1557 "account_id" => target_user.id,
1558 "comment" => "I don't like this user"
1561 CommonAPI.update_report_state(second_report_id, "closed")
1565 |> get("/api/pleroma/admin/reports", %{
1568 |> json_response(:ok)
1570 [open_report] = response["reports"]
1572 assert length(response["reports"]) == 1
1573 assert open_report["id"] == first_report_id
1575 assert response["total"] == 1
1579 |> get("/api/pleroma/admin/reports", %{
1582 |> json_response(:ok)
1584 [closed_report] = response["reports"]
1586 assert length(response["reports"]) == 1
1587 assert closed_report["id"] == second_report_id
1589 assert response["total"] == 1
1593 |> get("/api/pleroma/admin/reports", %{
1594 "state" => "resolved"
1596 |> json_response(:ok)
1598 assert Enum.empty?(response["reports"])
1599 assert response["total"] == 0
1602 test "returns 403 when requested by a non-admin" do
1603 user = insert(:user)
1604 token = insert(:oauth_token, user: user)
1608 |> assign(:user, user)
1609 |> assign(:token, token)
1610 |> get("/api/pleroma/admin/reports")
1612 assert json_response(conn, :forbidden) ==
1613 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1616 test "returns 403 when requested by anonymous" do
1617 conn = get(build_conn(), "/api/pleroma/admin/reports")
1619 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1623 describe "PUT /api/pleroma/admin/statuses/:id" do
1625 activity = insert(:note_activity)
1630 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1633 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1634 |> json_response(:ok)
1636 assert response["sensitive"]
1638 log_entry = Repo.one(ModerationLog)
1640 assert ModerationLog.get_log_entry_message(log_entry) ==
1641 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1645 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1646 |> json_response(:ok)
1648 refute response["sensitive"]
1651 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1654 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1655 |> json_response(:ok)
1657 assert response["visibility"] == "public"
1659 log_entry = Repo.one(ModerationLog)
1661 assert ModerationLog.get_log_entry_message(log_entry) ==
1662 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1666 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1667 |> json_response(:ok)
1669 assert response["visibility"] == "private"
1673 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1674 |> json_response(:ok)
1676 assert response["visibility"] == "unlisted"
1679 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1680 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1682 assert json_response(conn, :bad_request) == "Unsupported visibility"
1686 describe "DELETE /api/pleroma/admin/statuses/:id" do
1688 activity = insert(:note_activity)
1693 test "deletes status", %{conn: conn, id: id, admin: admin} do
1695 |> delete("/api/pleroma/admin/statuses/#{id}")
1696 |> json_response(:ok)
1698 refute Activity.get_by_id(id)
1700 log_entry = Repo.one(ModerationLog)
1702 assert ModerationLog.get_log_entry_message(log_entry) ==
1703 "@#{admin.nickname} deleted status ##{id}"
1706 test "returns 404 when the status does not exist", %{conn: conn} do
1707 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1709 assert json_response(conn, :not_found) == "Not found"
1713 describe "GET /api/pleroma/admin/config" do
1714 setup do: clear_config(:configurable_from_database, true)
1716 test "when configuration from database is off", %{conn: conn} do
1717 Config.put(:configurable_from_database, false)
1718 conn = get(conn, "/api/pleroma/admin/config")
1720 assert json_response(conn, 400) ==
1721 "To use this endpoint you need to enable configuration from database."
1724 test "with settings only in db", %{conn: conn} do
1725 config1 = insert(:config)
1726 config2 = insert(:config)
1728 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1733 "group" => ":pleroma",
1738 "group" => ":pleroma",
1743 } = json_response(conn, 200)
1745 assert key1 == config1.key
1746 assert key2 == config2.key
1749 test "db is added to settings that are in db", %{conn: conn} do
1750 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1752 %{"configs" => configs} =
1754 |> get("/api/pleroma/admin/config")
1755 |> json_response(200)
1758 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1759 group == ":pleroma" and key == ":instance"
1762 assert instance_config["db"] == [":name"]
1765 test "merged default setting with db settings", %{conn: conn} do
1766 config1 = insert(:config)
1767 config2 = insert(:config)
1771 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1774 %{"configs" => configs} =
1776 |> get("/api/pleroma/admin/config")
1777 |> json_response(200)
1779 assert length(configs) > 3
1782 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1783 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1786 assert length(received_configs) == 3
1790 |> ConfigDB.from_binary()
1792 |> ConfigDB.convert()
1794 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1795 assert db in [[config1.key], [config2.key], db_keys]
1798 ConfigDB.from_binary_with_convert(config1.value),
1799 ConfigDB.from_binary_with_convert(config2.value),
1800 ConfigDB.from_binary_with_convert(config3.value)
1805 test "subkeys with full update right merge", %{conn: conn} do
1809 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1815 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1818 %{"configs" => configs} =
1820 |> get("/api/pleroma/admin/config")
1821 |> json_response(200)
1824 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1825 group == ":pleroma" and key in [config1.key, config2.key]
1828 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1829 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1831 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1832 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1834 assert emoji_val[:groups] == [a: 1, b: 2]
1835 assert assets_val[:mascots] == [a: 1, b: 2]
1839 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1840 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1842 assert json_response(conn, 400) ==
1843 "To use this endpoint you need to enable configuration from database."
1846 describe "POST /api/pleroma/admin/config" do
1848 http = Application.get_env(:pleroma, :http)
1851 Application.delete_env(:pleroma, :key1)
1852 Application.delete_env(:pleroma, :key2)
1853 Application.delete_env(:pleroma, :key3)
1854 Application.delete_env(:pleroma, :key4)
1855 Application.delete_env(:pleroma, :keyaa1)
1856 Application.delete_env(:pleroma, :keyaa2)
1857 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1858 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1859 Application.put_env(:pleroma, :http, http)
1860 Application.put_env(:tesla, :adapter, Tesla.Mock)
1861 Restarter.Pleroma.refresh()
1865 setup do: clear_config(:configurable_from_database, true)
1867 @tag capture_log: true
1868 test "create new config setting in db", %{conn: conn} do
1869 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1870 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1873 post(conn, "/api/pleroma/admin/config", %{
1875 %{group: ":pleroma", key: ":key1", value: "value1"},
1877 group: ":ueberauth",
1879 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1885 ":nested_1" => "nested_value1",
1887 %{":nested_22" => "nested_value222"},
1888 %{":nested_33" => %{":nested_44" => "nested_444"}}
1896 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1897 %{"nested_4" => true}
1903 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1908 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1913 assert json_response(conn, 200) == %{
1916 "group" => ":pleroma",
1918 "value" => "value1",
1922 "group" => ":ueberauth",
1923 "key" => "Ueberauth",
1924 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1925 "db" => [":consumer_secret"]
1928 "group" => ":pleroma",
1931 ":nested_1" => "nested_value1",
1933 %{":nested_22" => "nested_value222"},
1934 %{":nested_33" => %{":nested_44" => "nested_444"}}
1940 "group" => ":pleroma",
1943 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1944 %{"nested_4" => true}
1949 "group" => ":pleroma",
1951 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
1957 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
1963 assert Application.get_env(:pleroma, :key1) == "value1"
1965 assert Application.get_env(:pleroma, :key2) == %{
1966 nested_1: "nested_value1",
1968 %{nested_22: "nested_value222"},
1969 %{nested_33: %{nested_44: "nested_444"}}
1973 assert Application.get_env(:pleroma, :key3) == [
1974 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
1975 %{"nested_4" => true}
1978 assert Application.get_env(:pleroma, :key4) == %{
1979 "endpoint" => "https://example.com",
1983 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
1986 test "save configs setting without explicit key", %{conn: conn} do
1987 level = Application.get_env(:quack, :level)
1988 meta = Application.get_env(:quack, :meta)
1989 webhook_url = Application.get_env(:quack, :webhook_url)
1992 Application.put_env(:quack, :level, level)
1993 Application.put_env(:quack, :meta, meta)
1994 Application.put_env(:quack, :webhook_url, webhook_url)
1998 post(conn, "/api/pleroma/admin/config", %{
2012 key: ":webhook_url",
2013 value: "https://hooks.slack.com/services/KEY"
2018 assert json_response(conn, 200) == %{
2021 "group" => ":quack",
2027 "group" => ":quack",
2029 "value" => [":none"],
2033 "group" => ":quack",
2034 "key" => ":webhook_url",
2035 "value" => "https://hooks.slack.com/services/KEY",
2036 "db" => [":webhook_url"]
2041 assert Application.get_env(:quack, :level) == :info
2042 assert Application.get_env(:quack, :meta) == [:none]
2043 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2046 test "saving config with partial update", %{conn: conn} do
2047 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2050 post(conn, "/api/pleroma/admin/config", %{
2052 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2056 assert json_response(conn, 200) == %{
2059 "group" => ":pleroma",
2062 %{"tuple" => [":key1", 1]},
2063 %{"tuple" => [":key2", 2]},
2064 %{"tuple" => [":key3", 3]}
2066 "db" => [":key1", ":key2", ":key3"]
2072 test "saving config which need pleroma reboot", %{conn: conn} do
2073 chat = Config.get(:chat)
2074 on_exit(fn -> Config.put(:chat, chat) end)
2078 "/api/pleroma/admin/config",
2081 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2085 |> json_response(200) == %{
2088 "db" => [":enabled"],
2089 "group" => ":pleroma",
2091 "value" => [%{"tuple" => [":enabled", true]}]
2094 "need_reboot" => true
2099 |> get("/api/pleroma/admin/config")
2100 |> json_response(200)
2102 assert configs["need_reboot"]
2105 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2106 end) =~ "pleroma restarted"
2110 |> get("/api/pleroma/admin/config")
2111 |> json_response(200)
2113 refute Map.has_key?(configs, "need_reboot")
2116 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2117 chat = Config.get(:chat)
2118 on_exit(fn -> Config.put(:chat, chat) end)
2122 "/api/pleroma/admin/config",
2125 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2129 |> json_response(200) == %{
2132 "db" => [":enabled"],
2133 "group" => ":pleroma",
2135 "value" => [%{"tuple" => [":enabled", true]}]
2138 "need_reboot" => true
2141 assert post(conn, "/api/pleroma/admin/config", %{
2143 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2146 |> json_response(200) == %{
2149 "group" => ":pleroma",
2152 %{"tuple" => [":key3", 3]}
2157 "need_reboot" => true
2161 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2162 end) =~ "pleroma restarted"
2166 |> get("/api/pleroma/admin/config")
2167 |> json_response(200)
2169 refute Map.has_key?(configs, "need_reboot")
2172 test "saving config with nested merge", %{conn: conn} do
2174 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2177 post(conn, "/api/pleroma/admin/config", %{
2180 group: config.group,
2183 %{"tuple" => [":key3", 3]},
2188 %{"tuple" => [":k2", 1]},
2189 %{"tuple" => [":k3", 3]}
2198 assert json_response(conn, 200) == %{
2201 "group" => ":pleroma",
2204 %{"tuple" => [":key1", 1]},
2205 %{"tuple" => [":key3", 3]},
2210 %{"tuple" => [":k1", 1]},
2211 %{"tuple" => [":k2", 1]},
2212 %{"tuple" => [":k3", 3]}
2217 "db" => [":key1", ":key3", ":key2"]
2223 test "saving special atoms", %{conn: conn} do
2225 post(conn, "/api/pleroma/admin/config", %{
2228 "group" => ":pleroma",
2234 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2242 assert json_response(conn, 200) == %{
2245 "group" => ":pleroma",
2251 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2255 "db" => [":ssl_options"]
2260 assert Application.get_env(:pleroma, :key1) == [
2261 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2265 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2266 backends = Application.get_env(:logger, :backends)
2267 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2273 value: :erlang.term_to_binary([])
2276 Pleroma.Config.TransferTask.load_and_update_env([], false)
2278 assert Application.get_env(:logger, :backends) == []
2281 post(conn, "/api/pleroma/admin/config", %{
2284 group: config.group,
2291 assert json_response(conn, 200) == %{
2294 "group" => ":logger",
2295 "key" => ":backends",
2299 "db" => [":backends"]
2304 assert Application.get_env(:logger, :backends) == [
2309 test "saving full setting if value is not keyword", %{conn: conn} do
2314 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2318 post(conn, "/api/pleroma/admin/config", %{
2320 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2324 assert json_response(conn, 200) == %{
2327 "group" => ":tesla",
2328 "key" => ":adapter",
2329 "value" => "Tesla.Adapter.Httpc",
2330 "db" => [":adapter"]
2336 test "update config setting & delete with fallback to default value", %{
2341 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2342 config1 = insert(:config, key: ":keyaa1")
2343 config2 = insert(:config, key: ":keyaa2")
2347 group: ":ueberauth",
2352 post(conn, "/api/pleroma/admin/config", %{
2354 %{group: config1.group, key: config1.key, value: "another_value"},
2355 %{group: config2.group, key: config2.key, value: "another_value"}
2359 assert json_response(conn, 200) == %{
2362 "group" => ":pleroma",
2363 "key" => config1.key,
2364 "value" => "another_value",
2368 "group" => ":pleroma",
2369 "key" => config2.key,
2370 "value" => "another_value",
2376 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2377 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2378 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2382 |> assign(:user, admin)
2383 |> assign(:token, token)
2384 |> post("/api/pleroma/admin/config", %{
2386 %{group: config2.group, key: config2.key, delete: true},
2388 group: ":ueberauth",
2395 assert json_response(conn, 200) == %{
2399 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2400 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2403 test "common config example", %{conn: conn} do
2405 post(conn, "/api/pleroma/admin/config", %{
2408 "group" => ":pleroma",
2409 "key" => "Pleroma.Captcha.NotReal",
2411 %{"tuple" => [":enabled", false]},
2412 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2413 %{"tuple" => [":seconds_valid", 60]},
2414 %{"tuple" => [":path", ""]},
2415 %{"tuple" => [":key1", nil]},
2416 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2417 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2418 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2419 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2420 %{"tuple" => [":name", "Pleroma"]}
2426 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2428 assert json_response(conn, 200) == %{
2431 "group" => ":pleroma",
2432 "key" => "Pleroma.Captcha.NotReal",
2434 %{"tuple" => [":enabled", false]},
2435 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2436 %{"tuple" => [":seconds_valid", 60]},
2437 %{"tuple" => [":path", ""]},
2438 %{"tuple" => [":key1", nil]},
2439 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2440 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2441 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2442 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2443 %{"tuple" => [":name", "Pleroma"]}
2462 test "tuples with more than two values", %{conn: conn} do
2464 post(conn, "/api/pleroma/admin/config", %{
2467 "group" => ":pleroma",
2468 "key" => "Pleroma.Web.Endpoint.NotReal",
2484 "/api/v1/streaming",
2485 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2492 "Phoenix.Endpoint.CowboyWebSocket",
2495 "Phoenix.Transports.WebSocket",
2498 "Pleroma.Web.Endpoint",
2499 "Pleroma.Web.UserSocket",
2510 "Phoenix.Endpoint.Cowboy2Handler",
2511 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2528 assert json_response(conn, 200) == %{
2531 "group" => ":pleroma",
2532 "key" => "Pleroma.Web.Endpoint.NotReal",
2548 "/api/v1/streaming",
2549 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2556 "Phoenix.Endpoint.CowboyWebSocket",
2559 "Phoenix.Transports.WebSocket",
2562 "Pleroma.Web.Endpoint",
2563 "Pleroma.Web.UserSocket",
2574 "Phoenix.Endpoint.Cowboy2Handler",
2575 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2594 test "settings with nesting map", %{conn: conn} do
2596 post(conn, "/api/pleroma/admin/config", %{
2599 "group" => ":pleroma",
2602 %{"tuple" => [":key2", "some_val"]},
2607 ":max_options" => 20,
2608 ":max_option_chars" => 200,
2609 ":min_expiration" => 0,
2610 ":max_expiration" => 31_536_000,
2612 ":max_options" => 20,
2613 ":max_option_chars" => 200,
2614 ":min_expiration" => 0,
2615 ":max_expiration" => 31_536_000
2625 assert json_response(conn, 200) ==
2629 "group" => ":pleroma",
2632 %{"tuple" => [":key2", "some_val"]},
2637 ":max_expiration" => 31_536_000,
2638 ":max_option_chars" => 200,
2639 ":max_options" => 20,
2640 ":min_expiration" => 0,
2642 ":max_expiration" => 31_536_000,
2643 ":max_option_chars" => 200,
2644 ":max_options" => 20,
2645 ":min_expiration" => 0
2651 "db" => [":key2", ":key3"]
2657 test "value as map", %{conn: conn} do
2659 post(conn, "/api/pleroma/admin/config", %{
2662 "group" => ":pleroma",
2664 "value" => %{"key" => "some_val"}
2669 assert json_response(conn, 200) ==
2673 "group" => ":pleroma",
2675 "value" => %{"key" => "some_val"},
2682 test "queues key as atom", %{conn: conn} do
2684 post(conn, "/api/pleroma/admin/config", %{
2690 %{"tuple" => [":federator_incoming", 50]},
2691 %{"tuple" => [":federator_outgoing", 50]},
2692 %{"tuple" => [":web_push", 50]},
2693 %{"tuple" => [":mailer", 10]},
2694 %{"tuple" => [":transmogrifier", 20]},
2695 %{"tuple" => [":scheduled_activities", 10]},
2696 %{"tuple" => [":background", 5]}
2702 assert json_response(conn, 200) == %{
2708 %{"tuple" => [":federator_incoming", 50]},
2709 %{"tuple" => [":federator_outgoing", 50]},
2710 %{"tuple" => [":web_push", 50]},
2711 %{"tuple" => [":mailer", 10]},
2712 %{"tuple" => [":transmogrifier", 20]},
2713 %{"tuple" => [":scheduled_activities", 10]},
2714 %{"tuple" => [":background", 5]}
2717 ":federator_incoming",
2718 ":federator_outgoing",
2722 ":scheduled_activities",
2730 test "delete part of settings by atom subkeys", %{conn: conn} do
2734 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2738 post(conn, "/api/pleroma/admin/config", %{
2741 group: config.group,
2743 subkeys: [":subkey1", ":subkey3"],
2749 assert json_response(conn, 200) == %{
2752 "group" => ":pleroma",
2754 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2755 "db" => [":subkey2"]
2761 test "proxy tuple localhost", %{conn: conn} do
2763 post(conn, "/api/pleroma/admin/config", %{
2769 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2770 %{"tuple" => [":send_user_agent", false]}
2776 assert json_response(conn, 200) == %{
2779 "group" => ":pleroma",
2782 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2783 %{"tuple" => [":send_user_agent", false]}
2785 "db" => [":proxy_url", ":send_user_agent"]
2791 test "proxy tuple domain", %{conn: conn} do
2793 post(conn, "/api/pleroma/admin/config", %{
2799 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2800 %{"tuple" => [":send_user_agent", false]}
2806 assert json_response(conn, 200) == %{
2809 "group" => ":pleroma",
2812 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2813 %{"tuple" => [":send_user_agent", false]}
2815 "db" => [":proxy_url", ":send_user_agent"]
2821 test "proxy tuple ip", %{conn: conn} do
2823 post(conn, "/api/pleroma/admin/config", %{
2829 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2830 %{"tuple" => [":send_user_agent", false]}
2836 assert json_response(conn, 200) == %{
2839 "group" => ":pleroma",
2842 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2843 %{"tuple" => [":send_user_agent", false]}
2845 "db" => [":proxy_url", ":send_user_agent"]
2852 describe "GET /api/pleroma/admin/restart" do
2853 setup do: clear_config(:configurable_from_database, true)
2855 test "pleroma restarts", %{conn: conn} do
2857 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2858 end) =~ "pleroma restarted"
2860 refute Restarter.Pleroma.need_reboot?()
2864 describe "GET /api/pleroma/admin/statuses" do
2865 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2866 blocked = insert(:user)
2867 user = insert(:user)
2868 User.block(admin, blocked)
2871 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2873 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2874 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2875 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2876 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2880 |> get("/api/pleroma/admin/statuses")
2881 |> json_response(200)
2883 refute "private" in Enum.map(response, & &1["visibility"])
2884 assert length(response) == 3
2887 test "returns only local statuses with local_only on", %{conn: conn} do
2888 user = insert(:user)
2889 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2890 insert(:note_activity, user: user, local: true)
2891 insert(:note_activity, user: remote_user, local: false)
2895 |> get("/api/pleroma/admin/statuses?local_only=true")
2896 |> json_response(200)
2898 assert length(response) == 1
2901 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2902 user = insert(:user)
2905 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2907 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2908 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2909 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2910 assert json_response(conn, 200) |> length() == 3
2914 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2916 user = insert(:user)
2918 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2919 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2920 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2922 insert(:note_activity, user: user, published: date1)
2923 insert(:note_activity, user: user, published: date2)
2924 insert(:note_activity, user: user, published: date3)
2929 test "renders user's statuses", %{conn: conn, user: user} do
2930 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2932 assert json_response(conn, 200) |> length() == 3
2935 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2936 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2938 assert json_response(conn, 200) |> length() == 2
2941 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2942 {:ok, _private_status} =
2943 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2945 {:ok, _public_status} =
2946 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2948 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2950 assert json_response(conn, 200) |> length() == 4
2953 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2954 {:ok, _private_status} =
2955 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2957 {:ok, _public_status} =
2958 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2960 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2962 assert json_response(conn, 200) |> length() == 5
2965 test "excludes reblogs by default", %{conn: conn, user: user} do
2966 other_user = insert(:user)
2967 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2968 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2970 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2971 assert json_response(conn_res, 200) |> length() == 0
2974 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2976 assert json_response(conn_res, 200) |> length() == 1
2980 describe "GET /api/pleroma/admin/moderation_log" do
2982 moderator = insert(:user, is_moderator: true)
2984 %{moderator: moderator}
2987 test "returns the log", %{conn: conn, admin: admin} do
2988 Repo.insert(%ModerationLog{
2992 "nickname" => admin.nickname,
2995 action: "relay_follow",
2996 target: "https://example.org/relay"
2998 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3001 Repo.insert(%ModerationLog{
3005 "nickname" => admin.nickname,
3008 action: "relay_unfollow",
3009 target: "https://example.org/relay"
3011 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3014 conn = get(conn, "/api/pleroma/admin/moderation_log")
3016 response = json_response(conn, 200)
3017 [first_entry, second_entry] = response["items"]
3019 assert response["total"] == 2
3020 assert first_entry["data"]["action"] == "relay_unfollow"
3022 assert first_entry["message"] ==
3023 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3025 assert second_entry["data"]["action"] == "relay_follow"
3027 assert second_entry["message"] ==
3028 "@#{admin.nickname} followed relay: https://example.org/relay"
3031 test "returns the log with pagination", %{conn: conn, admin: admin} do
3032 Repo.insert(%ModerationLog{
3036 "nickname" => admin.nickname,
3039 action: "relay_follow",
3040 target: "https://example.org/relay"
3042 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3045 Repo.insert(%ModerationLog{
3049 "nickname" => admin.nickname,
3052 action: "relay_unfollow",
3053 target: "https://example.org/relay"
3055 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3058 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3060 response1 = json_response(conn1, 200)
3061 [first_entry] = response1["items"]
3063 assert response1["total"] == 2
3064 assert response1["items"] |> length() == 1
3065 assert first_entry["data"]["action"] == "relay_unfollow"
3067 assert first_entry["message"] ==
3068 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3070 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3072 response2 = json_response(conn2, 200)
3073 [second_entry] = response2["items"]
3075 assert response2["total"] == 2
3076 assert response2["items"] |> length() == 1
3077 assert second_entry["data"]["action"] == "relay_follow"
3079 assert second_entry["message"] ==
3080 "@#{admin.nickname} followed relay: https://example.org/relay"
3083 test "filters log by date", %{conn: conn, admin: admin} do
3084 first_date = "2017-08-15T15:47:06Z"
3085 second_date = "2017-08-20T15:47:06Z"
3087 Repo.insert(%ModerationLog{
3091 "nickname" => admin.nickname,
3094 action: "relay_follow",
3095 target: "https://example.org/relay"
3097 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3100 Repo.insert(%ModerationLog{
3104 "nickname" => admin.nickname,
3107 action: "relay_unfollow",
3108 target: "https://example.org/relay"
3110 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3116 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3119 response1 = json_response(conn1, 200)
3120 [first_entry] = response1["items"]
3122 assert response1["total"] == 1
3123 assert first_entry["data"]["action"] == "relay_unfollow"
3125 assert first_entry["message"] ==
3126 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3129 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3130 Repo.insert(%ModerationLog{
3134 "nickname" => admin.nickname,
3137 action: "relay_follow",
3138 target: "https://example.org/relay"
3142 Repo.insert(%ModerationLog{
3145 "id" => moderator.id,
3146 "nickname" => moderator.nickname,
3149 action: "relay_unfollow",
3150 target: "https://example.org/relay"
3154 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3156 response1 = json_response(conn1, 200)
3157 [first_entry] = response1["items"]
3159 assert response1["total"] == 1
3160 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3163 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3164 ModerationLog.insert_log(%{
3166 action: "relay_follow",
3167 target: "https://example.org/relay"
3170 ModerationLog.insert_log(%{
3172 action: "relay_unfollow",
3173 target: "https://example.org/relay"
3176 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3178 response1 = json_response(conn1, 200)
3179 [first_entry] = response1["items"]
3181 assert response1["total"] == 1
3183 assert get_in(first_entry, ["data", "message"]) ==
3184 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3188 describe "GET /users/:nickname/credentials" do
3189 test "gets the user credentials", %{conn: conn} do
3190 user = insert(:user)
3191 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3193 response = assert json_response(conn, 200)
3194 assert response["email"] == user.email
3197 test "returns 403 if requested by a non-admin" do
3198 user = insert(:user)
3202 |> assign(:user, user)
3203 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3205 assert json_response(conn, :forbidden)
3209 describe "PATCH /users/:nickname/credentials" do
3210 test "changes password and email", %{conn: conn, admin: admin} do
3211 user = insert(:user)
3212 assert user.password_reset_pending == false
3215 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3216 "password" => "new_password",
3217 "email" => "new_email@example.com",
3218 "name" => "new_name"
3221 assert json_response(conn, 200) == %{"status" => "success"}
3223 ObanHelpers.perform_all()
3225 updated_user = User.get_by_id(user.id)
3227 assert updated_user.email == "new_email@example.com"
3228 assert updated_user.name == "new_name"
3229 assert updated_user.password_hash != user.password_hash
3230 assert updated_user.password_reset_pending == true
3232 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3234 assert ModerationLog.get_log_entry_message(log_entry1) ==
3235 "@#{admin.nickname} updated users: @#{user.nickname}"
3237 assert ModerationLog.get_log_entry_message(log_entry2) ==
3238 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3241 test "returns 403 if requested by a non-admin" do
3242 user = insert(:user)
3246 |> assign(:user, user)
3247 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3248 "password" => "new_password",
3249 "email" => "new_email@example.com",
3250 "name" => "new_name"
3253 assert json_response(conn, :forbidden)
3257 describe "PATCH /users/:nickname/force_password_reset" do
3258 test "sets password_reset_pending to true", %{conn: conn} do
3259 user = insert(:user)
3260 assert user.password_reset_pending == false
3263 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3265 assert json_response(conn, 204) == ""
3267 ObanHelpers.perform_all()
3269 assert User.get_by_id(user.id).password_reset_pending == true
3273 describe "relays" do
3274 test "POST /relay", %{conn: conn, admin: admin} do
3276 post(conn, "/api/pleroma/admin/relay", %{
3277 relay_url: "http://mastodon.example.org/users/admin"
3280 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3282 log_entry = Repo.one(ModerationLog)
3284 assert ModerationLog.get_log_entry_message(log_entry) ==
3285 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3288 test "GET /relay", %{conn: conn} do
3289 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3291 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3292 |> Enum.each(fn ap_id ->
3293 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3294 User.follow(relay_user, user)
3297 conn = get(conn, "/api/pleroma/admin/relay")
3299 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3302 test "DELETE /relay", %{conn: conn, admin: admin} do
3303 post(conn, "/api/pleroma/admin/relay", %{
3304 relay_url: "http://mastodon.example.org/users/admin"
3308 delete(conn, "/api/pleroma/admin/relay", %{
3309 relay_url: "http://mastodon.example.org/users/admin"
3312 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3314 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3316 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3317 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3319 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3320 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3324 describe "instances" do
3325 test "GET /instances/:instance/statuses", %{conn: conn} do
3326 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3327 user2 = insert(:user, local: false, nickname: "test@test.com")
3328 insert_pair(:note_activity, user: user)
3329 activity = insert(:note_activity, user: user2)
3331 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3333 response = json_response(ret_conn, 200)
3335 assert length(response) == 2
3337 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3339 response = json_response(ret_conn, 200)
3341 assert length(response) == 1
3343 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3345 response = json_response(ret_conn, 200)
3347 assert Enum.empty?(response)
3349 CommonAPI.repeat(activity.id, user)
3351 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3352 response = json_response(ret_conn, 200)
3353 assert length(response) == 2
3355 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3356 response = json_response(ret_conn, 200)
3357 assert length(response) == 3
3361 describe "PATCH /confirm_email" do
3362 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3363 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3365 assert first_user.confirmation_pending == true
3366 assert second_user.confirmation_pending == true
3369 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3371 first_user.nickname,
3372 second_user.nickname
3376 assert ret_conn.status == 200
3378 assert first_user.confirmation_pending == true
3379 assert second_user.confirmation_pending == true
3381 log_entry = Repo.one(ModerationLog)
3383 assert ModerationLog.get_log_entry_message(log_entry) ==
3384 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3385 second_user.nickname
3390 describe "PATCH /resend_confirmation_email" do
3391 test "it resend emails for two users", %{conn: conn, admin: admin} do
3392 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3395 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3397 first_user.nickname,
3398 second_user.nickname
3402 assert ret_conn.status == 200
3404 log_entry = Repo.one(ModerationLog)
3406 assert ModerationLog.get_log_entry_message(log_entry) ==
3407 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3408 second_user.nickname
3413 describe "POST /reports/:id/notes" do
3414 setup %{conn: conn, admin: admin} do
3415 [reporter, target_user] = insert_pair(:user)
3416 activity = insert(:note_activity, user: target_user)
3418 {:ok, %{id: report_id}} =
3419 CommonAPI.report(reporter, %{
3420 "account_id" => target_user.id,
3421 "comment" => "I feel offended",
3422 "status_ids" => [activity.id]
3425 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3426 content: "this is disgusting!"
3429 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3430 content: "this is disgusting2!"
3435 report_id: report_id
3439 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3440 [note, _] = Repo.all(ReportNote)
3443 activity_id: ^report_id,
3444 content: "this is disgusting!",
3449 test "it returns reports with notes", %{conn: conn, admin: admin} do
3450 conn = get(conn, "/api/pleroma/admin/reports")
3452 response = json_response(conn, 200)
3453 notes = hd(response["reports"])["notes"]
3456 assert note["user"]["nickname"] == admin.nickname
3457 assert note["content"] == "this is disgusting!"
3458 assert note["created_at"]
3459 assert response["total"] == 1
3462 test "it deletes the note", %{conn: conn, report_id: report_id} do
3463 assert ReportNote |> Repo.all() |> length() == 2
3465 [note, _] = Repo.all(ReportNote)
3467 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3469 assert ReportNote |> Repo.all() |> length() == 1
3473 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3474 admin = insert(:user, is_admin: true)
3477 assign(conn, :user, admin)
3478 |> get("/api/pleroma/admin/config/descriptions")
3480 assert [child | _others] = json_response(conn, 200)
3482 assert child["children"]
3484 assert String.starts_with?(child["group"], ":")
3485 assert child["description"]
3488 describe "/api/pleroma/admin/stats" do
3489 test "status visibility count", %{conn: conn} do
3490 admin = insert(:user, is_admin: true)
3491 user = insert(:user)
3492 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3493 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3494 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3498 |> assign(:user, admin)
3499 |> get("/api/pleroma/admin/stats")
3500 |> json_response(200)
3502 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3503 response["status_visibility"]
3508 # Needed for testing
3509 defmodule Pleroma.Web.Endpoint.NotReal do
3512 defmodule Pleroma.Captcha.NotReal do