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