Move config actions to AdminAPI.ConfigController
[akkoma] / test / web / admin_api / controllers / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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 Mock
11 import Pleroma.Factory
12
13 alias Pleroma.Activity
14 alias Pleroma.Config
15 alias Pleroma.HTML
16 alias Pleroma.MFA
17 alias Pleroma.ModerationLog
18 alias Pleroma.Repo
19 alias Pleroma.ReportNote
20 alias Pleroma.Tests.ObanHelpers
21 alias Pleroma.User
22 alias Pleroma.UserInviteToken
23 alias Pleroma.Web
24 alias Pleroma.Web.ActivityPub.Relay
25 alias Pleroma.Web.CommonAPI
26 alias Pleroma.Web.MediaProxy
27
28 setup_all do
29 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
30
31 :ok
32 end
33
34 setup do
35 admin = insert(:user, is_admin: true)
36 token = insert(:oauth_admin_token, user: admin)
37
38 conn =
39 build_conn()
40 |> assign(:user, admin)
41 |> assign(:token, token)
42
43 {:ok, %{admin: admin, token: token, conn: conn}}
44 end
45
46 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
47 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
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 end
93
94 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
95 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
96
97 test "GET /api/pleroma/admin/users/:nickname requires " <>
98 "read:accounts or admin:read:accounts or broader scope",
99 %{admin: admin} do
100 user = insert(:user)
101 url = "/api/pleroma/admin/users/#{user.nickname}"
102
103 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
104 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
105 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
106 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
107 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
108
109 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
110
111 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
112 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
113 bad_token3 = nil
114
115 for good_token <- good_tokens do
116 conn =
117 build_conn()
118 |> assign(:user, admin)
119 |> assign(:token, good_token)
120 |> get(url)
121
122 assert json_response(conn, 200)
123 end
124
125 for good_token <- good_tokens do
126 conn =
127 build_conn()
128 |> assign(:user, nil)
129 |> assign(:token, good_token)
130 |> get(url)
131
132 assert json_response(conn, :forbidden)
133 end
134
135 for bad_token <- [bad_token1, bad_token2, bad_token3] do
136 conn =
137 build_conn()
138 |> assign(:user, admin)
139 |> assign(:token, bad_token)
140 |> get(url)
141
142 assert json_response(conn, :forbidden)
143 end
144 end
145 end
146
147 describe "DELETE /api/pleroma/admin/users" do
148 test "single user", %{admin: admin, conn: conn} do
149 user = insert(:user)
150 clear_config([:instance, :federating], true)
151
152 with_mock Pleroma.Web.Federator,
153 publish: fn _ -> nil end do
154 conn =
155 conn
156 |> put_req_header("accept", "application/json")
157 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
158
159 ObanHelpers.perform_all()
160
161 assert User.get_by_nickname(user.nickname).deactivated
162
163 log_entry = Repo.one(ModerationLog)
164
165 assert ModerationLog.get_log_entry_message(log_entry) ==
166 "@#{admin.nickname} deleted users: @#{user.nickname}"
167
168 assert json_response(conn, 200) == [user.nickname]
169
170 assert called(Pleroma.Web.Federator.publish(:_))
171 end
172 end
173
174 test "multiple users", %{admin: admin, conn: conn} do
175 user_one = insert(:user)
176 user_two = insert(:user)
177
178 conn =
179 conn
180 |> put_req_header("accept", "application/json")
181 |> delete("/api/pleroma/admin/users", %{
182 nicknames: [user_one.nickname, user_two.nickname]
183 })
184
185 log_entry = Repo.one(ModerationLog)
186
187 assert ModerationLog.get_log_entry_message(log_entry) ==
188 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
189
190 response = json_response(conn, 200)
191 assert response -- [user_one.nickname, user_two.nickname] == []
192 end
193 end
194
195 describe "/api/pleroma/admin/users" do
196 test "Create", %{conn: conn} do
197 conn =
198 conn
199 |> put_req_header("accept", "application/json")
200 |> post("/api/pleroma/admin/users", %{
201 "users" => [
202 %{
203 "nickname" => "lain",
204 "email" => "lain@example.org",
205 "password" => "test"
206 },
207 %{
208 "nickname" => "lain2",
209 "email" => "lain2@example.org",
210 "password" => "test"
211 }
212 ]
213 })
214
215 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
216 assert response == ["success", "success"]
217
218 log_entry = Repo.one(ModerationLog)
219
220 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
221 end
222
223 test "Cannot create user with existing email", %{conn: conn} do
224 user = insert(:user)
225
226 conn =
227 conn
228 |> put_req_header("accept", "application/json")
229 |> post("/api/pleroma/admin/users", %{
230 "users" => [
231 %{
232 "nickname" => "lain",
233 "email" => user.email,
234 "password" => "test"
235 }
236 ]
237 })
238
239 assert json_response(conn, 409) == [
240 %{
241 "code" => 409,
242 "data" => %{
243 "email" => user.email,
244 "nickname" => "lain"
245 },
246 "error" => "email has already been taken",
247 "type" => "error"
248 }
249 ]
250 end
251
252 test "Cannot create user with existing nickname", %{conn: conn} do
253 user = insert(:user)
254
255 conn =
256 conn
257 |> put_req_header("accept", "application/json")
258 |> post("/api/pleroma/admin/users", %{
259 "users" => [
260 %{
261 "nickname" => user.nickname,
262 "email" => "someuser@plerama.social",
263 "password" => "test"
264 }
265 ]
266 })
267
268 assert json_response(conn, 409) == [
269 %{
270 "code" => 409,
271 "data" => %{
272 "email" => "someuser@plerama.social",
273 "nickname" => user.nickname
274 },
275 "error" => "nickname has already been taken",
276 "type" => "error"
277 }
278 ]
279 end
280
281 test "Multiple user creation works in transaction", %{conn: conn} do
282 user = insert(:user)
283
284 conn =
285 conn
286 |> put_req_header("accept", "application/json")
287 |> post("/api/pleroma/admin/users", %{
288 "users" => [
289 %{
290 "nickname" => "newuser",
291 "email" => "newuser@pleroma.social",
292 "password" => "test"
293 },
294 %{
295 "nickname" => "lain",
296 "email" => user.email,
297 "password" => "test"
298 }
299 ]
300 })
301
302 assert json_response(conn, 409) == [
303 %{
304 "code" => 409,
305 "data" => %{
306 "email" => user.email,
307 "nickname" => "lain"
308 },
309 "error" => "email has already been taken",
310 "type" => "error"
311 },
312 %{
313 "code" => 409,
314 "data" => %{
315 "email" => "newuser@pleroma.social",
316 "nickname" => "newuser"
317 },
318 "error" => "",
319 "type" => "error"
320 }
321 ]
322
323 assert User.get_by_nickname("newuser") === nil
324 end
325 end
326
327 describe "/api/pleroma/admin/users/:nickname" do
328 test "Show", %{conn: conn} do
329 user = insert(:user)
330
331 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
332
333 expected = %{
334 "deactivated" => false,
335 "id" => to_string(user.id),
336 "local" => true,
337 "nickname" => user.nickname,
338 "roles" => %{"admin" => false, "moderator" => false},
339 "tags" => [],
340 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
341 "display_name" => HTML.strip_tags(user.name || user.nickname),
342 "confirmation_pending" => false
343 }
344
345 assert expected == json_response(conn, 200)
346 end
347
348 test "when the user doesn't exist", %{conn: conn} do
349 user = build(:user)
350
351 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
352
353 assert %{"error" => "Not found"} == json_response(conn, 404)
354 end
355 end
356
357 describe "/api/pleroma/admin/users/follow" do
358 test "allows to force-follow another user", %{admin: admin, conn: conn} do
359 user = insert(:user)
360 follower = insert(:user)
361
362 conn
363 |> put_req_header("accept", "application/json")
364 |> post("/api/pleroma/admin/users/follow", %{
365 "follower" => follower.nickname,
366 "followed" => user.nickname
367 })
368
369 user = User.get_cached_by_id(user.id)
370 follower = User.get_cached_by_id(follower.id)
371
372 assert User.following?(follower, user)
373
374 log_entry = Repo.one(ModerationLog)
375
376 assert ModerationLog.get_log_entry_message(log_entry) ==
377 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
378 end
379 end
380
381 describe "/api/pleroma/admin/users/unfollow" do
382 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
383 user = insert(:user)
384 follower = insert(:user)
385
386 User.follow(follower, user)
387
388 conn
389 |> put_req_header("accept", "application/json")
390 |> post("/api/pleroma/admin/users/unfollow", %{
391 "follower" => follower.nickname,
392 "followed" => user.nickname
393 })
394
395 user = User.get_cached_by_id(user.id)
396 follower = User.get_cached_by_id(follower.id)
397
398 refute User.following?(follower, user)
399
400 log_entry = Repo.one(ModerationLog)
401
402 assert ModerationLog.get_log_entry_message(log_entry) ==
403 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
404 end
405 end
406
407 describe "PUT /api/pleroma/admin/users/tag" do
408 setup %{conn: conn} do
409 user1 = insert(:user, %{tags: ["x"]})
410 user2 = insert(:user, %{tags: ["y"]})
411 user3 = insert(:user, %{tags: ["unchanged"]})
412
413 conn =
414 conn
415 |> put_req_header("accept", "application/json")
416 |> put(
417 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
418 "#{user2.nickname}&tags[]=foo&tags[]=bar"
419 )
420
421 %{conn: conn, user1: user1, user2: user2, user3: user3}
422 end
423
424 test "it appends specified tags to users with specified nicknames", %{
425 conn: conn,
426 admin: admin,
427 user1: user1,
428 user2: user2
429 } do
430 assert json_response(conn, :no_content)
431 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
432 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
433
434 log_entry = Repo.one(ModerationLog)
435
436 users =
437 [user1.nickname, user2.nickname]
438 |> Enum.map(&"@#{&1}")
439 |> Enum.join(", ")
440
441 tags = ["foo", "bar"] |> Enum.join(", ")
442
443 assert ModerationLog.get_log_entry_message(log_entry) ==
444 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
445 end
446
447 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
448 assert json_response(conn, :no_content)
449 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
450 end
451 end
452
453 describe "DELETE /api/pleroma/admin/users/tag" do
454 setup %{conn: conn} do
455 user1 = insert(:user, %{tags: ["x"]})
456 user2 = insert(:user, %{tags: ["y", "z"]})
457 user3 = insert(:user, %{tags: ["unchanged"]})
458
459 conn =
460 conn
461 |> put_req_header("accept", "application/json")
462 |> delete(
463 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
464 "#{user2.nickname}&tags[]=x&tags[]=z"
465 )
466
467 %{conn: conn, user1: user1, user2: user2, user3: user3}
468 end
469
470 test "it removes specified tags from users with specified nicknames", %{
471 conn: conn,
472 admin: admin,
473 user1: user1,
474 user2: user2
475 } do
476 assert json_response(conn, :no_content)
477 assert User.get_cached_by_id(user1.id).tags == []
478 assert User.get_cached_by_id(user2.id).tags == ["y"]
479
480 log_entry = Repo.one(ModerationLog)
481
482 users =
483 [user1.nickname, user2.nickname]
484 |> Enum.map(&"@#{&1}")
485 |> Enum.join(", ")
486
487 tags = ["x", "z"] |> Enum.join(", ")
488
489 assert ModerationLog.get_log_entry_message(log_entry) ==
490 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
491 end
492
493 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
494 assert json_response(conn, :no_content)
495 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
496 end
497 end
498
499 describe "/api/pleroma/admin/users/:nickname/permission_group" do
500 test "GET is giving user_info", %{admin: admin, conn: conn} do
501 conn =
502 conn
503 |> put_req_header("accept", "application/json")
504 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
505
506 assert json_response(conn, 200) == %{
507 "is_admin" => true,
508 "is_moderator" => false
509 }
510 end
511
512 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
513 user = insert(:user)
514
515 conn =
516 conn
517 |> put_req_header("accept", "application/json")
518 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
519
520 assert json_response(conn, 200) == %{
521 "is_admin" => true
522 }
523
524 log_entry = Repo.one(ModerationLog)
525
526 assert ModerationLog.get_log_entry_message(log_entry) ==
527 "@#{admin.nickname} made @#{user.nickname} admin"
528 end
529
530 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
531 user_one = insert(:user)
532 user_two = insert(:user)
533
534 conn =
535 conn
536 |> put_req_header("accept", "application/json")
537 |> post("/api/pleroma/admin/users/permission_group/admin", %{
538 nicknames: [user_one.nickname, user_two.nickname]
539 })
540
541 assert json_response(conn, 200) == %{"is_admin" => true}
542
543 log_entry = Repo.one(ModerationLog)
544
545 assert ModerationLog.get_log_entry_message(log_entry) ==
546 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
547 end
548
549 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
550 user = insert(:user, is_admin: true)
551
552 conn =
553 conn
554 |> put_req_header("accept", "application/json")
555 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
556
557 assert json_response(conn, 200) == %{"is_admin" => false}
558
559 log_entry = Repo.one(ModerationLog)
560
561 assert ModerationLog.get_log_entry_message(log_entry) ==
562 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
563 end
564
565 test "/:right DELETE, can remove from a permission group (multiple)", %{
566 admin: admin,
567 conn: conn
568 } do
569 user_one = insert(:user, is_admin: true)
570 user_two = insert(:user, is_admin: true)
571
572 conn =
573 conn
574 |> put_req_header("accept", "application/json")
575 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
576 nicknames: [user_one.nickname, user_two.nickname]
577 })
578
579 assert json_response(conn, 200) == %{"is_admin" => false}
580
581 log_entry = Repo.one(ModerationLog)
582
583 assert ModerationLog.get_log_entry_message(log_entry) ==
584 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
585 user_two.nickname
586 }"
587 end
588 end
589
590 describe "POST /api/pleroma/admin/email_invite, with valid config" do
591 setup do: clear_config([:instance, :registrations_open], false)
592 setup do: clear_config([:instance, :invites_enabled], true)
593
594 test "sends invitation and returns 204", %{admin: admin, conn: conn} do
595 recipient_email = "foo@bar.com"
596 recipient_name = "J. D."
597
598 conn =
599 post(
600 conn,
601 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
602 )
603
604 assert json_response(conn, :no_content)
605
606 token_record = List.last(Repo.all(Pleroma.UserInviteToken))
607 assert token_record
608 refute token_record.used
609
610 notify_email = Config.get([:instance, :notify_email])
611 instance_name = Config.get([:instance, :name])
612
613 email =
614 Pleroma.Emails.UserEmail.user_invitation_email(
615 admin,
616 token_record,
617 recipient_email,
618 recipient_name
619 )
620
621 Swoosh.TestAssertions.assert_email_sent(
622 from: {instance_name, notify_email},
623 to: {recipient_name, recipient_email},
624 html_body: email.html_body
625 )
626 end
627
628 test "it returns 403 if requested by a non-admin" do
629 non_admin_user = insert(:user)
630 token = insert(:oauth_token, user: non_admin_user)
631
632 conn =
633 build_conn()
634 |> assign(:user, non_admin_user)
635 |> assign(:token, token)
636 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
637
638 assert json_response(conn, :forbidden)
639 end
640
641 test "email with +", %{conn: conn, admin: admin} do
642 recipient_email = "foo+bar@baz.com"
643
644 conn
645 |> put_req_header("content-type", "application/json;charset=utf-8")
646 |> post("/api/pleroma/admin/users/email_invite", %{email: recipient_email})
647 |> json_response(:no_content)
648
649 token_record =
650 Pleroma.UserInviteToken
651 |> Repo.all()
652 |> List.last()
653
654 assert token_record
655 refute token_record.used
656
657 notify_email = Config.get([:instance, :notify_email])
658 instance_name = Config.get([:instance, :name])
659
660 email =
661 Pleroma.Emails.UserEmail.user_invitation_email(
662 admin,
663 token_record,
664 recipient_email
665 )
666
667 Swoosh.TestAssertions.assert_email_sent(
668 from: {instance_name, notify_email},
669 to: recipient_email,
670 html_body: email.html_body
671 )
672 end
673 end
674
675 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
676 setup do: clear_config([:instance, :registrations_open])
677 setup do: clear_config([:instance, :invites_enabled])
678
679 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do
680 Config.put([:instance, :registrations_open], false)
681 Config.put([:instance, :invites_enabled], false)
682
683 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
684
685 assert json_response(conn, :bad_request) ==
686 %{
687 "error" =>
688 "To send invites you need to set the `invites_enabled` option to true."
689 }
690 end
691
692 test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do
693 Config.put([:instance, :registrations_open], true)
694 Config.put([:instance, :invites_enabled], true)
695
696 conn = post(conn, "/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
697
698 assert json_response(conn, :bad_request) ==
699 %{
700 "error" =>
701 "To send invites you need to set the `registrations_open` option to false."
702 }
703 end
704 end
705
706 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
707 user = insert(:user)
708
709 conn =
710 conn
711 |> put_req_header("accept", "application/json")
712 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
713
714 resp = json_response(conn, 200)
715
716 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
717 end
718
719 describe "GET /api/pleroma/admin/users" do
720 test "renders users array for the first page", %{conn: conn, admin: admin} do
721 user = insert(:user, local: false, tags: ["foo", "bar"])
722 conn = get(conn, "/api/pleroma/admin/users?page=1")
723
724 users =
725 [
726 %{
727 "deactivated" => admin.deactivated,
728 "id" => admin.id,
729 "nickname" => admin.nickname,
730 "roles" => %{"admin" => true, "moderator" => false},
731 "local" => true,
732 "tags" => [],
733 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
734 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
735 "confirmation_pending" => false
736 },
737 %{
738 "deactivated" => user.deactivated,
739 "id" => user.id,
740 "nickname" => user.nickname,
741 "roles" => %{"admin" => false, "moderator" => false},
742 "local" => false,
743 "tags" => ["foo", "bar"],
744 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
745 "display_name" => HTML.strip_tags(user.name || user.nickname),
746 "confirmation_pending" => false
747 }
748 ]
749 |> Enum.sort_by(& &1["nickname"])
750
751 assert json_response(conn, 200) == %{
752 "count" => 2,
753 "page_size" => 50,
754 "users" => users
755 }
756 end
757
758 test "pagination works correctly with service users", %{conn: conn} do
759 service1 = insert(:user, ap_id: Web.base_url() <> "/relay")
760 service2 = insert(:user, ap_id: Web.base_url() <> "/internal/fetch")
761 insert_list(25, :user)
762
763 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
764 conn
765 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
766 |> json_response(200)
767
768 assert Enum.count(users1) == 10
769 assert service1 not in [users1]
770 assert service2 not in [users1]
771
772 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
773 conn
774 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
775 |> json_response(200)
776
777 assert Enum.count(users2) == 10
778 assert service1 not in [users2]
779 assert service2 not in [users2]
780
781 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
782 conn
783 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
784 |> json_response(200)
785
786 assert Enum.count(users3) == 6
787 assert service1 not in [users3]
788 assert service2 not in [users3]
789 end
790
791 test "renders empty array for the second page", %{conn: conn} do
792 insert(:user)
793
794 conn = get(conn, "/api/pleroma/admin/users?page=2")
795
796 assert json_response(conn, 200) == %{
797 "count" => 2,
798 "page_size" => 50,
799 "users" => []
800 }
801 end
802
803 test "regular search", %{conn: conn} do
804 user = insert(:user, nickname: "bob")
805
806 conn = get(conn, "/api/pleroma/admin/users?query=bo")
807
808 assert json_response(conn, 200) == %{
809 "count" => 1,
810 "page_size" => 50,
811 "users" => [
812 %{
813 "deactivated" => user.deactivated,
814 "id" => user.id,
815 "nickname" => user.nickname,
816 "roles" => %{"admin" => false, "moderator" => false},
817 "local" => true,
818 "tags" => [],
819 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
820 "display_name" => HTML.strip_tags(user.name || user.nickname),
821 "confirmation_pending" => false
822 }
823 ]
824 }
825 end
826
827 test "search by domain", %{conn: conn} do
828 user = insert(:user, nickname: "nickname@domain.com")
829 insert(:user)
830
831 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
832
833 assert json_response(conn, 200) == %{
834 "count" => 1,
835 "page_size" => 50,
836 "users" => [
837 %{
838 "deactivated" => user.deactivated,
839 "id" => user.id,
840 "nickname" => user.nickname,
841 "roles" => %{"admin" => false, "moderator" => false},
842 "local" => true,
843 "tags" => [],
844 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
845 "display_name" => HTML.strip_tags(user.name || user.nickname),
846 "confirmation_pending" => false
847 }
848 ]
849 }
850 end
851
852 test "search by full nickname", %{conn: conn} do
853 user = insert(:user, nickname: "nickname@domain.com")
854 insert(:user)
855
856 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
857
858 assert json_response(conn, 200) == %{
859 "count" => 1,
860 "page_size" => 50,
861 "users" => [
862 %{
863 "deactivated" => user.deactivated,
864 "id" => user.id,
865 "nickname" => user.nickname,
866 "roles" => %{"admin" => false, "moderator" => false},
867 "local" => true,
868 "tags" => [],
869 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
870 "display_name" => HTML.strip_tags(user.name || user.nickname),
871 "confirmation_pending" => false
872 }
873 ]
874 }
875 end
876
877 test "search by display name", %{conn: conn} do
878 user = insert(:user, name: "Display name")
879 insert(:user)
880
881 conn = get(conn, "/api/pleroma/admin/users?name=display")
882
883 assert json_response(conn, 200) == %{
884 "count" => 1,
885 "page_size" => 50,
886 "users" => [
887 %{
888 "deactivated" => user.deactivated,
889 "id" => user.id,
890 "nickname" => user.nickname,
891 "roles" => %{"admin" => false, "moderator" => false},
892 "local" => true,
893 "tags" => [],
894 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
895 "display_name" => HTML.strip_tags(user.name || user.nickname),
896 "confirmation_pending" => false
897 }
898 ]
899 }
900 end
901
902 test "search by email", %{conn: conn} do
903 user = insert(:user, email: "email@example.com")
904 insert(:user)
905
906 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
907
908 assert json_response(conn, 200) == %{
909 "count" => 1,
910 "page_size" => 50,
911 "users" => [
912 %{
913 "deactivated" => user.deactivated,
914 "id" => user.id,
915 "nickname" => user.nickname,
916 "roles" => %{"admin" => false, "moderator" => false},
917 "local" => true,
918 "tags" => [],
919 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
920 "display_name" => HTML.strip_tags(user.name || user.nickname),
921 "confirmation_pending" => false
922 }
923 ]
924 }
925 end
926
927 test "regular search with page size", %{conn: conn} do
928 user = insert(:user, nickname: "aalice")
929 user2 = insert(:user, nickname: "alice")
930
931 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
932
933 assert json_response(conn1, 200) == %{
934 "count" => 2,
935 "page_size" => 1,
936 "users" => [
937 %{
938 "deactivated" => user.deactivated,
939 "id" => user.id,
940 "nickname" => user.nickname,
941 "roles" => %{"admin" => false, "moderator" => false},
942 "local" => true,
943 "tags" => [],
944 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
945 "display_name" => HTML.strip_tags(user.name || user.nickname),
946 "confirmation_pending" => false
947 }
948 ]
949 }
950
951 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
952
953 assert json_response(conn2, 200) == %{
954 "count" => 2,
955 "page_size" => 1,
956 "users" => [
957 %{
958 "deactivated" => user2.deactivated,
959 "id" => user2.id,
960 "nickname" => user2.nickname,
961 "roles" => %{"admin" => false, "moderator" => false},
962 "local" => true,
963 "tags" => [],
964 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
965 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
966 "confirmation_pending" => false
967 }
968 ]
969 }
970 end
971
972 test "only local users" do
973 admin = insert(:user, is_admin: true, nickname: "john")
974 token = insert(:oauth_admin_token, user: admin)
975 user = insert(:user, nickname: "bob")
976
977 insert(:user, nickname: "bobb", local: false)
978
979 conn =
980 build_conn()
981 |> assign(:user, admin)
982 |> assign(:token, token)
983 |> get("/api/pleroma/admin/users?query=bo&filters=local")
984
985 assert json_response(conn, 200) == %{
986 "count" => 1,
987 "page_size" => 50,
988 "users" => [
989 %{
990 "deactivated" => user.deactivated,
991 "id" => user.id,
992 "nickname" => user.nickname,
993 "roles" => %{"admin" => false, "moderator" => false},
994 "local" => true,
995 "tags" => [],
996 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
997 "display_name" => HTML.strip_tags(user.name || user.nickname),
998 "confirmation_pending" => false
999 }
1000 ]
1001 }
1002 end
1003
1004 test "only local users with no query", %{conn: conn, admin: old_admin} do
1005 admin = insert(:user, is_admin: true, nickname: "john")
1006 user = insert(:user, nickname: "bob")
1007
1008 insert(:user, nickname: "bobb", local: false)
1009
1010 conn = get(conn, "/api/pleroma/admin/users?filters=local")
1011
1012 users =
1013 [
1014 %{
1015 "deactivated" => user.deactivated,
1016 "id" => user.id,
1017 "nickname" => user.nickname,
1018 "roles" => %{"admin" => false, "moderator" => false},
1019 "local" => true,
1020 "tags" => [],
1021 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1022 "display_name" => HTML.strip_tags(user.name || user.nickname),
1023 "confirmation_pending" => false
1024 },
1025 %{
1026 "deactivated" => admin.deactivated,
1027 "id" => admin.id,
1028 "nickname" => admin.nickname,
1029 "roles" => %{"admin" => true, "moderator" => false},
1030 "local" => true,
1031 "tags" => [],
1032 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1033 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1034 "confirmation_pending" => false
1035 },
1036 %{
1037 "deactivated" => false,
1038 "id" => old_admin.id,
1039 "local" => true,
1040 "nickname" => old_admin.nickname,
1041 "roles" => %{"admin" => true, "moderator" => false},
1042 "tags" => [],
1043 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
1044 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
1045 "confirmation_pending" => false
1046 }
1047 ]
1048 |> Enum.sort_by(& &1["nickname"])
1049
1050 assert json_response(conn, 200) == %{
1051 "count" => 3,
1052 "page_size" => 50,
1053 "users" => users
1054 }
1055 end
1056
1057 test "load only admins", %{conn: conn, admin: admin} do
1058 second_admin = insert(:user, is_admin: true)
1059 insert(:user)
1060 insert(:user)
1061
1062 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1063
1064 users =
1065 [
1066 %{
1067 "deactivated" => false,
1068 "id" => admin.id,
1069 "nickname" => admin.nickname,
1070 "roles" => %{"admin" => true, "moderator" => false},
1071 "local" => admin.local,
1072 "tags" => [],
1073 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1074 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1075 "confirmation_pending" => false
1076 },
1077 %{
1078 "deactivated" => false,
1079 "id" => second_admin.id,
1080 "nickname" => second_admin.nickname,
1081 "roles" => %{"admin" => true, "moderator" => false},
1082 "local" => second_admin.local,
1083 "tags" => [],
1084 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1085 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1086 "confirmation_pending" => false
1087 }
1088 ]
1089 |> Enum.sort_by(& &1["nickname"])
1090
1091 assert json_response(conn, 200) == %{
1092 "count" => 2,
1093 "page_size" => 50,
1094 "users" => users
1095 }
1096 end
1097
1098 test "load only moderators", %{conn: conn} do
1099 moderator = insert(:user, is_moderator: true)
1100 insert(:user)
1101 insert(:user)
1102
1103 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1104
1105 assert json_response(conn, 200) == %{
1106 "count" => 1,
1107 "page_size" => 50,
1108 "users" => [
1109 %{
1110 "deactivated" => false,
1111 "id" => moderator.id,
1112 "nickname" => moderator.nickname,
1113 "roles" => %{"admin" => false, "moderator" => true},
1114 "local" => moderator.local,
1115 "tags" => [],
1116 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1117 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1118 "confirmation_pending" => false
1119 }
1120 ]
1121 }
1122 end
1123
1124 test "load users with tags list", %{conn: conn} do
1125 user1 = insert(:user, tags: ["first"])
1126 user2 = insert(:user, tags: ["second"])
1127 insert(:user)
1128 insert(:user)
1129
1130 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1131
1132 users =
1133 [
1134 %{
1135 "deactivated" => false,
1136 "id" => user1.id,
1137 "nickname" => user1.nickname,
1138 "roles" => %{"admin" => false, "moderator" => false},
1139 "local" => user1.local,
1140 "tags" => ["first"],
1141 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1142 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1143 "confirmation_pending" => false
1144 },
1145 %{
1146 "deactivated" => false,
1147 "id" => user2.id,
1148 "nickname" => user2.nickname,
1149 "roles" => %{"admin" => false, "moderator" => false},
1150 "local" => user2.local,
1151 "tags" => ["second"],
1152 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1153 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1154 "confirmation_pending" => false
1155 }
1156 ]
1157 |> Enum.sort_by(& &1["nickname"])
1158
1159 assert json_response(conn, 200) == %{
1160 "count" => 2,
1161 "page_size" => 50,
1162 "users" => users
1163 }
1164 end
1165
1166 test "it works with multiple filters" do
1167 admin = insert(:user, nickname: "john", is_admin: true)
1168 token = insert(:oauth_admin_token, user: admin)
1169 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1170
1171 insert(:user, nickname: "ken", local: true, deactivated: true)
1172 insert(:user, nickname: "bobb", local: false, deactivated: false)
1173
1174 conn =
1175 build_conn()
1176 |> assign(:user, admin)
1177 |> assign(:token, token)
1178 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1179
1180 assert json_response(conn, 200) == %{
1181 "count" => 1,
1182 "page_size" => 50,
1183 "users" => [
1184 %{
1185 "deactivated" => user.deactivated,
1186 "id" => user.id,
1187 "nickname" => user.nickname,
1188 "roles" => %{"admin" => false, "moderator" => false},
1189 "local" => user.local,
1190 "tags" => [],
1191 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1192 "display_name" => HTML.strip_tags(user.name || user.nickname),
1193 "confirmation_pending" => false
1194 }
1195 ]
1196 }
1197 end
1198
1199 test "it omits relay user", %{admin: admin, conn: conn} do
1200 assert %User{} = Relay.get_actor()
1201
1202 conn = get(conn, "/api/pleroma/admin/users")
1203
1204 assert json_response(conn, 200) == %{
1205 "count" => 1,
1206 "page_size" => 50,
1207 "users" => [
1208 %{
1209 "deactivated" => admin.deactivated,
1210 "id" => admin.id,
1211 "nickname" => admin.nickname,
1212 "roles" => %{"admin" => true, "moderator" => false},
1213 "local" => true,
1214 "tags" => [],
1215 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1216 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1217 "confirmation_pending" => false
1218 }
1219 ]
1220 }
1221 end
1222 end
1223
1224 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1225 user_one = insert(:user, deactivated: true)
1226 user_two = insert(:user, deactivated: true)
1227
1228 conn =
1229 patch(
1230 conn,
1231 "/api/pleroma/admin/users/activate",
1232 %{nicknames: [user_one.nickname, user_two.nickname]}
1233 )
1234
1235 response = json_response(conn, 200)
1236 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1237
1238 log_entry = Repo.one(ModerationLog)
1239
1240 assert ModerationLog.get_log_entry_message(log_entry) ==
1241 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1242 end
1243
1244 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1245 user_one = insert(:user, deactivated: false)
1246 user_two = insert(:user, deactivated: false)
1247
1248 conn =
1249 patch(
1250 conn,
1251 "/api/pleroma/admin/users/deactivate",
1252 %{nicknames: [user_one.nickname, user_two.nickname]}
1253 )
1254
1255 response = json_response(conn, 200)
1256 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1257
1258 log_entry = Repo.one(ModerationLog)
1259
1260 assert ModerationLog.get_log_entry_message(log_entry) ==
1261 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1262 end
1263
1264 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1265 user = insert(:user)
1266
1267 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1268
1269 assert json_response(conn, 200) ==
1270 %{
1271 "deactivated" => !user.deactivated,
1272 "id" => user.id,
1273 "nickname" => user.nickname,
1274 "roles" => %{"admin" => false, "moderator" => false},
1275 "local" => true,
1276 "tags" => [],
1277 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1278 "display_name" => HTML.strip_tags(user.name || user.nickname),
1279 "confirmation_pending" => false
1280 }
1281
1282 log_entry = Repo.one(ModerationLog)
1283
1284 assert ModerationLog.get_log_entry_message(log_entry) ==
1285 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1286 end
1287
1288 describe "PUT disable_mfa" do
1289 test "returns 200 and disable 2fa", %{conn: conn} do
1290 user =
1291 insert(:user,
1292 multi_factor_authentication_settings: %MFA.Settings{
1293 enabled: true,
1294 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1295 }
1296 )
1297
1298 response =
1299 conn
1300 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1301 |> json_response(200)
1302
1303 assert response == user.nickname
1304 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1305
1306 refute mfa_settings.enabled
1307 refute mfa_settings.totp.confirmed
1308 end
1309
1310 test "returns 404 if user not found", %{conn: conn} do
1311 response =
1312 conn
1313 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1314 |> json_response(404)
1315
1316 assert response == %{"error" => "Not found"}
1317 end
1318 end
1319
1320 describe "POST /api/pleroma/admin/users/invite_token" do
1321 test "without options", %{conn: conn} do
1322 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1323
1324 invite_json = json_response(conn, 200)
1325 invite = UserInviteToken.find_by_token!(invite_json["token"])
1326 refute invite.used
1327 refute invite.expires_at
1328 refute invite.max_use
1329 assert invite.invite_type == "one_time"
1330 end
1331
1332 test "with expires_at", %{conn: conn} do
1333 conn =
1334 post(conn, "/api/pleroma/admin/users/invite_token", %{
1335 "expires_at" => Date.to_string(Date.utc_today())
1336 })
1337
1338 invite_json = json_response(conn, 200)
1339 invite = UserInviteToken.find_by_token!(invite_json["token"])
1340
1341 refute invite.used
1342 assert invite.expires_at == Date.utc_today()
1343 refute invite.max_use
1344 assert invite.invite_type == "date_limited"
1345 end
1346
1347 test "with max_use", %{conn: conn} do
1348 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1349
1350 invite_json = json_response(conn, 200)
1351 invite = UserInviteToken.find_by_token!(invite_json["token"])
1352 refute invite.used
1353 refute invite.expires_at
1354 assert invite.max_use == 150
1355 assert invite.invite_type == "reusable"
1356 end
1357
1358 test "with max use and expires_at", %{conn: conn} do
1359 conn =
1360 post(conn, "/api/pleroma/admin/users/invite_token", %{
1361 "max_use" => 150,
1362 "expires_at" => Date.to_string(Date.utc_today())
1363 })
1364
1365 invite_json = json_response(conn, 200)
1366 invite = UserInviteToken.find_by_token!(invite_json["token"])
1367 refute invite.used
1368 assert invite.expires_at == Date.utc_today()
1369 assert invite.max_use == 150
1370 assert invite.invite_type == "reusable_date_limited"
1371 end
1372 end
1373
1374 describe "GET /api/pleroma/admin/users/invites" do
1375 test "no invites", %{conn: conn} do
1376 conn = get(conn, "/api/pleroma/admin/users/invites")
1377
1378 assert json_response(conn, 200) == %{"invites" => []}
1379 end
1380
1381 test "with invite", %{conn: conn} do
1382 {:ok, invite} = UserInviteToken.create_invite()
1383
1384 conn = get(conn, "/api/pleroma/admin/users/invites")
1385
1386 assert json_response(conn, 200) == %{
1387 "invites" => [
1388 %{
1389 "expires_at" => nil,
1390 "id" => invite.id,
1391 "invite_type" => "one_time",
1392 "max_use" => nil,
1393 "token" => invite.token,
1394 "used" => false,
1395 "uses" => 0
1396 }
1397 ]
1398 }
1399 end
1400 end
1401
1402 describe "POST /api/pleroma/admin/users/revoke_invite" do
1403 test "with token", %{conn: conn} do
1404 {:ok, invite} = UserInviteToken.create_invite()
1405
1406 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1407
1408 assert json_response(conn, 200) == %{
1409 "expires_at" => nil,
1410 "id" => invite.id,
1411 "invite_type" => "one_time",
1412 "max_use" => nil,
1413 "token" => invite.token,
1414 "used" => true,
1415 "uses" => 0
1416 }
1417 end
1418
1419 test "with invalid token", %{conn: conn} do
1420 conn = post(conn, "/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1421
1422 assert json_response(conn, :not_found) == %{"error" => "Not found"}
1423 end
1424 end
1425
1426 describe "GET /api/pleroma/admin/reports/:id" do
1427 test "returns report by its id", %{conn: conn} do
1428 [reporter, target_user] = insert_pair(:user)
1429 activity = insert(:note_activity, user: target_user)
1430
1431 {:ok, %{id: report_id}} =
1432 CommonAPI.report(reporter, %{
1433 account_id: target_user.id,
1434 comment: "I feel offended",
1435 status_ids: [activity.id]
1436 })
1437
1438 response =
1439 conn
1440 |> get("/api/pleroma/admin/reports/#{report_id}")
1441 |> json_response(:ok)
1442
1443 assert response["id"] == report_id
1444 end
1445
1446 test "returns 404 when report id is invalid", %{conn: conn} do
1447 conn = get(conn, "/api/pleroma/admin/reports/test")
1448
1449 assert json_response(conn, :not_found) == %{"error" => "Not found"}
1450 end
1451 end
1452
1453 describe "PATCH /api/pleroma/admin/reports" do
1454 setup do
1455 [reporter, target_user] = insert_pair(:user)
1456 activity = insert(:note_activity, user: target_user)
1457
1458 {:ok, %{id: report_id}} =
1459 CommonAPI.report(reporter, %{
1460 account_id: target_user.id,
1461 comment: "I feel offended",
1462 status_ids: [activity.id]
1463 })
1464
1465 {:ok, %{id: second_report_id}} =
1466 CommonAPI.report(reporter, %{
1467 account_id: target_user.id,
1468 comment: "I feel very offended",
1469 status_ids: [activity.id]
1470 })
1471
1472 %{
1473 id: report_id,
1474 second_report_id: second_report_id
1475 }
1476 end
1477
1478 test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do
1479 read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"])
1480 write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])
1481
1482 response =
1483 conn
1484 |> assign(:token, read_token)
1485 |> patch("/api/pleroma/admin/reports", %{
1486 "reports" => [%{"state" => "resolved", "id" => id}]
1487 })
1488 |> json_response(403)
1489
1490 assert response == %{
1491 "error" => "Insufficient permissions: admin:write:reports."
1492 }
1493
1494 conn
1495 |> assign(:token, write_token)
1496 |> patch("/api/pleroma/admin/reports", %{
1497 "reports" => [%{"state" => "resolved", "id" => id}]
1498 })
1499 |> json_response(:no_content)
1500 end
1501
1502 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1503 conn
1504 |> patch("/api/pleroma/admin/reports", %{
1505 "reports" => [
1506 %{"state" => "resolved", "id" => id}
1507 ]
1508 })
1509 |> json_response(:no_content)
1510
1511 activity = Activity.get_by_id(id)
1512 assert activity.data["state"] == "resolved"
1513
1514 log_entry = Repo.one(ModerationLog)
1515
1516 assert ModerationLog.get_log_entry_message(log_entry) ==
1517 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1518 end
1519
1520 test "closes report", %{conn: conn, id: id, admin: admin} do
1521 conn
1522 |> patch("/api/pleroma/admin/reports", %{
1523 "reports" => [
1524 %{"state" => "closed", "id" => id}
1525 ]
1526 })
1527 |> json_response(:no_content)
1528
1529 activity = Activity.get_by_id(id)
1530 assert activity.data["state"] == "closed"
1531
1532 log_entry = Repo.one(ModerationLog)
1533
1534 assert ModerationLog.get_log_entry_message(log_entry) ==
1535 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1536 end
1537
1538 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1539 conn =
1540 conn
1541 |> patch("/api/pleroma/admin/reports", %{
1542 "reports" => [
1543 %{"state" => "test", "id" => id}
1544 ]
1545 })
1546
1547 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1548 end
1549
1550 test "returns 404 when report is not exist", %{conn: conn} do
1551 conn =
1552 conn
1553 |> patch("/api/pleroma/admin/reports", %{
1554 "reports" => [
1555 %{"state" => "closed", "id" => "test"}
1556 ]
1557 })
1558
1559 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1560 end
1561
1562 test "updates state of multiple reports", %{
1563 conn: conn,
1564 id: id,
1565 admin: admin,
1566 second_report_id: second_report_id
1567 } do
1568 conn
1569 |> patch("/api/pleroma/admin/reports", %{
1570 "reports" => [
1571 %{"state" => "resolved", "id" => id},
1572 %{"state" => "closed", "id" => second_report_id}
1573 ]
1574 })
1575 |> json_response(:no_content)
1576
1577 activity = Activity.get_by_id(id)
1578 second_activity = Activity.get_by_id(second_report_id)
1579 assert activity.data["state"] == "resolved"
1580 assert second_activity.data["state"] == "closed"
1581
1582 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1583
1584 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1585 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1586
1587 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1588 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1589 end
1590 end
1591
1592 describe "GET /api/pleroma/admin/reports" do
1593 test "returns empty response when no reports created", %{conn: conn} do
1594 response =
1595 conn
1596 |> get("/api/pleroma/admin/reports")
1597 |> json_response(:ok)
1598
1599 assert Enum.empty?(response["reports"])
1600 assert response["total"] == 0
1601 end
1602
1603 test "returns reports", %{conn: conn} do
1604 [reporter, target_user] = insert_pair(:user)
1605 activity = insert(:note_activity, user: target_user)
1606
1607 {:ok, %{id: report_id}} =
1608 CommonAPI.report(reporter, %{
1609 account_id: target_user.id,
1610 comment: "I feel offended",
1611 status_ids: [activity.id]
1612 })
1613
1614 response =
1615 conn
1616 |> get("/api/pleroma/admin/reports")
1617 |> json_response(:ok)
1618
1619 [report] = response["reports"]
1620
1621 assert length(response["reports"]) == 1
1622 assert report["id"] == report_id
1623
1624 assert response["total"] == 1
1625 end
1626
1627 test "returns reports with specified state", %{conn: conn} do
1628 [reporter, target_user] = insert_pair(:user)
1629 activity = insert(:note_activity, user: target_user)
1630
1631 {:ok, %{id: first_report_id}} =
1632 CommonAPI.report(reporter, %{
1633 account_id: target_user.id,
1634 comment: "I feel offended",
1635 status_ids: [activity.id]
1636 })
1637
1638 {:ok, %{id: second_report_id}} =
1639 CommonAPI.report(reporter, %{
1640 account_id: target_user.id,
1641 comment: "I don't like this user"
1642 })
1643
1644 CommonAPI.update_report_state(second_report_id, "closed")
1645
1646 response =
1647 conn
1648 |> get("/api/pleroma/admin/reports", %{
1649 "state" => "open"
1650 })
1651 |> json_response(:ok)
1652
1653 [open_report] = response["reports"]
1654
1655 assert length(response["reports"]) == 1
1656 assert open_report["id"] == first_report_id
1657
1658 assert response["total"] == 1
1659
1660 response =
1661 conn
1662 |> get("/api/pleroma/admin/reports", %{
1663 "state" => "closed"
1664 })
1665 |> json_response(:ok)
1666
1667 [closed_report] = response["reports"]
1668
1669 assert length(response["reports"]) == 1
1670 assert closed_report["id"] == second_report_id
1671
1672 assert response["total"] == 1
1673
1674 response =
1675 conn
1676 |> get("/api/pleroma/admin/reports", %{
1677 "state" => "resolved"
1678 })
1679 |> json_response(:ok)
1680
1681 assert Enum.empty?(response["reports"])
1682 assert response["total"] == 0
1683 end
1684
1685 test "returns 403 when requested by a non-admin" do
1686 user = insert(:user)
1687 token = insert(:oauth_token, user: user)
1688
1689 conn =
1690 build_conn()
1691 |> assign(:user, user)
1692 |> assign(:token, token)
1693 |> get("/api/pleroma/admin/reports")
1694
1695 assert json_response(conn, :forbidden) ==
1696 %{"error" => "User is not an admin or OAuth admin scope is not granted."}
1697 end
1698
1699 test "returns 403 when requested by anonymous" do
1700 conn = get(build_conn(), "/api/pleroma/admin/reports")
1701
1702 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1703 end
1704 end
1705
1706 describe "GET /api/pleroma/admin/restart" do
1707 setup do: clear_config(:configurable_from_database, true)
1708
1709 test "pleroma restarts", %{conn: conn} do
1710 capture_log(fn ->
1711 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1712 end) =~ "pleroma restarted"
1713
1714 refute Restarter.Pleroma.need_reboot?()
1715 end
1716 end
1717
1718 test "need_reboot flag", %{conn: conn} do
1719 assert conn
1720 |> get("/api/pleroma/admin/need_reboot")
1721 |> json_response(200) == %{"need_reboot" => false}
1722
1723 Restarter.Pleroma.need_reboot()
1724
1725 assert conn
1726 |> get("/api/pleroma/admin/need_reboot")
1727 |> json_response(200) == %{"need_reboot" => true}
1728
1729 on_exit(fn -> Restarter.Pleroma.refresh() end)
1730 end
1731
1732 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
1733 setup do
1734 user = insert(:user)
1735
1736 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1737 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1738 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1739
1740 insert(:note_activity, user: user, published: date1)
1741 insert(:note_activity, user: user, published: date2)
1742 insert(:note_activity, user: user, published: date3)
1743
1744 %{user: user}
1745 end
1746
1747 test "renders user's statuses", %{conn: conn, user: user} do
1748 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1749
1750 assert json_response(conn, 200) |> length() == 3
1751 end
1752
1753 test "renders user's statuses with a limit", %{conn: conn, user: user} do
1754 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
1755
1756 assert json_response(conn, 200) |> length() == 2
1757 end
1758
1759 test "doesn't return private statuses by default", %{conn: conn, user: user} do
1760 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1761
1762 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1763
1764 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1765
1766 assert json_response(conn, 200) |> length() == 4
1767 end
1768
1769 test "returns private statuses with godmode on", %{conn: conn, user: user} do
1770 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1771
1772 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1773
1774 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
1775
1776 assert json_response(conn, 200) |> length() == 5
1777 end
1778
1779 test "excludes reblogs by default", %{conn: conn, user: user} do
1780 other_user = insert(:user)
1781 {:ok, activity} = CommonAPI.post(user, %{status: "."})
1782 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
1783
1784 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
1785 assert json_response(conn_res, 200) |> length() == 0
1786
1787 conn_res =
1788 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
1789
1790 assert json_response(conn_res, 200) |> length() == 1
1791 end
1792 end
1793
1794 describe "GET /api/pleroma/admin/moderation_log" do
1795 setup do
1796 moderator = insert(:user, is_moderator: true)
1797
1798 %{moderator: moderator}
1799 end
1800
1801 test "returns the log", %{conn: conn, admin: admin} do
1802 Repo.insert(%ModerationLog{
1803 data: %{
1804 actor: %{
1805 "id" => admin.id,
1806 "nickname" => admin.nickname,
1807 "type" => "user"
1808 },
1809 action: "relay_follow",
1810 target: "https://example.org/relay"
1811 },
1812 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1813 })
1814
1815 Repo.insert(%ModerationLog{
1816 data: %{
1817 actor: %{
1818 "id" => admin.id,
1819 "nickname" => admin.nickname,
1820 "type" => "user"
1821 },
1822 action: "relay_unfollow",
1823 target: "https://example.org/relay"
1824 },
1825 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1826 })
1827
1828 conn = get(conn, "/api/pleroma/admin/moderation_log")
1829
1830 response = json_response(conn, 200)
1831 [first_entry, second_entry] = response["items"]
1832
1833 assert response["total"] == 2
1834 assert first_entry["data"]["action"] == "relay_unfollow"
1835
1836 assert first_entry["message"] ==
1837 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1838
1839 assert second_entry["data"]["action"] == "relay_follow"
1840
1841 assert second_entry["message"] ==
1842 "@#{admin.nickname} followed relay: https://example.org/relay"
1843 end
1844
1845 test "returns the log with pagination", %{conn: conn, admin: admin} do
1846 Repo.insert(%ModerationLog{
1847 data: %{
1848 actor: %{
1849 "id" => admin.id,
1850 "nickname" => admin.nickname,
1851 "type" => "user"
1852 },
1853 action: "relay_follow",
1854 target: "https://example.org/relay"
1855 },
1856 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1857 })
1858
1859 Repo.insert(%ModerationLog{
1860 data: %{
1861 actor: %{
1862 "id" => admin.id,
1863 "nickname" => admin.nickname,
1864 "type" => "user"
1865 },
1866 action: "relay_unfollow",
1867 target: "https://example.org/relay"
1868 },
1869 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1870 })
1871
1872 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1873
1874 response1 = json_response(conn1, 200)
1875 [first_entry] = response1["items"]
1876
1877 assert response1["total"] == 2
1878 assert response1["items"] |> length() == 1
1879 assert first_entry["data"]["action"] == "relay_unfollow"
1880
1881 assert first_entry["message"] ==
1882 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1883
1884 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1885
1886 response2 = json_response(conn2, 200)
1887 [second_entry] = response2["items"]
1888
1889 assert response2["total"] == 2
1890 assert response2["items"] |> length() == 1
1891 assert second_entry["data"]["action"] == "relay_follow"
1892
1893 assert second_entry["message"] ==
1894 "@#{admin.nickname} followed relay: https://example.org/relay"
1895 end
1896
1897 test "filters log by date", %{conn: conn, admin: admin} do
1898 first_date = "2017-08-15T15:47:06Z"
1899 second_date = "2017-08-20T15:47:06Z"
1900
1901 Repo.insert(%ModerationLog{
1902 data: %{
1903 actor: %{
1904 "id" => admin.id,
1905 "nickname" => admin.nickname,
1906 "type" => "user"
1907 },
1908 action: "relay_follow",
1909 target: "https://example.org/relay"
1910 },
1911 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1912 })
1913
1914 Repo.insert(%ModerationLog{
1915 data: %{
1916 actor: %{
1917 "id" => admin.id,
1918 "nickname" => admin.nickname,
1919 "type" => "user"
1920 },
1921 action: "relay_unfollow",
1922 target: "https://example.org/relay"
1923 },
1924 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1925 })
1926
1927 conn1 =
1928 get(
1929 conn,
1930 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1931 )
1932
1933 response1 = json_response(conn1, 200)
1934 [first_entry] = response1["items"]
1935
1936 assert response1["total"] == 1
1937 assert first_entry["data"]["action"] == "relay_unfollow"
1938
1939 assert first_entry["message"] ==
1940 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1941 end
1942
1943 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1944 Repo.insert(%ModerationLog{
1945 data: %{
1946 actor: %{
1947 "id" => admin.id,
1948 "nickname" => admin.nickname,
1949 "type" => "user"
1950 },
1951 action: "relay_follow",
1952 target: "https://example.org/relay"
1953 }
1954 })
1955
1956 Repo.insert(%ModerationLog{
1957 data: %{
1958 actor: %{
1959 "id" => moderator.id,
1960 "nickname" => moderator.nickname,
1961 "type" => "user"
1962 },
1963 action: "relay_unfollow",
1964 target: "https://example.org/relay"
1965 }
1966 })
1967
1968 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1969
1970 response1 = json_response(conn1, 200)
1971 [first_entry] = response1["items"]
1972
1973 assert response1["total"] == 1
1974 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1975 end
1976
1977 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1978 ModerationLog.insert_log(%{
1979 actor: moderator,
1980 action: "relay_follow",
1981 target: "https://example.org/relay"
1982 })
1983
1984 ModerationLog.insert_log(%{
1985 actor: moderator,
1986 action: "relay_unfollow",
1987 target: "https://example.org/relay"
1988 })
1989
1990 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1991
1992 response1 = json_response(conn1, 200)
1993 [first_entry] = response1["items"]
1994
1995 assert response1["total"] == 1
1996
1997 assert get_in(first_entry, ["data", "message"]) ==
1998 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1999 end
2000 end
2001
2002 describe "GET /users/:nickname/credentials" do
2003 test "gets the user credentials", %{conn: conn} do
2004 user = insert(:user)
2005 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
2006
2007 response = assert json_response(conn, 200)
2008 assert response["email"] == user.email
2009 end
2010
2011 test "returns 403 if requested by a non-admin" do
2012 user = insert(:user)
2013
2014 conn =
2015 build_conn()
2016 |> assign(:user, user)
2017 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
2018
2019 assert json_response(conn, :forbidden)
2020 end
2021 end
2022
2023 describe "PATCH /users/:nickname/credentials" do
2024 setup do
2025 user = insert(:user)
2026 [user: user]
2027 end
2028
2029 test "changes password and email", %{conn: conn, admin: admin, user: user} do
2030 assert user.password_reset_pending == false
2031
2032 conn =
2033 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
2034 "password" => "new_password",
2035 "email" => "new_email@example.com",
2036 "name" => "new_name"
2037 })
2038
2039 assert json_response(conn, 200) == %{"status" => "success"}
2040
2041 ObanHelpers.perform_all()
2042
2043 updated_user = User.get_by_id(user.id)
2044
2045 assert updated_user.email == "new_email@example.com"
2046 assert updated_user.name == "new_name"
2047 assert updated_user.password_hash != user.password_hash
2048 assert updated_user.password_reset_pending == true
2049
2050 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
2051
2052 assert ModerationLog.get_log_entry_message(log_entry1) ==
2053 "@#{admin.nickname} updated users: @#{user.nickname}"
2054
2055 assert ModerationLog.get_log_entry_message(log_entry2) ==
2056 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
2057 end
2058
2059 test "returns 403 if requested by a non-admin", %{user: user} do
2060 conn =
2061 build_conn()
2062 |> assign(:user, user)
2063 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
2064 "password" => "new_password",
2065 "email" => "new_email@example.com",
2066 "name" => "new_name"
2067 })
2068
2069 assert json_response(conn, :forbidden)
2070 end
2071
2072 test "changes actor type from permitted list", %{conn: conn, user: user} do
2073 assert user.actor_type == "Person"
2074
2075 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
2076 "actor_type" => "Service"
2077 })
2078 |> json_response(200) == %{"status" => "success"}
2079
2080 updated_user = User.get_by_id(user.id)
2081
2082 assert updated_user.actor_type == "Service"
2083
2084 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
2085 "actor_type" => "Application"
2086 })
2087 |> json_response(200) == %{"errors" => %{"actor_type" => "is invalid"}}
2088 end
2089
2090 test "update non existing user", %{conn: conn} do
2091 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
2092 "password" => "new_password"
2093 })
2094 |> json_response(200) == %{"error" => "Unable to update user."}
2095 end
2096 end
2097
2098 describe "PATCH /users/:nickname/force_password_reset" do
2099 test "sets password_reset_pending to true", %{conn: conn} do
2100 user = insert(:user)
2101 assert user.password_reset_pending == false
2102
2103 conn =
2104 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
2105
2106 assert json_response(conn, 204) == ""
2107
2108 ObanHelpers.perform_all()
2109
2110 assert User.get_by_id(user.id).password_reset_pending == true
2111 end
2112 end
2113
2114 describe "relays" do
2115 test "POST /relay", %{conn: conn, admin: admin} do
2116 conn =
2117 post(conn, "/api/pleroma/admin/relay", %{
2118 relay_url: "http://mastodon.example.org/users/admin"
2119 })
2120
2121 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2122
2123 log_entry = Repo.one(ModerationLog)
2124
2125 assert ModerationLog.get_log_entry_message(log_entry) ==
2126 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2127 end
2128
2129 test "GET /relay", %{conn: conn} do
2130 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
2131
2132 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
2133 |> Enum.each(fn ap_id ->
2134 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
2135 User.follow(relay_user, user)
2136 end)
2137
2138 conn = get(conn, "/api/pleroma/admin/relay")
2139
2140 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
2141 end
2142
2143 test "DELETE /relay", %{conn: conn, admin: admin} do
2144 post(conn, "/api/pleroma/admin/relay", %{
2145 relay_url: "http://mastodon.example.org/users/admin"
2146 })
2147
2148 conn =
2149 delete(conn, "/api/pleroma/admin/relay", %{
2150 relay_url: "http://mastodon.example.org/users/admin"
2151 })
2152
2153 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2154
2155 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
2156
2157 assert ModerationLog.get_log_entry_message(log_entry_one) ==
2158 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2159
2160 assert ModerationLog.get_log_entry_message(log_entry_two) ==
2161 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
2162 end
2163 end
2164
2165 describe "instances" do
2166 test "GET /instances/:instance/statuses", %{conn: conn} do
2167 user = insert(:user, local: false, nickname: "archaeme@archae.me")
2168 user2 = insert(:user, local: false, nickname: "test@test.com")
2169 insert_pair(:note_activity, user: user)
2170 activity = insert(:note_activity, user: user2)
2171
2172 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
2173
2174 response = json_response(ret_conn, 200)
2175
2176 assert length(response) == 2
2177
2178 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
2179
2180 response = json_response(ret_conn, 200)
2181
2182 assert length(response) == 1
2183
2184 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
2185
2186 response = json_response(ret_conn, 200)
2187
2188 assert Enum.empty?(response)
2189
2190 CommonAPI.repeat(activity.id, user)
2191
2192 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
2193 response = json_response(ret_conn, 200)
2194 assert length(response) == 2
2195
2196 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
2197 response = json_response(ret_conn, 200)
2198 assert length(response) == 3
2199 end
2200 end
2201
2202 describe "PATCH /confirm_email" do
2203 test "it confirms emails of two users", %{conn: conn, admin: admin} do
2204 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2205
2206 assert first_user.confirmation_pending == true
2207 assert second_user.confirmation_pending == true
2208
2209 ret_conn =
2210 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
2211 nicknames: [
2212 first_user.nickname,
2213 second_user.nickname
2214 ]
2215 })
2216
2217 assert ret_conn.status == 200
2218
2219 assert first_user.confirmation_pending == true
2220 assert second_user.confirmation_pending == true
2221
2222 log_entry = Repo.one(ModerationLog)
2223
2224 assert ModerationLog.get_log_entry_message(log_entry) ==
2225 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
2226 second_user.nickname
2227 }"
2228 end
2229 end
2230
2231 describe "PATCH /resend_confirmation_email" do
2232 test "it resend emails for two users", %{conn: conn, admin: admin} do
2233 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2234
2235 ret_conn =
2236 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
2237 nicknames: [
2238 first_user.nickname,
2239 second_user.nickname
2240 ]
2241 })
2242
2243 assert ret_conn.status == 200
2244
2245 log_entry = Repo.one(ModerationLog)
2246
2247 assert ModerationLog.get_log_entry_message(log_entry) ==
2248 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
2249 second_user.nickname
2250 }"
2251 end
2252 end
2253
2254 describe "POST /reports/:id/notes" do
2255 setup %{conn: conn, admin: admin} do
2256 [reporter, target_user] = insert_pair(:user)
2257 activity = insert(:note_activity, user: target_user)
2258
2259 {:ok, %{id: report_id}} =
2260 CommonAPI.report(reporter, %{
2261 account_id: target_user.id,
2262 comment: "I feel offended",
2263 status_ids: [activity.id]
2264 })
2265
2266 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
2267 content: "this is disgusting!"
2268 })
2269
2270 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
2271 content: "this is disgusting2!"
2272 })
2273
2274 %{
2275 admin_id: admin.id,
2276 report_id: report_id
2277 }
2278 end
2279
2280 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
2281 [note, _] = Repo.all(ReportNote)
2282
2283 assert %{
2284 activity_id: ^report_id,
2285 content: "this is disgusting!",
2286 user_id: ^admin_id
2287 } = note
2288 end
2289
2290 test "it returns reports with notes", %{conn: conn, admin: admin} do
2291 conn = get(conn, "/api/pleroma/admin/reports")
2292
2293 response = json_response(conn, 200)
2294 notes = hd(response["reports"])["notes"]
2295 [note, _] = notes
2296
2297 assert note["user"]["nickname"] == admin.nickname
2298 assert note["content"] == "this is disgusting!"
2299 assert note["created_at"]
2300 assert response["total"] == 1
2301 end
2302
2303 test "it deletes the note", %{conn: conn, report_id: report_id} do
2304 assert ReportNote |> Repo.all() |> length() == 2
2305
2306 [note, _] = Repo.all(ReportNote)
2307
2308 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
2309
2310 assert ReportNote |> Repo.all() |> length() == 1
2311 end
2312 end
2313
2314 describe "/api/pleroma/admin/stats" do
2315 test "status visibility count", %{conn: conn} do
2316 admin = insert(:user, is_admin: true)
2317 user = insert(:user)
2318 CommonAPI.post(user, %{visibility: "public", status: "hey"})
2319 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
2320 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
2321
2322 response =
2323 conn
2324 |> assign(:user, admin)
2325 |> get("/api/pleroma/admin/stats")
2326 |> json_response(200)
2327
2328 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
2329 response["status_visibility"]
2330 end
2331 end
2332
2333 describe "POST /api/pleroma/admin/oauth_app" do
2334 test "errors", %{conn: conn} do
2335 response = conn |> post("/api/pleroma/admin/oauth_app", %{}) |> json_response(200)
2336
2337 assert response == %{"name" => "can't be blank", "redirect_uris" => "can't be blank"}
2338 end
2339
2340 test "success", %{conn: conn} do
2341 base_url = Web.base_url()
2342 app_name = "Trusted app"
2343
2344 response =
2345 conn
2346 |> post("/api/pleroma/admin/oauth_app", %{
2347 name: app_name,
2348 redirect_uris: base_url
2349 })
2350 |> json_response(200)
2351
2352 assert %{
2353 "client_id" => _,
2354 "client_secret" => _,
2355 "name" => ^app_name,
2356 "redirect_uri" => ^base_url,
2357 "trusted" => false
2358 } = response
2359 end
2360
2361 test "with trusted", %{conn: conn} do
2362 base_url = Web.base_url()
2363 app_name = "Trusted app"
2364
2365 response =
2366 conn
2367 |> post("/api/pleroma/admin/oauth_app", %{
2368 name: app_name,
2369 redirect_uris: base_url,
2370 trusted: true
2371 })
2372 |> json_response(200)
2373
2374 assert %{
2375 "client_id" => _,
2376 "client_secret" => _,
2377 "name" => ^app_name,
2378 "redirect_uri" => ^base_url,
2379 "trusted" => true
2380 } = response
2381 end
2382 end
2383
2384 describe "GET /api/pleroma/admin/oauth_app" do
2385 setup do
2386 app = insert(:oauth_app)
2387 {:ok, app: app}
2388 end
2389
2390 test "list", %{conn: conn} do
2391 response =
2392 conn
2393 |> get("/api/pleroma/admin/oauth_app")
2394 |> json_response(200)
2395
2396 assert %{"apps" => apps, "count" => count, "page_size" => _} = response
2397
2398 assert length(apps) == count
2399 end
2400
2401 test "with page size", %{conn: conn} do
2402 insert(:oauth_app)
2403 page_size = 1
2404
2405 response =
2406 conn
2407 |> get("/api/pleroma/admin/oauth_app", %{page_size: to_string(page_size)})
2408 |> json_response(200)
2409
2410 assert %{"apps" => apps, "count" => _, "page_size" => ^page_size} = response
2411
2412 assert length(apps) == page_size
2413 end
2414
2415 test "search by client name", %{conn: conn, app: app} do
2416 response =
2417 conn
2418 |> get("/api/pleroma/admin/oauth_app", %{name: app.client_name})
2419 |> json_response(200)
2420
2421 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
2422
2423 assert returned["client_id"] == app.client_id
2424 assert returned["name"] == app.client_name
2425 end
2426
2427 test "search by client id", %{conn: conn, app: app} do
2428 response =
2429 conn
2430 |> get("/api/pleroma/admin/oauth_app", %{client_id: app.client_id})
2431 |> json_response(200)
2432
2433 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
2434
2435 assert returned["client_id"] == app.client_id
2436 assert returned["name"] == app.client_name
2437 end
2438
2439 test "only trusted", %{conn: conn} do
2440 app = insert(:oauth_app, trusted: true)
2441
2442 response =
2443 conn
2444 |> get("/api/pleroma/admin/oauth_app", %{trusted: true})
2445 |> json_response(200)
2446
2447 assert %{"apps" => [returned], "count" => _, "page_size" => _} = response
2448
2449 assert returned["client_id"] == app.client_id
2450 assert returned["name"] == app.client_name
2451 end
2452 end
2453
2454 describe "DELETE /api/pleroma/admin/oauth_app/:id" do
2455 test "with id", %{conn: conn} do
2456 app = insert(:oauth_app)
2457
2458 response =
2459 conn
2460 |> delete("/api/pleroma/admin/oauth_app/" <> to_string(app.id))
2461 |> json_response(:no_content)
2462
2463 assert response == ""
2464 end
2465
2466 test "with non existance id", %{conn: conn} do
2467 response =
2468 conn
2469 |> delete("/api/pleroma/admin/oauth_app/0")
2470 |> json_response(:bad_request)
2471
2472 assert response == ""
2473 end
2474 end
2475
2476 describe "PATCH /api/pleroma/admin/oauth_app/:id" do
2477 test "with id", %{conn: conn} do
2478 app = insert(:oauth_app)
2479
2480 name = "another name"
2481 url = "https://example.com"
2482 scopes = ["admin"]
2483 id = app.id
2484 website = "http://website.com"
2485
2486 response =
2487 conn
2488 |> patch("/api/pleroma/admin/oauth_app/" <> to_string(app.id), %{
2489 name: name,
2490 trusted: true,
2491 redirect_uris: url,
2492 scopes: scopes,
2493 website: website
2494 })
2495 |> json_response(200)
2496
2497 assert %{
2498 "client_id" => _,
2499 "client_secret" => _,
2500 "id" => ^id,
2501 "name" => ^name,
2502 "redirect_uri" => ^url,
2503 "trusted" => true,
2504 "website" => ^website
2505 } = response
2506 end
2507
2508 test "without id", %{conn: conn} do
2509 response =
2510 conn
2511 |> patch("/api/pleroma/admin/oauth_app/0")
2512 |> json_response(:bad_request)
2513
2514 assert response == ""
2515 end
2516 end
2517 end
2518
2519 # Needed for testing
2520 defmodule Pleroma.Web.Endpoint.NotReal do
2521 end
2522
2523 defmodule Pleroma.Captcha.NotReal do
2524 end