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