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