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 "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1369 |> patch("/api/pleroma/admin/reports", %{
1371 %{"state" => "resolved", "id" => id}
1374 |> json_response(:no_content)
1376 activity = Activity.get_by_id(id)
1377 assert activity.data["state"] == "resolved"
1379 log_entry = Repo.one(ModerationLog)
1381 assert ModerationLog.get_log_entry_message(log_entry) ==
1382 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1385 test "closes report", %{conn: conn, id: id, admin: admin} do
1387 |> patch("/api/pleroma/admin/reports", %{
1389 %{"state" => "closed", "id" => id}
1392 |> json_response(:no_content)
1394 activity = Activity.get_by_id(id)
1395 assert activity.data["state"] == "closed"
1397 log_entry = Repo.one(ModerationLog)
1399 assert ModerationLog.get_log_entry_message(log_entry) ==
1400 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1403 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1406 |> patch("/api/pleroma/admin/reports", %{
1408 %{"state" => "test", "id" => id}
1412 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1415 test "returns 404 when report is not exist", %{conn: conn} do
1418 |> patch("/api/pleroma/admin/reports", %{
1420 %{"state" => "closed", "id" => "test"}
1424 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1427 test "updates state of multiple reports", %{
1431 second_report_id: second_report_id
1434 |> patch("/api/pleroma/admin/reports", %{
1436 %{"state" => "resolved", "id" => id},
1437 %{"state" => "closed", "id" => second_report_id}
1440 |> json_response(:no_content)
1442 activity = Activity.get_by_id(id)
1443 second_activity = Activity.get_by_id(second_report_id)
1444 assert activity.data["state"] == "resolved"
1445 assert second_activity.data["state"] == "closed"
1447 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1449 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1450 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1452 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1453 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1457 describe "GET /api/pleroma/admin/reports" do
1458 test "returns empty response when no reports created", %{conn: conn} do
1461 |> get("/api/pleroma/admin/reports")
1462 |> json_response(:ok)
1464 assert Enum.empty?(response["reports"])
1465 assert response["total"] == 0
1468 test "returns reports", %{conn: conn} do
1469 [reporter, target_user] = insert_pair(:user)
1470 activity = insert(:note_activity, user: target_user)
1472 {:ok, %{id: report_id}} =
1473 CommonAPI.report(reporter, %{
1474 "account_id" => target_user.id,
1475 "comment" => "I feel offended",
1476 "status_ids" => [activity.id]
1481 |> get("/api/pleroma/admin/reports")
1482 |> json_response(:ok)
1484 [report] = response["reports"]
1486 assert length(response["reports"]) == 1
1487 assert report["id"] == report_id
1489 assert response["total"] == 1
1492 test "returns reports with specified state", %{conn: conn} do
1493 [reporter, target_user] = insert_pair(:user)
1494 activity = insert(:note_activity, user: target_user)
1496 {:ok, %{id: first_report_id}} =
1497 CommonAPI.report(reporter, %{
1498 "account_id" => target_user.id,
1499 "comment" => "I feel offended",
1500 "status_ids" => [activity.id]
1503 {:ok, %{id: second_report_id}} =
1504 CommonAPI.report(reporter, %{
1505 "account_id" => target_user.id,
1506 "comment" => "I don't like this user"
1509 CommonAPI.update_report_state(second_report_id, "closed")
1513 |> get("/api/pleroma/admin/reports", %{
1516 |> json_response(:ok)
1518 [open_report] = response["reports"]
1520 assert length(response["reports"]) == 1
1521 assert open_report["id"] == first_report_id
1523 assert response["total"] == 1
1527 |> get("/api/pleroma/admin/reports", %{
1530 |> json_response(:ok)
1532 [closed_report] = response["reports"]
1534 assert length(response["reports"]) == 1
1535 assert closed_report["id"] == second_report_id
1537 assert response["total"] == 1
1541 |> get("/api/pleroma/admin/reports", %{
1542 "state" => "resolved"
1544 |> json_response(:ok)
1546 assert Enum.empty?(response["reports"])
1547 assert response["total"] == 0
1550 test "returns 403 when requested by a non-admin" do
1551 user = insert(:user)
1552 token = insert(:oauth_token, user: user)
1556 |> assign(:user, user)
1557 |> assign(:token, token)
1558 |> get("/api/pleroma/admin/reports")
1560 assert json_response(conn, :forbidden) ==
1561 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1564 test "returns 403 when requested by anonymous" do
1565 conn = get(build_conn(), "/api/pleroma/admin/reports")
1567 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1571 describe "GET /api/pleroma/admin/grouped_reports" do
1573 [reporter, target_user] = insert_pair(:user)
1575 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1576 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1577 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1580 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1583 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1586 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1588 {:ok, first_report} =
1589 CommonAPI.report(reporter, %{
1590 "account_id" => target_user.id,
1591 "status_ids" => [first_status.id, second_status.id, third_status.id]
1594 {:ok, second_report} =
1595 CommonAPI.report(reporter, %{
1596 "account_id" => target_user.id,
1597 "status_ids" => [first_status.id, second_status.id]
1600 {:ok, third_report} =
1601 CommonAPI.report(reporter, %{
1602 "account_id" => target_user.id,
1603 "status_ids" => [first_status.id]
1607 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1608 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1609 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1610 first_report: first_report,
1611 first_status_reports: [first_report, second_report, third_report],
1612 second_status_reports: [first_report, second_report],
1613 third_status_reports: [first_report],
1614 target_user: target_user,
1619 test "returns reports grouped by status", %{
1621 first_status: first_status,
1622 second_status: second_status,
1623 third_status: third_status,
1624 first_status_reports: first_status_reports,
1625 second_status_reports: second_status_reports,
1626 third_status_reports: third_status_reports,
1627 target_user: target_user,
1632 |> get("/api/pleroma/admin/grouped_reports")
1633 |> json_response(:ok)
1635 assert length(response["reports"]) == 3
1637 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1639 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1641 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1643 assert length(first_group["reports"]) == 3
1644 assert length(second_group["reports"]) == 2
1645 assert length(third_group["reports"]) == 1
1647 assert first_group["date"] ==
1648 Enum.max_by(first_status_reports, fn act ->
1649 NaiveDateTime.from_iso8601!(act.data["published"])
1650 end).data["published"]
1652 assert first_group["status"] ==
1654 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1659 assert(first_group["account"]["id"] == target_user.id)
1661 assert length(first_group["actors"]) == 1
1662 assert hd(first_group["actors"])["id"] == reporter.id
1664 assert Enum.map(first_group["reports"], & &1["id"]) --
1665 Enum.map(first_status_reports, & &1.id) == []
1667 assert second_group["date"] ==
1668 Enum.max_by(second_status_reports, fn act ->
1669 NaiveDateTime.from_iso8601!(act.data["published"])
1670 end).data["published"]
1672 assert second_group["status"] ==
1674 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1679 assert second_group["account"]["id"] == target_user.id
1681 assert length(second_group["actors"]) == 1
1682 assert hd(second_group["actors"])["id"] == reporter.id
1684 assert Enum.map(second_group["reports"], & &1["id"]) --
1685 Enum.map(second_status_reports, & &1.id) == []
1687 assert third_group["date"] ==
1688 Enum.max_by(third_status_reports, fn act ->
1689 NaiveDateTime.from_iso8601!(act.data["published"])
1690 end).data["published"]
1692 assert third_group["status"] ==
1694 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1699 assert third_group["account"]["id"] == target_user.id
1701 assert length(third_group["actors"]) == 1
1702 assert hd(third_group["actors"])["id"] == reporter.id
1704 assert Enum.map(third_group["reports"], & &1["id"]) --
1705 Enum.map(third_status_reports, & &1.id) == []
1708 test "reopened report renders status data", %{
1710 first_report: first_report,
1711 first_status: first_status
1713 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1717 |> get("/api/pleroma/admin/grouped_reports")
1718 |> json_response(:ok)
1720 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1722 assert first_group["status"] ==
1724 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1730 test "reopened report does not render status data if status has been deleted", %{
1732 first_report: first_report,
1733 first_status: first_status,
1734 target_user: target_user
1736 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1737 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1739 refute Activity.get_by_ap_id(first_status.id)
1743 |> get("/api/pleroma/admin/grouped_reports")
1744 |> json_response(:ok)
1746 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1750 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1753 test "account not empty if status was deleted", %{
1755 first_report: first_report,
1756 first_status: first_status,
1757 target_user: target_user
1759 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1760 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1762 refute Activity.get_by_ap_id(first_status.id)
1766 |> get("/api/pleroma/admin/grouped_reports")
1767 |> json_response(:ok)
1769 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
1773 describe "PUT /api/pleroma/admin/statuses/:id" do
1775 activity = insert(:note_activity)
1780 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1783 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1784 |> json_response(:ok)
1786 assert response["sensitive"]
1788 log_entry = Repo.one(ModerationLog)
1790 assert ModerationLog.get_log_entry_message(log_entry) ==
1791 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1795 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1796 |> json_response(:ok)
1798 refute response["sensitive"]
1801 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1804 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1805 |> json_response(:ok)
1807 assert response["visibility"] == "public"
1809 log_entry = Repo.one(ModerationLog)
1811 assert ModerationLog.get_log_entry_message(log_entry) ==
1812 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1816 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1817 |> json_response(:ok)
1819 assert response["visibility"] == "private"
1823 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1824 |> json_response(:ok)
1826 assert response["visibility"] == "unlisted"
1829 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1830 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1832 assert json_response(conn, :bad_request) == "Unsupported visibility"
1836 describe "DELETE /api/pleroma/admin/statuses/:id" do
1838 activity = insert(:note_activity)
1843 test "deletes status", %{conn: conn, id: id, admin: admin} do
1845 |> delete("/api/pleroma/admin/statuses/#{id}")
1846 |> json_response(:ok)
1848 refute Activity.get_by_id(id)
1850 log_entry = Repo.one(ModerationLog)
1852 assert ModerationLog.get_log_entry_message(log_entry) ==
1853 "@#{admin.nickname} deleted status ##{id}"
1856 test "returns error when status is not exist", %{conn: conn} do
1857 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1859 assert json_response(conn, :bad_request) == "Could not delete"
1863 describe "GET /api/pleroma/admin/config" do
1864 clear_config(:configurable_from_database) do
1865 Pleroma.Config.put(:configurable_from_database, true)
1868 test "when configuration from database is off", %{conn: conn} do
1869 initial = Pleroma.Config.get(:configurable_from_database)
1870 Pleroma.Config.put(:configurable_from_database, false)
1871 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
1872 conn = get(conn, "/api/pleroma/admin/config")
1874 assert json_response(conn, 400) ==
1875 "To use this endpoint you need to enable configuration from database."
1878 test "without any settings in db", %{conn: conn} do
1879 conn = get(conn, "/api/pleroma/admin/config")
1881 assert json_response(conn, 400) ==
1882 "To use configuration from database migrate your settings to database."
1885 test "with settings only in db", %{conn: conn} do
1886 config1 = insert(:config)
1887 config2 = insert(:config)
1889 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1894 "group" => ":pleroma",
1899 "group" => ":pleroma",
1904 } = json_response(conn, 200)
1906 assert key1 == config1.key
1907 assert key2 == config2.key
1910 test "db is added to settings that are in db", %{conn: conn} do
1911 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1913 %{"configs" => configs} =
1915 |> get("/api/pleroma/admin/config")
1916 |> json_response(200)
1919 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1920 group == ":pleroma" and key == ":instance"
1923 assert instance_config["db"] == [":name"]
1926 test "merged default setting with db settings", %{conn: conn} do
1927 config1 = insert(:config)
1928 config2 = insert(:config)
1932 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1935 %{"configs" => configs} =
1937 |> get("/api/pleroma/admin/config")
1938 |> json_response(200)
1940 assert length(configs) > 3
1943 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1944 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1947 assert length(received_configs) == 3
1951 |> ConfigDB.from_binary()
1953 |> ConfigDB.convert()
1955 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1956 assert db in [[config1.key], [config2.key], db_keys]
1959 ConfigDB.from_binary_with_convert(config1.value),
1960 ConfigDB.from_binary_with_convert(config2.value),
1961 ConfigDB.from_binary_with_convert(config3.value)
1966 test "subkeys with full update right merge", %{conn: conn} do
1970 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1976 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1979 %{"configs" => configs} =
1981 |> get("/api/pleroma/admin/config")
1982 |> json_response(200)
1985 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1986 group == ":pleroma" and key in [config1.key, config2.key]
1989 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1990 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1992 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1993 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1995 assert emoji_val[:groups] == [a: 1, b: 2]
1996 assert assets_val[:mascots] == [a: 1, b: 2]
2000 test "POST /api/pleroma/admin/config error", %{conn: conn} do
2001 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
2003 assert json_response(conn, 400) ==
2004 "To use this endpoint you need to enable configuration from database."
2007 describe "POST /api/pleroma/admin/config" do
2009 http = Application.get_env(:pleroma, :http)
2012 Application.delete_env(:pleroma, :key1)
2013 Application.delete_env(:pleroma, :key2)
2014 Application.delete_env(:pleroma, :key3)
2015 Application.delete_env(:pleroma, :key4)
2016 Application.delete_env(:pleroma, :keyaa1)
2017 Application.delete_env(:pleroma, :keyaa2)
2018 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
2019 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
2020 Application.put_env(:pleroma, :http, http)
2021 Application.put_env(:tesla, :adapter, Tesla.Mock)
2022 :ok = File.rm("config/test.exported_from_db.secret.exs")
2026 clear_config(:configurable_from_database) do
2027 Pleroma.Config.put(:configurable_from_database, true)
2030 @tag capture_log: true
2031 test "create new config setting in db", %{conn: conn} do
2033 post(conn, "/api/pleroma/admin/config", %{
2035 %{group: ":pleroma", key: ":key1", value: "value1"},
2037 group: ":ueberauth",
2039 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
2045 ":nested_1" => "nested_value1",
2047 %{":nested_22" => "nested_value222"},
2048 %{":nested_33" => %{":nested_44" => "nested_444"}}
2056 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2057 %{"nested_4" => true}
2063 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2068 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2073 assert json_response(conn, 200) == %{
2076 "group" => ":pleroma",
2078 "value" => "value1",
2082 "group" => ":ueberauth",
2083 "key" => "Ueberauth",
2084 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
2085 "db" => [":consumer_secret"]
2088 "group" => ":pleroma",
2091 ":nested_1" => "nested_value1",
2093 %{":nested_22" => "nested_value222"},
2094 %{":nested_33" => %{":nested_44" => "nested_444"}}
2100 "group" => ":pleroma",
2103 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2104 %{"nested_4" => true}
2109 "group" => ":pleroma",
2111 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2117 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
2123 assert Application.get_env(:pleroma, :key1) == "value1"
2125 assert Application.get_env(:pleroma, :key2) == %{
2126 nested_1: "nested_value1",
2128 %{nested_22: "nested_value222"},
2129 %{nested_33: %{nested_44: "nested_444"}}
2133 assert Application.get_env(:pleroma, :key3) == [
2134 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2135 %{"nested_4" => true}
2138 assert Application.get_env(:pleroma, :key4) == %{
2139 "endpoint" => "https://example.com",
2143 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2146 test "save config setting without key", %{conn: conn} do
2147 level = Application.get_env(:quack, :level)
2148 meta = Application.get_env(:quack, :meta)
2149 webhook_url = Application.get_env(:quack, :webhook_url)
2152 Application.put_env(:quack, :level, level)
2153 Application.put_env(:quack, :meta, meta)
2154 Application.put_env(:quack, :webhook_url, webhook_url)
2158 post(conn, "/api/pleroma/admin/config", %{
2172 key: ":webhook_url",
2173 value: "https://hooks.slack.com/services/KEY"
2178 assert json_response(conn, 200) == %{
2181 "group" => ":quack",
2187 "group" => ":quack",
2189 "value" => [":none"],
2193 "group" => ":quack",
2194 "key" => ":webhook_url",
2195 "value" => "https://hooks.slack.com/services/KEY",
2196 "db" => [":webhook_url"]
2201 assert Application.get_env(:quack, :level) == :info
2202 assert Application.get_env(:quack, :meta) == [:none]
2203 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2206 test "saving config with partial update", %{conn: conn} do
2207 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2210 post(conn, "/api/pleroma/admin/config", %{
2212 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2216 assert json_response(conn, 200) == %{
2219 "group" => ":pleroma",
2222 %{"tuple" => [":key1", 1]},
2223 %{"tuple" => [":key2", 2]},
2224 %{"tuple" => [":key3", 3]}
2226 "db" => [":key1", ":key2", ":key3"]
2232 test "saving config with nested merge", %{conn: conn} do
2234 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2237 post(conn, "/api/pleroma/admin/config", %{
2240 group: config.group,
2243 %{"tuple" => [":key3", 3]},
2248 %{"tuple" => [":k2", 1]},
2249 %{"tuple" => [":k3", 3]}
2258 assert json_response(conn, 200) == %{
2261 "group" => ":pleroma",
2264 %{"tuple" => [":key1", 1]},
2265 %{"tuple" => [":key3", 3]},
2270 %{"tuple" => [":k1", 1]},
2271 %{"tuple" => [":k2", 1]},
2272 %{"tuple" => [":k3", 3]}
2277 "db" => [":key1", ":key3", ":key2"]
2283 test "saving special atoms", %{conn: conn} do
2285 post(conn, "/api/pleroma/admin/config", %{
2288 "group" => ":pleroma",
2294 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2302 assert json_response(conn, 200) == %{
2305 "group" => ":pleroma",
2311 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2315 "db" => [":ssl_options"]
2320 assert Application.get_env(:pleroma, :key1) == [
2321 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2325 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2326 backends = Application.get_env(:logger, :backends)
2327 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2333 value: :erlang.term_to_binary([])
2337 post(conn, "/api/pleroma/admin/config", %{
2340 group: config.group,
2342 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2347 assert json_response(conn, 200) == %{
2350 "group" => ":logger",
2351 "key" => ":backends",
2354 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2356 "db" => [":backends"]
2361 assert Application.get_env(:logger, :backends) == [
2363 {ExSyslogger, :ex_syslogger}
2366 ExUnit.CaptureLog.capture_log(fn ->
2368 Logger.warn("Ooops...")
2372 test "saving full setting if value is not keyword", %{conn: conn} do
2377 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2381 post(conn, "/api/pleroma/admin/config", %{
2383 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2387 assert json_response(conn, 200) == %{
2390 "group" => ":tesla",
2391 "key" => ":adapter",
2392 "value" => "Tesla.Adapter.Httpc",
2393 "db" => [":adapter"]
2399 test "update config setting & delete", %{conn: conn} do
2400 config1 = insert(:config, key: ":keyaa1")
2401 config2 = insert(:config, key: ":keyaa2")
2405 key: "Ueberauth.Strategy.Microsoft.OAuth"
2409 post(conn, "/api/pleroma/admin/config", %{
2411 %{group: config1.group, key: config1.key, value: "another_value"},
2412 %{group: config2.group, key: config2.key, delete: true},
2415 key: "Ueberauth.Strategy.Microsoft.OAuth",
2421 assert json_response(conn, 200) == %{
2424 "group" => ":pleroma",
2425 "key" => config1.key,
2426 "value" => "another_value",
2432 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2433 refute Application.get_env(:pleroma, :keyaa2)
2436 test "common config example", %{conn: conn} do
2437 adapter = Application.get_env(:tesla, :adapter)
2438 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2441 post(conn, "/api/pleroma/admin/config", %{
2444 "group" => ":pleroma",
2445 "key" => "Pleroma.Captcha.NotReal",
2447 %{"tuple" => [":enabled", false]},
2448 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2449 %{"tuple" => [":seconds_valid", 60]},
2450 %{"tuple" => [":path", ""]},
2451 %{"tuple" => [":key1", nil]},
2452 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2453 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2454 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2455 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2456 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2457 %{"tuple" => [":name", "Pleroma"]}
2461 "group" => ":tesla",
2462 "key" => ":adapter",
2463 "value" => "Tesla.Adapter.Httpc"
2468 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2469 assert Pleroma.Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2471 assert json_response(conn, 200) == %{
2474 "group" => ":pleroma",
2475 "key" => "Pleroma.Captcha.NotReal",
2477 %{"tuple" => [":enabled", false]},
2478 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2479 %{"tuple" => [":seconds_valid", 60]},
2480 %{"tuple" => [":path", ""]},
2481 %{"tuple" => [":key1", nil]},
2482 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2483 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2484 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2485 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2486 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2487 %{"tuple" => [":name", "Pleroma"]}
2504 "group" => ":tesla",
2505 "key" => ":adapter",
2506 "value" => "Tesla.Adapter.Httpc",
2507 "db" => [":adapter"]
2513 test "tuples with more than two values", %{conn: conn} do
2515 post(conn, "/api/pleroma/admin/config", %{
2518 "group" => ":pleroma",
2519 "key" => "Pleroma.Web.Endpoint.NotReal",
2535 "/api/v1/streaming",
2536 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2543 "Phoenix.Endpoint.CowboyWebSocket",
2546 "Phoenix.Transports.WebSocket",
2549 "Pleroma.Web.Endpoint",
2550 "Pleroma.Web.UserSocket",
2561 "Phoenix.Endpoint.Cowboy2Handler",
2562 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2579 assert json_response(conn, 200) == %{
2582 "group" => ":pleroma",
2583 "key" => "Pleroma.Web.Endpoint.NotReal",
2599 "/api/v1/streaming",
2600 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2607 "Phoenix.Endpoint.CowboyWebSocket",
2610 "Phoenix.Transports.WebSocket",
2613 "Pleroma.Web.Endpoint",
2614 "Pleroma.Web.UserSocket",
2625 "Phoenix.Endpoint.Cowboy2Handler",
2626 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2645 test "settings with nesting map", %{conn: conn} do
2647 post(conn, "/api/pleroma/admin/config", %{
2650 "group" => ":pleroma",
2653 %{"tuple" => [":key2", "some_val"]},
2658 ":max_options" => 20,
2659 ":max_option_chars" => 200,
2660 ":min_expiration" => 0,
2661 ":max_expiration" => 31_536_000,
2663 ":max_options" => 20,
2664 ":max_option_chars" => 200,
2665 ":min_expiration" => 0,
2666 ":max_expiration" => 31_536_000
2676 assert json_response(conn, 200) ==
2680 "group" => ":pleroma",
2683 %{"tuple" => [":key2", "some_val"]},
2688 ":max_expiration" => 31_536_000,
2689 ":max_option_chars" => 200,
2690 ":max_options" => 20,
2691 ":min_expiration" => 0,
2693 ":max_expiration" => 31_536_000,
2694 ":max_option_chars" => 200,
2695 ":max_options" => 20,
2696 ":min_expiration" => 0
2702 "db" => [":key2", ":key3"]
2708 test "value as map", %{conn: conn} do
2710 post(conn, "/api/pleroma/admin/config", %{
2713 "group" => ":pleroma",
2715 "value" => %{"key" => "some_val"}
2720 assert json_response(conn, 200) ==
2724 "group" => ":pleroma",
2726 "value" => %{"key" => "some_val"},
2733 test "queues key as atom", %{conn: conn} do
2735 post(conn, "/api/pleroma/admin/config", %{
2741 %{"tuple" => [":federator_incoming", 50]},
2742 %{"tuple" => [":federator_outgoing", 50]},
2743 %{"tuple" => [":web_push", 50]},
2744 %{"tuple" => [":mailer", 10]},
2745 %{"tuple" => [":transmogrifier", 20]},
2746 %{"tuple" => [":scheduled_activities", 10]},
2747 %{"tuple" => [":background", 5]}
2753 assert json_response(conn, 200) == %{
2759 %{"tuple" => [":federator_incoming", 50]},
2760 %{"tuple" => [":federator_outgoing", 50]},
2761 %{"tuple" => [":web_push", 50]},
2762 %{"tuple" => [":mailer", 10]},
2763 %{"tuple" => [":transmogrifier", 20]},
2764 %{"tuple" => [":scheduled_activities", 10]},
2765 %{"tuple" => [":background", 5]}
2768 ":federator_incoming",
2769 ":federator_outgoing",
2773 ":scheduled_activities",
2781 test "delete part of settings by atom subkeys", %{conn: conn} do
2785 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2789 post(conn, "/api/pleroma/admin/config", %{
2792 group: config.group,
2794 subkeys: [":subkey1", ":subkey3"],
2800 assert json_response(conn, 200) == %{
2803 "group" => ":pleroma",
2805 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2806 "db" => [":subkey2"]
2812 test "proxy tuple localhost", %{conn: conn} do
2814 post(conn, "/api/pleroma/admin/config", %{
2820 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2821 %{"tuple" => [":send_user_agent", false]}
2827 assert json_response(conn, 200) == %{
2830 "group" => ":pleroma",
2833 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2834 %{"tuple" => [":send_user_agent", false]}
2836 "db" => [":proxy_url", ":send_user_agent"]
2842 test "proxy tuple domain", %{conn: conn} do
2844 post(conn, "/api/pleroma/admin/config", %{
2850 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2851 %{"tuple" => [":send_user_agent", false]}
2857 assert json_response(conn, 200) == %{
2860 "group" => ":pleroma",
2863 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2864 %{"tuple" => [":send_user_agent", false]}
2866 "db" => [":proxy_url", ":send_user_agent"]
2872 test "proxy tuple ip", %{conn: conn} do
2874 post(conn, "/api/pleroma/admin/config", %{
2880 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2881 %{"tuple" => [":send_user_agent", false]}
2887 assert json_response(conn, 200) == %{
2890 "group" => ":pleroma",
2893 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2894 %{"tuple" => [":send_user_agent", false]}
2896 "db" => [":proxy_url", ":send_user_agent"]
2903 describe "config mix tasks run" do
2905 Mix.shell(Mix.Shell.Quiet)
2908 Mix.shell(Mix.Shell.IO)
2914 clear_config(:configurable_from_database) do
2915 Pleroma.Config.put(:configurable_from_database, true)
2918 clear_config([:feed, :post_title]) do
2919 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
2922 test "transfer settings to DB and to file", %{conn: conn} do
2923 assert Repo.all(Pleroma.ConfigDB) == []
2924 Mix.Tasks.Pleroma.Config.migrate_to_db("test/fixtures/config/temp.secret.exs")
2925 assert Repo.aggregate(Pleroma.ConfigDB, :count, :id) > 0
2927 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
2929 assert json_response(conn, 200) == %{}
2930 assert Repo.all(Pleroma.ConfigDB) == []
2933 test "returns error if configuration from database is off", %{conn: conn} do
2934 initial = Pleroma.Config.get(:configurable_from_database)
2935 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
2936 Pleroma.Config.put(:configurable_from_database, false)
2938 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
2940 assert json_response(conn, 400) ==
2941 "To use this endpoint you need to enable configuration from database."
2943 assert Repo.all(Pleroma.ConfigDB) == []
2947 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2949 user = insert(:user)
2951 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2952 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2953 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2955 insert(:note_activity, user: user, published: date1)
2956 insert(:note_activity, user: user, published: date2)
2957 insert(:note_activity, user: user, published: date3)
2962 test "renders user's statuses", %{conn: conn, user: user} do
2963 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2965 assert json_response(conn, 200) |> length() == 3
2968 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2969 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2971 assert json_response(conn, 200) |> length() == 2
2974 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2975 {:ok, _private_status} =
2976 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2978 {:ok, _public_status} =
2979 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2981 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2983 assert json_response(conn, 200) |> length() == 4
2986 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2987 {:ok, _private_status} =
2988 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2990 {:ok, _public_status} =
2991 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2993 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2995 assert json_response(conn, 200) |> length() == 5
2999 describe "GET /api/pleroma/admin/moderation_log" do
3001 moderator = insert(:user, is_moderator: true)
3003 %{moderator: moderator}
3006 test "returns the log", %{conn: conn, admin: admin} do
3007 Repo.insert(%ModerationLog{
3011 "nickname" => admin.nickname,
3014 action: "relay_follow",
3015 target: "https://example.org/relay"
3017 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3020 Repo.insert(%ModerationLog{
3024 "nickname" => admin.nickname,
3027 action: "relay_unfollow",
3028 target: "https://example.org/relay"
3030 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3033 conn = get(conn, "/api/pleroma/admin/moderation_log")
3035 response = json_response(conn, 200)
3036 [first_entry, second_entry] = response["items"]
3038 assert response["total"] == 2
3039 assert first_entry["data"]["action"] == "relay_unfollow"
3041 assert first_entry["message"] ==
3042 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3044 assert second_entry["data"]["action"] == "relay_follow"
3046 assert second_entry["message"] ==
3047 "@#{admin.nickname} followed relay: https://example.org/relay"
3050 test "returns the log with pagination", %{conn: conn, admin: admin} do
3051 Repo.insert(%ModerationLog{
3055 "nickname" => admin.nickname,
3058 action: "relay_follow",
3059 target: "https://example.org/relay"
3061 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3064 Repo.insert(%ModerationLog{
3068 "nickname" => admin.nickname,
3071 action: "relay_unfollow",
3072 target: "https://example.org/relay"
3074 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3077 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3079 response1 = json_response(conn1, 200)
3080 [first_entry] = response1["items"]
3082 assert response1["total"] == 2
3083 assert response1["items"] |> length() == 1
3084 assert first_entry["data"]["action"] == "relay_unfollow"
3086 assert first_entry["message"] ==
3087 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3089 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3091 response2 = json_response(conn2, 200)
3092 [second_entry] = response2["items"]
3094 assert response2["total"] == 2
3095 assert response2["items"] |> length() == 1
3096 assert second_entry["data"]["action"] == "relay_follow"
3098 assert second_entry["message"] ==
3099 "@#{admin.nickname} followed relay: https://example.org/relay"
3102 test "filters log by date", %{conn: conn, admin: admin} do
3103 first_date = "2017-08-15T15:47:06Z"
3104 second_date = "2017-08-20T15:47:06Z"
3106 Repo.insert(%ModerationLog{
3110 "nickname" => admin.nickname,
3113 action: "relay_follow",
3114 target: "https://example.org/relay"
3116 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3119 Repo.insert(%ModerationLog{
3123 "nickname" => admin.nickname,
3126 action: "relay_unfollow",
3127 target: "https://example.org/relay"
3129 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3135 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3138 response1 = json_response(conn1, 200)
3139 [first_entry] = response1["items"]
3141 assert response1["total"] == 1
3142 assert first_entry["data"]["action"] == "relay_unfollow"
3144 assert first_entry["message"] ==
3145 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3148 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3149 Repo.insert(%ModerationLog{
3153 "nickname" => admin.nickname,
3156 action: "relay_follow",
3157 target: "https://example.org/relay"
3161 Repo.insert(%ModerationLog{
3164 "id" => moderator.id,
3165 "nickname" => moderator.nickname,
3168 action: "relay_unfollow",
3169 target: "https://example.org/relay"
3173 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3175 response1 = json_response(conn1, 200)
3176 [first_entry] = response1["items"]
3178 assert response1["total"] == 1
3179 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3182 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3183 ModerationLog.insert_log(%{
3185 action: "relay_follow",
3186 target: "https://example.org/relay"
3189 ModerationLog.insert_log(%{
3191 action: "relay_unfollow",
3192 target: "https://example.org/relay"
3195 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3197 response1 = json_response(conn1, 200)
3198 [first_entry] = response1["items"]
3200 assert response1["total"] == 1
3202 assert get_in(first_entry, ["data", "message"]) ==
3203 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3207 describe "PATCH /users/:nickname/force_password_reset" do
3208 test "sets password_reset_pending to true", %{conn: conn} do
3209 user = insert(:user)
3210 assert user.password_reset_pending == false
3213 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3215 assert json_response(conn, 204) == ""
3217 ObanHelpers.perform_all()
3219 assert User.get_by_id(user.id).password_reset_pending == true
3223 describe "relays" do
3224 test "POST /relay", %{conn: conn, admin: admin} do
3226 post(conn, "/api/pleroma/admin/relay", %{
3227 relay_url: "http://mastodon.example.org/users/admin"
3230 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3232 log_entry = Repo.one(ModerationLog)
3234 assert ModerationLog.get_log_entry_message(log_entry) ==
3235 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3238 test "GET /relay", %{conn: conn} do
3239 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3241 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3242 |> Enum.each(fn ap_id ->
3243 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3244 User.follow(relay_user, user)
3247 conn = get(conn, "/api/pleroma/admin/relay")
3249 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3252 test "DELETE /relay", %{conn: conn, admin: admin} do
3253 post(conn, "/api/pleroma/admin/relay", %{
3254 relay_url: "http://mastodon.example.org/users/admin"
3258 delete(conn, "/api/pleroma/admin/relay", %{
3259 relay_url: "http://mastodon.example.org/users/admin"
3262 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3264 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3266 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3267 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3269 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3270 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3274 describe "instances" do
3275 test "GET /instances/:instance/statuses", %{conn: conn} do
3276 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3277 user2 = insert(:user, local: false, nickname: "test@test.com")
3278 insert_pair(:note_activity, user: user)
3279 insert(:note_activity, user: user2)
3281 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3283 response = json_response(ret_conn, 200)
3285 assert length(response) == 2
3287 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3289 response = json_response(ret_conn, 200)
3291 assert length(response) == 1
3293 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3295 response = json_response(ret_conn, 200)
3297 assert length(response) == 0
3301 describe "PATCH /confirm_email" do
3302 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3303 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3305 assert first_user.confirmation_pending == true
3306 assert second_user.confirmation_pending == true
3309 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3311 first_user.nickname,
3312 second_user.nickname
3316 assert ret_conn.status == 200
3318 assert first_user.confirmation_pending == true
3319 assert second_user.confirmation_pending == true
3321 log_entry = Repo.one(ModerationLog)
3323 assert ModerationLog.get_log_entry_message(log_entry) ==
3324 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3325 second_user.nickname
3330 describe "PATCH /resend_confirmation_email" do
3331 test "it resend emails for two users", %{conn: conn, admin: admin} do
3332 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3335 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3337 first_user.nickname,
3338 second_user.nickname
3342 assert ret_conn.status == 200
3344 log_entry = Repo.one(ModerationLog)
3346 assert ModerationLog.get_log_entry_message(log_entry) ==
3347 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3348 second_user.nickname
3353 describe "POST /reports/:id/notes" do
3354 setup %{conn: conn, admin: admin} do
3355 [reporter, target_user] = insert_pair(:user)
3356 activity = insert(:note_activity, user: target_user)
3358 {:ok, %{id: report_id}} =
3359 CommonAPI.report(reporter, %{
3360 "account_id" => target_user.id,
3361 "comment" => "I feel offended",
3362 "status_ids" => [activity.id]
3365 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3366 content: "this is disgusting!"
3369 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3370 content: "this is disgusting2!"
3375 report_id: report_id
3379 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3380 [note, _] = Repo.all(ReportNote)
3383 activity_id: ^report_id,
3384 content: "this is disgusting!",
3389 test "it returns reports with notes", %{conn: conn, admin: admin} do
3390 conn = get(conn, "/api/pleroma/admin/reports")
3392 response = json_response(conn, 200)
3393 notes = hd(response["reports"])["notes"]
3396 assert note["user"]["nickname"] == admin.nickname
3397 assert note["content"] == "this is disgusting!"
3398 assert note["created_at"]
3399 assert response["total"] == 1
3402 test "it deletes the note", %{conn: conn, report_id: report_id} do
3403 assert ReportNote |> Repo.all() |> length() == 2
3405 [note, _] = Repo.all(ReportNote)
3407 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3409 assert ReportNote |> Repo.all() |> length() == 1
3413 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3414 admin = insert(:user, is_admin: true)
3417 assign(conn, :user, admin)
3418 |> get("/api/pleroma/admin/config/descriptions")
3420 assert [child | _others] = json_response(conn, 200)
3422 assert child["children"]
3424 assert String.starts_with?(child["group"], ":")
3425 assert child["description"]
3429 # Needed for testing
3430 defmodule Pleroma.Web.Endpoint.NotReal do
3433 defmodule Pleroma.Captcha.NotReal do