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