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