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