1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 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, async: false
7 use Oban.Testing, repo: Pleroma.Repo
9 import ExUnit.CaptureLog
10 import Pleroma.Factory
11 import Swoosh.TestAssertions
13 alias Pleroma.Activity
15 alias Pleroma.ModerationLog
17 alias Pleroma.Tests.ObanHelpers
18 alias Pleroma.UnstubbedConfigMock, as: ConfigMock
20 alias Pleroma.Web.CommonAPI
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
29 admin = insert(:user, is_admin: true)
30 token = insert(:oauth_admin_token, user: admin)
34 |> assign(:user, admin)
35 |> assign(:token, token)
37 {:ok, %{admin: admin, token: token, conn: conn}}
40 test "with valid `admin_token` query parameter, skips OAuth scopes check" do
41 clear_config([:admin_token], "password123")
45 conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
47 assert json_response(conn, 200)
50 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
53 url = "/api/pleroma/admin/users/#{user.nickname}"
55 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
56 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
57 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
59 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
60 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
63 for good_token <- [good_token1, good_token2, good_token3] do
66 |> assign(:user, admin)
67 |> assign(:token, good_token)
70 assert json_response(conn, 200)
73 for good_token <- [good_token1, good_token2, good_token3] do
77 |> assign(:token, good_token)
80 assert json_response(conn, :forbidden)
83 for bad_token <- [bad_token1, bad_token2, bad_token3] do
86 |> assign(:user, admin)
87 |> assign(:token, bad_token)
90 assert json_response(conn, :forbidden)
94 describe "PUT /api/pleroma/admin/users/tag" do
95 setup %{conn: conn} do
96 clear_config([:instance, :admin_privileges], [:users_manage_tags])
98 user1 = insert(:user, %{tags: ["x"]})
99 user2 = insert(:user, %{tags: ["y"]})
100 user3 = insert(:user, %{tags: ["unchanged"]})
102 %{conn: conn, user1: user1, user2: user2, user3: user3}
105 test "it appends specified tags to users with specified nicknames", %{
113 |> put_req_header("accept", "application/json")
115 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
116 "#{user2.nickname}&tags[]=foo&tags[]=bar"
119 assert empty_json_response(conn)
120 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
121 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
123 log_entry = Repo.one(ModerationLog)
126 [user1.nickname, user2.nickname]
127 |> Enum.map(&"@#{&1}")
130 tags = ["foo", "bar"] |> Enum.join(", ")
132 assert ModerationLog.get_log_entry_message(log_entry) ==
133 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
136 test "it does not modify tags of not specified users", %{
144 |> put_req_header("accept", "application/json")
146 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
147 "#{user2.nickname}&tags[]=foo&tags[]=bar"
150 assert empty_json_response(conn)
151 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
154 test "it requires privileged role :users_manage_tags", %{conn: conn} do
155 clear_config([:instance, :admin_privileges], [])
159 |> put_req_header("accept", "application/json")
160 |> put("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar")
162 assert json_response(response, :forbidden)
166 describe "DELETE /api/pleroma/admin/users/tag" do
167 setup %{conn: conn} do
168 clear_config([:instance, :admin_privileges], [:users_manage_tags])
169 user1 = insert(:user, %{tags: ["x"]})
170 user2 = insert(:user, %{tags: ["y", "z"]})
171 user3 = insert(:user, %{tags: ["unchanged"]})
173 %{conn: conn, user1: user1, user2: user2, user3: user3}
176 test "it removes specified tags from users with specified nicknames", %{
184 |> put_req_header("accept", "application/json")
186 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
187 "#{user2.nickname}&tags[]=x&tags[]=z"
190 assert empty_json_response(conn)
191 assert User.get_cached_by_id(user1.id).tags == []
192 assert User.get_cached_by_id(user2.id).tags == ["y"]
194 log_entry = Repo.one(ModerationLog)
197 [user1.nickname, user2.nickname]
198 |> Enum.map(&"@#{&1}")
201 tags = ["x", "z"] |> Enum.join(", ")
203 assert ModerationLog.get_log_entry_message(log_entry) ==
204 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
207 test "it does not modify tags of not specified users", %{
215 |> put_req_header("accept", "application/json")
217 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
218 "#{user2.nickname}&tags[]=x&tags[]=z"
221 assert empty_json_response(conn)
222 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
225 test "it requires privileged role :users_manage_tags", %{conn: conn} do
226 clear_config([:instance, :admin_privileges], [])
230 |> put_req_header("accept", "application/json")
231 |> delete("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar")
233 assert json_response(response, :forbidden)
237 describe "/api/pleroma/admin/users/:nickname/permission_group" do
238 test "GET is giving user_info", %{admin: admin, conn: conn} do
241 |> put_req_header("accept", "application/json")
242 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
244 assert json_response(conn, 200) == %{
246 "is_moderator" => false
250 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
255 |> put_req_header("accept", "application/json")
256 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
258 assert json_response(conn, 200) == %{
262 log_entry = Repo.one(ModerationLog)
264 assert ModerationLog.get_log_entry_message(log_entry) ==
265 "@#{admin.nickname} made @#{user.nickname} admin"
268 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
269 user_one = insert(:user)
270 user_two = insert(:user)
274 |> put_req_header("accept", "application/json")
275 |> post("/api/pleroma/admin/users/permission_group/admin", %{
276 nicknames: [user_one.nickname, user_two.nickname]
279 assert json_response(conn, 200) == %{"is_admin" => true}
281 log_entry = Repo.one(ModerationLog)
283 assert ModerationLog.get_log_entry_message(log_entry) ==
284 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
287 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
288 user = insert(:user, is_admin: true)
292 |> put_req_header("accept", "application/json")
293 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
295 assert json_response(conn, 200) == %{"is_admin" => false}
297 log_entry = Repo.one(ModerationLog)
299 assert ModerationLog.get_log_entry_message(log_entry) ==
300 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
303 test "/:right DELETE, can remove from a permission group (multiple)", %{
307 user_one = insert(:user, is_admin: true)
308 user_two = insert(:user, is_admin: true)
312 |> put_req_header("accept", "application/json")
313 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
314 nicknames: [user_one.nickname, user_two.nickname]
317 assert json_response(conn, 200) == %{"is_admin" => false}
319 log_entry = Repo.one(ModerationLog)
321 assert ModerationLog.get_log_entry_message(log_entry) ==
322 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{user_two.nickname}"
326 describe "/api/pleroma/admin/users/:nickname/password_reset" do
327 test "it returns a password reset link", %{conn: conn} do
328 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
334 |> put_req_header("accept", "application/json")
335 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
337 resp = json_response(conn, 200)
339 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
342 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
343 clear_config([:instance, :admin_privileges], [])
347 |> put_req_header("accept", "application/json")
348 |> get("/api/pleroma/admin/users/nickname/password_reset")
350 assert json_response(response, :forbidden)
354 describe "PUT disable_mfa" do
355 test "returns 200 and disable 2fa", %{conn: conn} do
356 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
360 multi_factor_authentication_settings: %MFA.Settings{
362 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
368 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
369 |> json_response(200)
371 assert response == user.nickname
372 mfa_settings = refresh_record(user).multi_factor_authentication_settings
374 refute mfa_settings.enabled
375 refute mfa_settings.totp.confirmed
378 test "returns 404 if user not found", %{conn: conn} do
379 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
383 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
384 |> json_response(404)
386 assert response == %{"error" => "Not found"}
389 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
390 clear_config([:instance, :admin_privileges], [])
394 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
396 assert json_response(response, :forbidden)
400 describe "GET /api/pleroma/admin/restart" do
401 setup do: clear_config(:configurable_from_database, true)
403 test "pleroma restarts", %{conn: conn} do
405 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
406 end) =~ "pleroma restarted"
408 refute Restarter.Pleroma.need_reboot?()
412 test "need_reboot flag", %{conn: conn} do
414 |> get("/api/pleroma/admin/need_reboot")
415 |> json_response(200) == %{"need_reboot" => false}
417 Restarter.Pleroma.need_reboot()
420 |> get("/api/pleroma/admin/need_reboot")
421 |> json_response(200) == %{"need_reboot" => true}
423 on_exit(fn -> Restarter.Pleroma.refresh() end)
426 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
428 clear_config([:instance, :admin_privileges], [:messages_read])
432 insert(:note_activity, user: user)
433 insert(:note_activity, user: user)
434 insert(:note_activity, user: user)
439 test "renders user's statuses", %{conn: conn, user: user} do
440 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
442 assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
443 assert length(activities) == 3
446 test "it requires privileged role :messages_read", %{conn: conn, user: user} do
447 clear_config([:instance, :admin_privileges], [])
449 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
451 assert json_response(conn, :forbidden)
454 test "renders user's statuses with pagination", %{conn: conn, user: user} do
455 %{"total" => 3, "activities" => [activity1]} =
457 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
458 |> json_response(200)
460 %{"total" => 3, "activities" => [activity2]} =
462 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
463 |> json_response(200)
465 refute activity1 == activity2
468 test "doesn't return private statuses by default", %{conn: conn, user: user} do
469 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
471 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
473 %{"total" => 4, "activities" => activities} =
475 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
476 |> json_response(200)
478 assert length(activities) == 4
481 test "returns private statuses with godmode on", %{conn: conn, user: user} do
482 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
484 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
486 %{"total" => 5, "activities" => activities} =
488 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
489 |> json_response(200)
491 assert length(activities) == 5
494 test "excludes reblogs by default", %{conn: conn, user: user} do
495 other_user = insert(:user)
496 {:ok, activity} = CommonAPI.post(user, %{status: "."})
497 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
499 assert %{"total" => 0, "activities" => []} ==
501 |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
502 |> json_response(200)
504 assert %{"total" => 1, "activities" => [_]} =
507 "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
509 |> json_response(200)
513 describe "GET /api/pleroma/admin/users/:nickname/chats" do
515 clear_config([:instance, :admin_privileges], [:messages_read])
522 test "renders user's chats", %{conn: conn, user: user} do
523 recipients = insert_list(3, :user)
525 Enum.each(recipients, fn recipient ->
526 CommonAPI.post_chat_message(user, recipient, "yo")
529 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
531 assert json_response(conn, 200) |> length() == 3
534 test "it requires privileged role :messages_read", %{conn: conn, user: user} do
535 clear_config([:instance, :admin_privileges], [])
537 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
539 assert json_response(conn, :forbidden)
543 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
546 recipient = insert(:user)
547 CommonAPI.post_chat_message(user, recipient, "yo")
548 %{conn: conn} = oauth_access(["read:chats"])
549 %{conn: conn, user: user}
552 test "returns 403", %{conn: conn, user: user} do
554 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
555 |> json_response(403)
559 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
562 recipient = insert(:user)
563 CommonAPI.post_chat_message(user, recipient, "yo")
564 %{conn: build_conn(), user: user}
567 test "returns 403", %{conn: conn, user: user} do
569 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
570 |> json_response(403)
574 describe "GET /api/pleroma/admin/moderation_log" do
576 clear_config([:instance, :admin_privileges], [:moderation_log_read])
577 moderator = insert(:user, is_moderator: true)
579 %{moderator: moderator}
582 test "returns the log", %{conn: conn, admin: admin} do
583 Repo.insert(%ModerationLog{
587 "nickname" => admin.nickname,
590 action: "relay_follow",
591 target: "https://example.org/relay"
593 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
596 Repo.insert(%ModerationLog{
600 "nickname" => admin.nickname,
603 action: "relay_unfollow",
604 target: "https://example.org/relay"
606 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
609 conn = get(conn, "/api/pleroma/admin/moderation_log")
611 response = json_response(conn, 200)
612 [first_entry, second_entry] = response["items"]
614 assert response["total"] == 2
615 assert first_entry["data"]["action"] == "relay_unfollow"
617 assert first_entry["message"] ==
618 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
620 assert second_entry["data"]["action"] == "relay_follow"
622 assert second_entry["message"] ==
623 "@#{admin.nickname} followed relay: https://example.org/relay"
626 test "returns the log with pagination", %{conn: conn, admin: admin} do
627 Repo.insert(%ModerationLog{
631 "nickname" => admin.nickname,
634 action: "relay_follow",
635 target: "https://example.org/relay"
637 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
640 Repo.insert(%ModerationLog{
644 "nickname" => admin.nickname,
647 action: "relay_unfollow",
648 target: "https://example.org/relay"
650 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
653 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
655 response1 = json_response(conn1, 200)
656 [first_entry] = response1["items"]
658 assert response1["total"] == 2
659 assert response1["items"] |> length() == 1
660 assert first_entry["data"]["action"] == "relay_unfollow"
662 assert first_entry["message"] ==
663 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
665 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
667 response2 = json_response(conn2, 200)
668 [second_entry] = response2["items"]
670 assert response2["total"] == 2
671 assert response2["items"] |> length() == 1
672 assert second_entry["data"]["action"] == "relay_follow"
674 assert second_entry["message"] ==
675 "@#{admin.nickname} followed relay: https://example.org/relay"
678 test "filters log by date", %{conn: conn, admin: admin} do
679 first_date = "2017-08-15T15:47:06Z"
680 second_date = "2017-08-20T15:47:06Z"
682 Repo.insert(%ModerationLog{
686 "nickname" => admin.nickname,
689 action: "relay_follow",
690 target: "https://example.org/relay"
692 inserted_at: NaiveDateTime.from_iso8601!(first_date)
695 Repo.insert(%ModerationLog{
699 "nickname" => admin.nickname,
702 action: "relay_unfollow",
703 target: "https://example.org/relay"
705 inserted_at: NaiveDateTime.from_iso8601!(second_date)
711 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
714 response1 = json_response(conn1, 200)
715 [first_entry] = response1["items"]
717 assert response1["total"] == 1
718 assert first_entry["data"]["action"] == "relay_unfollow"
720 assert first_entry["message"] ==
721 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
724 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
725 Repo.insert(%ModerationLog{
729 "nickname" => admin.nickname,
732 action: "relay_follow",
733 target: "https://example.org/relay"
737 Repo.insert(%ModerationLog{
740 "id" => moderator.id,
741 "nickname" => moderator.nickname,
744 action: "relay_unfollow",
745 target: "https://example.org/relay"
749 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
751 response1 = json_response(conn1, 200)
752 [first_entry] = response1["items"]
754 assert response1["total"] == 1
755 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
758 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
759 ModerationLog.insert_log(%{
761 action: "relay_follow",
762 target: "https://example.org/relay"
765 ModerationLog.insert_log(%{
767 action: "relay_unfollow",
768 target: "https://example.org/relay"
771 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
773 response1 = json_response(conn1, 200)
774 [first_entry] = response1["items"]
776 assert response1["total"] == 1
778 assert get_in(first_entry, ["data", "message"]) ==
779 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
782 test "it requires privileged role :moderation_log_read", %{conn: conn} do
783 clear_config([:instance, :admin_privileges], [])
786 |> put_req_header("content-type", "multipart/form-data")
787 |> get("/api/pleroma/admin/moderation_log")
788 |> json_response(:forbidden)
792 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
794 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
795 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
796 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
798 assert json_response(conn, 200)
801 describe "GET /users/:nickname/credentials" do
802 test "gets the user credentials", %{conn: conn} do
803 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
805 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
807 response = assert json_response(conn, 200)
808 assert response["email"] == user.email
811 test "returns 403 if requested by a non-admin" do
812 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
817 |> assign(:user, user)
818 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
820 assert json_response(conn, :forbidden)
823 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
824 clear_config([:instance, :admin_privileges], [])
828 |> get("/api/pleroma/admin/users/nickname/credentials")
830 assert json_response(response, :forbidden)
834 describe "PATCH /users/:nickname/credentials" do
840 test "changes password and email", %{conn: conn, admin: admin, user: user} do
841 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
843 assert user.password_reset_pending == false
846 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
847 "password" => "new_password",
848 "email" => "new_email@example.com",
852 assert json_response(conn, 200) == %{"status" => "success"}
854 ObanHelpers.perform_all()
856 updated_user = User.get_by_id(user.id)
858 assert updated_user.email == "new_email@example.com"
859 assert updated_user.name == "new_name"
860 assert updated_user.password_hash != user.password_hash
861 assert updated_user.password_reset_pending == true
863 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
865 assert ModerationLog.get_log_entry_message(log_entry1) ==
866 "@#{admin.nickname} updated users: @#{user.nickname}"
868 assert ModerationLog.get_log_entry_message(log_entry2) ==
869 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
872 test "returns 403 if requested by a non-admin", %{user: user} do
875 |> assign(:user, user)
876 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
877 "password" => "new_password",
878 "email" => "new_email@example.com",
882 assert json_response(conn, :forbidden)
885 test "returns 403 if not privileged with :users_manage_credentials", %{conn: conn, user: user} do
886 clear_config([:instance, :admin_privileges], [])
889 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
890 "password" => "new_password",
891 "email" => "new_email@example.com",
895 assert json_response(conn, :forbidden)
898 test "changes actor type from permitted list", %{conn: conn, user: user} do
899 assert user.actor_type == "Person"
901 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
902 "actor_type" => "Service"
904 |> json_response(200) == %{"status" => "success"}
906 updated_user = User.get_by_id(user.id)
908 assert updated_user.actor_type == "Service"
910 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
911 "actor_type" => "Application"
913 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
916 test "update non existing user", %{conn: conn} do
917 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
918 "password" => "new_password"
920 |> json_response(404) == %{"error" => "Not found"}
924 describe "PATCH /users/:nickname/force_password_reset" do
925 test "sets password_reset_pending to true", %{conn: conn} do
926 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
928 assert user.password_reset_pending == false
931 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
933 assert empty_json_response(conn) == ""
935 ObanHelpers.perform_all()
937 assert User.get_by_id(user.id).password_reset_pending == true
940 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
941 clear_config([:instance, :admin_privileges], [])
945 |> patch("/api/pleroma/admin/users/force_password_reset", %{nickname: "nickname"})
947 assert json_response(response, :forbidden)
951 describe "PATCH /confirm_email" do
952 test "it confirms emails of two users", %{conn: conn, admin: admin} do
953 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
954 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
956 refute first_user.is_confirmed
957 refute second_user.is_confirmed
960 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
967 assert ret_conn.status == 200
969 first_user = User.get_by_id(first_user.id)
970 second_user = User.get_by_id(second_user.id)
972 assert first_user.is_confirmed
973 assert second_user.is_confirmed
975 log_entry = Repo.one(ModerationLog)
977 assert ModerationLog.get_log_entry_message(log_entry) ==
978 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}"
981 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
982 clear_config([:instance, :admin_privileges], [])
986 |> patch("/api/pleroma/admin/users/confirm_email", %{nicknames: ["nickname"]})
988 assert json_response(response, :forbidden)
992 describe "PATCH /resend_confirmation_email" do
993 test "it resend emails for two users", %{conn: conn, admin: admin} do
994 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
995 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
998 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1000 first_user.nickname,
1001 second_user.nickname
1005 assert ret_conn.status == 200
1007 log_entry = Repo.one(ModerationLog)
1009 assert ModerationLog.get_log_entry_message(log_entry) ==
1010 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{second_user.nickname}"
1012 ObanHelpers.perform_all()
1014 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
1015 # temporary hackney fix until hackney max_connections bug is fixed
1016 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
1017 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
1018 |> assert_email_sent()
1021 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
1022 clear_config([:instance, :admin_privileges], [])
1026 |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{nicknames: ["nickname"]})
1028 assert json_response(response, :forbidden)
1032 describe "/api/pleroma/admin/stats" do
1034 clear_config([:instance, :admin_privileges], [:statistics_read])
1037 test "status visibility count", %{conn: conn} do
1038 user = insert(:user)
1039 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1040 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1041 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1045 |> get("/api/pleroma/admin/stats")
1046 |> json_response(200)
1048 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1049 response["status_visibility"]
1052 test "by instance", %{conn: conn} do
1053 user1 = insert(:user)
1054 instance2 = "instance2.tld"
1055 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1057 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1058 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1059 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1063 |> get("/api/pleroma/admin/stats", instance: instance2)
1064 |> json_response(200)
1066 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1067 response["status_visibility"]
1070 test "it requires privileged role :statistics_read", %{conn: conn} do
1071 clear_config([:instance, :admin_privileges], [])
1074 |> get("/api/pleroma/admin/stats", instance: "lain.wired")
1075 |> json_response(:forbidden)
1079 describe "/api/pleroma/backups" do
1080 test "it creates a backup", %{conn: conn} do
1082 |> Mox.stub_with(Pleroma.Config)
1084 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
1085 token = insert(:oauth_admin_token, user: admin)
1086 user = %{id: user_id, nickname: user_nickname} = insert(:user)
1090 |> assign(:user, admin)
1091 |> assign(:token, token)
1092 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1093 |> json_response(200)
1095 assert [backup] = Repo.all(Pleroma.User.Backup)
1097 ObanHelpers.perform_all()
1099 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
1101 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
1102 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
1104 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
1109 "action" => "create_backup",
1112 "nickname" => ^admin_nickname
1114 "message" => ^log_message,
1117 "nickname" => ^user_nickname
1121 ] = Pleroma.ModerationLog |> Repo.all()
1124 test "it doesn't limit admins", %{conn: conn} do
1125 admin = insert(:user, is_admin: true)
1126 token = insert(:oauth_admin_token, user: admin)
1127 user = insert(:user)
1131 |> assign(:user, admin)
1132 |> assign(:token, token)
1133 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1134 |> json_response(200)
1136 assert [_backup] = Repo.all(Pleroma.User.Backup)
1140 |> assign(:user, admin)
1141 |> assign(:token, token)
1142 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1143 |> json_response(200)
1145 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
1149 describe "POST /api/v1/pleroma/admin/reload_emoji" do
1151 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
1153 admin = insert(:user, is_admin: true)
1154 token = insert(:oauth_admin_token, user: admin)
1158 |> assign(:user, admin)
1159 |> assign(:token, token)
1161 {:ok, %{conn: conn, admin: admin}}
1164 test "it requires privileged role :emoji_manage_emoji", %{conn: conn} do
1166 |> post("/api/v1/pleroma/admin/reload_emoji")
1167 |> json_response(200)
1169 clear_config([:instance, :admin_privileges], [])
1172 |> post("/api/v1/pleroma/admin/reload_emoji")
1173 |> json_response(:forbidden)
1178 # Needed for testing
1179 defmodule Pleroma.Web.Endpoint.NotReal do
1182 defmodule Pleroma.Captcha.NotReal do