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
19 alias Pleroma.Web.CommonAPI
22 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
28 admin = insert(:user, is_admin: true)
29 token = insert(:oauth_admin_token, user: admin)
33 |> assign(:user, admin)
34 |> assign(:token, token)
36 {:ok, %{admin: admin, token: token, conn: conn}}
39 test "with valid `admin_token` query parameter, skips OAuth scopes check" do
40 clear_config([:admin_token], "password123")
44 conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
46 assert json_response(conn, 200)
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)
93 describe "PUT /api/pleroma/admin/users/tag" do
94 setup %{conn: conn} do
95 clear_config([:instance, :admin_privileges], [:users_manage_tags])
97 user1 = insert(:user, %{tags: ["x"]})
98 user2 = insert(:user, %{tags: ["y"]})
99 user3 = insert(:user, %{tags: ["unchanged"]})
101 %{conn: conn, user1: user1, user2: user2, user3: user3}
104 test "it appends specified tags to users with specified nicknames", %{
112 |> put_req_header("accept", "application/json")
114 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
115 "#{user2.nickname}&tags[]=foo&tags[]=bar"
118 assert empty_json_response(conn)
119 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
120 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
122 log_entry = Repo.one(ModerationLog)
125 [user1.nickname, user2.nickname]
126 |> Enum.map(&"@#{&1}")
129 tags = ["foo", "bar"] |> Enum.join(", ")
131 assert ModerationLog.get_log_entry_message(log_entry) ==
132 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
135 test "it does not modify tags of not specified users", %{
143 |> put_req_header("accept", "application/json")
145 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
146 "#{user2.nickname}&tags[]=foo&tags[]=bar"
149 assert empty_json_response(conn)
150 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
153 test "it requires privileged role :users_manage_tags", %{conn: conn} do
154 clear_config([:instance, :admin_privileges], [])
158 |> put_req_header("accept", "application/json")
159 |> put("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar")
161 assert json_response(response, :forbidden)
165 describe "DELETE /api/pleroma/admin/users/tag" do
166 setup %{conn: conn} do
167 clear_config([:instance, :admin_privileges], [:users_manage_tags])
168 user1 = insert(:user, %{tags: ["x"]})
169 user2 = insert(:user, %{tags: ["y", "z"]})
170 user3 = insert(:user, %{tags: ["unchanged"]})
172 %{conn: conn, user1: user1, user2: user2, user3: user3}
175 test "it removes specified tags from users with specified nicknames", %{
183 |> put_req_header("accept", "application/json")
185 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
186 "#{user2.nickname}&tags[]=x&tags[]=z"
189 assert empty_json_response(conn)
190 assert User.get_cached_by_id(user1.id).tags == []
191 assert User.get_cached_by_id(user2.id).tags == ["y"]
193 log_entry = Repo.one(ModerationLog)
196 [user1.nickname, user2.nickname]
197 |> Enum.map(&"@#{&1}")
200 tags = ["x", "z"] |> Enum.join(", ")
202 assert ModerationLog.get_log_entry_message(log_entry) ==
203 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
206 test "it does not modify tags of not specified users", %{
214 |> put_req_header("accept", "application/json")
216 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
217 "#{user2.nickname}&tags[]=x&tags[]=z"
220 assert empty_json_response(conn)
221 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
224 test "it requires privileged role :users_manage_tags", %{conn: conn} do
225 clear_config([:instance, :admin_privileges], [])
229 |> put_req_header("accept", "application/json")
230 |> delete("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar")
232 assert json_response(response, :forbidden)
236 describe "/api/pleroma/admin/users/:nickname/permission_group" do
237 test "GET is giving user_info", %{admin: admin, conn: conn} do
240 |> put_req_header("accept", "application/json")
241 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
243 assert json_response(conn, 200) == %{
245 "is_moderator" => false
249 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
254 |> put_req_header("accept", "application/json")
255 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
257 assert json_response(conn, 200) == %{
261 log_entry = Repo.one(ModerationLog)
263 assert ModerationLog.get_log_entry_message(log_entry) ==
264 "@#{admin.nickname} made @#{user.nickname} admin"
267 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
268 user_one = insert(:user)
269 user_two = insert(:user)
273 |> put_req_header("accept", "application/json")
274 |> post("/api/pleroma/admin/users/permission_group/admin", %{
275 nicknames: [user_one.nickname, user_two.nickname]
278 assert json_response(conn, 200) == %{"is_admin" => true}
280 log_entry = Repo.one(ModerationLog)
282 assert ModerationLog.get_log_entry_message(log_entry) ==
283 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
286 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
287 user = insert(:user, is_admin: true)
291 |> put_req_header("accept", "application/json")
292 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
294 assert json_response(conn, 200) == %{"is_admin" => false}
296 log_entry = Repo.one(ModerationLog)
298 assert ModerationLog.get_log_entry_message(log_entry) ==
299 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
302 test "/:right DELETE, can remove from a permission group (multiple)", %{
306 user_one = insert(:user, is_admin: true)
307 user_two = insert(:user, is_admin: true)
311 |> put_req_header("accept", "application/json")
312 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
313 nicknames: [user_one.nickname, user_two.nickname]
316 assert json_response(conn, 200) == %{"is_admin" => false}
318 log_entry = Repo.one(ModerationLog)
320 assert ModerationLog.get_log_entry_message(log_entry) ==
321 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{user_two.nickname}"
325 describe "/api/pleroma/admin/users/:nickname/password_reset" do
326 test "it returns a password reset link", %{conn: conn} do
327 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
333 |> put_req_header("accept", "application/json")
334 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
336 resp = json_response(conn, 200)
338 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
341 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
342 clear_config([:instance, :admin_privileges], [])
346 |> put_req_header("accept", "application/json")
347 |> get("/api/pleroma/admin/users/nickname/password_reset")
349 assert json_response(response, :forbidden)
353 describe "PUT disable_mfa" do
354 test "returns 200 and disable 2fa", %{conn: conn} do
355 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
359 multi_factor_authentication_settings: %MFA.Settings{
361 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
367 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
368 |> json_response(200)
370 assert response == user.nickname
371 mfa_settings = refresh_record(user).multi_factor_authentication_settings
373 refute mfa_settings.enabled
374 refute mfa_settings.totp.confirmed
377 test "returns 404 if user not found", %{conn: conn} do
378 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
382 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
383 |> json_response(404)
385 assert response == %{"error" => "Not found"}
388 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
389 clear_config([:instance, :admin_privileges], [])
393 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
395 assert json_response(response, :forbidden)
399 describe "GET /api/pleroma/admin/restart" do
400 setup do: clear_config(:configurable_from_database, true)
402 test "pleroma restarts", %{conn: conn} do
404 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
405 end) =~ "pleroma restarted"
407 refute Restarter.Pleroma.need_reboot?()
411 test "need_reboot flag", %{conn: conn} do
413 |> get("/api/pleroma/admin/need_reboot")
414 |> json_response(200) == %{"need_reboot" => false}
416 Restarter.Pleroma.need_reboot()
419 |> get("/api/pleroma/admin/need_reboot")
420 |> json_response(200) == %{"need_reboot" => true}
422 on_exit(fn -> Restarter.Pleroma.refresh() end)
425 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
427 clear_config([:instance, :admin_privileges], [:messages_read])
431 insert(:note_activity, user: user)
432 insert(:note_activity, user: user)
433 insert(:note_activity, user: user)
438 test "renders user's statuses", %{conn: conn, user: user} do
439 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
441 assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
442 assert length(activities) == 3
445 test "it requires privileged role :messages_read", %{conn: conn, user: user} do
446 clear_config([:instance, :admin_privileges], [])
448 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
450 assert json_response(conn, :forbidden)
453 test "renders user's statuses with pagination", %{conn: conn, user: user} do
454 %{"total" => 3, "activities" => [activity1]} =
456 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
457 |> json_response(200)
459 %{"total" => 3, "activities" => [activity2]} =
461 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
462 |> json_response(200)
464 refute activity1 == activity2
467 test "doesn't return private statuses by default", %{conn: conn, user: user} do
468 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
470 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
472 %{"total" => 4, "activities" => activities} =
474 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
475 |> json_response(200)
477 assert length(activities) == 4
480 test "returns private statuses with godmode on", %{conn: conn, user: user} do
481 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
483 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
485 %{"total" => 5, "activities" => activities} =
487 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
488 |> json_response(200)
490 assert length(activities) == 5
493 test "excludes reblogs by default", %{conn: conn, user: user} do
494 other_user = insert(:user)
495 {:ok, activity} = CommonAPI.post(user, %{status: "."})
496 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
498 assert %{"total" => 0, "activities" => []} ==
500 |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
501 |> json_response(200)
503 assert %{"total" => 1, "activities" => [_]} =
506 "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
508 |> json_response(200)
512 describe "GET /api/pleroma/admin/users/:nickname/chats" do
514 clear_config([:instance, :admin_privileges], [:messages_read])
521 test "renders user's chats", %{conn: conn, user: user} do
522 recipients = insert_list(3, :user)
524 Enum.each(recipients, fn recipient ->
525 CommonAPI.post_chat_message(user, recipient, "yo")
528 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
530 assert json_response(conn, 200) |> length() == 3
533 test "it requires privileged role :messages_read", %{conn: conn, user: user} do
534 clear_config([:instance, :admin_privileges], [])
536 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
538 assert json_response(conn, :forbidden)
542 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
545 recipient = insert(:user)
546 CommonAPI.post_chat_message(user, recipient, "yo")
547 %{conn: conn} = oauth_access(["read:chats"])
548 %{conn: conn, user: user}
551 test "returns 403", %{conn: conn, user: user} do
553 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
554 |> json_response(403)
558 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
561 recipient = insert(:user)
562 CommonAPI.post_chat_message(user, recipient, "yo")
563 %{conn: build_conn(), user: user}
566 test "returns 403", %{conn: conn, user: user} do
568 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
569 |> json_response(403)
573 describe "GET /api/pleroma/admin/moderation_log" do
575 clear_config([:instance, :admin_privileges], [:moderation_log_read])
576 moderator = insert(:user, is_moderator: true)
578 %{moderator: moderator}
581 test "returns the log", %{conn: conn, admin: admin} do
582 Repo.insert(%ModerationLog{
586 "nickname" => admin.nickname,
589 action: "relay_follow",
590 target: "https://example.org/relay"
592 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
595 Repo.insert(%ModerationLog{
599 "nickname" => admin.nickname,
602 action: "relay_unfollow",
603 target: "https://example.org/relay"
605 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
608 conn = get(conn, "/api/pleroma/admin/moderation_log")
610 response = json_response(conn, 200)
611 [first_entry, second_entry] = response["items"]
613 assert response["total"] == 2
614 assert first_entry["data"]["action"] == "relay_unfollow"
616 assert first_entry["message"] ==
617 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
619 assert second_entry["data"]["action"] == "relay_follow"
621 assert second_entry["message"] ==
622 "@#{admin.nickname} followed relay: https://example.org/relay"
625 test "returns the log with pagination", %{conn: conn, admin: admin} do
626 Repo.insert(%ModerationLog{
630 "nickname" => admin.nickname,
633 action: "relay_follow",
634 target: "https://example.org/relay"
636 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
639 Repo.insert(%ModerationLog{
643 "nickname" => admin.nickname,
646 action: "relay_unfollow",
647 target: "https://example.org/relay"
649 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
652 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
654 response1 = json_response(conn1, 200)
655 [first_entry] = response1["items"]
657 assert response1["total"] == 2
658 assert response1["items"] |> length() == 1
659 assert first_entry["data"]["action"] == "relay_unfollow"
661 assert first_entry["message"] ==
662 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
664 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
666 response2 = json_response(conn2, 200)
667 [second_entry] = response2["items"]
669 assert response2["total"] == 2
670 assert response2["items"] |> length() == 1
671 assert second_entry["data"]["action"] == "relay_follow"
673 assert second_entry["message"] ==
674 "@#{admin.nickname} followed relay: https://example.org/relay"
677 test "filters log by date", %{conn: conn, admin: admin} do
678 first_date = "2017-08-15T15:47:06Z"
679 second_date = "2017-08-20T15:47:06Z"
681 Repo.insert(%ModerationLog{
685 "nickname" => admin.nickname,
688 action: "relay_follow",
689 target: "https://example.org/relay"
691 inserted_at: NaiveDateTime.from_iso8601!(first_date)
694 Repo.insert(%ModerationLog{
698 "nickname" => admin.nickname,
701 action: "relay_unfollow",
702 target: "https://example.org/relay"
704 inserted_at: NaiveDateTime.from_iso8601!(second_date)
710 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
713 response1 = json_response(conn1, 200)
714 [first_entry] = response1["items"]
716 assert response1["total"] == 1
717 assert first_entry["data"]["action"] == "relay_unfollow"
719 assert first_entry["message"] ==
720 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
723 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
724 Repo.insert(%ModerationLog{
728 "nickname" => admin.nickname,
731 action: "relay_follow",
732 target: "https://example.org/relay"
736 Repo.insert(%ModerationLog{
739 "id" => moderator.id,
740 "nickname" => moderator.nickname,
743 action: "relay_unfollow",
744 target: "https://example.org/relay"
748 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
750 response1 = json_response(conn1, 200)
751 [first_entry] = response1["items"]
753 assert response1["total"] == 1
754 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
757 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
758 ModerationLog.insert_log(%{
760 action: "relay_follow",
761 target: "https://example.org/relay"
764 ModerationLog.insert_log(%{
766 action: "relay_unfollow",
767 target: "https://example.org/relay"
770 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
772 response1 = json_response(conn1, 200)
773 [first_entry] = response1["items"]
775 assert response1["total"] == 1
777 assert get_in(first_entry, ["data", "message"]) ==
778 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
781 test "it requires privileged role :moderation_log_read", %{conn: conn} do
782 clear_config([:instance, :admin_privileges], [])
785 |> put_req_header("content-type", "multipart/form-data")
786 |> get("/api/pleroma/admin/moderation_log")
787 |> json_response(:forbidden)
791 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
793 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
794 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
795 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
797 assert json_response(conn, 200)
800 describe "GET /users/:nickname/credentials" do
801 test "gets the user credentials", %{conn: conn} do
802 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
804 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
806 response = assert json_response(conn, 200)
807 assert response["email"] == user.email
810 test "returns 403 if requested by a non-admin" do
811 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
816 |> assign(:user, user)
817 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
819 assert json_response(conn, :forbidden)
822 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
823 clear_config([:instance, :admin_privileges], [])
827 |> get("/api/pleroma/admin/users/nickname/credentials")
829 assert json_response(response, :forbidden)
833 describe "PATCH /users/:nickname/credentials" do
839 test "changes password and email", %{conn: conn, admin: admin, user: user} do
840 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
842 assert user.password_reset_pending == false
845 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
846 "password" => "new_password",
847 "email" => "new_email@example.com",
851 assert json_response(conn, 200) == %{"status" => "success"}
853 ObanHelpers.perform_all()
855 updated_user = User.get_by_id(user.id)
857 assert updated_user.email == "new_email@example.com"
858 assert updated_user.name == "new_name"
859 assert updated_user.password_hash != user.password_hash
860 assert updated_user.password_reset_pending == true
862 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
864 assert ModerationLog.get_log_entry_message(log_entry1) ==
865 "@#{admin.nickname} updated users: @#{user.nickname}"
867 assert ModerationLog.get_log_entry_message(log_entry2) ==
868 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
871 test "returns 403 if requested by a non-admin", %{user: user} do
874 |> assign(:user, user)
875 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
876 "password" => "new_password",
877 "email" => "new_email@example.com",
881 assert json_response(conn, :forbidden)
884 test "returns 403 if not privileged with :users_manage_credentials", %{conn: conn, user: user} do
885 clear_config([:instance, :admin_privileges], [])
888 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
889 "password" => "new_password",
890 "email" => "new_email@example.com",
894 assert json_response(conn, :forbidden)
897 test "changes actor type from permitted list", %{conn: conn, user: user} do
898 assert user.actor_type == "Person"
900 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
901 "actor_type" => "Service"
903 |> json_response(200) == %{"status" => "success"}
905 updated_user = User.get_by_id(user.id)
907 assert updated_user.actor_type == "Service"
909 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
910 "actor_type" => "Application"
912 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
915 test "update non existing user", %{conn: conn} do
916 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
917 "password" => "new_password"
919 |> json_response(404) == %{"error" => "Not found"}
923 describe "PATCH /users/:nickname/force_password_reset" do
924 test "sets password_reset_pending to true", %{conn: conn} do
925 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
927 assert user.password_reset_pending == false
930 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
932 assert empty_json_response(conn) == ""
934 ObanHelpers.perform_all()
936 assert User.get_by_id(user.id).password_reset_pending == true
939 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
940 clear_config([:instance, :admin_privileges], [])
944 |> patch("/api/pleroma/admin/users/force_password_reset", %{nickname: "nickname"})
946 assert json_response(response, :forbidden)
950 describe "PATCH /confirm_email" do
951 test "it confirms emails of two users", %{conn: conn, admin: admin} do
952 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
953 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
955 refute first_user.is_confirmed
956 refute second_user.is_confirmed
959 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
966 assert ret_conn.status == 200
968 first_user = User.get_by_id(first_user.id)
969 second_user = User.get_by_id(second_user.id)
971 assert first_user.is_confirmed
972 assert second_user.is_confirmed
974 log_entry = Repo.one(ModerationLog)
976 assert ModerationLog.get_log_entry_message(log_entry) ==
977 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}"
980 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
981 clear_config([:instance, :admin_privileges], [])
985 |> patch("/api/pleroma/admin/users/confirm_email", %{nicknames: ["nickname"]})
987 assert json_response(response, :forbidden)
991 describe "PATCH /resend_confirmation_email" do
992 test "it resend emails for two users", %{conn: conn, admin: admin} do
993 clear_config([:instance, :admin_privileges], [:users_manage_credentials])
994 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
997 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1000 second_user.nickname
1004 assert ret_conn.status == 200
1006 log_entry = Repo.one(ModerationLog)
1008 assert ModerationLog.get_log_entry_message(log_entry) ==
1009 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{second_user.nickname}"
1011 ObanHelpers.perform_all()
1013 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
1014 # temporary hackney fix until hackney max_connections bug is fixed
1015 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
1016 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
1017 |> assert_email_sent()
1020 test "it requires privileged role :users_manage_credentials", %{conn: conn} do
1021 clear_config([:instance, :admin_privileges], [])
1025 |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{nicknames: ["nickname"]})
1027 assert json_response(response, :forbidden)
1031 describe "/api/pleroma/admin/stats" do
1033 clear_config([:instance, :admin_privileges], [:statistics_read])
1036 test "status visibility count", %{conn: conn} do
1037 user = insert(:user)
1038 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1039 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1040 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1044 |> get("/api/pleroma/admin/stats")
1045 |> json_response(200)
1047 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1048 response["status_visibility"]
1051 test "by instance", %{conn: conn} do
1052 user1 = insert(:user)
1053 instance2 = "instance2.tld"
1054 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1056 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1057 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1058 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1062 |> get("/api/pleroma/admin/stats", instance: instance2)
1063 |> json_response(200)
1065 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1066 response["status_visibility"]
1069 test "it requires privileged role :statistics_read", %{conn: conn} do
1070 clear_config([:instance, :admin_privileges], [])
1073 |> get("/api/pleroma/admin/stats", instance: "lain.wired")
1074 |> json_response(:forbidden)
1078 describe "/api/pleroma/backups" do
1079 test "it creates a backup", %{conn: conn} do
1080 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
1081 token = insert(:oauth_admin_token, user: admin)
1082 user = %{id: user_id, nickname: user_nickname} = insert(:user)
1086 |> assign(:user, admin)
1087 |> assign(:token, token)
1088 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1089 |> json_response(200)
1091 assert [backup] = Repo.all(Pleroma.User.Backup)
1093 ObanHelpers.perform_all()
1095 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
1097 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
1098 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
1100 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
1105 "action" => "create_backup",
1108 "nickname" => ^admin_nickname
1110 "message" => ^log_message,
1113 "nickname" => ^user_nickname
1117 ] = Pleroma.ModerationLog |> Repo.all()
1120 test "it doesn't limit admins", %{conn: conn} do
1121 admin = insert(:user, is_admin: true)
1122 token = insert(:oauth_admin_token, user: admin)
1123 user = insert(:user)
1127 |> assign(:user, admin)
1128 |> assign(:token, token)
1129 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1130 |> json_response(200)
1132 assert [_backup] = Repo.all(Pleroma.User.Backup)
1136 |> assign(:user, admin)
1137 |> assign(:token, token)
1138 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1139 |> json_response(200)
1141 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
1145 describe "POST /api/v1/pleroma/admin/reload_emoji" do
1147 clear_config([:instance, :admin_privileges], [:emoji_manage_emoji])
1149 admin = insert(:user, is_admin: true)
1150 token = insert(:oauth_admin_token, user: admin)
1154 |> assign(:user, admin)
1155 |> assign(:token, token)
1157 {:ok, %{conn: conn, admin: admin}}
1160 test "it requires privileged role :emoji_manage_emoji", %{conn: conn} do
1162 |> post("/api/v1/pleroma/admin/reload_emoji")
1163 |> json_response(200)
1165 clear_config([:instance, :admin_privileges], [])
1168 |> post("/api/v1/pleroma/admin/reload_emoji")
1169 |> json_response(:forbidden)
1174 # Needed for testing
1175 defmodule Pleroma.Web.Endpoint.NotReal do
1178 defmodule Pleroma.Captcha.NotReal do