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