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