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
9 import ExUnit.CaptureLog
11 import Pleroma.Factory
13 alias Pleroma.Activity
15 alias Pleroma.ConfigDB
17 alias Pleroma.ModerationLog
19 alias Pleroma.ReportNote
20 alias Pleroma.Tests.ObanHelpers
22 alias Pleroma.UserInviteToken
23 alias Pleroma.Web.ActivityPub.Relay
24 alias Pleroma.Web.CommonAPI
25 alias Pleroma.Web.MediaProxy
28 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
34 admin = insert(:user, is_admin: true)
35 token = insert(:oauth_admin_token, user: admin)
39 |> assign(:user, admin)
40 |> assign(:token, token)
42 {:ok, %{admin: admin, token: token, conn: conn}}
45 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
46 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
48 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
51 url = "/api/pleroma/admin/users/#{user.nickname}"
53 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
54 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
55 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
57 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
58 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
61 for good_token <- [good_token1, good_token2, good_token3] do
64 |> assign(:user, admin)
65 |> assign(:token, good_token)
68 assert json_response(conn, 200)
71 for good_token <- [good_token1, good_token2, good_token3] do
75 |> assign(:token, good_token)
78 assert json_response(conn, :forbidden)
81 for bad_token <- [bad_token1, bad_token2, bad_token3] do
84 |> assign(:user, admin)
85 |> assign(:token, bad_token)
88 assert json_response(conn, :forbidden)
93 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
94 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
96 test "GET /api/pleroma/admin/users/:nickname requires " <>
97 "read:accounts or admin:read:accounts or broader scope",
100 url = "/api/pleroma/admin/users/#{user.nickname}"
102 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
103 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
104 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
105 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
106 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
108 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
110 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
111 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
114 for good_token <- good_tokens do
117 |> assign(:user, admin)
118 |> assign(:token, good_token)
121 assert json_response(conn, 200)
124 for good_token <- good_tokens do
127 |> assign(:user, nil)
128 |> assign(:token, good_token)
131 assert json_response(conn, :forbidden)
134 for bad_token <- [bad_token1, bad_token2, bad_token3] do
137 |> assign(:user, admin)
138 |> assign(:token, bad_token)
141 assert json_response(conn, :forbidden)
146 describe "DELETE /api/pleroma/admin/users" do
147 test "single user", %{admin: admin, conn: conn} do
150 with_mock Pleroma.Web.Federator,
151 publish: fn _ -> nil end do
154 |> put_req_header("accept", "application/json")
155 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
157 ObanHelpers.perform_all()
159 assert User.get_by_nickname(user.nickname).deactivated
161 log_entry = Repo.one(ModerationLog)
163 assert ModerationLog.get_log_entry_message(log_entry) ==
164 "@#{admin.nickname} deleted users: @#{user.nickname}"
166 assert json_response(conn, 200) == [user.nickname]
168 assert called(Pleroma.Web.Federator.publish(:_))
172 test "multiple users", %{admin: admin, conn: conn} do
173 user_one = insert(:user)
174 user_two = insert(:user)
178 |> put_req_header("accept", "application/json")
179 |> delete("/api/pleroma/admin/users", %{
180 nicknames: [user_one.nickname, user_two.nickname]
183 log_entry = Repo.one(ModerationLog)
185 assert ModerationLog.get_log_entry_message(log_entry) ==
186 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
188 response = json_response(conn, 200)
189 assert response -- [user_one.nickname, user_two.nickname] == []
193 describe "/api/pleroma/admin/users" do
194 test "Create", %{conn: conn} do
197 |> put_req_header("accept", "application/json")
198 |> post("/api/pleroma/admin/users", %{
201 "nickname" => "lain",
202 "email" => "lain@example.org",
206 "nickname" => "lain2",
207 "email" => "lain2@example.org",
213 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
214 assert response == ["success", "success"]
216 log_entry = Repo.one(ModerationLog)
218 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
221 test "Cannot create user with existing email", %{conn: conn} do
226 |> put_req_header("accept", "application/json")
227 |> post("/api/pleroma/admin/users", %{
230 "nickname" => "lain",
231 "email" => user.email,
237 assert json_response(conn, 409) == [
241 "email" => user.email,
244 "error" => "email has already been taken",
250 test "Cannot create user with existing nickname", %{conn: conn} do
255 |> put_req_header("accept", "application/json")
256 |> post("/api/pleroma/admin/users", %{
259 "nickname" => user.nickname,
260 "email" => "someuser@plerama.social",
266 assert json_response(conn, 409) == [
270 "email" => "someuser@plerama.social",
271 "nickname" => user.nickname
273 "error" => "nickname has already been taken",
279 test "Multiple user creation works in transaction", %{conn: conn} do
284 |> put_req_header("accept", "application/json")
285 |> post("/api/pleroma/admin/users", %{
288 "nickname" => "newuser",
289 "email" => "newuser@pleroma.social",
293 "nickname" => "lain",
294 "email" => user.email,
300 assert json_response(conn, 409) == [
304 "email" => user.email,
307 "error" => "email has already been taken",
313 "email" => "newuser@pleroma.social",
314 "nickname" => "newuser"
321 assert User.get_by_nickname("newuser") === nil
325 describe "/api/pleroma/admin/users/:nickname" do
326 test "Show", %{conn: conn} do
329 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
332 "deactivated" => false,
333 "id" => to_string(user.id),
335 "nickname" => user.nickname,
336 "roles" => %{"admin" => false, "moderator" => false},
338 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
339 "display_name" => HTML.strip_tags(user.name || user.nickname),
340 "confirmation_pending" => false
343 assert expected == json_response(conn, 200)
346 test "when the user doesn't exist", %{conn: conn} do
349 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
351 assert "Not found" == json_response(conn, 404)
355 describe "/api/pleroma/admin/users/follow" do
356 test "allows to force-follow another user", %{admin: admin, conn: conn} do
358 follower = insert(:user)
361 |> put_req_header("accept", "application/json")
362 |> post("/api/pleroma/admin/users/follow", %{
363 "follower" => follower.nickname,
364 "followed" => user.nickname
367 user = User.get_cached_by_id(user.id)
368 follower = User.get_cached_by_id(follower.id)
370 assert User.following?(follower, user)
372 log_entry = Repo.one(ModerationLog)
374 assert ModerationLog.get_log_entry_message(log_entry) ==
375 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
379 describe "/api/pleroma/admin/users/unfollow" do
380 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
382 follower = insert(:user)
384 User.follow(follower, user)
387 |> put_req_header("accept", "application/json")
388 |> post("/api/pleroma/admin/users/unfollow", %{
389 "follower" => follower.nickname,
390 "followed" => user.nickname
393 user = User.get_cached_by_id(user.id)
394 follower = User.get_cached_by_id(follower.id)
396 refute User.following?(follower, user)
398 log_entry = Repo.one(ModerationLog)
400 assert ModerationLog.get_log_entry_message(log_entry) ==
401 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
405 describe "PUT /api/pleroma/admin/users/tag" do
406 setup %{conn: conn} do
407 user1 = insert(:user, %{tags: ["x"]})
408 user2 = insert(:user, %{tags: ["y"]})
409 user3 = insert(:user, %{tags: ["unchanged"]})
413 |> put_req_header("accept", "application/json")
415 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
416 "#{user2.nickname}&tags[]=foo&tags[]=bar"
419 %{conn: conn, user1: user1, user2: user2, user3: user3}
422 test "it appends specified tags to users with specified nicknames", %{
428 assert json_response(conn, :no_content)
429 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
430 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
432 log_entry = Repo.one(ModerationLog)
435 [user1.nickname, user2.nickname]
436 |> Enum.map(&"@#{&1}")
439 tags = ["foo", "bar"] |> Enum.join(", ")
441 assert ModerationLog.get_log_entry_message(log_entry) ==
442 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
445 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
446 assert json_response(conn, :no_content)
447 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
451 describe "DELETE /api/pleroma/admin/users/tag" do
452 setup %{conn: conn} do
453 user1 = insert(:user, %{tags: ["x"]})
454 user2 = insert(:user, %{tags: ["y", "z"]})
455 user3 = insert(:user, %{tags: ["unchanged"]})
459 |> put_req_header("accept", "application/json")
461 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
462 "#{user2.nickname}&tags[]=x&tags[]=z"
465 %{conn: conn, user1: user1, user2: user2, user3: user3}
468 test "it removes specified tags from users with specified nicknames", %{
474 assert json_response(conn, :no_content)
475 assert User.get_cached_by_id(user1.id).tags == []
476 assert User.get_cached_by_id(user2.id).tags == ["y"]
478 log_entry = Repo.one(ModerationLog)
481 [user1.nickname, user2.nickname]
482 |> Enum.map(&"@#{&1}")
485 tags = ["x", "z"] |> Enum.join(", ")
487 assert ModerationLog.get_log_entry_message(log_entry) ==
488 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
491 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
492 assert json_response(conn, :no_content)
493 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
497 describe "/api/pleroma/admin/users/:nickname/permission_group" do
498 test "GET is giving user_info", %{admin: admin, conn: conn} do
501 |> put_req_header("accept", "application/json")
502 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
504 assert json_response(conn, 200) == %{
506 "is_moderator" => false
510 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
515 |> put_req_header("accept", "application/json")
516 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
518 assert json_response(conn, 200) == %{
522 log_entry = Repo.one(ModerationLog)
524 assert ModerationLog.get_log_entry_message(log_entry) ==
525 "@#{admin.nickname} made @#{user.nickname} admin"
528 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
529 user_one = insert(:user)
530 user_two = insert(:user)
534 |> put_req_header("accept", "application/json")
535 |> post("/api/pleroma/admin/users/permission_group/admin", %{
536 nicknames: [user_one.nickname, user_two.nickname]
539 assert json_response(conn, 200) == %{"is_admin" => true}
541 log_entry = Repo.one(ModerationLog)
543 assert ModerationLog.get_log_entry_message(log_entry) ==
544 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
547 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
548 user = insert(:user, is_admin: true)
552 |> put_req_header("accept", "application/json")
553 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
555 assert json_response(conn, 200) == %{"is_admin" => false}
557 log_entry = Repo.one(ModerationLog)
559 assert ModerationLog.get_log_entry_message(log_entry) ==
560 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
563 test "/:right DELETE, can remove from a permission group (multiple)", %{
567 user_one = insert(:user, is_admin: true)
568 user_two = insert(:user, is_admin: true)
572 |> put_req_header("accept", "application/json")
573 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
574 nicknames: [user_one.nickname, user_two.nickname]
577 assert json_response(conn, 200) == %{"is_admin" => false}
579 log_entry = Repo.one(ModerationLog)
581 assert ModerationLog.get_log_entry_message(log_entry) ==
582 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
588 describe "POST /api/pleroma/admin/email_invite, with valid config" do
589 setup do: clear_config([:instance, :registrations_open], false)
590 setup do: clear_config([:instance, :invites_enabled], true)
592 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
593 recipient_email = "foo@bar.com"
594 recipient_name = "J. D."
599 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
602 assert json_response(conn, :no_content)
604 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
606 refute token_record.used
608 notify_email = Config.get([:instance, :notify_email])
609 instance_name = Config.get([:instance, :name])
612 Pleroma.Emails.UserEmail.user_invitation_email(
619 Swoosh.TestAssertions.assert_email_sent(
620 from: {instance_name, notify_email},
621 to: {recipient_name, recipient_email},
622 html_body: email.html_body
626 test "it returns 403 if requested by a non-admin" do
627 non_admin_user = insert(:user)
628 token = insert(:oauth_token, user: non_admin_user)
632 |> assign(:user, non_admin_user)
633 |> assign(:token, token)
634 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
636 assert json_response(conn, :forbidden)
639 test "email with +", %{conn: conn, admin: admin} do
640 recipient_email = "foo+bar@baz.com"
643 |> put_req_header("content-type", "application/json;charset=utf-8")
644 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
645 |> json_response(:no_content)
648 Pleroma.UserInviteToken
653 refute token_record.used
655 notify_email = Config.get([:instance, :notify_email])
656 instance_name = Config.get([:instance, :name])
659 Pleroma.Emails.UserEmail.user_invitation_email(
665 Swoosh.TestAssertions.assert_email_sent(
666 from: {instance_name, notify_email},
668 html_body: email.html_body
673 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
674 setup do: clear_config([:instance, :registrations_open])
675 setup do: clear_config([:instance, :invites_enabled])
677 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
678 Config.put([:instance, :registrations_open], false)
679 Config.put([:instance, :invites_enabled], false)
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 `invites_enabled` option to true."
687 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
688 Config.put([:instance, :registrations_open], true)
689 Config.put([:instance, :invites_enabled], true)
691 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
693 assert json_response(conn, :bad_request) ==
694 "To send invites you need to set the `registrations_open` option to false."
698 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
703 |> put_req_header("accept", "application/json")
704 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
706 resp = json_response(conn, 200)
708 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
711 describe "GET /api/pleroma/admin/users" do
712 test "renders users array for the first page", %{conn: conn, admin: admin} do
713 user = insert(:user, local: false, tags: ["foo", "bar"])
714 conn = get(conn, "/api/pleroma/admin/users?page=1")
719 "deactivated" => admin.deactivated,
721 "nickname" => admin.nickname,
722 "roles" => %{"admin" => true, "moderator" => false},
725 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
726 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
727 "confirmation_pending" => false
730 "deactivated" => user.deactivated,
732 "nickname" => user.nickname,
733 "roles" => %{"admin" => false, "moderator" => false},
735 "tags" => ["foo", "bar"],
736 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
737 "display_name" => HTML.strip_tags(user.name || user.nickname),
738 "confirmation_pending" => false
741 |> Enum.sort_by(& &1["nickname"])
743 assert json_response(conn, 200) == %{
750 test "renders empty array for the second page", %{conn: conn} do
753 conn = get(conn, "/api/pleroma/admin/users?page=2")
755 assert json_response(conn, 200) == %{
762 test "regular search", %{conn: conn} do
763 user = insert(:user, nickname: "bob")
765 conn = get(conn, "/api/pleroma/admin/users?query=bo")
767 assert json_response(conn, 200) == %{
772 "deactivated" => user.deactivated,
774 "nickname" => user.nickname,
775 "roles" => %{"admin" => false, "moderator" => false},
778 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
779 "display_name" => HTML.strip_tags(user.name || user.nickname),
780 "confirmation_pending" => false
786 test "search by domain", %{conn: conn} do
787 user = insert(:user, nickname: "nickname@domain.com")
790 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
792 assert json_response(conn, 200) == %{
797 "deactivated" => user.deactivated,
799 "nickname" => user.nickname,
800 "roles" => %{"admin" => false, "moderator" => false},
803 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
804 "display_name" => HTML.strip_tags(user.name || user.nickname),
805 "confirmation_pending" => false
811 test "search by full nickname", %{conn: conn} do
812 user = insert(:user, nickname: "nickname@domain.com")
815 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
817 assert json_response(conn, 200) == %{
822 "deactivated" => user.deactivated,
824 "nickname" => user.nickname,
825 "roles" => %{"admin" => false, "moderator" => false},
828 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
829 "display_name" => HTML.strip_tags(user.name || user.nickname),
830 "confirmation_pending" => false
836 test "search by display name", %{conn: conn} do
837 user = insert(:user, name: "Display name")
840 conn = get(conn, "/api/pleroma/admin/users?name=display")
842 assert json_response(conn, 200) == %{
847 "deactivated" => user.deactivated,
849 "nickname" => user.nickname,
850 "roles" => %{"admin" => false, "moderator" => false},
853 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
854 "display_name" => HTML.strip_tags(user.name || user.nickname),
855 "confirmation_pending" => false
861 test "search by email", %{conn: conn} do
862 user = insert(:user, email: "email@example.com")
865 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
867 assert json_response(conn, 200) == %{
872 "deactivated" => user.deactivated,
874 "nickname" => user.nickname,
875 "roles" => %{"admin" => false, "moderator" => false},
878 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
879 "display_name" => HTML.strip_tags(user.name || user.nickname),
880 "confirmation_pending" => false
886 test "regular search with page size", %{conn: conn} do
887 user = insert(:user, nickname: "aalice")
888 user2 = insert(:user, nickname: "alice")
890 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
892 assert json_response(conn1, 200) == %{
897 "deactivated" => user.deactivated,
899 "nickname" => user.nickname,
900 "roles" => %{"admin" => false, "moderator" => false},
903 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
904 "display_name" => HTML.strip_tags(user.name || user.nickname),
905 "confirmation_pending" => false
910 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
912 assert json_response(conn2, 200) == %{
917 "deactivated" => user2.deactivated,
919 "nickname" => user2.nickname,
920 "roles" => %{"admin" => false, "moderator" => false},
923 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
924 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
925 "confirmation_pending" => false
931 test "only local users" do
932 admin = insert(:user, is_admin: true, nickname: "john")
933 token = insert(:oauth_admin_token, user: admin)
934 user = insert(:user, nickname: "bob")
936 insert(:user, nickname: "bobb", local: false)
940 |> assign(:user, admin)
941 |> assign(:token, token)
942 |> get("/api/pleroma/admin/users?query=bo&filters=local")
944 assert json_response(conn, 200) == %{
949 "deactivated" => user.deactivated,
951 "nickname" => user.nickname,
952 "roles" => %{"admin" => false, "moderator" => false},
955 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
956 "display_name" => HTML.strip_tags(user.name || user.nickname),
957 "confirmation_pending" => false
963 test "only local users with no query", %{conn: conn, admin: old_admin} do
964 admin = insert(:user, is_admin: true, nickname: "john")
965 user = insert(:user, nickname: "bob")
967 insert(:user, nickname: "bobb", local: false)
969 conn = get(conn, "/api/pleroma/admin/users?filters=local")
974 "deactivated" => user.deactivated,
976 "nickname" => user.nickname,
977 "roles" => %{"admin" => false, "moderator" => false},
980 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
981 "display_name" => HTML.strip_tags(user.name || user.nickname),
982 "confirmation_pending" => false
985 "deactivated" => admin.deactivated,
987 "nickname" => admin.nickname,
988 "roles" => %{"admin" => true, "moderator" => false},
991 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
992 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
993 "confirmation_pending" => false
996 "deactivated" => false,
997 "id" => old_admin.id,
999 "nickname" => old_admin.nickname,
1000 "roles" => %{"admin" => true, "moderator" => false},
1002 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1003 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1004 "confirmation_pending" => false
1007 |> Enum.sort_by(& &1["nickname"])
1009 assert json_response(conn, 200) == %{
1016 test "load only admins", %{conn: conn, admin: admin} do
1017 second_admin = insert(:user, is_admin: true)
1021 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1026 "deactivated" => false,
1028 "nickname" => admin.nickname,
1029 "roles" => %{"admin" => true, "moderator" => false},
1030 "local" => admin.local,
1032 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1033 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1034 "confirmation_pending" => false
1037 "deactivated" => false,
1038 "id" => second_admin.id,
1039 "nickname" => second_admin.nickname,
1040 "roles" => %{"admin" => true, "moderator" => false},
1041 "local" => second_admin.local,
1043 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1044 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1045 "confirmation_pending" => false
1048 |> Enum.sort_by(& &1["nickname"])
1050 assert json_response(conn, 200) == %{
1057 test "load only moderators", %{conn: conn} do
1058 moderator = insert(:user, is_moderator: true)
1062 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1064 assert json_response(conn, 200) == %{
1069 "deactivated" => false,
1070 "id" => moderator.id,
1071 "nickname" => moderator.nickname,
1072 "roles" => %{"admin" => false, "moderator" => true},
1073 "local" => moderator.local,
1075 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1076 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1077 "confirmation_pending" => false
1083 test "load users with tags list", %{conn: conn} do
1084 user1 = insert(:user, tags: ["first"])
1085 user2 = insert(:user, tags: ["second"])
1089 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1094 "deactivated" => false,
1096 "nickname" => user1.nickname,
1097 "roles" => %{"admin" => false, "moderator" => false},
1098 "local" => user1.local,
1099 "tags" => ["first"],
1100 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1101 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1102 "confirmation_pending" => false
1105 "deactivated" => false,
1107 "nickname" => user2.nickname,
1108 "roles" => %{"admin" => false, "moderator" => false},
1109 "local" => user2.local,
1110 "tags" => ["second"],
1111 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1112 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1113 "confirmation_pending" => false
1116 |> Enum.sort_by(& &1["nickname"])
1118 assert json_response(conn, 200) == %{
1125 test "it works with multiple filters" do
1126 admin = insert(:user, nickname: "john", is_admin: true)
1127 token = insert(:oauth_admin_token, user: admin)
1128 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1130 insert(:user, nickname: "ken", local: true, deactivated: true)
1131 insert(:user, nickname: "bobb", local: false, deactivated: false)
1135 |> assign(:user, admin)
1136 |> assign(:token, token)
1137 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1139 assert json_response(conn, 200) == %{
1144 "deactivated" => user.deactivated,
1146 "nickname" => user.nickname,
1147 "roles" => %{"admin" => false, "moderator" => false},
1148 "local" => user.local,
1150 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1151 "display_name" => HTML.strip_tags(user.name || user.nickname),
1152 "confirmation_pending" => false
1158 test "it omits relay user", %{admin: admin, conn: conn} do
1159 assert %User{} = Relay.get_actor()
1161 conn = get(conn, "/api/pleroma/admin/users")
1163 assert json_response(conn, 200) == %{
1168 "deactivated" => admin.deactivated,
1170 "nickname" => admin.nickname,
1171 "roles" => %{"admin" => true, "moderator" => false},
1174 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1175 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1176 "confirmation_pending" => false
1183 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1184 user_one = insert(:user, deactivated: true)
1185 user_two = insert(:user, deactivated: true)
1190 "/api/pleroma/admin/users/activate",
1191 %{nicknames: [user_one.nickname, user_two.nickname]}
1194 response = json_response(conn, 200)
1195 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1197 log_entry = Repo.one(ModerationLog)
1199 assert ModerationLog.get_log_entry_message(log_entry) ==
1200 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1203 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1204 user_one = insert(:user, deactivated: false)
1205 user_two = insert(:user, deactivated: false)
1210 "/api/pleroma/admin/users/deactivate",
1211 %{nicknames: [user_one.nickname, user_two.nickname]}
1214 response = json_response(conn, 200)
1215 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1217 log_entry = Repo.one(ModerationLog)
1219 assert ModerationLog.get_log_entry_message(log_entry) ==
1220 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1223 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1224 user = insert(:user)
1226 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1228 assert json_response(conn, 200) ==
1230 "deactivated" => !user.deactivated,
1232 "nickname" => user.nickname,
1233 "roles" => %{"admin" => false, "moderator" => false},
1236 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1237 "display_name" => HTML.strip_tags(user.name || user.nickname),
1238 "confirmation_pending" => false
1241 log_entry = Repo.one(ModerationLog)
1243 assert ModerationLog.get_log_entry_message(log_entry) ==
1244 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1247 describe "POST /api/pleroma/admin/users/invite_token" do
1248 test "without options", %{conn: conn} do
1249 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1251 invite_json = json_response(conn, 200)
1252 invite = UserInviteToken.find_by_token!(invite_json["token"])
1254 refute invite.expires_at
1255 refute invite.max_use
1256 assert invite.invite_type == "one_time"
1259 test "with expires_at", %{conn: conn} do
1261 post(conn, "/api/pleroma/admin/users/invite_token", %{
1262 "expires_at" => Date.to_string(Date.utc_today())
1265 invite_json = json_response(conn, 200)
1266 invite = UserInviteToken.find_by_token!(invite_json["token"])
1269 assert invite.expires_at == Date.utc_today()
1270 refute invite.max_use
1271 assert invite.invite_type == "date_limited"
1274 test "with max_use", %{conn: conn} do
1275 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1277 invite_json = json_response(conn, 200)
1278 invite = UserInviteToken.find_by_token!(invite_json["token"])
1280 refute invite.expires_at
1281 assert invite.max_use == 150
1282 assert invite.invite_type == "reusable"
1285 test "with max use and expires_at", %{conn: conn} do
1287 post(conn, "/api/pleroma/admin/users/invite_token", %{
1289 "expires_at" => Date.to_string(Date.utc_today())
1292 invite_json = json_response(conn, 200)
1293 invite = UserInviteToken.find_by_token!(invite_json["token"])
1295 assert invite.expires_at == Date.utc_today()
1296 assert invite.max_use == 150
1297 assert invite.invite_type == "reusable_date_limited"
1301 describe "GET /api/pleroma/admin/users/invites" do
1302 test "no invites", %{conn: conn} do
1303 conn = get(conn, "/api/pleroma/admin/users/invites")
1305 assert json_response(conn, 200) == %{"invites" => []}
1308 test "with invite", %{conn: conn} do
1309 {:ok, invite} = UserInviteToken.create_invite()
1311 conn = get(conn, "/api/pleroma/admin/users/invites")
1313 assert json_response(conn, 200) == %{
1316 "expires_at" => nil,
1318 "invite_type" => "one_time",
1320 "token" => invite.token,
1329 describe "POST /api/pleroma/admin/users/revoke_invite" do
1330 test "with token", %{conn: conn} do
1331 {:ok, invite} = UserInviteToken.create_invite()
1333 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1335 assert json_response(conn, 200) == %{
1336 "expires_at" => nil,
1338 "invite_type" => "one_time",
1340 "token" => invite.token,
1346 test "with invalid token", %{conn: conn} do
1347 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1349 assert json_response(conn, :not_found) == "Not found"
1353 describe "GET /api/pleroma/admin/reports/:id" do
1354 test "returns report by its id", %{conn: conn} do
1355 [reporter, target_user] = insert_pair(:user)
1356 activity = insert(:note_activity, user: target_user)
1358 {:ok, %{id: report_id}} =
1359 CommonAPI.report(reporter, %{
1360 account_id: target_user.id,
1361 comment: "I feel offended",
1362 status_ids: [activity.id]
1367 |> get("/api/pleroma/admin/reports/#{report_id}")
1368 |> json_response(:ok)
1370 assert response["id"] == report_id
1373 test "returns 404 when report id is invalid", %{conn: conn} do
1374 conn = get(conn, "/api/pleroma/admin/reports/test")
1376 assert json_response(conn, :not_found) == "Not found"
1380 describe "PATCH /api/pleroma/admin/reports" do
1382 [reporter, target_user] = insert_pair(:user)
1383 activity = insert(:note_activity, user: target_user)
1385 {:ok, %{id: report_id}} =
1386 CommonAPI.report(reporter, %{
1387 account_id: target_user.id,
1388 comment: "I feel offended",
1389 status_ids: [activity.id]
1392 {:ok, %{id: second_report_id}} =
1393 CommonAPI.report(reporter, %{
1394 account_id: target_user.id,
1395 comment: "I feel very offended",
1396 status_ids: [activity.id]
1401 second_report_id: second_report_id
1405 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1406 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1407 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1411 |> assign(:token, read_token)
1412 |> patch("/api/pleroma/admin/reports", %{
1413 "reports" => [%{"state" => "resolved", "id" => id}]
1415 |> json_response(403)
1417 assert response == %{
1418 "error" => "Insufficient permissions: admin:write:reports."
1422 |> assign(:token, write_token)
1423 |> patch("/api/pleroma/admin/reports", %{
1424 "reports" => [%{"state" => "resolved", "id" => id}]
1426 |> json_response(:no_content)
1429 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1431 |> patch("/api/pleroma/admin/reports", %{
1433 %{"state" => "resolved", "id" => id}
1436 |> json_response(:no_content)
1438 activity = Activity.get_by_id(id)
1439 assert activity.data["state"] == "resolved"
1441 log_entry = Repo.one(ModerationLog)
1443 assert ModerationLog.get_log_entry_message(log_entry) ==
1444 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1447 test "closes report", %{conn: conn, id: id, admin: admin} do
1449 |> patch("/api/pleroma/admin/reports", %{
1451 %{"state" => "closed", "id" => id}
1454 |> json_response(:no_content)
1456 activity = Activity.get_by_id(id)
1457 assert activity.data["state"] == "closed"
1459 log_entry = Repo.one(ModerationLog)
1461 assert ModerationLog.get_log_entry_message(log_entry) ==
1462 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1465 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1468 |> patch("/api/pleroma/admin/reports", %{
1470 %{"state" => "test", "id" => id}
1474 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1477 test "returns 404 when report is not exist", %{conn: conn} do
1480 |> patch("/api/pleroma/admin/reports", %{
1482 %{"state" => "closed", "id" => "test"}
1486 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1489 test "updates state of multiple reports", %{
1493 second_report_id: second_report_id
1496 |> patch("/api/pleroma/admin/reports", %{
1498 %{"state" => "resolved", "id" => id},
1499 %{"state" => "closed", "id" => second_report_id}
1502 |> json_response(:no_content)
1504 activity = Activity.get_by_id(id)
1505 second_activity = Activity.get_by_id(second_report_id)
1506 assert activity.data["state"] == "resolved"
1507 assert second_activity.data["state"] == "closed"
1509 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1511 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1512 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1514 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1515 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1519 describe "GET /api/pleroma/admin/reports" do
1520 test "returns empty response when no reports created", %{conn: conn} do
1523 |> get("/api/pleroma/admin/reports")
1524 |> json_response(:ok)
1526 assert Enum.empty?(response["reports"])
1527 assert response["total"] == 0
1530 test "returns reports", %{conn: conn} do
1531 [reporter, target_user] = insert_pair(:user)
1532 activity = insert(:note_activity, user: target_user)
1534 {:ok, %{id: report_id}} =
1535 CommonAPI.report(reporter, %{
1536 account_id: target_user.id,
1537 comment: "I feel offended",
1538 status_ids: [activity.id]
1543 |> get("/api/pleroma/admin/reports")
1544 |> json_response(:ok)
1546 [report] = response["reports"]
1548 assert length(response["reports"]) == 1
1549 assert report["id"] == report_id
1551 assert response["total"] == 1
1554 test "returns reports with specified state", %{conn: conn} do
1555 [reporter, target_user] = insert_pair(:user)
1556 activity = insert(:note_activity, user: target_user)
1558 {:ok, %{id: first_report_id}} =
1559 CommonAPI.report(reporter, %{
1560 account_id: target_user.id,
1561 comment: "I feel offended",
1562 status_ids: [activity.id]
1565 {:ok, %{id: second_report_id}} =
1566 CommonAPI.report(reporter, %{
1567 account_id: target_user.id,
1568 comment: "I don't like this user"
1571 CommonAPI.update_report_state(second_report_id, "closed")
1575 |> get("/api/pleroma/admin/reports", %{
1578 |> json_response(:ok)
1580 [open_report] = response["reports"]
1582 assert length(response["reports"]) == 1
1583 assert open_report["id"] == first_report_id
1585 assert response["total"] == 1
1589 |> get("/api/pleroma/admin/reports", %{
1592 |> json_response(:ok)
1594 [closed_report] = response["reports"]
1596 assert length(response["reports"]) == 1
1597 assert closed_report["id"] == second_report_id
1599 assert response["total"] == 1
1603 |> get("/api/pleroma/admin/reports", %{
1604 "state" => "resolved"
1606 |> json_response(:ok)
1608 assert Enum.empty?(response["reports"])
1609 assert response["total"] == 0
1612 test "returns 403 when requested by a non-admin" do
1613 user = insert(:user)
1614 token = insert(:oauth_token, user: user)
1618 |> assign(:user, user)
1619 |> assign(:token, token)
1620 |> get("/api/pleroma/admin/reports")
1622 assert json_response(conn, :forbidden) ==
1623 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1626 test "returns 403 when requested by anonymous" do
1627 conn = get(build_conn(), "/api/pleroma/admin/reports")
1629 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1633 describe "PUT /api/pleroma/admin/statuses/:id" do
1635 activity = insert(:note_activity)
1640 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1643 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1644 |> json_response(:ok)
1646 assert response["sensitive"]
1648 log_entry = Repo.one(ModerationLog)
1650 assert ModerationLog.get_log_entry_message(log_entry) ==
1651 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1655 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1656 |> json_response(:ok)
1658 refute response["sensitive"]
1661 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1664 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1665 |> json_response(:ok)
1667 assert response["visibility"] == "public"
1669 log_entry = Repo.one(ModerationLog)
1671 assert ModerationLog.get_log_entry_message(log_entry) ==
1672 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1676 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1677 |> json_response(:ok)
1679 assert response["visibility"] == "private"
1683 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1684 |> json_response(:ok)
1686 assert response["visibility"] == "unlisted"
1689 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1690 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1692 assert json_response(conn, :bad_request) == "Unsupported visibility"
1696 describe "DELETE /api/pleroma/admin/statuses/:id" do
1698 activity = insert(:note_activity)
1703 test "deletes status", %{conn: conn, id: id, admin: admin} do
1705 |> delete("/api/pleroma/admin/statuses/#{id}")
1706 |> json_response(:ok)
1708 refute Activity.get_by_id(id)
1710 log_entry = Repo.one(ModerationLog)
1712 assert ModerationLog.get_log_entry_message(log_entry) ==
1713 "@#{admin.nickname} deleted status ##{id}"
1716 test "returns 404 when the status does not exist", %{conn: conn} do
1717 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1719 assert json_response(conn, :not_found) == "Not found"
1723 describe "GET /api/pleroma/admin/config" do
1724 setup do: clear_config(:configurable_from_database, true)
1726 test "when configuration from database is off", %{conn: conn} do
1727 Config.put(:configurable_from_database, false)
1728 conn = get(conn, "/api/pleroma/admin/config")
1730 assert json_response(conn, 400) ==
1731 "To use this endpoint you need to enable configuration from database."
1734 test "with settings only in db", %{conn: conn} do
1735 config1 = insert(:config)
1736 config2 = insert(:config)
1738 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1743 "group" => ":pleroma",
1748 "group" => ":pleroma",
1753 } = json_response(conn, 200)
1755 assert key1 == config1.key
1756 assert key2 == config2.key
1759 test "db is added to settings that are in db", %{conn: conn} do
1760 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1762 %{"configs" => configs} =
1764 |> get("/api/pleroma/admin/config")
1765 |> json_response(200)
1768 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1769 group == ":pleroma" and key == ":instance"
1772 assert instance_config["db"] == [":name"]
1775 test "merged default setting with db settings", %{conn: conn} do
1776 config1 = insert(:config)
1777 config2 = insert(:config)
1781 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1784 %{"configs" => configs} =
1786 |> get("/api/pleroma/admin/config")
1787 |> json_response(200)
1789 assert length(configs) > 3
1792 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1793 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1796 assert length(received_configs) == 3
1800 |> ConfigDB.from_binary()
1802 |> ConfigDB.convert()
1804 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1805 assert db in [[config1.key], [config2.key], db_keys]
1808 ConfigDB.from_binary_with_convert(config1.value),
1809 ConfigDB.from_binary_with_convert(config2.value),
1810 ConfigDB.from_binary_with_convert(config3.value)
1815 test "subkeys with full update right merge", %{conn: conn} do
1819 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1825 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1828 %{"configs" => configs} =
1830 |> get("/api/pleroma/admin/config")
1831 |> json_response(200)
1834 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1835 group == ":pleroma" and key in [config1.key, config2.key]
1838 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1839 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1841 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1842 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1844 assert emoji_val[:groups] == [a: 1, b: 2]
1845 assert assets_val[:mascots] == [a: 1, b: 2]
1849 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1850 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1852 assert json_response(conn, 400) ==
1853 "To use this endpoint you need to enable configuration from database."
1856 describe "POST /api/pleroma/admin/config" do
1858 http = Application.get_env(:pleroma, :http)
1861 Application.delete_env(:pleroma, :key1)
1862 Application.delete_env(:pleroma, :key2)
1863 Application.delete_env(:pleroma, :key3)
1864 Application.delete_env(:pleroma, :key4)
1865 Application.delete_env(:pleroma, :keyaa1)
1866 Application.delete_env(:pleroma, :keyaa2)
1867 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1868 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1869 Application.put_env(:pleroma, :http, http)
1870 Application.put_env(:tesla, :adapter, Tesla.Mock)
1871 Restarter.Pleroma.refresh()
1875 setup do: clear_config(:configurable_from_database, true)
1877 @tag capture_log: true
1878 test "create new config setting in db", %{conn: conn} do
1879 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1880 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1883 post(conn, "/api/pleroma/admin/config", %{
1885 %{group: ":pleroma", key: ":key1", value: "value1"},
1887 group: ":ueberauth",
1889 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1895 ":nested_1" => "nested_value1",
1897 %{":nested_22" => "nested_value222"},
1898 %{":nested_33" => %{":nested_44" => "nested_444"}}
1906 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1907 %{"nested_4" => true}
1913 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1918 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1923 assert json_response(conn, 200) == %{
1926 "group" => ":pleroma",
1928 "value" => "value1",
1932 "group" => ":ueberauth",
1933 "key" => "Ueberauth",
1934 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1935 "db" => [":consumer_secret"]
1938 "group" => ":pleroma",
1941 ":nested_1" => "nested_value1",
1943 %{":nested_22" => "nested_value222"},
1944 %{":nested_33" => %{":nested_44" => "nested_444"}}
1950 "group" => ":pleroma",
1953 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1954 %{"nested_4" => true}
1959 "group" => ":pleroma",
1961 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
1967 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
1973 assert Application.get_env(:pleroma, :key1) == "value1"
1975 assert Application.get_env(:pleroma, :key2) == %{
1976 nested_1: "nested_value1",
1978 %{nested_22: "nested_value222"},
1979 %{nested_33: %{nested_44: "nested_444"}}
1983 assert Application.get_env(:pleroma, :key3) == [
1984 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
1985 %{"nested_4" => true}
1988 assert Application.get_env(:pleroma, :key4) == %{
1989 "endpoint" => "https://example.com",
1993 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
1996 test "save configs setting without explicit key", %{conn: conn} do
1997 level = Application.get_env(:quack, :level)
1998 meta = Application.get_env(:quack, :meta)
1999 webhook_url = Application.get_env(:quack, :webhook_url)
2002 Application.put_env(:quack, :level, level)
2003 Application.put_env(:quack, :meta, meta)
2004 Application.put_env(:quack, :webhook_url, webhook_url)
2008 post(conn, "/api/pleroma/admin/config", %{
2022 key: ":webhook_url",
2023 value: "https://hooks.slack.com/services/KEY"
2028 assert json_response(conn, 200) == %{
2031 "group" => ":quack",
2037 "group" => ":quack",
2039 "value" => [":none"],
2043 "group" => ":quack",
2044 "key" => ":webhook_url",
2045 "value" => "https://hooks.slack.com/services/KEY",
2046 "db" => [":webhook_url"]
2051 assert Application.get_env(:quack, :level) == :info
2052 assert Application.get_env(:quack, :meta) == [:none]
2053 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2056 test "saving config with partial update", %{conn: conn} do
2057 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2060 post(conn, "/api/pleroma/admin/config", %{
2062 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2066 assert json_response(conn, 200) == %{
2069 "group" => ":pleroma",
2072 %{"tuple" => [":key1", 1]},
2073 %{"tuple" => [":key2", 2]},
2074 %{"tuple" => [":key3", 3]}
2076 "db" => [":key1", ":key2", ":key3"]
2082 test "saving config which need pleroma reboot", %{conn: conn} do
2083 chat = Config.get(:chat)
2084 on_exit(fn -> Config.put(:chat, chat) end)
2088 "/api/pleroma/admin/config",
2091 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2095 |> json_response(200) == %{
2098 "db" => [":enabled"],
2099 "group" => ":pleroma",
2101 "value" => [%{"tuple" => [":enabled", true]}]
2104 "need_reboot" => true
2109 |> get("/api/pleroma/admin/config")
2110 |> json_response(200)
2112 assert configs["need_reboot"]
2115 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2116 end) =~ "pleroma restarted"
2120 |> get("/api/pleroma/admin/config")
2121 |> json_response(200)
2123 assert configs["need_reboot"] == false
2126 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2127 chat = Config.get(:chat)
2128 on_exit(fn -> Config.put(:chat, chat) end)
2132 "/api/pleroma/admin/config",
2135 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2139 |> json_response(200) == %{
2142 "db" => [":enabled"],
2143 "group" => ":pleroma",
2145 "value" => [%{"tuple" => [":enabled", true]}]
2148 "need_reboot" => true
2151 assert post(conn, "/api/pleroma/admin/config", %{
2153 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2156 |> json_response(200) == %{
2159 "group" => ":pleroma",
2162 %{"tuple" => [":key3", 3]}
2167 "need_reboot" => true
2171 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2172 end) =~ "pleroma restarted"
2176 |> get("/api/pleroma/admin/config")
2177 |> json_response(200)
2179 assert configs["need_reboot"] == false
2182 test "saving config with nested merge", %{conn: conn} do
2184 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2187 post(conn, "/api/pleroma/admin/config", %{
2190 group: config.group,
2193 %{"tuple" => [":key3", 3]},
2198 %{"tuple" => [":k2", 1]},
2199 %{"tuple" => [":k3", 3]}
2208 assert json_response(conn, 200) == %{
2211 "group" => ":pleroma",
2214 %{"tuple" => [":key1", 1]},
2215 %{"tuple" => [":key3", 3]},
2220 %{"tuple" => [":k1", 1]},
2221 %{"tuple" => [":k2", 1]},
2222 %{"tuple" => [":k3", 3]}
2227 "db" => [":key1", ":key3", ":key2"]
2233 test "saving special atoms", %{conn: conn} do
2235 post(conn, "/api/pleroma/admin/config", %{
2238 "group" => ":pleroma",
2244 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2252 assert json_response(conn, 200) == %{
2255 "group" => ":pleroma",
2261 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2265 "db" => [":ssl_options"]
2270 assert Application.get_env(:pleroma, :key1) == [
2271 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2275 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2276 backends = Application.get_env(:logger, :backends)
2277 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2283 value: :erlang.term_to_binary([])
2286 Pleroma.Config.TransferTask.load_and_update_env([], false)
2288 assert Application.get_env(:logger, :backends) == []
2291 post(conn, "/api/pleroma/admin/config", %{
2294 group: config.group,
2301 assert json_response(conn, 200) == %{
2304 "group" => ":logger",
2305 "key" => ":backends",
2309 "db" => [":backends"]
2314 assert Application.get_env(:logger, :backends) == [
2319 test "saving full setting if value is not keyword", %{conn: conn} do
2324 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2328 post(conn, "/api/pleroma/admin/config", %{
2330 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2334 assert json_response(conn, 200) == %{
2337 "group" => ":tesla",
2338 "key" => ":adapter",
2339 "value" => "Tesla.Adapter.Httpc",
2340 "db" => [":adapter"]
2346 test "update config setting & delete with fallback to default value", %{
2351 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2352 config1 = insert(:config, key: ":keyaa1")
2353 config2 = insert(:config, key: ":keyaa2")
2357 group: ":ueberauth",
2362 post(conn, "/api/pleroma/admin/config", %{
2364 %{group: config1.group, key: config1.key, value: "another_value"},
2365 %{group: config2.group, key: config2.key, value: "another_value"}
2369 assert json_response(conn, 200) == %{
2372 "group" => ":pleroma",
2373 "key" => config1.key,
2374 "value" => "another_value",
2378 "group" => ":pleroma",
2379 "key" => config2.key,
2380 "value" => "another_value",
2386 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2387 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2388 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2392 |> assign(:user, admin)
2393 |> assign(:token, token)
2394 |> post("/api/pleroma/admin/config", %{
2396 %{group: config2.group, key: config2.key, delete: true},
2398 group: ":ueberauth",
2405 assert json_response(conn, 200) == %{
2409 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2410 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2413 test "common config example", %{conn: conn} do
2415 post(conn, "/api/pleroma/admin/config", %{
2418 "group" => ":pleroma",
2419 "key" => "Pleroma.Captcha.NotReal",
2421 %{"tuple" => [":enabled", false]},
2422 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2423 %{"tuple" => [":seconds_valid", 60]},
2424 %{"tuple" => [":path", ""]},
2425 %{"tuple" => [":key1", nil]},
2426 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2427 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2428 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2429 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2430 %{"tuple" => [":name", "Pleroma"]}
2436 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2438 assert json_response(conn, 200) == %{
2441 "group" => ":pleroma",
2442 "key" => "Pleroma.Captcha.NotReal",
2444 %{"tuple" => [":enabled", false]},
2445 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2446 %{"tuple" => [":seconds_valid", 60]},
2447 %{"tuple" => [":path", ""]},
2448 %{"tuple" => [":key1", nil]},
2449 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2450 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2451 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2452 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2453 %{"tuple" => [":name", "Pleroma"]}
2472 test "tuples with more than two values", %{conn: conn} do
2474 post(conn, "/api/pleroma/admin/config", %{
2477 "group" => ":pleroma",
2478 "key" => "Pleroma.Web.Endpoint.NotReal",
2494 "/api/v1/streaming",
2495 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2502 "Phoenix.Endpoint.CowboyWebSocket",
2505 "Phoenix.Transports.WebSocket",
2508 "Pleroma.Web.Endpoint",
2509 "Pleroma.Web.UserSocket",
2520 "Phoenix.Endpoint.Cowboy2Handler",
2521 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2538 assert json_response(conn, 200) == %{
2541 "group" => ":pleroma",
2542 "key" => "Pleroma.Web.Endpoint.NotReal",
2558 "/api/v1/streaming",
2559 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2566 "Phoenix.Endpoint.CowboyWebSocket",
2569 "Phoenix.Transports.WebSocket",
2572 "Pleroma.Web.Endpoint",
2573 "Pleroma.Web.UserSocket",
2584 "Phoenix.Endpoint.Cowboy2Handler",
2585 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2604 test "settings with nesting map", %{conn: conn} do
2606 post(conn, "/api/pleroma/admin/config", %{
2609 "group" => ":pleroma",
2612 %{"tuple" => [":key2", "some_val"]},
2617 ":max_options" => 20,
2618 ":max_option_chars" => 200,
2619 ":min_expiration" => 0,
2620 ":max_expiration" => 31_536_000,
2622 ":max_options" => 20,
2623 ":max_option_chars" => 200,
2624 ":min_expiration" => 0,
2625 ":max_expiration" => 31_536_000
2635 assert json_response(conn, 200) ==
2639 "group" => ":pleroma",
2642 %{"tuple" => [":key2", "some_val"]},
2647 ":max_expiration" => 31_536_000,
2648 ":max_option_chars" => 200,
2649 ":max_options" => 20,
2650 ":min_expiration" => 0,
2652 ":max_expiration" => 31_536_000,
2653 ":max_option_chars" => 200,
2654 ":max_options" => 20,
2655 ":min_expiration" => 0
2661 "db" => [":key2", ":key3"]
2667 test "value as map", %{conn: conn} do
2669 post(conn, "/api/pleroma/admin/config", %{
2672 "group" => ":pleroma",
2674 "value" => %{"key" => "some_val"}
2679 assert json_response(conn, 200) ==
2683 "group" => ":pleroma",
2685 "value" => %{"key" => "some_val"},
2692 test "queues key as atom", %{conn: conn} do
2694 post(conn, "/api/pleroma/admin/config", %{
2700 %{"tuple" => [":federator_incoming", 50]},
2701 %{"tuple" => [":federator_outgoing", 50]},
2702 %{"tuple" => [":web_push", 50]},
2703 %{"tuple" => [":mailer", 10]},
2704 %{"tuple" => [":transmogrifier", 20]},
2705 %{"tuple" => [":scheduled_activities", 10]},
2706 %{"tuple" => [":background", 5]}
2712 assert json_response(conn, 200) == %{
2718 %{"tuple" => [":federator_incoming", 50]},
2719 %{"tuple" => [":federator_outgoing", 50]},
2720 %{"tuple" => [":web_push", 50]},
2721 %{"tuple" => [":mailer", 10]},
2722 %{"tuple" => [":transmogrifier", 20]},
2723 %{"tuple" => [":scheduled_activities", 10]},
2724 %{"tuple" => [":background", 5]}
2727 ":federator_incoming",
2728 ":federator_outgoing",
2732 ":scheduled_activities",
2740 test "delete part of settings by atom subkeys", %{conn: conn} do
2744 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2748 post(conn, "/api/pleroma/admin/config", %{
2751 group: config.group,
2753 subkeys: [":subkey1", ":subkey3"],
2759 assert json_response(conn, 200) == %{
2762 "group" => ":pleroma",
2764 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2765 "db" => [":subkey2"]
2771 test "proxy tuple localhost", %{conn: conn} do
2773 post(conn, "/api/pleroma/admin/config", %{
2779 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2780 %{"tuple" => [":send_user_agent", false]}
2786 assert json_response(conn, 200) == %{
2789 "group" => ":pleroma",
2792 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2793 %{"tuple" => [":send_user_agent", false]}
2795 "db" => [":proxy_url", ":send_user_agent"]
2801 test "proxy tuple domain", %{conn: conn} do
2803 post(conn, "/api/pleroma/admin/config", %{
2809 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2810 %{"tuple" => [":send_user_agent", false]}
2816 assert json_response(conn, 200) == %{
2819 "group" => ":pleroma",
2822 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2823 %{"tuple" => [":send_user_agent", false]}
2825 "db" => [":proxy_url", ":send_user_agent"]
2831 test "proxy tuple ip", %{conn: conn} do
2833 post(conn, "/api/pleroma/admin/config", %{
2839 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2840 %{"tuple" => [":send_user_agent", false]}
2846 assert json_response(conn, 200) == %{
2849 "group" => ":pleroma",
2852 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2853 %{"tuple" => [":send_user_agent", false]}
2855 "db" => [":proxy_url", ":send_user_agent"]
2862 describe "GET /api/pleroma/admin/restart" do
2863 setup do: clear_config(:configurable_from_database, true)
2865 test "pleroma restarts", %{conn: conn} do
2867 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2868 end) =~ "pleroma restarted"
2870 refute Restarter.Pleroma.need_reboot?()
2874 test "need_reboot flag", %{conn: conn} do
2876 |> get("/api/pleroma/admin/need_reboot")
2877 |> json_response(200) == %{"need_reboot" => false}
2879 Restarter.Pleroma.need_reboot()
2882 |> get("/api/pleroma/admin/need_reboot")
2883 |> json_response(200) == %{"need_reboot" => true}
2885 on_exit(fn -> Restarter.Pleroma.refresh() end)
2888 describe "GET /api/pleroma/admin/statuses" do
2889 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2890 blocked = insert(:user)
2891 user = insert(:user)
2892 User.block(admin, blocked)
2895 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2897 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2898 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2899 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2900 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2904 |> get("/api/pleroma/admin/statuses")
2905 |> json_response(200)
2907 refute "private" in Enum.map(response, & &1["visibility"])
2908 assert length(response) == 3
2911 test "returns only local statuses with local_only on", %{conn: conn} do
2912 user = insert(:user)
2913 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2914 insert(:note_activity, user: user, local: true)
2915 insert(:note_activity, user: remote_user, local: false)
2919 |> get("/api/pleroma/admin/statuses?local_only=true")
2920 |> json_response(200)
2922 assert length(response) == 1
2925 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2926 user = insert(:user)
2929 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2931 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2932 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2933 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2934 assert json_response(conn, 200) |> length() == 3
2938 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2940 user = insert(:user)
2942 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2943 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2944 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2946 insert(:note_activity, user: user, published: date1)
2947 insert(:note_activity, user: user, published: date2)
2948 insert(:note_activity, user: user, published: date3)
2953 test "renders user's statuses", %{conn: conn, user: user} do
2954 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2956 assert json_response(conn, 200) |> length() == 3
2959 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2960 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2962 assert json_response(conn, 200) |> length() == 2
2965 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2966 {:ok, _private_status} =
2967 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2969 {:ok, _public_status} =
2970 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2972 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2974 assert json_response(conn, 200) |> length() == 4
2977 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2978 {:ok, _private_status} =
2979 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2981 {:ok, _public_status} =
2982 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2984 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2986 assert json_response(conn, 200) |> length() == 5
2989 test "excludes reblogs by default", %{conn: conn, user: user} do
2990 other_user = insert(:user)
2991 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2992 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2994 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2995 assert json_response(conn_res, 200) |> length() == 0
2998 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3000 assert json_response(conn_res, 200) |> length() == 1
3004 describe "GET /api/pleroma/admin/moderation_log" do
3006 moderator = insert(:user, is_moderator: true)
3008 %{moderator: moderator}
3011 test "returns the log", %{conn: conn, admin: admin} do
3012 Repo.insert(%ModerationLog{
3016 "nickname" => admin.nickname,
3019 action: "relay_follow",
3020 target: "https://example.org/relay"
3022 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3025 Repo.insert(%ModerationLog{
3029 "nickname" => admin.nickname,
3032 action: "relay_unfollow",
3033 target: "https://example.org/relay"
3035 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3038 conn = get(conn, "/api/pleroma/admin/moderation_log")
3040 response = json_response(conn, 200)
3041 [first_entry, second_entry] = response["items"]
3043 assert response["total"] == 2
3044 assert first_entry["data"]["action"] == "relay_unfollow"
3046 assert first_entry["message"] ==
3047 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3049 assert second_entry["data"]["action"] == "relay_follow"
3051 assert second_entry["message"] ==
3052 "@#{admin.nickname} followed relay: https://example.org/relay"
3055 test "returns the log with pagination", %{conn: conn, admin: admin} do
3056 Repo.insert(%ModerationLog{
3060 "nickname" => admin.nickname,
3063 action: "relay_follow",
3064 target: "https://example.org/relay"
3066 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3069 Repo.insert(%ModerationLog{
3073 "nickname" => admin.nickname,
3076 action: "relay_unfollow",
3077 target: "https://example.org/relay"
3079 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3082 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3084 response1 = json_response(conn1, 200)
3085 [first_entry] = response1["items"]
3087 assert response1["total"] == 2
3088 assert response1["items"] |> length() == 1
3089 assert first_entry["data"]["action"] == "relay_unfollow"
3091 assert first_entry["message"] ==
3092 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3094 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3096 response2 = json_response(conn2, 200)
3097 [second_entry] = response2["items"]
3099 assert response2["total"] == 2
3100 assert response2["items"] |> length() == 1
3101 assert second_entry["data"]["action"] == "relay_follow"
3103 assert second_entry["message"] ==
3104 "@#{admin.nickname} followed relay: https://example.org/relay"
3107 test "filters log by date", %{conn: conn, admin: admin} do
3108 first_date = "2017-08-15T15:47:06Z"
3109 second_date = "2017-08-20T15:47:06Z"
3111 Repo.insert(%ModerationLog{
3115 "nickname" => admin.nickname,
3118 action: "relay_follow",
3119 target: "https://example.org/relay"
3121 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3124 Repo.insert(%ModerationLog{
3128 "nickname" => admin.nickname,
3131 action: "relay_unfollow",
3132 target: "https://example.org/relay"
3134 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3140 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3143 response1 = json_response(conn1, 200)
3144 [first_entry] = response1["items"]
3146 assert response1["total"] == 1
3147 assert first_entry["data"]["action"] == "relay_unfollow"
3149 assert first_entry["message"] ==
3150 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3153 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3154 Repo.insert(%ModerationLog{
3158 "nickname" => admin.nickname,
3161 action: "relay_follow",
3162 target: "https://example.org/relay"
3166 Repo.insert(%ModerationLog{
3169 "id" => moderator.id,
3170 "nickname" => moderator.nickname,
3173 action: "relay_unfollow",
3174 target: "https://example.org/relay"
3178 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3180 response1 = json_response(conn1, 200)
3181 [first_entry] = response1["items"]
3183 assert response1["total"] == 1
3184 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3187 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3188 ModerationLog.insert_log(%{
3190 action: "relay_follow",
3191 target: "https://example.org/relay"
3194 ModerationLog.insert_log(%{
3196 action: "relay_unfollow",
3197 target: "https://example.org/relay"
3200 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3202 response1 = json_response(conn1, 200)
3203 [first_entry] = response1["items"]
3205 assert response1["total"] == 1
3207 assert get_in(first_entry, ["data", "message"]) ==
3208 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3212 describe "GET /users/:nickname/credentials" do
3213 test "gets the user credentials", %{conn: conn} do
3214 user = insert(:user)
3215 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3217 response = assert json_response(conn, 200)
3218 assert response["email"] == user.email
3221 test "returns 403 if requested by a non-admin" do
3222 user = insert(:user)
3226 |> assign(:user, user)
3227 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3229 assert json_response(conn, :forbidden)
3233 describe "PATCH /users/:nickname/credentials" do
3234 test "changes password and email", %{conn: conn, admin: admin} do
3235 user = insert(:user)
3236 assert user.password_reset_pending == false
3239 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3240 "password" => "new_password",
3241 "email" => "new_email@example.com",
3242 "name" => "new_name"
3245 assert json_response(conn, 200) == %{"status" => "success"}
3247 ObanHelpers.perform_all()
3249 updated_user = User.get_by_id(user.id)
3251 assert updated_user.email == "new_email@example.com"
3252 assert updated_user.name == "new_name"
3253 assert updated_user.password_hash != user.password_hash
3254 assert updated_user.password_reset_pending == true
3256 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3258 assert ModerationLog.get_log_entry_message(log_entry1) ==
3259 "@#{admin.nickname} updated users: @#{user.nickname}"
3261 assert ModerationLog.get_log_entry_message(log_entry2) ==
3262 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3265 test "returns 403 if requested by a non-admin" do
3266 user = insert(:user)
3270 |> assign(:user, user)
3271 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3272 "password" => "new_password",
3273 "email" => "new_email@example.com",
3274 "name" => "new_name"
3277 assert json_response(conn, :forbidden)
3281 describe "PATCH /users/:nickname/force_password_reset" do
3282 test "sets password_reset_pending to true", %{conn: conn} do
3283 user = insert(:user)
3284 assert user.password_reset_pending == false
3287 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3289 assert json_response(conn, 204) == ""
3291 ObanHelpers.perform_all()
3293 assert User.get_by_id(user.id).password_reset_pending == true
3297 describe "relays" do
3298 test "POST /relay", %{conn: conn, admin: admin} do
3300 post(conn, "/api/pleroma/admin/relay", %{
3301 relay_url: "http://mastodon.example.org/users/admin"
3304 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3306 log_entry = Repo.one(ModerationLog)
3308 assert ModerationLog.get_log_entry_message(log_entry) ==
3309 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3312 test "GET /relay", %{conn: conn} do
3313 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3315 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3316 |> Enum.each(fn ap_id ->
3317 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3318 User.follow(relay_user, user)
3321 conn = get(conn, "/api/pleroma/admin/relay")
3323 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3326 test "DELETE /relay", %{conn: conn, admin: admin} do
3327 post(conn, "/api/pleroma/admin/relay", %{
3328 relay_url: "http://mastodon.example.org/users/admin"
3332 delete(conn, "/api/pleroma/admin/relay", %{
3333 relay_url: "http://mastodon.example.org/users/admin"
3336 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3338 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3340 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3341 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3343 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3344 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3348 describe "instances" do
3349 test "GET /instances/:instance/statuses", %{conn: conn} do
3350 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3351 user2 = insert(:user, local: false, nickname: "test@test.com")
3352 insert_pair(:note_activity, user: user)
3353 activity = insert(:note_activity, user: user2)
3355 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3357 response = json_response(ret_conn, 200)
3359 assert length(response) == 2
3361 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3363 response = json_response(ret_conn, 200)
3365 assert length(response) == 1
3367 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3369 response = json_response(ret_conn, 200)
3371 assert Enum.empty?(response)
3373 CommonAPI.repeat(activity.id, user)
3375 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3376 response = json_response(ret_conn, 200)
3377 assert length(response) == 2
3379 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3380 response = json_response(ret_conn, 200)
3381 assert length(response) == 3
3385 describe "PATCH /confirm_email" do
3386 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3387 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3389 assert first_user.confirmation_pending == true
3390 assert second_user.confirmation_pending == true
3393 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3395 first_user.nickname,
3396 second_user.nickname
3400 assert ret_conn.status == 200
3402 assert first_user.confirmation_pending == true
3403 assert second_user.confirmation_pending == true
3405 log_entry = Repo.one(ModerationLog)
3407 assert ModerationLog.get_log_entry_message(log_entry) ==
3408 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3409 second_user.nickname
3414 describe "PATCH /resend_confirmation_email" do
3415 test "it resend emails for two users", %{conn: conn, admin: admin} do
3416 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3419 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3421 first_user.nickname,
3422 second_user.nickname
3426 assert ret_conn.status == 200
3428 log_entry = Repo.one(ModerationLog)
3430 assert ModerationLog.get_log_entry_message(log_entry) ==
3431 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3432 second_user.nickname
3437 describe "POST /reports/:id/notes" do
3438 setup %{conn: conn, admin: admin} do
3439 [reporter, target_user] = insert_pair(:user)
3440 activity = insert(:note_activity, user: target_user)
3442 {:ok, %{id: report_id}} =
3443 CommonAPI.report(reporter, %{
3444 account_id: target_user.id,
3445 comment: "I feel offended",
3446 status_ids: [activity.id]
3449 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3450 content: "this is disgusting!"
3453 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3454 content: "this is disgusting2!"
3459 report_id: report_id
3463 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3464 [note, _] = Repo.all(ReportNote)
3467 activity_id: ^report_id,
3468 content: "this is disgusting!",
3473 test "it returns reports with notes", %{conn: conn, admin: admin} do
3474 conn = get(conn, "/api/pleroma/admin/reports")
3476 response = json_response(conn, 200)
3477 notes = hd(response["reports"])["notes"]
3480 assert note["user"]["nickname"] == admin.nickname
3481 assert note["content"] == "this is disgusting!"
3482 assert note["created_at"]
3483 assert response["total"] == 1
3486 test "it deletes the note", %{conn: conn, report_id: report_id} do
3487 assert ReportNote |> Repo.all() |> length() == 2
3489 [note, _] = Repo.all(ReportNote)
3491 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3493 assert ReportNote |> Repo.all() |> length() == 1
3497 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3498 admin = insert(:user, is_admin: true)
3501 assign(conn, :user, admin)
3502 |> get("/api/pleroma/admin/config/descriptions")
3504 assert [child | _others] = json_response(conn, 200)
3506 assert child["children"]
3508 assert String.starts_with?(child["group"], ":")
3509 assert child["description"]
3512 describe "/api/pleroma/admin/stats" do
3513 test "status visibility count", %{conn: conn} do
3514 admin = insert(:user, is_admin: true)
3515 user = insert(:user)
3516 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3517 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3518 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3522 |> assign(:user, admin)
3523 |> get("/api/pleroma/admin/stats")
3524 |> json_response(200)
3526 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3527 response["status_visibility"]
3531 describe "POST /api/pleroma/admin/oauth_app" do
3532 test "errors", %{conn: conn} do
3533 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3535 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3538 test "success", %{conn: conn} do
3539 base_url = Pleroma.Web.base_url()
3540 app_name = "Trusted app"
3544 |> post("/api/pleroma/admin/oauth_app", %{
3546 redirect_uris: base_url
3548 |> json_response(200)
3552 "client_secret" => _,
3553 "name" => ^app_name,
3554 "redirect_uri" => ^base_url,
3559 test "with trusted", %{conn: conn} do
3560 base_url = Pleroma.Web.base_url()
3561 app_name = "Trusted app"
3565 |> post("/api/pleroma/admin/oauth_app", %{
3567 redirect_uris: base_url,
3570 |> json_response(200)
3574 "client_secret" => _,
3575 "name" => ^app_name,
3576 "redirect_uri" => ^base_url,
3582 describe "GET /api/pleroma/admin/oauth_app" do
3584 app = insert(:oauth_app)
3588 test "list", %{conn: conn} do
3591 |> get("/api/pleroma/admin/oauth_app")
3592 |> json_response(200)
3594 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3596 assert length(apps) == count
3599 test "with page size", %{conn: conn} do
3605 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3606 |> json_response(200)
3608 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3610 assert length(apps) == page_size
3613 test "search by client name", %{conn: conn, app: app} do
3616 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3617 |> json_response(200)
3619 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3621 assert returned["client_id"] == app.client_id
3622 assert returned["name"] == app.client_name
3625 test "search by client id", %{conn: conn, app: app} do
3628 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3629 |> json_response(200)
3631 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3633 assert returned["client_id"] == app.client_id
3634 assert returned["name"] == app.client_name
3637 test "only trusted", %{conn: conn} do
3638 app = insert(:oauth_app, trusted: true)
3642 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3643 |> json_response(200)
3645 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3647 assert returned["client_id"] == app.client_id
3648 assert returned["name"] == app.client_name
3652 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3653 test "with id", %{conn: conn} do
3654 app = insert(:oauth_app)
3658 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3659 |> json_response(:no_content)
3661 assert response == ""
3664 test "with non existance id", %{conn: conn} do
3667 |> delete("/api/pleroma/admin/oauth_app/0")
3668 |> json_response(:bad_request)
3670 assert response == ""
3674 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3675 test "with id", %{conn: conn} do
3676 app = insert(:oauth_app)
3678 name = "another name"
3679 url = "https://example.com"
3682 website = "http://website.com"
3686 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3693 |> json_response(200)
3697 "client_secret" => _,
3700 "redirect_uri" => ^url,
3702 "website" => ^website
3706 test "without id", %{conn: conn} do
3709 |> patch("/api/pleroma/admin/oauth_app/0")
3710 |> json_response(:bad_request)
3712 assert response == ""
3717 # Needed for testing
3718 defmodule Pleroma.Web.Endpoint.NotReal do
3721 defmodule Pleroma.Captcha.NotReal do