Merge branch 'develop' into feature/admin-api-render-whole-status
[akkoma] / test / web / admin_api / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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 alias Pleroma.Activity
10 alias Pleroma.HTML
11 alias Pleroma.ModerationLog
12 alias Pleroma.Repo
13 alias Pleroma.Tests.ObanHelpers
14 alias Pleroma.User
15 alias Pleroma.UserInviteToken
16 alias Pleroma.Web.ActivityPub.Relay
17 alias Pleroma.Web.CommonAPI
18 alias Pleroma.Web.MastodonAPI.StatusView
19 alias Pleroma.Web.MediaProxy
20 import Pleroma.Factory
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24
25 :ok
26 end
27
28 describe "DELETE /api/pleroma/admin/users" do
29 test "single user" do
30 admin = insert(:user, is_admin: true)
31 user = insert(:user)
32
33 conn =
34 build_conn()
35 |> assign(:user, admin)
36 |> put_req_header("accept", "application/json")
37 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
38
39 log_entry = Repo.one(ModerationLog)
40
41 assert ModerationLog.get_log_entry_message(log_entry) ==
42 "@#{admin.nickname} deleted users: @#{user.nickname}"
43
44 assert json_response(conn, 200) == user.nickname
45 end
46
47 test "multiple users" do
48 admin = insert(:user, is_admin: true)
49 user_one = insert(:user)
50 user_two = insert(:user)
51
52 conn =
53 build_conn()
54 |> assign(:user, admin)
55 |> put_req_header("accept", "application/json")
56 |> delete("/api/pleroma/admin/users", %{
57 nicknames: [user_one.nickname, user_two.nickname]
58 })
59
60 log_entry = Repo.one(ModerationLog)
61
62 assert ModerationLog.get_log_entry_message(log_entry) ==
63 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
64
65 response = json_response(conn, 200)
66 assert response -- [user_one.nickname, user_two.nickname] == []
67 end
68 end
69
70 describe "/api/pleroma/admin/users" do
71 test "Create" do
72 admin = insert(:user, is_admin: true)
73
74 conn =
75 build_conn()
76 |> assign(:user, admin)
77 |> put_req_header("accept", "application/json")
78 |> post("/api/pleroma/admin/users", %{
79 "users" => [
80 %{
81 "nickname" => "lain",
82 "email" => "lain@example.org",
83 "password" => "test"
84 },
85 %{
86 "nickname" => "lain2",
87 "email" => "lain2@example.org",
88 "password" => "test"
89 }
90 ]
91 })
92
93 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
94 assert response == ["success", "success"]
95
96 log_entry = Repo.one(ModerationLog)
97
98 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
99 end
100
101 test "Cannot create user with exisiting email" do
102 admin = insert(:user, is_admin: true)
103 user = insert(:user)
104
105 conn =
106 build_conn()
107 |> assign(:user, admin)
108 |> put_req_header("accept", "application/json")
109 |> post("/api/pleroma/admin/users", %{
110 "users" => [
111 %{
112 "nickname" => "lain",
113 "email" => user.email,
114 "password" => "test"
115 }
116 ]
117 })
118
119 assert json_response(conn, 409) == [
120 %{
121 "code" => 409,
122 "data" => %{
123 "email" => user.email,
124 "nickname" => "lain"
125 },
126 "error" => "email has already been taken",
127 "type" => "error"
128 }
129 ]
130 end
131
132 test "Cannot create user with exisiting nickname" do
133 admin = insert(:user, is_admin: true)
134 user = insert(:user)
135
136 conn =
137 build_conn()
138 |> assign(:user, admin)
139 |> put_req_header("accept", "application/json")
140 |> post("/api/pleroma/admin/users", %{
141 "users" => [
142 %{
143 "nickname" => user.nickname,
144 "email" => "someuser@plerama.social",
145 "password" => "test"
146 }
147 ]
148 })
149
150 assert json_response(conn, 409) == [
151 %{
152 "code" => 409,
153 "data" => %{
154 "email" => "someuser@plerama.social",
155 "nickname" => user.nickname
156 },
157 "error" => "nickname has already been taken",
158 "type" => "error"
159 }
160 ]
161 end
162
163 test "Multiple user creation works in transaction" do
164 admin = insert(:user, is_admin: true)
165 user = insert(:user)
166
167 conn =
168 build_conn()
169 |> assign(:user, admin)
170 |> put_req_header("accept", "application/json")
171 |> post("/api/pleroma/admin/users", %{
172 "users" => [
173 %{
174 "nickname" => "newuser",
175 "email" => "newuser@pleroma.social",
176 "password" => "test"
177 },
178 %{
179 "nickname" => "lain",
180 "email" => user.email,
181 "password" => "test"
182 }
183 ]
184 })
185
186 assert json_response(conn, 409) == [
187 %{
188 "code" => 409,
189 "data" => %{
190 "email" => user.email,
191 "nickname" => "lain"
192 },
193 "error" => "email has already been taken",
194 "type" => "error"
195 },
196 %{
197 "code" => 409,
198 "data" => %{
199 "email" => "newuser@pleroma.social",
200 "nickname" => "newuser"
201 },
202 "error" => "",
203 "type" => "error"
204 }
205 ]
206
207 assert User.get_by_nickname("newuser") === nil
208 end
209 end
210
211 describe "/api/pleroma/admin/users/:nickname" do
212 test "Show", %{conn: conn} do
213 admin = insert(:user, is_admin: true)
214 user = insert(:user)
215
216 conn =
217 conn
218 |> assign(:user, admin)
219 |> get("/api/pleroma/admin/users/#{user.nickname}")
220
221 expected = %{
222 "deactivated" => false,
223 "id" => to_string(user.id),
224 "local" => true,
225 "nickname" => user.nickname,
226 "roles" => %{"admin" => false, "moderator" => false},
227 "tags" => [],
228 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
229 "display_name" => HTML.strip_tags(user.name || user.nickname),
230 "confirmation_pending" => false
231 }
232
233 assert expected == json_response(conn, 200)
234 end
235
236 test "when the user doesn't exist", %{conn: conn} do
237 admin = insert(:user, is_admin: true)
238 user = build(:user)
239
240 conn =
241 conn
242 |> assign(:user, admin)
243 |> get("/api/pleroma/admin/users/#{user.nickname}")
244
245 assert "Not found" == json_response(conn, 404)
246 end
247 end
248
249 describe "/api/pleroma/admin/users/follow" do
250 test "allows to force-follow another user" do
251 admin = insert(:user, is_admin: true)
252 user = insert(:user)
253 follower = insert(:user)
254
255 build_conn()
256 |> assign(:user, admin)
257 |> put_req_header("accept", "application/json")
258 |> post("/api/pleroma/admin/users/follow", %{
259 "follower" => follower.nickname,
260 "followed" => user.nickname
261 })
262
263 user = User.get_cached_by_id(user.id)
264 follower = User.get_cached_by_id(follower.id)
265
266 assert User.following?(follower, user)
267
268 log_entry = Repo.one(ModerationLog)
269
270 assert ModerationLog.get_log_entry_message(log_entry) ==
271 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
272 end
273 end
274
275 describe "/api/pleroma/admin/users/unfollow" do
276 test "allows to force-unfollow another user" do
277 admin = insert(:user, is_admin: true)
278 user = insert(:user)
279 follower = insert(:user)
280
281 User.follow(follower, user)
282
283 build_conn()
284 |> assign(:user, admin)
285 |> put_req_header("accept", "application/json")
286 |> post("/api/pleroma/admin/users/unfollow", %{
287 "follower" => follower.nickname,
288 "followed" => user.nickname
289 })
290
291 user = User.get_cached_by_id(user.id)
292 follower = User.get_cached_by_id(follower.id)
293
294 refute User.following?(follower, user)
295
296 log_entry = Repo.one(ModerationLog)
297
298 assert ModerationLog.get_log_entry_message(log_entry) ==
299 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
300 end
301 end
302
303 describe "PUT /api/pleroma/admin/users/tag" do
304 setup do
305 admin = insert(:user, is_admin: true)
306 user1 = insert(:user, %{tags: ["x"]})
307 user2 = insert(:user, %{tags: ["y"]})
308 user3 = insert(:user, %{tags: ["unchanged"]})
309
310 conn =
311 build_conn()
312 |> assign(:user, admin)
313 |> put_req_header("accept", "application/json")
314 |> put(
315 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=#{
316 user2.nickname
317 }&tags[]=foo&tags[]=bar"
318 )
319
320 %{conn: conn, admin: admin, user1: user1, user2: user2, user3: user3}
321 end
322
323 test "it appends specified tags to users with specified nicknames", %{
324 conn: conn,
325 admin: admin,
326 user1: user1,
327 user2: user2
328 } do
329 assert json_response(conn, :no_content)
330 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
331 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
332
333 log_entry = Repo.one(ModerationLog)
334
335 users =
336 [user1.nickname, user2.nickname]
337 |> Enum.map(&"@#{&1}")
338 |> Enum.join(", ")
339
340 tags = ["foo", "bar"] |> Enum.join(", ")
341
342 assert ModerationLog.get_log_entry_message(log_entry) ==
343 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
344 end
345
346 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
347 assert json_response(conn, :no_content)
348 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
349 end
350 end
351
352 describe "DELETE /api/pleroma/admin/users/tag" do
353 setup do
354 admin = insert(:user, is_admin: true)
355 user1 = insert(:user, %{tags: ["x"]})
356 user2 = insert(:user, %{tags: ["y", "z"]})
357 user3 = insert(:user, %{tags: ["unchanged"]})
358
359 conn =
360 build_conn()
361 |> assign(:user, admin)
362 |> put_req_header("accept", "application/json")
363 |> delete(
364 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=#{
365 user2.nickname
366 }&tags[]=x&tags[]=z"
367 )
368
369 %{conn: conn, admin: admin, user1: user1, user2: user2, user3: user3}
370 end
371
372 test "it removes specified tags from users with specified nicknames", %{
373 conn: conn,
374 admin: admin,
375 user1: user1,
376 user2: user2
377 } do
378 assert json_response(conn, :no_content)
379 assert User.get_cached_by_id(user1.id).tags == []
380 assert User.get_cached_by_id(user2.id).tags == ["y"]
381
382 log_entry = Repo.one(ModerationLog)
383
384 users =
385 [user1.nickname, user2.nickname]
386 |> Enum.map(&"@#{&1}")
387 |> Enum.join(", ")
388
389 tags = ["x", "z"] |> Enum.join(", ")
390
391 assert ModerationLog.get_log_entry_message(log_entry) ==
392 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
393 end
394
395 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
396 assert json_response(conn, :no_content)
397 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
398 end
399 end
400
401 describe "/api/pleroma/admin/users/:nickname/permission_group" do
402 test "GET is giving user_info" do
403 admin = insert(:user, is_admin: true)
404
405 conn =
406 build_conn()
407 |> assign(:user, admin)
408 |> put_req_header("accept", "application/json")
409 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
410
411 assert json_response(conn, 200) == %{
412 "is_admin" => true,
413 "is_moderator" => false
414 }
415 end
416
417 test "/:right POST, can add to a permission group" do
418 admin = insert(:user, is_admin: true)
419 user = insert(:user)
420
421 conn =
422 build_conn()
423 |> assign(:user, admin)
424 |> put_req_header("accept", "application/json")
425 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
426
427 assert json_response(conn, 200) == %{
428 "is_admin" => true
429 }
430
431 log_entry = Repo.one(ModerationLog)
432
433 assert ModerationLog.get_log_entry_message(log_entry) ==
434 "@#{admin.nickname} made @#{user.nickname} admin"
435 end
436
437 test "/:right POST, can add to a permission group (multiple)" do
438 admin = insert(:user, is_admin: true)
439 user_one = insert(:user)
440 user_two = insert(:user)
441
442 conn =
443 build_conn()
444 |> assign(:user, admin)
445 |> put_req_header("accept", "application/json")
446 |> post("/api/pleroma/admin/users/permission_group/admin", %{
447 nicknames: [user_one.nickname, user_two.nickname]
448 })
449
450 assert json_response(conn, 200) == %{
451 "is_admin" => true
452 }
453
454 log_entry = Repo.one(ModerationLog)
455
456 assert ModerationLog.get_log_entry_message(log_entry) ==
457 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
458 end
459
460 test "/:right DELETE, can remove from a permission group" do
461 admin = insert(:user, is_admin: true)
462 user = insert(:user, is_admin: true)
463
464 conn =
465 build_conn()
466 |> assign(:user, admin)
467 |> put_req_header("accept", "application/json")
468 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
469
470 assert json_response(conn, 200) == %{
471 "is_admin" => false
472 }
473
474 log_entry = Repo.one(ModerationLog)
475
476 assert ModerationLog.get_log_entry_message(log_entry) ==
477 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
478 end
479
480 test "/:right DELETE, can remove from a permission group (multiple)" do
481 admin = insert(:user, is_admin: true)
482 user_one = insert(:user, is_admin: true)
483 user_two = insert(:user, is_admin: true)
484
485 conn =
486 build_conn()
487 |> assign(:user, admin)
488 |> put_req_header("accept", "application/json")
489 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
490 nicknames: [user_one.nickname, user_two.nickname]
491 })
492
493 assert json_response(conn, 200) == %{
494 "is_admin" => false
495 }
496
497 log_entry = Repo.one(ModerationLog)
498
499 assert ModerationLog.get_log_entry_message(log_entry) ==
500 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
501 user_two.nickname
502 }"
503 end
504 end
505
506 describe "POST /api/pleroma/admin/email_invite, with valid config" do
507 setup do
508 [user: insert(:user, is_admin: true)]
509 end
510
511 clear_config([:instance, :registrations_open]) do
512 Pleroma.Config.put([:instance, :registrations_open], false)
513 end
514
515 clear_config([:instance, :invites_enabled]) do
516 Pleroma.Config.put([:instance, :invites_enabled], true)
517 end
518
519 test "sends invitation and returns 204", %{conn: conn, user: user} do
520 recipient_email = "foo@bar.com"
521 recipient_name = "J. D."
522
523 conn =
524 conn
525 |> assign(:user, user)
526 |> post(
527 "/api/pleroma/admin/users/email_invite?email=#{recipient_email}&name=#{recipient_name}"
528 )
529
530 assert json_response(conn, :no_content)
531
532 token_record = List.last(Pleroma.Repo.all(Pleroma.UserInviteToken))
533 assert token_record
534 refute token_record.used
535
536 notify_email = Pleroma.Config.get([:instance, :notify_email])
537 instance_name = Pleroma.Config.get([:instance, :name])
538
539 email =
540 Pleroma.Emails.UserEmail.user_invitation_email(
541 user,
542 token_record,
543 recipient_email,
544 recipient_name
545 )
546
547 Swoosh.TestAssertions.assert_email_sent(
548 from: {instance_name, notify_email},
549 to: {recipient_name, recipient_email},
550 html_body: email.html_body
551 )
552 end
553
554 test "it returns 403 if requested by a non-admin", %{conn: conn} do
555 non_admin_user = insert(:user)
556
557 conn =
558 conn
559 |> assign(:user, non_admin_user)
560 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
561
562 assert json_response(conn, :forbidden)
563 end
564 end
565
566 describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do
567 setup do
568 [user: insert(:user, is_admin: true)]
569 end
570
571 clear_config([:instance, :registrations_open])
572 clear_config([:instance, :invites_enabled])
573
574 test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn, user: user} do
575 Pleroma.Config.put([:instance, :registrations_open], false)
576 Pleroma.Config.put([:instance, :invites_enabled], false)
577
578 conn =
579 conn
580 |> assign(:user, user)
581 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
582
583 assert json_response(conn, :internal_server_error)
584 end
585
586 test "it returns 500 if `registrations_open` is enabled", %{conn: conn, user: user} do
587 Pleroma.Config.put([:instance, :registrations_open], true)
588 Pleroma.Config.put([:instance, :invites_enabled], true)
589
590 conn =
591 conn
592 |> assign(:user, user)
593 |> post("/api/pleroma/admin/users/email_invite?email=foo@bar.com&name=JD")
594
595 assert json_response(conn, :internal_server_error)
596 end
597 end
598
599 test "/api/pleroma/admin/users/:nickname/password_reset" do
600 admin = insert(:user, is_admin: true)
601 user = insert(:user)
602
603 conn =
604 build_conn()
605 |> assign(:user, admin)
606 |> put_req_header("accept", "application/json")
607 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
608
609 resp = json_response(conn, 200)
610
611 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
612 end
613
614 describe "GET /api/pleroma/admin/users" do
615 setup do
616 admin = insert(:user, is_admin: true)
617
618 conn =
619 build_conn()
620 |> assign(:user, admin)
621
622 {:ok, conn: conn, admin: admin}
623 end
624
625 test "renders users array for the first page", %{conn: conn, admin: admin} do
626 user = insert(:user, local: false, tags: ["foo", "bar"])
627 conn = get(conn, "/api/pleroma/admin/users?page=1")
628
629 users =
630 [
631 %{
632 "deactivated" => admin.deactivated,
633 "id" => admin.id,
634 "nickname" => admin.nickname,
635 "roles" => %{"admin" => true, "moderator" => false},
636 "local" => true,
637 "tags" => [],
638 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
639 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
640 "confirmation_pending" => false
641 },
642 %{
643 "deactivated" => user.deactivated,
644 "id" => user.id,
645 "nickname" => user.nickname,
646 "roles" => %{"admin" => false, "moderator" => false},
647 "local" => false,
648 "tags" => ["foo", "bar"],
649 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
650 "display_name" => HTML.strip_tags(user.name || user.nickname),
651 "confirmation_pending" => false
652 }
653 ]
654 |> Enum.sort_by(& &1["nickname"])
655
656 assert json_response(conn, 200) == %{
657 "count" => 2,
658 "page_size" => 50,
659 "users" => users
660 }
661 end
662
663 test "renders empty array for the second page", %{conn: conn} do
664 insert(:user)
665
666 conn = get(conn, "/api/pleroma/admin/users?page=2")
667
668 assert json_response(conn, 200) == %{
669 "count" => 2,
670 "page_size" => 50,
671 "users" => []
672 }
673 end
674
675 test "regular search", %{conn: conn} do
676 user = insert(:user, nickname: "bob")
677
678 conn = get(conn, "/api/pleroma/admin/users?query=bo")
679
680 assert json_response(conn, 200) == %{
681 "count" => 1,
682 "page_size" => 50,
683 "users" => [
684 %{
685 "deactivated" => user.deactivated,
686 "id" => user.id,
687 "nickname" => user.nickname,
688 "roles" => %{"admin" => false, "moderator" => false},
689 "local" => true,
690 "tags" => [],
691 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
692 "display_name" => HTML.strip_tags(user.name || user.nickname),
693 "confirmation_pending" => false
694 }
695 ]
696 }
697 end
698
699 test "search by domain", %{conn: conn} do
700 user = insert(:user, nickname: "nickname@domain.com")
701 insert(:user)
702
703 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
704
705 assert json_response(conn, 200) == %{
706 "count" => 1,
707 "page_size" => 50,
708 "users" => [
709 %{
710 "deactivated" => user.deactivated,
711 "id" => user.id,
712 "nickname" => user.nickname,
713 "roles" => %{"admin" => false, "moderator" => false},
714 "local" => true,
715 "tags" => [],
716 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
717 "display_name" => HTML.strip_tags(user.name || user.nickname),
718 "confirmation_pending" => false
719 }
720 ]
721 }
722 end
723
724 test "search by full nickname", %{conn: conn} do
725 user = insert(:user, nickname: "nickname@domain.com")
726 insert(:user)
727
728 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
729
730 assert json_response(conn, 200) == %{
731 "count" => 1,
732 "page_size" => 50,
733 "users" => [
734 %{
735 "deactivated" => user.deactivated,
736 "id" => user.id,
737 "nickname" => user.nickname,
738 "roles" => %{"admin" => false, "moderator" => false},
739 "local" => true,
740 "tags" => [],
741 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
742 "display_name" => HTML.strip_tags(user.name || user.nickname),
743 "confirmation_pending" => false
744 }
745 ]
746 }
747 end
748
749 test "search by display name", %{conn: conn} do
750 user = insert(:user, name: "Display name")
751 insert(:user)
752
753 conn = get(conn, "/api/pleroma/admin/users?name=display")
754
755 assert json_response(conn, 200) == %{
756 "count" => 1,
757 "page_size" => 50,
758 "users" => [
759 %{
760 "deactivated" => user.deactivated,
761 "id" => user.id,
762 "nickname" => user.nickname,
763 "roles" => %{"admin" => false, "moderator" => false},
764 "local" => true,
765 "tags" => [],
766 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
767 "display_name" => HTML.strip_tags(user.name || user.nickname),
768 "confirmation_pending" => false
769 }
770 ]
771 }
772 end
773
774 test "search by email", %{conn: conn} do
775 user = insert(:user, email: "email@example.com")
776 insert(:user)
777
778 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
779
780 assert json_response(conn, 200) == %{
781 "count" => 1,
782 "page_size" => 50,
783 "users" => [
784 %{
785 "deactivated" => user.deactivated,
786 "id" => user.id,
787 "nickname" => user.nickname,
788 "roles" => %{"admin" => false, "moderator" => false},
789 "local" => true,
790 "tags" => [],
791 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
792 "display_name" => HTML.strip_tags(user.name || user.nickname),
793 "confirmation_pending" => false
794 }
795 ]
796 }
797 end
798
799 test "regular search with page size", %{conn: conn} do
800 user = insert(:user, nickname: "aalice")
801 user2 = insert(:user, nickname: "alice")
802
803 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
804
805 assert json_response(conn1, 200) == %{
806 "count" => 2,
807 "page_size" => 1,
808 "users" => [
809 %{
810 "deactivated" => user.deactivated,
811 "id" => user.id,
812 "nickname" => user.nickname,
813 "roles" => %{"admin" => false, "moderator" => false},
814 "local" => true,
815 "tags" => [],
816 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
817 "display_name" => HTML.strip_tags(user.name || user.nickname),
818 "confirmation_pending" => false
819 }
820 ]
821 }
822
823 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
824
825 assert json_response(conn2, 200) == %{
826 "count" => 2,
827 "page_size" => 1,
828 "users" => [
829 %{
830 "deactivated" => user2.deactivated,
831 "id" => user2.id,
832 "nickname" => user2.nickname,
833 "roles" => %{"admin" => false, "moderator" => false},
834 "local" => true,
835 "tags" => [],
836 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
837 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
838 "confirmation_pending" => false
839 }
840 ]
841 }
842 end
843
844 test "only local users" do
845 admin = insert(:user, is_admin: true, nickname: "john")
846 user = insert(:user, nickname: "bob")
847
848 insert(:user, nickname: "bobb", local: false)
849
850 conn =
851 build_conn()
852 |> assign(:user, admin)
853 |> get("/api/pleroma/admin/users?query=bo&filters=local")
854
855 assert json_response(conn, 200) == %{
856 "count" => 1,
857 "page_size" => 50,
858 "users" => [
859 %{
860 "deactivated" => user.deactivated,
861 "id" => user.id,
862 "nickname" => user.nickname,
863 "roles" => %{"admin" => false, "moderator" => false},
864 "local" => true,
865 "tags" => [],
866 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
867 "display_name" => HTML.strip_tags(user.name || user.nickname),
868 "confirmation_pending" => false
869 }
870 ]
871 }
872 end
873
874 test "only local users with no query", %{admin: old_admin} do
875 admin = insert(:user, is_admin: true, nickname: "john")
876 user = insert(:user, nickname: "bob")
877
878 insert(:user, nickname: "bobb", local: false)
879
880 conn =
881 build_conn()
882 |> assign(:user, admin)
883 |> get("/api/pleroma/admin/users?filters=local")
884
885 users =
886 [
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 "deactivated" => admin.deactivated,
900 "id" => admin.id,
901 "nickname" => admin.nickname,
902 "roles" => %{"admin" => true, "moderator" => false},
903 "local" => true,
904 "tags" => [],
905 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
906 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
907 "confirmation_pending" => false
908 },
909 %{
910 "deactivated" => false,
911 "id" => old_admin.id,
912 "local" => true,
913 "nickname" => old_admin.nickname,
914 "roles" => %{"admin" => true, "moderator" => false},
915 "tags" => [],
916 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
917 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
918 "confirmation_pending" => false
919 }
920 ]
921 |> Enum.sort_by(& &1["nickname"])
922
923 assert json_response(conn, 200) == %{
924 "count" => 3,
925 "page_size" => 50,
926 "users" => users
927 }
928 end
929
930 test "load only admins", %{conn: conn, admin: admin} do
931 second_admin = insert(:user, is_admin: true)
932 insert(:user)
933 insert(:user)
934
935 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
936
937 users =
938 [
939 %{
940 "deactivated" => false,
941 "id" => admin.id,
942 "nickname" => admin.nickname,
943 "roles" => %{"admin" => true, "moderator" => false},
944 "local" => admin.local,
945 "tags" => [],
946 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
947 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
948 "confirmation_pending" => false
949 },
950 %{
951 "deactivated" => false,
952 "id" => second_admin.id,
953 "nickname" => second_admin.nickname,
954 "roles" => %{"admin" => true, "moderator" => false},
955 "local" => second_admin.local,
956 "tags" => [],
957 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
958 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
959 "confirmation_pending" => false
960 }
961 ]
962 |> Enum.sort_by(& &1["nickname"])
963
964 assert json_response(conn, 200) == %{
965 "count" => 2,
966 "page_size" => 50,
967 "users" => users
968 }
969 end
970
971 test "load only moderators", %{conn: conn} do
972 moderator = insert(:user, is_moderator: true)
973 insert(:user)
974 insert(:user)
975
976 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
977
978 assert json_response(conn, 200) == %{
979 "count" => 1,
980 "page_size" => 50,
981 "users" => [
982 %{
983 "deactivated" => false,
984 "id" => moderator.id,
985 "nickname" => moderator.nickname,
986 "roles" => %{"admin" => false, "moderator" => true},
987 "local" => moderator.local,
988 "tags" => [],
989 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
990 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
991 "confirmation_pending" => false
992 }
993 ]
994 }
995 end
996
997 test "load users with tags list", %{conn: conn} do
998 user1 = insert(:user, tags: ["first"])
999 user2 = insert(:user, tags: ["second"])
1000 insert(:user)
1001 insert(:user)
1002
1003 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1004
1005 users =
1006 [
1007 %{
1008 "deactivated" => false,
1009 "id" => user1.id,
1010 "nickname" => user1.nickname,
1011 "roles" => %{"admin" => false, "moderator" => false},
1012 "local" => user1.local,
1013 "tags" => ["first"],
1014 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1015 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1016 "confirmation_pending" => false
1017 },
1018 %{
1019 "deactivated" => false,
1020 "id" => user2.id,
1021 "nickname" => user2.nickname,
1022 "roles" => %{"admin" => false, "moderator" => false},
1023 "local" => user2.local,
1024 "tags" => ["second"],
1025 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1026 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1027 "confirmation_pending" => false
1028 }
1029 ]
1030 |> Enum.sort_by(& &1["nickname"])
1031
1032 assert json_response(conn, 200) == %{
1033 "count" => 2,
1034 "page_size" => 50,
1035 "users" => users
1036 }
1037 end
1038
1039 test "it works with multiple filters" do
1040 admin = insert(:user, nickname: "john", is_admin: true)
1041 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1042
1043 insert(:user, nickname: "ken", local: true, deactivated: true)
1044 insert(:user, nickname: "bobb", local: false, deactivated: false)
1045
1046 conn =
1047 build_conn()
1048 |> assign(:user, admin)
1049 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1050
1051 assert json_response(conn, 200) == %{
1052 "count" => 1,
1053 "page_size" => 50,
1054 "users" => [
1055 %{
1056 "deactivated" => user.deactivated,
1057 "id" => user.id,
1058 "nickname" => user.nickname,
1059 "roles" => %{"admin" => false, "moderator" => false},
1060 "local" => user.local,
1061 "tags" => [],
1062 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1063 "display_name" => HTML.strip_tags(user.name || user.nickname),
1064 "confirmation_pending" => false
1065 }
1066 ]
1067 }
1068 end
1069
1070 test "it omits relay user", %{admin: admin} do
1071 assert %User{} = Relay.get_actor()
1072
1073 conn =
1074 build_conn()
1075 |> assign(:user, admin)
1076 |> get("/api/pleroma/admin/users")
1077
1078 assert json_response(conn, 200) == %{
1079 "count" => 1,
1080 "page_size" => 50,
1081 "users" => [
1082 %{
1083 "deactivated" => admin.deactivated,
1084 "id" => admin.id,
1085 "nickname" => admin.nickname,
1086 "roles" => %{"admin" => true, "moderator" => false},
1087 "local" => true,
1088 "tags" => [],
1089 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1090 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1091 "confirmation_pending" => false
1092 }
1093 ]
1094 }
1095 end
1096 end
1097
1098 test "PATCH /api/pleroma/admin/users/activate" do
1099 admin = insert(:user, is_admin: true)
1100 user_one = insert(:user, deactivated: true)
1101 user_two = insert(:user, deactivated: true)
1102
1103 conn =
1104 build_conn()
1105 |> assign(:user, admin)
1106 |> patch(
1107 "/api/pleroma/admin/users/activate",
1108 %{nicknames: [user_one.nickname, user_two.nickname]}
1109 )
1110
1111 response = json_response(conn, 200)
1112 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1113
1114 log_entry = Repo.one(ModerationLog)
1115
1116 assert ModerationLog.get_log_entry_message(log_entry) ==
1117 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1118 end
1119
1120 test "PATCH /api/pleroma/admin/users/deactivate" do
1121 admin = insert(:user, is_admin: true)
1122 user_one = insert(:user, deactivated: false)
1123 user_two = insert(:user, deactivated: false)
1124
1125 conn =
1126 build_conn()
1127 |> assign(:user, admin)
1128 |> patch(
1129 "/api/pleroma/admin/users/deactivate",
1130 %{nicknames: [user_one.nickname, user_two.nickname]}
1131 )
1132
1133 response = json_response(conn, 200)
1134 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1135
1136 log_entry = Repo.one(ModerationLog)
1137
1138 assert ModerationLog.get_log_entry_message(log_entry) ==
1139 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1140 end
1141
1142 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation" do
1143 admin = insert(:user, is_admin: true)
1144 user = insert(:user)
1145
1146 conn =
1147 build_conn()
1148 |> assign(:user, admin)
1149 |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1150
1151 assert json_response(conn, 200) ==
1152 %{
1153 "deactivated" => !user.deactivated,
1154 "id" => user.id,
1155 "nickname" => user.nickname,
1156 "roles" => %{"admin" => false, "moderator" => false},
1157 "local" => true,
1158 "tags" => [],
1159 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1160 "display_name" => HTML.strip_tags(user.name || user.nickname),
1161 "confirmation_pending" => false
1162 }
1163
1164 log_entry = Repo.one(ModerationLog)
1165
1166 assert ModerationLog.get_log_entry_message(log_entry) ==
1167 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1168 end
1169
1170 describe "POST /api/pleroma/admin/users/invite_token" do
1171 setup do
1172 admin = insert(:user, is_admin: true)
1173
1174 conn =
1175 build_conn()
1176 |> assign(:user, admin)
1177
1178 {:ok, conn: conn}
1179 end
1180
1181 test "without options", %{conn: conn} do
1182 conn = post(conn, "/api/pleroma/admin/users/invite_token")
1183
1184 invite_json = json_response(conn, 200)
1185 invite = UserInviteToken.find_by_token!(invite_json["token"])
1186 refute invite.used
1187 refute invite.expires_at
1188 refute invite.max_use
1189 assert invite.invite_type == "one_time"
1190 end
1191
1192 test "with expires_at", %{conn: conn} do
1193 conn =
1194 post(conn, "/api/pleroma/admin/users/invite_token", %{
1195 "expires_at" => Date.to_string(Date.utc_today())
1196 })
1197
1198 invite_json = json_response(conn, 200)
1199 invite = UserInviteToken.find_by_token!(invite_json["token"])
1200
1201 refute invite.used
1202 assert invite.expires_at == Date.utc_today()
1203 refute invite.max_use
1204 assert invite.invite_type == "date_limited"
1205 end
1206
1207 test "with max_use", %{conn: conn} do
1208 conn = post(conn, "/api/pleroma/admin/users/invite_token", %{"max_use" => 150})
1209
1210 invite_json = json_response(conn, 200)
1211 invite = UserInviteToken.find_by_token!(invite_json["token"])
1212 refute invite.used
1213 refute invite.expires_at
1214 assert invite.max_use == 150
1215 assert invite.invite_type == "reusable"
1216 end
1217
1218 test "with max use and expires_at", %{conn: conn} do
1219 conn =
1220 post(conn, "/api/pleroma/admin/users/invite_token", %{
1221 "max_use" => 150,
1222 "expires_at" => Date.to_string(Date.utc_today())
1223 })
1224
1225 invite_json = json_response(conn, 200)
1226 invite = UserInviteToken.find_by_token!(invite_json["token"])
1227 refute invite.used
1228 assert invite.expires_at == Date.utc_today()
1229 assert invite.max_use == 150
1230 assert invite.invite_type == "reusable_date_limited"
1231 end
1232 end
1233
1234 describe "GET /api/pleroma/admin/users/invites" do
1235 setup do
1236 admin = insert(:user, is_admin: true)
1237
1238 conn =
1239 build_conn()
1240 |> assign(:user, admin)
1241
1242 {:ok, conn: conn}
1243 end
1244
1245 test "no invites", %{conn: conn} do
1246 conn = get(conn, "/api/pleroma/admin/users/invites")
1247
1248 assert json_response(conn, 200) == %{"invites" => []}
1249 end
1250
1251 test "with invite", %{conn: conn} do
1252 {:ok, invite} = UserInviteToken.create_invite()
1253
1254 conn = get(conn, "/api/pleroma/admin/users/invites")
1255
1256 assert json_response(conn, 200) == %{
1257 "invites" => [
1258 %{
1259 "expires_at" => nil,
1260 "id" => invite.id,
1261 "invite_type" => "one_time",
1262 "max_use" => nil,
1263 "token" => invite.token,
1264 "used" => false,
1265 "uses" => 0
1266 }
1267 ]
1268 }
1269 end
1270 end
1271
1272 describe "POST /api/pleroma/admin/users/revoke_invite" do
1273 test "with token" do
1274 admin = insert(:user, is_admin: true)
1275 {:ok, invite} = UserInviteToken.create_invite()
1276
1277 conn =
1278 build_conn()
1279 |> assign(:user, admin)
1280 |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => invite.token})
1281
1282 assert json_response(conn, 200) == %{
1283 "expires_at" => nil,
1284 "id" => invite.id,
1285 "invite_type" => "one_time",
1286 "max_use" => nil,
1287 "token" => invite.token,
1288 "used" => true,
1289 "uses" => 0
1290 }
1291 end
1292
1293 test "with invalid token" do
1294 admin = insert(:user, is_admin: true)
1295
1296 conn =
1297 build_conn()
1298 |> assign(:user, admin)
1299 |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"})
1300
1301 assert json_response(conn, :not_found) == "Not found"
1302 end
1303 end
1304
1305 describe "GET /api/pleroma/admin/reports/:id" do
1306 setup %{conn: conn} do
1307 admin = insert(:user, is_admin: true)
1308
1309 %{conn: assign(conn, :user, admin)}
1310 end
1311
1312 test "returns report by its id", %{conn: conn} do
1313 [reporter, target_user] = insert_pair(:user)
1314 activity = insert(:note_activity, user: target_user)
1315
1316 {:ok, %{id: report_id}} =
1317 CommonAPI.report(reporter, %{
1318 "account_id" => target_user.id,
1319 "comment" => "I feel offended",
1320 "status_ids" => [activity.id]
1321 })
1322
1323 response =
1324 conn
1325 |> get("/api/pleroma/admin/reports/#{report_id}")
1326 |> json_response(:ok)
1327
1328 assert response["id"] == report_id
1329 end
1330
1331 test "returns 404 when report id is invalid", %{conn: conn} do
1332 conn = get(conn, "/api/pleroma/admin/reports/test")
1333
1334 assert json_response(conn, :not_found) == "Not found"
1335 end
1336 end
1337
1338 describe "PATCH /api/pleroma/admin/reports" do
1339 setup %{conn: conn} do
1340 admin = insert(:user, is_admin: true)
1341 [reporter, target_user] = insert_pair(:user)
1342 activity = insert(:note_activity, user: target_user)
1343
1344 {:ok, %{id: report_id}} =
1345 CommonAPI.report(reporter, %{
1346 "account_id" => target_user.id,
1347 "comment" => "I feel offended",
1348 "status_ids" => [activity.id]
1349 })
1350
1351 {:ok, %{id: second_report_id}} =
1352 CommonAPI.report(reporter, %{
1353 "account_id" => target_user.id,
1354 "comment" => "I feel very offended",
1355 "status_ids" => [activity.id]
1356 })
1357
1358 %{
1359 conn: assign(conn, :user, admin),
1360 id: report_id,
1361 admin: admin,
1362 second_report_id: second_report_id
1363 }
1364 end
1365
1366 test "mark report as resolved", %{conn: conn, id: id, admin: admin} do
1367 conn
1368 |> patch("/api/pleroma/admin/reports", %{
1369 "reports" => [
1370 %{"state" => "resolved", "id" => id}
1371 ]
1372 })
1373 |> json_response(:no_content)
1374
1375 activity = Activity.get_by_id(id)
1376 assert activity.data["state"] == "resolved"
1377
1378 log_entry = Repo.one(ModerationLog)
1379
1380 assert ModerationLog.get_log_entry_message(log_entry) ==
1381 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1382 end
1383
1384 test "closes report", %{conn: conn, id: id, admin: admin} do
1385 conn
1386 |> patch("/api/pleroma/admin/reports", %{
1387 "reports" => [
1388 %{"state" => "closed", "id" => id}
1389 ]
1390 })
1391 |> json_response(:no_content)
1392
1393 activity = Activity.get_by_id(id)
1394 assert activity.data["state"] == "closed"
1395
1396 log_entry = Repo.one(ModerationLog)
1397
1398 assert ModerationLog.get_log_entry_message(log_entry) ==
1399 "@#{admin.nickname} updated report ##{id} with 'closed' state"
1400 end
1401
1402 test "returns 400 when state is unknown", %{conn: conn, id: id} do
1403 conn =
1404 conn
1405 |> patch("/api/pleroma/admin/reports", %{
1406 "reports" => [
1407 %{"state" => "test", "id" => id}
1408 ]
1409 })
1410
1411 assert hd(json_response(conn, :bad_request))["error"] == "Unsupported state"
1412 end
1413
1414 test "returns 404 when report is not exist", %{conn: conn} do
1415 conn =
1416 conn
1417 |> patch("/api/pleroma/admin/reports", %{
1418 "reports" => [
1419 %{"state" => "closed", "id" => "test"}
1420 ]
1421 })
1422
1423 assert hd(json_response(conn, :bad_request))["error"] == "not_found"
1424 end
1425
1426 test "updates state of multiple reports", %{
1427 conn: conn,
1428 id: id,
1429 admin: admin,
1430 second_report_id: second_report_id
1431 } do
1432 conn
1433 |> patch("/api/pleroma/admin/reports", %{
1434 "reports" => [
1435 %{"state" => "resolved", "id" => id},
1436 %{"state" => "closed", "id" => second_report_id}
1437 ]
1438 })
1439 |> json_response(:no_content)
1440
1441 activity = Activity.get_by_id(id)
1442 second_activity = Activity.get_by_id(second_report_id)
1443 assert activity.data["state"] == "resolved"
1444 assert second_activity.data["state"] == "closed"
1445
1446 [first_log_entry, second_log_entry] = Repo.all(ModerationLog)
1447
1448 assert ModerationLog.get_log_entry_message(first_log_entry) ==
1449 "@#{admin.nickname} updated report ##{id} with 'resolved' state"
1450
1451 assert ModerationLog.get_log_entry_message(second_log_entry) ==
1452 "@#{admin.nickname} updated report ##{second_report_id} with 'closed' state"
1453 end
1454 end
1455
1456 describe "GET /api/pleroma/admin/reports" do
1457 setup %{conn: conn} do
1458 admin = insert(:user, is_admin: true)
1459
1460 %{conn: assign(conn, :user, admin)}
1461 end
1462
1463 test "returns empty response when no reports created", %{conn: conn} do
1464 response =
1465 conn
1466 |> get("/api/pleroma/admin/reports")
1467 |> json_response(:ok)
1468
1469 assert Enum.empty?(response["reports"])
1470 assert response["total"] == 0
1471 end
1472
1473 test "returns reports", %{conn: conn} do
1474 [reporter, target_user] = insert_pair(:user)
1475 activity = insert(:note_activity, user: target_user)
1476
1477 {:ok, %{id: report_id}} =
1478 CommonAPI.report(reporter, %{
1479 "account_id" => target_user.id,
1480 "comment" => "I feel offended",
1481 "status_ids" => [activity.id]
1482 })
1483
1484 response =
1485 conn
1486 |> get("/api/pleroma/admin/reports")
1487 |> json_response(:ok)
1488
1489 [report] = response["reports"]
1490
1491 assert length(response["reports"]) == 1
1492 assert report["id"] == report_id
1493
1494 assert response["total"] == 1
1495 end
1496
1497 test "returns reports with specified state", %{conn: conn} do
1498 [reporter, target_user] = insert_pair(:user)
1499 activity = insert(:note_activity, user: target_user)
1500
1501 {:ok, %{id: first_report_id}} =
1502 CommonAPI.report(reporter, %{
1503 "account_id" => target_user.id,
1504 "comment" => "I feel offended",
1505 "status_ids" => [activity.id]
1506 })
1507
1508 {:ok, %{id: second_report_id}} =
1509 CommonAPI.report(reporter, %{
1510 "account_id" => target_user.id,
1511 "comment" => "I don't like this user"
1512 })
1513
1514 CommonAPI.update_report_state(second_report_id, "closed")
1515
1516 response =
1517 conn
1518 |> get("/api/pleroma/admin/reports", %{
1519 "state" => "open"
1520 })
1521 |> json_response(:ok)
1522
1523 [open_report] = response["reports"]
1524
1525 assert length(response["reports"]) == 1
1526 assert open_report["id"] == first_report_id
1527
1528 assert response["total"] == 1
1529
1530 response =
1531 conn
1532 |> get("/api/pleroma/admin/reports", %{
1533 "state" => "closed"
1534 })
1535 |> json_response(:ok)
1536
1537 [closed_report] = response["reports"]
1538
1539 assert length(response["reports"]) == 1
1540 assert closed_report["id"] == second_report_id
1541
1542 assert response["total"] == 1
1543
1544 response =
1545 conn
1546 |> get("/api/pleroma/admin/reports", %{
1547 "state" => "resolved"
1548 })
1549 |> json_response(:ok)
1550
1551 assert Enum.empty?(response["reports"])
1552 assert response["total"] == 0
1553 end
1554
1555 test "returns 403 when requested by a non-admin" do
1556 user = insert(:user)
1557
1558 conn =
1559 build_conn()
1560 |> assign(:user, user)
1561 |> get("/api/pleroma/admin/reports")
1562
1563 assert json_response(conn, :forbidden) == %{"error" => "User is not admin."}
1564 end
1565
1566 test "returns 403 when requested by anonymous" do
1567 conn =
1568 build_conn()
1569 |> get("/api/pleroma/admin/reports")
1570
1571 assert json_response(conn, :forbidden) == %{"error" => "Invalid credentials."}
1572 end
1573 end
1574
1575 describe "GET /api/pleroma/admin/grouped_reports" do
1576 setup %{conn: conn} do
1577 admin = insert(:user, is_admin: true)
1578 [reporter, target_user] = insert_pair(:user)
1579
1580 date1 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1581 date2 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1582 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1583
1584 first_status =
1585 insert(:note_activity, user: target_user, data_attrs: %{"published" => date1})
1586
1587 second_status =
1588 insert(:note_activity, user: target_user, data_attrs: %{"published" => date2})
1589
1590 third_status =
1591 insert(:note_activity, user: target_user, data_attrs: %{"published" => date3})
1592
1593 {:ok, first_report} =
1594 CommonAPI.report(reporter, %{
1595 "account_id" => target_user.id,
1596 "status_ids" => [first_status.id, second_status.id, third_status.id]
1597 })
1598
1599 {:ok, second_report} =
1600 CommonAPI.report(reporter, %{
1601 "account_id" => target_user.id,
1602 "status_ids" => [first_status.id, second_status.id]
1603 })
1604
1605 {:ok, third_report} =
1606 CommonAPI.report(reporter, %{
1607 "account_id" => target_user.id,
1608 "status_ids" => [first_status.id]
1609 })
1610
1611 %{
1612 conn: assign(conn, :user, admin),
1613 first_status: Activity.get_by_ap_id_with_object(first_status.data["id"]),
1614 second_status: Activity.get_by_ap_id_with_object(second_status.data["id"]),
1615 third_status: Activity.get_by_ap_id_with_object(third_status.data["id"]),
1616 first_status_reports: [first_report, second_report, third_report],
1617 second_status_reports: [first_report, second_report],
1618 third_status_reports: [first_report],
1619 target_user: target_user,
1620 reporter: reporter
1621 }
1622 end
1623
1624 test "returns reports grouped by status", %{
1625 conn: conn,
1626 first_status: first_status,
1627 second_status: second_status,
1628 third_status: third_status,
1629 first_status_reports: first_status_reports,
1630 second_status_reports: second_status_reports,
1631 third_status_reports: third_status_reports,
1632 target_user: target_user,
1633 reporter: reporter
1634 } do
1635 response =
1636 conn
1637 |> get("/api/pleroma/admin/grouped_reports")
1638 |> json_response(:ok)
1639
1640 assert length(response["reports"]) == 3
1641
1642 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1643
1644 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1645
1646 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1647
1648 assert length(first_group["reports"]) == 3
1649 assert length(second_group["reports"]) == 2
1650 assert length(third_group["reports"]) == 1
1651
1652 assert first_group["date"] ==
1653 Enum.max_by(first_status_reports, fn act ->
1654 NaiveDateTime.from_iso8601!(act.data["published"])
1655 end).data["published"]
1656
1657 assert first_group["status"] == StatusView.render("show.json", %{activity: first_status})
1658
1659 assert first_group["account"]["id"] == target_user.id
1660
1661 assert length(first_group["actors"]) == 1
1662 assert hd(first_group["actors"])["id"] == reporter.id
1663
1664 assert Enum.map(first_group["reports"], & &1["id"]) --
1665 Enum.map(first_status_reports, & &1.id) == []
1666
1667 assert second_group["date"] ==
1668 Enum.max_by(second_status_reports, fn act ->
1669 NaiveDateTime.from_iso8601!(act.data["published"])
1670 end).data["published"]
1671
1672 assert second_group["status"] == %{
1673 "id" => second_status.data["id"],
1674 "content" => second_status.object.data["content"],
1675 "published" => second_status.object.data["published"]
1676 }
1677
1678 assert second_group["account"]["id"] == target_user.id
1679
1680 assert length(second_group["actors"]) == 1
1681 assert hd(second_group["actors"])["id"] == reporter.id
1682
1683 assert Enum.map(second_group["reports"], & &1["id"]) --
1684 Enum.map(second_status_reports, & &1.id) == []
1685
1686 assert third_group["date"] ==
1687 Enum.max_by(third_status_reports, fn act ->
1688 NaiveDateTime.from_iso8601!(act.data["published"])
1689 end).data["published"]
1690
1691 assert third_group["status"] == %{
1692 "id" => third_status.data["id"],
1693 "content" => third_status.object.data["content"],
1694 "published" => third_status.object.data["published"]
1695 }
1696
1697 assert third_group["account"]["id"] == target_user.id
1698
1699 assert length(third_group["actors"]) == 1
1700 assert hd(third_group["actors"])["id"] == reporter.id
1701
1702 assert Enum.map(third_group["reports"], & &1["id"]) --
1703 Enum.map(third_status_reports, & &1.id) == []
1704 end
1705 end
1706
1707 describe "POST /api/pleroma/admin/reports/:id/respond" do
1708 setup %{conn: conn} do
1709 admin = insert(:user, is_admin: true)
1710
1711 %{conn: assign(conn, :user, admin), admin: admin}
1712 end
1713
1714 test "returns created dm", %{conn: conn, admin: admin} do
1715 [reporter, target_user] = insert_pair(:user)
1716 activity = insert(:note_activity, user: target_user)
1717
1718 {:ok, %{id: report_id}} =
1719 CommonAPI.report(reporter, %{
1720 "account_id" => target_user.id,
1721 "comment" => "I feel offended",
1722 "status_ids" => [activity.id]
1723 })
1724
1725 response =
1726 conn
1727 |> post("/api/pleroma/admin/reports/#{report_id}/respond", %{
1728 "status" => "I will check it out"
1729 })
1730 |> json_response(:ok)
1731
1732 recipients = Enum.map(response["mentions"], & &1["username"])
1733
1734 assert reporter.nickname in recipients
1735 assert response["content"] == "I will check it out"
1736 assert response["visibility"] == "direct"
1737
1738 log_entry = Repo.one(ModerationLog)
1739
1740 assert ModerationLog.get_log_entry_message(log_entry) ==
1741 "@#{admin.nickname} responded with 'I will check it out' to report ##{
1742 response["id"]
1743 }"
1744 end
1745
1746 test "returns 400 when status is missing", %{conn: conn} do
1747 conn = post(conn, "/api/pleroma/admin/reports/test/respond")
1748
1749 assert json_response(conn, :bad_request) == "Invalid parameters"
1750 end
1751
1752 test "returns 404 when report id is invalid", %{conn: conn} do
1753 conn =
1754 post(conn, "/api/pleroma/admin/reports/test/respond", %{
1755 "status" => "foo"
1756 })
1757
1758 assert json_response(conn, :not_found) == "Not found"
1759 end
1760 end
1761
1762 describe "PUT /api/pleroma/admin/statuses/:id" do
1763 setup %{conn: conn} do
1764 admin = insert(:user, is_admin: true)
1765 activity = insert(:note_activity)
1766
1767 %{conn: assign(conn, :user, admin), id: activity.id, admin: admin}
1768 end
1769
1770 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1771 response =
1772 conn
1773 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1774 |> json_response(:ok)
1775
1776 assert response["sensitive"]
1777
1778 log_entry = Repo.one(ModerationLog)
1779
1780 assert ModerationLog.get_log_entry_message(log_entry) ==
1781 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1782
1783 response =
1784 conn
1785 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1786 |> json_response(:ok)
1787
1788 refute response["sensitive"]
1789 end
1790
1791 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1792 response =
1793 conn
1794 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1795 |> json_response(:ok)
1796
1797 assert response["visibility"] == "public"
1798
1799 log_entry = Repo.one(ModerationLog)
1800
1801 assert ModerationLog.get_log_entry_message(log_entry) ==
1802 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1803
1804 response =
1805 conn
1806 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1807 |> json_response(:ok)
1808
1809 assert response["visibility"] == "private"
1810
1811 response =
1812 conn
1813 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1814 |> json_response(:ok)
1815
1816 assert response["visibility"] == "unlisted"
1817 end
1818
1819 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1820 conn =
1821 conn
1822 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1823
1824 assert json_response(conn, :bad_request) == "Unsupported visibility"
1825 end
1826 end
1827
1828 describe "DELETE /api/pleroma/admin/statuses/:id" do
1829 setup %{conn: conn} do
1830 admin = insert(:user, is_admin: true)
1831 activity = insert(:note_activity)
1832
1833 %{conn: assign(conn, :user, admin), id: activity.id, admin: admin}
1834 end
1835
1836 test "deletes status", %{conn: conn, id: id, admin: admin} do
1837 conn
1838 |> delete("/api/pleroma/admin/statuses/#{id}")
1839 |> json_response(:ok)
1840
1841 refute Activity.get_by_id(id)
1842
1843 log_entry = Repo.one(ModerationLog)
1844
1845 assert ModerationLog.get_log_entry_message(log_entry) ==
1846 "@#{admin.nickname} deleted status ##{id}"
1847 end
1848
1849 test "returns error when status is not exist", %{conn: conn} do
1850 conn =
1851 conn
1852 |> delete("/api/pleroma/admin/statuses/test")
1853
1854 assert json_response(conn, :bad_request) == "Could not delete"
1855 end
1856 end
1857
1858 describe "GET /api/pleroma/admin/config" do
1859 setup %{conn: conn} do
1860 admin = insert(:user, is_admin: true)
1861
1862 %{conn: assign(conn, :user, admin)}
1863 end
1864
1865 test "without any settings in db", %{conn: conn} do
1866 conn = get(conn, "/api/pleroma/admin/config")
1867
1868 assert json_response(conn, 200) == %{"configs" => []}
1869 end
1870
1871 test "with settings in db", %{conn: conn} do
1872 config1 = insert(:config)
1873 config2 = insert(:config)
1874
1875 conn = get(conn, "/api/pleroma/admin/config")
1876
1877 %{
1878 "configs" => [
1879 %{
1880 "key" => key1,
1881 "value" => _
1882 },
1883 %{
1884 "key" => key2,
1885 "value" => _
1886 }
1887 ]
1888 } = json_response(conn, 200)
1889
1890 assert key1 == config1.key
1891 assert key2 == config2.key
1892 end
1893 end
1894
1895 describe "POST /api/pleroma/admin/config" do
1896 setup %{conn: conn} do
1897 admin = insert(:user, is_admin: true)
1898
1899 temp_file = "config/test.exported_from_db.secret.exs"
1900
1901 on_exit(fn ->
1902 Application.delete_env(:pleroma, :key1)
1903 Application.delete_env(:pleroma, :key2)
1904 Application.delete_env(:pleroma, :key3)
1905 Application.delete_env(:pleroma, :key4)
1906 Application.delete_env(:pleroma, :keyaa1)
1907 Application.delete_env(:pleroma, :keyaa2)
1908 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1909 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1910 :ok = File.rm(temp_file)
1911 end)
1912
1913 %{conn: assign(conn, :user, admin)}
1914 end
1915
1916 clear_config([:instance, :dynamic_configuration]) do
1917 Pleroma.Config.put([:instance, :dynamic_configuration], true)
1918 end
1919
1920 test "create new config setting in db", %{conn: conn} do
1921 conn =
1922 post(conn, "/api/pleroma/admin/config", %{
1923 configs: [
1924 %{group: "pleroma", key: "key1", value: "value1"},
1925 %{
1926 group: "ueberauth",
1927 key: "Ueberauth.Strategy.Twitter.OAuth",
1928 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1929 },
1930 %{
1931 group: "pleroma",
1932 key: "key2",
1933 value: %{
1934 ":nested_1" => "nested_value1",
1935 ":nested_2" => [
1936 %{":nested_22" => "nested_value222"},
1937 %{":nested_33" => %{":nested_44" => "nested_444"}}
1938 ]
1939 }
1940 },
1941 %{
1942 group: "pleroma",
1943 key: "key3",
1944 value: [
1945 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1946 %{"nested_4" => true}
1947 ]
1948 },
1949 %{
1950 group: "pleroma",
1951 key: "key4",
1952 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1953 },
1954 %{
1955 group: "idna",
1956 key: "key5",
1957 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1958 }
1959 ]
1960 })
1961
1962 assert json_response(conn, 200) == %{
1963 "configs" => [
1964 %{
1965 "group" => "pleroma",
1966 "key" => "key1",
1967 "value" => "value1"
1968 },
1969 %{
1970 "group" => "ueberauth",
1971 "key" => "Ueberauth.Strategy.Twitter.OAuth",
1972 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}]
1973 },
1974 %{
1975 "group" => "pleroma",
1976 "key" => "key2",
1977 "value" => %{
1978 ":nested_1" => "nested_value1",
1979 ":nested_2" => [
1980 %{":nested_22" => "nested_value222"},
1981 %{":nested_33" => %{":nested_44" => "nested_444"}}
1982 ]
1983 }
1984 },
1985 %{
1986 "group" => "pleroma",
1987 "key" => "key3",
1988 "value" => [
1989 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1990 %{"nested_4" => true}
1991 ]
1992 },
1993 %{
1994 "group" => "pleroma",
1995 "key" => "key4",
1996 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
1997 },
1998 %{
1999 "group" => "idna",
2000 "key" => "key5",
2001 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2002 }
2003 ]
2004 }
2005
2006 assert Application.get_env(:pleroma, :key1) == "value1"
2007
2008 assert Application.get_env(:pleroma, :key2) == %{
2009 nested_1: "nested_value1",
2010 nested_2: [
2011 %{nested_22: "nested_value222"},
2012 %{nested_33: %{nested_44: "nested_444"}}
2013 ]
2014 }
2015
2016 assert Application.get_env(:pleroma, :key3) == [
2017 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2018 %{"nested_4" => true}
2019 ]
2020
2021 assert Application.get_env(:pleroma, :key4) == %{
2022 "endpoint" => "https://example.com",
2023 nested_5: :upload
2024 }
2025
2026 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2027 end
2028
2029 test "update config setting & delete", %{conn: conn} do
2030 config1 = insert(:config, key: "keyaa1")
2031 config2 = insert(:config, key: "keyaa2")
2032
2033 insert(:config,
2034 group: "ueberauth",
2035 key: "Ueberauth.Strategy.Microsoft.OAuth",
2036 value: :erlang.term_to_binary([])
2037 )
2038
2039 conn =
2040 post(conn, "/api/pleroma/admin/config", %{
2041 configs: [
2042 %{group: config1.group, key: config1.key, value: "another_value"},
2043 %{group: config2.group, key: config2.key, delete: "true"},
2044 %{
2045 group: "ueberauth",
2046 key: "Ueberauth.Strategy.Microsoft.OAuth",
2047 delete: "true"
2048 }
2049 ]
2050 })
2051
2052 assert json_response(conn, 200) == %{
2053 "configs" => [
2054 %{
2055 "group" => "pleroma",
2056 "key" => config1.key,
2057 "value" => "another_value"
2058 }
2059 ]
2060 }
2061
2062 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2063 refute Application.get_env(:pleroma, :keyaa2)
2064 end
2065
2066 test "common config example", %{conn: conn} do
2067 conn =
2068 post(conn, "/api/pleroma/admin/config", %{
2069 configs: [
2070 %{
2071 "group" => "pleroma",
2072 "key" => "Pleroma.Captcha.NotReal",
2073 "value" => [
2074 %{"tuple" => [":enabled", false]},
2075 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2076 %{"tuple" => [":seconds_valid", 60]},
2077 %{"tuple" => [":path", ""]},
2078 %{"tuple" => [":key1", nil]},
2079 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2080 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2081 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2082 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2083 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}
2084 ]
2085 }
2086 ]
2087 })
2088
2089 assert json_response(conn, 200) == %{
2090 "configs" => [
2091 %{
2092 "group" => "pleroma",
2093 "key" => "Pleroma.Captcha.NotReal",
2094 "value" => [
2095 %{"tuple" => [":enabled", false]},
2096 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2097 %{"tuple" => [":seconds_valid", 60]},
2098 %{"tuple" => [":path", ""]},
2099 %{"tuple" => [":key1", nil]},
2100 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2101 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2102 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2103 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2104 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}
2105 ]
2106 }
2107 ]
2108 }
2109 end
2110
2111 test "tuples with more than two values", %{conn: conn} do
2112 conn =
2113 post(conn, "/api/pleroma/admin/config", %{
2114 configs: [
2115 %{
2116 "group" => "pleroma",
2117 "key" => "Pleroma.Web.Endpoint.NotReal",
2118 "value" => [
2119 %{
2120 "tuple" => [
2121 ":http",
2122 [
2123 %{
2124 "tuple" => [
2125 ":key2",
2126 [
2127 %{
2128 "tuple" => [
2129 ":_",
2130 [
2131 %{
2132 "tuple" => [
2133 "/api/v1/streaming",
2134 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2135 []
2136 ]
2137 },
2138 %{
2139 "tuple" => [
2140 "/websocket",
2141 "Phoenix.Endpoint.CowboyWebSocket",
2142 %{
2143 "tuple" => [
2144 "Phoenix.Transports.WebSocket",
2145 %{
2146 "tuple" => [
2147 "Pleroma.Web.Endpoint",
2148 "Pleroma.Web.UserSocket",
2149 []
2150 ]
2151 }
2152 ]
2153 }
2154 ]
2155 },
2156 %{
2157 "tuple" => [
2158 ":_",
2159 "Phoenix.Endpoint.Cowboy2Handler",
2160 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2161 ]
2162 }
2163 ]
2164 ]
2165 }
2166 ]
2167 ]
2168 }
2169 ]
2170 ]
2171 }
2172 ]
2173 }
2174 ]
2175 })
2176
2177 assert json_response(conn, 200) == %{
2178 "configs" => [
2179 %{
2180 "group" => "pleroma",
2181 "key" => "Pleroma.Web.Endpoint.NotReal",
2182 "value" => [
2183 %{
2184 "tuple" => [
2185 ":http",
2186 [
2187 %{
2188 "tuple" => [
2189 ":key2",
2190 [
2191 %{
2192 "tuple" => [
2193 ":_",
2194 [
2195 %{
2196 "tuple" => [
2197 "/api/v1/streaming",
2198 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2199 []
2200 ]
2201 },
2202 %{
2203 "tuple" => [
2204 "/websocket",
2205 "Phoenix.Endpoint.CowboyWebSocket",
2206 %{
2207 "tuple" => [
2208 "Phoenix.Transports.WebSocket",
2209 %{
2210 "tuple" => [
2211 "Pleroma.Web.Endpoint",
2212 "Pleroma.Web.UserSocket",
2213 []
2214 ]
2215 }
2216 ]
2217 }
2218 ]
2219 },
2220 %{
2221 "tuple" => [
2222 ":_",
2223 "Phoenix.Endpoint.Cowboy2Handler",
2224 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2225 ]
2226 }
2227 ]
2228 ]
2229 }
2230 ]
2231 ]
2232 }
2233 ]
2234 ]
2235 }
2236 ]
2237 }
2238 ]
2239 }
2240 end
2241
2242 test "settings with nesting map", %{conn: conn} do
2243 conn =
2244 post(conn, "/api/pleroma/admin/config", %{
2245 configs: [
2246 %{
2247 "group" => "pleroma",
2248 "key" => ":key1",
2249 "value" => [
2250 %{"tuple" => [":key2", "some_val"]},
2251 %{
2252 "tuple" => [
2253 ":key3",
2254 %{
2255 ":max_options" => 20,
2256 ":max_option_chars" => 200,
2257 ":min_expiration" => 0,
2258 ":max_expiration" => 31_536_000,
2259 "nested" => %{
2260 ":max_options" => 20,
2261 ":max_option_chars" => 200,
2262 ":min_expiration" => 0,
2263 ":max_expiration" => 31_536_000
2264 }
2265 }
2266 ]
2267 }
2268 ]
2269 }
2270 ]
2271 })
2272
2273 assert json_response(conn, 200) ==
2274 %{
2275 "configs" => [
2276 %{
2277 "group" => "pleroma",
2278 "key" => ":key1",
2279 "value" => [
2280 %{"tuple" => [":key2", "some_val"]},
2281 %{
2282 "tuple" => [
2283 ":key3",
2284 %{
2285 ":max_expiration" => 31_536_000,
2286 ":max_option_chars" => 200,
2287 ":max_options" => 20,
2288 ":min_expiration" => 0,
2289 "nested" => %{
2290 ":max_expiration" => 31_536_000,
2291 ":max_option_chars" => 200,
2292 ":max_options" => 20,
2293 ":min_expiration" => 0
2294 }
2295 }
2296 ]
2297 }
2298 ]
2299 }
2300 ]
2301 }
2302 end
2303
2304 test "value as map", %{conn: conn} do
2305 conn =
2306 post(conn, "/api/pleroma/admin/config", %{
2307 configs: [
2308 %{
2309 "group" => "pleroma",
2310 "key" => ":key1",
2311 "value" => %{"key" => "some_val"}
2312 }
2313 ]
2314 })
2315
2316 assert json_response(conn, 200) ==
2317 %{
2318 "configs" => [
2319 %{
2320 "group" => "pleroma",
2321 "key" => ":key1",
2322 "value" => %{"key" => "some_val"}
2323 }
2324 ]
2325 }
2326 end
2327
2328 test "dispatch setting", %{conn: conn} do
2329 conn =
2330 post(conn, "/api/pleroma/admin/config", %{
2331 configs: [
2332 %{
2333 "group" => "pleroma",
2334 "key" => "Pleroma.Web.Endpoint.NotReal",
2335 "value" => [
2336 %{
2337 "tuple" => [
2338 ":http",
2339 [
2340 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2341 %{"tuple" => [":dispatch", ["{:_,
2342 [
2343 {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
2344 {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
2345 {Phoenix.Transports.WebSocket,
2346 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
2347 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
2348 ]}"]]}
2349 ]
2350 ]
2351 }
2352 ]
2353 }
2354 ]
2355 })
2356
2357 dispatch_string =
2358 "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
2359 "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
2360 "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
2361 "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
2362
2363 assert json_response(conn, 200) == %{
2364 "configs" => [
2365 %{
2366 "group" => "pleroma",
2367 "key" => "Pleroma.Web.Endpoint.NotReal",
2368 "value" => [
2369 %{
2370 "tuple" => [
2371 ":http",
2372 [
2373 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2374 %{
2375 "tuple" => [
2376 ":dispatch",
2377 [
2378 dispatch_string
2379 ]
2380 ]
2381 }
2382 ]
2383 ]
2384 }
2385 ]
2386 }
2387 ]
2388 }
2389 end
2390
2391 test "queues key as atom", %{conn: conn} do
2392 conn =
2393 post(conn, "/api/pleroma/admin/config", %{
2394 configs: [
2395 %{
2396 "group" => "oban",
2397 "key" => ":queues",
2398 "value" => [
2399 %{"tuple" => [":federator_incoming", 50]},
2400 %{"tuple" => [":federator_outgoing", 50]},
2401 %{"tuple" => [":web_push", 50]},
2402 %{"tuple" => [":mailer", 10]},
2403 %{"tuple" => [":transmogrifier", 20]},
2404 %{"tuple" => [":scheduled_activities", 10]},
2405 %{"tuple" => [":background", 5]}
2406 ]
2407 }
2408 ]
2409 })
2410
2411 assert json_response(conn, 200) == %{
2412 "configs" => [
2413 %{
2414 "group" => "oban",
2415 "key" => ":queues",
2416 "value" => [
2417 %{"tuple" => [":federator_incoming", 50]},
2418 %{"tuple" => [":federator_outgoing", 50]},
2419 %{"tuple" => [":web_push", 50]},
2420 %{"tuple" => [":mailer", 10]},
2421 %{"tuple" => [":transmogrifier", 20]},
2422 %{"tuple" => [":scheduled_activities", 10]},
2423 %{"tuple" => [":background", 5]}
2424 ]
2425 }
2426 ]
2427 }
2428 end
2429
2430 test "delete part of settings by atom subkeys", %{conn: conn} do
2431 config =
2432 insert(:config,
2433 key: "keyaa1",
2434 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2435 )
2436
2437 conn =
2438 post(conn, "/api/pleroma/admin/config", %{
2439 configs: [
2440 %{
2441 group: config.group,
2442 key: config.key,
2443 subkeys: [":subkey1", ":subkey3"],
2444 delete: "true"
2445 }
2446 ]
2447 })
2448
2449 assert(
2450 json_response(conn, 200) == %{
2451 "configs" => [
2452 %{
2453 "group" => "pleroma",
2454 "key" => "keyaa1",
2455 "value" => [%{"tuple" => [":subkey2", "val2"]}]
2456 }
2457 ]
2458 }
2459 )
2460 end
2461 end
2462
2463 describe "config mix tasks run" do
2464 setup %{conn: conn} do
2465 admin = insert(:user, is_admin: true)
2466
2467 temp_file = "config/test.exported_from_db.secret.exs"
2468
2469 Mix.shell(Mix.Shell.Quiet)
2470
2471 on_exit(fn ->
2472 Mix.shell(Mix.Shell.IO)
2473 :ok = File.rm(temp_file)
2474 end)
2475
2476 %{conn: assign(conn, :user, admin), admin: admin}
2477 end
2478
2479 clear_config([:instance, :dynamic_configuration]) do
2480 Pleroma.Config.put([:instance, :dynamic_configuration], true)
2481 end
2482
2483 clear_config([:feed, :post_title]) do
2484 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
2485 end
2486
2487 test "transfer settings to DB and to file", %{conn: conn, admin: admin} do
2488 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2489 conn = get(conn, "/api/pleroma/admin/config/migrate_to_db")
2490 assert json_response(conn, 200) == %{}
2491 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0
2492
2493 conn =
2494 build_conn()
2495 |> assign(:user, admin)
2496 |> get("/api/pleroma/admin/config/migrate_from_db")
2497
2498 assert json_response(conn, 200) == %{}
2499 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2500 end
2501 end
2502
2503 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2504 setup do
2505 admin = insert(:user, is_admin: true)
2506 user = insert(:user)
2507
2508 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2509 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2510 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2511
2512 insert(:note_activity, user: user, published: date1)
2513 insert(:note_activity, user: user, published: date2)
2514 insert(:note_activity, user: user, published: date3)
2515
2516 conn =
2517 build_conn()
2518 |> assign(:user, admin)
2519
2520 {:ok, conn: conn, user: user}
2521 end
2522
2523 test "renders user's statuses", %{conn: conn, user: user} do
2524 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2525
2526 assert json_response(conn, 200) |> length() == 3
2527 end
2528
2529 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2530 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2531
2532 assert json_response(conn, 200) |> length() == 2
2533 end
2534
2535 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2536 {:ok, _private_status} =
2537 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2538
2539 {:ok, _public_status} =
2540 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2541
2542 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2543
2544 assert json_response(conn, 200) |> length() == 4
2545 end
2546
2547 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2548 {:ok, _private_status} =
2549 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2550
2551 {:ok, _public_status} =
2552 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2553
2554 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2555
2556 assert json_response(conn, 200) |> length() == 5
2557 end
2558 end
2559
2560 describe "GET /api/pleroma/admin/moderation_log" do
2561 setup %{conn: conn} do
2562 admin = insert(:user, is_admin: true)
2563 moderator = insert(:user, is_moderator: true)
2564
2565 %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator}
2566 end
2567
2568 test "returns the log", %{conn: conn, admin: admin} do
2569 Repo.insert(%ModerationLog{
2570 data: %{
2571 actor: %{
2572 "id" => admin.id,
2573 "nickname" => admin.nickname,
2574 "type" => "user"
2575 },
2576 action: "relay_follow",
2577 target: "https://example.org/relay"
2578 },
2579 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2580 })
2581
2582 Repo.insert(%ModerationLog{
2583 data: %{
2584 actor: %{
2585 "id" => admin.id,
2586 "nickname" => admin.nickname,
2587 "type" => "user"
2588 },
2589 action: "relay_unfollow",
2590 target: "https://example.org/relay"
2591 },
2592 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2593 })
2594
2595 conn = get(conn, "/api/pleroma/admin/moderation_log")
2596
2597 response = json_response(conn, 200)
2598 [first_entry, second_entry] = response["items"]
2599
2600 assert response["total"] == 2
2601 assert first_entry["data"]["action"] == "relay_unfollow"
2602
2603 assert first_entry["message"] ==
2604 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2605
2606 assert second_entry["data"]["action"] == "relay_follow"
2607
2608 assert second_entry["message"] ==
2609 "@#{admin.nickname} followed relay: https://example.org/relay"
2610 end
2611
2612 test "returns the log with pagination", %{conn: conn, admin: admin} do
2613 Repo.insert(%ModerationLog{
2614 data: %{
2615 actor: %{
2616 "id" => admin.id,
2617 "nickname" => admin.nickname,
2618 "type" => "user"
2619 },
2620 action: "relay_follow",
2621 target: "https://example.org/relay"
2622 },
2623 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2624 })
2625
2626 Repo.insert(%ModerationLog{
2627 data: %{
2628 actor: %{
2629 "id" => admin.id,
2630 "nickname" => admin.nickname,
2631 "type" => "user"
2632 },
2633 action: "relay_unfollow",
2634 target: "https://example.org/relay"
2635 },
2636 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2637 })
2638
2639 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
2640
2641 response1 = json_response(conn1, 200)
2642 [first_entry] = response1["items"]
2643
2644 assert response1["total"] == 2
2645 assert response1["items"] |> length() == 1
2646 assert first_entry["data"]["action"] == "relay_unfollow"
2647
2648 assert first_entry["message"] ==
2649 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2650
2651 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
2652
2653 response2 = json_response(conn2, 200)
2654 [second_entry] = response2["items"]
2655
2656 assert response2["total"] == 2
2657 assert response2["items"] |> length() == 1
2658 assert second_entry["data"]["action"] == "relay_follow"
2659
2660 assert second_entry["message"] ==
2661 "@#{admin.nickname} followed relay: https://example.org/relay"
2662 end
2663
2664 test "filters log by date", %{conn: conn, admin: admin} do
2665 first_date = "2017-08-15T15:47:06Z"
2666 second_date = "2017-08-20T15:47:06Z"
2667
2668 Repo.insert(%ModerationLog{
2669 data: %{
2670 actor: %{
2671 "id" => admin.id,
2672 "nickname" => admin.nickname,
2673 "type" => "user"
2674 },
2675 action: "relay_follow",
2676 target: "https://example.org/relay"
2677 },
2678 inserted_at: NaiveDateTime.from_iso8601!(first_date)
2679 })
2680
2681 Repo.insert(%ModerationLog{
2682 data: %{
2683 actor: %{
2684 "id" => admin.id,
2685 "nickname" => admin.nickname,
2686 "type" => "user"
2687 },
2688 action: "relay_unfollow",
2689 target: "https://example.org/relay"
2690 },
2691 inserted_at: NaiveDateTime.from_iso8601!(second_date)
2692 })
2693
2694 conn1 =
2695 get(
2696 conn,
2697 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
2698 )
2699
2700 response1 = json_response(conn1, 200)
2701 [first_entry] = response1["items"]
2702
2703 assert response1["total"] == 1
2704 assert first_entry["data"]["action"] == "relay_unfollow"
2705
2706 assert first_entry["message"] ==
2707 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2708 end
2709
2710 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
2711 Repo.insert(%ModerationLog{
2712 data: %{
2713 actor: %{
2714 "id" => admin.id,
2715 "nickname" => admin.nickname,
2716 "type" => "user"
2717 },
2718 action: "relay_follow",
2719 target: "https://example.org/relay"
2720 }
2721 })
2722
2723 Repo.insert(%ModerationLog{
2724 data: %{
2725 actor: %{
2726 "id" => moderator.id,
2727 "nickname" => moderator.nickname,
2728 "type" => "user"
2729 },
2730 action: "relay_unfollow",
2731 target: "https://example.org/relay"
2732 }
2733 })
2734
2735 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
2736
2737 response1 = json_response(conn1, 200)
2738 [first_entry] = response1["items"]
2739
2740 assert response1["total"] == 1
2741 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
2742 end
2743
2744 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
2745 ModerationLog.insert_log(%{
2746 actor: moderator,
2747 action: "relay_follow",
2748 target: "https://example.org/relay"
2749 })
2750
2751 ModerationLog.insert_log(%{
2752 actor: moderator,
2753 action: "relay_unfollow",
2754 target: "https://example.org/relay"
2755 })
2756
2757 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
2758
2759 response1 = json_response(conn1, 200)
2760 [first_entry] = response1["items"]
2761
2762 assert response1["total"] == 1
2763
2764 assert get_in(first_entry, ["data", "message"]) ==
2765 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
2766 end
2767 end
2768
2769 describe "PATCH /users/:nickname/force_password_reset" do
2770 setup %{conn: conn} do
2771 admin = insert(:user, is_admin: true)
2772 user = insert(:user)
2773
2774 %{conn: assign(conn, :user, admin), admin: admin, user: user}
2775 end
2776
2777 test "sets password_reset_pending to true", %{admin: admin, user: user} do
2778 assert user.password_reset_pending == false
2779
2780 conn =
2781 build_conn()
2782 |> assign(:user, admin)
2783 |> patch("/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
2784
2785 assert json_response(conn, 204) == ""
2786
2787 ObanHelpers.perform_all()
2788
2789 assert User.get_by_id(user.id).password_reset_pending == true
2790 end
2791 end
2792
2793 describe "relays" do
2794 setup %{conn: conn} do
2795 admin = insert(:user, is_admin: true)
2796
2797 %{conn: assign(conn, :user, admin), admin: admin}
2798 end
2799
2800 test "POST /relay", %{admin: admin} do
2801 conn =
2802 build_conn()
2803 |> assign(:user, admin)
2804 |> post("/api/pleroma/admin/relay", %{
2805 relay_url: "http://mastodon.example.org/users/admin"
2806 })
2807
2808 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2809
2810 log_entry = Repo.one(ModerationLog)
2811
2812 assert ModerationLog.get_log_entry_message(log_entry) ==
2813 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2814 end
2815
2816 test "GET /relay", %{admin: admin} do
2817 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
2818
2819 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
2820 |> Enum.each(fn ap_id ->
2821 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
2822 User.follow(relay_user, user)
2823 end)
2824
2825 conn =
2826 build_conn()
2827 |> assign(:user, admin)
2828 |> get("/api/pleroma/admin/relay")
2829
2830 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
2831 end
2832
2833 test "DELETE /relay", %{admin: admin} do
2834 build_conn()
2835 |> assign(:user, admin)
2836 |> post("/api/pleroma/admin/relay", %{
2837 relay_url: "http://mastodon.example.org/users/admin"
2838 })
2839
2840 conn =
2841 build_conn()
2842 |> assign(:user, admin)
2843 |> delete("/api/pleroma/admin/relay", %{
2844 relay_url: "http://mastodon.example.org/users/admin"
2845 })
2846
2847 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2848
2849 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
2850
2851 assert ModerationLog.get_log_entry_message(log_entry_one) ==
2852 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2853
2854 assert ModerationLog.get_log_entry_message(log_entry_two) ==
2855 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
2856 end
2857 end
2858
2859 describe "instances" do
2860 test "GET /instances/:instance/statuses" do
2861 admin = insert(:user, is_admin: true)
2862 user = insert(:user, local: false, nickname: "archaeme@archae.me")
2863 user2 = insert(:user, local: false, nickname: "test@test.com")
2864 insert_pair(:note_activity, user: user)
2865 insert(:note_activity, user: user2)
2866
2867 conn =
2868 build_conn()
2869 |> assign(:user, admin)
2870 |> get("/api/pleroma/admin/instances/archae.me/statuses")
2871
2872 response = json_response(conn, 200)
2873
2874 assert length(response) == 2
2875
2876 conn =
2877 build_conn()
2878 |> assign(:user, admin)
2879 |> get("/api/pleroma/admin/instances/test.com/statuses")
2880
2881 response = json_response(conn, 200)
2882
2883 assert length(response) == 1
2884
2885 conn =
2886 build_conn()
2887 |> assign(:user, admin)
2888 |> get("/api/pleroma/admin/instances/nonexistent.com/statuses")
2889
2890 response = json_response(conn, 200)
2891
2892 assert length(response) == 0
2893 end
2894 end
2895
2896 describe "PATCH /confirm_email" do
2897 setup %{conn: conn} do
2898 admin = insert(:user, is_admin: true)
2899
2900 %{conn: assign(conn, :user, admin), admin: admin}
2901 end
2902
2903 test "it confirms emails of two users", %{admin: admin} do
2904 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2905
2906 assert first_user.confirmation_pending == true
2907 assert second_user.confirmation_pending == true
2908
2909 build_conn()
2910 |> assign(:user, admin)
2911 |> patch("/api/pleroma/admin/users/confirm_email", %{
2912 nicknames: [
2913 first_user.nickname,
2914 second_user.nickname
2915 ]
2916 })
2917
2918 assert first_user.confirmation_pending == true
2919 assert second_user.confirmation_pending == true
2920
2921 log_entry = Repo.one(ModerationLog)
2922
2923 assert ModerationLog.get_log_entry_message(log_entry) ==
2924 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
2925 second_user.nickname
2926 }"
2927 end
2928 end
2929
2930 describe "PATCH /resend_confirmation_email" do
2931 setup %{conn: conn} do
2932 admin = insert(:user, is_admin: true)
2933
2934 %{conn: assign(conn, :user, admin), admin: admin}
2935 end
2936
2937 test "it resend emails for two users", %{admin: admin} do
2938 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2939
2940 build_conn()
2941 |> assign(:user, admin)
2942 |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{
2943 nicknames: [
2944 first_user.nickname,
2945 second_user.nickname
2946 ]
2947 })
2948
2949 log_entry = Repo.one(ModerationLog)
2950
2951 assert ModerationLog.get_log_entry_message(log_entry) ==
2952 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
2953 second_user.nickname
2954 }"
2955 end
2956 end
2957 end
2958
2959 # Needed for testing
2960 defmodule Pleroma.Web.Endpoint.NotReal do
2961 end
2962
2963 defmodule Pleroma.Captcha.NotReal do
2964 end