error improvement for email_invite endpoint
[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 set `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 set `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 adapter = Application.get_env(:tesla, :adapter)
2408 on_exit(fn -> Application.put_env(:tesla, :adapter, adapter) end)
2409
2410 conn =
2411 post(conn, "/api/pleroma/admin/config", %{
2412 configs: [
2413 %{
2414 "group" => ":pleroma",
2415 "key" => "Pleroma.Captcha.NotReal",
2416 "value" => [
2417 %{"tuple" => [":enabled", false]},
2418 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2419 %{"tuple" => [":seconds_valid", 60]},
2420 %{"tuple" => [":path", ""]},
2421 %{"tuple" => [":key1", nil]},
2422 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2423 %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
2424 %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
2425 %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
2426 %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
2427 %{"tuple" => [":name", "Pleroma"]}
2428 ]
2429 },
2430 %{
2431 "group" => ":tesla",
2432 "key" => ":adapter",
2433 "value" => "Tesla.Adapter.Httpc"
2434 }
2435 ]
2436 })
2437
2438 assert Application.get_env(:tesla, :adapter) == Tesla.Adapter.Httpc
2439 assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
2440
2441 assert json_response(conn, 200) == %{
2442 "configs" => [
2443 %{
2444 "group" => ":pleroma",
2445 "key" => "Pleroma.Captcha.NotReal",
2446 "value" => [
2447 %{"tuple" => [":enabled", false]},
2448 %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
2449 %{"tuple" => [":seconds_valid", 60]},
2450 %{"tuple" => [":path", ""]},
2451 %{"tuple" => [":key1", nil]},
2452 %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
2453 %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
2454 %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
2455 %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
2456 %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
2457 %{"tuple" => [":name", "Pleroma"]}
2458 ],
2459 "db" => [
2460 ":enabled",
2461 ":method",
2462 ":seconds_valid",
2463 ":path",
2464 ":key1",
2465 ":partial_chain",
2466 ":regex1",
2467 ":regex2",
2468 ":regex3",
2469 ":regex4",
2470 ":name"
2471 ]
2472 },
2473 %{
2474 "group" => ":tesla",
2475 "key" => ":adapter",
2476 "value" => "Tesla.Adapter.Httpc",
2477 "db" => [":adapter"]
2478 }
2479 ]
2480 }
2481 end
2482
2483 test "tuples with more than two values", %{conn: conn} do
2484 conn =
2485 post(conn, "/api/pleroma/admin/config", %{
2486 configs: [
2487 %{
2488 "group" => ":pleroma",
2489 "key" => "Pleroma.Web.Endpoint.NotReal",
2490 "value" => [
2491 %{
2492 "tuple" => [
2493 ":http",
2494 [
2495 %{
2496 "tuple" => [
2497 ":key2",
2498 [
2499 %{
2500 "tuple" => [
2501 ":_",
2502 [
2503 %{
2504 "tuple" => [
2505 "/api/v1/streaming",
2506 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2507 []
2508 ]
2509 },
2510 %{
2511 "tuple" => [
2512 "/websocket",
2513 "Phoenix.Endpoint.CowboyWebSocket",
2514 %{
2515 "tuple" => [
2516 "Phoenix.Transports.WebSocket",
2517 %{
2518 "tuple" => [
2519 "Pleroma.Web.Endpoint",
2520 "Pleroma.Web.UserSocket",
2521 []
2522 ]
2523 }
2524 ]
2525 }
2526 ]
2527 },
2528 %{
2529 "tuple" => [
2530 ":_",
2531 "Phoenix.Endpoint.Cowboy2Handler",
2532 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2533 ]
2534 }
2535 ]
2536 ]
2537 }
2538 ]
2539 ]
2540 }
2541 ]
2542 ]
2543 }
2544 ]
2545 }
2546 ]
2547 })
2548
2549 assert json_response(conn, 200) == %{
2550 "configs" => [
2551 %{
2552 "group" => ":pleroma",
2553 "key" => "Pleroma.Web.Endpoint.NotReal",
2554 "value" => [
2555 %{
2556 "tuple" => [
2557 ":http",
2558 [
2559 %{
2560 "tuple" => [
2561 ":key2",
2562 [
2563 %{
2564 "tuple" => [
2565 ":_",
2566 [
2567 %{
2568 "tuple" => [
2569 "/api/v1/streaming",
2570 "Pleroma.Web.MastodonAPI.WebsocketHandler",
2571 []
2572 ]
2573 },
2574 %{
2575 "tuple" => [
2576 "/websocket",
2577 "Phoenix.Endpoint.CowboyWebSocket",
2578 %{
2579 "tuple" => [
2580 "Phoenix.Transports.WebSocket",
2581 %{
2582 "tuple" => [
2583 "Pleroma.Web.Endpoint",
2584 "Pleroma.Web.UserSocket",
2585 []
2586 ]
2587 }
2588 ]
2589 }
2590 ]
2591 },
2592 %{
2593 "tuple" => [
2594 ":_",
2595 "Phoenix.Endpoint.Cowboy2Handler",
2596 %{"tuple" => ["Pleroma.Web.Endpoint", []]}
2597 ]
2598 }
2599 ]
2600 ]
2601 }
2602 ]
2603 ]
2604 }
2605 ]
2606 ]
2607 }
2608 ],
2609 "db" => [":http"]
2610 }
2611 ]
2612 }
2613 end
2614
2615 test "settings with nesting map", %{conn: conn} do
2616 conn =
2617 post(conn, "/api/pleroma/admin/config", %{
2618 configs: [
2619 %{
2620 "group" => ":pleroma",
2621 "key" => ":key1",
2622 "value" => [
2623 %{"tuple" => [":key2", "some_val"]},
2624 %{
2625 "tuple" => [
2626 ":key3",
2627 %{
2628 ":max_options" => 20,
2629 ":max_option_chars" => 200,
2630 ":min_expiration" => 0,
2631 ":max_expiration" => 31_536_000,
2632 "nested" => %{
2633 ":max_options" => 20,
2634 ":max_option_chars" => 200,
2635 ":min_expiration" => 0,
2636 ":max_expiration" => 31_536_000
2637 }
2638 }
2639 ]
2640 }
2641 ]
2642 }
2643 ]
2644 })
2645
2646 assert json_response(conn, 200) ==
2647 %{
2648 "configs" => [
2649 %{
2650 "group" => ":pleroma",
2651 "key" => ":key1",
2652 "value" => [
2653 %{"tuple" => [":key2", "some_val"]},
2654 %{
2655 "tuple" => [
2656 ":key3",
2657 %{
2658 ":max_expiration" => 31_536_000,
2659 ":max_option_chars" => 200,
2660 ":max_options" => 20,
2661 ":min_expiration" => 0,
2662 "nested" => %{
2663 ":max_expiration" => 31_536_000,
2664 ":max_option_chars" => 200,
2665 ":max_options" => 20,
2666 ":min_expiration" => 0
2667 }
2668 }
2669 ]
2670 }
2671 ],
2672 "db" => [":key2", ":key3"]
2673 }
2674 ]
2675 }
2676 end
2677
2678 test "value as map", %{conn: conn} do
2679 conn =
2680 post(conn, "/api/pleroma/admin/config", %{
2681 configs: [
2682 %{
2683 "group" => ":pleroma",
2684 "key" => ":key1",
2685 "value" => %{"key" => "some_val"}
2686 }
2687 ]
2688 })
2689
2690 assert json_response(conn, 200) ==
2691 %{
2692 "configs" => [
2693 %{
2694 "group" => ":pleroma",
2695 "key" => ":key1",
2696 "value" => %{"key" => "some_val"},
2697 "db" => [":key1"]
2698 }
2699 ]
2700 }
2701 end
2702
2703 test "queues key as atom", %{conn: conn} do
2704 conn =
2705 post(conn, "/api/pleroma/admin/config", %{
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 }
2720 ]
2721 })
2722
2723 assert json_response(conn, 200) == %{
2724 "configs" => [
2725 %{
2726 "group" => ":oban",
2727 "key" => ":queues",
2728 "value" => [
2729 %{"tuple" => [":federator_incoming", 50]},
2730 %{"tuple" => [":federator_outgoing", 50]},
2731 %{"tuple" => [":web_push", 50]},
2732 %{"tuple" => [":mailer", 10]},
2733 %{"tuple" => [":transmogrifier", 20]},
2734 %{"tuple" => [":scheduled_activities", 10]},
2735 %{"tuple" => [":background", 5]}
2736 ],
2737 "db" => [
2738 ":federator_incoming",
2739 ":federator_outgoing",
2740 ":web_push",
2741 ":mailer",
2742 ":transmogrifier",
2743 ":scheduled_activities",
2744 ":background"
2745 ]
2746 }
2747 ]
2748 }
2749 end
2750
2751 test "delete part of settings by atom subkeys", %{conn: conn} do
2752 config =
2753 insert(:config,
2754 key: ":keyaa1",
2755 value: :erlang.term_to_binary(subkey1: "val1", subkey2: "val2", subkey3: "val3")
2756 )
2757
2758 conn =
2759 post(conn, "/api/pleroma/admin/config", %{
2760 configs: [
2761 %{
2762 group: config.group,
2763 key: config.key,
2764 subkeys: [":subkey1", ":subkey3"],
2765 delete: true
2766 }
2767 ]
2768 })
2769
2770 assert json_response(conn, 200) == %{
2771 "configs" => [
2772 %{
2773 "group" => ":pleroma",
2774 "key" => ":keyaa1",
2775 "value" => [%{"tuple" => [":subkey2", "val2"]}],
2776 "db" => [":subkey2"]
2777 }
2778 ]
2779 }
2780 end
2781
2782 test "proxy tuple localhost", %{conn: conn} do
2783 conn =
2784 post(conn, "/api/pleroma/admin/config", %{
2785 configs: [
2786 %{
2787 group: ":pleroma",
2788 key: ":http",
2789 value: [
2790 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2791 %{"tuple" => [":send_user_agent", false]}
2792 ]
2793 }
2794 ]
2795 })
2796
2797 assert json_response(conn, 200) == %{
2798 "configs" => [
2799 %{
2800 "group" => ":pleroma",
2801 "key" => ":http",
2802 "value" => [
2803 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]},
2804 %{"tuple" => [":send_user_agent", false]}
2805 ],
2806 "db" => [":proxy_url", ":send_user_agent"]
2807 }
2808 ]
2809 }
2810 end
2811
2812 test "proxy tuple domain", %{conn: conn} do
2813 conn =
2814 post(conn, "/api/pleroma/admin/config", %{
2815 configs: [
2816 %{
2817 group: ":pleroma",
2818 key: ":http",
2819 value: [
2820 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2821 %{"tuple" => [":send_user_agent", false]}
2822 ]
2823 }
2824 ]
2825 })
2826
2827 assert json_response(conn, 200) == %{
2828 "configs" => [
2829 %{
2830 "group" => ":pleroma",
2831 "key" => ":http",
2832 "value" => [
2833 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]},
2834 %{"tuple" => [":send_user_agent", false]}
2835 ],
2836 "db" => [":proxy_url", ":send_user_agent"]
2837 }
2838 ]
2839 }
2840 end
2841
2842 test "proxy tuple ip", %{conn: conn} do
2843 conn =
2844 post(conn, "/api/pleroma/admin/config", %{
2845 configs: [
2846 %{
2847 group: ":pleroma",
2848 key: ":http",
2849 value: [
2850 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2851 %{"tuple" => [":send_user_agent", false]}
2852 ]
2853 }
2854 ]
2855 })
2856
2857 assert json_response(conn, 200) == %{
2858 "configs" => [
2859 %{
2860 "group" => ":pleroma",
2861 "key" => ":http",
2862 "value" => [
2863 %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]},
2864 %{"tuple" => [":send_user_agent", false]}
2865 ],
2866 "db" => [":proxy_url", ":send_user_agent"]
2867 }
2868 ]
2869 }
2870 end
2871 end
2872
2873 describe "GET /api/pleroma/admin/restart" do
2874 setup do: clear_config(:configurable_from_database, true)
2875
2876 test "pleroma restarts", %{conn: conn} do
2877 capture_log(fn ->
2878 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
2879 end) =~ "pleroma restarted"
2880
2881 refute Restarter.Pleroma.need_reboot?()
2882 end
2883 end
2884
2885 describe "GET /api/pleroma/admin/statuses" do
2886 test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do
2887 blocked = insert(:user)
2888 user = insert(:user)
2889 User.block(admin, blocked)
2890
2891 {:ok, _} =
2892 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2893
2894 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
2895 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2896 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2897 {:ok, _} = CommonAPI.post(blocked, %{"status" => ".", "visibility" => "public"})
2898
2899 response =
2900 conn
2901 |> get("/api/pleroma/admin/statuses")
2902 |> json_response(200)
2903
2904 refute "private" in Enum.map(response, & &1["visibility"])
2905 assert length(response) == 3
2906 end
2907
2908 test "returns only local statuses with local_only on", %{conn: conn} do
2909 user = insert(:user)
2910 remote_user = insert(:user, local: false, nickname: "archaeme@archae.me")
2911 insert(:note_activity, user: user, local: true)
2912 insert(:note_activity, user: remote_user, local: false)
2913
2914 response =
2915 conn
2916 |> get("/api/pleroma/admin/statuses?local_only=true")
2917 |> json_response(200)
2918
2919 assert length(response) == 1
2920 end
2921
2922 test "returns private and direct statuses with godmode on", %{conn: conn, admin: admin} do
2923 user = insert(:user)
2924
2925 {:ok, _} =
2926 CommonAPI.post(user, %{"status" => "@#{admin.nickname}", "visibility" => "direct"})
2927
2928 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
2929 {:ok, _} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
2930 conn = get(conn, "/api/pleroma/admin/statuses?godmode=true")
2931 assert json_response(conn, 200) |> length() == 3
2932 end
2933 end
2934
2935 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
2936 setup do
2937 user = insert(:user)
2938
2939 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
2940 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
2941 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
2942
2943 insert(:note_activity, user: user, published: date1)
2944 insert(:note_activity, user: user, published: date2)
2945 insert(:note_activity, user: user, published: date3)
2946
2947 %{user: user}
2948 end
2949
2950 test "renders user's statuses", %{conn: conn, user: user} do
2951 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2952
2953 assert json_response(conn, 200) |> length() == 3
2954 end
2955
2956 test "renders user's statuses with a limit", %{conn: conn, user: user} do
2957 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
2958
2959 assert json_response(conn, 200) |> length() == 2
2960 end
2961
2962 test "doesn't return private statuses by default", %{conn: conn, user: user} do
2963 {:ok, _private_status} =
2964 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2965
2966 {:ok, _public_status} =
2967 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2968
2969 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
2970
2971 assert json_response(conn, 200) |> length() == 4
2972 end
2973
2974 test "returns private statuses with godmode on", %{conn: conn, user: user} do
2975 {:ok, _private_status} =
2976 CommonAPI.post(user, %{"status" => "private", "visibility" => "private"})
2977
2978 {:ok, _public_status} =
2979 CommonAPI.post(user, %{"status" => "public", "visibility" => "public"})
2980
2981 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
2982
2983 assert json_response(conn, 200) |> length() == 5
2984 end
2985
2986 test "excludes reblogs by default", %{conn: conn, user: user} do
2987 other_user = insert(:user)
2988 {:ok, activity} = CommonAPI.post(user, %{"status" => "."})
2989 {:ok, %Activity{}, _} = CommonAPI.repeat(activity.id, other_user)
2990
2991 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
2992 assert json_response(conn_res, 200) |> length() == 0
2993
2994 conn_res =
2995 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
2996
2997 assert json_response(conn_res, 200) |> length() == 1
2998 end
2999 end
3000
3001 describe "GET /api/pleroma/admin/moderation_log" do
3002 setup do
3003 moderator = insert(:user, is_moderator: true)
3004
3005 %{moderator: moderator}
3006 end
3007
3008 test "returns the log", %{conn: conn, admin: admin} do
3009 Repo.insert(%ModerationLog{
3010 data: %{
3011 actor: %{
3012 "id" => admin.id,
3013 "nickname" => admin.nickname,
3014 "type" => "user"
3015 },
3016 action: "relay_follow",
3017 target: "https://example.org/relay"
3018 },
3019 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3020 })
3021
3022 Repo.insert(%ModerationLog{
3023 data: %{
3024 actor: %{
3025 "id" => admin.id,
3026 "nickname" => admin.nickname,
3027 "type" => "user"
3028 },
3029 action: "relay_unfollow",
3030 target: "https://example.org/relay"
3031 },
3032 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3033 })
3034
3035 conn = get(conn, "/api/pleroma/admin/moderation_log")
3036
3037 response = json_response(conn, 200)
3038 [first_entry, second_entry] = response["items"]
3039
3040 assert response["total"] == 2
3041 assert first_entry["data"]["action"] == "relay_unfollow"
3042
3043 assert first_entry["message"] ==
3044 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3045
3046 assert second_entry["data"]["action"] == "relay_follow"
3047
3048 assert second_entry["message"] ==
3049 "@#{admin.nickname} followed relay: https://example.org/relay"
3050 end
3051
3052 test "returns the log with pagination", %{conn: conn, admin: admin} do
3053 Repo.insert(%ModerationLog{
3054 data: %{
3055 actor: %{
3056 "id" => admin.id,
3057 "nickname" => admin.nickname,
3058 "type" => "user"
3059 },
3060 action: "relay_follow",
3061 target: "https://example.org/relay"
3062 },
3063 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
3064 })
3065
3066 Repo.insert(%ModerationLog{
3067 data: %{
3068 actor: %{
3069 "id" => admin.id,
3070 "nickname" => admin.nickname,
3071 "type" => "user"
3072 },
3073 action: "relay_unfollow",
3074 target: "https://example.org/relay"
3075 },
3076 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
3077 })
3078
3079 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
3080
3081 response1 = json_response(conn1, 200)
3082 [first_entry] = response1["items"]
3083
3084 assert response1["total"] == 2
3085 assert response1["items"] |> length() == 1
3086 assert first_entry["data"]["action"] == "relay_unfollow"
3087
3088 assert first_entry["message"] ==
3089 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3090
3091 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
3092
3093 response2 = json_response(conn2, 200)
3094 [second_entry] = response2["items"]
3095
3096 assert response2["total"] == 2
3097 assert response2["items"] |> length() == 1
3098 assert second_entry["data"]["action"] == "relay_follow"
3099
3100 assert second_entry["message"] ==
3101 "@#{admin.nickname} followed relay: https://example.org/relay"
3102 end
3103
3104 test "filters log by date", %{conn: conn, admin: admin} do
3105 first_date = "2017-08-15T15:47:06Z"
3106 second_date = "2017-08-20T15:47:06Z"
3107
3108 Repo.insert(%ModerationLog{
3109 data: %{
3110 actor: %{
3111 "id" => admin.id,
3112 "nickname" => admin.nickname,
3113 "type" => "user"
3114 },
3115 action: "relay_follow",
3116 target: "https://example.org/relay"
3117 },
3118 inserted_at: NaiveDateTime.from_iso8601!(first_date)
3119 })
3120
3121 Repo.insert(%ModerationLog{
3122 data: %{
3123 actor: %{
3124 "id" => admin.id,
3125 "nickname" => admin.nickname,
3126 "type" => "user"
3127 },
3128 action: "relay_unfollow",
3129 target: "https://example.org/relay"
3130 },
3131 inserted_at: NaiveDateTime.from_iso8601!(second_date)
3132 })
3133
3134 conn1 =
3135 get(
3136 conn,
3137 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
3138 )
3139
3140 response1 = json_response(conn1, 200)
3141 [first_entry] = response1["items"]
3142
3143 assert response1["total"] == 1
3144 assert first_entry["data"]["action"] == "relay_unfollow"
3145
3146 assert first_entry["message"] ==
3147 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
3148 end
3149
3150 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
3151 Repo.insert(%ModerationLog{
3152 data: %{
3153 actor: %{
3154 "id" => admin.id,
3155 "nickname" => admin.nickname,
3156 "type" => "user"
3157 },
3158 action: "relay_follow",
3159 target: "https://example.org/relay"
3160 }
3161 })
3162
3163 Repo.insert(%ModerationLog{
3164 data: %{
3165 actor: %{
3166 "id" => moderator.id,
3167 "nickname" => moderator.nickname,
3168 "type" => "user"
3169 },
3170 action: "relay_unfollow",
3171 target: "https://example.org/relay"
3172 }
3173 })
3174
3175 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
3176
3177 response1 = json_response(conn1, 200)
3178 [first_entry] = response1["items"]
3179
3180 assert response1["total"] == 1
3181 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
3182 end
3183
3184 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
3185 ModerationLog.insert_log(%{
3186 actor: moderator,
3187 action: "relay_follow",
3188 target: "https://example.org/relay"
3189 })
3190
3191 ModerationLog.insert_log(%{
3192 actor: moderator,
3193 action: "relay_unfollow",
3194 target: "https://example.org/relay"
3195 })
3196
3197 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
3198
3199 response1 = json_response(conn1, 200)
3200 [first_entry] = response1["items"]
3201
3202 assert response1["total"] == 1
3203
3204 assert get_in(first_entry, ["data", "message"]) ==
3205 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
3206 end
3207 end
3208
3209 describe "GET /users/:nickname/credentials" do
3210 test "gets the user credentials", %{conn: conn} do
3211 user = insert(:user)
3212 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
3213
3214 response = assert json_response(conn, 200)
3215 assert response["email"] == user.email
3216 end
3217
3218 test "returns 403 if requested by a non-admin" do
3219 user = insert(:user)
3220
3221 conn =
3222 build_conn()
3223 |> assign(:user, user)
3224 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
3225
3226 assert json_response(conn, :forbidden)
3227 end
3228 end
3229
3230 describe "PATCH /users/:nickname/credentials" do
3231 test "changes password and email", %{conn: conn, admin: admin} do
3232 user = insert(:user)
3233 assert user.password_reset_pending == false
3234
3235 conn =
3236 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3237 "password" => "new_password",
3238 "email" => "new_email@example.com",
3239 "name" => "new_name"
3240 })
3241
3242 assert json_response(conn, 200) == %{"status" => "success"}
3243
3244 ObanHelpers.perform_all()
3245
3246 updated_user = User.get_by_id(user.id)
3247
3248 assert updated_user.email == "new_email@example.com"
3249 assert updated_user.name == "new_name"
3250 assert updated_user.password_hash != user.password_hash
3251 assert updated_user.password_reset_pending == true
3252
3253 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
3254
3255 assert ModerationLog.get_log_entry_message(log_entry1) ==
3256 "@#{admin.nickname} updated users: @#{user.nickname}"
3257
3258 assert ModerationLog.get_log_entry_message(log_entry2) ==
3259 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
3260 end
3261
3262 test "returns 403 if requested by a non-admin" do
3263 user = insert(:user)
3264
3265 conn =
3266 build_conn()
3267 |> assign(:user, user)
3268 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
3269 "password" => "new_password",
3270 "email" => "new_email@example.com",
3271 "name" => "new_name"
3272 })
3273
3274 assert json_response(conn, :forbidden)
3275 end
3276 end
3277
3278 describe "PATCH /users/:nickname/force_password_reset" do
3279 test "sets password_reset_pending to true", %{conn: conn} do
3280 user = insert(:user)
3281 assert user.password_reset_pending == false
3282
3283 conn =
3284 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
3285
3286 assert json_response(conn, 204) == ""
3287
3288 ObanHelpers.perform_all()
3289
3290 assert User.get_by_id(user.id).password_reset_pending == true
3291 end
3292 end
3293
3294 describe "relays" do
3295 test "POST /relay", %{conn: conn, admin: admin} do
3296 conn =
3297 post(conn, "/api/pleroma/admin/relay", %{
3298 relay_url: "http://mastodon.example.org/users/admin"
3299 })
3300
3301 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3302
3303 log_entry = Repo.one(ModerationLog)
3304
3305 assert ModerationLog.get_log_entry_message(log_entry) ==
3306 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3307 end
3308
3309 test "GET /relay", %{conn: conn} do
3310 relay_user = Pleroma.Web.ActivityPub.Relay.get_actor()
3311
3312 ["http://mastodon.example.org/users/admin", "https://mstdn.io/users/mayuutann"]
3313 |> Enum.each(fn ap_id ->
3314 {:ok, user} = User.get_or_fetch_by_ap_id(ap_id)
3315 User.follow(relay_user, user)
3316 end)
3317
3318 conn = get(conn, "/api/pleroma/admin/relay")
3319
3320 assert json_response(conn, 200)["relays"] -- ["mastodon.example.org", "mstdn.io"] == []
3321 end
3322
3323 test "DELETE /relay", %{conn: conn, admin: admin} do
3324 post(conn, "/api/pleroma/admin/relay", %{
3325 relay_url: "http://mastodon.example.org/users/admin"
3326 })
3327
3328 conn =
3329 delete(conn, "/api/pleroma/admin/relay", %{
3330 relay_url: "http://mastodon.example.org/users/admin"
3331 })
3332
3333 assert json_response(conn, 200) == "http://mastodon.example.org/users/admin"
3334
3335 [log_entry_one, log_entry_two] = Repo.all(ModerationLog)
3336
3337 assert ModerationLog.get_log_entry_message(log_entry_one) ==
3338 "@#{admin.nickname} followed relay: http://mastodon.example.org/users/admin"
3339
3340 assert ModerationLog.get_log_entry_message(log_entry_two) ==
3341 "@#{admin.nickname} unfollowed relay: http://mastodon.example.org/users/admin"
3342 end
3343 end
3344
3345 describe "instances" do
3346 test "GET /instances/:instance/statuses", %{conn: conn} do
3347 user = insert(:user, local: false, nickname: "archaeme@archae.me")
3348 user2 = insert(:user, local: false, nickname: "test@test.com")
3349 insert_pair(:note_activity, user: user)
3350 activity = insert(:note_activity, user: user2)
3351
3352 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3353
3354 response = json_response(ret_conn, 200)
3355
3356 assert length(response) == 2
3357
3358 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
3359
3360 response = json_response(ret_conn, 200)
3361
3362 assert length(response) == 1
3363
3364 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
3365
3366 response = json_response(ret_conn, 200)
3367
3368 assert Enum.empty?(response)
3369
3370 CommonAPI.repeat(activity.id, user)
3371
3372 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
3373 response = json_response(ret_conn, 200)
3374 assert length(response) == 2
3375
3376 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
3377 response = json_response(ret_conn, 200)
3378 assert length(response) == 3
3379 end
3380 end
3381
3382 describe "PATCH /confirm_email" do
3383 test "it confirms emails of two users", %{conn: conn, admin: admin} do
3384 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3385
3386 assert first_user.confirmation_pending == true
3387 assert second_user.confirmation_pending == true
3388
3389 ret_conn =
3390 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
3391 nicknames: [
3392 first_user.nickname,
3393 second_user.nickname
3394 ]
3395 })
3396
3397 assert ret_conn.status == 200
3398
3399 assert first_user.confirmation_pending == true
3400 assert second_user.confirmation_pending == true
3401
3402 log_entry = Repo.one(ModerationLog)
3403
3404 assert ModerationLog.get_log_entry_message(log_entry) ==
3405 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
3406 second_user.nickname
3407 }"
3408 end
3409 end
3410
3411 describe "PATCH /resend_confirmation_email" do
3412 test "it resend emails for two users", %{conn: conn, admin: admin} do
3413 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
3414
3415 ret_conn =
3416 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
3417 nicknames: [
3418 first_user.nickname,
3419 second_user.nickname
3420 ]
3421 })
3422
3423 assert ret_conn.status == 200
3424
3425 log_entry = Repo.one(ModerationLog)
3426
3427 assert ModerationLog.get_log_entry_message(log_entry) ==
3428 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
3429 second_user.nickname
3430 }"
3431 end
3432 end
3433
3434 describe "POST /reports/:id/notes" do
3435 setup %{conn: conn, admin: admin} do
3436 [reporter, target_user] = insert_pair(:user)
3437 activity = insert(:note_activity, user: target_user)
3438
3439 {:ok, %{id: report_id}} =
3440 CommonAPI.report(reporter, %{
3441 "account_id" => target_user.id,
3442 "comment" => "I feel offended",
3443 "status_ids" => [activity.id]
3444 })
3445
3446 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3447 content: "this is disgusting!"
3448 })
3449
3450 post(conn, "/api/pleroma/admin/reports/#{report_id}/notes", %{
3451 content: "this is disgusting2!"
3452 })
3453
3454 %{
3455 admin_id: admin.id,
3456 report_id: report_id
3457 }
3458 end
3459
3460 test "it creates report note", %{admin_id: admin_id, report_id: report_id} do
3461 [note, _] = Repo.all(ReportNote)
3462
3463 assert %{
3464 activity_id: ^report_id,
3465 content: "this is disgusting!",
3466 user_id: ^admin_id
3467 } = note
3468 end
3469
3470 test "it returns reports with notes", %{conn: conn, admin: admin} do
3471 conn = get(conn, "/api/pleroma/admin/reports")
3472
3473 response = json_response(conn, 200)
3474 notes = hd(response["reports"])["notes"]
3475 [note, _] = notes
3476
3477 assert note["user"]["nickname"] == admin.nickname
3478 assert note["content"] == "this is disgusting!"
3479 assert note["created_at"]
3480 assert response["total"] == 1
3481 end
3482
3483 test "it deletes the note", %{conn: conn, report_id: report_id} do
3484 assert ReportNote |> Repo.all() |> length() == 2
3485
3486 [note, _] = Repo.all(ReportNote)
3487
3488 delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/#{note.id}")
3489
3490 assert ReportNote |> Repo.all() |> length() == 1
3491 end
3492 end
3493
3494 test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
3495 admin = insert(:user, is_admin: true)
3496
3497 conn =
3498 assign(conn, :user, admin)
3499 |> get("/api/pleroma/admin/config/descriptions")
3500
3501 assert [child | _others] = json_response(conn, 200)
3502
3503 assert child["children"]
3504 assert child["key"]
3505 assert String.starts_with?(child["group"], ":")
3506 assert child["description"]
3507 end
3508
3509 describe "/api/pleroma/admin/stats" do
3510 test "status visibility count", %{conn: conn} do
3511 admin = insert(:user, is_admin: true)
3512 user = insert(:user)
3513 CommonAPI.post(user, %{"visibility" => "public", "status" => "hey"})
3514 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3515 CommonAPI.post(user, %{"visibility" => "unlisted", "status" => "hey"})
3516
3517 response =
3518 conn
3519 |> assign(:user, admin)
3520 |> get("/api/pleroma/admin/stats")
3521 |> json_response(200)
3522
3523 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
3524 response["status_visibility"]
3525 end
3526 end
3527 end
3528
3529 # Needed for testing
3530 defmodule Pleroma.Web.Endpoint.NotReal do
3531 end
3532
3533 defmodule Pleroma.Captcha.NotReal do
3534 end