1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
9 import ExUnit.CaptureLog
11 import Pleroma.Factory
13 alias Pleroma.Activity
15 alias Pleroma.ConfigDB
17 alias Pleroma.ModerationLog
19 alias Pleroma.ReportNote
20 alias Pleroma.Tests.ObanHelpers
22 alias Pleroma.UserInviteToken
24 alias Pleroma.Web.ActivityPub.Relay
25 alias Pleroma.Web.CommonAPI
26 alias Pleroma.Web.MediaProxy
29 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
35 admin = insert(:user, is_admin: true)
36 token = insert(:oauth_admin_token, user: admin)
40 |> assign(:user, admin)
41 |> assign(:token, token)
43 {:ok, %{admin: admin, token: token, conn: conn}}
46 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
47 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
49 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
52 url = "/api/pleroma/admin/users/#{user.nickname}"
54 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
55 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
56 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
58 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
59 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
62 for good_token <- [good_token1, good_token2, good_token3] do
65 |> assign(:user, admin)
66 |> assign(:token, good_token)
69 assert json_response(conn, 200)
72 for good_token <- [good_token1, good_token2, good_token3] do
76 |> assign(:token, good_token)
79 assert json_response(conn, :forbidden)
82 for bad_token <- [bad_token1, bad_token2, bad_token3] do
85 |> assign(:user, admin)
86 |> assign(:token, bad_token)
89 assert json_response(conn, :forbidden)
94 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
95 setup do: clear_config([: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
151 with_mock Pleroma.Web.Federator,
152 publish: fn _ -> nil end do
155 |> put_req_header("accept", "application/json")
156 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
158 ObanHelpers.perform_all()
160 assert User.get_by_nickname(user.nickname).deactivated
162 log_entry = Repo.one(ModerationLog)
164 assert ModerationLog.get_log_entry_message(log_entry) ==
165 "@#{admin.nickname} deleted users: @#{user.nickname}"
167 assert json_response(conn, 200) == [user.nickname]
169 assert called(Pleroma.Web.Federator.publish(:_))
173 test "multiple users", %{admin: admin, conn: conn} do
174 user_one = insert(:user)
175 user_two = insert(:user)
179 |> put_req_header("accept", "application/json")
180 |> delete("/api/pleroma/admin/users", %{
181 nicknames: [user_one.nickname, user_two.nickname]
184 log_entry = Repo.one(ModerationLog)
186 assert ModerationLog.get_log_entry_message(log_entry) ==
187 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
189 response = json_response(conn, 200)
190 assert response -- [user_one.nickname, user_two.nickname] == []
194 describe "/api/pleroma/admin/users" do
195 test "Create", %{conn: conn} do
198 |> put_req_header("accept", "application/json")
199 |> post("/api/pleroma/admin/users", %{
202 "nickname" => "lain",
203 "email" => "lain@example.org",
207 "nickname" => "lain2",
208 "email" => "lain2@example.org",
214 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
215 assert response == ["success", "success"]
217 log_entry = Repo.one(ModerationLog)
219 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
222 test "Cannot create user with existing email", %{conn: conn} do
227 |> put_req_header("accept", "application/json")
228 |> post("/api/pleroma/admin/users", %{
231 "nickname" => "lain",
232 "email" => user.email,
238 assert json_response(conn, 409) == [
242 "email" => user.email,
245 "error" => "email has already been taken",
251 test "Cannot create user with existing nickname", %{conn: conn} do
256 |> put_req_header("accept", "application/json")
257 |> post("/api/pleroma/admin/users", %{
260 "nickname" => user.nickname,
261 "email" => "someuser@plerama.social",
267 assert json_response(conn, 409) == [
271 "email" => "someuser@plerama.social",
272 "nickname" => user.nickname
274 "error" => "nickname has already been taken",
280 test "Multiple user creation works in transaction", %{conn: conn} do
285 |> put_req_header("accept", "application/json")
286 |> post("/api/pleroma/admin/users", %{
289 "nickname" => "newuser",
290 "email" => "newuser@pleroma.social",
294 "nickname" => "lain",
295 "email" => user.email,
301 assert json_response(conn, 409) == [
305 "email" => user.email,
308 "error" => "email has already been taken",
314 "email" => "newuser@pleroma.social",
315 "nickname" => "newuser"
322 assert User.get_by_nickname("newuser") === nil
326 describe "/api/pleroma/admin/users/:nickname" do
327 test "Show", %{conn: conn} do
330 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
333 "deactivated" => false,
334 "id" => to_string(user.id),
336 "nickname" => user.nickname,
337 "roles" => %{"admin" => false, "moderator" => false},
339 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
340 "display_name" => HTML.strip_tags(user.name || user.nickname),
341 "confirmation_pending" => false
344 assert expected == json_response(conn, 200)
347 test "when the user doesn't exist", %{conn: conn} do
350 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
352 assert "Not found" == json_response(conn, 404)
356 describe "/api/pleroma/admin/users/follow" do
357 test "allows to force-follow another user", %{admin: admin, conn: conn} do
359 follower = insert(:user)
362 |> put_req_header("accept", "application/json")
363 |> post("/api/pleroma/admin/users/follow", %{
364 "follower" => follower.nickname,
365 "followed" => user.nickname
368 user = User.get_cached_by_id(user.id)
369 follower = User.get_cached_by_id(follower.id)
371 assert User.following?(follower, user)
373 log_entry = Repo.one(ModerationLog)
375 assert ModerationLog.get_log_entry_message(log_entry) ==
376 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
380 describe "/api/pleroma/admin/users/unfollow" do
381 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
383 follower = insert(:user)
385 User.follow(follower, user)
388 |> put_req_header("accept", "application/json")
389 |> post("/api/pleroma/admin/users/unfollow", %{
390 "follower" => follower.nickname,
391 "followed" => user.nickname
394 user = User.get_cached_by_id(user.id)
395 follower = User.get_cached_by_id(follower.id)
397 refute User.following?(follower, user)
399 log_entry = Repo.one(ModerationLog)
401 assert ModerationLog.get_log_entry_message(log_entry) ==
402 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
406 describe "PUT /api/pleroma/admin/users/tag" do
407 setup %{conn: conn} do
408 user1 = insert(:user, %{tags: ["x"]})
409 user2 = insert(:user, %{tags: ["y"]})
410 user3 = insert(:user, %{tags: ["unchanged"]})
414 |> put_req_header("accept", "application/json")
416 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
417 "#{user2.nickname}&tags[]=foo&tags[]=bar"
420 %{conn: conn, user1: user1, user2: user2, user3: user3}
423 test "it appends specified tags to users with specified nicknames", %{
429 assert json_response(conn, :no_content)
430 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
431 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
433 log_entry = Repo.one(ModerationLog)
436 [user1.nickname, user2.nickname]
437 |> Enum.map(&"@#{&1}")
440 tags = ["foo", "bar"] |> Enum.join(", ")
442 assert ModerationLog.get_log_entry_message(log_entry) ==
443 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
446 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
447 assert json_response(conn, :no_content)
448 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
452 describe "DELETE /api/pleroma/admin/users/tag" do
453 setup %{conn: conn} do
454 user1 = insert(:user, %{tags: ["x"]})
455 user2 = insert(:user, %{tags: ["y", "z"]})
456 user3 = insert(:user, %{tags: ["unchanged"]})
460 |> put_req_header("accept", "application/json")
462 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
463 "#{user2.nickname}&tags[]=x&tags[]=z"
466 %{conn: conn, user1: user1, user2: user2, user3: user3}
469 test "it removes specified tags from users with specified nicknames", %{
475 assert json_response(conn, :no_content)
476 assert User.get_cached_by_id(user1.id).tags == []
477 assert User.get_cached_by_id(user2.id).tags == ["y"]
479 log_entry = Repo.one(ModerationLog)
482 [user1.nickname, user2.nickname]
483 |> Enum.map(&"@#{&1}")
486 tags = ["x", "z"] |> Enum.join(", ")
488 assert ModerationLog.get_log_entry_message(log_entry) ==
489 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
492 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
493 assert json_response(conn, :no_content)
494 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
498 describe "/api/pleroma/admin/users/:nickname/permission_group" do
499 test "GET is giving user_info", %{admin: admin, conn: conn} do
502 |> put_req_header("accept", "application/json")
503 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
505 assert json_response(conn, 200) == %{
507 "is_moderator" => false
511 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
516 |> put_req_header("accept", "application/json")
517 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
519 assert json_response(conn, 200) == %{
523 log_entry = Repo.one(ModerationLog)
525 assert ModerationLog.get_log_entry_message(log_entry) ==
526 "@#{admin.nickname} made @#{user.nickname} admin"
529 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
530 user_one = insert(:user)
531 user_two = insert(:user)
535 |> put_req_header("accept", "application/json")
536 |> post("/api/pleroma/admin/users/permission_group/admin", %{
537 nicknames: [user_one.nickname, user_two.nickname]
540 assert json_response(conn, 200) == %{"is_admin" => true}
542 log_entry = Repo.one(ModerationLog)
544 assert ModerationLog.get_log_entry_message(log_entry) ==
545 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
548 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
549 user = insert(:user, is_admin: true)
553 |> put_req_header("accept", "application/json")
554 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
556 assert json_response(conn, 200) == %{"is_admin" => false}
558 log_entry = Repo.one(ModerationLog)
560 assert ModerationLog.get_log_entry_message(log_entry) ==
561 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
564 test "/:right DELETE, can remove from a permission group (multiple)", %{
568 user_one = insert(:user, is_admin: true)
569 user_two = insert(:user, is_admin: true)
573 |> put_req_header("accept", "application/json")
574 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
575 nicknames: [user_one.nickname, user_two.nickname]
578 assert json_response(conn, 200) == %{"is_admin" => false}
580 log_entry = Repo.one(ModerationLog)
582 assert ModerationLog.get_log_entry_message(log_entry) ==
583 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
589 describe "POST /api/pleroma/admin/email_invite, with valid config" do
590 setup do: clear_config([:instance, :registrations_open], false)
591 setup do: clear_config([:instance, :invites_enabled], true)
593 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
594 recipient_email = "foo@bar.com"
595 recipient_name = "J. D."
600 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
603 assert json_response(conn, :no_content)
605 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
607 refute token_record.used
609 notify_email = Config.get([:instance, :notify_email])
610 instance_name = Config.get([:instance, :name])
613 Pleroma.Emails.UserEmail.user_invitation_email(
620 Swoosh.TestAssertions.assert_email_sent(
621 from: {instance_name, notify_email},
622 to: {recipient_name, recipient_email},
623 html_body: email.html_body
627 test "it returns 403 if requested by a non-admin" do
628 non_admin_user = insert(:user)
629 token = insert(:oauth_token, user: non_admin_user)
633 |> assign(:user, non_admin_user)
634 |> assign(:token, token)
635 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
637 assert json_response(conn, :forbidden)
640 test "email with +", %{conn: conn, admin: admin} do
641 recipient_email = "foo+bar@baz.com"
644 |> put_req_header("content-type", "application/json;charset=utf-8")
645 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
646 |> json_response(:no_content)
649 Pleroma.UserInviteToken
654 refute token_record.used
656 notify_email = Config.get([:instance, :notify_email])
657 instance_name = Config.get([:instance, :name])
660 Pleroma.Emails.UserEmail.user_invitation_email(
666 Swoosh.TestAssertions.assert_email_sent(
667 from: {instance_name, notify_email},
669 html_body: email.html_body
674 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
675 setup do: clear_config([:instance, :registrations_open])
676 setup do: clear_config([:instance, :invites_enabled])
678 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
679 Config.put([:instance, :registrations_open], false)
680 Config.put([:instance, :invites_enabled], false)
682 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
684 assert json_response(conn, :bad_request) ==
685 "To send invites you need to set the `invites_enabled` option to true."
688 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
689 Config.put([:instance, :registrations_open], true)
690 Config.put([:instance, :invites_enabled], true)
692 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
694 assert json_response(conn, :bad_request) ==
695 "To send invites you need to set the `registrations_open` option to false."
699 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
704 |> put_req_header("accept", "application/json")
705 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
707 resp = json_response(conn, 200)
709 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
712 describe "GET /api/pleroma/admin/users" do
713 test "renders users array for the first page", %{conn: conn, admin: admin} do
714 user = insert(:user, local: false, tags: ["foo", "bar"])
715 conn = get(conn, "/api/pleroma/admin/users?page=1")
720 "deactivated" => admin.deactivated,
722 "nickname" => admin.nickname,
723 "roles" => %{"admin" => true, "moderator" => false},
726 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
727 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
728 "confirmation_pending" => false
731 "deactivated" => user.deactivated,
733 "nickname" => user.nickname,
734 "roles" => %{"admin" => false, "moderator" => false},
736 "tags" => ["foo", "bar"],
737 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
738 "display_name" => HTML.strip_tags(user.name || user.nickname),
739 "confirmation_pending" => false
742 |> Enum.sort_by(& &1["nickname"])
744 assert json_response(conn, 200) == %{
751 test "pagination works correctly with service users", %{conn: conn} do
752 service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
753 service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
754 insert_list(25, :user)
756 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
758 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
759 |> json_response(200)
761 assert Enum.count(users1) == 10
762 assert service1 not in [users1]
763 assert service2 not in [users1]
765 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
767 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
768 |> json_response(200)
770 assert Enum.count(users2) == 10
771 assert service1 not in [users2]
772 assert service2 not in [users2]
774 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
776 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
777 |> json_response(200)
779 assert Enum.count(users3) == 6
780 assert service1 not in [users3]
781 assert service2 not in [users3]
784 test "renders empty array for the second page", %{conn: conn} do
787 conn = get(conn, "/api/pleroma/admin/users?page=2")
789 assert json_response(conn, 200) == %{
796 test "regular search", %{conn: conn} do
797 user = insert(:user, nickname: "bob")
799 conn = get(conn, "/api/pleroma/admin/users?query=bo")
801 assert json_response(conn, 200) == %{
806 "deactivated" => user.deactivated,
808 "nickname" => user.nickname,
809 "roles" => %{"admin" => false, "moderator" => false},
812 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
813 "display_name" => HTML.strip_tags(user.name || user.nickname),
814 "confirmation_pending" => false
820 test "search by domain", %{conn: conn} do
821 user = insert(:user, nickname: "nickname@domain.com")
824 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
826 assert json_response(conn, 200) == %{
831 "deactivated" => user.deactivated,
833 "nickname" => user.nickname,
834 "roles" => %{"admin" => false, "moderator" => false},
837 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
838 "display_name" => HTML.strip_tags(user.name || user.nickname),
839 "confirmation_pending" => false
845 test "search by full nickname", %{conn: conn} do
846 user = insert(:user, nickname: "nickname@domain.com")
849 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
851 assert json_response(conn, 200) == %{
856 "deactivated" => user.deactivated,
858 "nickname" => user.nickname,
859 "roles" => %{"admin" => false, "moderator" => false},
862 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
863 "display_name" => HTML.strip_tags(user.name || user.nickname),
864 "confirmation_pending" => false
870 test "search by display name", %{conn: conn} do
871 user = insert(:user, name: "Display name")
874 conn = get(conn, "/api/pleroma/admin/users?name=display")
876 assert json_response(conn, 200) == %{
881 "deactivated" => user.deactivated,
883 "nickname" => user.nickname,
884 "roles" => %{"admin" => false, "moderator" => false},
887 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
888 "display_name" => HTML.strip_tags(user.name || user.nickname),
889 "confirmation_pending" => false
895 test "search by email", %{conn: conn} do
896 user = insert(:user, email: "email@example.com")
899 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
901 assert json_response(conn, 200) == %{
906 "deactivated" => user.deactivated,
908 "nickname" => user.nickname,
909 "roles" => %{"admin" => false, "moderator" => false},
912 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
913 "display_name" => HTML.strip_tags(user.name || user.nickname),
914 "confirmation_pending" => false
920 test "regular search with page size", %{conn: conn} do
921 user = insert(:user, nickname: "aalice")
922 user2 = insert(:user, nickname: "alice")
924 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
926 assert json_response(conn1, 200) == %{
931 "deactivated" => user.deactivated,
933 "nickname" => user.nickname,
934 "roles" => %{"admin" => false, "moderator" => false},
937 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
938 "display_name" => HTML.strip_tags(user.name || user.nickname),
939 "confirmation_pending" => false
944 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
946 assert json_response(conn2, 200) == %{
951 "deactivated" => user2.deactivated,
953 "nickname" => user2.nickname,
954 "roles" => %{"admin" => false, "moderator" => false},
957 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
958 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
959 "confirmation_pending" => false
965 test "only local users" do
966 admin = insert(:user, is_admin: true, nickname: "john")
967 token = insert(:oauth_admin_token, user: admin)
968 user = insert(:user, nickname: "bob")
970 insert(:user, nickname: "bobb", local: false)
974 |> assign(:user, admin)
975 |> assign(:token, token)
976 |> get("/api/pleroma/admin/users?query=bo&filters=local")
978 assert json_response(conn, 200) == %{
983 "deactivated" => user.deactivated,
985 "nickname" => user.nickname,
986 "roles" => %{"admin" => false, "moderator" => false},
989 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
990 "display_name" => HTML.strip_tags(user.name || user.nickname),
991 "confirmation_pending" => false
997 test "only local users with no query", %{conn: conn, admin: old_admin} do
998 admin = insert(:user, is_admin: true, nickname: "john")
999 user = insert(:user, nickname: "bob")
1001 insert(:user, nickname: "bobb", local: false)
1003 conn = get(conn, "/api/pleroma/admin/users?filters=local")
1008 "deactivated" => user.deactivated,
1010 "nickname" => user.nickname,
1011 "roles" => %{"admin" => false, "moderator" => false},
1014 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1015 "display_name" => HTML.strip_tags(user.name || user.nickname),
1016 "confirmation_pending" => false
1019 "deactivated" => admin.deactivated,
1021 "nickname" => admin.nickname,
1022 "roles" => %{"admin" => true, "moderator" => false},
1025 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1026 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1027 "confirmation_pending" => false
1030 "deactivated" => false,
1031 "id" => old_admin.id,
1033 "nickname" => old_admin.nickname,
1034 "roles" => %{"admin" => true, "moderator" => false},
1036 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1037 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1038 "confirmation_pending" => false
1041 |> Enum.sort_by(& &1["nickname"])
1043 assert json_response(conn, 200) == %{
1050 test "load only admins", %{conn: conn, admin: admin} do
1051 second_admin = insert(:user, is_admin: true)
1055 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1060 "deactivated" => false,
1062 "nickname" => admin.nickname,
1063 "roles" => %{"admin" => true, "moderator" => false},
1064 "local" => admin.local,
1066 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1067 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1068 "confirmation_pending" => false
1071 "deactivated" => false,
1072 "id" => second_admin.id,
1073 "nickname" => second_admin.nickname,
1074 "roles" => %{"admin" => true, "moderator" => false},
1075 "local" => second_admin.local,
1077 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1078 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1079 "confirmation_pending" => false
1082 |> Enum.sort_by(& &1["nickname"])
1084 assert json_response(conn, 200) == %{
1091 test "load only moderators", %{conn: conn} do
1092 moderator = insert(:user, is_moderator: true)
1096 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1098 assert json_response(conn, 200) == %{
1103 "deactivated" => false,
1104 "id" => moderator.id,
1105 "nickname" => moderator.nickname,
1106 "roles" => %{"admin" => false, "moderator" => true},
1107 "local" => moderator.local,
1109 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1110 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1111 "confirmation_pending" => false
1117 test "load users with tags list", %{conn: conn} do
1118 user1 = insert(:user, tags: ["first"])
1119 user2 = insert(:user, tags: ["second"])
1123 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1128 "deactivated" => false,
1130 "nickname" => user1.nickname,
1131 "roles" => %{"admin" => false, "moderator" => false},
1132 "local" => user1.local,
1133 "tags" => ["first"],
1134 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1135 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1136 "confirmation_pending" => false
1139 "deactivated" => false,
1141 "nickname" => user2.nickname,
1142 "roles" => %{"admin" => false, "moderator" => false},
1143 "local" => user2.local,
1144 "tags" => ["second"],
1145 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1146 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1147 "confirmation_pending" => false
1150 |> Enum.sort_by(& &1["nickname"])
1152 assert json_response(conn, 200) == %{
1159 test "it works with multiple filters" do
1160 admin = insert(:user, nickname: "john", is_admin: true)
1161 token = insert(:oauth_admin_token, user: admin)
1162 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1164 insert(:user, nickname: "ken", local: true, deactivated: true)
1165 insert(:user, nickname: "bobb", local: false, deactivated: false)
1169 |> assign(:user, admin)
1170 |> assign(:token, token)
1171 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1173 assert json_response(conn, 200) == %{
1178 "deactivated" => user.deactivated,
1180 "nickname" => user.nickname,
1181 "roles" => %{"admin" => false, "moderator" => false},
1182 "local" => user.local,
1184 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1185 "display_name" => HTML.strip_tags(user.name || user.nickname),
1186 "confirmation_pending" => false
1192 test "it omits relay user", %{admin: admin, conn: conn} do
1193 assert %User{} = Relay.get_actor()
1195 conn = get(conn, "/api/pleroma/admin/users")
1197 assert json_response(conn, 200) == %{
1202 "deactivated" => admin.deactivated,
1204 "nickname" => admin.nickname,
1205 "roles" => %{"admin" => true, "moderator" => false},
1208 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1209 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1210 "confirmation_pending" => false
1217 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1218 user_one = insert(:user, deactivated: true)
1219 user_two = insert(:user, deactivated: true)
1224 "/api/pleroma/admin/users/activate",
1225 %{nicknames: [user_one.nickname, user_two.nickname]}
1228 response = json_response(conn, 200)
1229 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1231 log_entry = Repo.one(ModerationLog)
1233 assert ModerationLog.get_log_entry_message(log_entry) ==
1234 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1237 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1238 user_one = insert(:user, deactivated: false)
1239 user_two = insert(:user, deactivated: false)
1244 "/api/pleroma/admin/users/deactivate",
1245 %{nicknames: [user_one.nickname, user_two.nickname]}
1248 response = json_response(conn, 200)
1249 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1251 log_entry = Repo.one(ModerationLog)
1253 assert ModerationLog.get_log_entry_message(log_entry) ==
1254 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1257 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1258 user = insert(:user)
1260 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1262 assert json_response(conn, 200) ==
1264 "deactivated" => !user.deactivated,
1266 "nickname" => user.nickname,
1267 "roles" => %{"admin" => false, "moderator" => false},
1270 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1271 "display_name" => HTML.strip_tags(user.name || user.nickname),
1272 "confirmation_pending" => false
1275 log_entry = Repo.one(ModerationLog)
1277 assert ModerationLog.get_log_entry_message(log_entry) ==
1278 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1281 describe "POST /api/pleroma/admin/users/invite_token" do
1282 test "without options", %{conn: conn} do
1283 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1285 invite_json = json_response(conn, 200)
1286 invite = UserInviteToken.find_by_token!(invite_json["token"])
1288 refute invite.expires_at
1289 refute invite.max_use
1290 assert invite.invite_type == "one_time"
1293 test "with expires_at", %{conn: conn} do
1295 post(conn, "/api/pleroma/admin/users/invite_token", %{
1296 "expires_at" => Date.to_string(Date.utc_today())
1299 invite_json = json_response(conn, 200)
1300 invite = UserInviteToken.find_by_token!(invite_json["token"])
1303 assert invite.expires_at == Date.utc_today()
1304 refute invite.max_use
1305 assert invite.invite_type == "date_limited"
1308 test "with max_use", %{conn: conn} do
1309 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1311 invite_json = json_response(conn, 200)
1312 invite = UserInviteToken.find_by_token!(invite_json["token"])
1314 refute invite.expires_at
1315 assert invite.max_use == 150
1316 assert invite.invite_type == "reusable"
1319 test "with max use and expires_at", %{conn: conn} do
1321 post(conn, "/api/pleroma/admin/users/invite_token", %{
1323 "expires_at" => Date.to_string(Date.utc_today())
1326 invite_json = json_response(conn, 200)
1327 invite = UserInviteToken.find_by_token!(invite_json["token"])
1329 assert invite.expires_at == Date.utc_today()
1330 assert invite.max_use == 150
1331 assert invite.invite_type == "reusable_date_limited"
1335 describe "GET /api/pleroma/admin/users/invites" do
1336 test "no invites", %{conn: conn} do
1337 conn = get(conn, "/api/pleroma/admin/users/invites")
1339 assert json_response(conn, 200) == %{"invites" => []}
1342 test "with invite", %{conn: conn} do
1343 {:ok, invite} = UserInviteToken.create_invite()
1345 conn = get(conn, "/api/pleroma/admin/users/invites")
1347 assert json_response(conn, 200) == %{
1350 "expires_at" => nil,
1352 "invite_type" => "one_time",
1354 "token" => invite.token,
1363 describe "POST /api/pleroma/admin/users/revoke_invite" do
1364 test "with token", %{conn: conn} do
1365 {:ok, invite} = UserInviteToken.create_invite()
1367 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1369 assert json_response(conn, 200) == %{
1370 "expires_at" => nil,
1372 "invite_type" => "one_time",
1374 "token" => invite.token,
1380 test "with invalid token", %{conn: conn} do
1381 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1383 assert json_response(conn, :not_found) == "Not found"
1387 describe "GET /api/pleroma/admin/reports/:id" do
1388 test "returns report by its id", %{conn: conn} do
1389 [reporter, target_user] = insert_pair(:user)
1390 activity = insert(:note_activity, user: target_user)
1392 {:ok, %{id: report_id}} =
1393 CommonAPI.report(reporter, %{
1394 account_id: target_user.id,
1395 comment: "I feel offended",
1396 status_ids: [activity.id]
1401 |> get("/api/pleroma/admin/reports/#{report_id}")
1402 |> json_response(:ok)
1404 assert response["id"] == report_id
1407 test "returns 404 when report id is invalid", %{conn: conn} do
1408 conn = get(conn, "/api/pleroma/admin/reports/test")
1410 assert json_response(conn, :not_found) == "Not found"
1414 describe "PATCH /api/pleroma/admin/reports" do
1416 [reporter, target_user] = insert_pair(:user)
1417 activity = insert(:note_activity, user: target_user)
1419 {:ok, %{id: report_id}} =
1420 CommonAPI.report(reporter, %{
1421 account_id: target_user.id,
1422 comment: "I feel offended",
1423 status_ids: [activity.id]
1426 {:ok, %{id: second_report_id}} =
1427 CommonAPI.report(reporter, %{
1428 account_id: target_user.id,
1429 comment: "I feel very offended",
1430 status_ids: [activity.id]
1435 second_report_id: second_report_id
1439 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1440 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1441 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1445 |> assign(:token, read_token)
1446 |> patch("/api/pleroma/admin/reports", %{
1447 "reports" => [%{"state" => "resolved", "id" => id}]
1449 |> json_response(403)
1451 assert response == %{
1452 "error" => "Insufficient permissions: admin:write:reports."
1456 |> assign(:token, write_token)
1457 |> patch("/api/pleroma/admin/reports", %{
1458 "reports" => [%{"state" => "resolved", "id" => id}]
1460 |> json_response(:no_content)
1463 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1465 |> patch("/api/pleroma/admin/reports", %{
1467 %{"state" => "resolved", "id" => id}
1470 |> json_response(:no_content)
1472 activity = Activity.get_by_id(id)
1473 assert activity.data["state"] == "resolved"
1475 log_entry = Repo.one(ModerationLog)
1477 assert ModerationLog.get_log_entry_message(log_entry) ==
1478 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1481 test "closes report", %{conn: conn, id: id, admin: admin} do
1483 |> patch("/api/pleroma/admin/reports", %{
1485 %{"state" => "closed", "id" => id}
1488 |> json_response(:no_content)
1490 activity = Activity.get_by_id(id)
1491 assert activity.data["state"] == "closed"
1493 log_entry = Repo.one(ModerationLog)
1495 assert ModerationLog.get_log_entry_message(log_entry) ==
1496 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1499 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1502 |> patch("/api/pleroma/admin/reports", %{
1504 %{"state" => "test", "id" => id}
1508 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1511 test "returns 404 when report is not exist", %{conn: conn} do
1514 |> patch("/api/pleroma/admin/reports", %{
1516 %{"state" => "closed", "id" => "test"}
1520 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1523 test "updates state of multiple reports", %{
1527 second_report_id: second_report_id
1530 |> patch("/api/pleroma/admin/reports", %{
1532 %{"state" => "resolved", "id" => id},
1533 %{"state" => "closed", "id" => second_report_id}
1536 |> json_response(:no_content)
1538 activity = Activity.get_by_id(id)
1539 second_activity = Activity.get_by_id(second_report_id)
1540 assert activity.data["state"] == "resolved"
1541 assert second_activity.data["state"] == "closed"
1543 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1545 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1546 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1548 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1549 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1553 describe "GET /api/pleroma/admin/reports" do
1554 test "returns empty response when no reports created", %{conn: conn} do
1557 |> get("/api/pleroma/admin/reports")
1558 |> json_response(:ok)
1560 assert Enum.empty?(response["reports"])
1561 assert response["total"] == 0
1564 test "returns reports", %{conn: conn} do
1565 [reporter, target_user] = insert_pair(:user)
1566 activity = insert(:note_activity, user: target_user)
1568 {:ok, %{id: report_id}} =
1569 CommonAPI.report(reporter, %{
1570 account_id: target_user.id,
1571 comment: "I feel offended",
1572 status_ids: [activity.id]
1577 |> get("/api/pleroma/admin/reports")
1578 |> json_response(:ok)
1580 [report] = response["reports"]
1582 assert length(response["reports"]) == 1
1583 assert report["id"] == report_id
1585 assert response["total"] == 1
1588 test "returns reports with specified state", %{conn: conn} do
1589 [reporter, target_user] = insert_pair(:user)
1590 activity = insert(:note_activity, user: target_user)
1592 {:ok, %{id: first_report_id}} =
1593 CommonAPI.report(reporter, %{
1594 account_id: target_user.id,
1595 comment: "I feel offended",
1596 status_ids: [activity.id]
1599 {:ok, %{id: second_report_id}} =
1600 CommonAPI.report(reporter, %{
1601 account_id: target_user.id,
1602 comment: "I don't like this user"
1605 CommonAPI.update_report_state(second_report_id, "closed")
1609 |> get("/api/pleroma/admin/reports", %{
1612 |> json_response(:ok)
1614 [open_report] = response["reports"]
1616 assert length(response["reports"]) == 1
1617 assert open_report["id"] == first_report_id
1619 assert response["total"] == 1
1623 |> get("/api/pleroma/admin/reports", %{
1626 |> json_response(:ok)
1628 [closed_report] = response["reports"]
1630 assert length(response["reports"]) == 1
1631 assert closed_report["id"] == second_report_id
1633 assert response["total"] == 1
1637 |> get("/api/pleroma/admin/reports", %{
1638 "state" => "resolved"
1640 |> json_response(:ok)
1642 assert Enum.empty?(response["reports"])
1643 assert response["total"] == 0
1646 test "returns 403 when requested by a non-admin" do
1647 user = insert(:user)
1648 token = insert(:oauth_token, user: user)
1652 |> assign(:user, user)
1653 |> assign(:token, token)
1654 |> get("/api/pleroma/admin/reports")
1656 assert json_response(conn, :forbidden) ==
1657 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1660 test "returns 403 when requested by anonymous" do
1661 conn = get(build_conn(), "/api/pleroma/admin/reports")
1663 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1667 describe "GET /api/pleroma/admin/statuses/:id" do
1668 test "not found", %{conn: conn} do
1670 |> get("/api/pleroma/admin/statuses/not_found")
1671 |> json_response(:not_found)
1674 test "shows activity", %{conn: conn} do
1675 activity = insert(:note_activity)
1679 |> get("/api/pleroma/admin/statuses/#{activity.id}")
1680 |> json_response(200)
1682 assert response["id"] == activity.id
1686 describe "PUT /api/pleroma/admin/statuses/:id" do
1688 activity = insert(:note_activity)
1693 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1696 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1697 |> json_response(:ok)
1699 assert response["sensitive"]
1701 log_entry = Repo.one(ModerationLog)
1703 assert ModerationLog.get_log_entry_message(log_entry) ==
1704 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1708 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1709 |> json_response(:ok)
1711 refute response["sensitive"]
1714 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1717 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1718 |> json_response(:ok)
1720 assert response["visibility"] == "public"
1722 log_entry = Repo.one(ModerationLog)
1724 assert ModerationLog.get_log_entry_message(log_entry) ==
1725 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1729 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1730 |> json_response(:ok)
1732 assert response["visibility"] == "private"
1736 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1737 |> json_response(:ok)
1739 assert response["visibility"] == "unlisted"
1742 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1743 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1745 assert json_response(conn, :bad_request) == "Unsupported visibility"
1749 describe "DELETE /api/pleroma/admin/statuses/:id" do
1751 activity = insert(:note_activity)
1756 test "deletes status", %{conn: conn, id: id, admin: admin} do
1758 |> delete("/api/pleroma/admin/statuses/#{id}")
1759 |> json_response(:ok)
1761 refute Activity.get_by_id(id)
1763 log_entry = Repo.one(ModerationLog)
1765 assert ModerationLog.get_log_entry_message(log_entry) ==
1766 "@#{admin.nickname} deleted status ##{id}"
1769 test "returns 404 when the status does not exist", %{conn: conn} do
1770 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1772 assert json_response(conn, :not_found) == "Not found"
1776 describe "GET /api/pleroma/admin/config" do
1777 setup do: clear_config(:configurable_from_database, true)
1779 test "when configuration from database is off", %{conn: conn} do
1780 Config.put(:configurable_from_database, false)
1781 conn = get(conn, "/api/pleroma/admin/config")
1783 assert json_response(conn, 400) ==
1784 "To use this endpoint you need to enable configuration from database."
1787 test "with settings only in db", %{conn: conn} do
1788 config1 = insert(:config)
1789 config2 = insert(:config)
1791 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1796 "group" => ":pleroma",
1801 "group" => ":pleroma",
1806 } = json_response(conn, 200)
1808 assert key1 == config1.key
1809 assert key2 == config2.key
1812 test "db is added to settings that are in db", %{conn: conn} do
1813 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1815 %{"configs" => configs} =
1817 |> get("/api/pleroma/admin/config")
1818 |> json_response(200)
1821 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1822 group == ":pleroma" and key == ":instance"
1825 assert instance_config["db"] == [":name"]
1828 test "merged default setting with db settings", %{conn: conn} do
1829 config1 = insert(:config)
1830 config2 = insert(:config)
1834 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1837 %{"configs" => configs} =
1839 |> get("/api/pleroma/admin/config")
1840 |> json_response(200)
1842 assert length(configs) > 3
1845 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1846 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1849 assert length(received_configs) == 3
1853 |> ConfigDB.from_binary()
1855 |> ConfigDB.convert()
1857 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1858 assert db in [[config1.key], [config2.key], db_keys]
1861 ConfigDB.from_binary_with_convert(config1.value),
1862 ConfigDB.from_binary_with_convert(config2.value),
1863 ConfigDB.from_binary_with_convert(config3.value)
1868 test "subkeys with full update right merge", %{conn: conn} do
1872 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1878 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1881 %{"configs" => configs} =
1883 |> get("/api/pleroma/admin/config")
1884 |> json_response(200)
1887 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1888 group == ":pleroma" and key in [config1.key, config2.key]
1891 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1892 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1894 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1895 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1897 assert emoji_val[:groups] == [a: 1, b: 2]
1898 assert assets_val[:mascots] == [a: 1, b: 2]
1902 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1903 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1905 assert json_response(conn, 400) ==
1906 "To use this endpoint you need to enable configuration from database."
1909 describe "POST /api/pleroma/admin/config" do
1911 http = Application.get_env(:pleroma, :http)
1914 Application.delete_env(:pleroma, :key1)
1915 Application.delete_env(:pleroma, :key2)
1916 Application.delete_env(:pleroma, :key3)
1917 Application.delete_env(:pleroma, :key4)
1918 Application.delete_env(:pleroma, :keyaa1)
1919 Application.delete_env(:pleroma, :keyaa2)
1920 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1921 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1922 Application.put_env(:pleroma, :http, http)
1923 Application.put_env(:tesla, :adapter, Tesla.Mock)
1924 Restarter.Pleroma.refresh()
1928 setup do: clear_config(:configurable_from_database, true)
1930 @tag capture_log: true
1931 test "create new config setting in db", %{conn: conn} do
1932 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1933 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1936 post(conn, "/api/pleroma/admin/config", %{
1938 %{group: ":pleroma", key: ":key1", value: "value1"},
1940 group: ":ueberauth",
1942 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1948 ":nested_1" => "nested_value1",
1950 %{":nested_22" => "nested_value222"},
1951 %{":nested_33" => %{":nested_44" => "nested_444"}}
1959 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1960 %{"nested_4" => true}
1966 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1971 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1976 assert json_response(conn, 200) == %{
1979 "group" => ":pleroma",
1981 "value" => "value1",
1985 "group" => ":ueberauth",
1986 "key" => "Ueberauth",
1987 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1988 "db" => [":consumer_secret"]
1991 "group" => ":pleroma",
1994 ":nested_1" => "nested_value1",
1996 %{":nested_22" => "nested_value222"},
1997 %{":nested_33" => %{":nested_44" => "nested_444"}}
2003 "group" => ":pleroma",
2006 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2007 %{"nested_4" => true}
2012 "group" => ":pleroma",
2014 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
2020 "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 configs setting without explicit 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) == %{
2084 "group" => ":quack",
2090 "group" => ":quack",
2092 "value" => [":none"],
2096 "group" => ":quack",
2097 "key" => ":webhook_url",
2098 "value" => "https://hooks.slack.com/services/KEY",
2099 "db" => [":webhook_url"]
2104 assert Application.get_env(:quack, :level) == :info
2105 assert Application.get_env(:quack, :meta) == [:none]
2106 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2109 test "saving config with partial update", %{conn: conn} do
2110 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2113 post(conn, "/api/pleroma/admin/config", %{
2115 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2119 assert json_response(conn, 200) == %{
2122 "group" => ":pleroma",
2125 %{"tuple" => [":key1", 1]},
2126 %{"tuple" => [":key2", 2]},
2127 %{"tuple" => [":key3", 3]}
2129 "db" => [":key1", ":key2", ":key3"]
2135 test "saving config which need pleroma reboot", %{conn: conn} do
2136 chat = Config.get(:chat)
2137 on_exit(fn -> Config.put(:chat, chat) end)
2141 "/api/pleroma/admin/config",
2144 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2148 |> json_response(200) == %{
2151 "db" => [":enabled"],
2152 "group" => ":pleroma",
2154 "value" => [%{"tuple" => [":enabled", true]}]
2157 "need_reboot" => true
2162 |> get("/api/pleroma/admin/config")
2163 |> json_response(200)
2165 assert configs["need_reboot"]
2168 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2169 end) =~ "pleroma restarted"
2173 |> get("/api/pleroma/admin/config")
2174 |> json_response(200)
2176 assert configs["need_reboot"] == false
2179 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2180 chat = Config.get(:chat)
2181 on_exit(fn -> Config.put(:chat, chat) end)
2185 "/api/pleroma/admin/config",
2188 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2192 |> json_response(200) == %{
2195 "db" => [":enabled"],
2196 "group" => ":pleroma",
2198 "value" => [%{"tuple" => [":enabled", true]}]
2201 "need_reboot" => true
2204 assert post(conn, "/api/pleroma/admin/config", %{
2206 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2209 |> json_response(200) == %{
2212 "group" => ":pleroma",
2215 %{"tuple" => [":key3", 3]}
2220 "need_reboot" => true
2224 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2225 end) =~ "pleroma restarted"
2229 |> get("/api/pleroma/admin/config")
2230 |> json_response(200)
2232 assert configs["need_reboot"] == false
2235 test "saving config with nested merge", %{conn: conn} do
2237 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2240 post(conn, "/api/pleroma/admin/config", %{
2243 group: config.group,
2246 %{"tuple" => [":key3", 3]},
2251 %{"tuple" => [":k2", 1]},
2252 %{"tuple" => [":k3", 3]}
2261 assert json_response(conn, 200) == %{
2264 "group" => ":pleroma",
2267 %{"tuple" => [":key1", 1]},
2268 %{"tuple" => [":key3", 3]},
2273 %{"tuple" => [":k1", 1]},
2274 %{"tuple" => [":k2", 1]},
2275 %{"tuple" => [":k3", 3]}
2280 "db" => [":key1", ":key3", ":key2"]
2286 test "saving special atoms", %{conn: conn} do
2288 post(conn, "/api/pleroma/admin/config", %{
2291 "group" => ":pleroma",
2297 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2305 assert json_response(conn, 200) == %{
2308 "group" => ":pleroma",
2314 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2318 "db" => [":ssl_options"]
2323 assert Application.get_env(:pleroma, :key1) == [
2324 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2328 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2329 backends = Application.get_env(:logger, :backends)
2330 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2336 value: :erlang.term_to_binary([])
2339 Pleroma.Config.TransferTask.load_and_update_env([], false)
2341 assert Application.get_env(:logger, :backends) == []
2344 post(conn, "/api/pleroma/admin/config", %{
2347 group: config.group,
2354 assert json_response(conn, 200) == %{
2357 "group" => ":logger",
2358 "key" => ":backends",
2362 "db" => [":backends"]
2367 assert Application.get_env(:logger, :backends) == [
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 with fallback to default value", %{
2404 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2405 config1 = insert(:config, key: ":keyaa1")
2406 config2 = insert(:config, key: ":keyaa2")
2410 group: ":ueberauth",
2415 post(conn, "/api/pleroma/admin/config", %{
2417 %{group: config1.group, key: config1.key, value: "another_value"},
2418 %{group: config2.group, key: config2.key, value: "another_value"}
2422 assert json_response(conn, 200) == %{
2425 "group" => ":pleroma",
2426 "key" => config1.key,
2427 "value" => "another_value",
2431 "group" => ":pleroma",
2432 "key" => config2.key,
2433 "value" => "another_value",
2439 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2440 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2441 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2445 |> assign(:user, admin)
2446 |> assign(:token, token)
2447 |> post("/api/pleroma/admin/config", %{
2449 %{group: config2.group, key: config2.key, delete: true},
2451 group: ":ueberauth",
2458 assert json_response(conn, 200) == %{
2462 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2463 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2466 test "common config example", %{conn: conn} do
2468 post(conn, "/api/pleroma/admin/config", %{
2471 "group" => ":pleroma",
2472 "key" => "Pleroma.Captcha.NotReal",
2474 %{"tuple" => [":enabled", false]},
2475 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2476 %{"tuple" => [":seconds_valid", 60]},
2477 %{"tuple" => [":path", ""]},
2478 %{"tuple" => [":key1", nil]},
2479 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2480 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2481 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2482 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2483 %{"tuple" => [":name", "Pleroma"]}
2489 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2491 assert json_response(conn, 200) == %{
2494 "group" => ":pleroma",
2495 "key" => "Pleroma.Captcha.NotReal",
2497 %{"tuple" => [":enabled", false]},
2498 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2499 %{"tuple" => [":seconds_valid", 60]},
2500 %{"tuple" => [":path", ""]},
2501 %{"tuple" => [":key1", nil]},
2502 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2503 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2504 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2505 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2506 %{"tuple" => [":name", "Pleroma"]}
2525 test "tuples with more than two values", %{conn: conn} do
2527 post(conn, "/api/pleroma/admin/config", %{
2530 "group" => ":pleroma",
2531 "key" => "Pleroma.Web.Endpoint.NotReal",
2547 "/api/v1/streaming",
2548 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2555 "Phoenix.Endpoint.CowboyWebSocket",
2558 "Phoenix.Transports.WebSocket",
2561 "Pleroma.Web.Endpoint",
2562 "Pleroma.Web.UserSocket",
2573 "Phoenix.Endpoint.Cowboy2Handler",
2574 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2591 assert json_response(conn, 200) == %{
2594 "group" => ":pleroma",
2595 "key" => "Pleroma.Web.Endpoint.NotReal",
2611 "/api/v1/streaming",
2612 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2619 "Phoenix.Endpoint.CowboyWebSocket",
2622 "Phoenix.Transports.WebSocket",
2625 "Pleroma.Web.Endpoint",
2626 "Pleroma.Web.UserSocket",
2637 "Phoenix.Endpoint.Cowboy2Handler",
2638 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2657 test "settings with nesting map", %{conn: conn} do
2659 post(conn, "/api/pleroma/admin/config", %{
2662 "group" => ":pleroma",
2665 %{"tuple" => [":key2", "some_val"]},
2670 ":max_options" => 20,
2671 ":max_option_chars" => 200,
2672 ":min_expiration" => 0,
2673 ":max_expiration" => 31_536_000,
2675 ":max_options" => 20,
2676 ":max_option_chars" => 200,
2677 ":min_expiration" => 0,
2678 ":max_expiration" => 31_536_000
2688 assert json_response(conn, 200) ==
2692 "group" => ":pleroma",
2695 %{"tuple" => [":key2", "some_val"]},
2700 ":max_expiration" => 31_536_000,
2701 ":max_option_chars" => 200,
2702 ":max_options" => 20,
2703 ":min_expiration" => 0,
2705 ":max_expiration" => 31_536_000,
2706 ":max_option_chars" => 200,
2707 ":max_options" => 20,
2708 ":min_expiration" => 0
2714 "db" => [":key2", ":key3"]
2720 test "value as map", %{conn: conn} do
2722 post(conn, "/api/pleroma/admin/config", %{
2725 "group" => ":pleroma",
2727 "value" => %{"key" => "some_val"}
2732 assert json_response(conn, 200) ==
2736 "group" => ":pleroma",
2738 "value" => %{"key" => "some_val"},
2745 test "queues key as atom", %{conn: conn} do
2747 post(conn, "/api/pleroma/admin/config", %{
2753 %{"tuple" => [":federator_incoming", 50]},
2754 %{"tuple" => [":federator_outgoing", 50]},
2755 %{"tuple" => [":web_push", 50]},
2756 %{"tuple" => [":mailer", 10]},
2757 %{"tuple" => [":transmogrifier", 20]},
2758 %{"tuple" => [":scheduled_activities", 10]},
2759 %{"tuple" => [":background", 5]}
2765 assert json_response(conn, 200) == %{
2771 %{"tuple" => [":federator_incoming", 50]},
2772 %{"tuple" => [":federator_outgoing", 50]},
2773 %{"tuple" => [":web_push", 50]},
2774 %{"tuple" => [":mailer", 10]},
2775 %{"tuple" => [":transmogrifier", 20]},
2776 %{"tuple" => [":scheduled_activities", 10]},
2777 %{"tuple" => [":background", 5]}
2780 ":federator_incoming",
2781 ":federator_outgoing",
2785 ":scheduled_activities",
2793 test "delete part of settings by atom subkeys", %{conn: conn} do
2797 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2801 post(conn, "/api/pleroma/admin/config", %{
2804 group: config.group,
2806 subkeys: [":subkey1", ":subkey3"],
2812 assert json_response(conn, 200) == %{
2815 "group" => ":pleroma",
2817 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2818 "db" => [":subkey2"]
2824 test "proxy tuple localhost", %{conn: conn} do
2826 post(conn, "/api/pleroma/admin/config", %{
2832 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2833 %{"tuple" => [":send_user_agent", false]}
2839 assert json_response(conn, 200) == %{
2842 "group" => ":pleroma",
2845 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2846 %{"tuple" => [":send_user_agent", false]}
2848 "db" => [":proxy_url", ":send_user_agent"]
2854 test "proxy tuple domain", %{conn: conn} do
2856 post(conn, "/api/pleroma/admin/config", %{
2862 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2863 %{"tuple" => [":send_user_agent", false]}
2869 assert json_response(conn, 200) == %{
2872 "group" => ":pleroma",
2875 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2876 %{"tuple" => [":send_user_agent", false]}
2878 "db" => [":proxy_url", ":send_user_agent"]
2884 test "proxy tuple ip", %{conn: conn} do
2886 post(conn, "/api/pleroma/admin/config", %{
2892 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2893 %{"tuple" => [":send_user_agent", false]}
2899 assert json_response(conn, 200) == %{
2902 "group" => ":pleroma",
2905 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2906 %{"tuple" => [":send_user_agent", false]}
2908 "db" => [":proxy_url", ":send_user_agent"]
2915 describe "GET /api/pleroma/admin/restart" do
2916 setup do: clear_config(:configurable_from_database, true)
2918 test "pleroma restarts", %{conn: conn} do
2920 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2921 end) =~ "pleroma restarted"
2923 refute Restarter.Pleroma.need_reboot?()
2927 test "need_reboot flag", %{conn: conn} do
2929 |> get("/api/pleroma/admin/need_reboot")
2930 |> json_response(200) == %{"need_reboot" => false}
2932 Restarter.Pleroma.need_reboot()
2935 |> get("/api/pleroma/admin/need_reboot")
2936 |> json_response(200) == %{"need_reboot" => true}
2938 on_exit(fn -> Restarter.Pleroma.refresh() end)
2941 describe "GET /api/pleroma/admin/statuses" do
2942 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2943 blocked = insert(:user)
2944 user = insert(:user)
2945 User.block(admin, blocked)
2948 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2950 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2951 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2952 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2953 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2957 |> get("/api/pleroma/admin/statuses")
2958 |> json_response(200)
2960 refute "private" in Enum.map(response, & &1["visibility"])
2961 assert length(response) == 3
2964 test "returns only local statuses with local_only on", %{conn: conn} do
2965 user = insert(:user)
2966 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2967 insert(:note_activity, user: user, local: true)
2968 insert(:note_activity, user: remote_user, local: false)
2972 |> get("/api/pleroma/admin/statuses?local_only=true")
2973 |> json_response(200)
2975 assert length(response) == 1
2978 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2979 user = insert(:user)
2982 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2984 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2985 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2986 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2987 assert json_response(conn, 200) |> length() == 3
2991 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2993 user = insert(:user)
2995 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2996 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2997 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2999 insert(:note_activity, user: user, published: date1)
3000 insert(:note_activity, user: user, published: date2)
3001 insert(:note_activity, user: user, published: date3)
3006 test "renders user's statuses", %{conn: conn, user: user} do
3007 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3009 assert json_response(conn, 200) |> length() == 3
3012 test "renders user's statuses with a limit", %{conn: conn, user: user} do
3013 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
3015 assert json_response(conn, 200) |> length() == 2
3018 test "doesn't return private statuses by default", %{conn: conn, user: user} do
3019 {:ok, _private_status} =
3020 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3022 {:ok, _public_status} =
3023 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3025 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
3027 assert json_response(conn, 200) |> length() == 4
3030 test "returns private statuses with godmode on", %{conn: conn, user: user} do
3031 {:ok, _private_status} =
3032 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
3034 {:ok, _public_status} =
3035 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
3037 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
3039 assert json_response(conn, 200) |> length() == 5
3042 test "excludes reblogs by default", %{conn: conn, user: user} do
3043 other_user = insert(:user)
3044 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
3045 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
3047 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
3048 assert json_response(conn_res, 200) |> length() == 0
3051 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
3053 assert json_response(conn_res, 200) |> length() == 1
3057 describe "GET /api/pleroma/admin/moderation_log" do
3059 moderator = insert(:user, is_moderator: true)
3061 %{moderator: moderator}
3064 test "returns the log", %{conn: conn, admin: admin} do
3065 Repo.insert(%ModerationLog{
3069 "nickname" => admin.nickname,
3072 action: "relay_follow",
3073 target: "https://example.org/relay"
3075 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3078 Repo.insert(%ModerationLog{
3082 "nickname" => admin.nickname,
3085 action: "relay_unfollow",
3086 target: "https://example.org/relay"
3088 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3091 conn = get(conn, "/api/pleroma/admin/moderation_log")
3093 response = json_response(conn, 200)
3094 [first_entry, second_entry] = response["items"]
3096 assert response["total"] == 2
3097 assert first_entry["data"]["action"] == "relay_unfollow"
3099 assert first_entry["message"] ==
3100 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3102 assert second_entry["data"]["action"] == "relay_follow"
3104 assert second_entry["message"] ==
3105 "@#{admin.nickname} followed relay: https://example.org/relay"
3108 test "returns the log with pagination", %{conn: conn, admin: admin} do
3109 Repo.insert(%ModerationLog{
3113 "nickname" => admin.nickname,
3116 action: "relay_follow",
3117 target: "https://example.org/relay"
3119 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3122 Repo.insert(%ModerationLog{
3126 "nickname" => admin.nickname,
3129 action: "relay_unfollow",
3130 target: "https://example.org/relay"
3132 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3135 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3137 response1 = json_response(conn1, 200)
3138 [first_entry] = response1["items"]
3140 assert response1["total"] == 2
3141 assert response1["items"] |> length() == 1
3142 assert first_entry["data"]["action"] == "relay_unfollow"
3144 assert first_entry["message"] ==
3145 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3147 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3149 response2 = json_response(conn2, 200)
3150 [second_entry] = response2["items"]
3152 assert response2["total"] == 2
3153 assert response2["items"] |> length() == 1
3154 assert second_entry["data"]["action"] == "relay_follow"
3156 assert second_entry["message"] ==
3157 "@#{admin.nickname} followed relay: https://example.org/relay"
3160 test "filters log by date", %{conn: conn, admin: admin} do
3161 first_date = "2017-08-15T15:47:06Z"
3162 second_date = "2017-08-20T15:47:06Z"
3164 Repo.insert(%ModerationLog{
3168 "nickname" => admin.nickname,
3171 action: "relay_follow",
3172 target: "https://example.org/relay"
3174 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3177 Repo.insert(%ModerationLog{
3181 "nickname" => admin.nickname,
3184 action: "relay_unfollow",
3185 target: "https://example.org/relay"
3187 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3193 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3196 response1 = json_response(conn1, 200)
3197 [first_entry] = response1["items"]
3199 assert response1["total"] == 1
3200 assert first_entry["data"]["action"] == "relay_unfollow"
3202 assert first_entry["message"] ==
3203 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3206 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3207 Repo.insert(%ModerationLog{
3211 "nickname" => admin.nickname,
3214 action: "relay_follow",
3215 target: "https://example.org/relay"
3219 Repo.insert(%ModerationLog{
3222 "id" => moderator.id,
3223 "nickname" => moderator.nickname,
3226 action: "relay_unfollow",
3227 target: "https://example.org/relay"
3231 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3233 response1 = json_response(conn1, 200)
3234 [first_entry] = response1["items"]
3236 assert response1["total"] == 1
3237 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3240 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3241 ModerationLog.insert_log(%{
3243 action: "relay_follow",
3244 target: "https://example.org/relay"
3247 ModerationLog.insert_log(%{
3249 action: "relay_unfollow",
3250 target: "https://example.org/relay"
3253 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3255 response1 = json_response(conn1, 200)
3256 [first_entry] = response1["items"]
3258 assert response1["total"] == 1
3260 assert get_in(first_entry, ["data", "message"]) ==
3261 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3265 describe "GET /users/:nickname/credentials" do
3266 test "gets the user credentials", %{conn: conn} do
3267 user = insert(:user)
3268 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3270 response = assert json_response(conn, 200)
3271 assert response["email"] == user.email
3274 test "returns 403 if requested by a non-admin" do
3275 user = insert(:user)
3279 |> assign(:user, user)
3280 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3282 assert json_response(conn, :forbidden)
3286 describe "PATCH /users/:nickname/credentials" do
3287 test "changes password and email", %{conn: conn, admin: admin} do
3288 user = insert(:user)
3289 assert user.password_reset_pending == false
3292 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3293 "password" => "new_password",
3294 "email" => "new_email@example.com",
3295 "name" => "new_name"
3298 assert json_response(conn, 200) == %{"status" => "success"}
3300 ObanHelpers.perform_all()
3302 updated_user = User.get_by_id(user.id)
3304 assert updated_user.email == "new_email@example.com"
3305 assert updated_user.name == "new_name"
3306 assert updated_user.password_hash != user.password_hash
3307 assert updated_user.password_reset_pending == true
3309 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3311 assert ModerationLog.get_log_entry_message(log_entry1) ==
3312 "@#{admin.nickname} updated users: @#{user.nickname}"
3314 assert ModerationLog.get_log_entry_message(log_entry2) ==
3315 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3318 test "returns 403 if requested by a non-admin" do
3319 user = insert(:user)
3323 |> assign(:user, user)
3324 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3325 "password" => "new_password",
3326 "email" => "new_email@example.com",
3327 "name" => "new_name"
3330 assert json_response(conn, :forbidden)
3334 describe "PATCH /users/:nickname/force_password_reset" do
3335 test "sets password_reset_pending to true", %{conn: conn} do
3336 user = insert(:user)
3337 assert user.password_reset_pending == false
3340 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3342 assert json_response(conn, 204) == ""
3344 ObanHelpers.perform_all()
3346 assert User.get_by_id(user.id).password_reset_pending == true
3350 describe "relays" do
3351 test "POST /relay", %{conn: conn, admin: admin} do
3353 post(conn, "/api/pleroma/admin/relay", %{
3354 relay_url: "http://mastodon.example.org/users/admin"
3357 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3359 log_entry = Repo.one(ModerationLog)
3361 assert ModerationLog.get_log_entry_message(log_entry) ==
3362 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3365 test "GET /relay", %{conn: conn} do
3366 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3368 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3369 |> Enum.each(fn ap_id ->
3370 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3371 User.follow(relay_user, user)
3374 conn = get(conn, "/api/pleroma/admin/relay")
3376 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3379 test "DELETE /relay", %{conn: conn, admin: admin} do
3380 post(conn, "/api/pleroma/admin/relay", %{
3381 relay_url: "http://mastodon.example.org/users/admin"
3385 delete(conn, "/api/pleroma/admin/relay", %{
3386 relay_url: "http://mastodon.example.org/users/admin"
3389 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3391 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3393 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3394 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3396 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3397 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3401 describe "instances" do
3402 test "GET /instances/:instance/statuses", %{conn: conn} do
3403 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3404 user2 = insert(:user, local: false, nickname: "test@test.com")
3405 insert_pair(:note_activity, user: user)
3406 activity = insert(:note_activity, user: user2)
3408 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3410 response = json_response(ret_conn, 200)
3412 assert length(response) == 2
3414 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3416 response = json_response(ret_conn, 200)
3418 assert length(response) == 1
3420 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3422 response = json_response(ret_conn, 200)
3424 assert Enum.empty?(response)
3426 CommonAPI.repeat(activity.id, user)
3428 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3429 response = json_response(ret_conn, 200)
3430 assert length(response) == 2
3432 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3433 response = json_response(ret_conn, 200)
3434 assert length(response) == 3
3438 describe "PATCH /confirm_email" do
3439 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3440 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3442 assert first_user.confirmation_pending == true
3443 assert second_user.confirmation_pending == true
3446 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3448 first_user.nickname,
3449 second_user.nickname
3453 assert ret_conn.status == 200
3455 assert first_user.confirmation_pending == true
3456 assert second_user.confirmation_pending == true
3458 log_entry = Repo.one(ModerationLog)
3460 assert ModerationLog.get_log_entry_message(log_entry) ==
3461 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3462 second_user.nickname
3467 describe "PATCH /resend_confirmation_email" do
3468 test "it resend emails for two users", %{conn: conn, admin: admin} do
3469 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3472 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3474 first_user.nickname,
3475 second_user.nickname
3479 assert ret_conn.status == 200
3481 log_entry = Repo.one(ModerationLog)
3483 assert ModerationLog.get_log_entry_message(log_entry) ==
3484 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3485 second_user.nickname
3490 describe "POST /reports/:id/notes" do
3491 setup %{conn: conn, admin: admin} do
3492 [reporter, target_user] = insert_pair(:user)
3493 activity = insert(:note_activity, user: target_user)
3495 {:ok, %{id: report_id}} =
3496 CommonAPI.report(reporter, %{
3497 account_id: target_user.id,
3498 comment: "I feel offended",
3499 status_ids: [activity.id]
3502 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3503 content: "this is disgusting!"
3506 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3507 content: "this is disgusting2!"
3512 report_id: report_id
3516 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3517 [note, _] = Repo.all(ReportNote)
3520 activity_id: ^report_id,
3521 content: "this is disgusting!",
3526 test "it returns reports with notes", %{conn: conn, admin: admin} do
3527 conn = get(conn, "/api/pleroma/admin/reports")
3529 response = json_response(conn, 200)
3530 notes = hd(response["reports"])["notes"]
3533 assert note["user"]["nickname"] == admin.nickname
3534 assert note["content"] == "this is disgusting!"
3535 assert note["created_at"]
3536 assert response["total"] == 1
3539 test "it deletes the note", %{conn: conn, report_id: report_id} do
3540 assert ReportNote |> Repo.all() |> length() == 2
3542 [note, _] = Repo.all(ReportNote)
3544 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3546 assert ReportNote |> Repo.all() |> length() == 1
3550 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3551 admin = insert(:user, is_admin: true)
3554 assign(conn, :user, admin)
3555 |> get("/api/pleroma/admin/config/descriptions")
3557 assert [child | _others] = json_response(conn, 200)
3559 assert child["children"]
3561 assert String.starts_with?(child["group"], ":")
3562 assert child["description"]
3565 describe "/api/pleroma/admin/stats" do
3566 test "status visibility count", %{conn: conn} do
3567 admin = insert(:user, is_admin: true)
3568 user = insert(:user)
3569 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3570 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3571 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3575 |> assign(:user, admin)
3576 |> get("/api/pleroma/admin/stats")
3577 |> json_response(200)
3579 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3580 response["status_visibility"]
3584 describe "POST /api/pleroma/admin/oauth_app" do
3585 test "errors", %{conn: conn} do
3586 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
3588 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
3591 test "success", %{conn: conn} do
3592 base_url = Web.base_url()
3593 app_name = "Trusted app"
3597 |> post("/api/pleroma/admin/oauth_app", %{
3599 redirect_uris: base_url
3601 |> json_response(200)
3605 "client_secret" => _,
3606 "name" => ^app_name,
3607 "redirect_uri" => ^base_url,
3612 test "with trusted", %{conn: conn} do
3613 base_url = Web.base_url()
3614 app_name = "Trusted app"
3618 |> post("/api/pleroma/admin/oauth_app", %{
3620 redirect_uris: base_url,
3623 |> json_response(200)
3627 "client_secret" => _,
3628 "name" => ^app_name,
3629 "redirect_uri" => ^base_url,
3635 describe "GET /api/pleroma/admin/oauth_app" do
3637 app = insert(:oauth_app)
3641 test "list", %{conn: conn} do
3644 |> get("/api/pleroma/admin/oauth_app")
3645 |> json_response(200)
3647 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
3649 assert length(apps) == count
3652 test "with page size", %{conn: conn} do
3658 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
3659 |> json_response(200)
3661 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
3663 assert length(apps) == page_size
3666 test "search by client name", %{conn: conn, app: app} do
3669 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
3670 |> json_response(200)
3672 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3674 assert returned["client_id"] == app.client_id
3675 assert returned["name"] == app.client_name
3678 test "search by client id", %{conn: conn, app: app} do
3681 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
3682 |> json_response(200)
3684 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3686 assert returned["client_id"] == app.client_id
3687 assert returned["name"] == app.client_name
3690 test "only trusted", %{conn: conn} do
3691 app = insert(:oauth_app, trusted: true)
3695 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
3696 |> json_response(200)
3698 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
3700 assert returned["client_id"] == app.client_id
3701 assert returned["name"] == app.client_name
3705 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
3706 test "with id", %{conn: conn} do
3707 app = insert(:oauth_app)
3711 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
3712 |> json_response(:no_content)
3714 assert response == ""
3717 test "with non existance id", %{conn: conn} do
3720 |> delete("/api/pleroma/admin/oauth_app/0")
3721 |> json_response(:bad_request)
3723 assert response == ""
3727 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
3728 test "with id", %{conn: conn} do
3729 app = insert(:oauth_app)
3731 name = "another name"
3732 url = "https://example.com"
3735 website = "http://website.com"
3739 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
3746 |> json_response(200)
3750 "client_secret" => _,
3753 "redirect_uri" => ^url,
3755 "website" => ^website
3759 test "without id", %{conn: conn} do
3762 |> patch("/api/pleroma/admin/oauth_app/0")
3763 |> json_response(:bad_request)
3765 assert response == ""
3770 # Needed for testing
3771 defmodule Pleroma.Web.Endpoint.NotReal do
3774 defmodule Pleroma.Captcha.NotReal do