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([])
2277 post(conn, "/api/pleroma/admin/config", %{
2280 group: config.group,
2282 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2287 assert json_response(conn, 200) == %{
2290 "group" => ":logger",
2291 "key" => ":backends",
2294 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2296 "db" => [":backends"]
2301 assert Application.get_env(:logger, :backends) == [
2303 {ExSyslogger, :ex_syslogger}
2308 Logger.warn("Ooops...")
2312 test "saving full setting if value is not keyword", %{conn: conn} do
2317 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2321 post(conn, "/api/pleroma/admin/config", %{
2323 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2327 assert json_response(conn, 200) == %{
2330 "group" => ":tesla",
2331 "key" => ":adapter",
2332 "value" => "Tesla.Adapter.Httpc",
2333 "db" => [":adapter"]
2339 test "update config setting & delete with fallback to default value", %{
2344 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2345 config1 = insert(:config, key: ":keyaa1")
2346 config2 = insert(:config, key: ":keyaa2")
2350 group: ":ueberauth",
2355 post(conn, "/api/pleroma/admin/config", %{
2357 %{group: config1.group, key: config1.key, value: "another_value"},
2358 %{group: config2.group, key: config2.key, value: "another_value"}
2362 assert json_response(conn, 200) == %{
2365 "group" => ":pleroma",
2366 "key" => config1.key,
2367 "value" => "another_value",
2371 "group" => ":pleroma",
2372 "key" => config2.key,
2373 "value" => "another_value",
2379 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2380 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2381 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2385 |> assign(:user, admin)
2386 |> assign(:token, token)
2387 |> post("/api/pleroma/admin/config", %{
2389 %{group: config2.group, key: config2.key, delete: true},
2391 group: ":ueberauth",
2398 assert json_response(conn, 200) == %{
2402 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2403 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2406 test "common config example", %{conn: conn} do
2408 post(conn, "/api/pleroma/admin/config", %{
2411 "group" => ":pleroma",
2412 "key" => "Pleroma.Captcha.NotReal",
2414 %{"tuple" => [":enabled", false]},
2415 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2416 %{"tuple" => [":seconds_valid", 60]},
2417 %{"tuple" => [":path", ""]},
2418 %{"tuple" => [":key1", nil]},
2419 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2420 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2421 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2422 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2423 %{"tuple" => [":name", "Pleroma"]}
2429 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2431 assert json_response(conn, 200) == %{
2434 "group" => ":pleroma",
2435 "key" => "Pleroma.Captcha.NotReal",
2437 %{"tuple" => [":enabled", false]},
2438 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2439 %{"tuple" => [":seconds_valid", 60]},
2440 %{"tuple" => [":path", ""]},
2441 %{"tuple" => [":key1", nil]},
2442 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2443 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2444 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2445 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2446 %{"tuple" => [":name", "Pleroma"]}
2465 test "tuples with more than two values", %{conn: conn} do
2467 post(conn, "/api/pleroma/admin/config", %{
2470 "group" => ":pleroma",
2471 "key" => "Pleroma.Web.Endpoint.NotReal",
2487 "/api/v1/streaming",
2488 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2495 "Phoenix.Endpoint.CowboyWebSocket",
2498 "Phoenix.Transports.WebSocket",
2501 "Pleroma.Web.Endpoint",
2502 "Pleroma.Web.UserSocket",
2513 "Phoenix.Endpoint.Cowboy2Handler",
2514 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2531 assert json_response(conn, 200) == %{
2534 "group" => ":pleroma",
2535 "key" => "Pleroma.Web.Endpoint.NotReal",
2551 "/api/v1/streaming",
2552 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2559 "Phoenix.Endpoint.CowboyWebSocket",
2562 "Phoenix.Transports.WebSocket",
2565 "Pleroma.Web.Endpoint",
2566 "Pleroma.Web.UserSocket",
2577 "Phoenix.Endpoint.Cowboy2Handler",
2578 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2597 test "settings with nesting map", %{conn: conn} do
2599 post(conn, "/api/pleroma/admin/config", %{
2602 "group" => ":pleroma",
2605 %{"tuple" => [":key2", "some_val"]},
2610 ":max_options" => 20,
2611 ":max_option_chars" => 200,
2612 ":min_expiration" => 0,
2613 ":max_expiration" => 31_536_000,
2615 ":max_options" => 20,
2616 ":max_option_chars" => 200,
2617 ":min_expiration" => 0,
2618 ":max_expiration" => 31_536_000
2628 assert json_response(conn, 200) ==
2632 "group" => ":pleroma",
2635 %{"tuple" => [":key2", "some_val"]},
2640 ":max_expiration" => 31_536_000,
2641 ":max_option_chars" => 200,
2642 ":max_options" => 20,
2643 ":min_expiration" => 0,
2645 ":max_expiration" => 31_536_000,
2646 ":max_option_chars" => 200,
2647 ":max_options" => 20,
2648 ":min_expiration" => 0
2654 "db" => [":key2", ":key3"]
2660 test "value as map", %{conn: conn} do
2662 post(conn, "/api/pleroma/admin/config", %{
2665 "group" => ":pleroma",
2667 "value" => %{"key" => "some_val"}
2672 assert json_response(conn, 200) ==
2676 "group" => ":pleroma",
2678 "value" => %{"key" => "some_val"},
2685 test "queues key as atom", %{conn: conn} do
2687 post(conn, "/api/pleroma/admin/config", %{
2693 %{"tuple" => [":federator_incoming", 50]},
2694 %{"tuple" => [":federator_outgoing", 50]},
2695 %{"tuple" => [":web_push", 50]},
2696 %{"tuple" => [":mailer", 10]},
2697 %{"tuple" => [":transmogrifier", 20]},
2698 %{"tuple" => [":scheduled_activities", 10]},
2699 %{"tuple" => [":background", 5]}
2705 assert json_response(conn, 200) == %{
2711 %{"tuple" => [":federator_incoming", 50]},
2712 %{"tuple" => [":federator_outgoing", 50]},
2713 %{"tuple" => [":web_push", 50]},
2714 %{"tuple" => [":mailer", 10]},
2715 %{"tuple" => [":transmogrifier", 20]},
2716 %{"tuple" => [":scheduled_activities", 10]},
2717 %{"tuple" => [":background", 5]}
2720 ":federator_incoming",
2721 ":federator_outgoing",
2725 ":scheduled_activities",
2733 test "delete part of settings by atom subkeys", %{conn: conn} do
2737 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2741 post(conn, "/api/pleroma/admin/config", %{
2744 group: config.group,
2746 subkeys: [":subkey1", ":subkey3"],
2752 assert json_response(conn, 200) == %{
2755 "group" => ":pleroma",
2757 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2758 "db" => [":subkey2"]
2764 test "proxy tuple localhost", %{conn: conn} do
2766 post(conn, "/api/pleroma/admin/config", %{
2772 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2773 %{"tuple" => [":send_user_agent", false]}
2779 assert json_response(conn, 200) == %{
2782 "group" => ":pleroma",
2785 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2786 %{"tuple" => [":send_user_agent", false]}
2788 "db" => [":proxy_url", ":send_user_agent"]
2794 test "proxy tuple domain", %{conn: conn} do
2796 post(conn, "/api/pleroma/admin/config", %{
2802 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2803 %{"tuple" => [":send_user_agent", false]}
2809 assert json_response(conn, 200) == %{
2812 "group" => ":pleroma",
2815 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2816 %{"tuple" => [":send_user_agent", false]}
2818 "db" => [":proxy_url", ":send_user_agent"]
2824 test "proxy tuple ip", %{conn: conn} do
2826 post(conn, "/api/pleroma/admin/config", %{
2832 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2833 %{"tuple" => [":send_user_agent", false]}
2839 assert json_response(conn, 200) == %{
2842 "group" => ":pleroma",
2845 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2846 %{"tuple" => [":send_user_agent", false]}
2848 "db" => [":proxy_url", ":send_user_agent"]
2855 describe "GET /api/pleroma/admin/restart" do
2856 setup do: clear_config(:configurable_from_database, true)
2858 test "pleroma restarts", %{conn: conn} do
2860 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2861 end) =~ "pleroma restarted"
2863 refute Restarter.Pleroma.need_reboot?()
2867 describe "GET /api/pleroma/admin/statuses" do
2868 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2869 blocked = insert(:user)
2870 user = insert(:user)
2871 User.block(admin, blocked)
2874 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2876 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2877 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2878 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2879 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2883 |> get("/api/pleroma/admin/statuses")
2884 |> json_response(200)
2886 refute "private" in Enum.map(response, & &1["visibility"])
2887 assert length(response) == 3
2890 test "returns only local statuses with local_only on", %{conn: conn} do
2891 user = insert(:user)
2892 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2893 insert(:note_activity, user: user, local: true)
2894 insert(:note_activity, user: remote_user, local: false)
2898 |> get("/api/pleroma/admin/statuses?local_only=true")
2899 |> json_response(200)
2901 assert length(response) == 1
2904 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2905 user = insert(:user)
2908 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2910 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2911 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2912 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2913 assert json_response(conn, 200) |> length() == 3
2917 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2919 user = insert(:user)
2921 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2922 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2923 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2925 insert(:note_activity, user: user, published: date1)
2926 insert(:note_activity, user: user, published: date2)
2927 insert(:note_activity, user: user, published: date3)
2932 test "renders user's statuses", %{conn: conn, user: user} do
2933 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2935 assert json_response(conn, 200) |> length() == 3
2938 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2939 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2941 assert json_response(conn, 200) |> length() == 2
2944 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2945 {:ok, _private_status} =
2946 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2948 {:ok, _public_status} =
2949 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2951 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2953 assert json_response(conn, 200) |> length() == 4
2956 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2957 {:ok, _private_status} =
2958 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2960 {:ok, _public_status} =
2961 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2963 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2965 assert json_response(conn, 200) |> length() == 5
2968 test "excludes reblogs by default", %{conn: conn, user: user} do
2969 other_user = insert(:user)
2970 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2971 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2973 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2974 assert json_response(conn_res, 200) |> length() == 0
2977 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2979 assert json_response(conn_res, 200) |> length() == 1
2983 describe "GET /api/pleroma/admin/moderation_log" do
2985 moderator = insert(:user, is_moderator: true)
2987 %{moderator: moderator}
2990 test "returns the log", %{conn: conn, admin: admin} do
2991 Repo.insert(%ModerationLog{
2995 "nickname" => admin.nickname,
2998 action: "relay_follow",
2999 target: "https://example.org/relay"
3001 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3004 Repo.insert(%ModerationLog{
3008 "nickname" => admin.nickname,
3011 action: "relay_unfollow",
3012 target: "https://example.org/relay"
3014 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3017 conn = get(conn, "/api/pleroma/admin/moderation_log")
3019 response = json_response(conn, 200)
3020 [first_entry, second_entry] = response["items"]
3022 assert response["total"] == 2
3023 assert first_entry["data"]["action"] == "relay_unfollow"
3025 assert first_entry["message"] ==
3026 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3028 assert second_entry["data"]["action"] == "relay_follow"
3030 assert second_entry["message"] ==
3031 "@#{admin.nickname} followed relay: https://example.org/relay"
3034 test "returns the log with pagination", %{conn: conn, admin: admin} do
3035 Repo.insert(%ModerationLog{
3039 "nickname" => admin.nickname,
3042 action: "relay_follow",
3043 target: "https://example.org/relay"
3045 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3048 Repo.insert(%ModerationLog{
3052 "nickname" => admin.nickname,
3055 action: "relay_unfollow",
3056 target: "https://example.org/relay"
3058 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3061 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3063 response1 = json_response(conn1, 200)
3064 [first_entry] = response1["items"]
3066 assert response1["total"] == 2
3067 assert response1["items"] |> length() == 1
3068 assert first_entry["data"]["action"] == "relay_unfollow"
3070 assert first_entry["message"] ==
3071 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3073 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3075 response2 = json_response(conn2, 200)
3076 [second_entry] = response2["items"]
3078 assert response2["total"] == 2
3079 assert response2["items"] |> length() == 1
3080 assert second_entry["data"]["action"] == "relay_follow"
3082 assert second_entry["message"] ==
3083 "@#{admin.nickname} followed relay: https://example.org/relay"
3086 test "filters log by date", %{conn: conn, admin: admin} do
3087 first_date = "2017-08-15T15:47:06Z"
3088 second_date = "2017-08-20T15:47:06Z"
3090 Repo.insert(%ModerationLog{
3094 "nickname" => admin.nickname,
3097 action: "relay_follow",
3098 target: "https://example.org/relay"
3100 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3103 Repo.insert(%ModerationLog{
3107 "nickname" => admin.nickname,
3110 action: "relay_unfollow",
3111 target: "https://example.org/relay"
3113 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3119 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3122 response1 = json_response(conn1, 200)
3123 [first_entry] = response1["items"]
3125 assert response1["total"] == 1
3126 assert first_entry["data"]["action"] == "relay_unfollow"
3128 assert first_entry["message"] ==
3129 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3132 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3133 Repo.insert(%ModerationLog{
3137 "nickname" => admin.nickname,
3140 action: "relay_follow",
3141 target: "https://example.org/relay"
3145 Repo.insert(%ModerationLog{
3148 "id" => moderator.id,
3149 "nickname" => moderator.nickname,
3152 action: "relay_unfollow",
3153 target: "https://example.org/relay"
3157 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3159 response1 = json_response(conn1, 200)
3160 [first_entry] = response1["items"]
3162 assert response1["total"] == 1
3163 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3166 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3167 ModerationLog.insert_log(%{
3169 action: "relay_follow",
3170 target: "https://example.org/relay"
3173 ModerationLog.insert_log(%{
3175 action: "relay_unfollow",
3176 target: "https://example.org/relay"
3179 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3181 response1 = json_response(conn1, 200)
3182 [first_entry] = response1["items"]
3184 assert response1["total"] == 1
3186 assert get_in(first_entry, ["data", "message"]) ==
3187 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3191 describe "GET /users/:nickname/credentials" do
3192 test "gets the user credentials", %{conn: conn} do
3193 user = insert(:user)
3194 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3196 response = assert json_response(conn, 200)
3197 assert response["email"] == user.email
3200 test "returns 403 if requested by a non-admin" do
3201 user = insert(:user)
3205 |> assign(:user, user)
3206 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3208 assert json_response(conn, :forbidden)
3212 describe "PATCH /users/:nickname/credentials" do
3213 test "changes password and email", %{conn: conn, admin: admin} do
3214 user = insert(:user)
3215 assert user.password_reset_pending == false
3218 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3219 "password" => "new_password",
3220 "email" => "new_email@example.com",
3221 "name" => "new_name"
3224 assert json_response(conn, 200) == %{"status" => "success"}
3226 ObanHelpers.perform_all()
3228 updated_user = User.get_by_id(user.id)
3230 assert updated_user.email == "new_email@example.com"
3231 assert updated_user.name == "new_name"
3232 assert updated_user.password_hash != user.password_hash
3233 assert updated_user.password_reset_pending == true
3235 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3237 assert ModerationLog.get_log_entry_message(log_entry1) ==
3238 "@#{admin.nickname} updated users: @#{user.nickname}"
3240 assert ModerationLog.get_log_entry_message(log_entry2) ==
3241 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3244 test "returns 403 if requested by a non-admin" do
3245 user = insert(:user)
3249 |> assign(:user, user)
3250 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3251 "password" => "new_password",
3252 "email" => "new_email@example.com",
3253 "name" => "new_name"
3256 assert json_response(conn, :forbidden)
3260 describe "PATCH /users/:nickname/force_password_reset" do
3261 test "sets password_reset_pending to true", %{conn: conn} do
3262 user = insert(:user)
3263 assert user.password_reset_pending == false
3266 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3268 assert json_response(conn, 204) == ""
3270 ObanHelpers.perform_all()
3272 assert User.get_by_id(user.id).password_reset_pending == true
3276 describe "relays" do
3277 test "POST /relay", %{conn: conn, admin: admin} do
3279 post(conn, "/api/pleroma/admin/relay", %{
3280 relay_url: "http://mastodon.example.org/users/admin"
3283 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3285 log_entry = Repo.one(ModerationLog)
3287 assert ModerationLog.get_log_entry_message(log_entry) ==
3288 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3291 test "GET /relay", %{conn: conn} do
3292 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3294 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3295 |> Enum.each(fn ap_id ->
3296 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3297 User.follow(relay_user, user)
3300 conn = get(conn, "/api/pleroma/admin/relay")
3302 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3305 test "DELETE /relay", %{conn: conn, admin: admin} do
3306 post(conn, "/api/pleroma/admin/relay", %{
3307 relay_url: "http://mastodon.example.org/users/admin"
3311 delete(conn, "/api/pleroma/admin/relay", %{
3312 relay_url: "http://mastodon.example.org/users/admin"
3315 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3317 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3319 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3320 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3322 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3323 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3327 describe "instances" do
3328 test "GET /instances/:instance/statuses", %{conn: conn} do
3329 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3330 user2 = insert(:user, local: false, nickname: "test@test.com")
3331 insert_pair(:note_activity, user: user)
3332 activity = insert(:note_activity, user: user2)
3334 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3336 response = json_response(ret_conn, 200)
3338 assert length(response) == 2
3340 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3342 response = json_response(ret_conn, 200)
3344 assert length(response) == 1
3346 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3348 response = json_response(ret_conn, 200)
3350 assert Enum.empty?(response)
3352 CommonAPI.repeat(activity.id, user)
3354 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3355 response = json_response(ret_conn, 200)
3356 assert length(response) == 2
3358 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3359 response = json_response(ret_conn, 200)
3360 assert length(response) == 3
3364 describe "PATCH /confirm_email" do
3365 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3366 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3368 assert first_user.confirmation_pending == true
3369 assert second_user.confirmation_pending == true
3372 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3374 first_user.nickname,
3375 second_user.nickname
3379 assert ret_conn.status == 200
3381 assert first_user.confirmation_pending == true
3382 assert second_user.confirmation_pending == true
3384 log_entry = Repo.one(ModerationLog)
3386 assert ModerationLog.get_log_entry_message(log_entry) ==
3387 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3388 second_user.nickname
3393 describe "PATCH /resend_confirmation_email" do
3394 test "it resend emails for two users", %{conn: conn, admin: admin} do
3395 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3398 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3400 first_user.nickname,
3401 second_user.nickname
3405 assert ret_conn.status == 200
3407 log_entry = Repo.one(ModerationLog)
3409 assert ModerationLog.get_log_entry_message(log_entry) ==
3410 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3411 second_user.nickname
3416 describe "POST /reports/:id/notes" do
3417 setup %{conn: conn, admin: admin} do
3418 [reporter, target_user] = insert_pair(:user)
3419 activity = insert(:note_activity, user: target_user)
3421 {:ok, %{id: report_id}} =
3422 CommonAPI.report(reporter, %{
3423 "account_id" => target_user.id,
3424 "comment" => "I feel offended",
3425 "status_ids" => [activity.id]
3428 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3429 content: "this is disgusting!"
3432 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3433 content: "this is disgusting2!"
3438 report_id: report_id
3442 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3443 [note, _] = Repo.all(ReportNote)
3446 activity_id: ^report_id,
3447 content: "this is disgusting!",
3452 test "it returns reports with notes", %{conn: conn, admin: admin} do
3453 conn = get(conn, "/api/pleroma/admin/reports")
3455 response = json_response(conn, 200)
3456 notes = hd(response["reports"])["notes"]
3459 assert note["user"]["nickname"] == admin.nickname
3460 assert note["content"] == "this is disgusting!"
3461 assert note["created_at"]
3462 assert response["total"] == 1
3465 test "it deletes the note", %{conn: conn, report_id: report_id} do
3466 assert ReportNote |> Repo.all() |> length() == 2
3468 [note, _] = Repo.all(ReportNote)
3470 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3472 assert ReportNote |> Repo.all() |> length() == 1
3476 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3477 admin = insert(:user, is_admin: true)
3480 assign(conn, :user, admin)
3481 |> get("/api/pleroma/admin/config/descriptions")
3483 assert [child | _others] = json_response(conn, 200)
3485 assert child["children"]
3487 assert String.starts_with?(child["group"], ":")
3488 assert child["description"]
3491 describe "/api/pleroma/admin/stats" do
3492 test "status visibility count", %{conn: conn} do
3493 admin = insert(:user, is_admin: true)
3494 user = insert(:user)
3495 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3496 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3497 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3501 |> assign(:user, admin)
3502 |> get("/api/pleroma/admin/stats")
3503 |> json_response(200)
3505 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3506 response["status_visibility"]
3511 # Needed for testing
3512 defmodule Pleroma.Web.Endpoint.NotReal do
3515 defmodule Pleroma.Captcha.NotReal do