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