Merge remote-tracking branch 'pleroma/develop' into instance-deletion
[akkoma] / test / pleroma / web / admin_api / controllers / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 import ExUnit.CaptureLog
10 import Pleroma.Factory
11 import Swoosh.TestAssertions
12
13 alias Pleroma.Activity
14 alias Pleroma.MFA
15 alias Pleroma.ModerationLog
16 alias Pleroma.Repo
17 alias Pleroma.Tests.ObanHelpers
18 alias Pleroma.User
19 alias Pleroma.Web.CommonAPI
20
21 setup_all do
22 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
23
24 :ok
25 end
26
27 setup do
28 admin = insert(:user, is_admin: true)
29 token = insert(:oauth_admin_token, user: admin)
30
31 conn =
32 build_conn()
33 |> assign(:user, admin)
34 |> assign(:token, token)
35
36 {:ok, %{admin: admin, token: token, conn: conn}}
37 end
38
39 test "with valid `admin_token` query parameter, skips OAuth scopes check" do
40 clear_config([:admin_token], "password123")
41
42 user = insert(:user)
43
44 conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
45
46 assert json_response(conn, 200)
47 end
48
49 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
50 %{admin: admin} do
51 user = insert(:user)
52 url = "/api/pleroma/admin/users/#{user.nickname}"
53
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"])
57
58 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
59 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
60 bad_token3 = nil
61
62 for good_token <- [good_token1, good_token2, good_token3] do
63 conn =
64 build_conn()
65 |> assign(:user, admin)
66 |> assign(:token, good_token)
67 |> get(url)
68
69 assert json_response(conn, 200)
70 end
71
72 for good_token <- [good_token1, good_token2, good_token3] do
73 conn =
74 build_conn()
75 |> assign(:user, nil)
76 |> assign(:token, good_token)
77 |> get(url)
78
79 assert json_response(conn, :forbidden)
80 end
81
82 for bad_token <- [bad_token1, bad_token2, bad_token3] do
83 conn =
84 build_conn()
85 |> assign(:user, admin)
86 |> assign(:token, bad_token)
87 |> get(url)
88
89 assert json_response(conn, :forbidden)
90 end
91 end
92
93 describe "PUT /api/pleroma/admin/users/tag" do
94 setup %{conn: conn} do
95 user1 = insert(:user, %{tags: ["x"]})
96 user2 = insert(:user, %{tags: ["y"]})
97 user3 = insert(:user, %{tags: ["unchanged"]})
98
99 conn =
100 conn
101 |> put_req_header("accept", "application/json")
102 |> put(
103 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
104 "#{user2.nickname}&tags[]=foo&tags[]=bar"
105 )
106
107 %{conn: conn, user1: user1, user2: user2, user3: user3}
108 end
109
110 test "it appends specified tags to users with specified nicknames", %{
111 conn: conn,
112 admin: admin,
113 user1: user1,
114 user2: user2
115 } do
116 assert empty_json_response(conn)
117 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
118 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
119
120 log_entry = Repo.one(ModerationLog)
121
122 users =
123 [user1.nickname, user2.nickname]
124 |> Enum.map(&"@#{&1}")
125 |> Enum.join(", ")
126
127 tags = ["foo", "bar"] |> Enum.join(", ")
128
129 assert ModerationLog.get_log_entry_message(log_entry) ==
130 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
131 end
132
133 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
134 assert empty_json_response(conn)
135 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
136 end
137 end
138
139 describe "DELETE /api/pleroma/admin/users/tag" do
140 setup %{conn: conn} do
141 user1 = insert(:user, %{tags: ["x"]})
142 user2 = insert(:user, %{tags: ["y", "z"]})
143 user3 = insert(:user, %{tags: ["unchanged"]})
144
145 conn =
146 conn
147 |> put_req_header("accept", "application/json")
148 |> delete(
149 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
150 "#{user2.nickname}&tags[]=x&tags[]=z"
151 )
152
153 %{conn: conn, user1: user1, user2: user2, user3: user3}
154 end
155
156 test "it removes specified tags from users with specified nicknames", %{
157 conn: conn,
158 admin: admin,
159 user1: user1,
160 user2: user2
161 } do
162 assert empty_json_response(conn)
163 assert User.get_cached_by_id(user1.id).tags == []
164 assert User.get_cached_by_id(user2.id).tags == ["y"]
165
166 log_entry = Repo.one(ModerationLog)
167
168 users =
169 [user1.nickname, user2.nickname]
170 |> Enum.map(&"@#{&1}")
171 |> Enum.join(", ")
172
173 tags = ["x", "z"] |> Enum.join(", ")
174
175 assert ModerationLog.get_log_entry_message(log_entry) ==
176 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
177 end
178
179 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
180 assert empty_json_response(conn)
181 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
182 end
183 end
184
185 describe "/api/pleroma/admin/users/:nickname/permission_group" do
186 test "GET is giving user_info", %{admin: admin, conn: conn} do
187 conn =
188 conn
189 |> put_req_header("accept", "application/json")
190 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
191
192 assert json_response(conn, 200) == %{
193 "is_admin" => true,
194 "is_moderator" => false
195 }
196 end
197
198 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
199 user = insert(:user)
200
201 conn =
202 conn
203 |> put_req_header("accept", "application/json")
204 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
205
206 assert json_response(conn, 200) == %{
207 "is_admin" => true
208 }
209
210 log_entry = Repo.one(ModerationLog)
211
212 assert ModerationLog.get_log_entry_message(log_entry) ==
213 "@#{admin.nickname} made @#{user.nickname} admin"
214 end
215
216 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
217 user_one = insert(:user)
218 user_two = insert(:user)
219
220 conn =
221 conn
222 |> put_req_header("accept", "application/json")
223 |> post("/api/pleroma/admin/users/permission_group/admin", %{
224 nicknames: [user_one.nickname, user_two.nickname]
225 })
226
227 assert json_response(conn, 200) == %{"is_admin" => true}
228
229 log_entry = Repo.one(ModerationLog)
230
231 assert ModerationLog.get_log_entry_message(log_entry) ==
232 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
233 end
234
235 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
236 user = insert(:user, is_admin: true)
237
238 conn =
239 conn
240 |> put_req_header("accept", "application/json")
241 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
242
243 assert json_response(conn, 200) == %{"is_admin" => false}
244
245 log_entry = Repo.one(ModerationLog)
246
247 assert ModerationLog.get_log_entry_message(log_entry) ==
248 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
249 end
250
251 test "/:right DELETE, can remove from a permission group (multiple)", %{
252 admin: admin,
253 conn: conn
254 } do
255 user_one = insert(:user, is_admin: true)
256 user_two = insert(:user, is_admin: true)
257
258 conn =
259 conn
260 |> put_req_header("accept", "application/json")
261 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
262 nicknames: [user_one.nickname, user_two.nickname]
263 })
264
265 assert json_response(conn, 200) == %{"is_admin" => false}
266
267 log_entry = Repo.one(ModerationLog)
268
269 assert ModerationLog.get_log_entry_message(log_entry) ==
270 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
271 user_two.nickname
272 }"
273 end
274 end
275
276 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
277 user = insert(:user)
278
279 conn =
280 conn
281 |> put_req_header("accept", "application/json")
282 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
283
284 resp = json_response(conn, 200)
285
286 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
287 end
288
289 describe "PUT disable_mfa" do
290 test "returns 200 and disable 2fa", %{conn: conn} do
291 user =
292 insert(:user,
293 multi_factor_authentication_settings: %MFA.Settings{
294 enabled: true,
295 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
296 }
297 )
298
299 response =
300 conn
301 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
302 |> json_response(200)
303
304 assert response == user.nickname
305 mfa_settings = refresh_record(user).multi_factor_authentication_settings
306
307 refute mfa_settings.enabled
308 refute mfa_settings.totp.confirmed
309 end
310
311 test "returns 404 if user not found", %{conn: conn} do
312 response =
313 conn
314 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
315 |> json_response(404)
316
317 assert response == %{"error" => "Not found"}
318 end
319 end
320
321 describe "GET /api/pleroma/admin/restart" do
322 setup do: clear_config(:configurable_from_database, true)
323
324 test "pleroma restarts", %{conn: conn} do
325 capture_log(fn ->
326 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
327 end) =~ "pleroma restarted"
328
329 refute Restarter.Pleroma.need_reboot?()
330 end
331 end
332
333 test "need_reboot flag", %{conn: conn} do
334 assert conn
335 |> get("/api/pleroma/admin/need_reboot")
336 |> json_response(200) == %{"need_reboot" => false}
337
338 Restarter.Pleroma.need_reboot()
339
340 assert conn
341 |> get("/api/pleroma/admin/need_reboot")
342 |> json_response(200) == %{"need_reboot" => true}
343
344 on_exit(fn -> Restarter.Pleroma.refresh() end)
345 end
346
347 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
348 setup do
349 user = insert(:user)
350
351 insert(:note_activity, user: user)
352 insert(:note_activity, user: user)
353 insert(:note_activity, user: user)
354
355 %{user: user}
356 end
357
358 test "renders user's statuses", %{conn: conn, user: user} do
359 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
360
361 assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
362 assert length(activities) == 3
363 end
364
365 test "renders user's statuses with pagination", %{conn: conn, user: user} do
366 %{"total" => 3, "activities" => [activity1]} =
367 conn
368 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
369 |> json_response(200)
370
371 %{"total" => 3, "activities" => [activity2]} =
372 conn
373 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
374 |> json_response(200)
375
376 refute activity1 == activity2
377 end
378
379 test "doesn't return private statuses by default", %{conn: conn, user: user} do
380 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
381
382 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
383
384 %{"total" => 4, "activities" => activities} =
385 conn
386 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
387 |> json_response(200)
388
389 assert length(activities) == 4
390 end
391
392 test "returns private statuses with godmode on", %{conn: conn, user: user} do
393 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
394
395 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
396
397 %{"total" => 5, "activities" => activities} =
398 conn
399 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
400 |> json_response(200)
401
402 assert length(activities) == 5
403 end
404
405 test "excludes reblogs by default", %{conn: conn, user: user} do
406 other_user = insert(:user)
407 {:ok, activity} = CommonAPI.post(user, %{status: "."})
408 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
409
410 assert %{"total" => 0, "activities" => []} ==
411 conn
412 |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
413 |> json_response(200)
414
415 assert %{"total" => 1, "activities" => [_]} =
416 conn
417 |> get(
418 "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
419 )
420 |> json_response(200)
421 end
422 end
423
424 describe "GET /api/pleroma/admin/users/:nickname/chats" do
425 setup do
426 user = insert(:user)
427 recipients = insert_list(3, :user)
428
429 Enum.each(recipients, fn recipient ->
430 CommonAPI.post_chat_message(user, recipient, "yo")
431 end)
432
433 %{user: user}
434 end
435
436 test "renders user's chats", %{conn: conn, user: user} do
437 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
438
439 assert json_response(conn, 200) |> length() == 3
440 end
441 end
442
443 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
444 setup do
445 user = insert(:user)
446 recipient = insert(:user)
447 CommonAPI.post_chat_message(user, recipient, "yo")
448 %{conn: conn} = oauth_access(["read:chats"])
449 %{conn: conn, user: user}
450 end
451
452 test "returns 403", %{conn: conn, user: user} do
453 conn
454 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
455 |> json_response(403)
456 end
457 end
458
459 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
460 setup do
461 user = insert(:user)
462 recipient = insert(:user)
463 CommonAPI.post_chat_message(user, recipient, "yo")
464 %{conn: build_conn(), user: user}
465 end
466
467 test "returns 403", %{conn: conn, user: user} do
468 conn
469 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
470 |> json_response(403)
471 end
472 end
473
474 describe "GET /api/pleroma/admin/moderation_log" do
475 setup do
476 moderator = insert(:user, is_moderator: true)
477
478 %{moderator: moderator}
479 end
480
481 test "returns the log", %{conn: conn, admin: admin} do
482 Repo.insert(%ModerationLog{
483 data: %{
484 actor: %{
485 "id" => admin.id,
486 "nickname" => admin.nickname,
487 "type" => "user"
488 },
489 action: "relay_follow",
490 target: "https://example.org/relay"
491 },
492 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
493 })
494
495 Repo.insert(%ModerationLog{
496 data: %{
497 actor: %{
498 "id" => admin.id,
499 "nickname" => admin.nickname,
500 "type" => "user"
501 },
502 action: "relay_unfollow",
503 target: "https://example.org/relay"
504 },
505 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
506 })
507
508 conn = get(conn, "/api/pleroma/admin/moderation_log")
509
510 response = json_response(conn, 200)
511 [first_entry, second_entry] = response["items"]
512
513 assert response["total"] == 2
514 assert first_entry["data"]["action"] == "relay_unfollow"
515
516 assert first_entry["message"] ==
517 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
518
519 assert second_entry["data"]["action"] == "relay_follow"
520
521 assert second_entry["message"] ==
522 "@#{admin.nickname} followed relay: https://example.org/relay"
523 end
524
525 test "returns the log with pagination", %{conn: conn, admin: admin} do
526 Repo.insert(%ModerationLog{
527 data: %{
528 actor: %{
529 "id" => admin.id,
530 "nickname" => admin.nickname,
531 "type" => "user"
532 },
533 action: "relay_follow",
534 target: "https://example.org/relay"
535 },
536 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
537 })
538
539 Repo.insert(%ModerationLog{
540 data: %{
541 actor: %{
542 "id" => admin.id,
543 "nickname" => admin.nickname,
544 "type" => "user"
545 },
546 action: "relay_unfollow",
547 target: "https://example.org/relay"
548 },
549 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
550 })
551
552 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
553
554 response1 = json_response(conn1, 200)
555 [first_entry] = response1["items"]
556
557 assert response1["total"] == 2
558 assert response1["items"] |> length() == 1
559 assert first_entry["data"]["action"] == "relay_unfollow"
560
561 assert first_entry["message"] ==
562 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
563
564 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
565
566 response2 = json_response(conn2, 200)
567 [second_entry] = response2["items"]
568
569 assert response2["total"] == 2
570 assert response2["items"] |> length() == 1
571 assert second_entry["data"]["action"] == "relay_follow"
572
573 assert second_entry["message"] ==
574 "@#{admin.nickname} followed relay: https://example.org/relay"
575 end
576
577 test "filters log by date", %{conn: conn, admin: admin} do
578 first_date = "2017-08-15T15:47:06Z"
579 second_date = "2017-08-20T15:47:06Z"
580
581 Repo.insert(%ModerationLog{
582 data: %{
583 actor: %{
584 "id" => admin.id,
585 "nickname" => admin.nickname,
586 "type" => "user"
587 },
588 action: "relay_follow",
589 target: "https://example.org/relay"
590 },
591 inserted_at: NaiveDateTime.from_iso8601!(first_date)
592 })
593
594 Repo.insert(%ModerationLog{
595 data: %{
596 actor: %{
597 "id" => admin.id,
598 "nickname" => admin.nickname,
599 "type" => "user"
600 },
601 action: "relay_unfollow",
602 target: "https://example.org/relay"
603 },
604 inserted_at: NaiveDateTime.from_iso8601!(second_date)
605 })
606
607 conn1 =
608 get(
609 conn,
610 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
611 )
612
613 response1 = json_response(conn1, 200)
614 [first_entry] = response1["items"]
615
616 assert response1["total"] == 1
617 assert first_entry["data"]["action"] == "relay_unfollow"
618
619 assert first_entry["message"] ==
620 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
621 end
622
623 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
624 Repo.insert(%ModerationLog{
625 data: %{
626 actor: %{
627 "id" => admin.id,
628 "nickname" => admin.nickname,
629 "type" => "user"
630 },
631 action: "relay_follow",
632 target: "https://example.org/relay"
633 }
634 })
635
636 Repo.insert(%ModerationLog{
637 data: %{
638 actor: %{
639 "id" => moderator.id,
640 "nickname" => moderator.nickname,
641 "type" => "user"
642 },
643 action: "relay_unfollow",
644 target: "https://example.org/relay"
645 }
646 })
647
648 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
649
650 response1 = json_response(conn1, 200)
651 [first_entry] = response1["items"]
652
653 assert response1["total"] == 1
654 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
655 end
656
657 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
658 ModerationLog.insert_log(%{
659 actor: moderator,
660 action: "relay_follow",
661 target: "https://example.org/relay"
662 })
663
664 ModerationLog.insert_log(%{
665 actor: moderator,
666 action: "relay_unfollow",
667 target: "https://example.org/relay"
668 })
669
670 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
671
672 response1 = json_response(conn1, 200)
673 [first_entry] = response1["items"]
674
675 assert response1["total"] == 1
676
677 assert get_in(first_entry, ["data", "message"]) ==
678 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
679 end
680 end
681
682 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
683 %{conn: conn} do
684 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
685 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
686 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
687
688 assert json_response(conn, 200)
689 end
690
691 describe "GET /users/:nickname/credentials" do
692 test "gets the user credentials", %{conn: conn} do
693 user = insert(:user)
694 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
695
696 response = assert json_response(conn, 200)
697 assert response["email"] == user.email
698 end
699
700 test "returns 403 if requested by a non-admin" do
701 user = insert(:user)
702
703 conn =
704 build_conn()
705 |> assign(:user, user)
706 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
707
708 assert json_response(conn, :forbidden)
709 end
710 end
711
712 describe "PATCH /users/:nickname/credentials" do
713 setup do
714 user = insert(:user)
715 [user: user]
716 end
717
718 test "changes password and email", %{conn: conn, admin: admin, user: user} do
719 assert user.password_reset_pending == false
720
721 conn =
722 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
723 "password" => "new_password",
724 "email" => "new_email@example.com",
725 "name" => "new_name"
726 })
727
728 assert json_response(conn, 200) == %{"status" => "success"}
729
730 ObanHelpers.perform_all()
731
732 updated_user = User.get_by_id(user.id)
733
734 assert updated_user.email == "new_email@example.com"
735 assert updated_user.name == "new_name"
736 assert updated_user.password_hash != user.password_hash
737 assert updated_user.password_reset_pending == true
738
739 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
740
741 assert ModerationLog.get_log_entry_message(log_entry1) ==
742 "@#{admin.nickname} updated users: @#{user.nickname}"
743
744 assert ModerationLog.get_log_entry_message(log_entry2) ==
745 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
746 end
747
748 test "returns 403 if requested by a non-admin", %{user: user} do
749 conn =
750 build_conn()
751 |> assign(:user, user)
752 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
753 "password" => "new_password",
754 "email" => "new_email@example.com",
755 "name" => "new_name"
756 })
757
758 assert json_response(conn, :forbidden)
759 end
760
761 test "changes actor type from permitted list", %{conn: conn, user: user} do
762 assert user.actor_type == "Person"
763
764 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
765 "actor_type" => "Service"
766 })
767 |> json_response(200) == %{"status" => "success"}
768
769 updated_user = User.get_by_id(user.id)
770
771 assert updated_user.actor_type == "Service"
772
773 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
774 "actor_type" => "Application"
775 })
776 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
777 end
778
779 test "update non existing user", %{conn: conn} do
780 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
781 "password" => "new_password"
782 })
783 |> json_response(404) == %{"error" => "Not found"}
784 end
785 end
786
787 describe "PATCH /users/:nickname/force_password_reset" do
788 test "sets password_reset_pending to true", %{conn: conn} do
789 user = insert(:user)
790 assert user.password_reset_pending == false
791
792 conn =
793 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
794
795 assert empty_json_response(conn) == ""
796
797 ObanHelpers.perform_all()
798
799 assert User.get_by_id(user.id).password_reset_pending == true
800 end
801 end
802
803 describe "PATCH /confirm_email" do
804 test "it confirms emails of two users", %{conn: conn, admin: admin} do
805 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
806
807 refute first_user.is_confirmed
808 refute second_user.is_confirmed
809
810 ret_conn =
811 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
812 nicknames: [
813 first_user.nickname,
814 second_user.nickname
815 ]
816 })
817
818 assert ret_conn.status == 200
819
820 first_user = User.get_by_id(first_user.id)
821 second_user = User.get_by_id(second_user.id)
822
823 assert first_user.is_confirmed
824 assert second_user.is_confirmed
825
826 log_entry = Repo.one(ModerationLog)
827
828 assert ModerationLog.get_log_entry_message(log_entry) ==
829 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
830 second_user.nickname
831 }"
832 end
833 end
834
835 describe "PATCH /resend_confirmation_email" do
836 test "it resend emails for two users", %{conn: conn, admin: admin} do
837 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
838
839 ret_conn =
840 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
841 nicknames: [
842 first_user.nickname,
843 second_user.nickname
844 ]
845 })
846
847 assert ret_conn.status == 200
848
849 log_entry = Repo.one(ModerationLog)
850
851 assert ModerationLog.get_log_entry_message(log_entry) ==
852 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
853 second_user.nickname
854 }"
855
856 ObanHelpers.perform_all()
857
858 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
859 # temporary hackney fix until hackney max_connections bug is fixed
860 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
861 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
862 |> assert_email_sent()
863 end
864 end
865
866 describe "/api/pleroma/admin/stats" do
867 test "status visibility count", %{conn: conn} do
868 user = insert(:user)
869 CommonAPI.post(user, %{visibility: "public", status: "hey"})
870 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
871 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
872
873 response =
874 conn
875 |> get("/api/pleroma/admin/stats")
876 |> json_response(200)
877
878 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
879 response["status_visibility"]
880 end
881
882 test "by instance", %{conn: conn} do
883 user1 = insert(:user)
884 instance2 = "instance2.tld"
885 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
886
887 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
888 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
889 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
890
891 response =
892 conn
893 |> get("/api/pleroma/admin/stats", instance: instance2)
894 |> json_response(200)
895
896 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
897 response["status_visibility"]
898 end
899 end
900
901 describe "/api/pleroma/backups" do
902 test "it creates a backup", %{conn: conn} do
903 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
904 token = insert(:oauth_admin_token, user: admin)
905 user = %{id: user_id, nickname: user_nickname} = insert(:user)
906
907 assert "" ==
908 conn
909 |> assign(:user, admin)
910 |> assign(:token, token)
911 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
912 |> json_response(200)
913
914 assert [backup] = Repo.all(Pleroma.User.Backup)
915
916 ObanHelpers.perform_all()
917
918 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
919
920 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
921 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
922
923 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
924
925 assert [
926 %{
927 data: %{
928 "action" => "create_backup",
929 "actor" => %{
930 "id" => ^admin_id,
931 "nickname" => ^admin_nickname
932 },
933 "message" => ^log_message,
934 "subject" => %{
935 "id" => ^user_id,
936 "nickname" => ^user_nickname
937 }
938 }
939 }
940 ] = Pleroma.ModerationLog |> Repo.all()
941 end
942
943 test "it doesn't limit admins", %{conn: conn} do
944 admin = insert(:user, is_admin: true)
945 token = insert(:oauth_admin_token, user: admin)
946 user = insert(:user)
947
948 assert "" ==
949 conn
950 |> assign(:user, admin)
951 |> assign(:token, token)
952 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
953 |> json_response(200)
954
955 assert [_backup] = Repo.all(Pleroma.User.Backup)
956
957 assert "" ==
958 conn
959 |> assign(:user, admin)
960 |> assign(:token, token)
961 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
962 |> json_response(200)
963
964 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
965 end
966 end
967 end
968
969 # Needed for testing
970 defmodule Pleroma.Web.Endpoint.NotReal do
971 end
972
973 defmodule Pleroma.Captcha.NotReal do
974 end