Merge branch 'fix/1658-invite-send' 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 "PUT /api/pleroma/admin/statuses/:id" do
1624 setup do
1625 activity = insert(:note_activity)
1626
1627 %{id: activity.id}
1628 end
1629
1630 test "toggle sensitive flag", %{conn: conn, id: id, admin: admin} do
1631 response =
1632 conn
1633 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "true"})
1634 |> json_response(:ok)
1635
1636 assert response["sensitive"]
1637
1638 log_entry = Repo.one(ModerationLog)
1639
1640 assert ModerationLog.get_log_entry_message(log_entry) ==
1641 "@#{admin.nickname} updated status ##{id}, set sensitive: 'true'"
1642
1643 response =
1644 conn
1645 |> put("/api/pleroma/admin/statuses/#{id}", %{"sensitive" => "false"})
1646 |> json_response(:ok)
1647
1648 refute response["sensitive"]
1649 end
1650
1651 test "change visibility flag", %{conn: conn, id: id, admin: admin} do
1652 response =
1653 conn
1654 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "public"})
1655 |> json_response(:ok)
1656
1657 assert response["visibility"] == "public"
1658
1659 log_entry = Repo.one(ModerationLog)
1660
1661 assert ModerationLog.get_log_entry_message(log_entry) ==
1662 "@#{admin.nickname} updated status ##{id}, set visibility: 'public'"
1663
1664 response =
1665 conn
1666 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "private"})
1667 |> json_response(:ok)
1668
1669 assert response["visibility"] == "private"
1670
1671 response =
1672 conn
1673 |> put("/api/pleroma/admin/statuses/#{id}", %{"visibility" => "unlisted"})
1674 |> json_response(:ok)
1675
1676 assert response["visibility"] == "unlisted"
1677 end
1678
1679 test "returns 400 when visibility is unknown", %{conn: conn, id: id} do
1680 conn = put(conn, "/api/pleroma/admin/statuses/#{id}", %{"visibility" => "test"})
1681
1682 assert json_response(conn, :bad_request) == "Unsupported visibility"
1683 end
1684 end
1685
1686 describe "DELETE /api/pleroma/admin/statuses/:id" do
1687 setup do
1688 activity = insert(:note_activity)
1689
1690 %{id: activity.id}
1691 end
1692
1693 test "deletes status", %{conn: conn, id: id, admin: admin} do
1694 conn
1695 |> delete("/api/pleroma/admin/statuses/#{id}")
1696 |> json_response(:ok)
1697
1698 refute Activity.get_by_id(id)
1699
1700 log_entry = Repo.one(ModerationLog)
1701
1702 assert ModerationLog.get_log_entry_message(log_entry) ==
1703 "@#{admin.nickname} deleted status ##{id}"
1704 end
1705
1706 test "returns 404 when the status does not exist", %{conn: conn} do
1707 conn = delete(conn, "/api/pleroma/admin/statuses/test")
1708
1709 assert json_response(conn, :not_found) == "Not found"
1710 end
1711 end
1712
1713 describe "GET /api/pleroma/admin/config" do
1714 setup do: clear_config(:configurable_from_database, true)
1715
1716 test "when configuration from database is off", %{conn: conn} do
1717 Config.put(:configurable_from_database, false)
1718 conn = get(conn, "/api/pleroma/admin/config")
1719
1720 assert json_response(conn, 400) ==
1721 "To use this endpoint you need to enable configuration from database."
1722 end
1723
1724 test "with settings only in db", %{conn: conn} do
1725 config1 = insert(:config)
1726 config2 = insert(:config)
1727
1728 conn = get(conn, "/api/pleroma/admin/config", %{"only_db" => true})
1729
1730 %{
1731 "configs" => [
1732 %{
1733 "group" => ":pleroma",
1734 "key" => key1,
1735 "value" => _
1736 },
1737 %{
1738 "group" => ":pleroma",
1739 "key" => key2,
1740 "value" => _
1741 }
1742 ]
1743 } = json_response(conn, 200)
1744
1745 assert key1 == config1.key
1746 assert key2 == config2.key
1747 end
1748
1749 test "db is added to settings that are in db", %{conn: conn} do
1750 _config = insert(:config, key: ":instance", value: ConfigDB.to_binary(name: "Some name"))
1751
1752 %{"configs" => configs} =
1753 conn
1754 |> get("/api/pleroma/admin/config")
1755 |> json_response(200)
1756
1757 [instance_config] =
1758 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1759 group == ":pleroma" and key == ":instance"
1760 end)
1761
1762 assert instance_config["db"] == [":name"]
1763 end
1764
1765 test "merged default setting with db settings", %{conn: conn} do
1766 config1 = insert(:config)
1767 config2 = insert(:config)
1768
1769 config3 =
1770 insert(:config,
1771 value: ConfigDB.to_binary(k1: :v1, k2: :v2)
1772 )
1773
1774 %{"configs" => configs} =
1775 conn
1776 |> get("/api/pleroma/admin/config")
1777 |> json_response(200)
1778
1779 assert length(configs) > 3
1780
1781 received_configs =
1782 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1783 group == ":pleroma" and key in [config1.key, config2.key, config3.key]
1784 end)
1785
1786 assert length(received_configs) == 3
1787
1788 db_keys =
1789 config3.value
1790 |> ConfigDB.from_binary()
1791 |> Keyword.keys()
1792 |> ConfigDB.convert()
1793
1794 Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
1795 assert db in [[config1.key], [config2.key], db_keys]
1796
1797 assert value in [
1798 ConfigDB.from_binary_with_convert(config1.value),
1799 ConfigDB.from_binary_with_convert(config2.value),
1800 ConfigDB.from_binary_with_convert(config3.value)
1801 ]
1802 end)
1803 end
1804
1805 test "subkeys with full update right merge", %{conn: conn} do
1806 config1 =
1807 insert(:config,
1808 key: ":emoji",
1809 value: ConfigDB.to_binary(groups: [a: 1, b: 2], key: [a: 1])
1810 )
1811
1812 config2 =
1813 insert(:config,
1814 key: ":assets",
1815 value: ConfigDB.to_binary(mascots: [a: 1, b: 2], key: [a: 1])
1816 )
1817
1818 %{"configs" => configs} =
1819 conn
1820 |> get("/api/pleroma/admin/config")
1821 |> json_response(200)
1822
1823 vals =
1824 Enum.filter(configs, fn %{"group" => group, "key" => key} ->
1825 group == ":pleroma" and key in [config1.key, config2.key]
1826 end)
1827
1828 emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
1829 assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
1830
1831 emoji_val = ConfigDB.transform_with_out_binary(emoji["value"])
1832 assets_val = ConfigDB.transform_with_out_binary(assets["value"])
1833
1834 assert emoji_val[:groups] == [a: 1, b: 2]
1835 assert assets_val[:mascots] == [a: 1, b: 2]
1836 end
1837 end
1838
1839 test "POST /api/pleroma/admin/config error", %{conn: conn} do
1840 conn = post(conn, "/api/pleroma/admin/config", %{"configs" => []})
1841
1842 assert json_response(conn, 400) ==
1843 "To use this endpoint you need to enable configuration from database."
1844 end
1845
1846 describe "POST /api/pleroma/admin/config" do
1847 setup do
1848 http = Application.get_env(:pleroma, :http)
1849
1850 on_exit(fn ->
1851 Application.delete_env(:pleroma, :key1)
1852 Application.delete_env(:pleroma, :key2)
1853 Application.delete_env(:pleroma, :key3)
1854 Application.delete_env(:pleroma, :key4)
1855 Application.delete_env(:pleroma, :keyaa1)
1856 Application.delete_env(:pleroma, :keyaa2)
1857 Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
1858 Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
1859 Application.put_env(:pleroma, :http, http)
1860 Application.put_env(:tesla, :adapter, Tesla.Mock)
1861 Restarter.Pleroma.refresh()
1862 end)
1863 end
1864
1865 setup do: clear_config(:configurable_from_database, true)
1866
1867 @tag capture_log: true
1868 test "create new config setting in db", %{conn: conn} do
1869 ueberauth = Application.get_env(:ueberauth, Ueberauth)
1870 on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
1871
1872 conn =
1873 post(conn, "/api/pleroma/admin/config", %{
1874 configs: [
1875 %{group: ":pleroma", key: ":key1", value: "value1"},
1876 %{
1877 group: ":ueberauth",
1878 key: "Ueberauth",
1879 value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
1880 },
1881 %{
1882 group: ":pleroma",
1883 key: ":key2",
1884 value: %{
1885 ":nested_1" => "nested_value1",
1886 ":nested_2" => [
1887 %{":nested_22" => "nested_value222"},
1888 %{":nested_33" => %{":nested_44" => "nested_444"}}
1889 ]
1890 }
1891 },
1892 %{
1893 group: ":pleroma",
1894 key: ":key3",
1895 value: [
1896 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1897 %{"nested_4" => true}
1898 ]
1899 },
1900 %{
1901 group: ":pleroma",
1902 key: ":key4",
1903 value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
1904 },
1905 %{
1906 group: ":idna",
1907 key: ":key5",
1908 value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
1909 }
1910 ]
1911 })
1912
1913 assert json_response(conn, 200) == %{
1914 "configs" => [
1915 %{
1916 "group" => ":pleroma",
1917 "key" => ":key1",
1918 "value" => "value1",
1919 "db" => [":key1"]
1920 },
1921 %{
1922 "group" => ":ueberauth",
1923 "key" => "Ueberauth",
1924 "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
1925 "db" => [":consumer_secret"]
1926 },
1927 %{
1928 "group" => ":pleroma",
1929 "key" => ":key2",
1930 "value" => %{
1931 ":nested_1" => "nested_value1",
1932 ":nested_2" => [
1933 %{":nested_22" => "nested_value222"},
1934 %{":nested_33" => %{":nested_44" => "nested_444"}}
1935 ]
1936 },
1937 "db" => [":key2"]
1938 },
1939 %{
1940 "group" => ":pleroma",
1941 "key" => ":key3",
1942 "value" => [
1943 %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
1944 %{"nested_4" => true}
1945 ],
1946 "db" => [":key3"]
1947 },
1948 %{
1949 "group" => ":pleroma",
1950 "key" => ":key4",
1951 "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
1952 "db" => [":key4"]
1953 },
1954 %{
1955 "group" => ":idna",
1956 "key" => ":key5",
1957 "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
1958 "db" => [":key5"]
1959 }
1960 ]
1961 }
1962
1963 assert Application.get_env(:pleroma, :key1) == "value1"
1964
1965 assert Application.get_env(:pleroma, :key2) == %{
1966 nested_1: "nested_value1",
1967 nested_2: [
1968 %{nested_22: "nested_value222"},
1969 %{nested_33: %{nested_44: "nested_444"}}
1970 ]
1971 }
1972
1973 assert Application.get_env(:pleroma, :key3) == [
1974 %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
1975 %{"nested_4" => true}
1976 ]
1977
1978 assert Application.get_env(:pleroma, :key4) == %{
1979 "endpoint" => "https://example.com",
1980 nested_5: :upload
1981 }
1982
1983 assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
1984 end
1985
1986 test "save configs setting without explicit key", %{conn: conn} do
1987 level = Application.get_env(:quack, :level)
1988 meta = Application.get_env(:quack, :meta)
1989 webhook_url = Application.get_env(:quack, :webhook_url)
1990
1991 on_exit(fn ->
1992 Application.put_env(:quack, :level, level)
1993 Application.put_env(:quack, :meta, meta)
1994 Application.put_env(:quack, :webhook_url, webhook_url)
1995 end)
1996
1997 conn =
1998 post(conn, "/api/pleroma/admin/config", %{
1999 configs: [
2000 %{
2001 group: ":quack",
2002 key: ":level",
2003 value: ":info"
2004 },
2005 %{
2006 group: ":quack",
2007 key: ":meta",
2008 value: [":none"]
2009 },
2010 %{
2011 group: ":quack",
2012 key: ":webhook_url",
2013 value: "https://hooks.slack.com/services/KEY"
2014 }
2015 ]
2016 })
2017
2018 assert json_response(conn, 200) == %{
2019 "configs" => [
2020 %{
2021 "group" => ":quack",
2022 "key" => ":level",
2023 "value" => ":info",
2024 "db" => [":level"]
2025 },
2026 %{
2027 "group" => ":quack",
2028 "key" => ":meta",
2029 "value" => [":none"],
2030 "db" => [":meta"]
2031 },
2032 %{
2033 "group" => ":quack",
2034 "key" => ":webhook_url",
2035 "value" => "https://hooks.slack.com/services/KEY",
2036 "db" => [":webhook_url"]
2037 }
2038 ]
2039 }
2040
2041 assert Application.get_env(:quack, :level) == :info
2042 assert Application.get_env(:quack, :meta) == [:none]
2043 assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
2044 end
2045
2046 test "saving config with partial update", %{conn: conn} do
2047 config = insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
2048
2049 conn =
2050 post(conn, "/api/pleroma/admin/config", %{
2051 configs: [
2052 %{group: config.group, key: config.key, value: [%{"tuple" => [":key3", 3]}]}
2053 ]
2054 })
2055
2056 assert json_response(conn, 200) == %{
2057 "configs" => [
2058 %{
2059 "group" => ":pleroma",
2060 "key" => ":key1",
2061 "value" => [
2062 %{"tuple" => [":key1", 1]},
2063 %{"tuple" => [":key2", 2]},
2064 %{"tuple" => [":key3", 3]}
2065 ],
2066 "db" => [":key1", ":key2", ":key3"]
2067 }
2068 ]
2069 }
2070 end
2071
2072 test "saving config which need pleroma reboot", %{conn: conn} do
2073 chat = Config.get(:chat)
2074 on_exit(fn -> Config.put(:chat, chat) end)
2075
2076 assert post(
2077 conn,
2078 "/api/pleroma/admin/config",
2079 %{
2080 configs: [
2081 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2082 ]
2083 }
2084 )
2085 |> json_response(200) == %{
2086 "configs" => [
2087 %{
2088 "db" => [":enabled"],
2089 "group" => ":pleroma",
2090 "key" => ":chat",
2091 "value" => [%{"tuple" => [":enabled", true]}]
2092 }
2093 ],
2094 "need_reboot" => true
2095 }
2096
2097 configs =
2098 conn
2099 |> get("/api/pleroma/admin/config")
2100 |> json_response(200)
2101
2102 assert configs["need_reboot"]
2103
2104 capture_log(fn ->
2105 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2106 end) =~ "pleroma restarted"
2107
2108 configs =
2109 conn
2110 |> get("/api/pleroma/admin/config")
2111 |> json_response(200)
2112
2113 refute Map.has_key?(configs, "need_reboot")
2114 end
2115
2116 test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
2117 chat = Config.get(:chat)
2118 on_exit(fn -> Config.put(:chat, chat) end)
2119
2120 assert post(
2121 conn,
2122 "/api/pleroma/admin/config",
2123 %{
2124 configs: [
2125 %{group: ":pleroma", key: ":chat", value: [%{"tuple" => [":enabled", true]}]}
2126 ]
2127 }
2128 )
2129 |> json_response(200) == %{
2130 "configs" => [
2131 %{
2132 "db" => [":enabled"],
2133 "group" => ":pleroma",
2134 "key" => ":chat",
2135 "value" => [%{"tuple" => [":enabled", true]}]
2136 }
2137 ],
2138 "need_reboot" => true
2139 }
2140
2141 assert post(conn, "/api/pleroma/admin/config", %{
2142 configs: [
2143 %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
2144 ]
2145 })
2146 |> json_response(200) == %{
2147 "configs" => [
2148 %{
2149 "group" => ":pleroma",
2150 "key" => ":key1",
2151 "value" => [
2152 %{"tuple" => [":key3", 3]}
2153 ],
2154 "db" => [":key3"]
2155 }
2156 ],
2157 "need_reboot" => true
2158 }
2159
2160 capture_log(fn ->
2161 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2162 end) =~ "pleroma restarted"
2163
2164 configs =
2165 conn
2166 |> get("/api/pleroma/admin/config")
2167 |> json_response(200)
2168
2169 refute Map.has_key?(configs, "need_reboot")
2170 end
2171
2172 test "saving config with nested merge", %{conn: conn} do
2173 config =
2174 insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: [k1: 1, k2: 2]))
2175
2176 conn =
2177 post(conn, "/api/pleroma/admin/config", %{
2178 configs: [
2179 %{
2180 group: config.group,
2181 key: config.key,
2182 value: [
2183 %{"tuple" => [":key3", 3]},
2184 %{
2185 "tuple" => [
2186 ":key2",
2187 [
2188 %{"tuple" => [":k2", 1]},
2189 %{"tuple" => [":k3", 3]}
2190 ]
2191 ]
2192 }
2193 ]
2194 }
2195 ]
2196 })
2197
2198 assert json_response(conn, 200) == %{
2199 "configs" => [
2200 %{
2201 "group" => ":pleroma",
2202 "key" => ":key1",
2203 "value" => [
2204 %{"tuple" => [":key1", 1]},
2205 %{"tuple" => [":key3", 3]},
2206 %{
2207 "tuple" => [
2208 ":key2",
2209 [
2210 %{"tuple" => [":k1", 1]},
2211 %{"tuple" => [":k2", 1]},
2212 %{"tuple" => [":k3", 3]}
2213 ]
2214 ]
2215 }
2216 ],
2217 "db" => [":key1", ":key3", ":key2"]
2218 }
2219 ]
2220 }
2221 end
2222
2223 test "saving special atoms", %{conn: conn} do
2224 conn =
2225 post(conn, "/api/pleroma/admin/config", %{
2226 "configs" => [
2227 %{
2228 "group" => ":pleroma",
2229 "key" => ":key1",
2230 "value" => [
2231 %{
2232 "tuple" => [
2233 ":ssl_options",
2234 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2235 ]
2236 }
2237 ]
2238 }
2239 ]
2240 })
2241
2242 assert json_response(conn, 200) == %{
2243 "configs" => [
2244 %{
2245 "group" => ":pleroma",
2246 "key" => ":key1",
2247 "value" => [
2248 %{
2249 "tuple" => [
2250 ":ssl_options",
2251 [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
2252 ]
2253 }
2254 ],
2255 "db" => [":ssl_options"]
2256 }
2257 ]
2258 }
2259
2260 assert Application.get_env(:pleroma, :key1) == [
2261 ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
2262 ]
2263 end
2264
2265 test "saving full setting if value is in full_key_update list", %{conn: conn} do
2266 backends = Application.get_env(:logger, :backends)
2267 on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
2268
2269 config =
2270 insert(:config,
2271 group: ":logger",
2272 key: ":backends",
2273 value: :erlang.term_to_binary([])
2274 )
2275
2276 conn =
2277 post(conn, "/api/pleroma/admin/config", %{
2278 configs: [
2279 %{
2280 group: config.group,
2281 key: config.key,
2282 value: [":console", %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}]
2283 }
2284 ]
2285 })
2286
2287 assert json_response(conn, 200) == %{
2288 "configs" => [
2289 %{
2290 "group" => ":logger",
2291 "key" => ":backends",
2292 "value" => [
2293 ":console",
2294 %{"tuple" => ["ExSyslogger", ":ex_syslogger"]}
2295 ],
2296 "db" => [":backends"]
2297 }
2298 ]
2299 }
2300
2301 assert Application.get_env(:logger, :backends) == [
2302 :console,
2303 {ExSyslogger, :ex_syslogger}
2304 ]
2305
2306 capture_log(fn ->
2307 require Logger
2308 Logger.warn("Ooops...")
2309 end) =~ "Ooops..."
2310 end
2311
2312 test "saving full setting if value is not keyword", %{conn: conn} do
2313 config =
2314 insert(:config,
2315 group: ":tesla",
2316 key: ":adapter",
2317 value: :erlang.term_to_binary(Tesla.Adapter.Hackey)
2318 )
2319
2320 conn =
2321 post(conn, "/api/pleroma/admin/config", %{
2322 configs: [
2323 %{group: config.group, key: config.key, value: "Tesla.Adapter.Httpc"}
2324 ]
2325 })
2326
2327 assert json_response(conn, 200) == %{
2328 "configs" => [
2329 %{
2330 "group" => ":tesla",
2331 "key" => ":adapter",
2332 "value" => "Tesla.Adapter.Httpc",
2333 "db" => [":adapter"]
2334 }
2335 ]
2336 }
2337 end
2338
2339 test "update config setting & delete with fallback to default value", %{
2340 conn: conn,
2341 admin: admin,
2342 token: token
2343 } do
2344 ueberauth = Application.get_env(:ueberauth, Ueberauth)
2345 config1 = insert(:config, key: ":keyaa1")
2346 config2 = insert(:config, key: ":keyaa2")
2347
2348 config3 =
2349 insert(:config,
2350 group: ":ueberauth",
2351 key: "Ueberauth"
2352 )
2353
2354 conn =
2355 post(conn, "/api/pleroma/admin/config", %{
2356 configs: [
2357 %{group: config1.group, key: config1.key, value: "another_value"},
2358 %{group: config2.group, key: config2.key, value: "another_value"}
2359 ]
2360 })
2361
2362 assert json_response(conn, 200) == %{
2363 "configs" => [
2364 %{
2365 "group" => ":pleroma",
2366 "key" => config1.key,
2367 "value" => "another_value",
2368 "db" => [":keyaa1"]
2369 },
2370 %{
2371 "group" => ":pleroma",
2372 "key" => config2.key,
2373 "value" => "another_value",
2374 "db" => [":keyaa2"]
2375 }
2376 ]
2377 }
2378
2379 assert Application.get_env(:pleroma, :keyaa1) == "another_value"
2380 assert Application.get_env(:pleroma, :keyaa2) == "another_value"
2381 assert Application.get_env(:ueberauth, Ueberauth) == ConfigDB.from_binary(config3.value)
2382
2383 conn =
2384 build_conn()
2385 |> assign(:user, admin)
2386 |> assign(:token, token)
2387 |> post("/api/pleroma/admin/config", %{
2388 configs: [
2389 %{group: config2.group, key: config2.key, delete: true},
2390 %{
2391 group: ":ueberauth",
2392 key: "Ueberauth",
2393 delete: true
2394 }
2395 ]
2396 })
2397
2398 assert json_response(conn, 200) == %{
2399 "configs" => []
2400 }
2401
2402 assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
2403 refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
2404 end
2405
2406 test "common config example", %{conn: conn} do
2407 conn =
2408 post(conn, "/api/pleroma/admin/config", %{
2409 configs: [
2410 %{
2411 "group" => ":pleroma",
2412 "key" => "Pleroma.Captcha.NotReal",
2413 "value" => [
2414 %{"tuple" => [":enabled", false]},
2415 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2416 %{"tuple" => [":seconds_valid", 60]},
2417 %{"tuple" => [":path", ""]},
2418 %{"tuple" => [":key1", nil]},
2419 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2420 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2421 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2422 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2423 %{"tuple" => [":name", "Pleroma"]}
2424 ]
2425 }
2426 ]
2427 })
2428
2429 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2430
2431 assert json_response(conn, 200) == %{
2432 "configs" => [
2433 %{
2434 "group" => ":pleroma",
2435 "key" => "Pleroma.Captcha.NotReal",
2436 "value" => [
2437 %{"tuple" => [":enabled", false]},
2438 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2439 %{"tuple" => [":seconds_valid", 60]},
2440 %{"tuple" => [":path", ""]},
2441 %{"tuple" => [":key1", nil]},
2442 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2443 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2444 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2445 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2446 %{"tuple" => [":name", "Pleroma"]}
2447 ],
2448 "db" => [
2449 ":enabled",
2450 ":method",
2451 ":seconds_valid",
2452 ":path",
2453 ":key1",
2454 ":regex1",
2455 ":regex2",
2456 ":regex3",
2457 ":regex4",
2458 ":name"
2459 ]
2460 }
2461 ]
2462 }
2463 end
2464
2465 test "tuples with more than two values", %{conn: conn} do
2466 conn =
2467 post(conn, "/api/pleroma/admin/config", %{
2468 configs: [
2469 %{
2470 "group" => ":pleroma",
2471 "key" => "Pleroma.Web.Endpoint.NotReal",
2472 "value" => [
2473 %{
2474 "tuple" => [
2475 ":http",
2476 [
2477 %{
2478 "tuple" => [
2479 ":key2",
2480 [
2481 %{
2482 "tuple" => [
2483 ":_",
2484 [
2485 %{
2486 "tuple" => [
2487 "/api/v1/streaming",
2488 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2489 []
2490 ]
2491 },
2492 %{
2493 "tuple" => [
2494 "/websocket",
2495 "Phoenix.Endpoint.CowboyWebSocket",
2496 %{
2497 "tuple" => [
2498 "Phoenix.Transports.WebSocket",
2499 %{
2500 "tuple" => [
2501 "Pleroma.Web.Endpoint",
2502 "Pleroma.Web.UserSocket",
2503 []
2504 ]
2505 }
2506 ]
2507 }
2508 ]
2509 },
2510 %{
2511 "tuple" => [
2512 ":_",
2513 "Phoenix.Endpoint.Cowboy2Handler",
2514 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2515 ]
2516 }
2517 ]
2518 ]
2519 }
2520 ]
2521 ]
2522 }
2523 ]
2524 ]
2525 }
2526 ]
2527 }
2528 ]
2529 })
2530
2531 assert json_response(conn, 200) == %{
2532 "configs" => [
2533 %{
2534 "group" => ":pleroma",
2535 "key" => "Pleroma.Web.Endpoint.NotReal",
2536 "value" => [
2537 %{
2538 "tuple" => [
2539 ":http",
2540 [
2541 %{
2542 "tuple" => [
2543 ":key2",
2544 [
2545 %{
2546 "tuple" => [
2547 ":_",
2548 [
2549 %{
2550 "tuple" => [
2551 "/api/v1/streaming",
2552 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2553 []
2554 ]
2555 },
2556 %{
2557 "tuple" => [
2558 "/websocket",
2559 "Phoenix.Endpoint.CowboyWebSocket",
2560 %{
2561 "tuple" => [
2562 "Phoenix.Transports.WebSocket",
2563 %{
2564 "tuple" => [
2565 "Pleroma.Web.Endpoint",
2566 "Pleroma.Web.UserSocket",
2567 []
2568 ]
2569 }
2570 ]
2571 }
2572 ]
2573 },
2574 %{
2575 "tuple" => [
2576 ":_",
2577 "Phoenix.Endpoint.Cowboy2Handler",
2578 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2579 ]
2580 }
2581 ]
2582 ]
2583 }
2584 ]
2585 ]
2586 }
2587 ]
2588 ]
2589 }
2590 ],
2591 "db" => [":http"]
2592 }
2593 ]
2594 }
2595 end
2596
2597 test "settings with nesting map", %{conn: conn} do
2598 conn =
2599 post(conn, "/api/pleroma/admin/config", %{
2600 configs: [
2601 %{
2602 "group" => ":pleroma",
2603 "key" => ":key1",
2604 "value" => [
2605 %{"tuple" => [":key2", "some_val"]},
2606 %{
2607 "tuple" => [
2608 ":key3",
2609 %{
2610 ":max_options" => 20,
2611 ":max_option_chars" => 200,
2612 ":min_expiration" => 0,
2613 ":max_expiration" => 31_536_000,
2614 "nested" => %{
2615 ":max_options" => 20,
2616 ":max_option_chars" => 200,
2617 ":min_expiration" => 0,
2618 ":max_expiration" => 31_536_000
2619 }
2620 }
2621 ]
2622 }
2623 ]
2624 }
2625 ]
2626 })
2627
2628 assert json_response(conn, 200) ==
2629 %{
2630 "configs" => [
2631 %{
2632 "group" => ":pleroma",
2633 "key" => ":key1",
2634 "value" => [
2635 %{"tuple" => [":key2", "some_val"]},
2636 %{
2637 "tuple" => [
2638 ":key3",
2639 %{
2640 ":max_expiration" => 31_536_000,
2641 ":max_option_chars" => 200,
2642 ":max_options" => 20,
2643 ":min_expiration" => 0,
2644 "nested" => %{
2645 ":max_expiration" => 31_536_000,
2646 ":max_option_chars" => 200,
2647 ":max_options" => 20,
2648 ":min_expiration" => 0
2649 }
2650 }
2651 ]
2652 }
2653 ],
2654 "db" => [":key2", ":key3"]
2655 }
2656 ]
2657 }
2658 end
2659
2660 test "value as map", %{conn: conn} do
2661 conn =
2662 post(conn, "/api/pleroma/admin/config", %{
2663 configs: [
2664 %{
2665 "group" => ":pleroma",
2666 "key" => ":key1",
2667 "value" => %{"key" => "some_val"}
2668 }
2669 ]
2670 })
2671
2672 assert json_response(conn, 200) ==
2673 %{
2674 "configs" => [
2675 %{
2676 "group" => ":pleroma",
2677 "key" => ":key1",
2678 "value" => %{"key" => "some_val"},
2679 "db" => [":key1"]
2680 }
2681 ]
2682 }
2683 end
2684
2685 test "queues key as atom", %{conn: conn} do
2686 conn =
2687 post(conn, "/api/pleroma/admin/config", %{
2688 configs: [
2689 %{
2690 "group" => ":oban",
2691 "key" => ":queues",
2692 "value" => [
2693 %{"tuple" => [":federator_incoming", 50]},
2694 %{"tuple" => [":federator_outgoing", 50]},
2695 %{"tuple" => [":web_push", 50]},
2696 %{"tuple" => [":mailer", 10]},
2697 %{"tuple" => [":transmogrifier", 20]},
2698 %{"tuple" => [":scheduled_activities", 10]},
2699 %{"tuple" => [":background", 5]}
2700 ]
2701 }
2702 ]
2703 })
2704
2705 assert json_response(conn, 200) == %{
2706 "configs" => [
2707 %{
2708 "group" => ":oban",
2709 "key" => ":queues",
2710 "value" => [
2711 %{"tuple" => [":federator_incoming", 50]},
2712 %{"tuple" => [":federator_outgoing", 50]},
2713 %{"tuple" => [":web_push", 50]},
2714 %{"tuple" => [":mailer", 10]},
2715 %{"tuple" => [":transmogrifier", 20]},
2716 %{"tuple" => [":scheduled_activities", 10]},
2717 %{"tuple" => [":background", 5]}
2718 ],
2719 "db" => [
2720 ":federator_incoming",
2721 ":federator_outgoing",
2722 ":web_push",
2723 ":mailer",
2724 ":transmogrifier",
2725 ":scheduled_activities",
2726 ":background"
2727 ]
2728 }
2729 ]
2730 }
2731 end
2732
2733 test "delete part of settings by atom subkeys", %{conn: conn} do
2734 config =
2735 insert(:config,
2736 key: ":keyaa1",
2737 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2738 )
2739
2740 conn =
2741 post(conn, "/api/pleroma/admin/config", %{
2742 configs: [
2743 %{
2744 group: config.group,
2745 key: config.key,
2746 subkeys: [":subkey1", ":subkey3"],
2747 delete: true
2748 }
2749 ]
2750 })
2751
2752 assert json_response(conn, 200) == %{
2753 "configs" => [
2754 %{
2755 "group" => ":pleroma",
2756 "key" => ":keyaa1",
2757 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2758 "db" => [":subkey2"]
2759 }
2760 ]
2761 }
2762 end
2763
2764 test "proxy tuple localhost", %{conn: conn} do
2765 conn =
2766 post(conn, "/api/pleroma/admin/config", %{
2767 configs: [
2768 %{
2769 group: ":pleroma",
2770 key: ":http",
2771 value: [
2772 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2773 %{"tuple" => [":send_user_agent", false]}
2774 ]
2775 }
2776 ]
2777 })
2778
2779 assert json_response(conn, 200) == %{
2780 "configs" => [
2781 %{
2782 "group" => ":pleroma",
2783 "key" => ":http",
2784 "value" => [
2785 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2786 %{"tuple" => [":send_user_agent", false]}
2787 ],
2788 "db" => [":proxy_url", ":send_user_agent"]
2789 }
2790 ]
2791 }
2792 end
2793
2794 test "proxy tuple domain", %{conn: conn} do
2795 conn =
2796 post(conn, "/api/pleroma/admin/config", %{
2797 configs: [
2798 %{
2799 group: ":pleroma",
2800 key: ":http",
2801 value: [
2802 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2803 %{"tuple" => [":send_user_agent", false]}
2804 ]
2805 }
2806 ]
2807 })
2808
2809 assert json_response(conn, 200) == %{
2810 "configs" => [
2811 %{
2812 "group" => ":pleroma",
2813 "key" => ":http",
2814 "value" => [
2815 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2816 %{"tuple" => [":send_user_agent", false]}
2817 ],
2818 "db" => [":proxy_url", ":send_user_agent"]
2819 }
2820 ]
2821 }
2822 end
2823
2824 test "proxy tuple ip", %{conn: conn} do
2825 conn =
2826 post(conn, "/api/pleroma/admin/config", %{
2827 configs: [
2828 %{
2829 group: ":pleroma",
2830 key: ":http",
2831 value: [
2832 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2833 %{"tuple" => [":send_user_agent", false]}
2834 ]
2835 }
2836 ]
2837 })
2838
2839 assert json_response(conn, 200) == %{
2840 "configs" => [
2841 %{
2842 "group" => ":pleroma",
2843 "key" => ":http",
2844 "value" => [
2845 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2846 %{"tuple" => [":send_user_agent", false]}
2847 ],
2848 "db" => [":proxy_url", ":send_user_agent"]
2849 }
2850 ]
2851 }
2852 end
2853 end
2854
2855 describe "GET /api/pleroma/admin/restart" do
2856 setup do: clear_config(:configurable_from_database, true)
2857
2858 test "pleroma restarts", %{conn: conn} do
2859 capture_log(fn ->
2860 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2861 end) =~ "pleroma restarted"
2862
2863 refute Restarter.Pleroma.need_reboot?()
2864 end
2865 end
2866
2867 describe "GET /api/pleroma/admin/statuses" do
2868 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2869 blocked = insert(:user)
2870 user = insert(:user)
2871 User.block(admin, blocked)
2872
2873 {:ok, _} =
2874 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2875
2876 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2877 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2878 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2879 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2880
2881 response =
2882 conn
2883 |> get("/api/pleroma/admin/statuses")
2884 |> json_response(200)
2885
2886 refute "private" in Enum.map(response, & &1["visibility"])
2887 assert length(response) == 3
2888 end
2889
2890 test "returns only local statuses with local_only on", %{conn: conn} do
2891 user = insert(:user)
2892 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2893 insert(:note_activity, user: user, local: true)
2894 insert(:note_activity, user: remote_user, local: false)
2895
2896 response =
2897 conn
2898 |> get("/api/pleroma/admin/statuses?local_only=true")
2899 |> json_response(200)
2900
2901 assert length(response) == 1
2902 end
2903
2904 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2905 user = insert(:user)
2906
2907 {:ok, _} =
2908 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2909
2910 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2911 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2912 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2913 assert json_response(conn, 200) |> length() == 3
2914 end
2915 end
2916
2917 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2918 setup do
2919 user = insert(:user)
2920
2921 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2922 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2923 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2924
2925 insert(:note_activity, user: user, published: date1)
2926 insert(:note_activity, user: user, published: date2)
2927 insert(:note_activity, user: user, published: date3)
2928
2929 %{user: user}
2930 end
2931
2932 test "renders user's statuses", %{conn: conn, user: user} do
2933 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2934
2935 assert json_response(conn, 200) |> length() == 3
2936 end
2937
2938 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2939 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2940
2941 assert json_response(conn, 200) |> length() == 2
2942 end
2943
2944 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2945 {:ok, _private_status} =
2946 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2947
2948 {:ok, _public_status} =
2949 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2950
2951 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2952
2953 assert json_response(conn, 200) |> length() == 4
2954 end
2955
2956 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2957 {:ok, _private_status} =
2958 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2959
2960 {:ok, _public_status} =
2961 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2962
2963 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2964
2965 assert json_response(conn, 200) |> length() == 5
2966 end
2967
2968 test "excludes reblogs by default", %{conn: conn, user: user} do
2969 other_user = insert(:user)
2970 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2971 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2972
2973 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2974 assert json_response(conn_res, 200) |> length() == 0
2975
2976 conn_res =
2977 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2978
2979 assert json_response(conn_res, 200) |> length() == 1
2980 end
2981 end
2982
2983 describe "GET /api/pleroma/admin/moderation_log" do
2984 setup do
2985 moderator = insert(:user, is_moderator: true)
2986
2987 %{moderator: moderator}
2988 end
2989
2990 test "returns the log", %{conn: conn, admin: admin} do
2991 Repo.insert(%ModerationLog{
2992 data: %{
2993 actor: %{
2994 "id" => admin.id,
2995 "nickname" => admin.nickname,
2996 "type" => "user"
2997 },
2998 action: "relay_follow",
2999 target: "https://example.org/relay"
3000 },
3001 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3002 })
3003
3004 Repo.insert(%ModerationLog{
3005 data: %{
3006 actor: %{
3007 "id" => admin.id,
3008 "nickname" => admin.nickname,
3009 "type" => "user"
3010 },
3011 action: "relay_unfollow",
3012 target: "https://example.org/relay"
3013 },
3014 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3015 })
3016
3017 conn = get(conn, "/api/pleroma/admin/moderation_log")
3018
3019 response = json_response(conn, 200)
3020 [first_entry, second_entry] = response["items"]
3021
3022 assert response["total"] == 2
3023 assert first_entry["data"]["action"] == "relay_unfollow"
3024
3025 assert first_entry["message"] ==
3026 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3027
3028 assert second_entry["data"]["action"] == "relay_follow"
3029
3030 assert second_entry["message"] ==
3031 "@#{admin.nickname} followed relay: https://example.org/relay"
3032 end
3033
3034 test "returns the log with pagination", %{conn: conn, admin: admin} do
3035 Repo.insert(%ModerationLog{
3036 data: %{
3037 actor: %{
3038 "id" => admin.id,
3039 "nickname" => admin.nickname,
3040 "type" => "user"
3041 },
3042 action: "relay_follow",
3043 target: "https://example.org/relay"
3044 },
3045 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3046 })
3047
3048 Repo.insert(%ModerationLog{
3049 data: %{
3050 actor: %{
3051 "id" => admin.id,
3052 "nickname" => admin.nickname,
3053 "type" => "user"
3054 },
3055 action: "relay_unfollow",
3056 target: "https://example.org/relay"
3057 },
3058 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3059 })
3060
3061 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3062
3063 response1 = json_response(conn1, 200)
3064 [first_entry] = response1["items"]
3065
3066 assert response1["total"] == 2
3067 assert response1["items"] |> length() == 1
3068 assert first_entry["data"]["action"] == "relay_unfollow"
3069
3070 assert first_entry["message"] ==
3071 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3072
3073 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3074
3075 response2 = json_response(conn2, 200)
3076 [second_entry] = response2["items"]
3077
3078 assert response2["total"] == 2
3079 assert response2["items"] |> length() == 1
3080 assert second_entry["data"]["action"] == "relay_follow"
3081
3082 assert second_entry["message"] ==
3083 "@#{admin.nickname} followed relay: https://example.org/relay"
3084 end
3085
3086 test "filters log by date", %{conn: conn, admin: admin} do
3087 first_date = "2017-08-15T15:47:06Z"
3088 second_date = "2017-08-20T15:47:06Z"
3089
3090 Repo.insert(%ModerationLog{
3091 data: %{
3092 actor: %{
3093 "id" => admin.id,
3094 "nickname" => admin.nickname,
3095 "type" => "user"
3096 },
3097 action: "relay_follow",
3098 target: "https://example.org/relay"
3099 },
3100 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3101 })
3102
3103 Repo.insert(%ModerationLog{
3104 data: %{
3105 actor: %{
3106 "id" => admin.id,
3107 "nickname" => admin.nickname,
3108 "type" => "user"
3109 },
3110 action: "relay_unfollow",
3111 target: "https://example.org/relay"
3112 },
3113 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3114 })
3115
3116 conn1 =
3117 get(
3118 conn,
3119 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3120 )
3121
3122 response1 = json_response(conn1, 200)
3123 [first_entry] = response1["items"]
3124
3125 assert response1["total"] == 1
3126 assert first_entry["data"]["action"] == "relay_unfollow"
3127
3128 assert first_entry["message"] ==
3129 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3130 end
3131
3132 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3133 Repo.insert(%ModerationLog{
3134 data: %{
3135 actor: %{
3136 "id" => admin.id,
3137 "nickname" => admin.nickname,
3138 "type" => "user"
3139 },
3140 action: "relay_follow",
3141 target: "https://example.org/relay"
3142 }
3143 })
3144
3145 Repo.insert(%ModerationLog{
3146 data: %{
3147 actor: %{
3148 "id" => moderator.id,
3149 "nickname" => moderator.nickname,
3150 "type" => "user"
3151 },
3152 action: "relay_unfollow",
3153 target: "https://example.org/relay"
3154 }
3155 })
3156
3157 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3158
3159 response1 = json_response(conn1, 200)
3160 [first_entry] = response1["items"]
3161
3162 assert response1["total"] == 1
3163 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3164 end
3165
3166 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3167 ModerationLog.insert_log(%{
3168 actor: moderator,
3169 action: "relay_follow",
3170 target: "https://example.org/relay"
3171 })
3172
3173 ModerationLog.insert_log(%{
3174 actor: moderator,
3175 action: "relay_unfollow",
3176 target: "https://example.org/relay"
3177 })
3178
3179 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3180
3181 response1 = json_response(conn1, 200)
3182 [first_entry] = response1["items"]
3183
3184 assert response1["total"] == 1
3185
3186 assert get_in(first_entry, ["data", "message"]) ==
3187 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3188 end
3189 end
3190
3191 describe "GET /users/:nickname/credentials" do
3192 test "gets the user credentials", %{conn: conn} do
3193 user = insert(:user)
3194 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3195
3196 response = assert json_response(conn, 200)
3197 assert response["email"] == user.email
3198 end
3199
3200 test "returns 403 if requested by a non-admin" do
3201 user = insert(:user)
3202
3203 conn =
3204 build_conn()
3205 |> assign(:user, user)
3206 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3207
3208 assert json_response(conn, :forbidden)
3209 end
3210 end
3211
3212 describe "PATCH /users/:nickname/credentials" do
3213 test "changes password and email", %{conn: conn, admin: admin} do
3214 user = insert(:user)
3215 assert user.password_reset_pending == false
3216
3217 conn =
3218 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3219 "password" => "new_password",
3220 "email" => "new_email@example.com",
3221 "name" => "new_name"
3222 })
3223
3224 assert json_response(conn, 200) == %{"status" => "success"}
3225
3226 ObanHelpers.perform_all()
3227
3228 updated_user = User.get_by_id(user.id)
3229
3230 assert updated_user.email == "new_email@example.com"
3231 assert updated_user.name == "new_name"
3232 assert updated_user.password_hash != user.password_hash
3233 assert updated_user.password_reset_pending == true
3234
3235 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3236
3237 assert ModerationLog.get_log_entry_message(log_entry1) ==
3238 "@#{admin.nickname} updated users: @#{user.nickname}"
3239
3240 assert ModerationLog.get_log_entry_message(log_entry2) ==
3241 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3242 end
3243
3244 test "returns 403 if requested by a non-admin" do
3245 user = insert(:user)
3246
3247 conn =
3248 build_conn()
3249 |> assign(:user, user)
3250 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3251 "password" => "new_password",
3252 "email" => "new_email@example.com",
3253 "name" => "new_name"
3254 })
3255
3256 assert json_response(conn, :forbidden)
3257 end
3258 end
3259
3260 describe "PATCH /users/:nickname/force_password_reset" do
3261 test "sets password_reset_pending to true", %{conn: conn} do
3262 user = insert(:user)
3263 assert user.password_reset_pending == false
3264
3265 conn =
3266 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3267
3268 assert json_response(conn, 204) == ""
3269
3270 ObanHelpers.perform_all()
3271
3272 assert User.get_by_id(user.id).password_reset_pending == true
3273 end
3274 end
3275
3276 describe "relays" do
3277 test "POST /relay", %{conn: conn, admin: admin} do
3278 conn =
3279 post(conn, "/api/pleroma/admin/relay", %{
3280 relay_url: "http://mastodon.example.org/users/admin"
3281 })
3282
3283 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3284
3285 log_entry = Repo.one(ModerationLog)
3286
3287 assert ModerationLog.get_log_entry_message(log_entry) ==
3288 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3289 end
3290
3291 test "GET /relay", %{conn: conn} do
3292 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3293
3294 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3295 |> Enum.each(fn ap_id ->
3296 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3297 User.follow(relay_user, user)
3298 end)
3299
3300 conn = get(conn, "/api/pleroma/admin/relay")
3301
3302 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3303 end
3304
3305 test "DELETE /relay", %{conn: conn, admin: admin} do
3306 post(conn, "/api/pleroma/admin/relay", %{
3307 relay_url: "http://mastodon.example.org/users/admin"
3308 })
3309
3310 conn =
3311 delete(conn, "/api/pleroma/admin/relay", %{
3312 relay_url: "http://mastodon.example.org/users/admin"
3313 })
3314
3315 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3316
3317 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3318
3319 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3320 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3321
3322 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3323 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3324 end
3325 end
3326
3327 describe "instances" do
3328 test "GET /instances/:instance/statuses", %{conn: conn} do
3329 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3330 user2 = insert(:user, local: false, nickname: "test@test.com")
3331 insert_pair(:note_activity, user: user)
3332 activity = insert(:note_activity, user: user2)
3333
3334 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3335
3336 response = json_response(ret_conn, 200)
3337
3338 assert length(response) == 2
3339
3340 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3341
3342 response = json_response(ret_conn, 200)
3343
3344 assert length(response) == 1
3345
3346 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3347
3348 response = json_response(ret_conn, 200)
3349
3350 assert Enum.empty?(response)
3351
3352 CommonAPI.repeat(activity.id, user)
3353
3354 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3355 response = json_response(ret_conn, 200)
3356 assert length(response) == 2
3357
3358 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3359 response = json_response(ret_conn, 200)
3360 assert length(response) == 3
3361 end
3362 end
3363
3364 describe "PATCH /confirm_email" do
3365 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3366 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3367
3368 assert first_user.confirmation_pending == true
3369 assert second_user.confirmation_pending == true
3370
3371 ret_conn =
3372 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3373 nicknames: [
3374 first_user.nickname,
3375 second_user.nickname
3376 ]
3377 })
3378
3379 assert ret_conn.status == 200
3380
3381 assert first_user.confirmation_pending == true
3382 assert second_user.confirmation_pending == true
3383
3384 log_entry = Repo.one(ModerationLog)
3385
3386 assert ModerationLog.get_log_entry_message(log_entry) ==
3387 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3388 second_user.nickname
3389 }"
3390 end
3391 end
3392
3393 describe "PATCH /resend_confirmation_email" do
3394 test "it resend emails for two users", %{conn: conn, admin: admin} do
3395 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3396
3397 ret_conn =
3398 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3399 nicknames: [
3400 first_user.nickname,
3401 second_user.nickname
3402 ]
3403 })
3404
3405 assert ret_conn.status == 200
3406
3407 log_entry = Repo.one(ModerationLog)
3408
3409 assert ModerationLog.get_log_entry_message(log_entry) ==
3410 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3411 second_user.nickname
3412 }"
3413 end
3414 end
3415
3416 describe "POST /reports/:id/notes" do
3417 setup %{conn: conn, admin: admin} do
3418 [reporter, target_user] = insert_pair(:user)
3419 activity = insert(:note_activity, user: target_user)
3420
3421 {:ok, %{id: report_id}} =
3422 CommonAPI.report(reporter, %{
3423 "account_id" => target_user.id,
3424 "comment" => "I feel offended",
3425 "status_ids" => [activity.id]
3426 })
3427
3428 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3429 content: "this is disgusting!"
3430 })
3431
3432 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3433 content: "this is disgusting2!"
3434 })
3435
3436 %{
3437 admin_id: admin.id,
3438 report_id: report_id
3439 }
3440 end
3441
3442 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3443 [note, _] = Repo.all(ReportNote)
3444
3445 assert %{
3446 activity_id: ^report_id,
3447 content: "this is disgusting!",
3448 user_id: ^admin_id
3449 } = note
3450 end
3451
3452 test "it returns reports with notes", %{conn: conn, admin: admin} do
3453 conn = get(conn, "/api/pleroma/admin/reports")
3454
3455 response = json_response(conn, 200)
3456 notes = hd(response["reports"])["notes"]
3457 [note, _] = notes
3458
3459 assert note["user"]["nickname"] == admin.nickname
3460 assert note["content"] == "this is disgusting!"
3461 assert note["created_at"]
3462 assert response["total"] == 1
3463 end
3464
3465 test "it deletes the note", %{conn: conn, report_id: report_id} do
3466 assert ReportNote |> Repo.all() |> length() == 2
3467
3468 [note, _] = Repo.all(ReportNote)
3469
3470 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3471
3472 assert ReportNote |> Repo.all() |> length() == 1
3473 end
3474 end
3475
3476 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3477 admin = insert(:user, is_admin: true)
3478
3479 conn =
3480 assign(conn, :user, admin)
3481 |> get("/api/pleroma/admin/config/descriptions")
3482
3483 assert [child | _others] = json_response(conn, 200)
3484
3485 assert child["children"]
3486 assert child["key"]
3487 assert String.starts_with?(child["group"], ":")
3488 assert child["description"]
3489 end
3490
3491 describe "/api/pleroma/admin/stats" do
3492 test "status visibility count", %{conn: conn} do
3493 admin = insert(:user, is_admin: true)
3494 user = insert(:user)
3495 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3496 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3497 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3498
3499 response =
3500 conn
3501 |> assign(:user, admin)
3502 |> get("/api/pleroma/admin/stats")
3503 |> json_response(200)
3504
3505 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3506 response["status_visibility"]
3507 end
3508 end
3509 end
3510
3511 # Needed for testing
3512 defmodule Pleroma.Web.Endpoint.NotReal do
3513 end
3514
3515 defmodule Pleroma.Captcha.NotReal do
3516 end