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