CI: Bump lint stage to elixir-1.12
[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}, @#{user_two.nickname}"
271 end
272 end
273
274 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
275 user = insert(:user)
276
277 conn =
278 conn
279 |> put_req_header("accept", "application/json")
280 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
281
282 resp = json_response(conn, 200)
283
284 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
285 end
286
287 describe "PUT disable_mfa" do
288 test "returns 200 and disable 2fa", %{conn: conn} do
289 user =
290 insert(:user,
291 multi_factor_authentication_settings: %MFA.Settings{
292 enabled: true,
293 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
294 }
295 )
296
297 response =
298 conn
299 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
300 |> json_response(200)
301
302 assert response == user.nickname
303 mfa_settings = refresh_record(user).multi_factor_authentication_settings
304
305 refute mfa_settings.enabled
306 refute mfa_settings.totp.confirmed
307 end
308
309 test "returns 404 if user not found", %{conn: conn} do
310 response =
311 conn
312 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
313 |> json_response(404)
314
315 assert response == %{"error" => "Not found"}
316 end
317 end
318
319 describe "GET /api/pleroma/admin/restart" do
320 setup do: clear_config(:configurable_from_database, true)
321
322 test "pleroma restarts", %{conn: conn} do
323 capture_log(fn ->
324 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
325 end) =~ "pleroma restarted"
326
327 refute Restarter.Pleroma.need_reboot?()
328 end
329 end
330
331 test "need_reboot flag", %{conn: conn} do
332 assert conn
333 |> get("/api/pleroma/admin/need_reboot")
334 |> json_response(200) == %{"need_reboot" => false}
335
336 Restarter.Pleroma.need_reboot()
337
338 assert conn
339 |> get("/api/pleroma/admin/need_reboot")
340 |> json_response(200) == %{"need_reboot" => true}
341
342 on_exit(fn -> Restarter.Pleroma.refresh() end)
343 end
344
345 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
346 setup do
347 user = insert(:user)
348
349 insert(:note_activity, user: user)
350 insert(:note_activity, user: user)
351 insert(:note_activity, user: user)
352
353 %{user: user}
354 end
355
356 test "renders user's statuses", %{conn: conn, user: user} do
357 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
358
359 assert %{"total" => 3, "activities" => activities} = json_response(conn, 200)
360 assert length(activities) == 3
361 end
362
363 test "renders user's statuses with pagination", %{conn: conn, user: user} do
364 %{"total" => 3, "activities" => [activity1]} =
365 conn
366 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
367 |> json_response(200)
368
369 %{"total" => 3, "activities" => [activity2]} =
370 conn
371 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
372 |> json_response(200)
373
374 refute activity1 == activity2
375 end
376
377 test "doesn't return private statuses by default", %{conn: conn, user: user} do
378 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
379
380 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
381
382 %{"total" => 4, "activities" => activities} =
383 conn
384 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses")
385 |> json_response(200)
386
387 assert length(activities) == 4
388 end
389
390 test "returns private statuses with godmode on", %{conn: conn, user: user} do
391 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
392
393 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
394
395 %{"total" => 5, "activities" => activities} =
396 conn
397 |> get("/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
398 |> json_response(200)
399
400 assert length(activities) == 5
401 end
402
403 test "excludes reblogs by default", %{conn: conn, user: user} do
404 other_user = insert(:user)
405 {:ok, activity} = CommonAPI.post(user, %{status: "."})
406 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
407
408 assert %{"total" => 0, "activities" => []} ==
409 conn
410 |> get("/api/pleroma/admin/users/#{other_user.nickname}/statuses")
411 |> json_response(200)
412
413 assert %{"total" => 1, "activities" => [_]} =
414 conn
415 |> get(
416 "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true"
417 )
418 |> json_response(200)
419 end
420 end
421
422 describe "GET /api/pleroma/admin/users/:nickname/chats" do
423 setup do
424 user = insert(:user)
425 recipients = insert_list(3, :user)
426
427 Enum.each(recipients, fn recipient ->
428 CommonAPI.post_chat_message(user, recipient, "yo")
429 end)
430
431 %{user: user}
432 end
433
434 test "renders user's chats", %{conn: conn, user: user} do
435 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
436
437 assert json_response(conn, 200) |> length() == 3
438 end
439 end
440
441 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
442 setup do
443 user = insert(:user)
444 recipient = insert(:user)
445 CommonAPI.post_chat_message(user, recipient, "yo")
446 %{conn: conn} = oauth_access(["read:chats"])
447 %{conn: conn, user: user}
448 end
449
450 test "returns 403", %{conn: conn, user: user} do
451 conn
452 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
453 |> json_response(403)
454 end
455 end
456
457 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
458 setup do
459 user = insert(:user)
460 recipient = insert(:user)
461 CommonAPI.post_chat_message(user, recipient, "yo")
462 %{conn: build_conn(), user: user}
463 end
464
465 test "returns 403", %{conn: conn, user: user} do
466 conn
467 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
468 |> json_response(403)
469 end
470 end
471
472 describe "GET /api/pleroma/admin/moderation_log" do
473 setup do
474 moderator = insert(:user, is_moderator: true)
475
476 %{moderator: moderator}
477 end
478
479 test "returns the log", %{conn: conn, admin: admin} do
480 Repo.insert(%ModerationLog{
481 data: %{
482 actor: %{
483 "id" => admin.id,
484 "nickname" => admin.nickname,
485 "type" => "user"
486 },
487 action: "relay_follow",
488 target: "https://example.org/relay"
489 },
490 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
491 })
492
493 Repo.insert(%ModerationLog{
494 data: %{
495 actor: %{
496 "id" => admin.id,
497 "nickname" => admin.nickname,
498 "type" => "user"
499 },
500 action: "relay_unfollow",
501 target: "https://example.org/relay"
502 },
503 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
504 })
505
506 conn = get(conn, "/api/pleroma/admin/moderation_log")
507
508 response = json_response(conn, 200)
509 [first_entry, second_entry] = response["items"]
510
511 assert response["total"] == 2
512 assert first_entry["data"]["action"] == "relay_unfollow"
513
514 assert first_entry["message"] ==
515 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
516
517 assert second_entry["data"]["action"] == "relay_follow"
518
519 assert second_entry["message"] ==
520 "@#{admin.nickname} followed relay: https://example.org/relay"
521 end
522
523 test "returns the log with pagination", %{conn: conn, admin: admin} do
524 Repo.insert(%ModerationLog{
525 data: %{
526 actor: %{
527 "id" => admin.id,
528 "nickname" => admin.nickname,
529 "type" => "user"
530 },
531 action: "relay_follow",
532 target: "https://example.org/relay"
533 },
534 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
535 })
536
537 Repo.insert(%ModerationLog{
538 data: %{
539 actor: %{
540 "id" => admin.id,
541 "nickname" => admin.nickname,
542 "type" => "user"
543 },
544 action: "relay_unfollow",
545 target: "https://example.org/relay"
546 },
547 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
548 })
549
550 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
551
552 response1 = json_response(conn1, 200)
553 [first_entry] = response1["items"]
554
555 assert response1["total"] == 2
556 assert response1["items"] |> length() == 1
557 assert first_entry["data"]["action"] == "relay_unfollow"
558
559 assert first_entry["message"] ==
560 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
561
562 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
563
564 response2 = json_response(conn2, 200)
565 [second_entry] = response2["items"]
566
567 assert response2["total"] == 2
568 assert response2["items"] |> length() == 1
569 assert second_entry["data"]["action"] == "relay_follow"
570
571 assert second_entry["message"] ==
572 "@#{admin.nickname} followed relay: https://example.org/relay"
573 end
574
575 test "filters log by date", %{conn: conn, admin: admin} do
576 first_date = "2017-08-15T15:47:06Z"
577 second_date = "2017-08-20T15:47:06Z"
578
579 Repo.insert(%ModerationLog{
580 data: %{
581 actor: %{
582 "id" => admin.id,
583 "nickname" => admin.nickname,
584 "type" => "user"
585 },
586 action: "relay_follow",
587 target: "https://example.org/relay"
588 },
589 inserted_at: NaiveDateTime.from_iso8601!(first_date)
590 })
591
592 Repo.insert(%ModerationLog{
593 data: %{
594 actor: %{
595 "id" => admin.id,
596 "nickname" => admin.nickname,
597 "type" => "user"
598 },
599 action: "relay_unfollow",
600 target: "https://example.org/relay"
601 },
602 inserted_at: NaiveDateTime.from_iso8601!(second_date)
603 })
604
605 conn1 =
606 get(
607 conn,
608 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
609 )
610
611 response1 = json_response(conn1, 200)
612 [first_entry] = response1["items"]
613
614 assert response1["total"] == 1
615 assert first_entry["data"]["action"] == "relay_unfollow"
616
617 assert first_entry["message"] ==
618 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
619 end
620
621 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
622 Repo.insert(%ModerationLog{
623 data: %{
624 actor: %{
625 "id" => admin.id,
626 "nickname" => admin.nickname,
627 "type" => "user"
628 },
629 action: "relay_follow",
630 target: "https://example.org/relay"
631 }
632 })
633
634 Repo.insert(%ModerationLog{
635 data: %{
636 actor: %{
637 "id" => moderator.id,
638 "nickname" => moderator.nickname,
639 "type" => "user"
640 },
641 action: "relay_unfollow",
642 target: "https://example.org/relay"
643 }
644 })
645
646 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
647
648 response1 = json_response(conn1, 200)
649 [first_entry] = response1["items"]
650
651 assert response1["total"] == 1
652 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
653 end
654
655 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
656 ModerationLog.insert_log(%{
657 actor: moderator,
658 action: "relay_follow",
659 target: "https://example.org/relay"
660 })
661
662 ModerationLog.insert_log(%{
663 actor: moderator,
664 action: "relay_unfollow",
665 target: "https://example.org/relay"
666 })
667
668 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
669
670 response1 = json_response(conn1, 200)
671 [first_entry] = response1["items"]
672
673 assert response1["total"] == 1
674
675 assert get_in(first_entry, ["data", "message"]) ==
676 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
677 end
678 end
679
680 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
681 %{conn: conn} do
682 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
683 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
684 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
685
686 assert json_response(conn, 200)
687 end
688
689 describe "GET /users/:nickname/credentials" do
690 test "gets the user credentials", %{conn: conn} do
691 user = insert(:user)
692 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
693
694 response = assert json_response(conn, 200)
695 assert response["email"] == user.email
696 end
697
698 test "returns 403 if requested by a non-admin" do
699 user = insert(:user)
700
701 conn =
702 build_conn()
703 |> assign(:user, user)
704 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
705
706 assert json_response(conn, :forbidden)
707 end
708 end
709
710 describe "PATCH /users/:nickname/credentials" do
711 setup do
712 user = insert(:user)
713 [user: user]
714 end
715
716 test "changes password and email", %{conn: conn, admin: admin, user: user} do
717 assert user.password_reset_pending == false
718
719 conn =
720 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
721 "password" => "new_password",
722 "email" => "new_email@example.com",
723 "name" => "new_name"
724 })
725
726 assert json_response(conn, 200) == %{"status" => "success"}
727
728 ObanHelpers.perform_all()
729
730 updated_user = User.get_by_id(user.id)
731
732 assert updated_user.email == "new_email@example.com"
733 assert updated_user.name == "new_name"
734 assert updated_user.password_hash != user.password_hash
735 assert updated_user.password_reset_pending == true
736
737 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
738
739 assert ModerationLog.get_log_entry_message(log_entry1) ==
740 "@#{admin.nickname} updated users: @#{user.nickname}"
741
742 assert ModerationLog.get_log_entry_message(log_entry2) ==
743 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
744 end
745
746 test "returns 403 if requested by a non-admin", %{user: user} do
747 conn =
748 build_conn()
749 |> assign(:user, user)
750 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
751 "password" => "new_password",
752 "email" => "new_email@example.com",
753 "name" => "new_name"
754 })
755
756 assert json_response(conn, :forbidden)
757 end
758
759 test "changes actor type from permitted list", %{conn: conn, user: user} do
760 assert user.actor_type == "Person"
761
762 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
763 "actor_type" => "Service"
764 })
765 |> json_response(200) == %{"status" => "success"}
766
767 updated_user = User.get_by_id(user.id)
768
769 assert updated_user.actor_type == "Service"
770
771 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
772 "actor_type" => "Application"
773 })
774 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
775 end
776
777 test "update non existing user", %{conn: conn} do
778 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
779 "password" => "new_password"
780 })
781 |> json_response(404) == %{"error" => "Not found"}
782 end
783 end
784
785 describe "PATCH /users/:nickname/force_password_reset" do
786 test "sets password_reset_pending to true", %{conn: conn} do
787 user = insert(:user)
788 assert user.password_reset_pending == false
789
790 conn =
791 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
792
793 assert empty_json_response(conn) == ""
794
795 ObanHelpers.perform_all()
796
797 assert User.get_by_id(user.id).password_reset_pending == true
798 end
799 end
800
801 describe "instances" do
802 test "GET /instances/:instance/statuses", %{conn: conn} do
803 user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme")
804 user2 = insert(:user, local: false, ap_id: "https://test.com/users/test")
805 insert_pair(:note_activity, user: user)
806 activity = insert(:note_activity, user: user2)
807
808 %{"total" => 2, "activities" => activities} =
809 conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
810
811 assert length(activities) == 2
812
813 %{"total" => 1, "activities" => [_]} =
814 conn |> get("/api/pleroma/admin/instances/test.com/statuses") |> json_response(200)
815
816 %{"total" => 0, "activities" => []} =
817 conn |> get("/api/pleroma/admin/instances/nonexistent.com/statuses") |> json_response(200)
818
819 CommonAPI.repeat(activity.id, user)
820
821 %{"total" => 2, "activities" => activities} =
822 conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(200)
823
824 assert length(activities) == 2
825
826 %{"total" => 3, "activities" => activities} =
827 conn
828 |> get("/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
829 |> json_response(200)
830
831 assert length(activities) == 3
832 end
833 end
834
835 describe "PATCH /confirm_email" do
836 test "it confirms emails of two users", %{conn: conn, admin: admin} do
837 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
838
839 refute first_user.is_confirmed
840 refute second_user.is_confirmed
841
842 ret_conn =
843 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
844 nicknames: [
845 first_user.nickname,
846 second_user.nickname
847 ]
848 })
849
850 assert ret_conn.status == 200
851
852 first_user = User.get_by_id(first_user.id)
853 second_user = User.get_by_id(second_user.id)
854
855 assert first_user.is_confirmed
856 assert second_user.is_confirmed
857
858 log_entry = Repo.one(ModerationLog)
859
860 assert ModerationLog.get_log_entry_message(log_entry) ==
861 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}"
862 end
863 end
864
865 describe "PATCH /resend_confirmation_email" do
866 test "it resend emails for two users", %{conn: conn, admin: admin} do
867 [first_user, second_user] = insert_pair(:user, is_confirmed: false)
868
869 ret_conn =
870 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
871 nicknames: [
872 first_user.nickname,
873 second_user.nickname
874 ]
875 })
876
877 assert ret_conn.status == 200
878
879 log_entry = Repo.one(ModerationLog)
880
881 assert ModerationLog.get_log_entry_message(log_entry) ==
882 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{second_user.nickname}"
883
884 ObanHelpers.perform_all()
885
886 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
887 # temporary hackney fix until hackney max_connections bug is fixed
888 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
889 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
890 |> assert_email_sent()
891 end
892 end
893
894 describe "/api/pleroma/admin/stats" do
895 test "status visibility count", %{conn: conn} do
896 user = insert(:user)
897 CommonAPI.post(user, %{visibility: "public", status: "hey"})
898 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
899 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
900
901 response =
902 conn
903 |> get("/api/pleroma/admin/stats")
904 |> json_response(200)
905
906 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
907 response["status_visibility"]
908 end
909
910 test "by instance", %{conn: conn} do
911 user1 = insert(:user)
912 instance2 = "instance2.tld"
913 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
914
915 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
916 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
917 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
918
919 response =
920 conn
921 |> get("/api/pleroma/admin/stats", instance: instance2)
922 |> json_response(200)
923
924 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
925 response["status_visibility"]
926 end
927 end
928
929 describe "/api/pleroma/backups" do
930 test "it creates a backup", %{conn: conn} do
931 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
932 token = insert(:oauth_admin_token, user: admin)
933 user = %{id: user_id, nickname: user_nickname} = insert(:user)
934
935 assert "" ==
936 conn
937 |> assign(:user, admin)
938 |> assign(:token, token)
939 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
940 |> json_response(200)
941
942 assert [backup] = Repo.all(Pleroma.User.Backup)
943
944 ObanHelpers.perform_all()
945
946 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
947
948 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
949 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
950
951 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
952
953 assert [
954 %{
955 data: %{
956 "action" => "create_backup",
957 "actor" => %{
958 "id" => ^admin_id,
959 "nickname" => ^admin_nickname
960 },
961 "message" => ^log_message,
962 "subject" => %{
963 "id" => ^user_id,
964 "nickname" => ^user_nickname
965 }
966 }
967 }
968 ] = Pleroma.ModerationLog |> Repo.all()
969 end
970
971 test "it doesn't limit admins", %{conn: conn} do
972 admin = insert(:user, is_admin: true)
973 token = insert(:oauth_admin_token, user: admin)
974 user = insert(:user)
975
976 assert "" ==
977 conn
978 |> assign(:user, admin)
979 |> assign(:token, token)
980 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
981 |> json_response(200)
982
983 assert [_backup] = Repo.all(Pleroma.User.Backup)
984
985 assert "" ==
986 conn
987 |> assign(:user, admin)
988 |> assign(:token, token)
989 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
990 |> json_response(200)
991
992 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
993 end
994 end
995 end
996
997 # Needed for testing
998 defmodule Pleroma.Web.Endpoint.NotReal do
999 end
1000
1001 defmodule Pleroma.Captcha.NotReal do
1002 end