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