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
2407 adapter = Application.get_env(:tesla, :adapter)
2408 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2411 post(conn, "/api/pleroma/admin/config", %{
2414 "group" => ":pleroma",
2415 "key" => "Pleroma.Captcha.NotReal",
2417 %{"tuple" => [":enabled", false]},
2418 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2419 %{"tuple" => [":seconds_valid", 60]},
2420 %{"tuple" => [":path", ""]},
2421 %{"tuple" => [":key1", nil]},
2422 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2423 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2424 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2425 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2426 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2427 %{"tuple" => [":name", "Pleroma"]}
2431 "group" => ":tesla",
2432 "key" => ":adapter",
2433 "value" => "Tesla.Adapter.Httpc"
2438 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2439 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2441 assert json_response(conn, 200) == %{
2444 "group" => ":pleroma",
2445 "key" => "Pleroma.Captcha.NotReal",
2447 %{"tuple" => [":enabled", false]},
2448 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2449 %{"tuple" => [":seconds_valid", 60]},
2450 %{"tuple" => [":path", ""]},
2451 %{"tuple" => [":key1", nil]},
2452 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2453 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2454 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2455 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2456 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2457 %{"tuple" => [":name", "Pleroma"]}
2474 "group" => ":tesla",
2475 "key" => ":adapter",
2476 "value" => "Tesla.Adapter.Httpc",
2477 "db" => [":adapter"]
2483 test "tuples with more than two values", %{conn: conn} do
2485 post(conn, "/api/pleroma/admin/config", %{
2488 "group" => ":pleroma",
2489 "key" => "Pleroma.Web.Endpoint.NotReal",
2505 "/api/v1/streaming",
2506 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2513 "Phoenix.Endpoint.CowboyWebSocket",
2516 "Phoenix.Transports.WebSocket",
2519 "Pleroma.Web.Endpoint",
2520 "Pleroma.Web.UserSocket",
2531 "Phoenix.Endpoint.Cowboy2Handler",
2532 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2549 assert json_response(conn, 200) == %{
2552 "group" => ":pleroma",
2553 "key" => "Pleroma.Web.Endpoint.NotReal",
2569 "/api/v1/streaming",
2570 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2577 "Phoenix.Endpoint.CowboyWebSocket",
2580 "Phoenix.Transports.WebSocket",
2583 "Pleroma.Web.Endpoint",
2584 "Pleroma.Web.UserSocket",
2595 "Phoenix.Endpoint.Cowboy2Handler",
2596 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2615 test "settings with nesting map", %{conn: conn} do
2617 post(conn, "/api/pleroma/admin/config", %{
2620 "group" => ":pleroma",
2623 %{"tuple" => [":key2", "some_val"]},
2628 ":max_options" => 20,
2629 ":max_option_chars" => 200,
2630 ":min_expiration" => 0,
2631 ":max_expiration" => 31_536_000,
2633 ":max_options" => 20,
2634 ":max_option_chars" => 200,
2635 ":min_expiration" => 0,
2636 ":max_expiration" => 31_536_000
2646 assert json_response(conn, 200) ==
2650 "group" => ":pleroma",
2653 %{"tuple" => [":key2", "some_val"]},
2658 ":max_expiration" => 31_536_000,
2659 ":max_option_chars" => 200,
2660 ":max_options" => 20,
2661 ":min_expiration" => 0,
2663 ":max_expiration" => 31_536_000,
2664 ":max_option_chars" => 200,
2665 ":max_options" => 20,
2666 ":min_expiration" => 0
2672 "db" => [":key2", ":key3"]
2678 test "value as map", %{conn: conn} do
2680 post(conn, "/api/pleroma/admin/config", %{
2683 "group" => ":pleroma",
2685 "value" => %{"key" => "some_val"}
2690 assert json_response(conn, 200) ==
2694 "group" => ":pleroma",
2696 "value" => %{"key" => "some_val"},
2703 test "queues key as atom", %{conn: conn} do
2705 post(conn, "/api/pleroma/admin/config", %{
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]}
2723 assert json_response(conn, 200) == %{
2729 %{"tuple" => [":federator_incoming", 50]},
2730 %{"tuple" => [":federator_outgoing", 50]},
2731 %{"tuple" => [":web_push", 50]},
2732 %{"tuple" => [":mailer", 10]},
2733 %{"tuple" => [":transmogrifier", 20]},
2734 %{"tuple" => [":scheduled_activities", 10]},
2735 %{"tuple" => [":background", 5]}
2738 ":federator_incoming",
2739 ":federator_outgoing",
2743 ":scheduled_activities",
2751 test "delete part of settings by atom subkeys", %{conn: conn} do
2755 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2759 post(conn, "/api/pleroma/admin/config", %{
2762 group: config.group,
2764 subkeys: [":subkey1", ":subkey3"],
2770 assert json_response(conn, 200) == %{
2773 "group" => ":pleroma",
2775 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2776 "db" => [":subkey2"]
2782 test "proxy tuple localhost", %{conn: conn} do
2784 post(conn, "/api/pleroma/admin/config", %{
2790 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2791 %{"tuple" => [":send_user_agent", false]}
2797 assert json_response(conn, 200) == %{
2800 "group" => ":pleroma",
2803 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2804 %{"tuple" => [":send_user_agent", false]}
2806 "db" => [":proxy_url", ":send_user_agent"]
2812 test "proxy tuple domain", %{conn: conn} do
2814 post(conn, "/api/pleroma/admin/config", %{
2820 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2821 %{"tuple" => [":send_user_agent", false]}
2827 assert json_response(conn, 200) == %{
2830 "group" => ":pleroma",
2833 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2834 %{"tuple" => [":send_user_agent", false]}
2836 "db" => [":proxy_url", ":send_user_agent"]
2842 test "proxy tuple ip", %{conn: conn} do
2844 post(conn, "/api/pleroma/admin/config", %{
2850 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2851 %{"tuple" => [":send_user_agent", false]}
2857 assert json_response(conn, 200) == %{
2860 "group" => ":pleroma",
2863 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2864 %{"tuple" => [":send_user_agent", false]}
2866 "db" => [":proxy_url", ":send_user_agent"]
2873 describe "GET /api/pleroma/admin/restart" do
2874 setup do: clear_config(:configurable_from_database, true)
2876 test "pleroma restarts", %{conn: conn} do
2878 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2879 end) =~ "pleroma restarted"
2881 refute Restarter.Pleroma.need_reboot?()
2885 describe "GET /api/pleroma/admin/statuses" do
2886 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2887 blocked = insert(:user)
2888 user = insert(:user)
2889 User.block(admin, blocked)
2892 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2894 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2895 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2896 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2897 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2901 |> get("/api/pleroma/admin/statuses")
2902 |> json_response(200)
2904 refute "private" in Enum.map(response, & &1["visibility"])
2905 assert length(response) == 3
2908 test "returns only local statuses with local_only on", %{conn: conn} do
2909 user = insert(:user)
2910 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2911 insert(:note_activity, user: user, local: true)
2912 insert(:note_activity, user: remote_user, local: false)
2916 |> get("/api/pleroma/admin/statuses?local_only=true")
2917 |> json_response(200)
2919 assert length(response) == 1
2922 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2923 user = insert(:user)
2926 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2928 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2929 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2930 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2931 assert json_response(conn, 200) |> length() == 3
2935 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2937 user = insert(:user)
2939 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2940 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2941 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2943 insert(:note_activity, user: user, published: date1)
2944 insert(:note_activity, user: user, published: date2)
2945 insert(:note_activity, user: user, published: date3)
2950 test "renders user's statuses", %{conn: conn, user: user} do
2951 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2953 assert json_response(conn, 200) |> length() == 3
2956 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2957 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2959 assert json_response(conn, 200) |> length() == 2
2962 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2963 {:ok, _private_status} =
2964 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2966 {:ok, _public_status} =
2967 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2969 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2971 assert json_response(conn, 200) |> length() == 4
2974 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2975 {:ok, _private_status} =
2976 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2978 {:ok, _public_status} =
2979 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2981 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2983 assert json_response(conn, 200) |> length() == 5
2986 test "excludes reblogs by default", %{conn: conn, user: user} do
2987 other_user = insert(:user)
2988 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2989 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2991 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2992 assert json_response(conn_res, 200) |> length() == 0
2995 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2997 assert json_response(conn_res, 200) |> length() == 1
3001 describe "GET /api/pleroma/admin/moderation_log" do
3003 moderator = insert(:user, is_moderator: true)
3005 %{moderator: moderator}
3008 test "returns the log", %{conn: conn, admin: admin} do
3009 Repo.insert(%ModerationLog{
3013 "nickname" => admin.nickname,
3016 action: "relay_follow",
3017 target: "https://example.org/relay"
3019 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3022 Repo.insert(%ModerationLog{
3026 "nickname" => admin.nickname,
3029 action: "relay_unfollow",
3030 target: "https://example.org/relay"
3032 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3035 conn = get(conn, "/api/pleroma/admin/moderation_log")
3037 response = json_response(conn, 200)
3038 [first_entry, second_entry] = response["items"]
3040 assert response["total"] == 2
3041 assert first_entry["data"]["action"] == "relay_unfollow"
3043 assert first_entry["message"] ==
3044 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3046 assert second_entry["data"]["action"] == "relay_follow"
3048 assert second_entry["message"] ==
3049 "@#{admin.nickname} followed relay: https://example.org/relay"
3052 test "returns the log with pagination", %{conn: conn, admin: admin} do
3053 Repo.insert(%ModerationLog{
3057 "nickname" => admin.nickname,
3060 action: "relay_follow",
3061 target: "https://example.org/relay"
3063 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3066 Repo.insert(%ModerationLog{
3070 "nickname" => admin.nickname,
3073 action: "relay_unfollow",
3074 target: "https://example.org/relay"
3076 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3079 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3081 response1 = json_response(conn1, 200)
3082 [first_entry] = response1["items"]
3084 assert response1["total"] == 2
3085 assert response1["items"] |> length() == 1
3086 assert first_entry["data"]["action"] == "relay_unfollow"
3088 assert first_entry["message"] ==
3089 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3091 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3093 response2 = json_response(conn2, 200)
3094 [second_entry] = response2["items"]
3096 assert response2["total"] == 2
3097 assert response2["items"] |> length() == 1
3098 assert second_entry["data"]["action"] == "relay_follow"
3100 assert second_entry["message"] ==
3101 "@#{admin.nickname} followed relay: https://example.org/relay"
3104 test "filters log by date", %{conn: conn, admin: admin} do
3105 first_date = "2017-08-15T15:47:06Z"
3106 second_date = "2017-08-20T15:47:06Z"
3108 Repo.insert(%ModerationLog{
3112 "nickname" => admin.nickname,
3115 action: "relay_follow",
3116 target: "https://example.org/relay"
3118 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3121 Repo.insert(%ModerationLog{
3125 "nickname" => admin.nickname,
3128 action: "relay_unfollow",
3129 target: "https://example.org/relay"
3131 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3137 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3140 response1 = json_response(conn1, 200)
3141 [first_entry] = response1["items"]
3143 assert response1["total"] == 1
3144 assert first_entry["data"]["action"] == "relay_unfollow"
3146 assert first_entry["message"] ==
3147 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3150 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3151 Repo.insert(%ModerationLog{
3155 "nickname" => admin.nickname,
3158 action: "relay_follow",
3159 target: "https://example.org/relay"
3163 Repo.insert(%ModerationLog{
3166 "id" => moderator.id,
3167 "nickname" => moderator.nickname,
3170 action: "relay_unfollow",
3171 target: "https://example.org/relay"
3175 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3177 response1 = json_response(conn1, 200)
3178 [first_entry] = response1["items"]
3180 assert response1["total"] == 1
3181 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3184 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3185 ModerationLog.insert_log(%{
3187 action: "relay_follow",
3188 target: "https://example.org/relay"
3191 ModerationLog.insert_log(%{
3193 action: "relay_unfollow",
3194 target: "https://example.org/relay"
3197 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3199 response1 = json_response(conn1, 200)
3200 [first_entry] = response1["items"]
3202 assert response1["total"] == 1
3204 assert get_in(first_entry, ["data", "message"]) ==
3205 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3209 describe "GET /users/:nickname/credentials" do
3210 test "gets the user credentials", %{conn: conn} do
3211 user = insert(:user)
3212 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3214 response = assert json_response(conn, 200)
3215 assert response["email"] == user.email
3218 test "returns 403 if requested by a non-admin" do
3219 user = insert(:user)
3223 |> assign(:user, user)
3224 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3226 assert json_response(conn, :forbidden)
3230 describe "PATCH /users/:nickname/credentials" do
3231 test "changes password and email", %{conn: conn, admin: admin} do
3232 user = insert(:user)
3233 assert user.password_reset_pending == false
3236 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3237 "password" => "new_password",
3238 "email" => "new_email@example.com",
3239 "name" => "new_name"
3242 assert json_response(conn, 200) == %{"status" => "success"}
3244 ObanHelpers.perform_all()
3246 updated_user = User.get_by_id(user.id)
3248 assert updated_user.email == "new_email@example.com"
3249 assert updated_user.name == "new_name"
3250 assert updated_user.password_hash != user.password_hash
3251 assert updated_user.password_reset_pending == true
3253 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3255 assert ModerationLog.get_log_entry_message(log_entry1) ==
3256 "@#{admin.nickname} updated users: @#{user.nickname}"
3258 assert ModerationLog.get_log_entry_message(log_entry2) ==
3259 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3262 test "returns 403 if requested by a non-admin" do
3263 user = insert(:user)
3267 |> assign(:user, user)
3268 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3269 "password" => "new_password",
3270 "email" => "new_email@example.com",
3271 "name" => "new_name"
3274 assert json_response(conn, :forbidden)
3278 describe "PATCH /users/:nickname/force_password_reset" do
3279 test "sets password_reset_pending to true", %{conn: conn} do
3280 user = insert(:user)
3281 assert user.password_reset_pending == false
3284 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3286 assert json_response(conn, 204) == ""
3288 ObanHelpers.perform_all()
3290 assert User.get_by_id(user.id).password_reset_pending == true
3294 describe "relays" do
3295 test "POST /relay", %{conn: conn, admin: admin} do
3297 post(conn, "/api/pleroma/admin/relay", %{
3298 relay_url: "http://mastodon.example.org/users/admin"
3301 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3303 log_entry = Repo.one(ModerationLog)
3305 assert ModerationLog.get_log_entry_message(log_entry) ==
3306 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3309 test "GET /relay", %{conn: conn} do
3310 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3312 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3313 |> Enum.each(fn ap_id ->
3314 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3315 User.follow(relay_user, user)
3318 conn = get(conn, "/api/pleroma/admin/relay")
3320 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3323 test "DELETE /relay", %{conn: conn, admin: admin} do
3324 post(conn, "/api/pleroma/admin/relay", %{
3325 relay_url: "http://mastodon.example.org/users/admin"
3329 delete(conn, "/api/pleroma/admin/relay", %{
3330 relay_url: "http://mastodon.example.org/users/admin"
3333 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3335 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3337 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3338 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3340 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3341 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3345 describe "instances" do
3346 test "GET /instances/:instance/statuses", %{conn: conn} do
3347 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3348 user2 = insert(:user, local: false, nickname: "test@test.com")
3349 insert_pair(:note_activity, user: user)
3350 activity = insert(:note_activity, user: user2)
3352 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3354 response = json_response(ret_conn, 200)
3356 assert length(response) == 2
3358 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3360 response = json_response(ret_conn, 200)
3362 assert length(response) == 1
3364 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3366 response = json_response(ret_conn, 200)
3368 assert Enum.empty?(response)
3370 CommonAPI.repeat(activity.id, user)
3372 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3373 response = json_response(ret_conn, 200)
3374 assert length(response) == 2
3376 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3377 response = json_response(ret_conn, 200)
3378 assert length(response) == 3
3382 describe "PATCH /confirm_email" do
3383 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3384 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3386 assert first_user.confirmation_pending == true
3387 assert second_user.confirmation_pending == true
3390 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3392 first_user.nickname,
3393 second_user.nickname
3397 assert ret_conn.status == 200
3399 assert first_user.confirmation_pending == true
3400 assert second_user.confirmation_pending == true
3402 log_entry = Repo.one(ModerationLog)
3404 assert ModerationLog.get_log_entry_message(log_entry) ==
3405 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3406 second_user.nickname
3411 describe "PATCH /resend_confirmation_email" do
3412 test "it resend emails for two users", %{conn: conn, admin: admin} do
3413 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3416 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3418 first_user.nickname,
3419 second_user.nickname
3423 assert ret_conn.status == 200
3425 log_entry = Repo.one(ModerationLog)
3427 assert ModerationLog.get_log_entry_message(log_entry) ==
3428 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3429 second_user.nickname
3434 describe "POST /reports/:id/notes" do
3435 setup %{conn: conn, admin: admin} do
3436 [reporter, target_user] = insert_pair(:user)
3437 activity = insert(:note_activity, user: target_user)
3439 {:ok, %{id: report_id}} =
3440 CommonAPI.report(reporter, %{
3441 "account_id" => target_user.id,
3442 "comment" => "I feel offended",
3443 "status_ids" => [activity.id]
3446 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3447 content: "this is disgusting!"
3450 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3451 content: "this is disgusting2!"
3456 report_id: report_id
3460 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3461 [note, _] = Repo.all(ReportNote)
3464 activity_id: ^report_id,
3465 content: "this is disgusting!",
3470 test "it returns reports with notes", %{conn: conn, admin: admin} do
3471 conn = get(conn, "/api/pleroma/admin/reports")
3473 response = json_response(conn, 200)
3474 notes = hd(response["reports"])["notes"]
3477 assert note["user"]["nickname"] == admin.nickname
3478 assert note["content"] == "this is disgusting!"
3479 assert note["created_at"]
3480 assert response["total"] == 1
3483 test "it deletes the note", %{conn: conn, report_id: report_id} do
3484 assert ReportNote |> Repo.all() |> length() == 2
3486 [note, _] = Repo.all(ReportNote)
3488 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3490 assert ReportNote |> Repo.all() |> length() == 1
3494 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3495 admin = insert(:user, is_admin: true)
3498 assign(conn, :user, admin)
3499 |> get("/api/pleroma/admin/config/descriptions")
3501 assert [child | _others] = json_response(conn, 200)
3503 assert child["children"]
3505 assert String.starts_with?(child["group"], ":")
3506 assert child["description"]
3509 describe "/api/pleroma/admin/stats" do
3510 test "status visibility count", %{conn: conn} do
3511 admin = insert(:user, is_admin: true)
3512 user = insert(:user)
3513 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3514 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3515 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3519 |> assign(:user, admin)
3520 |> get("/api/pleroma/admin/stats")
3521 |> json_response(200)
3523 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3524 response["status_visibility"]
3529 # Needed for testing
3530 defmodule Pleroma.Web.Endpoint.NotReal do
3533 defmodule Pleroma.Captcha.NotReal do