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