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