a69fadcdc85bdcef75e9d0545704c53b3a8fa55a
[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_report: first_report,
1617 first_status_reports: [first_report, second_report, third_report],
1618 second_status_reports: [first_report, second_report],
1619 third_status_reports: [first_report],
1620 target_user: target_user,
1621 reporter: reporter
1622 }
1623 end
1624
1625 test "returns reports grouped by status", %{
1626 conn: conn,
1627 first_status: first_status,
1628 second_status: second_status,
1629 third_status: third_status,
1630 first_status_reports: first_status_reports,
1631 second_status_reports: second_status_reports,
1632 third_status_reports: third_status_reports,
1633 target_user: target_user,
1634 reporter: reporter
1635 } do
1636 response =
1637 conn
1638 |> get("/api/pleroma/admin/grouped_reports")
1639 |> json_response(:ok)
1640
1641 assert length(response["reports"]) == 3
1642
1643 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1644
1645 second_group = Enum.find(response["reports"], &(&1["status"]["id"] == second_status.id))
1646
1647 third_group = Enum.find(response["reports"], &(&1["status"]["id"] == third_status.id))
1648
1649 assert length(first_group["reports"]) == 3
1650 assert length(second_group["reports"]) == 2
1651 assert length(third_group["reports"]) == 1
1652
1653 assert first_group["date"] ==
1654 Enum.max_by(first_status_reports, fn act ->
1655 NaiveDateTime.from_iso8601!(act.data["published"])
1656 end).data["published"]
1657
1658 assert first_group["status"] ==
1659 Map.put(
1660 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1661 "deleted",
1662 false
1663 )
1664
1665 assert(first_group["account"]["id"] == target_user.id)
1666
1667 assert length(first_group["actors"]) == 1
1668 assert hd(first_group["actors"])["id"] == reporter.id
1669
1670 assert Enum.map(first_group["reports"], & &1["id"]) --
1671 Enum.map(first_status_reports, & &1.id) == []
1672
1673 assert second_group["date"] ==
1674 Enum.max_by(second_status_reports, fn act ->
1675 NaiveDateTime.from_iso8601!(act.data["published"])
1676 end).data["published"]
1677
1678 assert second_group["status"] ==
1679 Map.put(
1680 stringify_keys(StatusView.render("show.json", %{activity: second_status})),
1681 "deleted",
1682 false
1683 )
1684
1685 assert second_group["account"]["id"] == target_user.id
1686
1687 assert length(second_group["actors"]) == 1
1688 assert hd(second_group["actors"])["id"] == reporter.id
1689
1690 assert Enum.map(second_group["reports"], & &1["id"]) --
1691 Enum.map(second_status_reports, & &1.id) == []
1692
1693 assert third_group["date"] ==
1694 Enum.max_by(third_status_reports, fn act ->
1695 NaiveDateTime.from_iso8601!(act.data["published"])
1696 end).data["published"]
1697
1698 assert third_group["status"] ==
1699 Map.put(
1700 stringify_keys(StatusView.render("show.json", %{activity: third_status})),
1701 "deleted",
1702 false
1703 )
1704
1705 assert third_group["account"]["id"] == target_user.id
1706
1707 assert length(third_group["actors"]) == 1
1708 assert hd(third_group["actors"])["id"] == reporter.id
1709
1710 assert Enum.map(third_group["reports"], & &1["id"]) --
1711 Enum.map(third_status_reports, & &1.id) == []
1712 end
1713
1714 test "reopened report renders status data", %{
1715 conn: conn,
1716 first_report: first_report,
1717 first_status: first_status
1718 } do
1719 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1720
1721 response =
1722 conn
1723 |> get("/api/pleroma/admin/grouped_reports")
1724 |> json_response(:ok)
1725
1726 first_group = Enum.find(response["reports"], &(&1["status"]["id"] == first_status.id))
1727
1728 assert first_group["status"] ==
1729 Map.put(
1730 stringify_keys(StatusView.render("show.json", %{activity: first_status})),
1731 "deleted",
1732 false
1733 )
1734 end
1735
1736 test "reopened report does not render status data if status has been deleted", %{
1737 conn: conn,
1738 first_report: first_report,
1739 first_status: first_status,
1740 target_user: target_user
1741 } do
1742 {:ok, _} = CommonAPI.update_report_state(first_report.id, "resolved")
1743 {:ok, _} = CommonAPI.delete(first_status.id, target_user)
1744
1745 refute Activity.get_by_ap_id(first_status.id)
1746
1747 response =
1748 conn
1749 |> get("/api/pleroma/admin/grouped_reports")
1750 |> json_response(:ok)
1751
1752 assert Enum.find(response["reports"], &(&1["status"]["deleted"] == true))["status"][
1753 "deleted"
1754 ] == true
1755
1756 assert length(Enum.filter(response["reports"], &(&1["status"]["deleted"] == false))) == 2
1757 end
1758 end
1759
1760 describe "POST /api/pleroma/admin/reports/:id/respond" do
1761 setup %{conn: conn} do
1762 admin = insert(:user, is_admin: true)
1763
1764 %{conn: assign(conn, :user, admin), admin: admin}
1765 end
1766
1767 test "returns created dm", %{conn: conn, admin: admin} do
1768 [reporter, target_user] = insert_pair(:user)
1769 activity = insert(:note_activity, user: target_user)
1770
1771 {:ok, %{id: report_id}} =
1772 CommonAPI.report(reporter, %{
1773 "account_id" => target_user.id,
1774 "comment" => "I feel offended",
1775 "status_ids" => [activity.id]
1776 })
1777
1778 response =
1779 conn
1780 |> post("/api/pleroma/admin/reports/#{report_id}/respond", %{
1781 "status" => "I will check it out"
1782 })
1783 |> json_response(:ok)
1784
1785 recipients = Enum.map(response["mentions"], & &1["username"])
1786
1787 assert reporter.nickname in recipients
1788 assert response["content"] == "I will check it out"
1789 assert response["visibility"] == "direct"
1790
1791 log_entry = Repo.one(ModerationLog)
1792
1793 assert ModerationLog.get_log_entry_message(log_entry) ==
1794 "@#{admin.nickname} responded with 'I will check it out' to report ##{
1795 response["id"]
1796 }"
1797 end
1798
1799 test "returns 400 when status is missing", %{conn: conn} do
1800 conn = post(conn, "/api/pleroma/admin/reports/test/respond")
1801
1802 assert json_response(conn, :bad_request) == "Invalid parameters"
1803 end
1804
1805 test "returns 404 when report id is invalid", %{conn: conn} do
1806 conn =
1807 post(conn, "/api/pleroma/admin/reports/test/respond", %{
1808 "status" => "foo"
1809 })
1810
1811 assert json_response(conn, :not_found) == "Not found"
1812 end
1813 end
1814
1815 describe "PUT /api/pleroma/admin/statuses/:id" do
1816 setup %{conn: conn} do
1817 admin = insert(:user, is_admin: true)
1818 activity = insert(:note_activity)
1819
1820 %{conn: assign(conn, :user, admin), id: activity.id, admin: admin}
1821 end
1822
1823 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1824 response =
1825 conn
1826 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1827 |> json_response(:ok)
1828
1829 assert response["sensitive"]
1830
1831 log_entry = Repo.one(ModerationLog)
1832
1833 assert ModerationLog.get_log_entry_message(log_entry) ==
1834 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1835
1836 response =
1837 conn
1838 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1839 |> json_response(:ok)
1840
1841 refute response["sensitive"]
1842 end
1843
1844 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1845 response =
1846 conn
1847 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1848 |> json_response(:ok)
1849
1850 assert response["visibility"] == "public"
1851
1852 log_entry = Repo.one(ModerationLog)
1853
1854 assert ModerationLog.get_log_entry_message(log_entry) ==
1855 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1856
1857 response =
1858 conn
1859 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1860 |> json_response(:ok)
1861
1862 assert response["visibility"] == "private"
1863
1864 response =
1865 conn
1866 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1867 |> json_response(:ok)
1868
1869 assert response["visibility"] == "unlisted"
1870 end
1871
1872 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1873 conn =
1874 conn
1875 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1876
1877 assert json_response(conn, :bad_request) == "Unsupported visibility"
1878 end
1879 end
1880
1881 describe "DELETE /api/pleroma/admin/statuses/:id" do
1882 setup %{conn: conn} do
1883 admin = insert(:user, is_admin: true)
1884 activity = insert(:note_activity)
1885
1886 %{conn: assign(conn, :user, admin), id: activity.id, admin: admin}
1887 end
1888
1889 test "deletes status", %{conn: conn, id: id, admin: admin} do
1890 conn
1891 |> delete("/api/pleroma/admin/statuses/#{id}")
1892 |> json_response(:ok)
1893
1894 refute Activity.get_by_id(id)
1895
1896 log_entry = Repo.one(ModerationLog)
1897
1898 assert ModerationLog.get_log_entry_message(log_entry) ==
1899 "@#{admin.nickname} deleted status ##{id}"
1900 end
1901
1902 test "returns error when status is not exist", %{conn: conn} do
1903 conn =
1904 conn
1905 |> delete("/api/pleroma/admin/statuses/test")
1906
1907 assert json_response(conn, :bad_request) == "Could not delete"
1908 end
1909 end
1910
1911 describe "GET /api/pleroma/admin/config" do
1912 setup %{conn: conn} do
1913 admin = insert(:user, is_admin: true)
1914
1915 %{conn: assign(conn, :user, admin)}
1916 end
1917
1918 test "without any settings in db", %{conn: conn} do
1919 conn = get(conn, "/api/pleroma/admin/config")
1920
1921 assert json_response(conn, 200) == %{"configs" => []}
1922 end
1923
1924 test "with settings in db", %{conn: conn} do
1925 config1 = insert(:config)
1926 config2 = insert(:config)
1927
1928 conn = get(conn, "/api/pleroma/admin/config")
1929
1930 %{
1931 "configs" => [
1932 %{
1933 "key" => key1,
1934 "value" => _
1935 },
1936 %{
1937 "key" => key2,
1938 "value" => _
1939 }
1940 ]
1941 } = json_response(conn, 200)
1942
1943 assert key1 == config1.key
1944 assert key2 == config2.key
1945 end
1946 end
1947
1948 describe "POST /api/pleroma/admin/config" do
1949 setup %{conn: conn} do
1950 admin = insert(:user, is_admin: true)
1951
1952 temp_file = "config/test.exported_from_db.secret.exs"
1953
1954 on_exit(fn ->
1955 Application.delete_env(:pleroma, :key1)
1956 Application.delete_env(:pleroma, :key2)
1957 Application.delete_env(:pleroma, :key3)
1958 Application.delete_env(:pleroma, :key4)
1959 Application.delete_env(:pleroma, :keyaa1)
1960 Application.delete_env(:pleroma, :keyaa2)
1961 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1962 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1963 :ok = File.rm(temp_file)
1964 end)
1965
1966 %{conn: assign(conn, :user, admin)}
1967 end
1968
1969 clear_config([:instance, :dynamic_configuration]) do
1970 Pleroma.Config.put([:instance, :dynamic_configuration], true)
1971 end
1972
1973 test "create new config setting in db", %{conn: conn} do
1974 conn =
1975 post(conn, "/api/pleroma/admin/config", %{
1976 configs: [
1977 %{group: "pleroma", key: "key1", value: "value1"},
1978 %{
1979 group: "ueberauth",
1980 key: "Ueberauth.Strategy.Twitter.OAuth",
1981 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1982 },
1983 %{
1984 group: "pleroma",
1985 key: "key2",
1986 value: %{
1987 ":nested_1" => "nested_value1",
1988 ":nested_2" => [
1989 %{":nested_22" => "nested_value222"},
1990 %{":nested_33" => %{":nested_44" => "nested_444"}}
1991 ]
1992 }
1993 },
1994 %{
1995 group: "pleroma",
1996 key: "key3",
1997 value: [
1998 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1999 %{"nested_4" => true}
2000 ]
2001 },
2002 %{
2003 group: "pleroma",
2004 key: "key4",
2005 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
2006 },
2007 %{
2008 group: "idna",
2009 key: "key5",
2010 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2011 }
2012 ]
2013 })
2014
2015 assert json_response(conn, 200) == %{
2016 "configs" => [
2017 %{
2018 "group" => "pleroma",
2019 "key" => "key1",
2020 "value" => "value1"
2021 },
2022 %{
2023 "group" => "ueberauth",
2024 "key" => "Ueberauth.Strategy.Twitter.OAuth",
2025 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}]
2026 },
2027 %{
2028 "group" => "pleroma",
2029 "key" => "key2",
2030 "value" => %{
2031 ":nested_1" => "nested_value1",
2032 ":nested_2" => [
2033 %{":nested_22" => "nested_value222"},
2034 %{":nested_33" => %{":nested_44" => "nested_444"}}
2035 ]
2036 }
2037 },
2038 %{
2039 "group" => "pleroma",
2040 "key" => "key3",
2041 "value" => [
2042 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
2043 %{"nested_4" => true}
2044 ]
2045 },
2046 %{
2047 "group" => "pleroma",
2048 "key" => "key4",
2049 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"}
2050 },
2051 %{
2052 "group" => "idna",
2053 "key" => "key5",
2054 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
2055 }
2056 ]
2057 }
2058
2059 assert Application.get_env(:pleroma, :key1) == "value1"
2060
2061 assert Application.get_env(:pleroma, :key2) == %{
2062 nested_1: "nested_value1",
2063 nested_2: [
2064 %{nested_22: "nested_value222"},
2065 %{nested_33: %{nested_44: "nested_444"}}
2066 ]
2067 }
2068
2069 assert Application.get_env(:pleroma, :key3) == [
2070 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
2071 %{"nested_4" => true}
2072 ]
2073
2074 assert Application.get_env(:pleroma, :key4) == %{
2075 "endpoint" => "https://example.com",
2076 nested_5: :upload
2077 }
2078
2079 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
2080 end
2081
2082 test "update config setting & delete", %{conn: conn} do
2083 config1 = insert(:config, key: "keyaa1")
2084 config2 = insert(:config, key: "keyaa2")
2085
2086 insert(:config,
2087 group: "ueberauth",
2088 key: "Ueberauth.Strategy.Microsoft.OAuth",
2089 value: :erlang.term_to_binary([])
2090 )
2091
2092 conn =
2093 post(conn, "/api/pleroma/admin/config", %{
2094 configs: [
2095 %{group: config1.group, key: config1.key, value: "another_value"},
2096 %{group: config2.group, key: config2.key, delete: "true"},
2097 %{
2098 group: "ueberauth",
2099 key: "Ueberauth.Strategy.Microsoft.OAuth",
2100 delete: "true"
2101 }
2102 ]
2103 })
2104
2105 assert json_response(conn, 200) == %{
2106 "configs" => [
2107 %{
2108 "group" => "pleroma",
2109 "key" => config1.key,
2110 "value" => "another_value"
2111 }
2112 ]
2113 }
2114
2115 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2116 refute Application.get_env(:pleroma, :keyaa2)
2117 end
2118
2119 test "common config example", %{conn: conn} do
2120 conn =
2121 post(conn, "/api/pleroma/admin/config", %{
2122 configs: [
2123 %{
2124 "group" => "pleroma",
2125 "key" => "Pleroma.Captcha.NotReal",
2126 "value" => [
2127 %{"tuple" => [":enabled", false]},
2128 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2129 %{"tuple" => [":seconds_valid", 60]},
2130 %{"tuple" => [":path", ""]},
2131 %{"tuple" => [":key1", nil]},
2132 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2133 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2134 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2135 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2136 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]}
2137 ]
2138 }
2139 ]
2140 })
2141
2142 assert json_response(conn, 200) == %{
2143 "configs" => [
2144 %{
2145 "group" => "pleroma",
2146 "key" => "Pleroma.Captcha.NotReal",
2147 "value" => [
2148 %{"tuple" => [":enabled", false]},
2149 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2150 %{"tuple" => [":seconds_valid", 60]},
2151 %{"tuple" => [":path", ""]},
2152 %{"tuple" => [":key1", nil]},
2153 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2154 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2155 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2156 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2157 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]}
2158 ]
2159 }
2160 ]
2161 }
2162 end
2163
2164 test "tuples with more than two values", %{conn: conn} do
2165 conn =
2166 post(conn, "/api/pleroma/admin/config", %{
2167 configs: [
2168 %{
2169 "group" => "pleroma",
2170 "key" => "Pleroma.Web.Endpoint.NotReal",
2171 "value" => [
2172 %{
2173 "tuple" => [
2174 ":http",
2175 [
2176 %{
2177 "tuple" => [
2178 ":key2",
2179 [
2180 %{
2181 "tuple" => [
2182 ":_",
2183 [
2184 %{
2185 "tuple" => [
2186 "/api/v1/streaming",
2187 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2188 []
2189 ]
2190 },
2191 %{
2192 "tuple" => [
2193 "/websocket",
2194 "Phoenix.Endpoint.CowboyWebSocket",
2195 %{
2196 "tuple" => [
2197 "Phoenix.Transports.WebSocket",
2198 %{
2199 "tuple" => [
2200 "Pleroma.Web.Endpoint",
2201 "Pleroma.Web.UserSocket",
2202 []
2203 ]
2204 }
2205 ]
2206 }
2207 ]
2208 },
2209 %{
2210 "tuple" => [
2211 ":_",
2212 "Phoenix.Endpoint.Cowboy2Handler",
2213 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2214 ]
2215 }
2216 ]
2217 ]
2218 }
2219 ]
2220 ]
2221 }
2222 ]
2223 ]
2224 }
2225 ]
2226 }
2227 ]
2228 })
2229
2230 assert json_response(conn, 200) == %{
2231 "configs" => [
2232 %{
2233 "group" => "pleroma",
2234 "key" => "Pleroma.Web.Endpoint.NotReal",
2235 "value" => [
2236 %{
2237 "tuple" => [
2238 ":http",
2239 [
2240 %{
2241 "tuple" => [
2242 ":key2",
2243 [
2244 %{
2245 "tuple" => [
2246 ":_",
2247 [
2248 %{
2249 "tuple" => [
2250 "/api/v1/streaming",
2251 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2252 []
2253 ]
2254 },
2255 %{
2256 "tuple" => [
2257 "/websocket",
2258 "Phoenix.Endpoint.CowboyWebSocket",
2259 %{
2260 "tuple" => [
2261 "Phoenix.Transports.WebSocket",
2262 %{
2263 "tuple" => [
2264 "Pleroma.Web.Endpoint",
2265 "Pleroma.Web.UserSocket",
2266 []
2267 ]
2268 }
2269 ]
2270 }
2271 ]
2272 },
2273 %{
2274 "tuple" => [
2275 ":_",
2276 "Phoenix.Endpoint.Cowboy2Handler",
2277 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2278 ]
2279 }
2280 ]
2281 ]
2282 }
2283 ]
2284 ]
2285 }
2286 ]
2287 ]
2288 }
2289 ]
2290 }
2291 ]
2292 }
2293 end
2294
2295 test "settings with nesting map", %{conn: conn} do
2296 conn =
2297 post(conn, "/api/pleroma/admin/config", %{
2298 configs: [
2299 %{
2300 "group" => "pleroma",
2301 "key" => ":key1",
2302 "value" => [
2303 %{"tuple" => [":key2", "some_val"]},
2304 %{
2305 "tuple" => [
2306 ":key3",
2307 %{
2308 ":max_options" => 20,
2309 ":max_option_chars" => 200,
2310 ":min_expiration" => 0,
2311 ":max_expiration" => 31_536_000,
2312 "nested" => %{
2313 ":max_options" => 20,
2314 ":max_option_chars" => 200,
2315 ":min_expiration" => 0,
2316 ":max_expiration" => 31_536_000
2317 }
2318 }
2319 ]
2320 }
2321 ]
2322 }
2323 ]
2324 })
2325
2326 assert json_response(conn, 200) ==
2327 %{
2328 "configs" => [
2329 %{
2330 "group" => "pleroma",
2331 "key" => ":key1",
2332 "value" => [
2333 %{"tuple" => [":key2", "some_val"]},
2334 %{
2335 "tuple" => [
2336 ":key3",
2337 %{
2338 ":max_expiration" => 31_536_000,
2339 ":max_option_chars" => 200,
2340 ":max_options" => 20,
2341 ":min_expiration" => 0,
2342 "nested" => %{
2343 ":max_expiration" => 31_536_000,
2344 ":max_option_chars" => 200,
2345 ":max_options" => 20,
2346 ":min_expiration" => 0
2347 }
2348 }
2349 ]
2350 }
2351 ]
2352 }
2353 ]
2354 }
2355 end
2356
2357 test "value as map", %{conn: conn} do
2358 conn =
2359 post(conn, "/api/pleroma/admin/config", %{
2360 configs: [
2361 %{
2362 "group" => "pleroma",
2363 "key" => ":key1",
2364 "value" => %{"key" => "some_val"}
2365 }
2366 ]
2367 })
2368
2369 assert json_response(conn, 200) ==
2370 %{
2371 "configs" => [
2372 %{
2373 "group" => "pleroma",
2374 "key" => ":key1",
2375 "value" => %{"key" => "some_val"}
2376 }
2377 ]
2378 }
2379 end
2380
2381 test "dispatch setting", %{conn: conn} do
2382 conn =
2383 post(conn, "/api/pleroma/admin/config", %{
2384 configs: [
2385 %{
2386 "group" => "pleroma",
2387 "key" => "Pleroma.Web.Endpoint.NotReal",
2388 "value" => [
2389 %{
2390 "tuple" => [
2391 ":http",
2392 [
2393 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2394 %{"tuple" => [":dispatch", ["{:_,
2395 [
2396 {\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []},
2397 {\"/websocket\", Phoenix.Endpoint.CowboyWebSocket,
2398 {Phoenix.Transports.WebSocket,
2399 {Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}},
2400 {:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}
2401 ]}"]]}
2402 ]
2403 ]
2404 }
2405 ]
2406 }
2407 ]
2408 })
2409
2410 dispatch_string =
2411 "{:_, [{\"/api/v1/streaming\", Pleroma.Web.MastodonAPI.WebsocketHandler, []}, " <>
2412 "{\"/websocket\", Phoenix.Endpoint.CowboyWebSocket, {Phoenix.Transports.WebSocket, " <>
2413 "{Pleroma.Web.Endpoint, Pleroma.Web.UserSocket, [path: \"/websocket\"]}}}, " <>
2414 "{:_, Phoenix.Endpoint.Cowboy2Handler, {Pleroma.Web.Endpoint, []}}]}"
2415
2416 assert json_response(conn, 200) == %{
2417 "configs" => [
2418 %{
2419 "group" => "pleroma",
2420 "key" => "Pleroma.Web.Endpoint.NotReal",
2421 "value" => [
2422 %{
2423 "tuple" => [
2424 ":http",
2425 [
2426 %{"tuple" => [":ip", %{"tuple" => [127, 0, 0, 1]}]},
2427 %{
2428 "tuple" => [
2429 ":dispatch",
2430 [
2431 dispatch_string
2432 ]
2433 ]
2434 }
2435 ]
2436 ]
2437 }
2438 ]
2439 }
2440 ]
2441 }
2442 end
2443
2444 test "queues key as atom", %{conn: conn} do
2445 conn =
2446 post(conn, "/api/pleroma/admin/config", %{
2447 configs: [
2448 %{
2449 "group" => "oban",
2450 "key" => ":queues",
2451 "value" => [
2452 %{"tuple" => [":federator_incoming", 50]},
2453 %{"tuple" => [":federator_outgoing", 50]},
2454 %{"tuple" => [":web_push", 50]},
2455 %{"tuple" => [":mailer", 10]},
2456 %{"tuple" => [":transmogrifier", 20]},
2457 %{"tuple" => [":scheduled_activities", 10]},
2458 %{"tuple" => [":background", 5]}
2459 ]
2460 }
2461 ]
2462 })
2463
2464 assert json_response(conn, 200) == %{
2465 "configs" => [
2466 %{
2467 "group" => "oban",
2468 "key" => ":queues",
2469 "value" => [
2470 %{"tuple" => [":federator_incoming", 50]},
2471 %{"tuple" => [":federator_outgoing", 50]},
2472 %{"tuple" => [":web_push", 50]},
2473 %{"tuple" => [":mailer", 10]},
2474 %{"tuple" => [":transmogrifier", 20]},
2475 %{"tuple" => [":scheduled_activities", 10]},
2476 %{"tuple" => [":background", 5]}
2477 ]
2478 }
2479 ]
2480 }
2481 end
2482
2483 test "delete part of settings by atom subkeys", %{conn: conn} do
2484 config =
2485 insert(:config,
2486 key: "keyaa1",
2487 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2488 )
2489
2490 conn =
2491 post(conn, "/api/pleroma/admin/config", %{
2492 configs: [
2493 %{
2494 group: config.group,
2495 key: config.key,
2496 subkeys: [":subkey1", ":subkey3"],
2497 delete: "true"
2498 }
2499 ]
2500 })
2501
2502 assert(
2503 json_response(conn, 200) == %{
2504 "configs" => [
2505 %{
2506 "group" => "pleroma",
2507 "key" => "keyaa1",
2508 "value" => [%{"tuple" => [":subkey2", "val2"]}]
2509 }
2510 ]
2511 }
2512 )
2513 end
2514 end
2515
2516 describe "config mix tasks run" do
2517 setup %{conn: conn} do
2518 admin = insert(:user, is_admin: true)
2519
2520 temp_file = "config/test.exported_from_db.secret.exs"
2521
2522 Mix.shell(Mix.Shell.Quiet)
2523
2524 on_exit(fn ->
2525 Mix.shell(Mix.Shell.IO)
2526 :ok = File.rm(temp_file)
2527 end)
2528
2529 %{conn: assign(conn, :user, admin), admin: admin}
2530 end
2531
2532 clear_config([:instance, :dynamic_configuration]) do
2533 Pleroma.Config.put([:instance, :dynamic_configuration], true)
2534 end
2535
2536 clear_config([:feed, :post_title]) do
2537 Pleroma.Config.put([:feed, :post_title], %{max_length: 100, omission: "…"})
2538 end
2539
2540 test "transfer settings to DB and to file", %{conn: conn, admin: admin} do
2541 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2542 conn = get(conn, "/api/pleroma/admin/config/migrate_to_db")
2543 assert json_response(conn, 200) == %{}
2544 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) > 0
2545
2546 conn =
2547 build_conn()
2548 |> assign(:user, admin)
2549 |> get("/api/pleroma/admin/config/migrate_from_db")
2550
2551 assert json_response(conn, 200) == %{}
2552 assert Pleroma.Repo.all(Pleroma.Web.AdminAPI.Config) == []
2553 end
2554 end
2555
2556 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2557 setup do
2558 admin = insert(:user, is_admin: true)
2559 user = insert(:user)
2560
2561 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2562 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2563 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2564
2565 insert(:note_activity, user: user, published: date1)
2566 insert(:note_activity, user: user, published: date2)
2567 insert(:note_activity, user: user, published: date3)
2568
2569 conn =
2570 build_conn()
2571 |> assign(:user, admin)
2572
2573 {:ok, conn: conn, user: user}
2574 end
2575
2576 test "renders user's statuses", %{conn: conn, user: user} do
2577 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2578
2579 assert json_response(conn, 200) |> length() == 3
2580 end
2581
2582 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2583 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2584
2585 assert json_response(conn, 200) |> length() == 2
2586 end
2587
2588 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2589 {:ok, _private_status} =
2590 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2591
2592 {:ok, _public_status} =
2593 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2594
2595 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2596
2597 assert json_response(conn, 200) |> length() == 4
2598 end
2599
2600 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2601 {:ok, _private_status} =
2602 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2603
2604 {:ok, _public_status} =
2605 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2606
2607 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2608
2609 assert json_response(conn, 200) |> length() == 5
2610 end
2611 end
2612
2613 describe "GET /api/pleroma/admin/moderation_log" do
2614 setup %{conn: conn} do
2615 admin = insert(:user, is_admin: true)
2616 moderator = insert(:user, is_moderator: true)
2617
2618 %{conn: assign(conn, :user, admin), admin: admin, moderator: moderator}
2619 end
2620
2621 test "returns the log", %{conn: conn, admin: admin} do
2622 Repo.insert(%ModerationLog{
2623 data: %{
2624 actor: %{
2625 "id" => admin.id,
2626 "nickname" => admin.nickname,
2627 "type" => "user"
2628 },
2629 action: "relay_follow",
2630 target: "https://example.org/relay"
2631 },
2632 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2633 })
2634
2635 Repo.insert(%ModerationLog{
2636 data: %{
2637 actor: %{
2638 "id" => admin.id,
2639 "nickname" => admin.nickname,
2640 "type" => "user"
2641 },
2642 action: "relay_unfollow",
2643 target: "https://example.org/relay"
2644 },
2645 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2646 })
2647
2648 conn = get(conn, "/api/pleroma/admin/moderation_log")
2649
2650 response = json_response(conn, 200)
2651 [first_entry, second_entry] = response["items"]
2652
2653 assert response["total"] == 2
2654 assert first_entry["data"]["action"] == "relay_unfollow"
2655
2656 assert first_entry["message"] ==
2657 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2658
2659 assert second_entry["data"]["action"] == "relay_follow"
2660
2661 assert second_entry["message"] ==
2662 "@#{admin.nickname} followed relay: https://example.org/relay"
2663 end
2664
2665 test "returns the log with pagination", %{conn: conn, admin: admin} do
2666 Repo.insert(%ModerationLog{
2667 data: %{
2668 actor: %{
2669 "id" => admin.id,
2670 "nickname" => admin.nickname,
2671 "type" => "user"
2672 },
2673 action: "relay_follow",
2674 target: "https://example.org/relay"
2675 },
2676 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
2677 })
2678
2679 Repo.insert(%ModerationLog{
2680 data: %{
2681 actor: %{
2682 "id" => admin.id,
2683 "nickname" => admin.nickname,
2684 "type" => "user"
2685 },
2686 action: "relay_unfollow",
2687 target: "https://example.org/relay"
2688 },
2689 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
2690 })
2691
2692 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
2693
2694 response1 = json_response(conn1, 200)
2695 [first_entry] = response1["items"]
2696
2697 assert response1["total"] == 2
2698 assert response1["items"] |> length() == 1
2699 assert first_entry["data"]["action"] == "relay_unfollow"
2700
2701 assert first_entry["message"] ==
2702 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2703
2704 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
2705
2706 response2 = json_response(conn2, 200)
2707 [second_entry] = response2["items"]
2708
2709 assert response2["total"] == 2
2710 assert response2["items"] |> length() == 1
2711 assert second_entry["data"]["action"] == "relay_follow"
2712
2713 assert second_entry["message"] ==
2714 "@#{admin.nickname} followed relay: https://example.org/relay"
2715 end
2716
2717 test "filters log by date", %{conn: conn, admin: admin} do
2718 first_date = "2017-08-15T15:47:06Z"
2719 second_date = "2017-08-20T15:47:06Z"
2720
2721 Repo.insert(%ModerationLog{
2722 data: %{
2723 actor: %{
2724 "id" => admin.id,
2725 "nickname" => admin.nickname,
2726 "type" => "user"
2727 },
2728 action: "relay_follow",
2729 target: "https://example.org/relay"
2730 },
2731 inserted_at: NaiveDateTime.from_iso8601!(first_date)
2732 })
2733
2734 Repo.insert(%ModerationLog{
2735 data: %{
2736 actor: %{
2737 "id" => admin.id,
2738 "nickname" => admin.nickname,
2739 "type" => "user"
2740 },
2741 action: "relay_unfollow",
2742 target: "https://example.org/relay"
2743 },
2744 inserted_at: NaiveDateTime.from_iso8601!(second_date)
2745 })
2746
2747 conn1 =
2748 get(
2749 conn,
2750 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
2751 )
2752
2753 response1 = json_response(conn1, 200)
2754 [first_entry] = response1["items"]
2755
2756 assert response1["total"] == 1
2757 assert first_entry["data"]["action"] == "relay_unfollow"
2758
2759 assert first_entry["message"] ==
2760 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
2761 end
2762
2763 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
2764 Repo.insert(%ModerationLog{
2765 data: %{
2766 actor: %{
2767 "id" => admin.id,
2768 "nickname" => admin.nickname,
2769 "type" => "user"
2770 },
2771 action: "relay_follow",
2772 target: "https://example.org/relay"
2773 }
2774 })
2775
2776 Repo.insert(%ModerationLog{
2777 data: %{
2778 actor: %{
2779 "id" => moderator.id,
2780 "nickname" => moderator.nickname,
2781 "type" => "user"
2782 },
2783 action: "relay_unfollow",
2784 target: "https://example.org/relay"
2785 }
2786 })
2787
2788 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
2789
2790 response1 = json_response(conn1, 200)
2791 [first_entry] = response1["items"]
2792
2793 assert response1["total"] == 1
2794 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
2795 end
2796
2797 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
2798 ModerationLog.insert_log(%{
2799 actor: moderator,
2800 action: "relay_follow",
2801 target: "https://example.org/relay"
2802 })
2803
2804 ModerationLog.insert_log(%{
2805 actor: moderator,
2806 action: "relay_unfollow",
2807 target: "https://example.org/relay"
2808 })
2809
2810 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
2811
2812 response1 = json_response(conn1, 200)
2813 [first_entry] = response1["items"]
2814
2815 assert response1["total"] == 1
2816
2817 assert get_in(first_entry, ["data", "message"]) ==
2818 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
2819 end
2820 end
2821
2822 describe "PATCH /users/:nickname/force_password_reset" do
2823 setup %{conn: conn} do
2824 admin = insert(:user, is_admin: true)
2825 user = insert(:user)
2826
2827 %{conn: assign(conn, :user, admin), admin: admin, user: user}
2828 end
2829
2830 test "sets password_reset_pending to true", %{admin: admin, user: user} do
2831 assert user.password_reset_pending == false
2832
2833 conn =
2834 build_conn()
2835 |> assign(:user, admin)
2836 |> patch("/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
2837
2838 assert json_response(conn, 204) == ""
2839
2840 ObanHelpers.perform_all()
2841
2842 assert User.get_by_id(user.id).password_reset_pending == true
2843 end
2844 end
2845
2846 describe "relays" do
2847 setup %{conn: conn} do
2848 admin = insert(:user, is_admin: true)
2849
2850 %{conn: assign(conn, :user, admin), admin: admin}
2851 end
2852
2853 test "POST /relay", %{admin: admin} do
2854 conn =
2855 build_conn()
2856 |> assign(:user, admin)
2857 |> post("/api/pleroma/admin/relay", %{
2858 relay_url: "http://mastodon.example.org/users/admin"
2859 })
2860
2861 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2862
2863 log_entry = Repo.one(ModerationLog)
2864
2865 assert ModerationLog.get_log_entry_message(log_entry) ==
2866 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2867 end
2868
2869 test "GET /relay", %{admin: admin} do
2870 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
2871
2872 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
2873 |> Enum.each(fn ap_id ->
2874 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
2875 User.follow(relay_user, user)
2876 end)
2877
2878 conn =
2879 build_conn()
2880 |> assign(:user, admin)
2881 |> get("/api/pleroma/admin/relay")
2882
2883 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
2884 end
2885
2886 test "DELETE /relay", %{admin: admin} do
2887 build_conn()
2888 |> assign(:user, admin)
2889 |> post("/api/pleroma/admin/relay", %{
2890 relay_url: "http://mastodon.example.org/users/admin"
2891 })
2892
2893 conn =
2894 build_conn()
2895 |> assign(:user, admin)
2896 |> delete("/api/pleroma/admin/relay", %{
2897 relay_url: "http://mastodon.example.org/users/admin"
2898 })
2899
2900 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
2901
2902 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
2903
2904 assert ModerationLog.get_log_entry_message(log_entry_one) ==
2905 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
2906
2907 assert ModerationLog.get_log_entry_message(log_entry_two) ==
2908 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
2909 end
2910 end
2911
2912 describe "instances" do
2913 test "GET /instances/:instance/statuses" do
2914 admin = insert(:user, is_admin: true)
2915 user = insert(:user, local: false, nickname: "archaeme@archae.me")
2916 user2 = insert(:user, local: false, nickname: "test@test.com")
2917 insert_pair(:note_activity, user: user)
2918 insert(:note_activity, user: user2)
2919
2920 conn =
2921 build_conn()
2922 |> assign(:user, admin)
2923 |> get("/api/pleroma/admin/instances/archae.me/statuses")
2924
2925 response = json_response(conn, 200)
2926
2927 assert length(response) == 2
2928
2929 conn =
2930 build_conn()
2931 |> assign(:user, admin)
2932 |> get("/api/pleroma/admin/instances/test.com/statuses")
2933
2934 response = json_response(conn, 200)
2935
2936 assert length(response) == 1
2937
2938 conn =
2939 build_conn()
2940 |> assign(:user, admin)
2941 |> get("/api/pleroma/admin/instances/nonexistent.com/statuses")
2942
2943 response = json_response(conn, 200)
2944
2945 assert length(response) == 0
2946 end
2947 end
2948
2949 describe "PATCH /confirm_email" do
2950 setup %{conn: conn} do
2951 admin = insert(:user, is_admin: true)
2952
2953 %{conn: assign(conn, :user, admin), admin: admin}
2954 end
2955
2956 test "it confirms emails of two users", %{admin: admin} do
2957 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2958
2959 assert first_user.confirmation_pending == true
2960 assert second_user.confirmation_pending == true
2961
2962 build_conn()
2963 |> assign(:user, admin)
2964 |> patch("/api/pleroma/admin/users/confirm_email", %{
2965 nicknames: [
2966 first_user.nickname,
2967 second_user.nickname
2968 ]
2969 })
2970
2971 assert first_user.confirmation_pending == true
2972 assert second_user.confirmation_pending == true
2973
2974 log_entry = Repo.one(ModerationLog)
2975
2976 assert ModerationLog.get_log_entry_message(log_entry) ==
2977 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
2978 second_user.nickname
2979 }"
2980 end
2981 end
2982
2983 describe "PATCH /resend_confirmation_email" do
2984 setup %{conn: conn} do
2985 admin = insert(:user, is_admin: true)
2986
2987 %{conn: assign(conn, :user, admin), admin: admin}
2988 end
2989
2990 test "it resend emails for two users", %{admin: admin} do
2991 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
2992
2993 build_conn()
2994 |> assign(:user, admin)
2995 |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{
2996 nicknames: [
2997 first_user.nickname,
2998 second_user.nickname
2999 ]
3000 })
3001
3002 log_entry = Repo.one(ModerationLog)
3003
3004 assert ModerationLog.get_log_entry_message(log_entry) ==
3005 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3006 second_user.nickname
3007 }"
3008 end
3009 end
3010 end
3011
3012 # Needed for testing
3013 defmodule Pleroma.Web.Endpoint.NotReal do
3014 end
3015
3016 defmodule Pleroma.Captcha.NotReal do
3017 end