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