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