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