8cd9f939b20312ca64553e47a1b39c78b9ba63c3
[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 "instances" do
804 test "GET /instances/:instance/statuses", %{conn: conn} do
805 user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme")
806 user2 = insert(:user, local: false, ap_id: "https://test.com/users/test")
807 insert_pair(:note_activity, user: user)
808 activity = insert(:note_activity, user: user2)
809
810 %{"total" => 2, "activities" => activities} =
811 conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
812
813 assert length(activities) == 2
814
815 %{"total" => 1, "activities" => [_]} =
816 conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200)
817
818 %{"total" => 0, "activities" => []} =
819 conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200)
820
821 CommonAPI.repeat(activity.id, user)
822
823 %{"total" => 2, "activities" => activities} =
824 conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
825
826 assert length(activities) == 2
827
828 %{"total" => 3, "activities" => activities} =
829 conn
830 |> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
831 |> json_response(200)
832
833 assert length(activities) == 3
834 end
835 end
836
837 describe "PATCH /confirm_email" do
838 test "it confirms emails of two users", %{conn: conn, admin: admin} do
839 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
840
841 refute first_user.is_confirmed
842 refute second_user.is_confirmed
843
844 ret_conn =
845 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
846 nicknames: [
847 first_user.nickname,
848 second_user.nickname
849 ]
850 })
851
852 assert ret_conn.status == 200
853
854 first_user = User.get_by_id(first_user.id)
855 second_user = User.get_by_id(second_user.id)
856
857 assert first_user.is_confirmed
858 assert second_user.is_confirmed
859
860 log_entry = Repo.one(ModerationLog)
861
862 assert ModerationLog.get_log_entry_message(log_entry) ==
863 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
864 second_user.nickname
865 }"
866 end
867 end
868
869 describe "PATCH /resend_confirmation_email" do
870 test "it resend emails for two users", %{conn: conn, admin: admin} do
871 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
872
873 ret_conn =
874 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
875 nicknames: [
876 first_user.nickname,
877 second_user.nickname
878 ]
879 })
880
881 assert ret_conn.status == 200
882
883 log_entry = Repo.one(ModerationLog)
884
885 assert ModerationLog.get_log_entry_message(log_entry) ==
886 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
887 second_user.nickname
888 }"
889
890 ObanHelpers.perform_all()
891
892 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
893 # temporary hackney fix until hackney max_connections bug is fixed
894 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
895 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
896 |> assert_email_sent()
897 end
898 end
899
900 describe "/api/pleroma/admin/stats" do
901 test "status visibility count", %{conn: conn} do
902 user = insert(:user)
903 CommonAPI.post(user, %{visibility: "public", status: "hey"})
904 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
905 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
906
907 response =
908 conn
909 |> get("/api/pleroma/admin/stats")
910 |> json_response(200)
911
912 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
913 response["status_visibility"]
914 end
915
916 test "by instance", %{conn: conn} do
917 user1 = insert(:user)
918 instance2 = "instance2.tld"
919 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
920
921 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
922 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
923 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
924
925 response =
926 conn
927 |> get("/api/pleroma/admin/stats", instance: instance2)
928 |> json_response(200)
929
930 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
931 response["status_visibility"]
932 end
933 end
934
935 describe "/api/pleroma/backups" do
936 test "it creates a backup", %{conn: conn} do
937 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
938 token = insert(:oauth_admin_token, user: admin)
939 user = %{id: user_id, nickname: user_nickname} = insert(:user)
940
941 assert "" ==
942 conn
943 |> assign(:user, admin)
944 |> assign(:token, token)
945 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
946 |> json_response(200)
947
948 assert [backup] = Repo.all(Pleroma.User.Backup)
949
950 ObanHelpers.perform_all()
951
952 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
953
954 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
955 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
956
957 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
958
959 assert [
960 %{
961 data: %{
962 "action" => "create_backup",
963 "actor" => %{
964 "id" => ^admin_id,
965 "nickname" => ^admin_nickname
966 },
967 "message" => ^log_message,
968 "subject" => %{
969 "id" => ^user_id,
970 "nickname" => ^user_nickname
971 }
972 }
973 }
974 ] = Pleroma.ModerationLog |> Repo.all()
975 end
976
977 test "it doesn't limit admins", %{conn: conn} do
978 admin = insert(:user, is_admin: true)
979 token = insert(:oauth_admin_token, user: admin)
980 user = insert(:user)
981
982 assert "" ==
983 conn
984 |> assign(:user, admin)
985 |> assign(:token, token)
986 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
987 |> json_response(200)
988
989 assert [_backup] = Repo.all(Pleroma.User.Backup)
990
991 assert "" ==
992 conn
993 |> assign(:user, admin)
994 |> assign(:token, token)
995 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
996 |> json_response(200)
997
998 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
999 end
1000 end
1001 end
1002
1003 # Needed for testing
1004 defmodule Pleroma.Web.Endpoint.NotReal do
1005 end
1006
1007 defmodule Pleroma.Captcha.NotReal do
1008 end