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