556e8d97aa4b6d8f47a350e1f386b6e3d4dce72f
[akkoma] / test / web / admin_api / controllers / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 import ExUnit.CaptureLog
10 import Mock
11 import Pleroma.Factory
12
13 alias Pleroma.Activity
14 alias Pleroma.Config
15 alias Pleroma.HTML
16 alias Pleroma.MFA
17 alias Pleroma.ModerationLog
18 alias Pleroma.Repo
19 alias Pleroma.Tests.ObanHelpers
20 alias Pleroma.User
21 alias Pleroma.Web
22 alias Pleroma.Web.ActivityPub.Relay
23 alias Pleroma.Web.CommonAPI
24 alias Pleroma.Web.MediaProxy
25
26 setup_all do
27 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
28
29 :ok
30 end
31
32 setup do
33 admin = insert(:user, is_admin: true)
34 token = insert(:oauth_admin_token, user: admin)
35
36 conn =
37 build_conn()
38 |> assign(:user, admin)
39 |> assign(:token, token)
40
41 {:ok, %{admin: admin, token: token, conn: conn}}
42 end
43
44 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
45 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
46
47 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
48 %{admin: admin} do
49 user = insert(:user)
50 url = "/api/pleroma/admin/users/#{user.nickname}"
51
52 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
53 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
54 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
55
56 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
57 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
58 bad_token3 = nil
59
60 for good_token <- [good_token1, good_token2, good_token3] do
61 conn =
62 build_conn()
63 |> assign(:user, admin)
64 |> assign(:token, good_token)
65 |> get(url)
66
67 assert json_response(conn, 200)
68 end
69
70 for good_token <- [good_token1, good_token2, good_token3] do
71 conn =
72 build_conn()
73 |> assign(:user, nil)
74 |> assign(:token, good_token)
75 |> get(url)
76
77 assert json_response(conn, :forbidden)
78 end
79
80 for bad_token <- [bad_token1, bad_token2, bad_token3] do
81 conn =
82 build_conn()
83 |> assign(:user, admin)
84 |> assign(:token, bad_token)
85 |> get(url)
86
87 assert json_response(conn, :forbidden)
88 end
89 end
90 end
91
92 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
93 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
94
95 test "GET /api/pleroma/admin/users/:nickname requires " <>
96 "read:accounts or admin:read:accounts or broader scope",
97 %{admin: admin} do
98 user = insert(:user)
99 url = "/api/pleroma/admin/users/#{user.nickname}"
100
101 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
102 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
103 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
104 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
105 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
106
107 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
108
109 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
110 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
111 bad_token3 = nil
112
113 for good_token <- good_tokens do
114 conn =
115 build_conn()
116 |> assign(:user, admin)
117 |> assign(:token, good_token)
118 |> get(url)
119
120 assert json_response(conn, 200)
121 end
122
123 for good_token <- good_tokens do
124 conn =
125 build_conn()
126 |> assign(:user, nil)
127 |> assign(:token, good_token)
128 |> get(url)
129
130 assert json_response(conn, :forbidden)
131 end
132
133 for bad_token <- [bad_token1, bad_token2, bad_token3] do
134 conn =
135 build_conn()
136 |> assign(:user, admin)
137 |> assign(:token, bad_token)
138 |> get(url)
139
140 assert json_response(conn, :forbidden)
141 end
142 end
143 end
144
145 describe "DELETE /api/pleroma/admin/users" do
146 test "single user", %{admin: admin, conn: conn} do
147 user = insert(:user)
148 clear_config([:instance, :federating], true)
149
150 with_mock Pleroma.Web.Federator,
151 publish: fn _ -> nil end do
152 conn =
153 conn
154 |> put_req_header("accept", "application/json")
155 |> delete("/api/pleroma/admin/users?nickname=#{user.nickname}")
156
157 ObanHelpers.perform_all()
158
159 assert User.get_by_nickname(user.nickname).deactivated
160
161 log_entry = Repo.one(ModerationLog)
162
163 assert ModerationLog.get_log_entry_message(log_entry) ==
164 "@#{admin.nickname} deleted users: @#{user.nickname}"
165
166 assert json_response(conn, 200) == [user.nickname]
167
168 assert called(Pleroma.Web.Federator.publish(:_))
169 end
170 end
171
172 test "multiple users", %{admin: admin, conn: conn} do
173 user_one = insert(:user)
174 user_two = insert(:user)
175
176 conn =
177 conn
178 |> put_req_header("accept", "application/json")
179 |> delete("/api/pleroma/admin/users", %{
180 nicknames: [user_one.nickname, user_two.nickname]
181 })
182
183 log_entry = Repo.one(ModerationLog)
184
185 assert ModerationLog.get_log_entry_message(log_entry) ==
186 "@#{admin.nickname} deleted users: @#{user_one.nickname}, @#{user_two.nickname}"
187
188 response = json_response(conn, 200)
189 assert response -- [user_one.nickname, user_two.nickname] == []
190 end
191 end
192
193 describe "/api/pleroma/admin/users" do
194 test "Create", %{conn: conn} do
195 conn =
196 conn
197 |> put_req_header("accept", "application/json")
198 |> post("/api/pleroma/admin/users", %{
199 "users" => [
200 %{
201 "nickname" => "lain",
202 "email" => "lain@example.org",
203 "password" => "test"
204 },
205 %{
206 "nickname" => "lain2",
207 "email" => "lain2@example.org",
208 "password" => "test"
209 }
210 ]
211 })
212
213 response = json_response(conn, 200) |> Enum.map(&Map.get(&1, "type"))
214 assert response == ["success", "success"]
215
216 log_entry = Repo.one(ModerationLog)
217
218 assert ["lain", "lain2"] -- Enum.map(log_entry.data["subjects"], & &1["nickname"]) == []
219 end
220
221 test "Cannot create user with existing email", %{conn: conn} do
222 user = insert(:user)
223
224 conn =
225 conn
226 |> put_req_header("accept", "application/json")
227 |> post("/api/pleroma/admin/users", %{
228 "users" => [
229 %{
230 "nickname" => "lain",
231 "email" => user.email,
232 "password" => "test"
233 }
234 ]
235 })
236
237 assert json_response(conn, 409) == [
238 %{
239 "code" => 409,
240 "data" => %{
241 "email" => user.email,
242 "nickname" => "lain"
243 },
244 "error" => "email has already been taken",
245 "type" => "error"
246 }
247 ]
248 end
249
250 test "Cannot create user with existing nickname", %{conn: conn} do
251 user = insert(:user)
252
253 conn =
254 conn
255 |> put_req_header("accept", "application/json")
256 |> post("/api/pleroma/admin/users", %{
257 "users" => [
258 %{
259 "nickname" => user.nickname,
260 "email" => "someuser@plerama.social",
261 "password" => "test"
262 }
263 ]
264 })
265
266 assert json_response(conn, 409) == [
267 %{
268 "code" => 409,
269 "data" => %{
270 "email" => "someuser@plerama.social",
271 "nickname" => user.nickname
272 },
273 "error" => "nickname has already been taken",
274 "type" => "error"
275 }
276 ]
277 end
278
279 test "Multiple user creation works in transaction", %{conn: conn} do
280 user = insert(:user)
281
282 conn =
283 conn
284 |> put_req_header("accept", "application/json")
285 |> post("/api/pleroma/admin/users", %{
286 "users" => [
287 %{
288 "nickname" => "newuser",
289 "email" => "newuser@pleroma.social",
290 "password" => "test"
291 },
292 %{
293 "nickname" => "lain",
294 "email" => user.email,
295 "password" => "test"
296 }
297 ]
298 })
299
300 assert json_response(conn, 409) == [
301 %{
302 "code" => 409,
303 "data" => %{
304 "email" => user.email,
305 "nickname" => "lain"
306 },
307 "error" => "email has already been taken",
308 "type" => "error"
309 },
310 %{
311 "code" => 409,
312 "data" => %{
313 "email" => "newuser@pleroma.social",
314 "nickname" => "newuser"
315 },
316 "error" => "",
317 "type" => "error"
318 }
319 ]
320
321 assert User.get_by_nickname("newuser") === nil
322 end
323 end
324
325 describe "/api/pleroma/admin/users/:nickname" do
326 test "Show", %{conn: conn} do
327 user = insert(:user)
328
329 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
330
331 expected = %{
332 "deactivated" => false,
333 "id" => to_string(user.id),
334 "local" => true,
335 "nickname" => user.nickname,
336 "roles" => %{"admin" => false, "moderator" => false},
337 "tags" => [],
338 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
339 "display_name" => HTML.strip_tags(user.name || user.nickname),
340 "confirmation_pending" => false,
341 "url" => user.ap_id,
342 "registration_reason" => nil
343 }
344
345 assert expected == json_response(conn, 200)
346 end
347
348 test "when the user doesn't exist", %{conn: conn} do
349 user = build(:user)
350
351 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
352
353 assert %{"error" => "Not found"} == json_response(conn, 404)
354 end
355 end
356
357 describe "/api/pleroma/admin/users/follow" do
358 test "allows to force-follow another user", %{admin: admin, conn: conn} do
359 user = insert(:user)
360 follower = insert(:user)
361
362 conn
363 |> put_req_header("accept", "application/json")
364 |> post("/api/pleroma/admin/users/follow", %{
365 "follower" => follower.nickname,
366 "followed" => user.nickname
367 })
368
369 user = User.get_cached_by_id(user.id)
370 follower = User.get_cached_by_id(follower.id)
371
372 assert User.following?(follower, user)
373
374 log_entry = Repo.one(ModerationLog)
375
376 assert ModerationLog.get_log_entry_message(log_entry) ==
377 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
378 end
379 end
380
381 describe "/api/pleroma/admin/users/unfollow" do
382 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
383 user = insert(:user)
384 follower = insert(:user)
385
386 User.follow(follower, user)
387
388 conn
389 |> put_req_header("accept", "application/json")
390 |> post("/api/pleroma/admin/users/unfollow", %{
391 "follower" => follower.nickname,
392 "followed" => user.nickname
393 })
394
395 user = User.get_cached_by_id(user.id)
396 follower = User.get_cached_by_id(follower.id)
397
398 refute User.following?(follower, user)
399
400 log_entry = Repo.one(ModerationLog)
401
402 assert ModerationLog.get_log_entry_message(log_entry) ==
403 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
404 end
405 end
406
407 describe "PUT /api/pleroma/admin/users/tag" do
408 setup %{conn: conn} do
409 user1 = insert(:user, %{tags: ["x"]})
410 user2 = insert(:user, %{tags: ["y"]})
411 user3 = insert(:user, %{tags: ["unchanged"]})
412
413 conn =
414 conn
415 |> put_req_header("accept", "application/json")
416 |> put(
417 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
418 "#{user2.nickname}&tags[]=foo&tags[]=bar"
419 )
420
421 %{conn: conn, user1: user1, user2: user2, user3: user3}
422 end
423
424 test "it appends specified tags to users with specified nicknames", %{
425 conn: conn,
426 admin: admin,
427 user1: user1,
428 user2: user2
429 } do
430 assert json_response(conn, :no_content)
431 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
432 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
433
434 log_entry = Repo.one(ModerationLog)
435
436 users =
437 [user1.nickname, user2.nickname]
438 |> Enum.map(&"@#{&1}")
439 |> Enum.join(", ")
440
441 tags = ["foo", "bar"] |> Enum.join(", ")
442
443 assert ModerationLog.get_log_entry_message(log_entry) ==
444 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
445 end
446
447 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
448 assert json_response(conn, :no_content)
449 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
450 end
451 end
452
453 describe "DELETE /api/pleroma/admin/users/tag" do
454 setup %{conn: conn} do
455 user1 = insert(:user, %{tags: ["x"]})
456 user2 = insert(:user, %{tags: ["y", "z"]})
457 user3 = insert(:user, %{tags: ["unchanged"]})
458
459 conn =
460 conn
461 |> put_req_header("accept", "application/json")
462 |> delete(
463 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
464 "#{user2.nickname}&tags[]=x&tags[]=z"
465 )
466
467 %{conn: conn, user1: user1, user2: user2, user3: user3}
468 end
469
470 test "it removes specified tags from users with specified nicknames", %{
471 conn: conn,
472 admin: admin,
473 user1: user1,
474 user2: user2
475 } do
476 assert json_response(conn, :no_content)
477 assert User.get_cached_by_id(user1.id).tags == []
478 assert User.get_cached_by_id(user2.id).tags == ["y"]
479
480 log_entry = Repo.one(ModerationLog)
481
482 users =
483 [user1.nickname, user2.nickname]
484 |> Enum.map(&"@#{&1}")
485 |> Enum.join(", ")
486
487 tags = ["x", "z"] |> Enum.join(", ")
488
489 assert ModerationLog.get_log_entry_message(log_entry) ==
490 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
491 end
492
493 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
494 assert json_response(conn, :no_content)
495 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
496 end
497 end
498
499 describe "/api/pleroma/admin/users/:nickname/permission_group" do
500 test "GET is giving user_info", %{admin: admin, conn: conn} do
501 conn =
502 conn
503 |> put_req_header("accept", "application/json")
504 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
505
506 assert json_response(conn, 200) == %{
507 "is_admin" => true,
508 "is_moderator" => false
509 }
510 end
511
512 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
513 user = insert(:user)
514
515 conn =
516 conn
517 |> put_req_header("accept", "application/json")
518 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
519
520 assert json_response(conn, 200) == %{
521 "is_admin" => true
522 }
523
524 log_entry = Repo.one(ModerationLog)
525
526 assert ModerationLog.get_log_entry_message(log_entry) ==
527 "@#{admin.nickname} made @#{user.nickname} admin"
528 end
529
530 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
531 user_one = insert(:user)
532 user_two = insert(:user)
533
534 conn =
535 conn
536 |> put_req_header("accept", "application/json")
537 |> post("/api/pleroma/admin/users/permission_group/admin", %{
538 nicknames: [user_one.nickname, user_two.nickname]
539 })
540
541 assert json_response(conn, 200) == %{"is_admin" => true}
542
543 log_entry = Repo.one(ModerationLog)
544
545 assert ModerationLog.get_log_entry_message(log_entry) ==
546 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
547 end
548
549 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
550 user = insert(:user, is_admin: true)
551
552 conn =
553 conn
554 |> put_req_header("accept", "application/json")
555 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
556
557 assert json_response(conn, 200) == %{"is_admin" => false}
558
559 log_entry = Repo.one(ModerationLog)
560
561 assert ModerationLog.get_log_entry_message(log_entry) ==
562 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
563 end
564
565 test "/:right DELETE, can remove from a permission group (multiple)", %{
566 admin: admin,
567 conn: conn
568 } do
569 user_one = insert(:user, is_admin: true)
570 user_two = insert(:user, is_admin: true)
571
572 conn =
573 conn
574 |> put_req_header("accept", "application/json")
575 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
576 nicknames: [user_one.nickname, user_two.nickname]
577 })
578
579 assert json_response(conn, 200) == %{"is_admin" => false}
580
581 log_entry = Repo.one(ModerationLog)
582
583 assert ModerationLog.get_log_entry_message(log_entry) ==
584 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
585 user_two.nickname
586 }"
587 end
588 end
589
590 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
591 user = insert(:user)
592
593 conn =
594 conn
595 |> put_req_header("accept", "application/json")
596 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
597
598 resp = json_response(conn, 200)
599
600 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
601 end
602
603 describe "GET /api/pleroma/admin/users" do
604 test "renders users array for the first page", %{conn: conn, admin: admin} do
605 user =
606 insert(:user, local: false, tags: ["foo", "bar"], registration_reason: "I'm a chill dude")
607
608 conn = get(conn, "/api/pleroma/admin/users?page=1")
609
610 users =
611 [
612 %{
613 "deactivated" => admin.deactivated,
614 "id" => admin.id,
615 "nickname" => admin.nickname,
616 "roles" => %{"admin" => true, "moderator" => false},
617 "local" => true,
618 "tags" => [],
619 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
620 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
621 "confirmation_pending" => false,
622 "url" => admin.ap_id,
623 "registration_reason" => nil
624 },
625 %{
626 "deactivated" => user.deactivated,
627 "id" => user.id,
628 "nickname" => user.nickname,
629 "roles" => %{"admin" => false, "moderator" => false},
630 "local" => false,
631 "tags" => ["foo", "bar"],
632 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
633 "display_name" => HTML.strip_tags(user.name || user.nickname),
634 "confirmation_pending" => false,
635 "url" => user.ap_id,
636 "registration_reason" => "I'm a chill dude"
637 }
638 ]
639 |> Enum.sort_by(& &1["nickname"])
640
641 assert json_response(conn, 200) == %{
642 "count" => 2,
643 "page_size" => 50,
644 "users" => users
645 }
646 end
647
648 test "pagination works correctly with service users", %{conn: conn} do
649 service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
650
651 insert_list(25, :user)
652
653 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
654 conn
655 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
656 |> json_response(200)
657
658 assert Enum.count(users1) == 10
659 assert service1 not in users1
660
661 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
662 conn
663 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
664 |> json_response(200)
665
666 assert Enum.count(users2) == 10
667 assert service1 not in users2
668
669 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
670 conn
671 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
672 |> json_response(200)
673
674 assert Enum.count(users3) == 6
675 assert service1 not in users3
676 end
677
678 test "renders empty array for the second page", %{conn: conn} do
679 insert(:user)
680
681 conn = get(conn, "/api/pleroma/admin/users?page=2")
682
683 assert json_response(conn, 200) == %{
684 "count" => 2,
685 "page_size" => 50,
686 "users" => []
687 }
688 end
689
690 test "regular search", %{conn: conn} do
691 user = insert(:user, nickname: "bob")
692
693 conn = get(conn, "/api/pleroma/admin/users?query=bo")
694
695 assert json_response(conn, 200) == %{
696 "count" => 1,
697 "page_size" => 50,
698 "users" => [
699 %{
700 "deactivated" => user.deactivated,
701 "id" => user.id,
702 "nickname" => user.nickname,
703 "roles" => %{"admin" => false, "moderator" => false},
704 "local" => true,
705 "tags" => [],
706 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
707 "display_name" => HTML.strip_tags(user.name || user.nickname),
708 "confirmation_pending" => false,
709 "url" => user.ap_id,
710 "registration_reason" => nil
711 }
712 ]
713 }
714 end
715
716 test "search by domain", %{conn: conn} do
717 user = insert(:user, nickname: "nickname@domain.com")
718 insert(:user)
719
720 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
721
722 assert json_response(conn, 200) == %{
723 "count" => 1,
724 "page_size" => 50,
725 "users" => [
726 %{
727 "deactivated" => user.deactivated,
728 "id" => user.id,
729 "nickname" => user.nickname,
730 "roles" => %{"admin" => false, "moderator" => false},
731 "local" => true,
732 "tags" => [],
733 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
734 "display_name" => HTML.strip_tags(user.name || user.nickname),
735 "confirmation_pending" => false,
736 "url" => user.ap_id,
737 "registration_reason" => nil
738 }
739 ]
740 }
741 end
742
743 test "search by full nickname", %{conn: conn} do
744 user = insert(:user, nickname: "nickname@domain.com")
745 insert(:user)
746
747 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
748
749 assert json_response(conn, 200) == %{
750 "count" => 1,
751 "page_size" => 50,
752 "users" => [
753 %{
754 "deactivated" => user.deactivated,
755 "id" => user.id,
756 "nickname" => user.nickname,
757 "roles" => %{"admin" => false, "moderator" => false},
758 "local" => true,
759 "tags" => [],
760 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
761 "display_name" => HTML.strip_tags(user.name || user.nickname),
762 "confirmation_pending" => false,
763 "url" => user.ap_id,
764 "registration_reason" => nil
765 }
766 ]
767 }
768 end
769
770 test "search by display name", %{conn: conn} do
771 user = insert(:user, name: "Display name")
772 insert(:user)
773
774 conn = get(conn, "/api/pleroma/admin/users?name=display")
775
776 assert json_response(conn, 200) == %{
777 "count" => 1,
778 "page_size" => 50,
779 "users" => [
780 %{
781 "deactivated" => user.deactivated,
782 "id" => user.id,
783 "nickname" => user.nickname,
784 "roles" => %{"admin" => false, "moderator" => false},
785 "local" => true,
786 "tags" => [],
787 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
788 "display_name" => HTML.strip_tags(user.name || user.nickname),
789 "confirmation_pending" => false,
790 "url" => user.ap_id,
791 "registration_reason" => nil
792 }
793 ]
794 }
795 end
796
797 test "search by email", %{conn: conn} do
798 user = insert(:user, email: "email@example.com")
799 insert(:user)
800
801 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
802
803 assert json_response(conn, 200) == %{
804 "count" => 1,
805 "page_size" => 50,
806 "users" => [
807 %{
808 "deactivated" => user.deactivated,
809 "id" => user.id,
810 "nickname" => user.nickname,
811 "roles" => %{"admin" => false, "moderator" => false},
812 "local" => true,
813 "tags" => [],
814 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
815 "display_name" => HTML.strip_tags(user.name || user.nickname),
816 "confirmation_pending" => false,
817 "url" => user.ap_id,
818 "registration_reason" => nil
819 }
820 ]
821 }
822 end
823
824 test "regular search with page size", %{conn: conn} do
825 user = insert(:user, nickname: "aalice")
826 user2 = insert(:user, nickname: "alice")
827
828 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
829
830 assert json_response(conn1, 200) == %{
831 "count" => 2,
832 "page_size" => 1,
833 "users" => [
834 %{
835 "deactivated" => user.deactivated,
836 "id" => user.id,
837 "nickname" => user.nickname,
838 "roles" => %{"admin" => false, "moderator" => false},
839 "local" => true,
840 "tags" => [],
841 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
842 "display_name" => HTML.strip_tags(user.name || user.nickname),
843 "confirmation_pending" => false,
844 "url" => user.ap_id,
845 "registration_reason" => nil
846 }
847 ]
848 }
849
850 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
851
852 assert json_response(conn2, 200) == %{
853 "count" => 2,
854 "page_size" => 1,
855 "users" => [
856 %{
857 "deactivated" => user2.deactivated,
858 "id" => user2.id,
859 "nickname" => user2.nickname,
860 "roles" => %{"admin" => false, "moderator" => false},
861 "local" => true,
862 "tags" => [],
863 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
864 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
865 "confirmation_pending" => false,
866 "url" => user2.ap_id,
867 "registration_reason" => nil
868 }
869 ]
870 }
871 end
872
873 test "only local users" do
874 admin = insert(:user, is_admin: true, nickname: "john")
875 token = insert(:oauth_admin_token, user: admin)
876 user = insert(:user, nickname: "bob")
877
878 insert(:user, nickname: "bobb", local: false)
879
880 conn =
881 build_conn()
882 |> assign(:user, admin)
883 |> assign(:token, token)
884 |> get("/api/pleroma/admin/users?query=bo&filters=local")
885
886 assert json_response(conn, 200) == %{
887 "count" => 1,
888 "page_size" => 50,
889 "users" => [
890 %{
891 "deactivated" => user.deactivated,
892 "id" => user.id,
893 "nickname" => user.nickname,
894 "roles" => %{"admin" => false, "moderator" => false},
895 "local" => true,
896 "tags" => [],
897 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
898 "display_name" => HTML.strip_tags(user.name || user.nickname),
899 "confirmation_pending" => false,
900 "url" => user.ap_id,
901 "registration_reason" => nil
902 }
903 ]
904 }
905 end
906
907 test "only local users with no query", %{conn: conn, admin: old_admin} do
908 admin = insert(:user, is_admin: true, nickname: "john")
909 user = insert(:user, nickname: "bob")
910
911 insert(:user, nickname: "bobb", local: false)
912
913 conn = get(conn, "/api/pleroma/admin/users?filters=local")
914
915 users =
916 [
917 %{
918 "deactivated" => user.deactivated,
919 "id" => user.id,
920 "nickname" => user.nickname,
921 "roles" => %{"admin" => false, "moderator" => false},
922 "local" => true,
923 "tags" => [],
924 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
925 "display_name" => HTML.strip_tags(user.name || user.nickname),
926 "confirmation_pending" => false,
927 "url" => user.ap_id,
928 "registration_reason" => nil
929 },
930 %{
931 "deactivated" => admin.deactivated,
932 "id" => admin.id,
933 "nickname" => admin.nickname,
934 "roles" => %{"admin" => true, "moderator" => false},
935 "local" => true,
936 "tags" => [],
937 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
938 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
939 "confirmation_pending" => false,
940 "url" => admin.ap_id,
941 "registration_reason" => nil
942 },
943 %{
944 "deactivated" => false,
945 "id" => old_admin.id,
946 "local" => true,
947 "nickname" => old_admin.nickname,
948 "roles" => %{"admin" => true, "moderator" => false},
949 "tags" => [],
950 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
951 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
952 "confirmation_pending" => false,
953 "url" => old_admin.ap_id,
954 "registration_reason" => nil
955 }
956 ]
957 |> Enum.sort_by(& &1["nickname"])
958
959 assert json_response(conn, 200) == %{
960 "count" => 3,
961 "page_size" => 50,
962 "users" => users
963 }
964 end
965
966 test "load only admins", %{conn: conn, admin: admin} do
967 second_admin = insert(:user, is_admin: true)
968 insert(:user)
969 insert(:user)
970
971 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
972
973 users =
974 [
975 %{
976 "deactivated" => false,
977 "id" => admin.id,
978 "nickname" => admin.nickname,
979 "roles" => %{"admin" => true, "moderator" => false},
980 "local" => admin.local,
981 "tags" => [],
982 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
983 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
984 "confirmation_pending" => false,
985 "url" => admin.ap_id,
986 "registration_reason" => nil
987 },
988 %{
989 "deactivated" => false,
990 "id" => second_admin.id,
991 "nickname" => second_admin.nickname,
992 "roles" => %{"admin" => true, "moderator" => false},
993 "local" => second_admin.local,
994 "tags" => [],
995 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
996 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
997 "confirmation_pending" => false,
998 "url" => second_admin.ap_id,
999 "registration_reason" => nil
1000 }
1001 ]
1002 |> Enum.sort_by(& &1["nickname"])
1003
1004 assert json_response(conn, 200) == %{
1005 "count" => 2,
1006 "page_size" => 50,
1007 "users" => users
1008 }
1009 end
1010
1011 test "load only moderators", %{conn: conn} do
1012 moderator = insert(:user, is_moderator: true)
1013 insert(:user)
1014 insert(:user)
1015
1016 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1017
1018 assert json_response(conn, 200) == %{
1019 "count" => 1,
1020 "page_size" => 50,
1021 "users" => [
1022 %{
1023 "deactivated" => false,
1024 "id" => moderator.id,
1025 "nickname" => moderator.nickname,
1026 "roles" => %{"admin" => false, "moderator" => true},
1027 "local" => moderator.local,
1028 "tags" => [],
1029 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1030 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1031 "confirmation_pending" => false,
1032 "url" => moderator.ap_id,
1033 "registration_reason" => nil
1034 }
1035 ]
1036 }
1037 end
1038
1039 test "load users with tags list", %{conn: conn} do
1040 user1 = insert(:user, tags: ["first"])
1041 user2 = insert(:user, tags: ["second"])
1042 insert(:user)
1043 insert(:user)
1044
1045 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1046
1047 users =
1048 [
1049 %{
1050 "deactivated" => false,
1051 "id" => user1.id,
1052 "nickname" => user1.nickname,
1053 "roles" => %{"admin" => false, "moderator" => false},
1054 "local" => user1.local,
1055 "tags" => ["first"],
1056 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1057 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1058 "confirmation_pending" => false,
1059 "url" => user1.ap_id,
1060 "registration_reason" => nil
1061 },
1062 %{
1063 "deactivated" => false,
1064 "id" => user2.id,
1065 "nickname" => user2.nickname,
1066 "roles" => %{"admin" => false, "moderator" => false},
1067 "local" => user2.local,
1068 "tags" => ["second"],
1069 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1070 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1071 "confirmation_pending" => false,
1072 "url" => user2.ap_id,
1073 "registration_reason" => nil
1074 }
1075 ]
1076 |> Enum.sort_by(& &1["nickname"])
1077
1078 assert json_response(conn, 200) == %{
1079 "count" => 2,
1080 "page_size" => 50,
1081 "users" => users
1082 }
1083 end
1084
1085 test "it works with multiple filters" do
1086 admin = insert(:user, nickname: "john", is_admin: true)
1087 token = insert(:oauth_admin_token, user: admin)
1088 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1089
1090 insert(:user, nickname: "ken", local: true, deactivated: true)
1091 insert(:user, nickname: "bobb", local: false, deactivated: false)
1092
1093 conn =
1094 build_conn()
1095 |> assign(:user, admin)
1096 |> assign(:token, token)
1097 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1098
1099 assert json_response(conn, 200) == %{
1100 "count" => 1,
1101 "page_size" => 50,
1102 "users" => [
1103 %{
1104 "deactivated" => user.deactivated,
1105 "id" => user.id,
1106 "nickname" => user.nickname,
1107 "roles" => %{"admin" => false, "moderator" => false},
1108 "local" => user.local,
1109 "tags" => [],
1110 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1111 "display_name" => HTML.strip_tags(user.name || user.nickname),
1112 "confirmation_pending" => false,
1113 "url" => user.ap_id,
1114 "registration_reason" => nil
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 "url" => admin.ap_id,
1140 "registration_reason" => nil
1141 }
1142 ]
1143 }
1144 end
1145 end
1146
1147 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1148 user_one = insert(:user, deactivated: true)
1149 user_two = insert(:user, deactivated: true)
1150
1151 conn =
1152 patch(
1153 conn,
1154 "/api/pleroma/admin/users/activate",
1155 %{nicknames: [user_one.nickname, user_two.nickname]}
1156 )
1157
1158 response = json_response(conn, 200)
1159 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1160
1161 log_entry = Repo.one(ModerationLog)
1162
1163 assert ModerationLog.get_log_entry_message(log_entry) ==
1164 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1165 end
1166
1167 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1168 user_one = insert(:user, deactivated: false)
1169 user_two = insert(:user, deactivated: false)
1170
1171 conn =
1172 patch(
1173 conn,
1174 "/api/pleroma/admin/users/deactivate",
1175 %{nicknames: [user_one.nickname, user_two.nickname]}
1176 )
1177
1178 response = json_response(conn, 200)
1179 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1180
1181 log_entry = Repo.one(ModerationLog)
1182
1183 assert ModerationLog.get_log_entry_message(log_entry) ==
1184 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1185 end
1186
1187 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1188 user = insert(:user)
1189
1190 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1191
1192 assert json_response(conn, 200) ==
1193 %{
1194 "deactivated" => !user.deactivated,
1195 "id" => user.id,
1196 "nickname" => user.nickname,
1197 "roles" => %{"admin" => false, "moderator" => false},
1198 "local" => true,
1199 "tags" => [],
1200 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1201 "display_name" => HTML.strip_tags(user.name || user.nickname),
1202 "confirmation_pending" => false,
1203 "url" => user.ap_id,
1204 "registration_reason" => nil
1205 }
1206
1207 log_entry = Repo.one(ModerationLog)
1208
1209 assert ModerationLog.get_log_entry_message(log_entry) ==
1210 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1211 end
1212
1213 describe "PUT disable_mfa" do
1214 test "returns 200 and disable 2fa", %{conn: conn} do
1215 user =
1216 insert(:user,
1217 multi_factor_authentication_settings: %MFA.Settings{
1218 enabled: true,
1219 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1220 }
1221 )
1222
1223 response =
1224 conn
1225 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1226 |> json_response(200)
1227
1228 assert response == user.nickname
1229 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1230
1231 refute mfa_settings.enabled
1232 refute mfa_settings.totp.confirmed
1233 end
1234
1235 test "returns 404 if user not found", %{conn: conn} do
1236 response =
1237 conn
1238 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1239 |> json_response(404)
1240
1241 assert response == %{"error" => "Not found"}
1242 end
1243 end
1244
1245 describe "GET /api/pleroma/admin/restart" do
1246 setup do: clear_config(:configurable_from_database, true)
1247
1248 test "pleroma restarts", %{conn: conn} do
1249 capture_log(fn ->
1250 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1251 end) =~ "pleroma restarted"
1252
1253 refute Restarter.Pleroma.need_reboot?()
1254 end
1255 end
1256
1257 test "need_reboot flag", %{conn: conn} do
1258 assert conn
1259 |> get("/api/pleroma/admin/need_reboot")
1260 |> json_response(200) == %{"need_reboot" => false}
1261
1262 Restarter.Pleroma.need_reboot()
1263
1264 assert conn
1265 |> get("/api/pleroma/admin/need_reboot")
1266 |> json_response(200) == %{"need_reboot" => true}
1267
1268 on_exit(fn -> Restarter.Pleroma.refresh() end)
1269 end
1270
1271 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
1272 setup do
1273 user = insert(:user)
1274
1275 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1276 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1277 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1278
1279 insert(:note_activity, user: user, published: date1)
1280 insert(:note_activity, user: user, published: date2)
1281 insert(:note_activity, user: user, published: date3)
1282
1283 %{user: user}
1284 end
1285
1286 test "renders user's statuses", %{conn: conn, user: user} do
1287 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1288
1289 assert json_response(conn, 200) |> length() == 3
1290 end
1291
1292 test "renders user's statuses with a limit", %{conn: conn, user: user} do
1293 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
1294
1295 assert json_response(conn, 200) |> length() == 2
1296 end
1297
1298 test "doesn't return private statuses by default", %{conn: conn, user: user} do
1299 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1300
1301 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1302
1303 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1304
1305 assert json_response(conn, 200) |> length() == 4
1306 end
1307
1308 test "returns private statuses with godmode on", %{conn: conn, user: user} do
1309 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1310
1311 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1312
1313 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
1314
1315 assert json_response(conn, 200) |> length() == 5
1316 end
1317
1318 test "excludes reblogs by default", %{conn: conn, user: user} do
1319 other_user = insert(:user)
1320 {:ok, activity} = CommonAPI.post(user, %{status: "."})
1321 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
1322
1323 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
1324 assert json_response(conn_res, 200) |> length() == 0
1325
1326 conn_res =
1327 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
1328
1329 assert json_response(conn_res, 200) |> length() == 1
1330 end
1331 end
1332
1333 describe "GET /api/pleroma/admin/moderation_log" do
1334 setup do
1335 moderator = insert(:user, is_moderator: true)
1336
1337 %{moderator: moderator}
1338 end
1339
1340 test "returns the log", %{conn: conn, admin: admin} do
1341 Repo.insert(%ModerationLog{
1342 data: %{
1343 actor: %{
1344 "id" => admin.id,
1345 "nickname" => admin.nickname,
1346 "type" => "user"
1347 },
1348 action: "relay_follow",
1349 target: "https://example.org/relay"
1350 },
1351 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1352 })
1353
1354 Repo.insert(%ModerationLog{
1355 data: %{
1356 actor: %{
1357 "id" => admin.id,
1358 "nickname" => admin.nickname,
1359 "type" => "user"
1360 },
1361 action: "relay_unfollow",
1362 target: "https://example.org/relay"
1363 },
1364 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1365 })
1366
1367 conn = get(conn, "/api/pleroma/admin/moderation_log")
1368
1369 response = json_response(conn, 200)
1370 [first_entry, second_entry] = response["items"]
1371
1372 assert response["total"] == 2
1373 assert first_entry["data"]["action"] == "relay_unfollow"
1374
1375 assert first_entry["message"] ==
1376 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1377
1378 assert second_entry["data"]["action"] == "relay_follow"
1379
1380 assert second_entry["message"] ==
1381 "@#{admin.nickname} followed relay: https://example.org/relay"
1382 end
1383
1384 test "returns the log with pagination", %{conn: conn, admin: admin} do
1385 Repo.insert(%ModerationLog{
1386 data: %{
1387 actor: %{
1388 "id" => admin.id,
1389 "nickname" => admin.nickname,
1390 "type" => "user"
1391 },
1392 action: "relay_follow",
1393 target: "https://example.org/relay"
1394 },
1395 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1396 })
1397
1398 Repo.insert(%ModerationLog{
1399 data: %{
1400 actor: %{
1401 "id" => admin.id,
1402 "nickname" => admin.nickname,
1403 "type" => "user"
1404 },
1405 action: "relay_unfollow",
1406 target: "https://example.org/relay"
1407 },
1408 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1409 })
1410
1411 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1412
1413 response1 = json_response(conn1, 200)
1414 [first_entry] = response1["items"]
1415
1416 assert response1["total"] == 2
1417 assert response1["items"] |> length() == 1
1418 assert first_entry["data"]["action"] == "relay_unfollow"
1419
1420 assert first_entry["message"] ==
1421 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1422
1423 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1424
1425 response2 = json_response(conn2, 200)
1426 [second_entry] = response2["items"]
1427
1428 assert response2["total"] == 2
1429 assert response2["items"] |> length() == 1
1430 assert second_entry["data"]["action"] == "relay_follow"
1431
1432 assert second_entry["message"] ==
1433 "@#{admin.nickname} followed relay: https://example.org/relay"
1434 end
1435
1436 test "filters log by date", %{conn: conn, admin: admin} do
1437 first_date = "2017-08-15T15:47:06Z"
1438 second_date = "2017-08-20T15:47:06Z"
1439
1440 Repo.insert(%ModerationLog{
1441 data: %{
1442 actor: %{
1443 "id" => admin.id,
1444 "nickname" => admin.nickname,
1445 "type" => "user"
1446 },
1447 action: "relay_follow",
1448 target: "https://example.org/relay"
1449 },
1450 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1451 })
1452
1453 Repo.insert(%ModerationLog{
1454 data: %{
1455 actor: %{
1456 "id" => admin.id,
1457 "nickname" => admin.nickname,
1458 "type" => "user"
1459 },
1460 action: "relay_unfollow",
1461 target: "https://example.org/relay"
1462 },
1463 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1464 })
1465
1466 conn1 =
1467 get(
1468 conn,
1469 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1470 )
1471
1472 response1 = json_response(conn1, 200)
1473 [first_entry] = response1["items"]
1474
1475 assert response1["total"] == 1
1476 assert first_entry["data"]["action"] == "relay_unfollow"
1477
1478 assert first_entry["message"] ==
1479 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1480 end
1481
1482 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1483 Repo.insert(%ModerationLog{
1484 data: %{
1485 actor: %{
1486 "id" => admin.id,
1487 "nickname" => admin.nickname,
1488 "type" => "user"
1489 },
1490 action: "relay_follow",
1491 target: "https://example.org/relay"
1492 }
1493 })
1494
1495 Repo.insert(%ModerationLog{
1496 data: %{
1497 actor: %{
1498 "id" => moderator.id,
1499 "nickname" => moderator.nickname,
1500 "type" => "user"
1501 },
1502 action: "relay_unfollow",
1503 target: "https://example.org/relay"
1504 }
1505 })
1506
1507 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1508
1509 response1 = json_response(conn1, 200)
1510 [first_entry] = response1["items"]
1511
1512 assert response1["total"] == 1
1513 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1514 end
1515
1516 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1517 ModerationLog.insert_log(%{
1518 actor: moderator,
1519 action: "relay_follow",
1520 target: "https://example.org/relay"
1521 })
1522
1523 ModerationLog.insert_log(%{
1524 actor: moderator,
1525 action: "relay_unfollow",
1526 target: "https://example.org/relay"
1527 })
1528
1529 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1530
1531 response1 = json_response(conn1, 200)
1532 [first_entry] = response1["items"]
1533
1534 assert response1["total"] == 1
1535
1536 assert get_in(first_entry, ["data", "message"]) ==
1537 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1538 end
1539 end
1540
1541 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
1542 %{conn: conn} do
1543 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
1544 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
1545 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1546
1547 assert json_response(conn, 200)
1548 end
1549
1550 describe "GET /users/:nickname/credentials" do
1551 test "gets the user credentials", %{conn: conn} do
1552 user = insert(:user)
1553 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1554
1555 response = assert json_response(conn, 200)
1556 assert response["email"] == user.email
1557 end
1558
1559 test "returns 403 if requested by a non-admin" do
1560 user = insert(:user)
1561
1562 conn =
1563 build_conn()
1564 |> assign(:user, user)
1565 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
1566
1567 assert json_response(conn, :forbidden)
1568 end
1569 end
1570
1571 describe "PATCH /users/:nickname/credentials" do
1572 setup do
1573 user = insert(:user)
1574 [user: user]
1575 end
1576
1577 test "changes password and email", %{conn: conn, admin: admin, user: user} do
1578 assert user.password_reset_pending == false
1579
1580 conn =
1581 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1582 "password" => "new_password",
1583 "email" => "new_email@example.com",
1584 "name" => "new_name"
1585 })
1586
1587 assert json_response(conn, 200) == %{"status" => "success"}
1588
1589 ObanHelpers.perform_all()
1590
1591 updated_user = User.get_by_id(user.id)
1592
1593 assert updated_user.email == "new_email@example.com"
1594 assert updated_user.name == "new_name"
1595 assert updated_user.password_hash != user.password_hash
1596 assert updated_user.password_reset_pending == true
1597
1598 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
1599
1600 assert ModerationLog.get_log_entry_message(log_entry1) ==
1601 "@#{admin.nickname} updated users: @#{user.nickname}"
1602
1603 assert ModerationLog.get_log_entry_message(log_entry2) ==
1604 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
1605 end
1606
1607 test "returns 403 if requested by a non-admin", %{user: user} do
1608 conn =
1609 build_conn()
1610 |> assign(:user, user)
1611 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1612 "password" => "new_password",
1613 "email" => "new_email@example.com",
1614 "name" => "new_name"
1615 })
1616
1617 assert json_response(conn, :forbidden)
1618 end
1619
1620 test "changes actor type from permitted list", %{conn: conn, user: user} do
1621 assert user.actor_type == "Person"
1622
1623 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1624 "actor_type" => "Service"
1625 })
1626 |> json_response(200) == %{"status" => "success"}
1627
1628 updated_user = User.get_by_id(user.id)
1629
1630 assert updated_user.actor_type == "Service"
1631
1632 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1633 "actor_type" => "Application"
1634 })
1635 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
1636 end
1637
1638 test "update non existing user", %{conn: conn} do
1639 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
1640 "password" => "new_password"
1641 })
1642 |> json_response(404) == %{"error" => "Not found"}
1643 end
1644 end
1645
1646 describe "PATCH /users/:nickname/force_password_reset" do
1647 test "sets password_reset_pending to true", %{conn: conn} do
1648 user = insert(:user)
1649 assert user.password_reset_pending == false
1650
1651 conn =
1652 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
1653
1654 assert json_response(conn, 204) == ""
1655
1656 ObanHelpers.perform_all()
1657
1658 assert User.get_by_id(user.id).password_reset_pending == true
1659 end
1660 end
1661
1662 describe "instances" do
1663 test "GET /instances/:instance/statuses", %{conn: conn} do
1664 user = insert(:user, local: false, nickname: "archaeme@archae.me")
1665 user2 = insert(:user, local: false, nickname: "test@test.com")
1666 insert_pair(:note_activity, user: user)
1667 activity = insert(:note_activity, user: user2)
1668
1669 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1670
1671 response = json_response(ret_conn, 200)
1672
1673 assert length(response) == 2
1674
1675 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
1676
1677 response = json_response(ret_conn, 200)
1678
1679 assert length(response) == 1
1680
1681 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
1682
1683 response = json_response(ret_conn, 200)
1684
1685 assert Enum.empty?(response)
1686
1687 CommonAPI.repeat(activity.id, user)
1688
1689 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1690 response = json_response(ret_conn, 200)
1691 assert length(response) == 2
1692
1693 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
1694 response = json_response(ret_conn, 200)
1695 assert length(response) == 3
1696 end
1697 end
1698
1699 describe "PATCH /confirm_email" do
1700 test "it confirms emails of two users", %{conn: conn, admin: admin} do
1701 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1702
1703 assert first_user.confirmation_pending == true
1704 assert second_user.confirmation_pending == true
1705
1706 ret_conn =
1707 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
1708 nicknames: [
1709 first_user.nickname,
1710 second_user.nickname
1711 ]
1712 })
1713
1714 assert ret_conn.status == 200
1715
1716 assert first_user.confirmation_pending == true
1717 assert second_user.confirmation_pending == true
1718
1719 log_entry = Repo.one(ModerationLog)
1720
1721 assert ModerationLog.get_log_entry_message(log_entry) ==
1722 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
1723 second_user.nickname
1724 }"
1725 end
1726 end
1727
1728 describe "PATCH /resend_confirmation_email" do
1729 test "it resend emails for two users", %{conn: conn, admin: admin} do
1730 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1731
1732 ret_conn =
1733 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1734 nicknames: [
1735 first_user.nickname,
1736 second_user.nickname
1737 ]
1738 })
1739
1740 assert ret_conn.status == 200
1741
1742 log_entry = Repo.one(ModerationLog)
1743
1744 assert ModerationLog.get_log_entry_message(log_entry) ==
1745 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
1746 second_user.nickname
1747 }"
1748 end
1749 end
1750
1751 describe "/api/pleroma/admin/stats" do
1752 test "status visibility count", %{conn: conn} do
1753 admin = insert(:user, is_admin: true)
1754 user = insert(:user)
1755 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1756 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1757 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1758
1759 response =
1760 conn
1761 |> assign(:user, admin)
1762 |> get("/api/pleroma/admin/stats")
1763 |> json_response(200)
1764
1765 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1766 response["status_visibility"]
1767 end
1768
1769 test "by instance", %{conn: conn} do
1770 admin = insert(:user, is_admin: true)
1771 user1 = insert(:user)
1772 instance2 = "instance2.tld"
1773 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1774
1775 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1776 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1777 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1778
1779 response =
1780 conn
1781 |> assign(:user, admin)
1782 |> get("/api/pleroma/admin/stats", instance: instance2)
1783 |> json_response(200)
1784
1785 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1786 response["status_visibility"]
1787 end
1788 end
1789 end
1790
1791 # Needed for testing
1792 defmodule Pleroma.Web.Endpoint.NotReal do
1793 end
1794
1795 defmodule Pleroma.Captcha.NotReal do
1796 end