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