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
11 alias Pleroma.ModerationLog
13 alias Pleroma.ReportNote
14 alias Pleroma.Tests.ObanHelpers
16 alias Pleroma.UserInviteToken
17 alias Pleroma.Web.ActivityPub.Relay
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.MastodonAPI.StatusView
20 alias Pleroma.Web.MediaProxy
21 import Pleroma.Factory
24 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
30 admin = insert(:user, is_admin: true)
31 token = insert(:oauth_admin_token, user: admin)
35 |> assign(:user, admin)
36 |> assign(:token, token)
38 {:ok, %{admin: admin, token: token, conn: conn}}
41 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
42 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
43 Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], true)
46 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
49 url = "/api/pleroma/admin/users/#{user.nickname}"
51 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
52 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
53 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
55 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
56 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
59 for good_token <- [good_token1, good_token2, good_token3] do
62 |> assign(:user, admin)
63 |> assign(:token, good_token)
66 assert json_response(conn, 200)
69 for good_token <- [good_token1, good_token2, good_token3] do
73 |> assign(:token, good_token)
76 assert json_response(conn, :forbidden)
79 for bad_token <- [bad_token1, bad_token2, bad_token3] do
82 |> assign(:user, admin)
83 |> assign(:token, bad_token)
86 assert json_response(conn, :forbidden)
91 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
92 clear_config([:auth, :enforce_oauth_admin_scope_usage]) do
93 Pleroma.Config.put([:auth, :enforce_oauth_admin_scope_usage], false)
96 test "GET /api/pleroma/admin/users/:nickname requires " <>
97 "read:accounts or admin:read:accounts or broader scope",
100 url = "/api/pleroma/admin/users/#{user.nickname}"
102 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
103 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
104 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
105 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
106 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
108 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
110 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
111 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
114 for good_token <- good_tokens do
117 |> assign(:user, admin)
118 |> assign(:token, good_token)
121 assert json_response(conn, 200)
124 for good_token <- good_tokens do
127 |> assign(:user, nil)
128 |> assign(:token, good_token)
131 assert json_response(conn, :forbidden)
134 for bad_token <- [bad_token1, bad_token2, bad_token3] do
137 |> assign(:user, admin)
138 |> assign(:token, bad_token)
141 assert json_response(conn, :forbidden)
146 describe "DELETE /api/pleroma/admin/users" do
147 test "single user", %{admin: admin, conn: conn} do
152 |> put_req_header("accept", "application/json")
153 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
155 log_entry = Repo.one(ModerationLog)
157 assert ModerationLog.get_log_entry_message(log_entry) ==
158 "@#{admin.nickname} deleted users: @#{user.nickname}"
160 assert json_response(conn, 200) == user.nickname
163 test "multiple users", %{admin: admin, conn: conn} do
164 user_one = insert(:user)
165 user_two = insert(:user)
169 |> put_req_header("accept", "application/json")
170 |> delete("/api/pleroma/admin/users", %{
171 nicknames: [user_one.nickname, user_two.nickname]
174 log_entry = Repo.one(ModerationLog)
176 assert ModerationLog.get_log_entry_message(log_entry) ==
177 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
179 response = json_response(conn, 200)
180 assert response -- [user_one.nickname, user_two.nickname] == []
184 describe "/api/pleroma/admin/users" do
185 test "Create", %{conn: conn} do
188 |> put_req_header("accept", "application/json")
189 |> post("/api/pleroma/admin/users", %{
192 "nickname" => "lain",
193 "email" => "lain@example.org",
197 "nickname" => "lain2",
198 "email" => "lain2@example.org",
204 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
205 assert response == ["success", "success"]
207 log_entry = Repo.one(ModerationLog)
209 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
212 test "Cannot create user with existing email", %{conn: conn} do
217 |> put_req_header("accept", "application/json")
218 |> post("/api/pleroma/admin/users", %{
221 "nickname" => "lain",
222 "email" => user.email,
228 assert json_response(conn, 409) == [
232 "email" => user.email,
235 "error" => "email has already been taken",
241 test "Cannot create user with existing nickname", %{conn: conn} do
246 |> put_req_header("accept", "application/json")
247 |> post("/api/pleroma/admin/users", %{
250 "nickname" => user.nickname,
251 "email" => "someuser@plerama.social",
257 assert json_response(conn, 409) == [
261 "email" => "someuser@plerama.social",
262 "nickname" => user.nickname
264 "error" => "nickname has already been taken",
270 test "Multiple user creation works in transaction", %{conn: conn} do
275 |> put_req_header("accept", "application/json")
276 |> post("/api/pleroma/admin/users", %{
279 "nickname" => "newuser",
280 "email" => "newuser@pleroma.social",
284 "nickname" => "lain",
285 "email" => user.email,
291 assert json_response(conn, 409) == [
295 "email" => user.email,
298 "error" => "email has already been taken",
304 "email" => "newuser@pleroma.social",
305 "nickname" => "newuser"
312 assert User.get_by_nickname("newuser") === nil
316 describe "/api/pleroma/admin/users/:nickname" do
317 test "Show", %{conn: conn} do
320 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
323 "deactivated" => false,
324 "id" => to_string(user.id),
326 "nickname" => user.nickname,
327 "roles" => %{"admin" => false, "moderator" => false},
329 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
330 "display_name" => HTML.strip_tags(user.name || user.nickname),
331 "confirmation_pending" => false
334 assert expected == json_response(conn, 200)
337 test "when the user doesn't exist", %{conn: conn} do
340 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
342 assert "Not found" == json_response(conn, 404)
346 describe "/api/pleroma/admin/users/follow" do
347 test "allows to force-follow another user", %{admin: admin, conn: conn} do
349 follower = insert(:user)
352 |> put_req_header("accept", "application/json")
353 |> post("/api/pleroma/admin/users/follow", %{
354 "follower" => follower.nickname,
355 "followed" => user.nickname
358 user = User.get_cached_by_id(user.id)
359 follower = User.get_cached_by_id(follower.id)
361 assert User.following?(follower, user)
363 log_entry = Repo.one(ModerationLog)
365 assert ModerationLog.get_log_entry_message(log_entry) ==
366 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
370 describe "/api/pleroma/admin/users/unfollow" do
371 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
373 follower = insert(:user)
375 User.follow(follower, user)
378 |> put_req_header("accept", "application/json")
379 |> post("/api/pleroma/admin/users/unfollow", %{
380 "follower" => follower.nickname,
381 "followed" => user.nickname
384 user = User.get_cached_by_id(user.id)
385 follower = User.get_cached_by_id(follower.id)
387 refute User.following?(follower, user)
389 log_entry = Repo.one(ModerationLog)
391 assert ModerationLog.get_log_entry_message(log_entry) ==
392 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
396 describe "PUT /api/pleroma/admin/users/tag" do
397 setup %{conn: conn} do
398 user1 = insert(:user, %{tags: ["x"]})
399 user2 = insert(:user, %{tags: ["y"]})
400 user3 = insert(:user, %{tags: ["unchanged"]})
404 |> put_req_header("accept", "application/json")
406 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
407 "#{user2.nickname}&tags[]=foo&tags[]=bar"
410 %{conn: conn, user1: user1, user2: user2, user3: user3}
413 test "it appends specified tags to users with specified nicknames", %{
419 assert json_response(conn, :no_content)
420 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
421 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
423 log_entry = Repo.one(ModerationLog)
426 [user1.nickname, user2.nickname]
427 |> Enum.map(&"@#{&1}")
430 tags = ["foo", "bar"] |> Enum.join(", ")
432 assert ModerationLog.get_log_entry_message(log_entry) ==
433 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
436 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
437 assert json_response(conn, :no_content)
438 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
442 describe "DELETE /api/pleroma/admin/users/tag" do
443 setup %{conn: conn} do
444 user1 = insert(:user, %{tags: ["x"]})
445 user2 = insert(:user, %{tags: ["y", "z"]})
446 user3 = insert(:user, %{tags: ["unchanged"]})
450 |> put_req_header("accept", "application/json")
452 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
453 "#{user2.nickname}&tags[]=x&tags[]=z"
456 %{conn: conn, user1: user1, user2: user2, user3: user3}
459 test "it removes specified tags from users with specified nicknames", %{
465 assert json_response(conn, :no_content)
466 assert User.get_cached_by_id(user1.id).tags == []
467 assert User.get_cached_by_id(user2.id).tags == ["y"]
469 log_entry = Repo.one(ModerationLog)
472 [user1.nickname, user2.nickname]
473 |> Enum.map(&"@#{&1}")
476 tags = ["x", "z"] |> Enum.join(", ")
478 assert ModerationLog.get_log_entry_message(log_entry) ==
479 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
482 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
483 assert json_response(conn, :no_content)
484 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
488 describe "/api/pleroma/admin/users/:nickname/permission_group" do
489 test "GET is giving user_info", %{admin: admin, conn: conn} do
492 |> put_req_header("accept", "application/json")
493 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
495 assert json_response(conn, 200) == %{
497 "is_moderator" => false
501 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
506 |> put_req_header("accept", "application/json")
507 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
509 assert json_response(conn, 200) == %{
513 log_entry = Repo.one(ModerationLog)
515 assert ModerationLog.get_log_entry_message(log_entry) ==
516 "@#{admin.nickname} made @#{user.nickname} admin"
519 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
520 user_one = insert(:user)
521 user_two = insert(:user)
525 |> put_req_header("accept", "application/json")
526 |> post("/api/pleroma/admin/users/permission_group/admin", %{
527 nicknames: [user_one.nickname, user_two.nickname]
530 assert json_response(conn, 200) == %{"is_admin" => true}
532 log_entry = Repo.one(ModerationLog)
534 assert ModerationLog.get_log_entry_message(log_entry) ==
535 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
538 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
539 user = insert(:user, is_admin: true)
543 |> put_req_header("accept", "application/json")
544 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
546 assert json_response(conn, 200) == %{"is_admin" => false}
548 log_entry = Repo.one(ModerationLog)
550 assert ModerationLog.get_log_entry_message(log_entry) ==
551 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
554 test "/:right DELETE, can remove from a permission group (multiple)", %{
558 user_one = insert(:user, is_admin: true)
559 user_two = insert(:user, is_admin: true)
563 |> put_req_header("accept", "application/json")
564 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
565 nicknames: [user_one.nickname, user_two.nickname]
568 assert json_response(conn, 200) == %{"is_admin" => false}
570 log_entry = Repo.one(ModerationLog)
572 assert ModerationLog.get_log_entry_message(log_entry) ==
573 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
579 describe "POST /api/pleroma/admin/email_invite, with valid config" do
580 clear_config([:instance, :registrations_open]) do
581 Pleroma.Config.put([:instance, :registrations_open], false)
584 clear_config([:instance, :invites_enabled]) do
585 Pleroma.Config.put([:instance, :invites_enabled], true)
588 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
589 recipient_email = "foo@bar.com"
590 recipient_name = "J. D."
595 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
598 assert json_response(conn, :no_content)
600 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
602 refute token_record.used
604 notify_email = Pleroma.Config.get([:instance, :notify_email])
605 instance_name = Pleroma.Config.get([:instance, :name])
608 Pleroma.Emails.UserEmail.user_invitation_email(
615 Swoosh.TestAssertions.assert_email_sent(
616 from: {instance_name, notify_email},
617 to: {recipient_name, recipient_email},
618 html_body: email.html_body
622 test "it returns 403 if requested by a non-admin" do
623 non_admin_user = insert(:user)
624 token = insert(:oauth_token, user: non_admin_user)
628 |> assign(:user, non_admin_user)
629 |> assign(:token, token)
630 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
632 assert json_response(conn, :forbidden)
636 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
637 clear_config([:instance, :registrations_open])
638 clear_config([:instance, :invites_enabled])
640 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
641 Pleroma.Config.put([:instance, :registrations_open], false)
642 Pleroma.Config.put([:instance, :invites_enabled], false)
644 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
646 assert json_response(conn, :internal_server_error)
649 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
650 Pleroma.Config.put([:instance, :registrations_open], true)
651 Pleroma.Config.put([:instance, :invites_enabled], true)
653 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
655 assert json_response(conn, :internal_server_error)
659 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
664 |> put_req_header("accept", "application/json")
665 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
667 resp = json_response(conn, 200)
669 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
672 describe "GET /api/pleroma/admin/users" do
673 test "renders users array for the first page", %{conn: conn, admin: admin} do
674 user = insert(:user, local: false, tags: ["foo", "bar"])
675 conn = get(conn, "/api/pleroma/admin/users?page=1")
680 "deactivated" => admin.deactivated,
682 "nickname" => admin.nickname,
683 "roles" => %{"admin" => true, "moderator" => false},
686 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
687 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
688 "confirmation_pending" => false
691 "deactivated" => user.deactivated,
693 "nickname" => user.nickname,
694 "roles" => %{"admin" => false, "moderator" => false},
696 "tags" => ["foo", "bar"],
697 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
698 "display_name" => HTML.strip_tags(user.name || user.nickname),
699 "confirmation_pending" => false
702 |> Enum.sort_by(& &1["nickname"])
704 assert json_response(conn, 200) == %{
711 test "renders empty array for the second page", %{conn: conn} do
714 conn = get(conn, "/api/pleroma/admin/users?page=2")
716 assert json_response(conn, 200) == %{
723 test "regular search", %{conn: conn} do
724 user = insert(:user, nickname: "bob")
726 conn = get(conn, "/api/pleroma/admin/users?query=bo")
728 assert json_response(conn, 200) == %{
733 "deactivated" => user.deactivated,
735 "nickname" => user.nickname,
736 "roles" => %{"admin" => false, "moderator" => false},
739 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
740 "display_name" => HTML.strip_tags(user.name || user.nickname),
741 "confirmation_pending" => false
747 test "search by domain", %{conn: conn} do
748 user = insert(:user, nickname: "nickname@domain.com")
751 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
753 assert json_response(conn, 200) == %{
758 "deactivated" => user.deactivated,
760 "nickname" => user.nickname,
761 "roles" => %{"admin" => false, "moderator" => false},
764 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
765 "display_name" => HTML.strip_tags(user.name || user.nickname),
766 "confirmation_pending" => false
772 test "search by full nickname", %{conn: conn} do
773 user = insert(:user, nickname: "nickname@domain.com")
776 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
778 assert json_response(conn, 200) == %{
783 "deactivated" => user.deactivated,
785 "nickname" => user.nickname,
786 "roles" => %{"admin" => false, "moderator" => false},
789 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
790 "display_name" => HTML.strip_tags(user.name || user.nickname),
791 "confirmation_pending" => false
797 test "search by display name", %{conn: conn} do
798 user = insert(:user, name: "Display name")
801 conn = get(conn, "/api/pleroma/admin/users?name=display")
803 assert json_response(conn, 200) == %{
808 "deactivated" => user.deactivated,
810 "nickname" => user.nickname,
811 "roles" => %{"admin" => false, "moderator" => false},
814 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
815 "display_name" => HTML.strip_tags(user.name || user.nickname),
816 "confirmation_pending" => false
822 test "search by email", %{conn: conn} do
823 user = insert(:user, email: "email@example.com")
826 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
828 assert json_response(conn, 200) == %{
833 "deactivated" => user.deactivated,
835 "nickname" => user.nickname,
836 "roles" => %{"admin" => false, "moderator" => false},
839 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
840 "display_name" => HTML.strip_tags(user.name || user.nickname),
841 "confirmation_pending" => false
847 test "regular search with page size", %{conn: conn} do
848 user = insert(:user, nickname: "aalice")
849 user2 = insert(:user, nickname: "alice")
851 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
853 assert json_response(conn1, 200) == %{
858 "deactivated" => user.deactivated,
860 "nickname" => user.nickname,
861 "roles" => %{"admin" => false, "moderator" => false},
864 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
865 "display_name" => HTML.strip_tags(user.name || user.nickname),
866 "confirmation_pending" => false
871 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
873 assert json_response(conn2, 200) == %{
878 "deactivated" => user2.deactivated,
880 "nickname" => user2.nickname,
881 "roles" => %{"admin" => false, "moderator" => false},
884 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
885 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
886 "confirmation_pending" => false
892 test "only local users" do
893 admin = insert(:user, is_admin: true, nickname: "john")
894 token = insert(:oauth_admin_token, user: admin)
895 user = insert(:user, nickname: "bob")
897 insert(:user, nickname: "bobb", local: false)
901 |> assign(:user, admin)
902 |> assign(:token, token)
903 |> get("/api/pleroma/admin/users?query=bo&filters=local")
905 assert json_response(conn, 200) == %{
910 "deactivated" => user.deactivated,
912 "nickname" => user.nickname,
913 "roles" => %{"admin" => false, "moderator" => false},
916 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
917 "display_name" => HTML.strip_tags(user.name || user.nickname),
918 "confirmation_pending" => false
924 test "only local users with no query", %{conn: conn, admin: old_admin} do
925 admin = insert(:user, is_admin: true, nickname: "john")
926 user = insert(:user, nickname: "bob")
928 insert(:user, nickname: "bobb", local: false)
930 conn = get(conn, "/api/pleroma/admin/users?filters=local")
935 "deactivated" => user.deactivated,
937 "nickname" => user.nickname,
938 "roles" => %{"admin" => false, "moderator" => false},
941 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
942 "display_name" => HTML.strip_tags(user.name || user.nickname),
943 "confirmation_pending" => false
946 "deactivated" => admin.deactivated,
948 "nickname" => admin.nickname,
949 "roles" => %{"admin" => true, "moderator" => false},
952 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
953 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
954 "confirmation_pending" => false
957 "deactivated" => false,
958 "id" => old_admin.id,
960 "nickname" => old_admin.nickname,
961 "roles" => %{"admin" => true, "moderator" => false},
963 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
964 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
965 "confirmation_pending" => false
968 |> Enum.sort_by(& &1["nickname"])
970 assert json_response(conn, 200) == %{
977 test "load only admins", %{conn: conn, admin: admin} do
978 second_admin = insert(:user, is_admin: true)
982 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
987 "deactivated" => false,
989 "nickname" => admin.nickname,
990 "roles" => %{"admin" => true, "moderator" => false},
991 "local" => admin.local,
993 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
994 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
995 "confirmation_pending" => false
998 "deactivated" => false,
999 "id" => second_admin.id,
1000 "nickname" => second_admin.nickname,
1001 "roles" => %{"admin" => true, "moderator" => false},
1002 "local" => second_admin.local,
1004 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1005 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1006 "confirmation_pending" => false
1009 |> Enum.sort_by(& &1["nickname"])
1011 assert json_response(conn, 200) == %{
1018 test "load only moderators", %{conn: conn} do
1019 moderator = insert(:user, is_moderator: true)
1023 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1025 assert json_response(conn, 200) == %{
1030 "deactivated" => false,
1031 "id" => moderator.id,
1032 "nickname" => moderator.nickname,
1033 "roles" => %{"admin" => false, "moderator" => true},
1034 "local" => moderator.local,
1036 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1037 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1038 "confirmation_pending" => false
1044 test "load users with tags list", %{conn: conn} do
1045 user1 = insert(:user, tags: ["first"])
1046 user2 = insert(:user, tags: ["second"])
1050 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1055 "deactivated" => false,
1057 "nickname" => user1.nickname,
1058 "roles" => %{"admin" => false, "moderator" => false},
1059 "local" => user1.local,
1060 "tags" => ["first"],
1061 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1062 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1063 "confirmation_pending" => false
1066 "deactivated" => false,
1068 "nickname" => user2.nickname,
1069 "roles" => %{"admin" => false, "moderator" => false},
1070 "local" => user2.local,
1071 "tags" => ["second"],
1072 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1073 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1074 "confirmation_pending" => false
1077 |> Enum.sort_by(& &1["nickname"])
1079 assert json_response(conn, 200) == %{
1086 test "it works with multiple filters" do
1087 admin = insert(:user, nickname: "john", is_admin: true)
1088 token = insert(:oauth_admin_token, user: admin)
1089 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1091 insert(:user, nickname: "ken", local: true, deactivated: true)
1092 insert(:user, nickname: "bobb", local: false, deactivated: false)
1096 |> assign(:user, admin)
1097 |> assign(:token, token)
1098 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1100 assert json_response(conn, 200) == %{
1105 "deactivated" => user.deactivated,
1107 "nickname" => user.nickname,
1108 "roles" => %{"admin" => false, "moderator" => false},
1109 "local" => user.local,
1111 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1112 "display_name" => HTML.strip_tags(user.name || user.nickname),
1113 "confirmation_pending" => false
1119 test "it omits relay user", %{admin: admin, conn: conn} do
1120 assert %User{} = Relay.get_actor()
1122 conn = get(conn, "/api/pleroma/admin/users")
1124 assert json_response(conn, 200) == %{
1129 "deactivated" => admin.deactivated,
1131 "nickname" => admin.nickname,
1132 "roles" => %{"admin" => true, "moderator" => false},
1135 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1136 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1137 "confirmation_pending" => false
1144 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1145 user_one = insert(:user, deactivated: true)
1146 user_two = insert(:user, deactivated: true)
1151 "/api/pleroma/admin/users/activate",
1152 %{nicknames: [user_one.nickname, user_two.nickname]}
1155 response = json_response(conn, 200)
1156 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1158 log_entry = Repo.one(ModerationLog)
1160 assert ModerationLog.get_log_entry_message(log_entry) ==
1161 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1164 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1165 user_one = insert(:user, deactivated: false)
1166 user_two = insert(:user, deactivated: false)
1171 "/api/pleroma/admin/users/deactivate",
1172 %{nicknames: [user_one.nickname, user_two.nickname]}
1175 response = json_response(conn, 200)
1176 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1178 log_entry = Repo.one(ModerationLog)
1180 assert ModerationLog.get_log_entry_message(log_entry) ==
1181 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1184 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1185 user = insert(:user)
1187 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1189 assert json_response(conn, 200) ==
1191 "deactivated" => !user.deactivated,
1193 "nickname" => user.nickname,
1194 "roles" => %{"admin" => false, "moderator" => false},
1197 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1198 "display_name" => HTML.strip_tags(user.name || user.nickname),
1199 "confirmation_pending" => false
1202 log_entry = Repo.one(ModerationLog)
1204 assert ModerationLog.get_log_entry_message(log_entry) ==
1205 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1208 describe "POST /api/pleroma/admin/users/invite_token" do
1209 test "without options", %{conn: conn} do
1210 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1212 invite_json = json_response(conn, 200)
1213 invite = UserInviteToken.find_by_token!(invite_json["token"])
1215 refute invite.expires_at
1216 refute invite.max_use
1217 assert invite.invite_type == "one_time"
1220 test "with expires_at", %{conn: conn} do
1222 post(conn, "/api/pleroma/admin/users/invite_token", %{
1223 "expires_at" => Date.to_string(Date.utc_today())
1226 invite_json = json_response(conn, 200)
1227 invite = UserInviteToken.find_by_token!(invite_json["token"])
1230 assert invite.expires_at == Date.utc_today()
1231 refute invite.max_use
1232 assert invite.invite_type == "date_limited"
1235 test "with max_use", %{conn: conn} do
1236 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1238 invite_json = json_response(conn, 200)
1239 invite = UserInviteToken.find_by_token!(invite_json["token"])
1241 refute invite.expires_at
1242 assert invite.max_use == 150
1243 assert invite.invite_type == "reusable"
1246 test "with max use and expires_at", %{conn: conn} do
1248 post(conn, "/api/pleroma/admin/users/invite_token", %{
1250 "expires_at" => Date.to_string(Date.utc_today())
1253 invite_json = json_response(conn, 200)
1254 invite = UserInviteToken.find_by_token!(invite_json["token"])
1256 assert invite.expires_at == Date.utc_today()
1257 assert invite.max_use == 150
1258 assert invite.invite_type == "reusable_date_limited"
1262 describe "GET /api/pleroma/admin/users/invites" do
1263 test "no invites", %{conn: conn} do
1264 conn = get(conn, "/api/pleroma/admin/users/invites")
1266 assert json_response(conn, 200) == %{"invites" => []}
1269 test "with invite", %{conn: conn} do
1270 {:ok, invite} = UserInviteToken.create_invite()
1272 conn = get(conn, "/api/pleroma/admin/users/invites")
1274 assert json_response(conn, 200) == %{
1277 "expires_at" => nil,
1279 "invite_type" => "one_time",
1281 "token" => invite.token,
1290 describe "POST /api/pleroma/admin/users/revoke_invite" do
1291 test "with token", %{conn: conn} do
1292 {:ok, invite} = UserInviteToken.create_invite()
1294 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1296 assert json_response(conn, 200) == %{
1297 "expires_at" => nil,
1299 "invite_type" => "one_time",
1301 "token" => invite.token,
1307 test "with invalid token", %{conn: conn} do
1308 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1310 assert json_response(conn, :not_found) == "Not found"
1314 describe "GET /api/pleroma/admin/reports/:id" do
1315 test "returns report by its id", %{conn: conn} do
1316 [reporter, target_user] = insert_pair(:user)
1317 activity = insert(:note_activity, user: target_user)
1319 {:ok, %{id: report_id}} =
1320 CommonAPI.report(reporter, %{
1321 "account_id" => target_user.id,
1322 "comment" => "I feel offended",
1323 "status_ids" => [activity.id]
1328 |> get("/api/pleroma/admin/reports/#{report_id}")
1329 |> json_response(:ok)
1331 assert response["id"] == report_id
1334 test "returns 404 when report id is invalid", %{conn: conn} do
1335 conn = get(conn, "/api/pleroma/admin/reports/test")
1337 assert json_response(conn, :not_found) == "Not found"
1341 describe "PATCH /api/pleroma/admin/reports" do
1343 [reporter, target_user] = insert_pair(:user)
1344 activity = insert(:note_activity, user: target_user)
1346 {:ok, %{id: report_id}} =
1347 CommonAPI.report(reporter, %{
1348 "account_id" => target_user.id,
1349 "comment" => "I feel offended",
1350 "status_ids" => [activity.id]
1353 {:ok, %{id: second_report_id}} =
1354 CommonAPI.report(reporter, %{
1355 "account_id" => target_user.id,
1356 "comment" => "I feel very offended",
1357 "status_ids" => [activity.id]
1362 second_report_id: second_report_id
1366 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1368 |> patch("/api/pleroma/admin/reports", %{
1370 %{"state" => "resolved", "id" => id}
1373 |> json_response(:no_content)
1375 activity = Activity.get_by_id(id)
1376 assert activity.data["state"] == "resolved"
1378 log_entry = Repo.one(ModerationLog)
1380 assert ModerationLog.get_log_entry_message(log_entry) ==
1381 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1384 test "closes report", %{conn: conn, id: id, admin: admin} do
1386 |> patch("/api/pleroma/admin/reports", %{
1388 %{"state" => "closed", "id" => id}
1391 |> json_response(:no_content)
1393 activity = Activity.get_by_id(id)
1394 assert activity.data["state"] == "closed"
1396 log_entry = Repo.one(ModerationLog)
1398 assert ModerationLog.get_log_entry_message(log_entry) ==
1399 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1402 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1405 |> patch("/api/pleroma/admin/reports", %{
1407 %{"state" => "test", "id" => id}
1411 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1414 test "returns 404 when report is not exist", %{conn: conn} do
1417 |> patch("/api/pleroma/admin/reports", %{
1419 %{"state" => "closed", "id" => "test"}
1423 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1426 test "updates state of multiple reports", %{
1430 second_report_id: second_report_id
1433 |> patch("/api/pleroma/admin/reports", %{
1435 %{"state" => "resolved", "id" => id},
1436 %{"state" => "closed", "id" => second_report_id}
1439 |> json_response(:no_content)
1441 activity = Activity.get_by_id(id)
1442 second_activity = Activity.get_by_id(second_report_id)
1443 assert activity.data["state"] == "resolved"
1444 assert second_activity.data["state"] == "closed"
1446 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1448 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1449 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1451 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1452 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1456 describe "GET /api/pleroma/admin/reports" do
1457 test "returns empty response when no reports created", %{conn: conn} do
1460 |> get("/api/pleroma/admin/reports")
1461 |> json_response(:ok)
1463 assert Enum.empty?(response["reports"])
1464 assert response["total"] == 0
1467 test "returns reports", %{conn: conn} do
1468 [reporter, target_user] = insert_pair(:user)
1469 activity = insert(:note_activity, user: target_user)
1471 {:ok, %{id: report_id}} =
1472 CommonAPI.report(reporter, %{
1473 "account_id" => target_user.id,
1474 "comment" => "I feel offended",
1475 "status_ids" => [activity.id]
1480 |> get("/api/pleroma/admin/reports")
1481 |> json_response(:ok)
1483 [report] = response["reports"]
1485 assert length(response["reports"]) == 1
1486 assert report["id"] == report_id
1488 assert response["total"] == 1
1491 test "returns reports with specified state", %{conn: conn} do
1492 [reporter, target_user] = insert_pair(:user)
1493 activity = insert(:note_activity, user: target_user)
1495 {:ok, %{id: first_report_id}} =
1496 CommonAPI.report(reporter, %{
1497 "account_id" => target_user.id,
1498 "comment" => "I feel offended",
1499 "status_ids" => [activity.id]
1502 {:ok, %{id: second_report_id}} =
1503 CommonAPI.report(reporter, %{
1504 "account_id" => target_user.id,
1505 "comment" => "I don't like this user"
1508 CommonAPI.update_report_state(second_report_id, "closed")
1512 |> get("/api/pleroma/admin/reports", %{
1515 |> json_response(:ok)
1517 [open_report] = response["reports"]
1519 assert length(response["reports"]) == 1
1520 assert open_report["id"] == first_report_id
1522 assert response["total"] == 1
1526 |> get("/api/pleroma/admin/reports", %{
1529 |> json_response(:ok)
1531 [closed_report] = response["reports"]
1533 assert length(response["reports"]) == 1
1534 assert closed_report["id"] == second_report_id
1536 assert response["total"] == 1
1540 |> get("/api/pleroma/admin/reports", %{
1541 "state" => "resolved"
1543 |> json_response(:ok)
1545 assert Enum.empty?(response["reports"])
1546 assert response["total"] == 0
1549 test "returns 403 when requested by a non-admin" do
1550 user = insert(:user)
1551 token = insert(:oauth_token, user: user)
1555 |> assign(:user, user)
1556 |> assign(:token, token)
1557 |> get("/api/pleroma/admin/reports")
1559 assert json_response(conn, :forbidden) ==
1560 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1563 test "returns 403 when requested by anonymous" do
1564 conn = get(build_conn(), "/api/pleroma/admin/reports")
1566 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1570 describe "GET /api/pleroma/admin/grouped_reports" do
1572 [reporter, target_user] = insert_pair(:user)
1574 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1575 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1576 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1579 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1582 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1585 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1587 {:ok, first_report} =
1588 CommonAPI.report(reporter, %{
1589 "account_id" => target_user.id,
1590 "status_ids" => [first_status.id, second_status.id, third_status.id]
1593 {:ok, second_report} =
1594 CommonAPI.report(reporter, %{
1595 "account_id" => target_user.id,
1596 "status_ids" => [first_status.id, second_status.id]
1599 {:ok, third_report} =
1600 CommonAPI.report(reporter, %{
1601 "account_id" => target_user.id,
1602 "status_ids" => [first_status.id]
1606 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1607 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1608 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1609 first_report: first_report,
1610 first_status_reports: [first_report, second_report, third_report],
1611 second_status_reports: [first_report, second_report],
1612 third_status_reports: [first_report],
1613 target_user: target_user,
1618 test "returns reports grouped by status", %{
1620 first_status: first_status,
1621 second_status: second_status,
1622 third_status: third_status,
1623 first_status_reports: first_status_reports,
1624 second_status_reports: second_status_reports,
1625 third_status_reports: third_status_reports,
1626 target_user: target_user,
1631 |> get("/api/pleroma/admin/grouped_reports")
1632 |> json_response(:ok)
1634 assert length(response["reports"]) == 3
1636 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1638 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1640 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1642 assert length(first_group["reports"]) == 3
1643 assert length(second_group["reports"]) == 2
1644 assert length(third_group["reports"]) == 1
1646 assert first_group["date"] ==
1647 Enum.max_by(first_status_reports, fn act ->
1648 NaiveDateTime.from_iso8601!(act.data["published"])
1649 end).data["published"]
1651 assert first_group["status"] ==
1653 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1658 assert(first_group["account"]["id"] == target_user.id)
1660 assert length(first_group["actors"]) == 1
1661 assert hd(first_group["actors"])["id"] == reporter.id
1663 assert Enum.map(first_group["reports"], & &1["id"]) --
1664 Enum.map(first_status_reports, & &1.id) == []
1666 assert second_group["date"] ==
1667 Enum.max_by(second_status_reports, fn act ->
1668 NaiveDateTime.from_iso8601!(act.data["published"])
1669 end).data["published"]
1671 assert second_group["status"] ==
1673 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1678 assert second_group["account"]["id"] == target_user.id
1680 assert length(second_group["actors"]) == 1
1681 assert hd(second_group["actors"])["id"] == reporter.id
1683 assert Enum.map(second_group["reports"], & &1["id"]) --
1684 Enum.map(second_status_reports, & &1.id) == []
1686 assert third_group["date"] ==
1687 Enum.max_by(third_status_reports, fn act ->
1688 NaiveDateTime.from_iso8601!(act.data["published"])
1689 end).data["published"]
1691 assert third_group["status"] ==
1693 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1698 assert third_group["account"]["id"] == target_user.id
1700 assert length(third_group["actors"]) == 1
1701 assert hd(third_group["actors"])["id"] == reporter.id
1703 assert Enum.map(third_group["reports"], & &1["id"]) --
1704 Enum.map(third_status_reports, & &1.id) == []
1707 test "reopened report renders status data", %{
1709 first_report: first_report,
1710 first_status: first_status
1712 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1716 |> get("/api/pleroma/admin/grouped_reports")
1717 |> json_response(:ok)
1719 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1721 assert first_group["status"] ==
1723 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1729 test "reopened report does not render status data if status has been deleted", %{
1731 first_report: first_report,
1732 first_status: first_status,
1733 target_user: target_user
1735 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1736 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1738 refute Activity.get_by_ap_id(first_status.id)
1742 |> get("/api/pleroma/admin/grouped_reports")
1743 |> json_response(:ok)
1745 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1749 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1752 test "account not empty if status was deleted", %{
1754 first_report: first_report,
1755 first_status: first_status,
1756 target_user: target_user
1758 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1759 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1761 refute Activity.get_by_ap_id(first_status.id)
1765 |> get("/api/pleroma/admin/grouped_reports")
1766 |> json_response(:ok)
1768 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["account"]
1772 describe "PUT /api/pleroma/admin/statuses/:id" do
1774 activity = insert(:note_activity)
1779 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1782 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1783 |> json_response(:ok)
1785 assert response["sensitive"]
1787 log_entry = Repo.one(ModerationLog)
1789 assert ModerationLog.get_log_entry_message(log_entry) ==
1790 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1794 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1795 |> json_response(:ok)
1797 refute response["sensitive"]
1800 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1803 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1804 |> json_response(:ok)
1806 assert response["visibility"] == "public"
1808 log_entry = Repo.one(ModerationLog)
1810 assert ModerationLog.get_log_entry_message(log_entry) ==
1811 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1815 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1816 |> json_response(:ok)
1818 assert response["visibility"] == "private"
1822 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1823 |> json_response(:ok)
1825 assert response["visibility"] == "unlisted"
1828 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1829 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1831 assert json_response(conn, :bad_request) == "Unsupported visibility"
1835 describe "DELETE /api/pleroma/admin/statuses/:id" do
1837 activity = insert(:note_activity)
1842 test "deletes status", %{conn: conn, id: id, admin: admin} do
1844 |> delete("/api/pleroma/admin/statuses/#{id}")
1845 |> json_response(:ok)
1847 refute Activity.get_by_id(id)
1849 log_entry = Repo.one(ModerationLog)
1851 assert ModerationLog.get_log_entry_message(log_entry) ==
1852 "@#{admin.nickname} deleted status ##{id}"
1855 test "returns error when status is not exist", %{conn: conn} do
1856 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1858 assert json_response(conn, :bad_request) == "Could not delete"
1862 describe "GET /api/pleroma/admin/config" do
1863 clear_config(:configurable_from_database) do
1864 Pleroma.Config.put(:configurable_from_database, true)
1867 test "when configuration from database is off", %{conn: conn} do
1868 initial = Pleroma.Config.get(:configurable_from_database)
1869 Pleroma.Config.put(:configurable_from_database, false)
1870 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
1871 conn = get(conn, "/api/pleroma/admin/config")
1873 assert json_response(conn, 400) ==
1874 "To use this endpoint you need to enable configuration from database."
1877 test "without any settings in db", %{conn: conn} do
1878 conn = get(conn, "/api/pleroma/admin/config")
1880 assert json_response(conn, 400) ==
1881 "To use configuration from database migrate your settings to database."
1884 test "with settings in db", %{conn: conn} do
1885 config1 = insert(:config)
1886 config2 = insert(:config)
1888 conn = get(conn, "/api/pleroma/admin/config")
1893 "group" => ":pleroma",
1902 } = json_response(conn, 200)
1904 assert key1 == config1.key
1905 assert key2 == config2.key
1909 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1910 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1912 assert json_response(conn, 400) ==
1913 "To use this endpoint you need to enable configuration from database."
1916 describe "POST /api/pleroma/admin/config" do
1918 http = Application.get_env(:pleroma, :http)
1921 Application.delete_env(:pleroma, :key1)
1922 Application.delete_env(:pleroma, :key2)
1923 Application.delete_env(:pleroma, :key3)
1924 Application.delete_env(:pleroma, :key4)
1925 Application.delete_env(:pleroma, :keyaa1)
1926 Application.delete_env(:pleroma, :keyaa2)
1927 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1928 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1929 Application.put_env(:pleroma, :http, http)
1930 Application.put_env(:tesla, :adapter, Tesla.Mock)
1931 :ok = File.rm("config/test.exported_from_db.secret.exs")
1935 clear_config(:configurable_from_database) do
1936 Pleroma.Config.put(:configurable_from_database, true)
1939 @tag capture_log: true
1940 test "create new config setting in db", %{conn: conn} do
1942 post(conn, "/api/pleroma/admin/config", %{
1944 %{group: ":pleroma", key: ":key1", value: "value1"},
1946 group: ":ueberauth",
1947 key: "Ueberauth.Strategy.Twitter.OAuth",
1948 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1954 ":nested_1" => "nested_value1",
1956 %{":nested_22" => "nested_value222"},
1957 %{":nested_33" => %{":nested_44" => "nested_444"}}
1965 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1966 %{"nested_4" => true}
1972 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1977 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1982 assert json_response(conn, 200) == %{
1985 "group" => ":pleroma",
1990 "group" => ":ueberauth",
1991 "key" => "Ueberauth.Strategy.Twitter.OAuth",
1992 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}]
1995 "group" => ":pleroma",
1998 ":nested_1" => "nested_value1",
2000 %{":nested_22" => "nested_value222"},
2001 %{":nested_33" => %{":nested_44" => "nested_444"}}
2006 "group" => ":pleroma",
2009 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2010 %{"nested_4" => true}
2014 "group" => ":pleroma",
2016 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
2021 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2026 assert Application.get_env(:pleroma, :key1) == "value1"
2028 assert Application.get_env(:pleroma, :key2) == %{
2029 nested_1: "nested_value1",
2031 %{nested_22: "nested_value222"},
2032 %{nested_33: %{nested_44: "nested_444"}}
2036 assert Application.get_env(:pleroma, :key3) == [
2037 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2038 %{"nested_4" => true}
2041 assert Application.get_env(:pleroma, :key4) == %{
2042 "endpoint" => "https://example.com",
2046 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2049 test "save config setting without key", %{conn: conn} do
2050 level = Application.get_env(:quack, :level)
2051 meta = Application.get_env(:quack, :meta)
2052 webhook_url = Application.get_env(:quack, :webhook_url)
2055 Application.put_env(:quack, :level, level)
2056 Application.put_env(:quack, :meta, meta)
2057 Application.put_env(:quack, :webhook_url, webhook_url)
2061 post(conn, "/api/pleroma/admin/config", %{
2075 key: ":webhook_url",
2076 value: "https://hooks.slack.com/services/KEY"
2081 assert json_response(conn, 200) == %{
2083 %{"group" => ":quack", "key" => ":level", "value" => ":info"},
2084 %{"group" => ":quack", "key" => ":meta", "value" => [":none"]},
2086 "group" => ":quack",
2087 "key" => ":webhook_url",
2088 "value" => "https://hooks.slack.com/services/KEY"
2093 assert Application.get_env(:quack, :level) == :info
2094 assert Application.get_env(:quack, :meta) == [:none]
2095 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2098 test "saving config with partial update", %{conn: conn} do
2099 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2102 post(conn, "/api/pleroma/admin/config", %{
2104 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2108 assert json_response(conn, 200) == %{
2111 "group" => ":pleroma",
2114 %{"tuple" => [":key1", 1]},
2115 %{"tuple" => [":key2", 2]},
2116 %{"tuple" => [":key3", 3]}
2123 test "saving config with nested merge", %{conn: conn} do
2125 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2128 post(conn, "/api/pleroma/admin/config", %{
2131 group: config.group,
2134 %{"tuple" => [":key3", 3]},
2139 %{"tuple" => [":k2", 1]},
2140 %{"tuple" => [":k3", 3]}
2149 assert json_response(conn, 200) == %{
2152 "group" => ":pleroma",
2155 %{"tuple" => [":key1", 1]},
2156 %{"tuple" => [":key3", 3]},
2161 %{"tuple" => [":k1", 1]},
2162 %{"tuple" => [":k2", 1]},
2163 %{"tuple" => [":k3", 3]}
2173 test "saving special atoms", %{conn: conn} do
2175 post(conn, "/api/pleroma/admin/config", %{
2178 "group" => ":pleroma",
2184 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2192 assert json_response(conn, 200) == %{
2195 "group" => ":pleroma",
2201 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2209 assert Application.get_env(:pleroma, :key1) == [
2210 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2214 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2215 backends = Application.get_env(:logger, :backends)
2216 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2222 value: :erlang.term_to_binary([])
2226 post(conn, "/api/pleroma/admin/config", %{
2229 group: config.group,
2231 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2236 assert json_response(conn, 200) == %{
2239 "group" => ":logger",
2240 "key" => ":backends",
2243 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2249 assert Application.get_env(:logger, :backends) == [
2251 {ExSyslogger, :ex_syslogger}
2254 ExUnit.CaptureLog.capture_log(fn ->
2256 Logger.warn("Ooops...")
2260 test "saving full setting if value is not keyword", %{conn: conn} do
2265 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2269 post(conn, "/api/pleroma/admin/config", %{
2271 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2275 assert json_response(conn, 200) == %{
2278 "group" => ":tesla",
2279 "key" => ":adapter",
2280 "value" => "Tesla.Adapter.Httpc"
2286 test "update config setting & delete", %{conn: conn} do
2287 config1 = insert(:config, key: ":keyaa1")
2288 config2 = insert(:config, key: ":keyaa2")
2292 key: "Ueberauth.Strategy.Microsoft.OAuth"
2296 post(conn, "/api/pleroma/admin/config", %{
2298 %{group: config1.group, key: config1.key, value: "another_value"},
2299 %{group: config2.group, key: config2.key, delete: true},
2302 key: "Ueberauth.Strategy.Microsoft.OAuth",
2308 assert json_response(conn, 200) == %{
2311 "group" => ":pleroma",
2312 "key" => config1.key,
2313 "value" => "another_value"
2318 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2319 refute Application.get_env(:pleroma, :keyaa2)
2322 test "common config example", %{conn: conn} do
2323 adapter = Application.get_env(:tesla, :adapter)
2324 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2327 post(conn, "/api/pleroma/admin/config", %{
2330 "group" => ":pleroma",
2331 "key" => "Pleroma.Captcha.NotReal",
2333 %{"tuple" => [":enabled", false]},
2334 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2335 %{"tuple" => [":seconds_valid", 60]},
2336 %{"tuple" => [":path", ""]},
2337 %{"tuple" => [":key1", nil]},
2338 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2339 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2340 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2341 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2342 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2343 %{"tuple" => [":name", "Pleroma"]}
2346 %{"group" => ":tesla", "key" => ":adapter", "value" => "Tesla.Adapter.Httpc"}
2350 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2351 assert Pleroma.Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2353 assert json_response(conn, 200) == %{
2356 "group" => ":pleroma",
2357 "key" => "Pleroma.Captcha.NotReal",
2359 %{"tuple" => [":enabled", false]},
2360 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2361 %{"tuple" => [":seconds_valid", 60]},
2362 %{"tuple" => [":path", ""]},
2363 %{"tuple" => [":key1", nil]},
2364 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2365 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2366 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2367 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2368 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2369 %{"tuple" => [":name", "Pleroma"]}
2372 %{"group" => ":tesla", "key" => ":adapter", "value" => "Tesla.Adapter.Httpc"}
2377 test "tuples with more than two values", %{conn: conn} do
2379 post(conn, "/api/pleroma/admin/config", %{
2382 "group" => ":pleroma",
2383 "key" => "Pleroma.Web.Endpoint.NotReal",
2399 "/api/v1/streaming",
2400 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2407 "Phoenix.Endpoint.CowboyWebSocket",
2410 "Phoenix.Transports.WebSocket",
2413 "Pleroma.Web.Endpoint",
2414 "Pleroma.Web.UserSocket",
2425 "Phoenix.Endpoint.Cowboy2Handler",
2426 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2443 assert json_response(conn, 200) == %{
2446 "group" => ":pleroma",
2447 "key" => "Pleroma.Web.Endpoint.NotReal",
2463 "/api/v1/streaming",
2464 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2471 "Phoenix.Endpoint.CowboyWebSocket",
2474 "Phoenix.Transports.WebSocket",
2477 "Pleroma.Web.Endpoint",
2478 "Pleroma.Web.UserSocket",
2489 "Phoenix.Endpoint.Cowboy2Handler",
2490 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2508 test "settings with nesting map", %{conn: conn} do
2510 post(conn, "/api/pleroma/admin/config", %{
2513 "group" => ":pleroma",
2516 %{"tuple" => [":key2", "some_val"]},
2521 ":max_options" => 20,
2522 ":max_option_chars" => 200,
2523 ":min_expiration" => 0,
2524 ":max_expiration" => 31_536_000,
2526 ":max_options" => 20,
2527 ":max_option_chars" => 200,
2528 ":min_expiration" => 0,
2529 ":max_expiration" => 31_536_000
2539 assert json_response(conn, 200) ==
2543 "group" => ":pleroma",
2546 %{"tuple" => [":key2", "some_val"]},
2551 ":max_expiration" => 31_536_000,
2552 ":max_option_chars" => 200,
2553 ":max_options" => 20,
2554 ":min_expiration" => 0,
2556 ":max_expiration" => 31_536_000,
2557 ":max_option_chars" => 200,
2558 ":max_options" => 20,
2559 ":min_expiration" => 0
2570 test "value as map", %{conn: conn} do
2572 post(conn, "/api/pleroma/admin/config", %{
2575 "group" => ":pleroma",
2577 "value" => %{"key" => "some_val"}
2582 assert json_response(conn, 200) ==
2586 "group" => ":pleroma",
2588 "value" => %{"key" => "some_val"}
2594 test "dispatch setting", %{conn: conn} do
2596 post(conn, "/api/pleroma/admin/config", %{
2599 "group" => ":pleroma",
2600 "key" => "Pleroma.Web.Endpoint.NotReal",
2606 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2607 %{"tuple" => [":dispatch", ["{:_,
2609 {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
2610 {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
2611 {Phoenix.Transports.WebSocket,
2612 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
2613 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
2624 "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
2625 "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
2626 "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
2627 "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
2629 assert json_response(conn, 200) == %{
2632 "group" => ":pleroma",
2633 "key" => "Pleroma.Web.Endpoint.NotReal",
2639 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2657 test "queues key as atom", %{conn: conn} do
2659 post(conn, "/api/pleroma/admin/config", %{
2665 %{"tuple" => [":federator_incoming", 50]},
2666 %{"tuple" => [":federator_outgoing", 50]},
2667 %{"tuple" => [":web_push", 50]},
2668 %{"tuple" => [":mailer", 10]},
2669 %{"tuple" => [":transmogrifier", 20]},
2670 %{"tuple" => [":scheduled_activities", 10]},
2671 %{"tuple" => [":background", 5]}
2677 assert json_response(conn, 200) == %{
2683 %{"tuple" => [":federator_incoming", 50]},
2684 %{"tuple" => [":federator_outgoing", 50]},
2685 %{"tuple" => [":web_push", 50]},
2686 %{"tuple" => [":mailer", 10]},
2687 %{"tuple" => [":transmogrifier", 20]},
2688 %{"tuple" => [":scheduled_activities", 10]},
2689 %{"tuple" => [":background", 5]}
2696 test "delete part of settings by atom subkeys", %{conn: conn} do
2700 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2704 post(conn, "/api/pleroma/admin/config", %{
2707 group: config.group,
2709 subkeys: [":subkey1", ":subkey3"],
2715 assert json_response(conn, 200) == %{
2718 "group" => ":pleroma",
2720 "value" => [%{"tuple" => [":subkey2", "val2"]}]
2726 test "proxy tuple localhost", %{conn: conn} do
2728 post(conn, "/api/pleroma/admin/config", %{
2734 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2735 %{"tuple" => [":send_user_agent", false]}
2741 assert json_response(conn, 200) == %{
2744 "group" => ":pleroma",
2747 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2748 %{"tuple" => [":send_user_agent", false]}
2755 test "proxy tuple domain", %{conn: conn} do
2757 post(conn, "/api/pleroma/admin/config", %{
2763 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2764 %{"tuple" => [":send_user_agent", false]}
2770 assert json_response(conn, 200) == %{
2773 "group" => ":pleroma",
2776 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2777 %{"tuple" => [":send_user_agent", false]}
2784 test "proxy tuple ip", %{conn: conn} do
2786 post(conn, "/api/pleroma/admin/config", %{
2792 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2793 %{"tuple" => [":send_user_agent", false]}
2799 assert json_response(conn, 200) == %{
2802 "group" => ":pleroma",
2805 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2806 %{"tuple" => [":send_user_agent", false]}
2814 describe "config mix tasks run" do
2816 Mix.shell(Mix.Shell.Quiet)
2819 Mix.shell(Mix.Shell.IO)
2825 clear_config(:configurable_from_database) do
2826 Pleroma.Config.put(:configurable_from_database, true)
2829 clear_config([:feed, :post_title]) do
2830 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
2833 test "transfer settings to DB and to file", %{conn: conn} do
2834 on_exit(fn -> :ok = File.rm("config/test.exported_from_db.secret.exs") end)
2835 assert Repo.all(Pleroma.ConfigDB) == []
2836 Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
2837 assert Repo.aggregate(Pleroma.ConfigDB, :count, :id) > 0
2839 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
2841 assert json_response(conn, 200) == %{}
2842 assert Repo.all(Pleroma.ConfigDB) == []
2845 test "returns error if configuration from database is off", %{conn: conn} do
2846 initial = Pleroma.Config.get(:configurable_from_database)
2847 on_exit(fn -> Pleroma.Config.put(:configurable_from_database, initial) end)
2848 Pleroma.Config.put(:configurable_from_database, false)
2850 conn = get(conn, "/api/pleroma/admin/config/migrate_from_db")
2852 assert json_response(conn, 400) ==
2853 "To use this endpoint you need to enable configuration from database."
2855 assert Repo.all(Pleroma.ConfigDB) == []
2859 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2861 user = insert(:user)
2863 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2864 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2865 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2867 insert(:note_activity, user: user, published: date1)
2868 insert(:note_activity, user: user, published: date2)
2869 insert(:note_activity, user: user, published: date3)
2874 test "renders user's statuses", %{conn: conn, user: user} do
2875 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2877 assert json_response(conn, 200) |> length() == 3
2880 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2881 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2883 assert json_response(conn, 200) |> length() == 2
2886 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2887 {:ok, _private_status} =
2888 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2890 {:ok, _public_status} =
2891 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2893 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2895 assert json_response(conn, 200) |> length() == 4
2898 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2899 {:ok, _private_status} =
2900 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2902 {:ok, _public_status} =
2903 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2905 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2907 assert json_response(conn, 200) |> length() == 5
2911 describe "GET /api/pleroma/admin/moderation_log" do
2913 moderator = insert(:user, is_moderator: true)
2915 %{moderator: moderator}
2918 test "returns the log", %{conn: conn, admin: admin} do
2919 Repo.insert(%ModerationLog{
2923 "nickname" => admin.nickname,
2926 action: "relay_follow",
2927 target: "https://example.org/relay"
2929 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2932 Repo.insert(%ModerationLog{
2936 "nickname" => admin.nickname,
2939 action: "relay_unfollow",
2940 target: "https://example.org/relay"
2942 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2945 conn = get(conn, "/api/pleroma/admin/moderation_log")
2947 response = json_response(conn, 200)
2948 [first_entry, second_entry] = response["items"]
2950 assert response["total"] == 2
2951 assert first_entry["data"]["action"] == "relay_unfollow"
2953 assert first_entry["message"] ==
2954 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2956 assert second_entry["data"]["action"] == "relay_follow"
2958 assert second_entry["message"] ==
2959 "@#{admin.nickname} followed relay: https://example.org/relay"
2962 test "returns the log with pagination", %{conn: conn, admin: admin} do
2963 Repo.insert(%ModerationLog{
2967 "nickname" => admin.nickname,
2970 action: "relay_follow",
2971 target: "https://example.org/relay"
2973 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2976 Repo.insert(%ModerationLog{
2980 "nickname" => admin.nickname,
2983 action: "relay_unfollow",
2984 target: "https://example.org/relay"
2986 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2989 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
2991 response1 = json_response(conn1, 200)
2992 [first_entry] = response1["items"]
2994 assert response1["total"] == 2
2995 assert response1["items"] |> length() == 1
2996 assert first_entry["data"]["action"] == "relay_unfollow"
2998 assert first_entry["message"] ==
2999 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3001 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3003 response2 = json_response(conn2, 200)
3004 [second_entry] = response2["items"]
3006 assert response2["total"] == 2
3007 assert response2["items"] |> length() == 1
3008 assert second_entry["data"]["action"] == "relay_follow"
3010 assert second_entry["message"] ==
3011 "@#{admin.nickname} followed relay: https://example.org/relay"
3014 test "filters log by date", %{conn: conn, admin: admin} do
3015 first_date = "2017-08-15T15:47:06Z"
3016 second_date = "2017-08-20T15:47:06Z"
3018 Repo.insert(%ModerationLog{
3022 "nickname" => admin.nickname,
3025 action: "relay_follow",
3026 target: "https://example.org/relay"
3028 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3031 Repo.insert(%ModerationLog{
3035 "nickname" => admin.nickname,
3038 action: "relay_unfollow",
3039 target: "https://example.org/relay"
3041 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3047 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3050 response1 = json_response(conn1, 200)
3051 [first_entry] = response1["items"]
3053 assert response1["total"] == 1
3054 assert first_entry["data"]["action"] == "relay_unfollow"
3056 assert first_entry["message"] ==
3057 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3060 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3061 Repo.insert(%ModerationLog{
3065 "nickname" => admin.nickname,
3068 action: "relay_follow",
3069 target: "https://example.org/relay"
3073 Repo.insert(%ModerationLog{
3076 "id" => moderator.id,
3077 "nickname" => moderator.nickname,
3080 action: "relay_unfollow",
3081 target: "https://example.org/relay"
3085 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3087 response1 = json_response(conn1, 200)
3088 [first_entry] = response1["items"]
3090 assert response1["total"] == 1
3091 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3094 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3095 ModerationLog.insert_log(%{
3097 action: "relay_follow",
3098 target: "https://example.org/relay"
3101 ModerationLog.insert_log(%{
3103 action: "relay_unfollow",
3104 target: "https://example.org/relay"
3107 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3109 response1 = json_response(conn1, 200)
3110 [first_entry] = response1["items"]
3112 assert response1["total"] == 1
3114 assert get_in(first_entry, ["data", "message"]) ==
3115 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3119 describe "PATCH /users/:nickname/force_password_reset" do
3120 test "sets password_reset_pending to true", %{conn: conn} do
3121 user = insert(:user)
3122 assert user.password_reset_pending == false
3125 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3127 assert json_response(conn, 204) == ""
3129 ObanHelpers.perform_all()
3131 assert User.get_by_id(user.id).password_reset_pending == true
3135 describe "relays" do
3136 test "POST /relay", %{conn: conn, admin: admin} do
3138 post(conn, "/api/pleroma/admin/relay", %{
3139 relay_url: "http://mastodon.example.org/users/admin"
3142 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3144 log_entry = Repo.one(ModerationLog)
3146 assert ModerationLog.get_log_entry_message(log_entry) ==
3147 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3150 test "GET /relay", %{conn: conn} do
3151 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3153 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3154 |> Enum.each(fn ap_id ->
3155 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3156 User.follow(relay_user, user)
3159 conn = get(conn, "/api/pleroma/admin/relay")
3161 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3164 test "DELETE /relay", %{conn: conn, admin: admin} do
3165 post(conn, "/api/pleroma/admin/relay", %{
3166 relay_url: "http://mastodon.example.org/users/admin"
3170 delete(conn, "/api/pleroma/admin/relay", %{
3171 relay_url: "http://mastodon.example.org/users/admin"
3174 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3176 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3178 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3179 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3181 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3182 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3186 describe "instances" do
3187 test "GET /instances/:instance/statuses", %{conn: conn} do
3188 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3189 user2 = insert(:user, local: false, nickname: "test@test.com")
3190 insert_pair(:note_activity, user: user)
3191 insert(:note_activity, user: user2)
3193 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3195 response = json_response(ret_conn, 200)
3197 assert length(response) == 2
3199 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3201 response = json_response(ret_conn, 200)
3203 assert length(response) == 1
3205 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3207 response = json_response(ret_conn, 200)
3209 assert length(response) == 0
3213 describe "PATCH /confirm_email" do
3214 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3215 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3217 assert first_user.confirmation_pending == true
3218 assert second_user.confirmation_pending == true
3221 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3223 first_user.nickname,
3224 second_user.nickname
3228 assert ret_conn.status == 200
3230 assert first_user.confirmation_pending == true
3231 assert second_user.confirmation_pending == true
3233 log_entry = Repo.one(ModerationLog)
3235 assert ModerationLog.get_log_entry_message(log_entry) ==
3236 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3237 second_user.nickname
3242 describe "PATCH /resend_confirmation_email" do
3243 test "it resend emails for two users", %{conn: conn, admin: admin} do
3244 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3247 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3249 first_user.nickname,
3250 second_user.nickname
3254 assert ret_conn.status == 200
3256 log_entry = Repo.one(ModerationLog)
3258 assert ModerationLog.get_log_entry_message(log_entry) ==
3259 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3260 second_user.nickname
3265 describe "POST /reports/:id/notes" do
3266 setup %{conn: conn, admin: admin} do
3267 [reporter, target_user] = insert_pair(:user)
3268 activity = insert(:note_activity, user: target_user)
3270 {:ok, %{id: report_id}} =
3271 CommonAPI.report(reporter, %{
3272 "account_id" => target_user.id,
3273 "comment" => "I feel offended",
3274 "status_ids" => [activity.id]
3277 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3278 content: "this is disgusting!"
3281 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3282 content: "this is disgusting2!"
3287 report_id: report_id
3291 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3292 [note, _] = Repo.all(ReportNote)
3295 activity_id: ^report_id,
3296 content: "this is disgusting!",
3301 test "it returns reports with notes", %{conn: conn, admin: admin} do
3302 conn = get(conn, "/api/pleroma/admin/reports")
3304 response = json_response(conn, 200)
3305 notes = hd(response["reports"])["notes"]
3308 assert note["user"]["nickname"] == admin.nickname
3309 assert note["content"] == "this is disgusting!"
3310 assert note["created_at"]
3311 assert response["total"] == 1
3314 test "it deletes the note", %{conn: conn, report_id: report_id} do
3315 assert ReportNote |> Repo.all() |> length() == 2
3317 [note, _] = Repo.all(ReportNote)
3319 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3321 assert ReportNote |> Repo.all() |> length() == 1
3325 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3326 admin = insert(:user, is_admin: true)
3329 assign(conn, :user, admin)
3330 |> get("/api/pleroma/admin/config/descriptions")
3332 assert [child | _others] = json_response(conn, 200)
3334 assert child["children"]
3336 assert String.starts_with?(child["group"], ":")
3337 assert child["description"]
3341 # Needed for testing
3342 defmodule Pleroma.Web.Endpoint.NotReal do
3345 defmodule Pleroma.Captcha.NotReal do