Merge branch 'buildx-multiarch-arm32v7' into 'develop'
[akkoma] / test / web / admin_api / controllers / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 import ExUnit.CaptureLog
10 import Mock
11 import Pleroma.Factory
12 import Swoosh.TestAssertions
13
14 alias Pleroma.Activity
15 alias Pleroma.Config
16 alias Pleroma.HTML
17 alias Pleroma.MFA
18 alias Pleroma.ModerationLog
19 alias Pleroma.Repo
20 alias Pleroma.Tests.ObanHelpers
21 alias Pleroma.User
22 alias Pleroma.Web
23 alias Pleroma.Web.ActivityPub.Relay
24 alias Pleroma.Web.CommonAPI
25 alias Pleroma.Web.MediaProxy
26
27 setup_all do
28 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
29
30 :ok
31 end
32
33 setup do
34 admin = insert(:user, is_admin: true)
35 token = insert(:oauth_admin_token, user: admin)
36
37 conn =
38 build_conn()
39 |> assign(:user, admin)
40 |> assign(:token, token)
41
42 {:ok, %{admin: admin, token: token, conn: conn}}
43 end
44
45 test "with valid `admin_token` query parameter, skips OAuth scopes check" do
46 clear_config([:admin_token], "password123")
47
48 user = insert(:user)
49
50 conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
51
52 assert json_response(conn, 200)
53 end
54
55 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
56 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
57
58 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
59 %{admin: admin} do
60 user = insert(:user)
61 url = "/api/pleroma/admin/users/#{user.nickname}"
62
63 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
64 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
65 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
66
67 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
68 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
69 bad_token3 = nil
70
71 for good_token <- [good_token1, good_token2, good_token3] do
72 conn =
73 build_conn()
74 |> assign(:user, admin)
75 |> assign(:token, good_token)
76 |> get(url)
77
78 assert json_response(conn, 200)
79 end
80
81 for good_token <- [good_token1, good_token2, good_token3] do
82 conn =
83 build_conn()
84 |> assign(:user, nil)
85 |> assign(:token, good_token)
86 |> get(url)
87
88 assert json_response(conn, :forbidden)
89 end
90
91 for bad_token <- [bad_token1, bad_token2, bad_token3] do
92 conn =
93 build_conn()
94 |> assign(:user, admin)
95 |> assign(:token, bad_token)
96 |> get(url)
97
98 assert json_response(conn, :forbidden)
99 end
100 end
101 end
102
103 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
104 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
105
106 test "GET /api/pleroma/admin/users/:nickname requires " <>
107 "read:accounts or admin:read:accounts or broader scope",
108 %{admin: admin} do
109 user = insert(:user)
110 url = "/api/pleroma/admin/users/#{user.nickname}"
111
112 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
113 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
114 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
115 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
116 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
117
118 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
119
120 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
121 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
122 bad_token3 = nil
123
124 for good_token <- good_tokens do
125 conn =
126 build_conn()
127 |> assign(:user, admin)
128 |> assign(:token, good_token)
129 |> get(url)
130
131 assert json_response(conn, 200)
132 end
133
134 for good_token <- good_tokens do
135 conn =
136 build_conn()
137 |> assign(:user, nil)
138 |> assign(:token, good_token)
139 |> get(url)
140
141 assert json_response(conn, :forbidden)
142 end
143
144 for bad_token <- [bad_token1, bad_token2, bad_token3] do
145 conn =
146 build_conn()
147 |> assign(:user, admin)
148 |> assign(:token, bad_token)
149 |> get(url)
150
151 assert json_response(conn, :forbidden)
152 end
153 end
154 end
155
156 describe "DELETE /api/pleroma/admin/users" do
157 test "single user", %{admin: admin, conn: conn} do
158 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/moderation_log" do
1514 setup do
1515 moderator = insert(:user, is_moderator: true)
1516
1517 %{moderator: moderator}
1518 end
1519
1520 test "returns the log", %{conn: conn, admin: admin} do
1521 Repo.insert(%ModerationLog{
1522 data: %{
1523 actor: %{
1524 "id" => admin.id,
1525 "nickname" => admin.nickname,
1526 "type" => "user"
1527 },
1528 action: "relay_follow",
1529 target: "https://example.org/relay"
1530 },
1531 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1532 })
1533
1534 Repo.insert(%ModerationLog{
1535 data: %{
1536 actor: %{
1537 "id" => admin.id,
1538 "nickname" => admin.nickname,
1539 "type" => "user"
1540 },
1541 action: "relay_unfollow",
1542 target: "https://example.org/relay"
1543 },
1544 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1545 })
1546
1547 conn = get(conn, "/api/pleroma/admin/moderation_log")
1548
1549 response = json_response(conn, 200)
1550 [first_entry, second_entry] = response["items"]
1551
1552 assert response["total"] == 2
1553 assert first_entry["data"]["action"] == "relay_unfollow"
1554
1555 assert first_entry["message"] ==
1556 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1557
1558 assert second_entry["data"]["action"] == "relay_follow"
1559
1560 assert second_entry["message"] ==
1561 "@#{admin.nickname} followed relay: https://example.org/relay"
1562 end
1563
1564 test "returns the log with pagination", %{conn: conn, admin: admin} do
1565 Repo.insert(%ModerationLog{
1566 data: %{
1567 actor: %{
1568 "id" => admin.id,
1569 "nickname" => admin.nickname,
1570 "type" => "user"
1571 },
1572 action: "relay_follow",
1573 target: "https://example.org/relay"
1574 },
1575 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1576 })
1577
1578 Repo.insert(%ModerationLog{
1579 data: %{
1580 actor: %{
1581 "id" => admin.id,
1582 "nickname" => admin.nickname,
1583 "type" => "user"
1584 },
1585 action: "relay_unfollow",
1586 target: "https://example.org/relay"
1587 },
1588 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1589 })
1590
1591 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1592
1593 response1 = json_response(conn1, 200)
1594 [first_entry] = response1["items"]
1595
1596 assert response1["total"] == 2
1597 assert response1["items"] |> length() == 1
1598 assert first_entry["data"]["action"] == "relay_unfollow"
1599
1600 assert first_entry["message"] ==
1601 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1602
1603 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1604
1605 response2 = json_response(conn2, 200)
1606 [second_entry] = response2["items"]
1607
1608 assert response2["total"] == 2
1609 assert response2["items"] |> length() == 1
1610 assert second_entry["data"]["action"] == "relay_follow"
1611
1612 assert second_entry["message"] ==
1613 "@#{admin.nickname} followed relay: https://example.org/relay"
1614 end
1615
1616 test "filters log by date", %{conn: conn, admin: admin} do
1617 first_date = "2017-08-15T15:47:06Z"
1618 second_date = "2017-08-20T15:47:06Z"
1619
1620 Repo.insert(%ModerationLog{
1621 data: %{
1622 actor: %{
1623 "id" => admin.id,
1624 "nickname" => admin.nickname,
1625 "type" => "user"
1626 },
1627 action: "relay_follow",
1628 target: "https://example.org/relay"
1629 },
1630 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1631 })
1632
1633 Repo.insert(%ModerationLog{
1634 data: %{
1635 actor: %{
1636 "id" => admin.id,
1637 "nickname" => admin.nickname,
1638 "type" => "user"
1639 },
1640 action: "relay_unfollow",
1641 target: "https://example.org/relay"
1642 },
1643 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1644 })
1645
1646 conn1 =
1647 get(
1648 conn,
1649 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1650 )
1651
1652 response1 = json_response(conn1, 200)
1653 [first_entry] = response1["items"]
1654
1655 assert response1["total"] == 1
1656 assert first_entry["data"]["action"] == "relay_unfollow"
1657
1658 assert first_entry["message"] ==
1659 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1660 end
1661
1662 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1663 Repo.insert(%ModerationLog{
1664 data: %{
1665 actor: %{
1666 "id" => admin.id,
1667 "nickname" => admin.nickname,
1668 "type" => "user"
1669 },
1670 action: "relay_follow",
1671 target: "https://example.org/relay"
1672 }
1673 })
1674
1675 Repo.insert(%ModerationLog{
1676 data: %{
1677 actor: %{
1678 "id" => moderator.id,
1679 "nickname" => moderator.nickname,
1680 "type" => "user"
1681 },
1682 action: "relay_unfollow",
1683 target: "https://example.org/relay"
1684 }
1685 })
1686
1687 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1688
1689 response1 = json_response(conn1, 200)
1690 [first_entry] = response1["items"]
1691
1692 assert response1["total"] == 1
1693 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1694 end
1695
1696 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1697 ModerationLog.insert_log(%{
1698 actor: moderator,
1699 action: "relay_follow",
1700 target: "https://example.org/relay"
1701 })
1702
1703 ModerationLog.insert_log(%{
1704 actor: moderator,
1705 action: "relay_unfollow",
1706 target: "https://example.org/relay"
1707 })
1708
1709 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1710
1711 response1 = json_response(conn1, 200)
1712 [first_entry] = response1["items"]
1713
1714 assert response1["total"] == 1
1715
1716 assert get_in(first_entry, ["data", "message"]) ==
1717 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1718 end
1719 end
1720
1721 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
1722 %{conn: conn} do
1723 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
1724 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
1725 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1726
1727 assert json_response(conn, 200)
1728 end
1729
1730 describe "GET /users/:nickname/credentials" do
1731 test "gets the user credentials", %{conn: conn} do
1732 user = insert(:user)
1733 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1734
1735 response = assert json_response(conn, 200)
1736 assert response["email"] == user.email
1737 end
1738
1739 test "returns 403 if requested by a non-admin" do
1740 user = insert(:user)
1741
1742 conn =
1743 build_conn()
1744 |> assign(:user, user)
1745 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
1746
1747 assert json_response(conn, :forbidden)
1748 end
1749 end
1750
1751 describe "PATCH /users/:nickname/credentials" do
1752 setup do
1753 user = insert(:user)
1754 [user: user]
1755 end
1756
1757 test "changes password and email", %{conn: conn, admin: admin, user: user} do
1758 assert user.password_reset_pending == false
1759
1760 conn =
1761 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1762 "password" => "new_password",
1763 "email" => "new_email@example.com",
1764 "name" => "new_name"
1765 })
1766
1767 assert json_response(conn, 200) == %{"status" => "success"}
1768
1769 ObanHelpers.perform_all()
1770
1771 updated_user = User.get_by_id(user.id)
1772
1773 assert updated_user.email == "new_email@example.com"
1774 assert updated_user.name == "new_name"
1775 assert updated_user.password_hash != user.password_hash
1776 assert updated_user.password_reset_pending == true
1777
1778 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
1779
1780 assert ModerationLog.get_log_entry_message(log_entry1) ==
1781 "@#{admin.nickname} updated users: @#{user.nickname}"
1782
1783 assert ModerationLog.get_log_entry_message(log_entry2) ==
1784 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
1785 end
1786
1787 test "returns 403 if requested by a non-admin", %{user: user} do
1788 conn =
1789 build_conn()
1790 |> assign(:user, user)
1791 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1792 "password" => "new_password",
1793 "email" => "new_email@example.com",
1794 "name" => "new_name"
1795 })
1796
1797 assert json_response(conn, :forbidden)
1798 end
1799
1800 test "changes actor type from permitted list", %{conn: conn, user: user} do
1801 assert user.actor_type == "Person"
1802
1803 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1804 "actor_type" => "Service"
1805 })
1806 |> json_response(200) == %{"status" => "success"}
1807
1808 updated_user = User.get_by_id(user.id)
1809
1810 assert updated_user.actor_type == "Service"
1811
1812 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1813 "actor_type" => "Application"
1814 })
1815 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
1816 end
1817
1818 test "update non existing user", %{conn: conn} do
1819 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
1820 "password" => "new_password"
1821 })
1822 |> json_response(404) == %{"error" => "Not found"}
1823 end
1824 end
1825
1826 describe "PATCH /users/:nickname/force_password_reset" do
1827 test "sets password_reset_pending to true", %{conn: conn} do
1828 user = insert(:user)
1829 assert user.password_reset_pending == false
1830
1831 conn =
1832 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
1833
1834 assert empty_json_response(conn) == ""
1835
1836 ObanHelpers.perform_all()
1837
1838 assert User.get_by_id(user.id).password_reset_pending == true
1839 end
1840 end
1841
1842 describe "instances" do
1843 test "GET /instances/:instance/statuses", %{conn: conn} do
1844 user = insert(:user, local: false, nickname: "archaeme@archae.me")
1845 user2 = insert(:user, local: false, nickname: "test@test.com")
1846 insert_pair(:note_activity, user: user)
1847 activity = insert(:note_activity, user: user2)
1848
1849 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1850
1851 response = json_response(ret_conn, 200)
1852
1853 assert length(response) == 2
1854
1855 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
1856
1857 response = json_response(ret_conn, 200)
1858
1859 assert length(response) == 1
1860
1861 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
1862
1863 response = json_response(ret_conn, 200)
1864
1865 assert Enum.empty?(response)
1866
1867 CommonAPI.repeat(activity.id, user)
1868
1869 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1870 response = json_response(ret_conn, 200)
1871 assert length(response) == 2
1872
1873 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
1874 response = json_response(ret_conn, 200)
1875 assert length(response) == 3
1876 end
1877 end
1878
1879 describe "PATCH /confirm_email" do
1880 test "it confirms emails of two users", %{conn: conn, admin: admin} do
1881 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1882
1883 assert first_user.confirmation_pending == true
1884 assert second_user.confirmation_pending == true
1885
1886 ret_conn =
1887 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
1888 nicknames: [
1889 first_user.nickname,
1890 second_user.nickname
1891 ]
1892 })
1893
1894 assert ret_conn.status == 200
1895
1896 assert first_user.confirmation_pending == true
1897 assert second_user.confirmation_pending == true
1898
1899 log_entry = Repo.one(ModerationLog)
1900
1901 assert ModerationLog.get_log_entry_message(log_entry) ==
1902 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
1903 second_user.nickname
1904 }"
1905 end
1906 end
1907
1908 describe "PATCH /resend_confirmation_email" do
1909 test "it resend emails for two users", %{conn: conn, admin: admin} do
1910 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1911
1912 ret_conn =
1913 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1914 nicknames: [
1915 first_user.nickname,
1916 second_user.nickname
1917 ]
1918 })
1919
1920 assert ret_conn.status == 200
1921
1922 log_entry = Repo.one(ModerationLog)
1923
1924 assert ModerationLog.get_log_entry_message(log_entry) ==
1925 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
1926 second_user.nickname
1927 }"
1928
1929 ObanHelpers.perform_all()
1930 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(first_user))
1931 end
1932 end
1933
1934 describe "/api/pleroma/admin/stats" do
1935 test "status visibility count", %{conn: conn} do
1936 admin = insert(:user, is_admin: true)
1937 user = insert(:user)
1938 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1939 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1940 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1941
1942 response =
1943 conn
1944 |> assign(:user, admin)
1945 |> get("/api/pleroma/admin/stats")
1946 |> json_response(200)
1947
1948 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1949 response["status_visibility"]
1950 end
1951
1952 test "by instance", %{conn: conn} do
1953 admin = insert(:user, is_admin: true)
1954 user1 = insert(:user)
1955 instance2 = "instance2.tld"
1956 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1957
1958 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1959 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1960 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1961
1962 response =
1963 conn
1964 |> assign(:user, admin)
1965 |> get("/api/pleroma/admin/stats", instance: instance2)
1966 |> json_response(200)
1967
1968 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1969 response["status_visibility"]
1970 end
1971 end
1972 end
1973
1974 # Needed for testing
1975 defmodule Pleroma.Web.Endpoint.NotReal do
1976 end
1977
1978 defmodule Pleroma.Captcha.NotReal do
1979 end