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