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