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 assert configs["need_reboot"] == false
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 assert configs["need_reboot"] == false
2172 test "saving config with nested merge", %{conn: conn} do
2174 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2177 post(conn, "/api/pleroma/admin/config", %{
2180 group: config.group,
2183 %{"tuple" => [":key3", 3]},
2188 %{"tuple" => [":k2", 1]},
2189 %{"tuple" => [":k3", 3]}
2198 assert json_response(conn, 200) == %{
2201 "group" => ":pleroma",
2204 %{"tuple" => [":key1", 1]},
2205 %{"tuple" => [":key3", 3]},
2210 %{"tuple" => [":k1", 1]},
2211 %{"tuple" => [":k2", 1]},
2212 %{"tuple" => [":k3", 3]}
2217 "db" => [":key1", ":key3", ":key2"]
2223 test "saving special atoms", %{conn: conn} do
2225 post(conn, "/api/pleroma/admin/config", %{
2228 "group" => ":pleroma",
2234 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2242 assert json_response(conn, 200) == %{
2245 "group" => ":pleroma",
2251 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2255 "db" => [":ssl_options"]
2260 assert Application.get_env(:pleroma, :key1) == [
2261 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2265 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2266 backends = Application.get_env(:logger, :backends)
2267 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2273 value: :erlang.term_to_binary([])
2276 Pleroma.Config.TransferTask.load_and_update_env([], false)
2278 assert Application.get_env(:logger, :backends) == []
2281 post(conn, "/api/pleroma/admin/config", %{
2284 group: config.group,
2291 assert json_response(conn, 200) == %{
2294 "group" => ":logger",
2295 "key" => ":backends",
2299 "db" => [":backends"]
2304 assert Application.get_env(:logger, :backends) == [
2309 test "saving full setting if value is not keyword", %{conn: conn} do
2314 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2318 post(conn, "/api/pleroma/admin/config", %{
2320 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2324 assert json_response(conn, 200) == %{
2327 "group" => ":tesla",
2328 "key" => ":adapter",
2329 "value" => "Tesla.Adapter.Httpc",
2330 "db" => [":adapter"]
2336 test "update config setting & delete with fallback to default value", %{
2341 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2342 config1 = insert(:config, key: ":keyaa1")
2343 config2 = insert(:config, key: ":keyaa2")
2347 group: ":ueberauth",
2352 post(conn, "/api/pleroma/admin/config", %{
2354 %{group: config1.group, key: config1.key, value: "another_value"},
2355 %{group: config2.group, key: config2.key, value: "another_value"}
2359 assert json_response(conn, 200) == %{
2362 "group" => ":pleroma",
2363 "key" => config1.key,
2364 "value" => "another_value",
2368 "group" => ":pleroma",
2369 "key" => config2.key,
2370 "value" => "another_value",
2376 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2377 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2378 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2382 |> assign(:user, admin)
2383 |> assign(:token, token)
2384 |> post("/api/pleroma/admin/config", %{
2386 %{group: config2.group, key: config2.key, delete: true},
2388 group: ":ueberauth",
2395 assert json_response(conn, 200) == %{
2399 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2400 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2403 test "common config example", %{conn: conn} do
2405 post(conn, "/api/pleroma/admin/config", %{
2408 "group" => ":pleroma",
2409 "key" => "Pleroma.Captcha.NotReal",
2411 %{"tuple" => [":enabled", false]},
2412 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2413 %{"tuple" => [":seconds_valid", 60]},
2414 %{"tuple" => [":path", ""]},
2415 %{"tuple" => [":key1", nil]},
2416 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2417 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2418 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2419 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2420 %{"tuple" => [":name", "Pleroma"]}
2426 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2428 assert json_response(conn, 200) == %{
2431 "group" => ":pleroma",
2432 "key" => "Pleroma.Captcha.NotReal",
2434 %{"tuple" => [":enabled", false]},
2435 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2436 %{"tuple" => [":seconds_valid", 60]},
2437 %{"tuple" => [":path", ""]},
2438 %{"tuple" => [":key1", nil]},
2439 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2440 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2441 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2442 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2443 %{"tuple" => [":name", "Pleroma"]}
2462 test "tuples with more than two values", %{conn: conn} do
2464 post(conn, "/api/pleroma/admin/config", %{
2467 "group" => ":pleroma",
2468 "key" => "Pleroma.Web.Endpoint.NotReal",
2484 "/api/v1/streaming",
2485 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2492 "Phoenix.Endpoint.CowboyWebSocket",
2495 "Phoenix.Transports.WebSocket",
2498 "Pleroma.Web.Endpoint",
2499 "Pleroma.Web.UserSocket",
2510 "Phoenix.Endpoint.Cowboy2Handler",
2511 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2528 assert json_response(conn, 200) == %{
2531 "group" => ":pleroma",
2532 "key" => "Pleroma.Web.Endpoint.NotReal",
2548 "/api/v1/streaming",
2549 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2556 "Phoenix.Endpoint.CowboyWebSocket",
2559 "Phoenix.Transports.WebSocket",
2562 "Pleroma.Web.Endpoint",
2563 "Pleroma.Web.UserSocket",
2574 "Phoenix.Endpoint.Cowboy2Handler",
2575 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2594 test "settings with nesting map", %{conn: conn} do
2596 post(conn, "/api/pleroma/admin/config", %{
2599 "group" => ":pleroma",
2602 %{"tuple" => [":key2", "some_val"]},
2607 ":max_options" => 20,
2608 ":max_option_chars" => 200,
2609 ":min_expiration" => 0,
2610 ":max_expiration" => 31_536_000,
2612 ":max_options" => 20,
2613 ":max_option_chars" => 200,
2614 ":min_expiration" => 0,
2615 ":max_expiration" => 31_536_000
2625 assert json_response(conn, 200) ==
2629 "group" => ":pleroma",
2632 %{"tuple" => [":key2", "some_val"]},
2637 ":max_expiration" => 31_536_000,
2638 ":max_option_chars" => 200,
2639 ":max_options" => 20,
2640 ":min_expiration" => 0,
2642 ":max_expiration" => 31_536_000,
2643 ":max_option_chars" => 200,
2644 ":max_options" => 20,
2645 ":min_expiration" => 0
2651 "db" => [":key2", ":key3"]
2657 test "value as map", %{conn: conn} do
2659 post(conn, "/api/pleroma/admin/config", %{
2662 "group" => ":pleroma",
2664 "value" => %{"key" => "some_val"}
2669 assert json_response(conn, 200) ==
2673 "group" => ":pleroma",
2675 "value" => %{"key" => "some_val"},
2682 test "queues key as atom", %{conn: conn} do
2684 post(conn, "/api/pleroma/admin/config", %{
2690 %{"tuple" => [":federator_incoming", 50]},
2691 %{"tuple" => [":federator_outgoing", 50]},
2692 %{"tuple" => [":web_push", 50]},
2693 %{"tuple" => [":mailer", 10]},
2694 %{"tuple" => [":transmogrifier", 20]},
2695 %{"tuple" => [":scheduled_activities", 10]},
2696 %{"tuple" => [":background", 5]}
2702 assert json_response(conn, 200) == %{
2708 %{"tuple" => [":federator_incoming", 50]},
2709 %{"tuple" => [":federator_outgoing", 50]},
2710 %{"tuple" => [":web_push", 50]},
2711 %{"tuple" => [":mailer", 10]},
2712 %{"tuple" => [":transmogrifier", 20]},
2713 %{"tuple" => [":scheduled_activities", 10]},
2714 %{"tuple" => [":background", 5]}
2717 ":federator_incoming",
2718 ":federator_outgoing",
2722 ":scheduled_activities",
2730 test "delete part of settings by atom subkeys", %{conn: conn} do
2734 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2738 post(conn, "/api/pleroma/admin/config", %{
2741 group: config.group,
2743 subkeys: [":subkey1", ":subkey3"],
2749 assert json_response(conn, 200) == %{
2752 "group" => ":pleroma",
2754 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2755 "db" => [":subkey2"]
2761 test "proxy tuple localhost", %{conn: conn} do
2763 post(conn, "/api/pleroma/admin/config", %{
2769 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2770 %{"tuple" => [":send_user_agent", false]}
2776 assert json_response(conn, 200) == %{
2779 "group" => ":pleroma",
2782 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2783 %{"tuple" => [":send_user_agent", false]}
2785 "db" => [":proxy_url", ":send_user_agent"]
2791 test "proxy tuple domain", %{conn: conn} do
2793 post(conn, "/api/pleroma/admin/config", %{
2799 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2800 %{"tuple" => [":send_user_agent", false]}
2806 assert json_response(conn, 200) == %{
2809 "group" => ":pleroma",
2812 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2813 %{"tuple" => [":send_user_agent", false]}
2815 "db" => [":proxy_url", ":send_user_agent"]
2821 test "proxy tuple ip", %{conn: conn} do
2823 post(conn, "/api/pleroma/admin/config", %{
2829 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2830 %{"tuple" => [":send_user_agent", false]}
2836 assert json_response(conn, 200) == %{
2839 "group" => ":pleroma",
2842 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2843 %{"tuple" => [":send_user_agent", false]}
2845 "db" => [":proxy_url", ":send_user_agent"]
2852 describe "GET /api/pleroma/admin/restart" do
2853 setup do: clear_config(:configurable_from_database, true)
2855 test "pleroma restarts", %{conn: conn} do
2857 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2858 end) =~ "pleroma restarted"
2860 refute Restarter.Pleroma.need_reboot?()
2864 test "need_reboot flag", %{conn: conn} do
2866 |> get("/api/pleroma/admin/need_reboot")
2867 |> json_response(200) == %{"need_reboot" => false}
2869 Restarter.Pleroma.need_reboot()
2872 |> get("/api/pleroma/admin/need_reboot")
2873 |> json_response(200) == %{"need_reboot" => true}
2875 on_exit(fn -> Restarter.Pleroma.refresh() end)
2878 describe "GET /api/pleroma/admin/statuses" do
2879 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2880 blocked = insert(:user)
2881 user = insert(:user)
2882 User.block(admin, blocked)
2885 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2887 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2888 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2889 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2890 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2894 |> get("/api/pleroma/admin/statuses")
2895 |> json_response(200)
2897 refute "private" in Enum.map(response, & &1["visibility"])
2898 assert length(response) == 3
2901 test "returns only local statuses with local_only on", %{conn: conn} do
2902 user = insert(:user)
2903 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2904 insert(:note_activity, user: user, local: true)
2905 insert(:note_activity, user: remote_user, local: false)
2909 |> get("/api/pleroma/admin/statuses?local_only=true")
2910 |> json_response(200)
2912 assert length(response) == 1
2915 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2916 user = insert(:user)
2919 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2921 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2922 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2923 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2924 assert json_response(conn, 200) |> length() == 3
2928 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2930 user = insert(:user)
2932 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2933 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2934 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2936 insert(:note_activity, user: user, published: date1)
2937 insert(:note_activity, user: user, published: date2)
2938 insert(:note_activity, user: user, published: date3)
2943 test "renders user's statuses", %{conn: conn, user: user} do
2944 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2946 assert json_response(conn, 200) |> length() == 3
2949 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2950 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2952 assert json_response(conn, 200) |> length() == 2
2955 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2956 {:ok, _private_status} =
2957 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2959 {:ok, _public_status} =
2960 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2962 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2964 assert json_response(conn, 200) |> length() == 4
2967 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2968 {:ok, _private_status} =
2969 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2971 {:ok, _public_status} =
2972 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2974 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2976 assert json_response(conn, 200) |> length() == 5
2979 test "excludes reblogs by default", %{conn: conn, user: user} do
2980 other_user = insert(:user)
2981 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2982 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2984 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2985 assert json_response(conn_res, 200) |> length() == 0
2988 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2990 assert json_response(conn_res, 200) |> length() == 1
2994 describe "GET /api/pleroma/admin/moderation_log" do
2996 moderator = insert(:user, is_moderator: true)
2998 %{moderator: moderator}
3001 test "returns the log", %{conn: conn, admin: admin} do
3002 Repo.insert(%ModerationLog{
3006 "nickname" => admin.nickname,
3009 action: "relay_follow",
3010 target: "https://example.org/relay"
3012 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3015 Repo.insert(%ModerationLog{
3019 "nickname" => admin.nickname,
3022 action: "relay_unfollow",
3023 target: "https://example.org/relay"
3025 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3028 conn = get(conn, "/api/pleroma/admin/moderation_log")
3030 response = json_response(conn, 200)
3031 [first_entry, second_entry] = response["items"]
3033 assert response["total"] == 2
3034 assert first_entry["data"]["action"] == "relay_unfollow"
3036 assert first_entry["message"] ==
3037 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3039 assert second_entry["data"]["action"] == "relay_follow"
3041 assert second_entry["message"] ==
3042 "@#{admin.nickname} followed relay: https://example.org/relay"
3045 test "returns the log with pagination", %{conn: conn, admin: admin} do
3046 Repo.insert(%ModerationLog{
3050 "nickname" => admin.nickname,
3053 action: "relay_follow",
3054 target: "https://example.org/relay"
3056 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3059 Repo.insert(%ModerationLog{
3063 "nickname" => admin.nickname,
3066 action: "relay_unfollow",
3067 target: "https://example.org/relay"
3069 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3072 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3074 response1 = json_response(conn1, 200)
3075 [first_entry] = response1["items"]
3077 assert response1["total"] == 2
3078 assert response1["items"] |> length() == 1
3079 assert first_entry["data"]["action"] == "relay_unfollow"
3081 assert first_entry["message"] ==
3082 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3084 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3086 response2 = json_response(conn2, 200)
3087 [second_entry] = response2["items"]
3089 assert response2["total"] == 2
3090 assert response2["items"] |> length() == 1
3091 assert second_entry["data"]["action"] == "relay_follow"
3093 assert second_entry["message"] ==
3094 "@#{admin.nickname} followed relay: https://example.org/relay"
3097 test "filters log by date", %{conn: conn, admin: admin} do
3098 first_date = "2017-08-15T15:47:06Z"
3099 second_date = "2017-08-20T15:47:06Z"
3101 Repo.insert(%ModerationLog{
3105 "nickname" => admin.nickname,
3108 action: "relay_follow",
3109 target: "https://example.org/relay"
3111 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3114 Repo.insert(%ModerationLog{
3118 "nickname" => admin.nickname,
3121 action: "relay_unfollow",
3122 target: "https://example.org/relay"
3124 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3130 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3133 response1 = json_response(conn1, 200)
3134 [first_entry] = response1["items"]
3136 assert response1["total"] == 1
3137 assert first_entry["data"]["action"] == "relay_unfollow"
3139 assert first_entry["message"] ==
3140 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3143 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3144 Repo.insert(%ModerationLog{
3148 "nickname" => admin.nickname,
3151 action: "relay_follow",
3152 target: "https://example.org/relay"
3156 Repo.insert(%ModerationLog{
3159 "id" => moderator.id,
3160 "nickname" => moderator.nickname,
3163 action: "relay_unfollow",
3164 target: "https://example.org/relay"
3168 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3170 response1 = json_response(conn1, 200)
3171 [first_entry] = response1["items"]
3173 assert response1["total"] == 1
3174 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3177 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3178 ModerationLog.insert_log(%{
3180 action: "relay_follow",
3181 target: "https://example.org/relay"
3184 ModerationLog.insert_log(%{
3186 action: "relay_unfollow",
3187 target: "https://example.org/relay"
3190 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3192 response1 = json_response(conn1, 200)
3193 [first_entry] = response1["items"]
3195 assert response1["total"] == 1
3197 assert get_in(first_entry, ["data", "message"]) ==
3198 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3202 describe "GET /users/:nickname/credentials" do
3203 test "gets the user credentials", %{conn: conn} do
3204 user = insert(:user)
3205 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3207 response = assert json_response(conn, 200)
3208 assert response["email"] == user.email
3211 test "returns 403 if requested by a non-admin" do
3212 user = insert(:user)
3216 |> assign(:user, user)
3217 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3219 assert json_response(conn, :forbidden)
3223 describe "PATCH /users/:nickname/credentials" do
3224 test "changes password and email", %{conn: conn, admin: admin} do
3225 user = insert(:user)
3226 assert user.password_reset_pending == false
3229 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3230 "password" => "new_password",
3231 "email" => "new_email@example.com",
3232 "name" => "new_name"
3235 assert json_response(conn, 200) == %{"status" => "success"}
3237 ObanHelpers.perform_all()
3239 updated_user = User.get_by_id(user.id)
3241 assert updated_user.email == "new_email@example.com"
3242 assert updated_user.name == "new_name"
3243 assert updated_user.password_hash != user.password_hash
3244 assert updated_user.password_reset_pending == true
3246 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3248 assert ModerationLog.get_log_entry_message(log_entry1) ==
3249 "@#{admin.nickname} updated users: @#{user.nickname}"
3251 assert ModerationLog.get_log_entry_message(log_entry2) ==
3252 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3255 test "returns 403 if requested by a non-admin" do
3256 user = insert(:user)
3260 |> assign(:user, user)
3261 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3262 "password" => "new_password",
3263 "email" => "new_email@example.com",
3264 "name" => "new_name"
3267 assert json_response(conn, :forbidden)
3271 describe "PATCH /users/:nickname/force_password_reset" do
3272 test "sets password_reset_pending to true", %{conn: conn} do
3273 user = insert(:user)
3274 assert user.password_reset_pending == false
3277 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3279 assert json_response(conn, 204) == ""
3281 ObanHelpers.perform_all()
3283 assert User.get_by_id(user.id).password_reset_pending == true
3287 describe "relays" do
3288 test "POST /relay", %{conn: conn, admin: admin} do
3290 post(conn, "/api/pleroma/admin/relay", %{
3291 relay_url: "http://mastodon.example.org/users/admin"
3294 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3296 log_entry = Repo.one(ModerationLog)
3298 assert ModerationLog.get_log_entry_message(log_entry) ==
3299 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3302 test "GET /relay", %{conn: conn} do
3303 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3305 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3306 |> Enum.each(fn ap_id ->
3307 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3308 User.follow(relay_user, user)
3311 conn = get(conn, "/api/pleroma/admin/relay")
3313 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3316 test "DELETE /relay", %{conn: conn, admin: admin} do
3317 post(conn, "/api/pleroma/admin/relay", %{
3318 relay_url: "http://mastodon.example.org/users/admin"
3322 delete(conn, "/api/pleroma/admin/relay", %{
3323 relay_url: "http://mastodon.example.org/users/admin"
3326 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3328 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3330 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3331 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3333 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3334 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3338 describe "instances" do
3339 test "GET /instances/:instance/statuses", %{conn: conn} do
3340 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3341 user2 = insert(:user, local: false, nickname: "test@test.com")
3342 insert_pair(:note_activity, user: user)
3343 activity = insert(:note_activity, user: user2)
3345 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3347 response = json_response(ret_conn, 200)
3349 assert length(response) == 2
3351 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3353 response = json_response(ret_conn, 200)
3355 assert length(response) == 1
3357 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3359 response = json_response(ret_conn, 200)
3361 assert Enum.empty?(response)
3363 CommonAPI.repeat(activity.id, user)
3365 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3366 response = json_response(ret_conn, 200)
3367 assert length(response) == 2
3369 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3370 response = json_response(ret_conn, 200)
3371 assert length(response) == 3
3375 describe "PATCH /confirm_email" do
3376 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3377 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3379 assert first_user.confirmation_pending == true
3380 assert second_user.confirmation_pending == true
3383 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3385 first_user.nickname,
3386 second_user.nickname
3390 assert ret_conn.status == 200
3392 assert first_user.confirmation_pending == true
3393 assert second_user.confirmation_pending == true
3395 log_entry = Repo.one(ModerationLog)
3397 assert ModerationLog.get_log_entry_message(log_entry) ==
3398 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3399 second_user.nickname
3404 describe "PATCH /resend_confirmation_email" do
3405 test "it resend emails for two users", %{conn: conn, admin: admin} do
3406 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3409 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3411 first_user.nickname,
3412 second_user.nickname
3416 assert ret_conn.status == 200
3418 log_entry = Repo.one(ModerationLog)
3420 assert ModerationLog.get_log_entry_message(log_entry) ==
3421 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3422 second_user.nickname
3427 describe "POST /reports/:id/notes" do
3428 setup %{conn: conn, admin: admin} do
3429 [reporter, target_user] = insert_pair(:user)
3430 activity = insert(:note_activity, user: target_user)
3432 {:ok, %{id: report_id}} =
3433 CommonAPI.report(reporter, %{
3434 "account_id" => target_user.id,
3435 "comment" => "I feel offended",
3436 "status_ids" => [activity.id]
3439 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3440 content: "this is disgusting!"
3443 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3444 content: "this is disgusting2!"
3449 report_id: report_id
3453 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3454 [note, _] = Repo.all(ReportNote)
3457 activity_id: ^report_id,
3458 content: "this is disgusting!",
3463 test "it returns reports with notes", %{conn: conn, admin: admin} do
3464 conn = get(conn, "/api/pleroma/admin/reports")
3466 response = json_response(conn, 200)
3467 notes = hd(response["reports"])["notes"]
3470 assert note["user"]["nickname"] == admin.nickname
3471 assert note["content"] == "this is disgusting!"
3472 assert note["created_at"]
3473 assert response["total"] == 1
3476 test "it deletes the note", %{conn: conn, report_id: report_id} do
3477 assert ReportNote |> Repo.all() |> length() == 2
3479 [note, _] = Repo.all(ReportNote)
3481 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3483 assert ReportNote |> Repo.all() |> length() == 1
3487 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3488 admin = insert(:user, is_admin: true)
3491 assign(conn, :user, admin)
3492 |> get("/api/pleroma/admin/config/descriptions")
3494 assert [child | _others] = json_response(conn, 200)
3496 assert child["children"]
3498 assert String.starts_with?(child["group"], ":")
3499 assert child["description"]
3502 describe "/api/pleroma/admin/stats" do
3503 test "status visibility count", %{conn: conn} do
3504 admin = insert(:user, is_admin: true)
3505 user = insert(:user)
3506 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3507 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3508 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3512 |> assign(:user, admin)
3513 |> get("/api/pleroma/admin/stats")
3514 |> json_response(200)
3516 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3517 response["status_visibility"]
3521 describe "POST /api/pleroma/admin/oauth_app" do
3522 test "errors", %{conn: conn} do
3523 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3525 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3528 test "success", %{conn: conn} do
3529 base_url = Pleroma.Web.base_url()
3530 app_name = "Trusted app"
3534 |> post("/api/pleroma/admin/oauth_app", %{
3536 redirect_uris: base_url
3538 |> json_response(200)
3542 "client_secret" => _,
3543 "name" => ^app_name,
3544 "redirect_uri" => ^base_url,
3549 test "with trusted", %{conn: conn} do
3550 base_url = Pleroma.Web.base_url()
3551 app_name = "Trusted app"
3555 |> post("/api/pleroma/admin/oauth_app", %{
3557 redirect_uris: base_url,
3560 |> json_response(200)
3564 "client_secret" => _,
3565 "name" => ^app_name,
3566 "redirect_uri" => ^base_url,
3572 describe "GET /api/pleroma/admin/oauth_app" do
3574 app = insert(:oauth_app)
3578 test "list", %{conn: conn} do
3581 |> get("/api/pleroma/admin/oauth_app")
3582 |> json_response(200)
3584 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3586 assert length(apps) == count
3589 test "with page size", %{conn: conn} do
3595 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3596 |> json_response(200)
3598 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3600 assert length(apps) == page_size
3603 test "search by client name", %{conn: conn, app: app} do
3606 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3607 |> json_response(200)
3609 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3611 assert returned["client_id"] == app.client_id
3612 assert returned["name"] == app.client_name
3615 test "search by client id", %{conn: conn, app: app} do
3618 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3619 |> json_response(200)
3621 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3623 assert returned["client_id"] == app.client_id
3624 assert returned["name"] == app.client_name
3627 test "only trusted", %{conn: conn} do
3628 app = insert(:oauth_app, trusted: true)
3632 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3633 |> json_response(200)
3635 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3637 assert returned["client_id"] == app.client_id
3638 assert returned["name"] == app.client_name
3642 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3643 test "with id", %{conn: conn} do
3644 app = insert(:oauth_app)
3648 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3649 |> json_response(:no_content)
3651 assert response == ""
3654 test "with non existance id", %{conn: conn} do
3657 |> delete("/api/pleroma/admin/oauth_app/0")
3658 |> json_response(:bad_request)
3660 assert response == ""
3664 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3665 test "with id", %{conn: conn} do
3666 app = insert(:oauth_app)
3668 name = "another name"
3669 url = "https://example.com"
3672 website = "http://website.com"
3676 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3683 |> json_response(200)
3687 "client_secret" => _,
3690 "redirect_uri" => ^url,
3692 "website" => ^website
3696 test "without id", %{conn: conn} do
3699 |> patch("/api/pleroma/admin/oauth_app/0")
3700 |> json_response(:bad_request)
3702 assert response == ""
3707 # Needed for testing
3708 defmodule Pleroma.Web.Endpoint.NotReal do
3711 defmodule Pleroma.Captcha.NotReal do