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