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