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