1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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 alias Pleroma.ConfigDB
12 alias Pleroma.ModerationLog
14 alias Pleroma.ReportNote
15 alias Pleroma.Tests.ObanHelpers
17 alias Pleroma.UserInviteToken
18 alias Pleroma.Web.ActivityPub.Relay
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.MastodonAPI.StatusView
21 alias Pleroma.Web.MediaProxy
22 import Pleroma.Factory
25 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
31 admin = insert(:user, is_admin: true)
32 token = insert(:oauth_admin_token, user: admin)
36 |> assign(:user, admin)
37 |> assign(:token, token)
39 {:ok, %{admin: admin, token: token, conn: conn}}
42 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
43 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
44 Pleroma.Config.put([: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 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
94 Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
97 test "GET /api/pleroma/admin/users/:nickname requires " <>
98 "read:accounts or admin:read:accounts or broader scope",
101 url = "/api/pleroma/admin/users/#{user.nickname}"
103 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
104 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
105 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
106 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
107 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
109 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
111 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
112 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
115 for good_token <- good_tokens do
118 |> assign(:user, admin)
119 |> assign(:token, good_token)
122 assert json_response(conn, 200)
125 for good_token <- good_tokens do
128 |> assign(:user, nil)
129 |> assign(:token, good_token)
132 assert json_response(conn, :forbidden)
135 for bad_token <- [bad_token1, bad_token2, bad_token3] do
138 |> assign(:user, admin)
139 |> assign(:token, bad_token)
142 assert json_response(conn, :forbidden)
147 describe "DELETE /api/pleroma/admin/users" do
148 test "single user", %{admin: admin, conn: conn} do
153 |> put_req_header("accept", "application/json")
154 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
156 log_entry = Repo.one(ModerationLog)
158 assert ModerationLog.get_log_entry_message(log_entry) ==
159 "@#{admin.nickname} deleted users: @#{user.nickname}"
161 assert json_response(conn, 200) == user.nickname
164 test "multiple users", %{admin: admin, conn: conn} do
165 user_one = insert(:user)
166 user_two = insert(:user)
170 |> put_req_header("accept", "application/json")
171 |> delete("/api/pleroma/admin/users", %{
172 nicknames: [user_one.nickname, user_two.nickname]
175 log_entry = Repo.one(ModerationLog)
177 assert ModerationLog.get_log_entry_message(log_entry) ==
178 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
180 response = json_response(conn, 200)
181 assert response -- [user_one.nickname, user_two.nickname] == []
185 describe "/api/pleroma/admin/users" do
186 test "Create", %{conn: conn} do
189 |> put_req_header("accept", "application/json")
190 |> post("/api/pleroma/admin/users", %{
193 "nickname" => "lain",
194 "email" => "lain@example.org",
198 "nickname" => "lain2",
199 "email" => "lain2@example.org",
205 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
206 assert response == ["success", "success"]
208 log_entry = Repo.one(ModerationLog)
210 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
213 test "Cannot create user with existing email", %{conn: conn} do
218 |> put_req_header("accept", "application/json")
219 |> post("/api/pleroma/admin/users", %{
222 "nickname" => "lain",
223 "email" => user.email,
229 assert json_response(conn, 409) == [
233 "email" => user.email,
236 "error" => "email has already been taken",
242 test "Cannot create user with existing nickname", %{conn: conn} do
247 |> put_req_header("accept", "application/json")
248 |> post("/api/pleroma/admin/users", %{
251 "nickname" => user.nickname,
252 "email" => "someuser@plerama.social",
258 assert json_response(conn, 409) == [
262 "email" => "someuser@plerama.social",
263 "nickname" => user.nickname
265 "error" => "nickname has already been taken",
271 test "Multiple user creation works in transaction", %{conn: conn} do
276 |> put_req_header("accept", "application/json")
277 |> post("/api/pleroma/admin/users", %{
280 "nickname" => "newuser",
281 "email" => "newuser@pleroma.social",
285 "nickname" => "lain",
286 "email" => user.email,
292 assert json_response(conn, 409) == [
296 "email" => user.email,
299 "error" => "email has already been taken",
305 "email" => "newuser@pleroma.social",
306 "nickname" => "newuser"
313 assert User.get_by_nickname("newuser") === nil
317 describe "/api/pleroma/admin/users/:nickname" do
318 test "Show", %{conn: conn} do
321 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
324 "deactivated" => false,
325 "id" => to_string(user.id),
327 "nickname" => user.nickname,
328 "roles" => %{"admin" => false, "moderator" => false},
330 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
331 "display_name" => HTML.strip_tags(user.name || user.nickname),
332 "confirmation_pending" => false
335 assert expected == json_response(conn, 200)
338 test "when the user doesn't exist", %{conn: conn} do
341 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
343 assert "Not found" == json_response(conn, 404)
347 describe "/api/pleroma/admin/users/follow" do
348 test "allows to force-follow another user", %{admin: admin, conn: conn} do
350 follower = insert(:user)
353 |> put_req_header("accept", "application/json")
354 |> post("/api/pleroma/admin/users/follow", %{
355 "follower" => follower.nickname,
356 "followed" => user.nickname
359 user = User.get_cached_by_id(user.id)
360 follower = User.get_cached_by_id(follower.id)
362 assert User.following?(follower, user)
364 log_entry = Repo.one(ModerationLog)
366 assert ModerationLog.get_log_entry_message(log_entry) ==
367 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
371 describe "/api/pleroma/admin/users/unfollow" do
372 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
374 follower = insert(:user)
376 User.follow(follower, user)
379 |> put_req_header("accept", "application/json")
380 |> post("/api/pleroma/admin/users/unfollow", %{
381 "follower" => follower.nickname,
382 "followed" => user.nickname
385 user = User.get_cached_by_id(user.id)
386 follower = User.get_cached_by_id(follower.id)
388 refute User.following?(follower, user)
390 log_entry = Repo.one(ModerationLog)
392 assert ModerationLog.get_log_entry_message(log_entry) ==
393 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
397 describe "PUT /api/pleroma/admin/users/tag" do
398 setup %{conn: conn} do
399 user1 = insert(:user, %{tags: ["x"]})
400 user2 = insert(:user, %{tags: ["y"]})
401 user3 = insert(:user, %{tags: ["unchanged"]})
405 |> put_req_header("accept", "application/json")
407 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
408 "#{user2.nickname}&tags[]=foo&tags[]=bar"
411 %{conn: conn, user1: user1, user2: user2, user3: user3}
414 test "it appends specified tags to users with specified nicknames", %{
420 assert json_response(conn, :no_content)
421 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
422 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
424 log_entry = Repo.one(ModerationLog)
427 [user1.nickname, user2.nickname]
428 |> Enum.map(&"@#{&1}")
431 tags = ["foo", "bar"] |> Enum.join(", ")
433 assert ModerationLog.get_log_entry_message(log_entry) ==
434 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
437 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
438 assert json_response(conn, :no_content)
439 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
443 describe "DELETE /api/pleroma/admin/users/tag" do
444 setup %{conn: conn} do
445 user1 = insert(:user, %{tags: ["x"]})
446 user2 = insert(:user, %{tags: ["y", "z"]})
447 user3 = insert(:user, %{tags: ["unchanged"]})
451 |> put_req_header("accept", "application/json")
453 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
454 "#{user2.nickname}&tags[]=x&tags[]=z"
457 %{conn: conn, user1: user1, user2: user2, user3: user3}
460 test "it removes specified tags from users with specified nicknames", %{
466 assert json_response(conn, :no_content)
467 assert User.get_cached_by_id(user1.id).tags == []
468 assert User.get_cached_by_id(user2.id).tags == ["y"]
470 log_entry = Repo.one(ModerationLog)
473 [user1.nickname, user2.nickname]
474 |> Enum.map(&"@#{&1}")
477 tags = ["x", "z"] |> Enum.join(", ")
479 assert ModerationLog.get_log_entry_message(log_entry) ==
480 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
483 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
484 assert json_response(conn, :no_content)
485 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
489 describe "/api/pleroma/admin/users/:nickname/permission_group" do
490 test "GET is giving user_info", %{admin: admin, conn: conn} do
493 |> put_req_header("accept", "application/json")
494 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
496 assert json_response(conn, 200) == %{
498 "is_moderator" => false
502 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
507 |> put_req_header("accept", "application/json")
508 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
510 assert json_response(conn, 200) == %{
514 log_entry = Repo.one(ModerationLog)
516 assert ModerationLog.get_log_entry_message(log_entry) ==
517 "@#{admin.nickname} made @#{user.nickname} admin"
520 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
521 user_one = insert(:user)
522 user_two = insert(:user)
526 |> put_req_header("accept", "application/json")
527 |> post("/api/pleroma/admin/users/permission_group/admin", %{
528 nicknames: [user_one.nickname, user_two.nickname]
531 assert json_response(conn, 200) == %{"is_admin" => true}
533 log_entry = Repo.one(ModerationLog)
535 assert ModerationLog.get_log_entry_message(log_entry) ==
536 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
539 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
540 user = insert(:user, is_admin: true)
544 |> put_req_header("accept", "application/json")
545 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
547 assert json_response(conn, 200) == %{"is_admin" => false}
549 log_entry = Repo.one(ModerationLog)
551 assert ModerationLog.get_log_entry_message(log_entry) ==
552 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
555 test "/:right DELETE, can remove from a permission group (multiple)", %{
559 user_one = insert(:user, is_admin: true)
560 user_two = insert(:user, is_admin: true)
564 |> put_req_header("accept", "application/json")
565 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
566 nicknames: [user_one.nickname, user_two.nickname]
569 assert json_response(conn, 200) == %{"is_admin" => false}
571 log_entry = Repo.one(ModerationLog)
573 assert ModerationLog.get_log_entry_message(log_entry) ==
574 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
580 describe "POST /api/pleroma/admin/email_invite, with valid config" do
581 clear_config([:instance, :registrations_open]) do
582 Pleroma.Config.put([:instance, :registrations_open], false)
585 clear_config([:instance, :invites_enabled]) do
586 Pleroma.Config.put([:instance, :invites_enabled], true)
589 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
590 recipient_email = "foo@bar.com"
591 recipient_name = "J. D."
596 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
599 assert json_response(conn, :no_content)
601 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
603 refute token_record.used
605 notify_email = Pleroma.Config.get([:instance, :notify_email])
606 instance_name = Pleroma.Config.get([:instance, :name])
609 Pleroma.Emails.UserEmail.user_invitation_email(
616 Swoosh.TestAssertions.assert_email_sent(
617 from: {instance_name, notify_email},
618 to: {recipient_name, recipient_email},
619 html_body: email.html_body
623 test "it returns 403 if requested by a non-admin" do
624 non_admin_user = insert(:user)
625 token = insert(:oauth_token, user: non_admin_user)
629 |> assign(:user, non_admin_user)
630 |> assign(:token, token)
631 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
633 assert json_response(conn, :forbidden)
637 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
638 clear_config([:instance, :registrations_open])
639 clear_config([:instance, :invites_enabled])
641 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
642 Pleroma.Config.put([:instance, :registrations_open], false)
643 Pleroma.Config.put([:instance, :invites_enabled], false)
645 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
647 assert json_response(conn, :internal_server_error)
650 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
651 Pleroma.Config.put([:instance, :registrations_open], true)
652 Pleroma.Config.put([:instance, :invites_enabled], true)
654 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
656 assert json_response(conn, :internal_server_error)
660 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
665 |> put_req_header("accept", "application/json")
666 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
668 resp = json_response(conn, 200)
670 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
673 describe "GET /api/pleroma/admin/users" do
674 test "renders users array for the first page", %{conn: conn, admin: admin} do
675 user = insert(:user, local: false, tags: ["foo", "bar"])
676 conn = get(conn, "/api/pleroma/admin/users?page=1")
681 "deactivated" => admin.deactivated,
683 "nickname" => admin.nickname,
684 "roles" => %{"admin" => true, "moderator" => false},
687 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
688 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
689 "confirmation_pending" => false
692 "deactivated" => user.deactivated,
694 "nickname" => user.nickname,
695 "roles" => %{"admin" => false, "moderator" => false},
697 "tags" => ["foo", "bar"],
698 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
699 "display_name" => HTML.strip_tags(user.name || user.nickname),
700 "confirmation_pending" => false
703 |> Enum.sort_by(& &1["nickname"])
705 assert json_response(conn, 200) == %{
712 test "renders empty array for the second page", %{conn: conn} do
715 conn = get(conn, "/api/pleroma/admin/users?page=2")
717 assert json_response(conn, 200) == %{
724 test "regular search", %{conn: conn} do
725 user = insert(:user, nickname: "bob")
727 conn = get(conn, "/api/pleroma/admin/users?query=bo")
729 assert json_response(conn, 200) == %{
734 "deactivated" => user.deactivated,
736 "nickname" => user.nickname,
737 "roles" => %{"admin" => false, "moderator" => false},
740 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
741 "display_name" => HTML.strip_tags(user.name || user.nickname),
742 "confirmation_pending" => false
748 test "search by domain", %{conn: conn} do
749 user = insert(:user, nickname: "nickname@domain.com")
752 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
754 assert json_response(conn, 200) == %{
759 "deactivated" => user.deactivated,
761 "nickname" => user.nickname,
762 "roles" => %{"admin" => false, "moderator" => false},
765 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
766 "display_name" => HTML.strip_tags(user.name || user.nickname),
767 "confirmation_pending" => false
773 test "search by full nickname", %{conn: conn} do
774 user = insert(:user, nickname: "nickname@domain.com")
777 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
779 assert json_response(conn, 200) == %{
784 "deactivated" => user.deactivated,
786 "nickname" => user.nickname,
787 "roles" => %{"admin" => false, "moderator" => false},
790 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
791 "display_name" => HTML.strip_tags(user.name || user.nickname),
792 "confirmation_pending" => false
798 test "search by display name", %{conn: conn} do
799 user = insert(:user, name: "Display name")
802 conn = get(conn, "/api/pleroma/admin/users?name=display")
804 assert json_response(conn, 200) == %{
809 "deactivated" => user.deactivated,
811 "nickname" => user.nickname,
812 "roles" => %{"admin" => false, "moderator" => false},
815 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
816 "display_name" => HTML.strip_tags(user.name || user.nickname),
817 "confirmation_pending" => false
823 test "search by email", %{conn: conn} do
824 user = insert(:user, email: "email@example.com")
827 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
829 assert json_response(conn, 200) == %{
834 "deactivated" => user.deactivated,
836 "nickname" => user.nickname,
837 "roles" => %{"admin" => false, "moderator" => false},
840 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
841 "display_name" => HTML.strip_tags(user.name || user.nickname),
842 "confirmation_pending" => false
848 test "regular search with page size", %{conn: conn} do
849 user = insert(:user, nickname: "aalice")
850 user2 = insert(:user, nickname: "alice")
852 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
854 assert json_response(conn1, 200) == %{
859 "deactivated" => user.deactivated,
861 "nickname" => user.nickname,
862 "roles" => %{"admin" => false, "moderator" => false},
865 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
866 "display_name" => HTML.strip_tags(user.name || user.nickname),
867 "confirmation_pending" => false
872 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
874 assert json_response(conn2, 200) == %{
879 "deactivated" => user2.deactivated,
881 "nickname" => user2.nickname,
882 "roles" => %{"admin" => false, "moderator" => false},
885 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
886 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
887 "confirmation_pending" => false
893 test "only local users" do
894 admin = insert(:user, is_admin: true, nickname: "john")
895 token = insert(:oauth_admin_token, user: admin)
896 user = insert(:user, nickname: "bob")
898 insert(:user, nickname: "bobb", local: false)
902 |> assign(:user, admin)
903 |> assign(:token, token)
904 |> get("/api/pleroma/admin/users?query=bo&filters=local")
906 assert json_response(conn, 200) == %{
911 "deactivated" => user.deactivated,
913 "nickname" => user.nickname,
914 "roles" => %{"admin" => false, "moderator" => false},
917 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
918 "display_name" => HTML.strip_tags(user.name || user.nickname),
919 "confirmation_pending" => false
925 test "only local users with no query", %{conn: conn, admin: old_admin} do
926 admin = insert(:user, is_admin: true, nickname: "john")
927 user = insert(:user, nickname: "bob")
929 insert(:user, nickname: "bobb", local: false)
931 conn = get(conn, "/api/pleroma/admin/users?filters=local")
936 "deactivated" => user.deactivated,
938 "nickname" => user.nickname,
939 "roles" => %{"admin" => false, "moderator" => false},
942 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
943 "display_name" => HTML.strip_tags(user.name || user.nickname),
944 "confirmation_pending" => false
947 "deactivated" => admin.deactivated,
949 "nickname" => admin.nickname,
950 "roles" => %{"admin" => true, "moderator" => false},
953 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
954 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
955 "confirmation_pending" => false
958 "deactivated" => false,
959 "id" => old_admin.id,
961 "nickname" => old_admin.nickname,
962 "roles" => %{"admin" => true, "moderator" => false},
964 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
965 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
966 "confirmation_pending" => false
969 |> Enum.sort_by(& &1["nickname"])
971 assert json_response(conn, 200) == %{
978 test "load only admins", %{conn: conn, admin: admin} do
979 second_admin = insert(:user, is_admin: true)
983 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
988 "deactivated" => false,
990 "nickname" => admin.nickname,
991 "roles" => %{"admin" => true, "moderator" => false},
992 "local" => admin.local,
994 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
995 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
996 "confirmation_pending" => false
999 "deactivated" => false,
1000 "id" => second_admin.id,
1001 "nickname" => second_admin.nickname,
1002 "roles" => %{"admin" => true, "moderator" => false},
1003 "local" => second_admin.local,
1005 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1006 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1007 "confirmation_pending" => false
1010 |> Enum.sort_by(& &1["nickname"])
1012 assert json_response(conn, 200) == %{
1019 test "load only moderators", %{conn: conn} do
1020 moderator = insert(:user, is_moderator: true)
1024 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1026 assert json_response(conn, 200) == %{
1031 "deactivated" => false,
1032 "id" => moderator.id,
1033 "nickname" => moderator.nickname,
1034 "roles" => %{"admin" => false, "moderator" => true},
1035 "local" => moderator.local,
1037 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1038 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1039 "confirmation_pending" => false
1045 test "load users with tags list", %{conn: conn} do
1046 user1 = insert(:user, tags: ["first"])
1047 user2 = insert(:user, tags: ["second"])
1051 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1056 "deactivated" => false,
1058 "nickname" => user1.nickname,
1059 "roles" => %{"admin" => false, "moderator" => false},
1060 "local" => user1.local,
1061 "tags" => ["first"],
1062 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1063 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1064 "confirmation_pending" => false
1067 "deactivated" => false,
1069 "nickname" => user2.nickname,
1070 "roles" => %{"admin" => false, "moderator" => false},
1071 "local" => user2.local,
1072 "tags" => ["second"],
1073 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1074 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1075 "confirmation_pending" => false
1078 |> Enum.sort_by(& &1["nickname"])
1080 assert json_response(conn, 200) == %{
1087 test "it works with multiple filters" do
1088 admin = insert(:user, nickname: "john", is_admin: true)
1089 token = insert(:oauth_admin_token, user: admin)
1090 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1092 insert(:user, nickname: "ken", local: true, deactivated: true)
1093 insert(:user, nickname: "bobb", local: false, deactivated: false)
1097 |> assign(:user, admin)
1098 |> assign(:token, token)
1099 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1101 assert json_response(conn, 200) == %{
1106 "deactivated" => user.deactivated,
1108 "nickname" => user.nickname,
1109 "roles" => %{"admin" => false, "moderator" => false},
1110 "local" => user.local,
1112 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1113 "display_name" => HTML.strip_tags(user.name || user.nickname),
1114 "confirmation_pending" => false
1120 test "it omits relay user", %{admin: admin, conn: conn} do
1121 assert %User{} = Relay.get_actor()
1123 conn = get(conn, "/api/pleroma/admin/users")
1125 assert json_response(conn, 200) == %{
1130 "deactivated" => admin.deactivated,
1132 "nickname" => admin.nickname,
1133 "roles" => %{"admin" => true, "moderator" => false},
1136 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1137 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1138 "confirmation_pending" => false
1145 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1146 user_one = insert(:user, deactivated: true)
1147 user_two = insert(:user, deactivated: true)
1152 "/api/pleroma/admin/users/activate",
1153 %{nicknames: [user_one.nickname, user_two.nickname]}
1156 response = json_response(conn, 200)
1157 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1159 log_entry = Repo.one(ModerationLog)
1161 assert ModerationLog.get_log_entry_message(log_entry) ==
1162 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1165 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1166 user_one = insert(:user, deactivated: false)
1167 user_two = insert(:user, deactivated: false)
1172 "/api/pleroma/admin/users/deactivate",
1173 %{nicknames: [user_one.nickname, user_two.nickname]}
1176 response = json_response(conn, 200)
1177 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1179 log_entry = Repo.one(ModerationLog)
1181 assert ModerationLog.get_log_entry_message(log_entry) ==
1182 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1185 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1186 user = insert(:user)
1188 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1190 assert json_response(conn, 200) ==
1192 "deactivated" => !user.deactivated,
1194 "nickname" => user.nickname,
1195 "roles" => %{"admin" => false, "moderator" => false},
1198 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1199 "display_name" => HTML.strip_tags(user.name || user.nickname),
1200 "confirmation_pending" => false
1203 log_entry = Repo.one(ModerationLog)
1205 assert ModerationLog.get_log_entry_message(log_entry) ==
1206 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1209 describe "POST /api/pleroma/admin/users/invite_token" do
1210 test "without options", %{conn: conn} do
1211 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1213 invite_json = json_response(conn, 200)
1214 invite = UserInviteToken.find_by_token!(invite_json["token"])
1216 refute invite.expires_at
1217 refute invite.max_use
1218 assert invite.invite_type == "one_time"
1221 test "with expires_at", %{conn: conn} do
1223 post(conn, "/api/pleroma/admin/users/invite_token", %{
1224 "expires_at" => Date.to_string(Date.utc_today())
1227 invite_json = json_response(conn, 200)
1228 invite = UserInviteToken.find_by_token!(invite_json["token"])
1231 assert invite.expires_at == Date.utc_today()
1232 refute invite.max_use
1233 assert invite.invite_type == "date_limited"
1236 test "with max_use", %{conn: conn} do
1237 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1239 invite_json = json_response(conn, 200)
1240 invite = UserInviteToken.find_by_token!(invite_json["token"])
1242 refute invite.expires_at
1243 assert invite.max_use == 150
1244 assert invite.invite_type == "reusable"
1247 test "with max use and expires_at", %{conn: conn} do
1249 post(conn, "/api/pleroma/admin/users/invite_token", %{
1251 "expires_at" => Date.to_string(Date.utc_today())
1254 invite_json = json_response(conn, 200)
1255 invite = UserInviteToken.find_by_token!(invite_json["token"])
1257 assert invite.expires_at == Date.utc_today()
1258 assert invite.max_use == 150
1259 assert invite.invite_type == "reusable_date_limited"
1263 describe "GET /api/pleroma/admin/users/invites" do
1264 test "no invites", %{conn: conn} do
1265 conn = get(conn, "/api/pleroma/admin/users/invites")
1267 assert json_response(conn, 200) == %{"invites" => []}
1270 test "with invite", %{conn: conn} do
1271 {:ok, invite} = UserInviteToken.create_invite()
1273 conn = get(conn, "/api/pleroma/admin/users/invites")
1275 assert json_response(conn, 200) == %{
1278 "expires_at" => nil,
1280 "invite_type" => "one_time",
1282 "token" => invite.token,
1291 describe "POST /api/pleroma/admin/users/revoke_invite" do
1292 test "with token", %{conn: conn} do
1293 {:ok, invite} = UserInviteToken.create_invite()
1295 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1297 assert json_response(conn, 200) == %{
1298 "expires_at" => nil,
1300 "invite_type" => "one_time",
1302 "token" => invite.token,
1308 test "with invalid token", %{conn: conn} do
1309 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1311 assert json_response(conn, :not_found) == "Not found"
1315 describe "GET /api/pleroma/admin/reports/:id" do
1316 test "returns report by its id", %{conn: conn} do
1317 [reporter, target_user] = insert_pair(:user)
1318 activity = insert(:note_activity, user: target_user)
1320 {:ok, %{id: report_id}} =
1321 CommonAPI.report(reporter, %{
1322 "account_id" => target_user.id,
1323 "comment" => "I feel offended",
1324 "status_ids" => [activity.id]
1329 |> get("/api/pleroma/admin/reports/#{report_id}")
1330 |> json_response(:ok)
1332 assert response["id"] == report_id
1335 test "returns 404 when report id is invalid", %{conn: conn} do
1336 conn = get(conn, "/api/pleroma/admin/reports/test")
1338 assert json_response(conn, :not_found) == "Not found"
1342 describe "PATCH /api/pleroma/admin/reports" do
1344 [reporter, target_user] = insert_pair(:user)
1345 activity = insert(:note_activity, user: target_user)
1347 {:ok, %{id: report_id}} =
1348 CommonAPI.report(reporter, %{
1349 "account_id" => target_user.id,
1350 "comment" => "I feel offended",
1351 "status_ids" => [activity.id]
1354 {:ok, %{id: second_report_id}} =
1355 CommonAPI.report(reporter, %{
1356 "account_id" => target_user.id,
1357 "comment" => "I feel very offended",
1358 "status_ids" => [activity.id]
1363 second_report_id: second_report_id
1367 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1368 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1369 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1373 |> assign(:token, read_token)
1374 |> patch("/api/pleroma/admin/reports", %{
1375 "reports" => [%{"state" => "resolved", "id" => id}]
1377 |> json_response(403)
1379 assert response == %{
1380 "error" => "Insufficient permissions: admin:write:reports."
1384 |> assign(:token, write_token)
1385 |> patch("/api/pleroma/admin/reports", %{
1386 "reports" => [%{"state" => "resolved", "id" => id}]
1388 |> json_response(:no_content)
1391 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1393 |> patch("/api/pleroma/admin/reports", %{
1395 %{"state" => "resolved", "id" => id}
1398 |> json_response(:no_content)
1400 activity = Activity.get_by_id(id)
1401 assert activity.data["state"] == "resolved"
1403 log_entry = Repo.one(ModerationLog)
1405 assert ModerationLog.get_log_entry_message(log_entry) ==
1406 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1409 test "closes report", %{conn: conn, id: id, admin: admin} do
1411 |> patch("/api/pleroma/admin/reports", %{
1413 %{"state" => "closed", "id" => id}
1416 |> json_response(:no_content)
1418 activity = Activity.get_by_id(id)
1419 assert activity.data["state"] == "closed"
1421 log_entry = Repo.one(ModerationLog)
1423 assert ModerationLog.get_log_entry_message(log_entry) ==
1424 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1427 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1430 |> patch("/api/pleroma/admin/reports", %{
1432 %{"state" => "test", "id" => id}
1436 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1439 test "returns 404 when report is not exist", %{conn: conn} do
1442 |> patch("/api/pleroma/admin/reports", %{
1444 %{"state" => "closed", "id" => "test"}
1448 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1451 test "updates state of multiple reports", %{
1455 second_report_id: second_report_id
1458 |> patch("/api/pleroma/admin/reports", %{
1460 %{"state" => "resolved", "id" => id},
1461 %{"state" => "closed", "id" => second_report_id}
1464 |> json_response(:no_content)
1466 activity = Activity.get_by_id(id)
1467 second_activity = Activity.get_by_id(second_report_id)
1468 assert activity.data["state"] == "resolved"
1469 assert second_activity.data["state"] == "closed"
1471 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1473 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1474 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1476 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1477 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1481 describe "GET /api/pleroma/admin/reports" do
1482 test "returns empty response when no reports created", %{conn: conn} do
1485 |> get("/api/pleroma/admin/reports")
1486 |> json_response(:ok)
1488 assert Enum.empty?(response["reports"])
1489 assert response["total"] == 0
1492 test "returns reports", %{conn: conn} do
1493 [reporter, target_user] = insert_pair(:user)
1494 activity = insert(:note_activity, user: target_user)
1496 {:ok, %{id: report_id}} =
1497 CommonAPI.report(reporter, %{
1498 "account_id" => target_user.id,
1499 "comment" => "I feel offended",
1500 "status_ids" => [activity.id]
1505 |> get("/api/pleroma/admin/reports")
1506 |> json_response(:ok)
1508 [report] = response["reports"]
1510 assert length(response["reports"]) == 1
1511 assert report["id"] == report_id
1513 assert response["total"] == 1
1516 test "returns reports with specified state", %{conn: conn} do
1517 [reporter, target_user] = insert_pair(:user)
1518 activity = insert(:note_activity, user: target_user)
1520 {:ok, %{id: first_report_id}} =
1521 CommonAPI.report(reporter, %{
1522 "account_id" => target_user.id,
1523 "comment" => "I feel offended",
1524 "status_ids" => [activity.id]
1527 {:ok, %{id: second_report_id}} =
1528 CommonAPI.report(reporter, %{
1529 "account_id" => target_user.id,
1530 "comment" => "I don't like this user"
1533 CommonAPI.update_report_state(second_report_id, "closed")
1537 |> get("/api/pleroma/admin/reports", %{
1540 |> json_response(:ok)
1542 [open_report] = response["reports"]
1544 assert length(response["reports"]) == 1
1545 assert open_report["id"] == first_report_id
1547 assert response["total"] == 1
1551 |> get("/api/pleroma/admin/reports", %{
1554 |> json_response(:ok)
1556 [closed_report] = response["reports"]
1558 assert length(response["reports"]) == 1
1559 assert closed_report["id"] == second_report_id
1561 assert response["total"] == 1
1565 |> get("/api/pleroma/admin/reports", %{
1566 "state" => "resolved"
1568 |> json_response(:ok)
1570 assert Enum.empty?(response["reports"])
1571 assert response["total"] == 0
1574 test "returns 403 when requested by a non-admin" do
1575 user = insert(:user)
1576 token = insert(:oauth_token, user: user)
1580 |> assign(:user, user)
1581 |> assign(:token, token)
1582 |> get("/api/pleroma/admin/reports")
1584 assert json_response(conn, :forbidden) ==
1585 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1588 test "returns 403 when requested by anonymous" do
1589 conn = get(build_conn(), "/api/pleroma/admin/reports")
1591 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1595 describe "GET /api/pleroma/admin/grouped_reports" do
1597 [reporter, target_user] = insert_pair(:user)
1599 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1600 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1601 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1604 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1607 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1610 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1612 {:ok, first_report} =
1613 CommonAPI.report(reporter, %{
1614 "account_id" => target_user.id,
1615 "status_ids" => [first_status.id, second_status.id, third_status.id]
1618 {:ok, second_report} =
1619 CommonAPI.report(reporter, %{
1620 "account_id" => target_user.id,
1621 "status_ids" => [first_status.id, second_status.id]
1624 {:ok, third_report} =
1625 CommonAPI.report(reporter, %{
1626 "account_id" => target_user.id,
1627 "status_ids" => [first_status.id]
1631 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1632 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1633 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1634 first_report: first_report,
1635 first_status_reports: [first_report, second_report, third_report],
1636 second_status_reports: [first_report, second_report],
1637 third_status_reports: [first_report],
1638 target_user: target_user,
1643 test "returns reports grouped by status", %{
1645 first_status: first_status,
1646 second_status: second_status,
1647 third_status: third_status,
1648 first_status_reports: first_status_reports,
1649 second_status_reports: second_status_reports,
1650 third_status_reports: third_status_reports,
1651 target_user: target_user,
1656 |> get("/api/pleroma/admin/grouped_reports")
1657 |> json_response(:ok)
1659 assert length(response["reports"]) == 3
1661 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1663 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1665 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1667 assert length(first_group["reports"]) == 3
1668 assert length(second_group["reports"]) == 2
1669 assert length(third_group["reports"]) == 1
1671 assert first_group["date"] ==
1672 Enum.max_by(first_status_reports, fn act ->
1673 NaiveDateTime.from_iso8601!(act.data["published"])
1674 end).data["published"]
1676 assert first_group["status"] ==
1678 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1683 assert(first_group["account"]["id"] == target_user.id)
1685 assert length(first_group["actors"]) == 1
1686 assert hd(first_group["actors"])["id"] == reporter.id
1688 assert Enum.map(first_group["reports"], & &1["id"]) --
1689 Enum.map(first_status_reports, & &1.id) == []
1691 assert second_group["date"] ==
1692 Enum.max_by(second_status_reports, fn act ->
1693 NaiveDateTime.from_iso8601!(act.data["published"])
1694 end).data["published"]
1696 assert second_group["status"] ==
1698 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1703 assert second_group["account"]["id"] == target_user.id
1705 assert length(second_group["actors"]) == 1
1706 assert hd(second_group["actors"])["id"] == reporter.id
1708 assert Enum.map(second_group["reports"], & &1["id"]) --
1709 Enum.map(second_status_reports, & &1.id) == []
1711 assert third_group["date"] ==
1712 Enum.max_by(third_status_reports, fn act ->
1713 NaiveDateTime.from_iso8601!(act.data["published"])
1714 end).data["published"]
1716 assert third_group["status"] ==
1718 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1723 assert third_group["account"]["id"] == target_user.id
1725 assert length(third_group["actors"]) == 1
1726 assert hd(third_group["actors"])["id"] == reporter.id
1728 assert Enum.map(third_group["reports"], & &1["id"]) --
1729 Enum.map(third_status_reports, & &1.id) == []
1732 test "reopened report renders status data", %{
1734 first_report: first_report,
1735 first_status: first_status
1737 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1741 |> get("/api/pleroma/admin/grouped_reports")
1742 |> json_response(:ok)
1744 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1746 assert first_group["status"] ==
1748 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1754 test "reopened report does not render status data if status has been deleted", %{
1756 first_report: first_report,
1757 first_status: first_status,
1758 target_user: target_user
1760 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1761 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1763 refute Activity.get_by_ap_id(first_status.id)
1767 |> get("/api/pleroma/admin/grouped_reports")
1768 |> json_response(:ok)
1770 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1774 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1777 test "account not empty if status was deleted", %{
1779 first_report: first_report,
1780 first_status: first_status,
1781 target_user: target_user
1783 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1784 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1786 refute Activity.get_by_ap_id(first_status.id)
1790 |> get("/api/pleroma/admin/grouped_reports")
1791 |> json_response(:ok)
1793 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
1797 describe "PUT /api/pleroma/admin/statuses/:id" do
1799 activity = insert(:note_activity)
1804 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1807 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1808 |> json_response(:ok)
1810 assert response["sensitive"]
1812 log_entry = Repo.one(ModerationLog)
1814 assert ModerationLog.get_log_entry_message(log_entry) ==
1815 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1819 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1820 |> json_response(:ok)
1822 refute response["sensitive"]
1825 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1828 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1829 |> json_response(:ok)
1831 assert response["visibility"] == "public"
1833 log_entry = Repo.one(ModerationLog)
1835 assert ModerationLog.get_log_entry_message(log_entry) ==
1836 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1840 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1841 |> json_response(:ok)
1843 assert response["visibility"] == "private"
1847 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1848 |> json_response(:ok)
1850 assert response["visibility"] == "unlisted"
1853 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1854 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1856 assert json_response(conn, :bad_request) == "Unsupported visibility"
1860 describe "DELETE /api/pleroma/admin/statuses/:id" do
1862 activity = insert(:note_activity)
1867 test "deletes status", %{conn: conn, id: id, admin: admin} do
1869 |> delete("/api/pleroma/admin/statuses/#{id}")
1870 |> json_response(:ok)
1872 refute Activity.get_by_id(id)
1874 log_entry = Repo.one(ModerationLog)
1876 assert ModerationLog.get_log_entry_message(log_entry) ==
1877 "@#{admin.nickname} deleted status ##{id}"
1880 test "returns error when status is not exist", %{conn: conn} do
1881 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1883 assert json_response(conn, :bad_request) == "Could not delete"
1887 describe "GET /api/pleroma/admin/config" do
1888 clear_config(:configurable_from_database) do
1889 Pleroma.Config.put(:configurable_from_database, true)
1892 test "when configuration from database is off", %{conn: conn} do
1893 initial = Pleroma.Config.get(:configurable_from_database)
1894 Pleroma.Config.put(:configurable_from_database, false)
1895 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
1896 conn = get(conn, "/api/pleroma/admin/config")
1898 assert json_response(conn, 400) ==
1899 "To use this endpoint you need to enable configuration from database."
1902 test "without any settings in db", %{conn: conn} do
1903 conn = get(conn, "/api/pleroma/admin/config")
1905 assert json_response(conn, 400) ==
1906 "To use configuration from database migrate your settings to database."
1909 test "with settings only in db", %{conn: conn} do
1910 config1 = insert(:config)
1911 config2 = insert(:config)
1913 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1918 "group" => ":pleroma",
1923 "group" => ":pleroma",
1928 } = json_response(conn, 200)
1930 assert key1 == config1.key
1931 assert key2 == config2.key
1934 test "db is added to settings that are in db", %{conn: conn} do
1935 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1937 %{"configs" => configs} =
1939 |> get("/api/pleroma/admin/config")
1940 |> json_response(200)
1943 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1944 group == ":pleroma" and key == ":instance"
1947 assert instance_config["db"] == [":name"]
1950 test "merged default setting with db settings", %{conn: conn} do
1951 config1 = insert(:config)
1952 config2 = insert(:config)
1956 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1959 %{"configs" => configs} =
1961 |> get("/api/pleroma/admin/config")
1962 |> json_response(200)
1964 assert length(configs) > 3
1967 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1968 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1971 assert length(received_configs) == 3
1975 |> ConfigDB.from_binary()
1977 |> ConfigDB.convert()
1979 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1980 assert db in [[config1.key], [config2.key], db_keys]
1983 ConfigDB.from_binary_with_convert(config1.value),
1984 ConfigDB.from_binary_with_convert(config2.value),
1985 ConfigDB.from_binary_with_convert(config3.value)
1990 test "subkeys with full update right merge", %{conn: conn} do
1994 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
2000 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
2003 %{"configs" => configs} =
2005 |> get("/api/pleroma/admin/config")
2006 |> json_response(200)
2009 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
2010 group == ":pleroma" and key in [config1.key, config2.key]
2013 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
2014 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
2016 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
2017 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
2019 assert emoji_val[:groups] == [a: 1, b: 2]
2020 assert assets_val[:mascots] == [a: 1, b: 2]
2024 test "POST /api/pleroma/admin/config error", %{conn: conn} do
2025 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
2027 assert json_response(conn, 400) ==
2028 "To use this endpoint you need to enable configuration from database."
2031 describe "POST /api/pleroma/admin/config" do
2033 http = Application.get_env(:pleroma, :http)
2036 Application.delete_env(:pleroma, :key1)
2037 Application.delete_env(:pleroma, :key2)
2038 Application.delete_env(:pleroma, :key3)
2039 Application.delete_env(:pleroma, :key4)
2040 Application.delete_env(:pleroma, :keyaa1)
2041 Application.delete_env(:pleroma, :keyaa2)
2042 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
2043 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
2044 Application.put_env(:pleroma, :http, http)
2045 Application.put_env(:tesla, :adapter, Tesla.Mock)
2049 clear_config(:configurable_from_database) do
2050 Pleroma.Config.put(:configurable_from_database, true)
2053 @tag capture_log: true
2054 test "create new config setting in db", %{conn: conn} do
2055 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2056 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
2059 post(conn, "/api/pleroma/admin/config", %{
2061 %{group: ":pleroma", key: ":key1", value: "value1"},
2063 group: ":ueberauth",
2065 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
2071 ":nested_1" => "nested_value1",
2073 %{":nested_22" => "nested_value222"},
2074 %{":nested_33" => %{":nested_44" => "nested_444"}}
2082 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2083 %{"nested_4" => true}
2089 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2094 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2099 assert json_response(conn, 200) == %{
2102 "group" => ":pleroma",
2104 "value" => "value1",
2108 "group" => ":ueberauth",
2109 "key" => "Ueberauth",
2110 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
2111 "db" => [":consumer_secret"]
2114 "group" => ":pleroma",
2117 ":nested_1" => "nested_value1",
2119 %{":nested_22" => "nested_value222"},
2120 %{":nested_33" => %{":nested_44" => "nested_444"}}
2126 "group" => ":pleroma",
2129 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2130 %{"nested_4" => true}
2135 "group" => ":pleroma",
2137 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2143 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2149 assert Application.get_env(:pleroma, :key1) == "value1"
2151 assert Application.get_env(:pleroma, :key2) == %{
2152 nested_1: "nested_value1",
2154 %{nested_22: "nested_value222"},
2155 %{nested_33: %{nested_44: "nested_444"}}
2159 assert Application.get_env(:pleroma, :key3) == [
2160 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2161 %{"nested_4" => true}
2164 assert Application.get_env(:pleroma, :key4) == %{
2165 "endpoint" => "https://example.com",
2169 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2172 test "save configs setting without explicit key", %{conn: conn} do
2173 level = Application.get_env(:quack, :level)
2174 meta = Application.get_env(:quack, :meta)
2175 webhook_url = Application.get_env(:quack, :webhook_url)
2178 Application.put_env(:quack, :level, level)
2179 Application.put_env(:quack, :meta, meta)
2180 Application.put_env(:quack, :webhook_url, webhook_url)
2184 post(conn, "/api/pleroma/admin/config", %{
2198 key: ":webhook_url",
2199 value: "https://hooks.slack.com/services/KEY"
2204 assert json_response(conn, 200) == %{
2207 "group" => ":quack",
2213 "group" => ":quack",
2215 "value" => [":none"],
2219 "group" => ":quack",
2220 "key" => ":webhook_url",
2221 "value" => "https://hooks.slack.com/services/KEY",
2222 "db" => [":webhook_url"]
2227 assert Application.get_env(:quack, :level) == :info
2228 assert Application.get_env(:quack, :meta) == [:none]
2229 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2232 test "saving config with partial update", %{conn: conn} do
2233 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2236 post(conn, "/api/pleroma/admin/config", %{
2238 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2242 assert json_response(conn, 200) == %{
2245 "group" => ":pleroma",
2248 %{"tuple" => [":key1", 1]},
2249 %{"tuple" => [":key2", 2]},
2250 %{"tuple" => [":key3", 3]}
2252 "db" => [":key1", ":key2", ":key3"]
2258 test "saving config which need pleroma reboot", %{conn: conn} do
2259 chat = Pleroma.Config.get(:chat)
2260 on_exit(fn -> Pleroma.Config.put(:chat, chat) end)
2265 "/api/pleroma/admin/config",
2268 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2273 assert json_response(conn, 200) == %{
2276 "db" => [":enabled"],
2277 "group" => ":pleroma",
2279 "value" => [%{"tuple" => [":enabled", true]}]
2282 "need_reboot" => true
2286 test "saving config with nested merge", %{conn: conn} do
2288 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2291 post(conn, "/api/pleroma/admin/config", %{
2294 group: config.group,
2297 %{"tuple" => [":key3", 3]},
2302 %{"tuple" => [":k2", 1]},
2303 %{"tuple" => [":k3", 3]}
2312 assert json_response(conn, 200) == %{
2315 "group" => ":pleroma",
2318 %{"tuple" => [":key1", 1]},
2319 %{"tuple" => [":key3", 3]},
2324 %{"tuple" => [":k1", 1]},
2325 %{"tuple" => [":k2", 1]},
2326 %{"tuple" => [":k3", 3]}
2331 "db" => [":key1", ":key3", ":key2"]
2337 test "saving special atoms", %{conn: conn} do
2339 post(conn, "/api/pleroma/admin/config", %{
2342 "group" => ":pleroma",
2348 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2356 assert json_response(conn, 200) == %{
2359 "group" => ":pleroma",
2365 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2369 "db" => [":ssl_options"]
2374 assert Application.get_env(:pleroma, :key1) == [
2375 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2379 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2380 backends = Application.get_env(:logger, :backends)
2381 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2387 value: :erlang.term_to_binary([])
2391 post(conn, "/api/pleroma/admin/config", %{
2394 group: config.group,
2396 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2401 assert json_response(conn, 200) == %{
2404 "group" => ":logger",
2405 "key" => ":backends",
2408 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2410 "db" => [":backends"]
2415 assert Application.get_env(:logger, :backends) == [
2417 {ExSyslogger, :ex_syslogger}
2420 ExUnit.CaptureLog.capture_log(fn ->
2422 Logger.warn("Ooops...")
2426 test "saving full setting if value is not keyword", %{conn: conn} do
2431 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2435 post(conn, "/api/pleroma/admin/config", %{
2437 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2441 assert json_response(conn, 200) == %{
2444 "group" => ":tesla",
2445 "key" => ":adapter",
2446 "value" => "Tesla.Adapter.Httpc",
2447 "db" => [":adapter"]
2453 test "update config setting & delete with fallback to default value", %{
2458 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2459 config1 = insert(:config, key: ":keyaa1")
2460 config2 = insert(:config, key: ":keyaa2")
2464 group: ":ueberauth",
2469 post(conn, "/api/pleroma/admin/config", %{
2471 %{group: config1.group, key: config1.key, value: "another_value"},
2472 %{group: config2.group, key: config2.key, value: "another_value"}
2476 assert json_response(conn, 200) == %{
2479 "group" => ":pleroma",
2480 "key" => config1.key,
2481 "value" => "another_value",
2485 "group" => ":pleroma",
2486 "key" => config2.key,
2487 "value" => "another_value",
2493 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2494 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2495 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2499 |> assign(:user, admin)
2500 |> assign(:token, token)
2501 |> post("/api/pleroma/admin/config", %{
2503 %{group: config2.group, key: config2.key, delete: true},
2505 group: ":ueberauth",
2512 assert json_response(conn, 200) == %{
2516 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2517 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2520 test "common config example", %{conn: conn} do
2521 adapter = Application.get_env(:tesla, :adapter)
2522 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2525 post(conn, "/api/pleroma/admin/config", %{
2528 "group" => ":pleroma",
2529 "key" => "Pleroma.Captcha.NotReal",
2531 %{"tuple" => [":enabled", false]},
2532 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2533 %{"tuple" => [":seconds_valid", 60]},
2534 %{"tuple" => [":path", ""]},
2535 %{"tuple" => [":key1", nil]},
2536 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2537 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2538 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2539 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2540 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2541 %{"tuple" => [":name", "Pleroma"]}
2545 "group" => ":tesla",
2546 "key" => ":adapter",
2547 "value" => "Tesla.Adapter.Httpc"
2552 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2553 assert Pleroma.Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2555 assert json_response(conn, 200) == %{
2558 "group" => ":pleroma",
2559 "key" => "Pleroma.Captcha.NotReal",
2561 %{"tuple" => [":enabled", false]},
2562 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2563 %{"tuple" => [":seconds_valid", 60]},
2564 %{"tuple" => [":path", ""]},
2565 %{"tuple" => [":key1", nil]},
2566 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2567 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2568 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2569 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2570 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2571 %{"tuple" => [":name", "Pleroma"]}
2588 "group" => ":tesla",
2589 "key" => ":adapter",
2590 "value" => "Tesla.Adapter.Httpc",
2591 "db" => [":adapter"]
2597 test "tuples with more than two values", %{conn: conn} do
2599 post(conn, "/api/pleroma/admin/config", %{
2602 "group" => ":pleroma",
2603 "key" => "Pleroma.Web.Endpoint.NotReal",
2619 "/api/v1/streaming",
2620 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2627 "Phoenix.Endpoint.CowboyWebSocket",
2630 "Phoenix.Transports.WebSocket",
2633 "Pleroma.Web.Endpoint",
2634 "Pleroma.Web.UserSocket",
2645 "Phoenix.Endpoint.Cowboy2Handler",
2646 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2663 assert json_response(conn, 200) == %{
2666 "group" => ":pleroma",
2667 "key" => "Pleroma.Web.Endpoint.NotReal",
2683 "/api/v1/streaming",
2684 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2691 "Phoenix.Endpoint.CowboyWebSocket",
2694 "Phoenix.Transports.WebSocket",
2697 "Pleroma.Web.Endpoint",
2698 "Pleroma.Web.UserSocket",
2709 "Phoenix.Endpoint.Cowboy2Handler",
2710 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2729 test "settings with nesting map", %{conn: conn} do
2731 post(conn, "/api/pleroma/admin/config", %{
2734 "group" => ":pleroma",
2737 %{"tuple" => [":key2", "some_val"]},
2742 ":max_options" => 20,
2743 ":max_option_chars" => 200,
2744 ":min_expiration" => 0,
2745 ":max_expiration" => 31_536_000,
2747 ":max_options" => 20,
2748 ":max_option_chars" => 200,
2749 ":min_expiration" => 0,
2750 ":max_expiration" => 31_536_000
2760 assert json_response(conn, 200) ==
2764 "group" => ":pleroma",
2767 %{"tuple" => [":key2", "some_val"]},
2772 ":max_expiration" => 31_536_000,
2773 ":max_option_chars" => 200,
2774 ":max_options" => 20,
2775 ":min_expiration" => 0,
2777 ":max_expiration" => 31_536_000,
2778 ":max_option_chars" => 200,
2779 ":max_options" => 20,
2780 ":min_expiration" => 0
2786 "db" => [":key2", ":key3"]
2792 test "value as map", %{conn: conn} do
2794 post(conn, "/api/pleroma/admin/config", %{
2797 "group" => ":pleroma",
2799 "value" => %{"key" => "some_val"}
2804 assert json_response(conn, 200) ==
2808 "group" => ":pleroma",
2810 "value" => %{"key" => "some_val"},
2817 test "queues key as atom", %{conn: conn} do
2819 post(conn, "/api/pleroma/admin/config", %{
2825 %{"tuple" => [":federator_incoming", 50]},
2826 %{"tuple" => [":federator_outgoing", 50]},
2827 %{"tuple" => [":web_push", 50]},
2828 %{"tuple" => [":mailer", 10]},
2829 %{"tuple" => [":transmogrifier", 20]},
2830 %{"tuple" => [":scheduled_activities", 10]},
2831 %{"tuple" => [":background", 5]}
2837 assert json_response(conn, 200) == %{
2843 %{"tuple" => [":federator_incoming", 50]},
2844 %{"tuple" => [":federator_outgoing", 50]},
2845 %{"tuple" => [":web_push", 50]},
2846 %{"tuple" => [":mailer", 10]},
2847 %{"tuple" => [":transmogrifier", 20]},
2848 %{"tuple" => [":scheduled_activities", 10]},
2849 %{"tuple" => [":background", 5]}
2852 ":federator_incoming",
2853 ":federator_outgoing",
2857 ":scheduled_activities",
2865 test "delete part of settings by atom subkeys", %{conn: conn} do
2869 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2873 post(conn, "/api/pleroma/admin/config", %{
2876 group: config.group,
2878 subkeys: [":subkey1", ":subkey3"],
2884 assert json_response(conn, 200) == %{
2887 "group" => ":pleroma",
2889 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2890 "db" => [":subkey2"]
2896 test "proxy tuple localhost", %{conn: conn} do
2898 post(conn, "/api/pleroma/admin/config", %{
2904 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2905 %{"tuple" => [":send_user_agent", false]}
2911 assert json_response(conn, 200) == %{
2914 "group" => ":pleroma",
2917 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2918 %{"tuple" => [":send_user_agent", false]}
2920 "db" => [":proxy_url", ":send_user_agent"]
2926 test "proxy tuple domain", %{conn: conn} do
2928 post(conn, "/api/pleroma/admin/config", %{
2934 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2935 %{"tuple" => [":send_user_agent", false]}
2941 assert json_response(conn, 200) == %{
2944 "group" => ":pleroma",
2947 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2948 %{"tuple" => [":send_user_agent", false]}
2950 "db" => [":proxy_url", ":send_user_agent"]
2956 test "proxy tuple ip", %{conn: conn} do
2958 post(conn, "/api/pleroma/admin/config", %{
2964 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2965 %{"tuple" => [":send_user_agent", false]}
2971 assert json_response(conn, 200) == %{
2974 "group" => ":pleroma",
2977 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2978 %{"tuple" => [":send_user_agent", false]}
2980 "db" => [":proxy_url", ":send_user_agent"]
2987 describe "config mix tasks run" do
2989 Mix.shell(Mix.Shell.Quiet)
2992 Mix.shell(Mix.Shell.IO)
2998 clear_config(:configurable_from_database) do
2999 Pleroma.Config.put(:configurable_from_database, true)
3002 clear_config([:feed, :post_title]) do
3003 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
3006 test "transfer settings to DB and to file", %{conn: conn} do
3007 assert Repo.all(Pleroma.ConfigDB) == []
3008 Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
3009 assert Repo.aggregate(Pleroma.ConfigDB, :count, :id) > 0
3011 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
3013 assert json_response(conn, 200) == %{}
3014 assert Repo.all(Pleroma.ConfigDB) == []
3017 test "returns error if configuration from database is off", %{conn: conn} do
3018 initial = Pleroma.Config.get(:configurable_from_database)
3019 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
3020 Pleroma.Config.put(:configurable_from_database, false)
3022 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
3024 assert json_response(conn, 400) ==
3025 "To use this endpoint you need to enable configuration from database."
3027 assert Repo.all(Pleroma.ConfigDB) == []
3031 describe "GET /api/pleroma/admin/restart" do
3032 clear_config(:configurable_from_database) do
3033 Pleroma.Config.put(:configurable_from_database, true)
3036 test "pleroma restarts", %{conn: conn} do
3037 ExUnit.CaptureLog.capture_log(fn ->
3038 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
3039 end) =~ "pleroma restarted"
3043 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
3045 user = insert(:user)
3047 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
3048 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
3049 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
3051 insert(:note_activity, user: user, published: date1)
3052 insert(:note_activity, user: user, published: date2)
3053 insert(:note_activity, user: user, published: date3)
3058 test "renders user's statuses", %{conn: conn, user: user} do
3059 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3061 assert json_response(conn, 200) |> length() == 3
3064 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3065 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3067 assert json_response(conn, 200) |> length() == 2
3070 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3071 {:ok, _private_status} =
3072 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3074 {:ok, _public_status} =
3075 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3077 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3079 assert json_response(conn, 200) |> length() == 4
3082 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3083 {:ok, _private_status} =
3084 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3086 {:ok, _public_status} =
3087 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3089 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3091 assert json_response(conn, 200) |> length() == 5
3095 describe "GET /api/pleroma/admin/moderation_log" do
3097 moderator = insert(:user, is_moderator: true)
3099 %{moderator: moderator}
3102 test "returns the log", %{conn: conn, admin: admin} do
3103 Repo.insert(%ModerationLog{
3107 "nickname" => admin.nickname,
3110 action: "relay_follow",
3111 target: "https://example.org/relay"
3113 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3116 Repo.insert(%ModerationLog{
3120 "nickname" => admin.nickname,
3123 action: "relay_unfollow",
3124 target: "https://example.org/relay"
3126 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3129 conn = get(conn, "/api/pleroma/admin/moderation_log")
3131 response = json_response(conn, 200)
3132 [first_entry, second_entry] = response["items"]
3134 assert response["total"] == 2
3135 assert first_entry["data"]["action"] == "relay_unfollow"
3137 assert first_entry["message"] ==
3138 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3140 assert second_entry["data"]["action"] == "relay_follow"
3142 assert second_entry["message"] ==
3143 "@#{admin.nickname} followed relay: https://example.org/relay"
3146 test "returns the log with pagination", %{conn: conn, admin: admin} do
3147 Repo.insert(%ModerationLog{
3151 "nickname" => admin.nickname,
3154 action: "relay_follow",
3155 target: "https://example.org/relay"
3157 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3160 Repo.insert(%ModerationLog{
3164 "nickname" => admin.nickname,
3167 action: "relay_unfollow",
3168 target: "https://example.org/relay"
3170 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3173 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3175 response1 = json_response(conn1, 200)
3176 [first_entry] = response1["items"]
3178 assert response1["total"] == 2
3179 assert response1["items"] |> length() == 1
3180 assert first_entry["data"]["action"] == "relay_unfollow"
3182 assert first_entry["message"] ==
3183 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3185 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3187 response2 = json_response(conn2, 200)
3188 [second_entry] = response2["items"]
3190 assert response2["total"] == 2
3191 assert response2["items"] |> length() == 1
3192 assert second_entry["data"]["action"] == "relay_follow"
3194 assert second_entry["message"] ==
3195 "@#{admin.nickname} followed relay: https://example.org/relay"
3198 test "filters log by date", %{conn: conn, admin: admin} do
3199 first_date = "2017-08-15T15:47:06Z"
3200 second_date = "2017-08-20T15:47:06Z"
3202 Repo.insert(%ModerationLog{
3206 "nickname" => admin.nickname,
3209 action: "relay_follow",
3210 target: "https://example.org/relay"
3212 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3215 Repo.insert(%ModerationLog{
3219 "nickname" => admin.nickname,
3222 action: "relay_unfollow",
3223 target: "https://example.org/relay"
3225 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3231 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3234 response1 = json_response(conn1, 200)
3235 [first_entry] = response1["items"]
3237 assert response1["total"] == 1
3238 assert first_entry["data"]["action"] == "relay_unfollow"
3240 assert first_entry["message"] ==
3241 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3244 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3245 Repo.insert(%ModerationLog{
3249 "nickname" => admin.nickname,
3252 action: "relay_follow",
3253 target: "https://example.org/relay"
3257 Repo.insert(%ModerationLog{
3260 "id" => moderator.id,
3261 "nickname" => moderator.nickname,
3264 action: "relay_unfollow",
3265 target: "https://example.org/relay"
3269 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3271 response1 = json_response(conn1, 200)
3272 [first_entry] = response1["items"]
3274 assert response1["total"] == 1
3275 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3278 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3279 ModerationLog.insert_log(%{
3281 action: "relay_follow",
3282 target: "https://example.org/relay"
3285 ModerationLog.insert_log(%{
3287 action: "relay_unfollow",
3288 target: "https://example.org/relay"
3291 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3293 response1 = json_response(conn1, 200)
3294 [first_entry] = response1["items"]
3296 assert response1["total"] == 1
3298 assert get_in(first_entry, ["data", "message"]) ==
3299 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3303 describe "PATCH /users/:nickname/force_password_reset" do
3304 test "sets password_reset_pending to true", %{conn: conn} do
3305 user = insert(:user)
3306 assert user.password_reset_pending == false
3309 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3311 assert json_response(conn, 204) == ""
3313 ObanHelpers.perform_all()
3315 assert User.get_by_id(user.id).password_reset_pending == true
3319 describe "relays" do
3320 test "POST /relay", %{conn: conn, admin: admin} do
3322 post(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 = Repo.one(ModerationLog)
3330 assert ModerationLog.get_log_entry_message(log_entry) ==
3331 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3334 test "GET /relay", %{conn: conn} do
3335 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3337 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3338 |> Enum.each(fn ap_id ->
3339 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3340 User.follow(relay_user, user)
3343 conn = get(conn, "/api/pleroma/admin/relay")
3345 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3348 test "DELETE /relay", %{conn: conn, admin: admin} do
3349 post(conn, "/api/pleroma/admin/relay", %{
3350 relay_url: "http://mastodon.example.org/users/admin"
3354 delete(conn, "/api/pleroma/admin/relay", %{
3355 relay_url: "http://mastodon.example.org/users/admin"
3358 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3360 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3362 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3363 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3365 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3366 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3370 describe "instances" do
3371 test "GET /instances/:instance/statuses", %{conn: conn} do
3372 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3373 user2 = insert(:user, local: false, nickname: "test@test.com")
3374 insert_pair(:note_activity, user: user)
3375 insert(:note_activity, user: user2)
3377 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3379 response = json_response(ret_conn, 200)
3381 assert length(response) == 2
3383 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3385 response = json_response(ret_conn, 200)
3387 assert length(response) == 1
3389 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3391 response = json_response(ret_conn, 200)
3393 assert Enum.empty?(response)
3397 describe "PATCH /confirm_email" do
3398 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3399 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3401 assert first_user.confirmation_pending == true
3402 assert second_user.confirmation_pending == true
3405 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3407 first_user.nickname,
3408 second_user.nickname
3412 assert ret_conn.status == 200
3414 assert first_user.confirmation_pending == true
3415 assert second_user.confirmation_pending == true
3417 log_entry = Repo.one(ModerationLog)
3419 assert ModerationLog.get_log_entry_message(log_entry) ==
3420 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3421 second_user.nickname
3426 describe "PATCH /resend_confirmation_email" do
3427 test "it resend emails for two users", %{conn: conn, admin: admin} do
3428 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3431 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3433 first_user.nickname,
3434 second_user.nickname
3438 assert ret_conn.status == 200
3440 log_entry = Repo.one(ModerationLog)
3442 assert ModerationLog.get_log_entry_message(log_entry) ==
3443 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3444 second_user.nickname
3449 describe "POST /reports/:id/notes" do
3450 setup %{conn: conn, admin: admin} do
3451 [reporter, target_user] = insert_pair(:user)
3452 activity = insert(:note_activity, user: target_user)
3454 {:ok, %{id: report_id}} =
3455 CommonAPI.report(reporter, %{
3456 "account_id" => target_user.id,
3457 "comment" => "I feel offended",
3458 "status_ids" => [activity.id]
3461 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3462 content: "this is disgusting!"
3465 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3466 content: "this is disgusting2!"
3471 report_id: report_id
3475 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3476 [note, _] = Repo.all(ReportNote)
3479 activity_id: ^report_id,
3480 content: "this is disgusting!",
3485 test "it returns reports with notes", %{conn: conn, admin: admin} do
3486 conn = get(conn, "/api/pleroma/admin/reports")
3488 response = json_response(conn, 200)
3489 notes = hd(response["reports"])["notes"]
3492 assert note["user"]["nickname"] == admin.nickname
3493 assert note["content"] == "this is disgusting!"
3494 assert note["created_at"]
3495 assert response["total"] == 1
3498 test "it deletes the note", %{conn: conn, report_id: report_id} do
3499 assert ReportNote |> Repo.all() |> length() == 2
3501 [note, _] = Repo.all(ReportNote)
3503 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3505 assert ReportNote |> Repo.all() |> length() == 1
3509 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3510 admin = insert(:user, is_admin: true)
3513 assign(conn, :user, admin)
3514 |> get("/api/pleroma/admin/config/descriptions")
3516 assert [child | _others] = json_response(conn, 200)
3518 assert child["children"]
3520 assert String.starts_with?(child["group"], ":")
3521 assert child["description"]
3525 # Needed for testing
3526 defmodule Pleroma.Web.Endpoint.NotReal do
3529 defmodule Pleroma.Captcha.NotReal do