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