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 "GET /api/pleroma/admin/statuses/:id" do
1624 test "not found", %{conn: conn} do
1626 |> get("/api/pleroma/admin/statuses/not_found")
1627 |> json_response(:not_found)
1630 test "shows activity", %{conn: conn} do
1631 activity = insert(:note_activity)
1635 |> get("/api/pleroma/admin/statuses/#{activity.id}")
1636 |> json_response(200)
1638 assert response["id"] == activity.id
1642 describe "PUT /api/pleroma/admin/statuses/:id" do
1644 activity = insert(:note_activity)
1649 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1652 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1653 |> json_response(:ok)
1655 assert response["sensitive"]
1657 log_entry = Repo.one(ModerationLog)
1659 assert ModerationLog.get_log_entry_message(log_entry) ==
1660 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1664 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1665 |> json_response(:ok)
1667 refute response["sensitive"]
1670 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1673 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1674 |> json_response(:ok)
1676 assert response["visibility"] == "public"
1678 log_entry = Repo.one(ModerationLog)
1680 assert ModerationLog.get_log_entry_message(log_entry) ==
1681 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1685 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1686 |> json_response(:ok)
1688 assert response["visibility"] == "private"
1692 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1693 |> json_response(:ok)
1695 assert response["visibility"] == "unlisted"
1698 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1699 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1701 assert json_response(conn, :bad_request) == "Unsupported visibility"
1705 describe "DELETE /api/pleroma/admin/statuses/:id" do
1707 activity = insert(:note_activity)
1712 test "deletes status", %{conn: conn, id: id, admin: admin} do
1714 |> delete("/api/pleroma/admin/statuses/#{id}")
1715 |> json_response(:ok)
1717 refute Activity.get_by_id(id)
1719 log_entry = Repo.one(ModerationLog)
1721 assert ModerationLog.get_log_entry_message(log_entry) ==
1722 "@#{admin.nickname} deleted status ##{id}"
1725 test "returns 404 when the status does not exist", %{conn: conn} do
1726 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1728 assert json_response(conn, :not_found) == "Not found"
1732 describe "GET /api/pleroma/admin/config" do
1733 setup do: clear_config(:configurable_from_database, true)
1735 test "when configuration from database is off", %{conn: conn} do
1736 Config.put(:configurable_from_database, false)
1737 conn = get(conn, "/api/pleroma/admin/config")
1739 assert json_response(conn, 400) ==
1740 "To use this endpoint you need to enable configuration from database."
1743 test "with settings only in db", %{conn: conn} do
1744 config1 = insert(:config)
1745 config2 = insert(:config)
1747 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1752 "group" => ":pleroma",
1757 "group" => ":pleroma",
1762 } = json_response(conn, 200)
1764 assert key1 == config1.key
1765 assert key2 == config2.key
1768 test "db is added to settings that are in db", %{conn: conn} do
1769 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1771 %{"configs" => configs} =
1773 |> get("/api/pleroma/admin/config")
1774 |> json_response(200)
1777 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1778 group == ":pleroma" and key == ":instance"
1781 assert instance_config["db"] == [":name"]
1784 test "merged default setting with db settings", %{conn: conn} do
1785 config1 = insert(:config)
1786 config2 = insert(:config)
1790 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1793 %{"configs" => configs} =
1795 |> get("/api/pleroma/admin/config")
1796 |> json_response(200)
1798 assert length(configs) > 3
1801 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1802 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1805 assert length(received_configs) == 3
1809 |> ConfigDB.from_binary()
1811 |> ConfigDB.convert()
1813 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1814 assert db in [[config1.key], [config2.key], db_keys]
1817 ConfigDB.from_binary_with_convert(config1.value),
1818 ConfigDB.from_binary_with_convert(config2.value),
1819 ConfigDB.from_binary_with_convert(config3.value)
1824 test "subkeys with full update right merge", %{conn: conn} do
1828 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1834 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1837 %{"configs" => configs} =
1839 |> get("/api/pleroma/admin/config")
1840 |> json_response(200)
1843 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1844 group == ":pleroma" and key in [config1.key, config2.key]
1847 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1848 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1850 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1851 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1853 assert emoji_val[:groups] == [a: 1, b: 2]
1854 assert assets_val[:mascots] == [a: 1, b: 2]
1858 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1859 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1861 assert json_response(conn, 400) ==
1862 "To use this endpoint you need to enable configuration from database."
1865 describe "POST /api/pleroma/admin/config" do
1867 http = Application.get_env(:pleroma, :http)
1870 Application.delete_env(:pleroma, :key1)
1871 Application.delete_env(:pleroma, :key2)
1872 Application.delete_env(:pleroma, :key3)
1873 Application.delete_env(:pleroma, :key4)
1874 Application.delete_env(:pleroma, :keyaa1)
1875 Application.delete_env(:pleroma, :keyaa2)
1876 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1877 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1878 Application.put_env(:pleroma, :http, http)
1879 Application.put_env(:tesla, :adapter, Tesla.Mock)
1880 Restarter.Pleroma.refresh()
1884 setup do: clear_config(:configurable_from_database, true)
1886 @tag capture_log: true
1887 test "create new config setting in db", %{conn: conn} do
1888 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1889 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1892 post(conn, "/api/pleroma/admin/config", %{
1894 %{group: ":pleroma", key: ":key1", value: "value1"},
1896 group: ":ueberauth",
1898 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1904 ":nested_1" => "nested_value1",
1906 %{":nested_22" => "nested_value222"},
1907 %{":nested_33" => %{":nested_44" => "nested_444"}}
1915 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1916 %{"nested_4" => true}
1922 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1927 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1932 assert json_response(conn, 200) == %{
1935 "group" => ":pleroma",
1937 "value" => "value1",
1941 "group" => ":ueberauth",
1942 "key" => "Ueberauth",
1943 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1944 "db" => [":consumer_secret"]
1947 "group" => ":pleroma",
1950 ":nested_1" => "nested_value1",
1952 %{":nested_22" => "nested_value222"},
1953 %{":nested_33" => %{":nested_44" => "nested_444"}}
1959 "group" => ":pleroma",
1962 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1963 %{"nested_4" => true}
1968 "group" => ":pleroma",
1970 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
1976 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
1982 assert Application.get_env(:pleroma, :key1) == "value1"
1984 assert Application.get_env(:pleroma, :key2) == %{
1985 nested_1: "nested_value1",
1987 %{nested_22: "nested_value222"},
1988 %{nested_33: %{nested_44: "nested_444"}}
1992 assert Application.get_env(:pleroma, :key3) == [
1993 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
1994 %{"nested_4" => true}
1997 assert Application.get_env(:pleroma, :key4) == %{
1998 "endpoint" => "https://example.com",
2002 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2005 test "save configs setting without explicit key", %{conn: conn} do
2006 level = Application.get_env(:quack, :level)
2007 meta = Application.get_env(:quack, :meta)
2008 webhook_url = Application.get_env(:quack, :webhook_url)
2011 Application.put_env(:quack, :level, level)
2012 Application.put_env(:quack, :meta, meta)
2013 Application.put_env(:quack, :webhook_url, webhook_url)
2017 post(conn, "/api/pleroma/admin/config", %{
2031 key: ":webhook_url",
2032 value: "https://hooks.slack.com/services/KEY"
2037 assert json_response(conn, 200) == %{
2040 "group" => ":quack",
2046 "group" => ":quack",
2048 "value" => [":none"],
2052 "group" => ":quack",
2053 "key" => ":webhook_url",
2054 "value" => "https://hooks.slack.com/services/KEY",
2055 "db" => [":webhook_url"]
2060 assert Application.get_env(:quack, :level) == :info
2061 assert Application.get_env(:quack, :meta) == [:none]
2062 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2065 test "saving config with partial update", %{conn: conn} do
2066 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2069 post(conn, "/api/pleroma/admin/config", %{
2071 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2075 assert json_response(conn, 200) == %{
2078 "group" => ":pleroma",
2081 %{"tuple" => [":key1", 1]},
2082 %{"tuple" => [":key2", 2]},
2083 %{"tuple" => [":key3", 3]}
2085 "db" => [":key1", ":key2", ":key3"]
2091 test "saving config which need pleroma reboot", %{conn: conn} do
2092 chat = Config.get(:chat)
2093 on_exit(fn -> Config.put(:chat, chat) end)
2097 "/api/pleroma/admin/config",
2100 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2104 |> json_response(200) == %{
2107 "db" => [":enabled"],
2108 "group" => ":pleroma",
2110 "value" => [%{"tuple" => [":enabled", true]}]
2113 "need_reboot" => true
2118 |> get("/api/pleroma/admin/config")
2119 |> json_response(200)
2121 assert configs["need_reboot"]
2124 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2125 end) =~ "pleroma restarted"
2129 |> get("/api/pleroma/admin/config")
2130 |> json_response(200)
2132 assert configs["need_reboot"] == false
2135 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2136 chat = Config.get(:chat)
2137 on_exit(fn -> Config.put(:chat, chat) end)
2141 "/api/pleroma/admin/config",
2144 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2148 |> json_response(200) == %{
2151 "db" => [":enabled"],
2152 "group" => ":pleroma",
2154 "value" => [%{"tuple" => [":enabled", true]}]
2157 "need_reboot" => true
2160 assert post(conn, "/api/pleroma/admin/config", %{
2162 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2165 |> json_response(200) == %{
2168 "group" => ":pleroma",
2171 %{"tuple" => [":key3", 3]}
2176 "need_reboot" => true
2180 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2181 end) =~ "pleroma restarted"
2185 |> get("/api/pleroma/admin/config")
2186 |> json_response(200)
2188 assert configs["need_reboot"] == false
2191 test "saving config with nested merge", %{conn: conn} do
2193 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2196 post(conn, "/api/pleroma/admin/config", %{
2199 group: config.group,
2202 %{"tuple" => [":key3", 3]},
2207 %{"tuple" => [":k2", 1]},
2208 %{"tuple" => [":k3", 3]}
2217 assert json_response(conn, 200) == %{
2220 "group" => ":pleroma",
2223 %{"tuple" => [":key1", 1]},
2224 %{"tuple" => [":key3", 3]},
2229 %{"tuple" => [":k1", 1]},
2230 %{"tuple" => [":k2", 1]},
2231 %{"tuple" => [":k3", 3]}
2236 "db" => [":key1", ":key3", ":key2"]
2242 test "saving special atoms", %{conn: conn} do
2244 post(conn, "/api/pleroma/admin/config", %{
2247 "group" => ":pleroma",
2253 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2261 assert json_response(conn, 200) == %{
2264 "group" => ":pleroma",
2270 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2274 "db" => [":ssl_options"]
2279 assert Application.get_env(:pleroma, :key1) == [
2280 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2284 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2285 backends = Application.get_env(:logger, :backends)
2286 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2292 value: :erlang.term_to_binary([])
2295 Pleroma.Config.TransferTask.load_and_update_env([], false)
2297 assert Application.get_env(:logger, :backends) == []
2300 post(conn, "/api/pleroma/admin/config", %{
2303 group: config.group,
2310 assert json_response(conn, 200) == %{
2313 "group" => ":logger",
2314 "key" => ":backends",
2318 "db" => [":backends"]
2323 assert Application.get_env(:logger, :backends) == [
2328 test "saving full setting if value is not keyword", %{conn: conn} do
2333 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2337 post(conn, "/api/pleroma/admin/config", %{
2339 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2343 assert json_response(conn, 200) == %{
2346 "group" => ":tesla",
2347 "key" => ":adapter",
2348 "value" => "Tesla.Adapter.Httpc",
2349 "db" => [":adapter"]
2355 test "update config setting & delete with fallback to default value", %{
2360 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2361 config1 = insert(:config, key: ":keyaa1")
2362 config2 = insert(:config, key: ":keyaa2")
2366 group: ":ueberauth",
2371 post(conn, "/api/pleroma/admin/config", %{
2373 %{group: config1.group, key: config1.key, value: "another_value"},
2374 %{group: config2.group, key: config2.key, value: "another_value"}
2378 assert json_response(conn, 200) == %{
2381 "group" => ":pleroma",
2382 "key" => config1.key,
2383 "value" => "another_value",
2387 "group" => ":pleroma",
2388 "key" => config2.key,
2389 "value" => "another_value",
2395 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2396 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2397 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2401 |> assign(:user, admin)
2402 |> assign(:token, token)
2403 |> post("/api/pleroma/admin/config", %{
2405 %{group: config2.group, key: config2.key, delete: true},
2407 group: ":ueberauth",
2414 assert json_response(conn, 200) == %{
2418 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2419 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2422 test "common config example", %{conn: conn} do
2424 post(conn, "/api/pleroma/admin/config", %{
2427 "group" => ":pleroma",
2428 "key" => "Pleroma.Captcha.NotReal",
2430 %{"tuple" => [":enabled", false]},
2431 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2432 %{"tuple" => [":seconds_valid", 60]},
2433 %{"tuple" => [":path", ""]},
2434 %{"tuple" => [":key1", nil]},
2435 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2436 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2437 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2438 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2439 %{"tuple" => [":name", "Pleroma"]}
2445 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2447 assert json_response(conn, 200) == %{
2450 "group" => ":pleroma",
2451 "key" => "Pleroma.Captcha.NotReal",
2453 %{"tuple" => [":enabled", false]},
2454 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2455 %{"tuple" => [":seconds_valid", 60]},
2456 %{"tuple" => [":path", ""]},
2457 %{"tuple" => [":key1", nil]},
2458 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2459 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2460 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2461 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2462 %{"tuple" => [":name", "Pleroma"]}
2481 test "tuples with more than two values", %{conn: conn} do
2483 post(conn, "/api/pleroma/admin/config", %{
2486 "group" => ":pleroma",
2487 "key" => "Pleroma.Web.Endpoint.NotReal",
2503 "/api/v1/streaming",
2504 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2511 "Phoenix.Endpoint.CowboyWebSocket",
2514 "Phoenix.Transports.WebSocket",
2517 "Pleroma.Web.Endpoint",
2518 "Pleroma.Web.UserSocket",
2529 "Phoenix.Endpoint.Cowboy2Handler",
2530 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2547 assert json_response(conn, 200) == %{
2550 "group" => ":pleroma",
2551 "key" => "Pleroma.Web.Endpoint.NotReal",
2567 "/api/v1/streaming",
2568 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2575 "Phoenix.Endpoint.CowboyWebSocket",
2578 "Phoenix.Transports.WebSocket",
2581 "Pleroma.Web.Endpoint",
2582 "Pleroma.Web.UserSocket",
2593 "Phoenix.Endpoint.Cowboy2Handler",
2594 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2613 test "settings with nesting map", %{conn: conn} do
2615 post(conn, "/api/pleroma/admin/config", %{
2618 "group" => ":pleroma",
2621 %{"tuple" => [":key2", "some_val"]},
2626 ":max_options" => 20,
2627 ":max_option_chars" => 200,
2628 ":min_expiration" => 0,
2629 ":max_expiration" => 31_536_000,
2631 ":max_options" => 20,
2632 ":max_option_chars" => 200,
2633 ":min_expiration" => 0,
2634 ":max_expiration" => 31_536_000
2644 assert json_response(conn, 200) ==
2648 "group" => ":pleroma",
2651 %{"tuple" => [":key2", "some_val"]},
2656 ":max_expiration" => 31_536_000,
2657 ":max_option_chars" => 200,
2658 ":max_options" => 20,
2659 ":min_expiration" => 0,
2661 ":max_expiration" => 31_536_000,
2662 ":max_option_chars" => 200,
2663 ":max_options" => 20,
2664 ":min_expiration" => 0
2670 "db" => [":key2", ":key3"]
2676 test "value as map", %{conn: conn} do
2678 post(conn, "/api/pleroma/admin/config", %{
2681 "group" => ":pleroma",
2683 "value" => %{"key" => "some_val"}
2688 assert json_response(conn, 200) ==
2692 "group" => ":pleroma",
2694 "value" => %{"key" => "some_val"},
2701 test "queues key as atom", %{conn: conn} do
2703 post(conn, "/api/pleroma/admin/config", %{
2709 %{"tuple" => [":federator_incoming", 50]},
2710 %{"tuple" => [":federator_outgoing", 50]},
2711 %{"tuple" => [":web_push", 50]},
2712 %{"tuple" => [":mailer", 10]},
2713 %{"tuple" => [":transmogrifier", 20]},
2714 %{"tuple" => [":scheduled_activities", 10]},
2715 %{"tuple" => [":background", 5]}
2721 assert json_response(conn, 200) == %{
2727 %{"tuple" => [":federator_incoming", 50]},
2728 %{"tuple" => [":federator_outgoing", 50]},
2729 %{"tuple" => [":web_push", 50]},
2730 %{"tuple" => [":mailer", 10]},
2731 %{"tuple" => [":transmogrifier", 20]},
2732 %{"tuple" => [":scheduled_activities", 10]},
2733 %{"tuple" => [":background", 5]}
2736 ":federator_incoming",
2737 ":federator_outgoing",
2741 ":scheduled_activities",
2749 test "delete part of settings by atom subkeys", %{conn: conn} do
2753 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2757 post(conn, "/api/pleroma/admin/config", %{
2760 group: config.group,
2762 subkeys: [":subkey1", ":subkey3"],
2768 assert json_response(conn, 200) == %{
2771 "group" => ":pleroma",
2773 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2774 "db" => [":subkey2"]
2780 test "proxy tuple localhost", %{conn: conn} do
2782 post(conn, "/api/pleroma/admin/config", %{
2788 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2789 %{"tuple" => [":send_user_agent", false]}
2795 assert json_response(conn, 200) == %{
2798 "group" => ":pleroma",
2801 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2802 %{"tuple" => [":send_user_agent", false]}
2804 "db" => [":proxy_url", ":send_user_agent"]
2810 test "proxy tuple domain", %{conn: conn} do
2812 post(conn, "/api/pleroma/admin/config", %{
2818 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2819 %{"tuple" => [":send_user_agent", false]}
2825 assert json_response(conn, 200) == %{
2828 "group" => ":pleroma",
2831 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2832 %{"tuple" => [":send_user_agent", false]}
2834 "db" => [":proxy_url", ":send_user_agent"]
2840 test "proxy tuple ip", %{conn: conn} do
2842 post(conn, "/api/pleroma/admin/config", %{
2848 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2849 %{"tuple" => [":send_user_agent", false]}
2855 assert json_response(conn, 200) == %{
2858 "group" => ":pleroma",
2861 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2862 %{"tuple" => [":send_user_agent", false]}
2864 "db" => [":proxy_url", ":send_user_agent"]
2871 describe "GET /api/pleroma/admin/restart" do
2872 setup do: clear_config(:configurable_from_database, true)
2874 test "pleroma restarts", %{conn: conn} do
2876 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2877 end) =~ "pleroma restarted"
2879 refute Restarter.Pleroma.need_reboot?()
2883 test "need_reboot flag", %{conn: conn} do
2885 |> get("/api/pleroma/admin/need_reboot")
2886 |> json_response(200) == %{"need_reboot" => false}
2888 Restarter.Pleroma.need_reboot()
2891 |> get("/api/pleroma/admin/need_reboot")
2892 |> json_response(200) == %{"need_reboot" => true}
2894 on_exit(fn -> Restarter.Pleroma.refresh() end)
2897 describe "GET /api/pleroma/admin/statuses" do
2898 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2899 blocked = insert(:user)
2900 user = insert(:user)
2901 User.block(admin, blocked)
2904 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2906 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2907 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2908 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2909 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2913 |> get("/api/pleroma/admin/statuses")
2914 |> json_response(200)
2916 refute "private" in Enum.map(response, & &1["visibility"])
2917 assert length(response) == 3
2920 test "returns only local statuses with local_only on", %{conn: conn} do
2921 user = insert(:user)
2922 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2923 insert(:note_activity, user: user, local: true)
2924 insert(:note_activity, user: remote_user, local: false)
2928 |> get("/api/pleroma/admin/statuses?local_only=true")
2929 |> json_response(200)
2931 assert length(response) == 1
2934 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2935 user = insert(:user)
2938 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2940 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2941 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2942 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2943 assert json_response(conn, 200) |> length() == 3
2947 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2949 user = insert(:user)
2951 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2952 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2953 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2955 insert(:note_activity, user: user, published: date1)
2956 insert(:note_activity, user: user, published: date2)
2957 insert(:note_activity, user: user, published: date3)
2962 test "renders user's statuses", %{conn: conn, user: user} do
2963 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2965 assert json_response(conn, 200) |> length() == 3
2968 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2969 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2971 assert json_response(conn, 200) |> length() == 2
2974 test "doesn't return private statuses by default", %{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")
2983 assert json_response(conn, 200) |> length() == 4
2986 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2987 {:ok, _private_status} =
2988 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2990 {:ok, _public_status} =
2991 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2993 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2995 assert json_response(conn, 200) |> length() == 5
2998 test "excludes reblogs by default", %{conn: conn, user: user} do
2999 other_user = insert(:user)
3000 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3001 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3003 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3004 assert json_response(conn_res, 200) |> length() == 0
3007 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3009 assert json_response(conn_res, 200) |> length() == 1
3013 describe "GET /api/pleroma/admin/moderation_log" do
3015 moderator = insert(:user, is_moderator: true)
3017 %{moderator: moderator}
3020 test "returns the log", %{conn: conn, admin: admin} do
3021 Repo.insert(%ModerationLog{
3025 "nickname" => admin.nickname,
3028 action: "relay_follow",
3029 target: "https://example.org/relay"
3031 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3034 Repo.insert(%ModerationLog{
3038 "nickname" => admin.nickname,
3041 action: "relay_unfollow",
3042 target: "https://example.org/relay"
3044 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3047 conn = get(conn, "/api/pleroma/admin/moderation_log")
3049 response = json_response(conn, 200)
3050 [first_entry, second_entry] = response["items"]
3052 assert response["total"] == 2
3053 assert first_entry["data"]["action"] == "relay_unfollow"
3055 assert first_entry["message"] ==
3056 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3058 assert second_entry["data"]["action"] == "relay_follow"
3060 assert second_entry["message"] ==
3061 "@#{admin.nickname} followed relay: https://example.org/relay"
3064 test "returns the log with pagination", %{conn: conn, admin: admin} do
3065 Repo.insert(%ModerationLog{
3069 "nickname" => admin.nickname,
3072 action: "relay_follow",
3073 target: "https://example.org/relay"
3075 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3078 Repo.insert(%ModerationLog{
3082 "nickname" => admin.nickname,
3085 action: "relay_unfollow",
3086 target: "https://example.org/relay"
3088 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3091 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3093 response1 = json_response(conn1, 200)
3094 [first_entry] = response1["items"]
3096 assert response1["total"] == 2
3097 assert response1["items"] |> length() == 1
3098 assert first_entry["data"]["action"] == "relay_unfollow"
3100 assert first_entry["message"] ==
3101 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3103 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3105 response2 = json_response(conn2, 200)
3106 [second_entry] = response2["items"]
3108 assert response2["total"] == 2
3109 assert response2["items"] |> length() == 1
3110 assert second_entry["data"]["action"] == "relay_follow"
3112 assert second_entry["message"] ==
3113 "@#{admin.nickname} followed relay: https://example.org/relay"
3116 test "filters log by date", %{conn: conn, admin: admin} do
3117 first_date = "2017-08-15T15:47:06Z"
3118 second_date = "2017-08-20T15:47:06Z"
3120 Repo.insert(%ModerationLog{
3124 "nickname" => admin.nickname,
3127 action: "relay_follow",
3128 target: "https://example.org/relay"
3130 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3133 Repo.insert(%ModerationLog{
3137 "nickname" => admin.nickname,
3140 action: "relay_unfollow",
3141 target: "https://example.org/relay"
3143 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3149 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3152 response1 = json_response(conn1, 200)
3153 [first_entry] = response1["items"]
3155 assert response1["total"] == 1
3156 assert first_entry["data"]["action"] == "relay_unfollow"
3158 assert first_entry["message"] ==
3159 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3162 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3163 Repo.insert(%ModerationLog{
3167 "nickname" => admin.nickname,
3170 action: "relay_follow",
3171 target: "https://example.org/relay"
3175 Repo.insert(%ModerationLog{
3178 "id" => moderator.id,
3179 "nickname" => moderator.nickname,
3182 action: "relay_unfollow",
3183 target: "https://example.org/relay"
3187 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3189 response1 = json_response(conn1, 200)
3190 [first_entry] = response1["items"]
3192 assert response1["total"] == 1
3193 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3196 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3197 ModerationLog.insert_log(%{
3199 action: "relay_follow",
3200 target: "https://example.org/relay"
3203 ModerationLog.insert_log(%{
3205 action: "relay_unfollow",
3206 target: "https://example.org/relay"
3209 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3211 response1 = json_response(conn1, 200)
3212 [first_entry] = response1["items"]
3214 assert response1["total"] == 1
3216 assert get_in(first_entry, ["data", "message"]) ==
3217 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3221 describe "GET /users/:nickname/credentials" do
3222 test "gets the user credentials", %{conn: conn} do
3223 user = insert(:user)
3224 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3226 response = assert json_response(conn, 200)
3227 assert response["email"] == user.email
3230 test "returns 403 if requested by a non-admin" do
3231 user = insert(:user)
3235 |> assign(:user, user)
3236 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3238 assert json_response(conn, :forbidden)
3242 describe "PATCH /users/:nickname/credentials" do
3243 test "changes password and email", %{conn: conn, admin: admin} do
3244 user = insert(:user)
3245 assert user.password_reset_pending == false
3248 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3249 "password" => "new_password",
3250 "email" => "new_email@example.com",
3251 "name" => "new_name"
3254 assert json_response(conn, 200) == %{"status" => "success"}
3256 ObanHelpers.perform_all()
3258 updated_user = User.get_by_id(user.id)
3260 assert updated_user.email == "new_email@example.com"
3261 assert updated_user.name == "new_name"
3262 assert updated_user.password_hash != user.password_hash
3263 assert updated_user.password_reset_pending == true
3265 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3267 assert ModerationLog.get_log_entry_message(log_entry1) ==
3268 "@#{admin.nickname} updated users: @#{user.nickname}"
3270 assert ModerationLog.get_log_entry_message(log_entry2) ==
3271 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3274 test "returns 403 if requested by a non-admin" do
3275 user = insert(:user)
3279 |> assign(:user, user)
3280 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3281 "password" => "new_password",
3282 "email" => "new_email@example.com",
3283 "name" => "new_name"
3286 assert json_response(conn, :forbidden)
3290 describe "PATCH /users/:nickname/force_password_reset" do
3291 test "sets password_reset_pending to true", %{conn: conn} do
3292 user = insert(:user)
3293 assert user.password_reset_pending == false
3296 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3298 assert json_response(conn, 204) == ""
3300 ObanHelpers.perform_all()
3302 assert User.get_by_id(user.id).password_reset_pending == true
3306 describe "relays" do
3307 test "POST /relay", %{conn: conn, admin: admin} do
3309 post(conn, "/api/pleroma/admin/relay", %{
3310 relay_url: "http://mastodon.example.org/users/admin"
3313 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3315 log_entry = Repo.one(ModerationLog)
3317 assert ModerationLog.get_log_entry_message(log_entry) ==
3318 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3321 test "GET /relay", %{conn: conn} do
3322 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3324 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3325 |> Enum.each(fn ap_id ->
3326 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3327 User.follow(relay_user, user)
3330 conn = get(conn, "/api/pleroma/admin/relay")
3332 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3335 test "DELETE /relay", %{conn: conn, admin: admin} do
3336 post(conn, "/api/pleroma/admin/relay", %{
3337 relay_url: "http://mastodon.example.org/users/admin"
3341 delete(conn, "/api/pleroma/admin/relay", %{
3342 relay_url: "http://mastodon.example.org/users/admin"
3345 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3347 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3349 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3350 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3352 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3353 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3357 describe "instances" do
3358 test "GET /instances/:instance/statuses", %{conn: conn} do
3359 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3360 user2 = insert(:user, local: false, nickname: "test@test.com")
3361 insert_pair(:note_activity, user: user)
3362 activity = insert(:note_activity, user: user2)
3364 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3366 response = json_response(ret_conn, 200)
3368 assert length(response) == 2
3370 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3372 response = json_response(ret_conn, 200)
3374 assert length(response) == 1
3376 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3378 response = json_response(ret_conn, 200)
3380 assert Enum.empty?(response)
3382 CommonAPI.repeat(activity.id, user)
3384 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3385 response = json_response(ret_conn, 200)
3386 assert length(response) == 2
3388 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3389 response = json_response(ret_conn, 200)
3390 assert length(response) == 3
3394 describe "PATCH /confirm_email" do
3395 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3396 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3398 assert first_user.confirmation_pending == true
3399 assert second_user.confirmation_pending == true
3402 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3404 first_user.nickname,
3405 second_user.nickname
3409 assert ret_conn.status == 200
3411 assert first_user.confirmation_pending == true
3412 assert second_user.confirmation_pending == true
3414 log_entry = Repo.one(ModerationLog)
3416 assert ModerationLog.get_log_entry_message(log_entry) ==
3417 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3418 second_user.nickname
3423 describe "PATCH /resend_confirmation_email" do
3424 test "it resend emails for two users", %{conn: conn, admin: admin} do
3425 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3428 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3430 first_user.nickname,
3431 second_user.nickname
3435 assert ret_conn.status == 200
3437 log_entry = Repo.one(ModerationLog)
3439 assert ModerationLog.get_log_entry_message(log_entry) ==
3440 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3441 second_user.nickname
3446 describe "POST /reports/:id/notes" do
3447 setup %{conn: conn, admin: admin} do
3448 [reporter, target_user] = insert_pair(:user)
3449 activity = insert(:note_activity, user: target_user)
3451 {:ok, %{id: report_id}} =
3452 CommonAPI.report(reporter, %{
3453 account_id: target_user.id,
3454 comment: "I feel offended",
3455 status_ids: [activity.id]
3458 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3459 content: "this is disgusting!"
3462 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3463 content: "this is disgusting2!"
3468 report_id: report_id
3472 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3473 [note, _] = Repo.all(ReportNote)
3476 activity_id: ^report_id,
3477 content: "this is disgusting!",
3482 test "it returns reports with notes", %{conn: conn, admin: admin} do
3483 conn = get(conn, "/api/pleroma/admin/reports")
3485 response = json_response(conn, 200)
3486 notes = hd(response["reports"])["notes"]
3489 assert note["user"]["nickname"] == admin.nickname
3490 assert note["content"] == "this is disgusting!"
3491 assert note["created_at"]
3492 assert response["total"] == 1
3495 test "it deletes the note", %{conn: conn, report_id: report_id} do
3496 assert ReportNote |> Repo.all() |> length() == 2
3498 [note, _] = Repo.all(ReportNote)
3500 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3502 assert ReportNote |> Repo.all() |> length() == 1
3506 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3507 admin = insert(:user, is_admin: true)
3510 assign(conn, :user, admin)
3511 |> get("/api/pleroma/admin/config/descriptions")
3513 assert [child | _others] = json_response(conn, 200)
3515 assert child["children"]
3517 assert String.starts_with?(child["group"], ":")
3518 assert child["description"]
3521 describe "/api/pleroma/admin/stats" do
3522 test "status visibility count", %{conn: conn} do
3523 admin = insert(:user, is_admin: true)
3524 user = insert(:user)
3525 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3526 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3527 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3531 |> assign(:user, admin)
3532 |> get("/api/pleroma/admin/stats")
3533 |> json_response(200)
3535 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3536 response["status_visibility"]
3540 describe "POST /api/pleroma/admin/oauth_app" do
3541 test "errors", %{conn: conn} do
3542 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3544 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3547 test "success", %{conn: conn} do
3548 base_url = Pleroma.Web.base_url()
3549 app_name = "Trusted app"
3553 |> post("/api/pleroma/admin/oauth_app", %{
3555 redirect_uris: base_url
3557 |> json_response(200)
3561 "client_secret" => _,
3562 "name" => ^app_name,
3563 "redirect_uri" => ^base_url,
3568 test "with trusted", %{conn: conn} do
3569 base_url = Pleroma.Web.base_url()
3570 app_name = "Trusted app"
3574 |> post("/api/pleroma/admin/oauth_app", %{
3576 redirect_uris: base_url,
3579 |> json_response(200)
3583 "client_secret" => _,
3584 "name" => ^app_name,
3585 "redirect_uri" => ^base_url,
3591 describe "GET /api/pleroma/admin/oauth_app" do
3593 app = insert(:oauth_app)
3597 test "list", %{conn: conn} do
3600 |> get("/api/pleroma/admin/oauth_app")
3601 |> json_response(200)
3603 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3605 assert length(apps) == count
3608 test "with page size", %{conn: conn} do
3614 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3615 |> json_response(200)
3617 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3619 assert length(apps) == page_size
3622 test "search by client name", %{conn: conn, app: app} do
3625 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3626 |> json_response(200)
3628 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3630 assert returned["client_id"] == app.client_id
3631 assert returned["name"] == app.client_name
3634 test "search by client id", %{conn: conn, app: app} do
3637 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3638 |> json_response(200)
3640 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3642 assert returned["client_id"] == app.client_id
3643 assert returned["name"] == app.client_name
3646 test "only trusted", %{conn: conn} do
3647 app = insert(:oauth_app, trusted: true)
3651 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3652 |> json_response(200)
3654 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3656 assert returned["client_id"] == app.client_id
3657 assert returned["name"] == app.client_name
3661 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3662 test "with id", %{conn: conn} do
3663 app = insert(:oauth_app)
3667 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3668 |> json_response(:no_content)
3670 assert response == ""
3673 test "with non existance id", %{conn: conn} do
3676 |> delete("/api/pleroma/admin/oauth_app/0")
3677 |> json_response(:bad_request)
3679 assert response == ""
3683 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3684 test "with id", %{conn: conn} do
3685 app = insert(:oauth_app)
3687 name = "another name"
3688 url = "https://example.com"
3691 website = "http://website.com"
3695 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3702 |> json_response(200)
3706 "client_secret" => _,
3709 "redirect_uri" => ^url,
3711 "website" => ^website
3715 test "without id", %{conn: conn} do
3718 |> patch("/api/pleroma/admin/oauth_app/0")
3719 |> json_response(:bad_request)
3721 assert response == ""
3726 # Needed for testing
3727 defmodule Pleroma.Web.Endpoint.NotReal do
3730 defmodule Pleroma.Captcha.NotReal do