Chat moderation: add tests for unauthorized access
[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 == nil
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
1517 insert(:chat, user: user)
1518 insert(:chat, user: user)
1519 insert(:chat, user: user)
1520
1521 %{user: user}
1522 end
1523
1524 test "renders user's statuses", %{conn: conn, user: user} do
1525 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
1526
1527 assert json_response(conn, 200) |> length() == 3
1528 end
1529 end
1530
1531 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
1532 setup do
1533 user = insert(:user)
1534 insert(:chat, user: user)
1535 %{conn: conn} = oauth_access(["read:chats"])
1536 %{conn: conn, user: user}
1537 end
1538
1539 test "returns 403", %{conn: conn, user: user} do
1540 conn
1541 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
1542 |> json_response(403)
1543 end
1544 end
1545
1546 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
1547 setup do
1548 user = insert(:user)
1549 insert(:chat, user: user)
1550 %{conn: build_conn(), user: user}
1551 end
1552
1553 test "returns 403", %{conn: conn, user: user} do
1554 conn
1555 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
1556 |> json_response(403)
1557 end
1558 end
1559
1560 describe "GET /api/pleroma/admin/moderation_log" do
1561 setup do
1562 moderator = insert(:user, is_moderator: true)
1563
1564 %{moderator: moderator}
1565 end
1566
1567 test "returns the log", %{conn: conn, admin: admin} do
1568 Repo.insert(%ModerationLog{
1569 data: %{
1570 actor: %{
1571 "id" => admin.id,
1572 "nickname" => admin.nickname,
1573 "type" => "user"
1574 },
1575 action: "relay_follow",
1576 target: "https://example.org/relay"
1577 },
1578 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1579 })
1580
1581 Repo.insert(%ModerationLog{
1582 data: %{
1583 actor: %{
1584 "id" => admin.id,
1585 "nickname" => admin.nickname,
1586 "type" => "user"
1587 },
1588 action: "relay_unfollow",
1589 target: "https://example.org/relay"
1590 },
1591 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1592 })
1593
1594 conn = get(conn, "/api/pleroma/admin/moderation_log")
1595
1596 response = json_response(conn, 200)
1597 [first_entry, second_entry] = response["items"]
1598
1599 assert response["total"] == 2
1600 assert first_entry["data"]["action"] == "relay_unfollow"
1601
1602 assert first_entry["message"] ==
1603 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1604
1605 assert second_entry["data"]["action"] == "relay_follow"
1606
1607 assert second_entry["message"] ==
1608 "@#{admin.nickname} followed relay: https://example.org/relay"
1609 end
1610
1611 test "returns the log with pagination", %{conn: conn, admin: admin} do
1612 Repo.insert(%ModerationLog{
1613 data: %{
1614 actor: %{
1615 "id" => admin.id,
1616 "nickname" => admin.nickname,
1617 "type" => "user"
1618 },
1619 action: "relay_follow",
1620 target: "https://example.org/relay"
1621 },
1622 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1623 })
1624
1625 Repo.insert(%ModerationLog{
1626 data: %{
1627 actor: %{
1628 "id" => admin.id,
1629 "nickname" => admin.nickname,
1630 "type" => "user"
1631 },
1632 action: "relay_unfollow",
1633 target: "https://example.org/relay"
1634 },
1635 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1636 })
1637
1638 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1639
1640 response1 = json_response(conn1, 200)
1641 [first_entry] = response1["items"]
1642
1643 assert response1["total"] == 2
1644 assert response1["items"] |> length() == 1
1645 assert first_entry["data"]["action"] == "relay_unfollow"
1646
1647 assert first_entry["message"] ==
1648 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1649
1650 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1651
1652 response2 = json_response(conn2, 200)
1653 [second_entry] = response2["items"]
1654
1655 assert response2["total"] == 2
1656 assert response2["items"] |> length() == 1
1657 assert second_entry["data"]["action"] == "relay_follow"
1658
1659 assert second_entry["message"] ==
1660 "@#{admin.nickname} followed relay: https://example.org/relay"
1661 end
1662
1663 test "filters log by date", %{conn: conn, admin: admin} do
1664 first_date = "2017-08-15T15:47:06Z"
1665 second_date = "2017-08-20T15:47:06Z"
1666
1667 Repo.insert(%ModerationLog{
1668 data: %{
1669 actor: %{
1670 "id" => admin.id,
1671 "nickname" => admin.nickname,
1672 "type" => "user"
1673 },
1674 action: "relay_follow",
1675 target: "https://example.org/relay"
1676 },
1677 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1678 })
1679
1680 Repo.insert(%ModerationLog{
1681 data: %{
1682 actor: %{
1683 "id" => admin.id,
1684 "nickname" => admin.nickname,
1685 "type" => "user"
1686 },
1687 action: "relay_unfollow",
1688 target: "https://example.org/relay"
1689 },
1690 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1691 })
1692
1693 conn1 =
1694 get(
1695 conn,
1696 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1697 )
1698
1699 response1 = json_response(conn1, 200)
1700 [first_entry] = response1["items"]
1701
1702 assert response1["total"] == 1
1703 assert first_entry["data"]["action"] == "relay_unfollow"
1704
1705 assert first_entry["message"] ==
1706 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1707 end
1708
1709 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1710 Repo.insert(%ModerationLog{
1711 data: %{
1712 actor: %{
1713 "id" => admin.id,
1714 "nickname" => admin.nickname,
1715 "type" => "user"
1716 },
1717 action: "relay_follow",
1718 target: "https://example.org/relay"
1719 }
1720 })
1721
1722 Repo.insert(%ModerationLog{
1723 data: %{
1724 actor: %{
1725 "id" => moderator.id,
1726 "nickname" => moderator.nickname,
1727 "type" => "user"
1728 },
1729 action: "relay_unfollow",
1730 target: "https://example.org/relay"
1731 }
1732 })
1733
1734 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1735
1736 response1 = json_response(conn1, 200)
1737 [first_entry] = response1["items"]
1738
1739 assert response1["total"] == 1
1740 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1741 end
1742
1743 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1744 ModerationLog.insert_log(%{
1745 actor: moderator,
1746 action: "relay_follow",
1747 target: "https://example.org/relay"
1748 })
1749
1750 ModerationLog.insert_log(%{
1751 actor: moderator,
1752 action: "relay_unfollow",
1753 target: "https://example.org/relay"
1754 })
1755
1756 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1757
1758 response1 = json_response(conn1, 200)
1759 [first_entry] = response1["items"]
1760
1761 assert response1["total"] == 1
1762
1763 assert get_in(first_entry, ["data", "message"]) ==
1764 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1765 end
1766 end
1767
1768 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
1769 %{conn: conn} do
1770 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
1771 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
1772 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1773
1774 assert json_response(conn, 200)
1775 end
1776
1777 describe "GET /users/:nickname/credentials" do
1778 test "gets the user credentials", %{conn: conn} do
1779 user = insert(:user)
1780 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1781
1782 response = assert json_response(conn, 200)
1783 assert response["email"] == user.email
1784 end
1785
1786 test "returns 403 if requested by a non-admin" do
1787 user = insert(:user)
1788
1789 conn =
1790 build_conn()
1791 |> assign(:user, user)
1792 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
1793
1794 assert json_response(conn, :forbidden)
1795 end
1796 end
1797
1798 describe "PATCH /users/:nickname/credentials" do
1799 setup do
1800 user = insert(:user)
1801 [user: user]
1802 end
1803
1804 test "changes password and email", %{conn: conn, admin: admin, user: user} do
1805 assert user.password_reset_pending == false
1806
1807 conn =
1808 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1809 "password" => "new_password",
1810 "email" => "new_email@example.com",
1811 "name" => "new_name"
1812 })
1813
1814 assert json_response(conn, 200) == %{"status" => "success"}
1815
1816 ObanHelpers.perform_all()
1817
1818 updated_user = User.get_by_id(user.id)
1819
1820 assert updated_user.email == "new_email@example.com"
1821 assert updated_user.name == "new_name"
1822 assert updated_user.password_hash != user.password_hash
1823 assert updated_user.password_reset_pending == true
1824
1825 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
1826
1827 assert ModerationLog.get_log_entry_message(log_entry1) ==
1828 "@#{admin.nickname} updated users: @#{user.nickname}"
1829
1830 assert ModerationLog.get_log_entry_message(log_entry2) ==
1831 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
1832 end
1833
1834 test "returns 403 if requested by a non-admin", %{user: user} do
1835 conn =
1836 build_conn()
1837 |> assign(:user, user)
1838 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1839 "password" => "new_password",
1840 "email" => "new_email@example.com",
1841 "name" => "new_name"
1842 })
1843
1844 assert json_response(conn, :forbidden)
1845 end
1846
1847 test "changes actor type from permitted list", %{conn: conn, user: user} do
1848 assert user.actor_type == "Person"
1849
1850 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1851 "actor_type" => "Service"
1852 })
1853 |> json_response(200) == %{"status" => "success"}
1854
1855 updated_user = User.get_by_id(user.id)
1856
1857 assert updated_user.actor_type == "Service"
1858
1859 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1860 "actor_type" => "Application"
1861 })
1862 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
1863 end
1864
1865 test "update non existing user", %{conn: conn} do
1866 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
1867 "password" => "new_password"
1868 })
1869 |> json_response(404) == %{"error" => "Not found"}
1870 end
1871 end
1872
1873 describe "PATCH /users/:nickname/force_password_reset" do
1874 test "sets password_reset_pending to true", %{conn: conn} do
1875 user = insert(:user)
1876 assert user.password_reset_pending == false
1877
1878 conn =
1879 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
1880
1881 assert empty_json_response(conn) == ""
1882
1883 ObanHelpers.perform_all()
1884
1885 assert User.get_by_id(user.id).password_reset_pending == true
1886 end
1887 end
1888
1889 describe "instances" do
1890 test "GET /instances/:instance/statuses", %{conn: conn} do
1891 user = insert(:user, local: false, nickname: "archaeme@archae.me")
1892 user2 = insert(:user, local: false, nickname: "test@test.com")
1893 insert_pair(:note_activity, user: user)
1894 activity = insert(:note_activity, user: user2)
1895
1896 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1897
1898 response = json_response(ret_conn, 200)
1899
1900 assert length(response) == 2
1901
1902 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
1903
1904 response = json_response(ret_conn, 200)
1905
1906 assert length(response) == 1
1907
1908 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
1909
1910 response = json_response(ret_conn, 200)
1911
1912 assert Enum.empty?(response)
1913
1914 CommonAPI.repeat(activity.id, user)
1915
1916 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1917 response = json_response(ret_conn, 200)
1918 assert length(response) == 2
1919
1920 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
1921 response = json_response(ret_conn, 200)
1922 assert length(response) == 3
1923 end
1924 end
1925
1926 describe "PATCH /confirm_email" do
1927 test "it confirms emails of two users", %{conn: conn, admin: admin} do
1928 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1929
1930 assert first_user.confirmation_pending == true
1931 assert second_user.confirmation_pending == true
1932
1933 ret_conn =
1934 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
1935 nicknames: [
1936 first_user.nickname,
1937 second_user.nickname
1938 ]
1939 })
1940
1941 assert ret_conn.status == 200
1942
1943 assert first_user.confirmation_pending == true
1944 assert second_user.confirmation_pending == true
1945
1946 log_entry = Repo.one(ModerationLog)
1947
1948 assert ModerationLog.get_log_entry_message(log_entry) ==
1949 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
1950 second_user.nickname
1951 }"
1952 end
1953 end
1954
1955 describe "PATCH /resend_confirmation_email" do
1956 test "it resend emails for two users", %{conn: conn, admin: admin} do
1957 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1958
1959 ret_conn =
1960 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1961 nicknames: [
1962 first_user.nickname,
1963 second_user.nickname
1964 ]
1965 })
1966
1967 assert ret_conn.status == 200
1968
1969 log_entry = Repo.one(ModerationLog)
1970
1971 assert ModerationLog.get_log_entry_message(log_entry) ==
1972 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
1973 second_user.nickname
1974 }"
1975
1976 ObanHelpers.perform_all()
1977 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
1978 end
1979 end
1980
1981 describe "/api/pleroma/admin/stats" do
1982 test "status visibility count", %{conn: conn} do
1983 admin = insert(:user, is_admin: true)
1984 user = insert(:user)
1985 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1986 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1987 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1988
1989 response =
1990 conn
1991 |> assign(:user, admin)
1992 |> get("/api/pleroma/admin/stats")
1993 |> json_response(200)
1994
1995 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1996 response["status_visibility"]
1997 end
1998
1999 test "by instance", %{conn: conn} do
2000 admin = insert(:user, is_admin: true)
2001 user1 = insert(:user)
2002 instance2 = "instance2.tld"
2003 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
2004
2005 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
2006 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
2007 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
2008
2009 response =
2010 conn
2011 |> assign(:user, admin)
2012 |> get("/api/pleroma/admin/stats", instance: instance2)
2013 |> json_response(200)
2014
2015 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
2016 response["status_visibility"]
2017 end
2018 end
2019 end
2020
2021 # Needed for testing
2022 defmodule Pleroma.Web.Endpoint.NotReal do
2023 end
2024
2025 defmodule Pleroma.Captcha.NotReal do
2026 end