Merge 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
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 }
343
344 assert expected == json_response(conn, 200)
345 end
346
347 test "when the user doesn't exist", %{conn: conn} do
348 user = build(:user)
349
350 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}")
351
352 assert %{"error" => "Not found"} == json_response(conn, 404)
353 end
354 end
355
356 describe "/api/pleroma/admin/users/follow" do
357 test "allows to force-follow another user", %{admin: admin, conn: conn} do
358 user = insert(:user)
359 follower = insert(:user)
360
361 conn
362 |> put_req_header("accept", "application/json")
363 |> post("/api/pleroma/admin/users/follow", %{
364 "follower" => follower.nickname,
365 "followed" => user.nickname
366 })
367
368 user = User.get_cached_by_id(user.id)
369 follower = User.get_cached_by_id(follower.id)
370
371 assert User.following?(follower, user)
372
373 log_entry = Repo.one(ModerationLog)
374
375 assert ModerationLog.get_log_entry_message(log_entry) ==
376 "@#{admin.nickname} made @#{follower.nickname} follow @#{user.nickname}"
377 end
378 end
379
380 describe "/api/pleroma/admin/users/unfollow" do
381 test "allows to force-unfollow another user", %{admin: admin, conn: conn} do
382 user = insert(:user)
383 follower = insert(:user)
384
385 User.follow(follower, user)
386
387 conn
388 |> put_req_header("accept", "application/json")
389 |> post("/api/pleroma/admin/users/unfollow", %{
390 "follower" => follower.nickname,
391 "followed" => user.nickname
392 })
393
394 user = User.get_cached_by_id(user.id)
395 follower = User.get_cached_by_id(follower.id)
396
397 refute User.following?(follower, user)
398
399 log_entry = Repo.one(ModerationLog)
400
401 assert ModerationLog.get_log_entry_message(log_entry) ==
402 "@#{admin.nickname} made @#{follower.nickname} unfollow @#{user.nickname}"
403 end
404 end
405
406 describe "PUT /api/pleroma/admin/users/tag" do
407 setup %{conn: conn} do
408 user1 = insert(:user, %{tags: ["x"]})
409 user2 = insert(:user, %{tags: ["y"]})
410 user3 = insert(:user, %{tags: ["unchanged"]})
411
412 conn =
413 conn
414 |> put_req_header("accept", "application/json")
415 |> put(
416 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
417 "#{user2.nickname}&tags[]=foo&tags[]=bar"
418 )
419
420 %{conn: conn, user1: user1, user2: user2, user3: user3}
421 end
422
423 test "it appends specified tags to users with specified nicknames", %{
424 conn: conn,
425 admin: admin,
426 user1: user1,
427 user2: user2
428 } do
429 assert json_response(conn, :no_content)
430 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
431 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
432
433 log_entry = Repo.one(ModerationLog)
434
435 users =
436 [user1.nickname, user2.nickname]
437 |> Enum.map(&"@#{&1}")
438 |> Enum.join(", ")
439
440 tags = ["foo", "bar"] |> Enum.join(", ")
441
442 assert ModerationLog.get_log_entry_message(log_entry) ==
443 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
444 end
445
446 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
447 assert json_response(conn, :no_content)
448 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
449 end
450 end
451
452 describe "DELETE /api/pleroma/admin/users/tag" do
453 setup %{conn: conn} do
454 user1 = insert(:user, %{tags: ["x"]})
455 user2 = insert(:user, %{tags: ["y", "z"]})
456 user3 = insert(:user, %{tags: ["unchanged"]})
457
458 conn =
459 conn
460 |> put_req_header("accept", "application/json")
461 |> delete(
462 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
463 "#{user2.nickname}&tags[]=x&tags[]=z"
464 )
465
466 %{conn: conn, user1: user1, user2: user2, user3: user3}
467 end
468
469 test "it removes specified tags from users with specified nicknames", %{
470 conn: conn,
471 admin: admin,
472 user1: user1,
473 user2: user2
474 } do
475 assert json_response(conn, :no_content)
476 assert User.get_cached_by_id(user1.id).tags == []
477 assert User.get_cached_by_id(user2.id).tags == ["y"]
478
479 log_entry = Repo.one(ModerationLog)
480
481 users =
482 [user1.nickname, user2.nickname]
483 |> Enum.map(&"@#{&1}")
484 |> Enum.join(", ")
485
486 tags = ["x", "z"] |> Enum.join(", ")
487
488 assert ModerationLog.get_log_entry_message(log_entry) ==
489 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
490 end
491
492 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
493 assert json_response(conn, :no_content)
494 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
495 end
496 end
497
498 describe "/api/pleroma/admin/users/:nickname/permission_group" do
499 test "GET is giving user_info", %{admin: admin, conn: conn} do
500 conn =
501 conn
502 |> put_req_header("accept", "application/json")
503 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
504
505 assert json_response(conn, 200) == %{
506 "is_admin" => true,
507 "is_moderator" => false
508 }
509 end
510
511 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
512 user = insert(:user)
513
514 conn =
515 conn
516 |> put_req_header("accept", "application/json")
517 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
518
519 assert json_response(conn, 200) == %{
520 "is_admin" => true
521 }
522
523 log_entry = Repo.one(ModerationLog)
524
525 assert ModerationLog.get_log_entry_message(log_entry) ==
526 "@#{admin.nickname} made @#{user.nickname} admin"
527 end
528
529 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
530 user_one = insert(:user)
531 user_two = insert(:user)
532
533 conn =
534 conn
535 |> put_req_header("accept", "application/json")
536 |> post("/api/pleroma/admin/users/permission_group/admin", %{
537 nicknames: [user_one.nickname, user_two.nickname]
538 })
539
540 assert json_response(conn, 200) == %{"is_admin" => true}
541
542 log_entry = Repo.one(ModerationLog)
543
544 assert ModerationLog.get_log_entry_message(log_entry) ==
545 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
546 end
547
548 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
549 user = insert(:user, is_admin: true)
550
551 conn =
552 conn
553 |> put_req_header("accept", "application/json")
554 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
555
556 assert json_response(conn, 200) == %{"is_admin" => false}
557
558 log_entry = Repo.one(ModerationLog)
559
560 assert ModerationLog.get_log_entry_message(log_entry) ==
561 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
562 end
563
564 test "/:right DELETE, can remove from a permission group (multiple)", %{
565 admin: admin,
566 conn: conn
567 } do
568 user_one = insert(:user, is_admin: true)
569 user_two = insert(:user, is_admin: true)
570
571 conn =
572 conn
573 |> put_req_header("accept", "application/json")
574 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
575 nicknames: [user_one.nickname, user_two.nickname]
576 })
577
578 assert json_response(conn, 200) == %{"is_admin" => false}
579
580 log_entry = Repo.one(ModerationLog)
581
582 assert ModerationLog.get_log_entry_message(log_entry) ==
583 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
584 user_two.nickname
585 }"
586 end
587 end
588
589 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
590 user = insert(:user)
591
592 conn =
593 conn
594 |> put_req_header("accept", "application/json")
595 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
596
597 resp = json_response(conn, 200)
598
599 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
600 end
601
602 describe "GET /api/pleroma/admin/users" do
603 test "renders users array for the first page", %{conn: conn, admin: admin} do
604 user = insert(:user, local: false, tags: ["foo", "bar"])
605 conn = get(conn, "/api/pleroma/admin/users?page=1")
606
607 users =
608 [
609 %{
610 "deactivated" => admin.deactivated,
611 "id" => admin.id,
612 "nickname" => admin.nickname,
613 "roles" => %{"admin" => true, "moderator" => false},
614 "local" => true,
615 "tags" => [],
616 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
617 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
618 "confirmation_pending" => false,
619 "url" => admin.ap_id
620 },
621 %{
622 "deactivated" => user.deactivated,
623 "id" => user.id,
624 "nickname" => user.nickname,
625 "roles" => %{"admin" => false, "moderator" => false},
626 "local" => false,
627 "tags" => ["foo", "bar"],
628 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
629 "display_name" => HTML.strip_tags(user.name || user.nickname),
630 "confirmation_pending" => false,
631 "url" => user.ap_id
632 }
633 ]
634 |> Enum.sort_by(& &1["nickname"])
635
636 assert json_response(conn, 200) == %{
637 "count" => 2,
638 "page_size" => 50,
639 "users" => users
640 }
641 end
642
643 test "pagination works correctly with service users", %{conn: conn} do
644 service1 = User.get_or_create_service_actor_by_ap_id(Web.base_url() <> "/meido", "meido")
645
646 insert_list(25, :user)
647
648 assert %{"count" => 26, "page_size" => 10, "users" => users1} =
649 conn
650 |> get("/api/pleroma/admin/users?page=1&filters=", %{page_size: "10"})
651 |> json_response(200)
652
653 assert Enum.count(users1) == 10
654 assert service1 not in users1
655
656 assert %{"count" => 26, "page_size" => 10, "users" => users2} =
657 conn
658 |> get("/api/pleroma/admin/users?page=2&filters=", %{page_size: "10"})
659 |> json_response(200)
660
661 assert Enum.count(users2) == 10
662 assert service1 not in users2
663
664 assert %{"count" => 26, "page_size" => 10, "users" => users3} =
665 conn
666 |> get("/api/pleroma/admin/users?page=3&filters=", %{page_size: "10"})
667 |> json_response(200)
668
669 assert Enum.count(users3) == 6
670 assert service1 not in users3
671 end
672
673 test "renders empty array for the second page", %{conn: conn} do
674 insert(:user)
675
676 conn = get(conn, "/api/pleroma/admin/users?page=2")
677
678 assert json_response(conn, 200) == %{
679 "count" => 2,
680 "page_size" => 50,
681 "users" => []
682 }
683 end
684
685 test "regular search", %{conn: conn} do
686 user = insert(:user, nickname: "bob")
687
688 conn = get(conn, "/api/pleroma/admin/users?query=bo")
689
690 assert json_response(conn, 200) == %{
691 "count" => 1,
692 "page_size" => 50,
693 "users" => [
694 %{
695 "deactivated" => user.deactivated,
696 "id" => user.id,
697 "nickname" => user.nickname,
698 "roles" => %{"admin" => false, "moderator" => false},
699 "local" => true,
700 "tags" => [],
701 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
702 "display_name" => HTML.strip_tags(user.name || user.nickname),
703 "confirmation_pending" => false,
704 "url" => user.ap_id
705 }
706 ]
707 }
708 end
709
710 test "search by domain", %{conn: conn} do
711 user = insert(:user, nickname: "nickname@domain.com")
712 insert(:user)
713
714 conn = get(conn, "/api/pleroma/admin/users?query=domain.com")
715
716 assert json_response(conn, 200) == %{
717 "count" => 1,
718 "page_size" => 50,
719 "users" => [
720 %{
721 "deactivated" => user.deactivated,
722 "id" => user.id,
723 "nickname" => user.nickname,
724 "roles" => %{"admin" => false, "moderator" => false},
725 "local" => true,
726 "tags" => [],
727 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
728 "display_name" => HTML.strip_tags(user.name || user.nickname),
729 "confirmation_pending" => false,
730 "url" => user.ap_id
731 }
732 ]
733 }
734 end
735
736 test "search by full nickname", %{conn: conn} do
737 user = insert(:user, nickname: "nickname@domain.com")
738 insert(:user)
739
740 conn = get(conn, "/api/pleroma/admin/users?query=nickname@domain.com")
741
742 assert json_response(conn, 200) == %{
743 "count" => 1,
744 "page_size" => 50,
745 "users" => [
746 %{
747 "deactivated" => user.deactivated,
748 "id" => user.id,
749 "nickname" => user.nickname,
750 "roles" => %{"admin" => false, "moderator" => false},
751 "local" => true,
752 "tags" => [],
753 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
754 "display_name" => HTML.strip_tags(user.name || user.nickname),
755 "confirmation_pending" => false,
756 "url" => user.ap_id
757 }
758 ]
759 }
760 end
761
762 test "search by display name", %{conn: conn} do
763 user = insert(:user, name: "Display name")
764 insert(:user)
765
766 conn = get(conn, "/api/pleroma/admin/users?name=display")
767
768 assert json_response(conn, 200) == %{
769 "count" => 1,
770 "page_size" => 50,
771 "users" => [
772 %{
773 "deactivated" => user.deactivated,
774 "id" => user.id,
775 "nickname" => user.nickname,
776 "roles" => %{"admin" => false, "moderator" => false},
777 "local" => true,
778 "tags" => [],
779 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
780 "display_name" => HTML.strip_tags(user.name || user.nickname),
781 "confirmation_pending" => false,
782 "url" => user.ap_id
783 }
784 ]
785 }
786 end
787
788 test "search by email", %{conn: conn} do
789 user = insert(:user, email: "email@example.com")
790 insert(:user)
791
792 conn = get(conn, "/api/pleroma/admin/users?email=email@example.com")
793
794 assert json_response(conn, 200) == %{
795 "count" => 1,
796 "page_size" => 50,
797 "users" => [
798 %{
799 "deactivated" => user.deactivated,
800 "id" => user.id,
801 "nickname" => user.nickname,
802 "roles" => %{"admin" => false, "moderator" => false},
803 "local" => true,
804 "tags" => [],
805 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
806 "display_name" => HTML.strip_tags(user.name || user.nickname),
807 "confirmation_pending" => false,
808 "url" => user.ap_id
809 }
810 ]
811 }
812 end
813
814 test "regular search with page size", %{conn: conn} do
815 user = insert(:user, nickname: "aalice")
816 user2 = insert(:user, nickname: "alice")
817
818 conn1 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=1")
819
820 assert json_response(conn1, 200) == %{
821 "count" => 2,
822 "page_size" => 1,
823 "users" => [
824 %{
825 "deactivated" => user.deactivated,
826 "id" => user.id,
827 "nickname" => user.nickname,
828 "roles" => %{"admin" => false, "moderator" => false},
829 "local" => true,
830 "tags" => [],
831 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
832 "display_name" => HTML.strip_tags(user.name || user.nickname),
833 "confirmation_pending" => false,
834 "url" => user.ap_id
835 }
836 ]
837 }
838
839 conn2 = get(conn, "/api/pleroma/admin/users?query=a&page_size=1&page=2")
840
841 assert json_response(conn2, 200) == %{
842 "count" => 2,
843 "page_size" => 1,
844 "users" => [
845 %{
846 "deactivated" => user2.deactivated,
847 "id" => user2.id,
848 "nickname" => user2.nickname,
849 "roles" => %{"admin" => false, "moderator" => false},
850 "local" => true,
851 "tags" => [],
852 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
853 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
854 "confirmation_pending" => false,
855 "url" => user2.ap_id
856 }
857 ]
858 }
859 end
860
861 test "only local users" do
862 admin = insert(:user, is_admin: true, nickname: "john")
863 token = insert(:oauth_admin_token, user: admin)
864 user = insert(:user, nickname: "bob")
865
866 insert(:user, nickname: "bobb", local: false)
867
868 conn =
869 build_conn()
870 |> assign(:user, admin)
871 |> assign(:token, token)
872 |> get("/api/pleroma/admin/users?query=bo&filters=local")
873
874 assert json_response(conn, 200) == %{
875 "count" => 1,
876 "page_size" => 50,
877 "users" => [
878 %{
879 "deactivated" => user.deactivated,
880 "id" => user.id,
881 "nickname" => user.nickname,
882 "roles" => %{"admin" => false, "moderator" => false},
883 "local" => true,
884 "tags" => [],
885 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
886 "display_name" => HTML.strip_tags(user.name || user.nickname),
887 "confirmation_pending" => false,
888 "url" => user.ap_id
889 }
890 ]
891 }
892 end
893
894 test "only local users with no query", %{conn: conn, admin: old_admin} do
895 admin = insert(:user, is_admin: true, nickname: "john")
896 user = insert(:user, nickname: "bob")
897
898 insert(:user, nickname: "bobb", local: false)
899
900 conn = get(conn, "/api/pleroma/admin/users?filters=local")
901
902 users =
903 [
904 %{
905 "deactivated" => user.deactivated,
906 "id" => user.id,
907 "nickname" => user.nickname,
908 "roles" => %{"admin" => false, "moderator" => false},
909 "local" => true,
910 "tags" => [],
911 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
912 "display_name" => HTML.strip_tags(user.name || user.nickname),
913 "confirmation_pending" => false,
914 "url" => user.ap_id
915 },
916 %{
917 "deactivated" => admin.deactivated,
918 "id" => admin.id,
919 "nickname" => admin.nickname,
920 "roles" => %{"admin" => true, "moderator" => false},
921 "local" => true,
922 "tags" => [],
923 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
924 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
925 "confirmation_pending" => false,
926 "url" => admin.ap_id
927 },
928 %{
929 "deactivated" => false,
930 "id" => old_admin.id,
931 "local" => true,
932 "nickname" => old_admin.nickname,
933 "roles" => %{"admin" => true, "moderator" => false},
934 "tags" => [],
935 "avatar" => User.avatar_url(old_admin) |> MediaProxy.url(),
936 "display_name" => HTML.strip_tags(old_admin.name || old_admin.nickname),
937 "confirmation_pending" => false,
938 "url" => old_admin.ap_id
939 }
940 ]
941 |> Enum.sort_by(& &1["nickname"])
942
943 assert json_response(conn, 200) == %{
944 "count" => 3,
945 "page_size" => 50,
946 "users" => users
947 }
948 end
949
950 test "load only admins", %{conn: conn, admin: admin} do
951 second_admin = insert(:user, is_admin: true)
952 insert(:user)
953 insert(:user)
954
955 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
956
957 users =
958 [
959 %{
960 "deactivated" => false,
961 "id" => admin.id,
962 "nickname" => admin.nickname,
963 "roles" => %{"admin" => true, "moderator" => false},
964 "local" => admin.local,
965 "tags" => [],
966 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
967 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
968 "confirmation_pending" => false,
969 "url" => admin.ap_id
970 },
971 %{
972 "deactivated" => false,
973 "id" => second_admin.id,
974 "nickname" => second_admin.nickname,
975 "roles" => %{"admin" => true, "moderator" => false},
976 "local" => second_admin.local,
977 "tags" => [],
978 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
979 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
980 "confirmation_pending" => false,
981 "url" => second_admin.ap_id
982 }
983 ]
984 |> Enum.sort_by(& &1["nickname"])
985
986 assert json_response(conn, 200) == %{
987 "count" => 2,
988 "page_size" => 50,
989 "users" => users
990 }
991 end
992
993 test "load only moderators", %{conn: conn} do
994 moderator = insert(:user, is_moderator: true)
995 insert(:user)
996 insert(:user)
997
998 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
999
1000 assert json_response(conn, 200) == %{
1001 "count" => 1,
1002 "page_size" => 50,
1003 "users" => [
1004 %{
1005 "deactivated" => false,
1006 "id" => moderator.id,
1007 "nickname" => moderator.nickname,
1008 "roles" => %{"admin" => false, "moderator" => true},
1009 "local" => moderator.local,
1010 "tags" => [],
1011 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1012 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1013 "confirmation_pending" => false,
1014 "url" => moderator.ap_id
1015 }
1016 ]
1017 }
1018 end
1019
1020 test "load users with tags list", %{conn: conn} do
1021 user1 = insert(:user, tags: ["first"])
1022 user2 = insert(:user, tags: ["second"])
1023 insert(:user)
1024 insert(:user)
1025
1026 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1027
1028 users =
1029 [
1030 %{
1031 "deactivated" => false,
1032 "id" => user1.id,
1033 "nickname" => user1.nickname,
1034 "roles" => %{"admin" => false, "moderator" => false},
1035 "local" => user1.local,
1036 "tags" => ["first"],
1037 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1038 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1039 "confirmation_pending" => false,
1040 "url" => user1.ap_id
1041 },
1042 %{
1043 "deactivated" => false,
1044 "id" => user2.id,
1045 "nickname" => user2.nickname,
1046 "roles" => %{"admin" => false, "moderator" => false},
1047 "local" => user2.local,
1048 "tags" => ["second"],
1049 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1050 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1051 "confirmation_pending" => false,
1052 "url" => user2.ap_id
1053 }
1054 ]
1055 |> Enum.sort_by(& &1["nickname"])
1056
1057 assert json_response(conn, 200) == %{
1058 "count" => 2,
1059 "page_size" => 50,
1060 "users" => users
1061 }
1062 end
1063
1064 test "it works with multiple filters" do
1065 admin = insert(:user, nickname: "john", is_admin: true)
1066 token = insert(:oauth_admin_token, user: admin)
1067 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1068
1069 insert(:user, nickname: "ken", local: true, deactivated: true)
1070 insert(:user, nickname: "bobb", local: false, deactivated: false)
1071
1072 conn =
1073 build_conn()
1074 |> assign(:user, admin)
1075 |> assign(:token, token)
1076 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1077
1078 assert json_response(conn, 200) == %{
1079 "count" => 1,
1080 "page_size" => 50,
1081 "users" => [
1082 %{
1083 "deactivated" => user.deactivated,
1084 "id" => user.id,
1085 "nickname" => user.nickname,
1086 "roles" => %{"admin" => false, "moderator" => false},
1087 "local" => user.local,
1088 "tags" => [],
1089 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1090 "display_name" => HTML.strip_tags(user.name || user.nickname),
1091 "confirmation_pending" => false,
1092 "url" => user.ap_id
1093 }
1094 ]
1095 }
1096 end
1097
1098 test "it omits relay user", %{admin: admin, conn: conn} do
1099 assert %User{} = Relay.get_actor()
1100
1101 conn = get(conn, "/api/pleroma/admin/users")
1102
1103 assert json_response(conn, 200) == %{
1104 "count" => 1,
1105 "page_size" => 50,
1106 "users" => [
1107 %{
1108 "deactivated" => admin.deactivated,
1109 "id" => admin.id,
1110 "nickname" => admin.nickname,
1111 "roles" => %{"admin" => true, "moderator" => false},
1112 "local" => true,
1113 "tags" => [],
1114 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1115 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1116 "confirmation_pending" => false,
1117 "url" => admin.ap_id
1118 }
1119 ]
1120 }
1121 end
1122 end
1123
1124 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1125 user_one = insert(:user, deactivated: true)
1126 user_two = insert(:user, deactivated: true)
1127
1128 conn =
1129 patch(
1130 conn,
1131 "/api/pleroma/admin/users/activate",
1132 %{nicknames: [user_one.nickname, user_two.nickname]}
1133 )
1134
1135 response = json_response(conn, 200)
1136 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1137
1138 log_entry = Repo.one(ModerationLog)
1139
1140 assert ModerationLog.get_log_entry_message(log_entry) ==
1141 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1142 end
1143
1144 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1145 user_one = insert(:user, deactivated: false)
1146 user_two = insert(:user, deactivated: false)
1147
1148 conn =
1149 patch(
1150 conn,
1151 "/api/pleroma/admin/users/deactivate",
1152 %{nicknames: [user_one.nickname, user_two.nickname]}
1153 )
1154
1155 response = json_response(conn, 200)
1156 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1157
1158 log_entry = Repo.one(ModerationLog)
1159
1160 assert ModerationLog.get_log_entry_message(log_entry) ==
1161 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1162 end
1163
1164 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1165 user = insert(:user)
1166
1167 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1168
1169 assert json_response(conn, 200) ==
1170 %{
1171 "deactivated" => !user.deactivated,
1172 "id" => user.id,
1173 "nickname" => user.nickname,
1174 "roles" => %{"admin" => false, "moderator" => false},
1175 "local" => true,
1176 "tags" => [],
1177 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1178 "display_name" => HTML.strip_tags(user.name || user.nickname),
1179 "confirmation_pending" => false,
1180 "url" => user.ap_id
1181 }
1182
1183 log_entry = Repo.one(ModerationLog)
1184
1185 assert ModerationLog.get_log_entry_message(log_entry) ==
1186 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1187 end
1188
1189 describe "PUT disable_mfa" do
1190 test "returns 200 and disable 2fa", %{conn: conn} do
1191 user =
1192 insert(:user,
1193 multi_factor_authentication_settings: %MFA.Settings{
1194 enabled: true,
1195 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1196 }
1197 )
1198
1199 response =
1200 conn
1201 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1202 |> json_response(200)
1203
1204 assert response == user.nickname
1205 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1206
1207 refute mfa_settings.enabled
1208 refute mfa_settings.totp.confirmed
1209 end
1210
1211 test "returns 404 if user not found", %{conn: conn} do
1212 response =
1213 conn
1214 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1215 |> json_response(404)
1216
1217 assert response == %{"error" => "Not found"}
1218 end
1219 end
1220
1221 describe "GET /api/pleroma/admin/restart" do
1222 setup do: clear_config(:configurable_from_database, true)
1223
1224 test "pleroma restarts", %{conn: conn} do
1225 capture_log(fn ->
1226 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1227 end) =~ "pleroma restarted"
1228
1229 refute Restarter.Pleroma.need_reboot?()
1230 end
1231 end
1232
1233 test "need_reboot flag", %{conn: conn} do
1234 assert conn
1235 |> get("/api/pleroma/admin/need_reboot")
1236 |> json_response(200) == %{"need_reboot" => false}
1237
1238 Restarter.Pleroma.need_reboot()
1239
1240 assert conn
1241 |> get("/api/pleroma/admin/need_reboot")
1242 |> json_response(200) == %{"need_reboot" => true}
1243
1244 on_exit(fn -> Restarter.Pleroma.refresh() end)
1245 end
1246
1247 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
1248 setup do
1249 user = insert(:user)
1250
1251 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1252 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1253 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1254
1255 insert(:note_activity, user: user, published: date1)
1256 insert(:note_activity, user: user, published: date2)
1257 insert(:note_activity, user: user, published: date3)
1258
1259 %{user: user}
1260 end
1261
1262 test "renders user's statuses", %{conn: conn, user: user} do
1263 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1264
1265 assert json_response(conn, 200) |> length() == 3
1266 end
1267
1268 test "renders user's statuses with a limit", %{conn: conn, user: user} do
1269 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
1270
1271 assert json_response(conn, 200) |> length() == 2
1272 end
1273
1274 test "doesn't return private statuses by default", %{conn: conn, user: user} do
1275 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1276
1277 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1278
1279 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1280
1281 assert json_response(conn, 200) |> length() == 4
1282 end
1283
1284 test "returns private statuses with godmode on", %{conn: conn, user: user} do
1285 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1286
1287 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1288
1289 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
1290
1291 assert json_response(conn, 200) |> length() == 5
1292 end
1293
1294 test "excludes reblogs by default", %{conn: conn, user: user} do
1295 other_user = insert(:user)
1296 {:ok, activity} = CommonAPI.post(user, %{status: "."})
1297 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
1298
1299 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
1300 assert json_response(conn_res, 200) |> length() == 0
1301
1302 conn_res =
1303 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
1304
1305 assert json_response(conn_res, 200) |> length() == 1
1306 end
1307 end
1308
1309 describe "GET /api/pleroma/admin/moderation_log" do
1310 setup do
1311 moderator = insert(:user, is_moderator: true)
1312
1313 %{moderator: moderator}
1314 end
1315
1316 test "returns the log", %{conn: conn, admin: admin} do
1317 Repo.insert(%ModerationLog{
1318 data: %{
1319 actor: %{
1320 "id" => admin.id,
1321 "nickname" => admin.nickname,
1322 "type" => "user"
1323 },
1324 action: "relay_follow",
1325 target: "https://example.org/relay"
1326 },
1327 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1328 })
1329
1330 Repo.insert(%ModerationLog{
1331 data: %{
1332 actor: %{
1333 "id" => admin.id,
1334 "nickname" => admin.nickname,
1335 "type" => "user"
1336 },
1337 action: "relay_unfollow",
1338 target: "https://example.org/relay"
1339 },
1340 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1341 })
1342
1343 conn = get(conn, "/api/pleroma/admin/moderation_log")
1344
1345 response = json_response(conn, 200)
1346 [first_entry, second_entry] = response["items"]
1347
1348 assert response["total"] == 2
1349 assert first_entry["data"]["action"] == "relay_unfollow"
1350
1351 assert first_entry["message"] ==
1352 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1353
1354 assert second_entry["data"]["action"] == "relay_follow"
1355
1356 assert second_entry["message"] ==
1357 "@#{admin.nickname} followed relay: https://example.org/relay"
1358 end
1359
1360 test "returns the log with pagination", %{conn: conn, admin: admin} do
1361 Repo.insert(%ModerationLog{
1362 data: %{
1363 actor: %{
1364 "id" => admin.id,
1365 "nickname" => admin.nickname,
1366 "type" => "user"
1367 },
1368 action: "relay_follow",
1369 target: "https://example.org/relay"
1370 },
1371 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1372 })
1373
1374 Repo.insert(%ModerationLog{
1375 data: %{
1376 actor: %{
1377 "id" => admin.id,
1378 "nickname" => admin.nickname,
1379 "type" => "user"
1380 },
1381 action: "relay_unfollow",
1382 target: "https://example.org/relay"
1383 },
1384 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1385 })
1386
1387 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1388
1389 response1 = json_response(conn1, 200)
1390 [first_entry] = response1["items"]
1391
1392 assert response1["total"] == 2
1393 assert response1["items"] |> length() == 1
1394 assert first_entry["data"]["action"] == "relay_unfollow"
1395
1396 assert first_entry["message"] ==
1397 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1398
1399 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1400
1401 response2 = json_response(conn2, 200)
1402 [second_entry] = response2["items"]
1403
1404 assert response2["total"] == 2
1405 assert response2["items"] |> length() == 1
1406 assert second_entry["data"]["action"] == "relay_follow"
1407
1408 assert second_entry["message"] ==
1409 "@#{admin.nickname} followed relay: https://example.org/relay"
1410 end
1411
1412 test "filters log by date", %{conn: conn, admin: admin} do
1413 first_date = "2017-08-15T15:47:06Z"
1414 second_date = "2017-08-20T15:47:06Z"
1415
1416 Repo.insert(%ModerationLog{
1417 data: %{
1418 actor: %{
1419 "id" => admin.id,
1420 "nickname" => admin.nickname,
1421 "type" => "user"
1422 },
1423 action: "relay_follow",
1424 target: "https://example.org/relay"
1425 },
1426 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1427 })
1428
1429 Repo.insert(%ModerationLog{
1430 data: %{
1431 actor: %{
1432 "id" => admin.id,
1433 "nickname" => admin.nickname,
1434 "type" => "user"
1435 },
1436 action: "relay_unfollow",
1437 target: "https://example.org/relay"
1438 },
1439 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1440 })
1441
1442 conn1 =
1443 get(
1444 conn,
1445 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1446 )
1447
1448 response1 = json_response(conn1, 200)
1449 [first_entry] = response1["items"]
1450
1451 assert response1["total"] == 1
1452 assert first_entry["data"]["action"] == "relay_unfollow"
1453
1454 assert first_entry["message"] ==
1455 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1456 end
1457
1458 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1459 Repo.insert(%ModerationLog{
1460 data: %{
1461 actor: %{
1462 "id" => admin.id,
1463 "nickname" => admin.nickname,
1464 "type" => "user"
1465 },
1466 action: "relay_follow",
1467 target: "https://example.org/relay"
1468 }
1469 })
1470
1471 Repo.insert(%ModerationLog{
1472 data: %{
1473 actor: %{
1474 "id" => moderator.id,
1475 "nickname" => moderator.nickname,
1476 "type" => "user"
1477 },
1478 action: "relay_unfollow",
1479 target: "https://example.org/relay"
1480 }
1481 })
1482
1483 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1484
1485 response1 = json_response(conn1, 200)
1486 [first_entry] = response1["items"]
1487
1488 assert response1["total"] == 1
1489 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1490 end
1491
1492 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1493 ModerationLog.insert_log(%{
1494 actor: moderator,
1495 action: "relay_follow",
1496 target: "https://example.org/relay"
1497 })
1498
1499 ModerationLog.insert_log(%{
1500 actor: moderator,
1501 action: "relay_unfollow",
1502 target: "https://example.org/relay"
1503 })
1504
1505 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1506
1507 response1 = json_response(conn1, 200)
1508 [first_entry] = response1["items"]
1509
1510 assert response1["total"] == 1
1511
1512 assert get_in(first_entry, ["data", "message"]) ==
1513 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1514 end
1515 end
1516
1517 describe "GET /users/:nickname/credentials" do
1518 test "gets the user credentials", %{conn: conn} do
1519 user = insert(:user)
1520 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1521
1522 response = assert json_response(conn, 200)
1523 assert response["email"] == user.email
1524 end
1525
1526 test "returns 403 if requested by a non-admin" do
1527 user = insert(:user)
1528
1529 conn =
1530 build_conn()
1531 |> assign(:user, user)
1532 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
1533
1534 assert json_response(conn, :forbidden)
1535 end
1536 end
1537
1538 describe "PATCH /users/:nickname/credentials" do
1539 setup do
1540 user = insert(:user)
1541 [user: user]
1542 end
1543
1544 test "changes password and email", %{conn: conn, admin: admin, user: user} do
1545 assert user.password_reset_pending == false
1546
1547 conn =
1548 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1549 "password" => "new_password",
1550 "email" => "new_email@example.com",
1551 "name" => "new_name"
1552 })
1553
1554 assert json_response(conn, 200) == %{"status" => "success"}
1555
1556 ObanHelpers.perform_all()
1557
1558 updated_user = User.get_by_id(user.id)
1559
1560 assert updated_user.email == "new_email@example.com"
1561 assert updated_user.name == "new_name"
1562 assert updated_user.password_hash != user.password_hash
1563 assert updated_user.password_reset_pending == true
1564
1565 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
1566
1567 assert ModerationLog.get_log_entry_message(log_entry1) ==
1568 "@#{admin.nickname} updated users: @#{user.nickname}"
1569
1570 assert ModerationLog.get_log_entry_message(log_entry2) ==
1571 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
1572 end
1573
1574 test "returns 403 if requested by a non-admin", %{user: user} do
1575 conn =
1576 build_conn()
1577 |> assign(:user, user)
1578 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1579 "password" => "new_password",
1580 "email" => "new_email@example.com",
1581 "name" => "new_name"
1582 })
1583
1584 assert json_response(conn, :forbidden)
1585 end
1586
1587 test "changes actor type from permitted list", %{conn: conn, user: user} do
1588 assert user.actor_type == "Person"
1589
1590 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1591 "actor_type" => "Service"
1592 })
1593 |> json_response(200) == %{"status" => "success"}
1594
1595 updated_user = User.get_by_id(user.id)
1596
1597 assert updated_user.actor_type == "Service"
1598
1599 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1600 "actor_type" => "Application"
1601 })
1602 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
1603 end
1604
1605 test "update non existing user", %{conn: conn} do
1606 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
1607 "password" => "new_password"
1608 })
1609 |> json_response(404) == %{"error" => "Not found"}
1610 end
1611 end
1612
1613 describe "PATCH /users/:nickname/force_password_reset" do
1614 test "sets password_reset_pending to true", %{conn: conn} do
1615 user = insert(:user)
1616 assert user.password_reset_pending == false
1617
1618 conn =
1619 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
1620
1621 assert json_response(conn, 204) == ""
1622
1623 ObanHelpers.perform_all()
1624
1625 assert User.get_by_id(user.id).password_reset_pending == true
1626 end
1627 end
1628
1629 describe "instances" do
1630 test "GET /instances/:instance/statuses", %{conn: conn} do
1631 user = insert(:user, local: false, nickname: "archaeme@archae.me")
1632 user2 = insert(:user, local: false, nickname: "test@test.com")
1633 insert_pair(:note_activity, user: user)
1634 activity = insert(:note_activity, user: user2)
1635
1636 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1637
1638 response = json_response(ret_conn, 200)
1639
1640 assert length(response) == 2
1641
1642 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
1643
1644 response = json_response(ret_conn, 200)
1645
1646 assert length(response) == 1
1647
1648 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
1649
1650 response = json_response(ret_conn, 200)
1651
1652 assert Enum.empty?(response)
1653
1654 CommonAPI.repeat(activity.id, user)
1655
1656 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1657 response = json_response(ret_conn, 200)
1658 assert length(response) == 2
1659
1660 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
1661 response = json_response(ret_conn, 200)
1662 assert length(response) == 3
1663 end
1664 end
1665
1666 describe "PATCH /confirm_email" do
1667 test "it confirms emails of two users", %{conn: conn, admin: admin} do
1668 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1669
1670 assert first_user.confirmation_pending == true
1671 assert second_user.confirmation_pending == true
1672
1673 ret_conn =
1674 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
1675 nicknames: [
1676 first_user.nickname,
1677 second_user.nickname
1678 ]
1679 })
1680
1681 assert ret_conn.status == 200
1682
1683 assert first_user.confirmation_pending == true
1684 assert second_user.confirmation_pending == true
1685
1686 log_entry = Repo.one(ModerationLog)
1687
1688 assert ModerationLog.get_log_entry_message(log_entry) ==
1689 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
1690 second_user.nickname
1691 }"
1692 end
1693 end
1694
1695 describe "PATCH /resend_confirmation_email" do
1696 test "it resend emails for two users", %{conn: conn, admin: admin} do
1697 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1698
1699 ret_conn =
1700 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1701 nicknames: [
1702 first_user.nickname,
1703 second_user.nickname
1704 ]
1705 })
1706
1707 assert ret_conn.status == 200
1708
1709 log_entry = Repo.one(ModerationLog)
1710
1711 assert ModerationLog.get_log_entry_message(log_entry) ==
1712 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
1713 second_user.nickname
1714 }"
1715 end
1716 end
1717
1718 describe "/api/pleroma/admin/stats" do
1719 test "status visibility count", %{conn: conn} do
1720 admin = insert(:user, is_admin: true)
1721 user = insert(:user)
1722 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1723 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1724 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1725
1726 response =
1727 conn
1728 |> assign(:user, admin)
1729 |> get("/api/pleroma/admin/stats")
1730 |> json_response(200)
1731
1732 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1733 response["status_visibility"]
1734 end
1735
1736 test "by instance", %{conn: conn} do
1737 admin = insert(:user, is_admin: true)
1738 user1 = insert(:user)
1739 instance2 = "instance2.tld"
1740 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1741
1742 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1743 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1744 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1745
1746 response =
1747 conn
1748 |> assign(:user, admin)
1749 |> get("/api/pleroma/admin/stats", instance: instance2)
1750 |> json_response(200)
1751
1752 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1753 response["status_visibility"]
1754 end
1755 end
1756 end
1757
1758 # Needed for testing
1759 defmodule Pleroma.Web.Endpoint.NotReal do
1760 end
1761
1762 defmodule Pleroma.Captcha.NotReal do
1763 end