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