351df8883a7771687eb664c7fc97ae810e58269e
[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 "only unapproved users", %{conn: conn} do
995 user =
996 insert(:user,
997 nickname: "sadboy",
998 approval_pending: true,
999 registration_reason: "Plz let me in!"
1000 )
1001
1002 insert(:user, nickname: "happyboy", approval_pending: false)
1003
1004 conn = get(conn, "/api/pleroma/admin/users?filters=need_approval")
1005
1006 users =
1007 [
1008 %{
1009 "deactivated" => user.deactivated,
1010 "id" => user.id,
1011 "nickname" => user.nickname,
1012 "roles" => %{"admin" => false, "moderator" => false},
1013 "local" => true,
1014 "tags" => [],
1015 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1016 "display_name" => HTML.strip_tags(user.name || user.nickname),
1017 "confirmation_pending" => false,
1018 "approval_pending" => true,
1019 "url" => user.ap_id,
1020 "registration_reason" => "Plz let me in!"
1021 }
1022 ]
1023 |> Enum.sort_by(& &1["nickname"])
1024
1025 assert json_response(conn, 200) == %{
1026 "count" => 1,
1027 "page_size" => 50,
1028 "users" => users
1029 }
1030 end
1031
1032 test "load only admins", %{conn: conn, admin: admin} do
1033 second_admin = insert(:user, is_admin: true)
1034 insert(:user)
1035 insert(:user)
1036
1037 conn = get(conn, "/api/pleroma/admin/users?filters=is_admin")
1038
1039 users =
1040 [
1041 %{
1042 "deactivated" => false,
1043 "id" => admin.id,
1044 "nickname" => admin.nickname,
1045 "roles" => %{"admin" => true, "moderator" => false},
1046 "local" => admin.local,
1047 "tags" => [],
1048 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1049 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1050 "confirmation_pending" => false,
1051 "approval_pending" => false,
1052 "url" => admin.ap_id,
1053 "registration_reason" => nil
1054 },
1055 %{
1056 "deactivated" => false,
1057 "id" => second_admin.id,
1058 "nickname" => second_admin.nickname,
1059 "roles" => %{"admin" => true, "moderator" => false},
1060 "local" => second_admin.local,
1061 "tags" => [],
1062 "avatar" => User.avatar_url(second_admin) |> MediaProxy.url(),
1063 "display_name" => HTML.strip_tags(second_admin.name || second_admin.nickname),
1064 "confirmation_pending" => false,
1065 "approval_pending" => false,
1066 "url" => second_admin.ap_id,
1067 "registration_reason" => nil
1068 }
1069 ]
1070 |> Enum.sort_by(& &1["nickname"])
1071
1072 assert json_response(conn, 200) == %{
1073 "count" => 2,
1074 "page_size" => 50,
1075 "users" => users
1076 }
1077 end
1078
1079 test "load only moderators", %{conn: conn} do
1080 moderator = insert(:user, is_moderator: true)
1081 insert(:user)
1082 insert(:user)
1083
1084 conn = get(conn, "/api/pleroma/admin/users?filters=is_moderator")
1085
1086 assert json_response(conn, 200) == %{
1087 "count" => 1,
1088 "page_size" => 50,
1089 "users" => [
1090 %{
1091 "deactivated" => false,
1092 "id" => moderator.id,
1093 "nickname" => moderator.nickname,
1094 "roles" => %{"admin" => false, "moderator" => true},
1095 "local" => moderator.local,
1096 "tags" => [],
1097 "avatar" => User.avatar_url(moderator) |> MediaProxy.url(),
1098 "display_name" => HTML.strip_tags(moderator.name || moderator.nickname),
1099 "confirmation_pending" => false,
1100 "approval_pending" => false,
1101 "url" => moderator.ap_id,
1102 "registration_reason" => nil
1103 }
1104 ]
1105 }
1106 end
1107
1108 test "load users with tags list", %{conn: conn} do
1109 user1 = insert(:user, tags: ["first"])
1110 user2 = insert(:user, tags: ["second"])
1111 insert(:user)
1112 insert(:user)
1113
1114 conn = get(conn, "/api/pleroma/admin/users?tags[]=first&tags[]=second")
1115
1116 users =
1117 [
1118 %{
1119 "deactivated" => false,
1120 "id" => user1.id,
1121 "nickname" => user1.nickname,
1122 "roles" => %{"admin" => false, "moderator" => false},
1123 "local" => user1.local,
1124 "tags" => ["first"],
1125 "avatar" => User.avatar_url(user1) |> MediaProxy.url(),
1126 "display_name" => HTML.strip_tags(user1.name || user1.nickname),
1127 "confirmation_pending" => false,
1128 "approval_pending" => false,
1129 "url" => user1.ap_id,
1130 "registration_reason" => nil
1131 },
1132 %{
1133 "deactivated" => false,
1134 "id" => user2.id,
1135 "nickname" => user2.nickname,
1136 "roles" => %{"admin" => false, "moderator" => false},
1137 "local" => user2.local,
1138 "tags" => ["second"],
1139 "avatar" => User.avatar_url(user2) |> MediaProxy.url(),
1140 "display_name" => HTML.strip_tags(user2.name || user2.nickname),
1141 "confirmation_pending" => false,
1142 "approval_pending" => false,
1143 "url" => user2.ap_id,
1144 "registration_reason" => nil
1145 }
1146 ]
1147 |> Enum.sort_by(& &1["nickname"])
1148
1149 assert json_response(conn, 200) == %{
1150 "count" => 2,
1151 "page_size" => 50,
1152 "users" => users
1153 }
1154 end
1155
1156 test "it works with multiple filters" do
1157 admin = insert(:user, nickname: "john", is_admin: true)
1158 token = insert(:oauth_admin_token, user: admin)
1159 user = insert(:user, nickname: "bob", local: false, deactivated: true)
1160
1161 insert(:user, nickname: "ken", local: true, deactivated: true)
1162 insert(:user, nickname: "bobb", local: false, deactivated: false)
1163
1164 conn =
1165 build_conn()
1166 |> assign(:user, admin)
1167 |> assign(:token, token)
1168 |> get("/api/pleroma/admin/users?filters=deactivated,external")
1169
1170 assert json_response(conn, 200) == %{
1171 "count" => 1,
1172 "page_size" => 50,
1173 "users" => [
1174 %{
1175 "deactivated" => user.deactivated,
1176 "id" => user.id,
1177 "nickname" => user.nickname,
1178 "roles" => %{"admin" => false, "moderator" => false},
1179 "local" => user.local,
1180 "tags" => [],
1181 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1182 "display_name" => HTML.strip_tags(user.name || user.nickname),
1183 "confirmation_pending" => false,
1184 "approval_pending" => false,
1185 "url" => user.ap_id,
1186 "registration_reason" => nil
1187 }
1188 ]
1189 }
1190 end
1191
1192 test "it omits relay user", %{admin: admin, conn: conn} do
1193 assert %User{} = Relay.get_actor()
1194
1195 conn = get(conn, "/api/pleroma/admin/users")
1196
1197 assert json_response(conn, 200) == %{
1198 "count" => 1,
1199 "page_size" => 50,
1200 "users" => [
1201 %{
1202 "deactivated" => admin.deactivated,
1203 "id" => admin.id,
1204 "nickname" => admin.nickname,
1205 "roles" => %{"admin" => true, "moderator" => false},
1206 "local" => true,
1207 "tags" => [],
1208 "avatar" => User.avatar_url(admin) |> MediaProxy.url(),
1209 "display_name" => HTML.strip_tags(admin.name || admin.nickname),
1210 "confirmation_pending" => false,
1211 "approval_pending" => false,
1212 "url" => admin.ap_id,
1213 "registration_reason" => nil
1214 }
1215 ]
1216 }
1217 end
1218 end
1219
1220 test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do
1221 user_one = insert(:user, deactivated: true)
1222 user_two = insert(:user, deactivated: true)
1223
1224 conn =
1225 patch(
1226 conn,
1227 "/api/pleroma/admin/users/activate",
1228 %{nicknames: [user_one.nickname, user_two.nickname]}
1229 )
1230
1231 response = json_response(conn, 200)
1232 assert Enum.map(response["users"], & &1["deactivated"]) == [false, false]
1233
1234 log_entry = Repo.one(ModerationLog)
1235
1236 assert ModerationLog.get_log_entry_message(log_entry) ==
1237 "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}"
1238 end
1239
1240 test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do
1241 user_one = insert(:user, deactivated: false)
1242 user_two = insert(:user, deactivated: false)
1243
1244 conn =
1245 patch(
1246 conn,
1247 "/api/pleroma/admin/users/deactivate",
1248 %{nicknames: [user_one.nickname, user_two.nickname]}
1249 )
1250
1251 response = json_response(conn, 200)
1252 assert Enum.map(response["users"], & &1["deactivated"]) == [true, true]
1253
1254 log_entry = Repo.one(ModerationLog)
1255
1256 assert ModerationLog.get_log_entry_message(log_entry) ==
1257 "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}"
1258 end
1259
1260 test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do
1261 user_one = insert(:user, approval_pending: true)
1262 user_two = insert(:user, approval_pending: true)
1263
1264 conn =
1265 patch(
1266 conn,
1267 "/api/pleroma/admin/users/approve",
1268 %{nicknames: [user_one.nickname, user_two.nickname]}
1269 )
1270
1271 response = json_response(conn, 200)
1272 assert Enum.map(response["users"], & &1["approval_pending"]) == [false, false]
1273
1274 log_entry = Repo.one(ModerationLog)
1275
1276 assert ModerationLog.get_log_entry_message(log_entry) ==
1277 "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}"
1278 end
1279
1280 test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do
1281 user = insert(:user)
1282
1283 conn = patch(conn, "/api/pleroma/admin/users/#{user.nickname}/toggle_activation")
1284
1285 assert json_response(conn, 200) ==
1286 %{
1287 "deactivated" => !user.deactivated,
1288 "id" => user.id,
1289 "nickname" => user.nickname,
1290 "roles" => %{"admin" => false, "moderator" => false},
1291 "local" => true,
1292 "tags" => [],
1293 "avatar" => User.avatar_url(user) |> MediaProxy.url(),
1294 "display_name" => HTML.strip_tags(user.name || user.nickname),
1295 "confirmation_pending" => false,
1296 "approval_pending" => false,
1297 "url" => user.ap_id,
1298 "registration_reason" => nil
1299 }
1300
1301 log_entry = Repo.one(ModerationLog)
1302
1303 assert ModerationLog.get_log_entry_message(log_entry) ==
1304 "@#{admin.nickname} deactivated users: @#{user.nickname}"
1305 end
1306
1307 describe "PUT disable_mfa" do
1308 test "returns 200 and disable 2fa", %{conn: conn} do
1309 user =
1310 insert(:user,
1311 multi_factor_authentication_settings: %MFA.Settings{
1312 enabled: true,
1313 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
1314 }
1315 )
1316
1317 response =
1318 conn
1319 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
1320 |> json_response(200)
1321
1322 assert response == user.nickname
1323 mfa_settings = refresh_record(user).multi_factor_authentication_settings
1324
1325 refute mfa_settings.enabled
1326 refute mfa_settings.totp.confirmed
1327 end
1328
1329 test "returns 404 if user not found", %{conn: conn} do
1330 response =
1331 conn
1332 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
1333 |> json_response(404)
1334
1335 assert response == %{"error" => "Not found"}
1336 end
1337 end
1338
1339 describe "GET /api/pleroma/admin/restart" do
1340 setup do: clear_config(:configurable_from_database, true)
1341
1342 test "pleroma restarts", %{conn: conn} do
1343 capture_log(fn ->
1344 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
1345 end) =~ "pleroma restarted"
1346
1347 refute Restarter.Pleroma.need_reboot?()
1348 end
1349 end
1350
1351 test "need_reboot flag", %{conn: conn} do
1352 assert conn
1353 |> get("/api/pleroma/admin/need_reboot")
1354 |> json_response(200) == %{"need_reboot" => false}
1355
1356 Restarter.Pleroma.need_reboot()
1357
1358 assert conn
1359 |> get("/api/pleroma/admin/need_reboot")
1360 |> json_response(200) == %{"need_reboot" => true}
1361
1362 on_exit(fn -> Restarter.Pleroma.refresh() end)
1363 end
1364
1365 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
1366 setup do
1367 user = insert(:user)
1368
1369 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
1370 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
1371 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
1372
1373 insert(:note_activity, user: user, published: date1)
1374 insert(:note_activity, user: user, published: date2)
1375 insert(:note_activity, user: user, published: date3)
1376
1377 %{user: user}
1378 end
1379
1380 test "renders user's statuses", %{conn: conn, user: user} do
1381 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1382
1383 assert json_response(conn, 200) |> length() == 3
1384 end
1385
1386 test "renders user's statuses with a limit", %{conn: conn, user: user} do
1387 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
1388
1389 assert json_response(conn, 200) |> length() == 2
1390 end
1391
1392 test "doesn't return private statuses by default", %{conn: conn, user: user} do
1393 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1394
1395 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1396
1397 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
1398
1399 assert json_response(conn, 200) |> length() == 4
1400 end
1401
1402 test "returns private statuses with godmode on", %{conn: conn, user: user} do
1403 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
1404
1405 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
1406
1407 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
1408
1409 assert json_response(conn, 200) |> length() == 5
1410 end
1411
1412 test "excludes reblogs by default", %{conn: conn, user: user} do
1413 other_user = insert(:user)
1414 {:ok, activity} = CommonAPI.post(user, %{status: "."})
1415 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
1416
1417 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
1418 assert json_response(conn_res, 200) |> length() == 0
1419
1420 conn_res =
1421 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
1422
1423 assert json_response(conn_res, 200) |> length() == 1
1424 end
1425 end
1426
1427 describe "GET /api/pleroma/admin/moderation_log" do
1428 setup do
1429 moderator = insert(:user, is_moderator: true)
1430
1431 %{moderator: moderator}
1432 end
1433
1434 test "returns the log", %{conn: conn, admin: admin} do
1435 Repo.insert(%ModerationLog{
1436 data: %{
1437 actor: %{
1438 "id" => admin.id,
1439 "nickname" => admin.nickname,
1440 "type" => "user"
1441 },
1442 action: "relay_follow",
1443 target: "https://example.org/relay"
1444 },
1445 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1446 })
1447
1448 Repo.insert(%ModerationLog{
1449 data: %{
1450 actor: %{
1451 "id" => admin.id,
1452 "nickname" => admin.nickname,
1453 "type" => "user"
1454 },
1455 action: "relay_unfollow",
1456 target: "https://example.org/relay"
1457 },
1458 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1459 })
1460
1461 conn = get(conn, "/api/pleroma/admin/moderation_log")
1462
1463 response = json_response(conn, 200)
1464 [first_entry, second_entry] = response["items"]
1465
1466 assert response["total"] == 2
1467 assert first_entry["data"]["action"] == "relay_unfollow"
1468
1469 assert first_entry["message"] ==
1470 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1471
1472 assert second_entry["data"]["action"] == "relay_follow"
1473
1474 assert second_entry["message"] ==
1475 "@#{admin.nickname} followed relay: https://example.org/relay"
1476 end
1477
1478 test "returns the log with pagination", %{conn: conn, admin: admin} do
1479 Repo.insert(%ModerationLog{
1480 data: %{
1481 actor: %{
1482 "id" => admin.id,
1483 "nickname" => admin.nickname,
1484 "type" => "user"
1485 },
1486 action: "relay_follow",
1487 target: "https://example.org/relay"
1488 },
1489 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
1490 })
1491
1492 Repo.insert(%ModerationLog{
1493 data: %{
1494 actor: %{
1495 "id" => admin.id,
1496 "nickname" => admin.nickname,
1497 "type" => "user"
1498 },
1499 action: "relay_unfollow",
1500 target: "https://example.org/relay"
1501 },
1502 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
1503 })
1504
1505 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
1506
1507 response1 = json_response(conn1, 200)
1508 [first_entry] = response1["items"]
1509
1510 assert response1["total"] == 2
1511 assert response1["items"] |> length() == 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
1517 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
1518
1519 response2 = json_response(conn2, 200)
1520 [second_entry] = response2["items"]
1521
1522 assert response2["total"] == 2
1523 assert response2["items"] |> length() == 1
1524 assert second_entry["data"]["action"] == "relay_follow"
1525
1526 assert second_entry["message"] ==
1527 "@#{admin.nickname} followed relay: https://example.org/relay"
1528 end
1529
1530 test "filters log by date", %{conn: conn, admin: admin} do
1531 first_date = "2017-08-15T15:47:06Z"
1532 second_date = "2017-08-20T15:47:06Z"
1533
1534 Repo.insert(%ModerationLog{
1535 data: %{
1536 actor: %{
1537 "id" => admin.id,
1538 "nickname" => admin.nickname,
1539 "type" => "user"
1540 },
1541 action: "relay_follow",
1542 target: "https://example.org/relay"
1543 },
1544 inserted_at: NaiveDateTime.from_iso8601!(first_date)
1545 })
1546
1547 Repo.insert(%ModerationLog{
1548 data: %{
1549 actor: %{
1550 "id" => admin.id,
1551 "nickname" => admin.nickname,
1552 "type" => "user"
1553 },
1554 action: "relay_unfollow",
1555 target: "https://example.org/relay"
1556 },
1557 inserted_at: NaiveDateTime.from_iso8601!(second_date)
1558 })
1559
1560 conn1 =
1561 get(
1562 conn,
1563 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
1564 )
1565
1566 response1 = json_response(conn1, 200)
1567 [first_entry] = response1["items"]
1568
1569 assert response1["total"] == 1
1570 assert first_entry["data"]["action"] == "relay_unfollow"
1571
1572 assert first_entry["message"] ==
1573 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
1574 end
1575
1576 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
1577 Repo.insert(%ModerationLog{
1578 data: %{
1579 actor: %{
1580 "id" => admin.id,
1581 "nickname" => admin.nickname,
1582 "type" => "user"
1583 },
1584 action: "relay_follow",
1585 target: "https://example.org/relay"
1586 }
1587 })
1588
1589 Repo.insert(%ModerationLog{
1590 data: %{
1591 actor: %{
1592 "id" => moderator.id,
1593 "nickname" => moderator.nickname,
1594 "type" => "user"
1595 },
1596 action: "relay_unfollow",
1597 target: "https://example.org/relay"
1598 }
1599 })
1600
1601 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
1602
1603 response1 = json_response(conn1, 200)
1604 [first_entry] = response1["items"]
1605
1606 assert response1["total"] == 1
1607 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
1608 end
1609
1610 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
1611 ModerationLog.insert_log(%{
1612 actor: moderator,
1613 action: "relay_follow",
1614 target: "https://example.org/relay"
1615 })
1616
1617 ModerationLog.insert_log(%{
1618 actor: moderator,
1619 action: "relay_unfollow",
1620 target: "https://example.org/relay"
1621 })
1622
1623 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
1624
1625 response1 = json_response(conn1, 200)
1626 [first_entry] = response1["items"]
1627
1628 assert response1["total"] == 1
1629
1630 assert get_in(first_entry, ["data", "message"]) ==
1631 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
1632 end
1633 end
1634
1635 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
1636 %{conn: conn} do
1637 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
1638 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
1639 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1640
1641 assert json_response(conn, 200)
1642 end
1643
1644 describe "GET /users/:nickname/credentials" do
1645 test "gets the user credentials", %{conn: conn} do
1646 user = insert(:user)
1647 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
1648
1649 response = assert json_response(conn, 200)
1650 assert response["email"] == user.email
1651 end
1652
1653 test "returns 403 if requested by a non-admin" do
1654 user = insert(:user)
1655
1656 conn =
1657 build_conn()
1658 |> assign(:user, user)
1659 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
1660
1661 assert json_response(conn, :forbidden)
1662 end
1663 end
1664
1665 describe "PATCH /users/:nickname/credentials" do
1666 setup do
1667 user = insert(:user)
1668 [user: user]
1669 end
1670
1671 test "changes password and email", %{conn: conn, admin: admin, user: user} do
1672 assert user.password_reset_pending == false
1673
1674 conn =
1675 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1676 "password" => "new_password",
1677 "email" => "new_email@example.com",
1678 "name" => "new_name"
1679 })
1680
1681 assert json_response(conn, 200) == %{"status" => "success"}
1682
1683 ObanHelpers.perform_all()
1684
1685 updated_user = User.get_by_id(user.id)
1686
1687 assert updated_user.email == "new_email@example.com"
1688 assert updated_user.name == "new_name"
1689 assert updated_user.password_hash != user.password_hash
1690 assert updated_user.password_reset_pending == true
1691
1692 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
1693
1694 assert ModerationLog.get_log_entry_message(log_entry1) ==
1695 "@#{admin.nickname} updated users: @#{user.nickname}"
1696
1697 assert ModerationLog.get_log_entry_message(log_entry2) ==
1698 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
1699 end
1700
1701 test "returns 403 if requested by a non-admin", %{user: user} do
1702 conn =
1703 build_conn()
1704 |> assign(:user, user)
1705 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1706 "password" => "new_password",
1707 "email" => "new_email@example.com",
1708 "name" => "new_name"
1709 })
1710
1711 assert json_response(conn, :forbidden)
1712 end
1713
1714 test "changes actor type from permitted list", %{conn: conn, user: user} do
1715 assert user.actor_type == "Person"
1716
1717 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1718 "actor_type" => "Service"
1719 })
1720 |> json_response(200) == %{"status" => "success"}
1721
1722 updated_user = User.get_by_id(user.id)
1723
1724 assert updated_user.actor_type == "Service"
1725
1726 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
1727 "actor_type" => "Application"
1728 })
1729 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
1730 end
1731
1732 test "update non existing user", %{conn: conn} do
1733 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
1734 "password" => "new_password"
1735 })
1736 |> json_response(404) == %{"error" => "Not found"}
1737 end
1738 end
1739
1740 describe "PATCH /users/:nickname/force_password_reset" do
1741 test "sets password_reset_pending to true", %{conn: conn} do
1742 user = insert(:user)
1743 assert user.password_reset_pending == false
1744
1745 conn =
1746 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
1747
1748 assert json_response(conn, 204) == ""
1749
1750 ObanHelpers.perform_all()
1751
1752 assert User.get_by_id(user.id).password_reset_pending == true
1753 end
1754 end
1755
1756 describe "instances" do
1757 test "GET /instances/:instance/statuses", %{conn: conn} do
1758 user = insert(:user, local: false, nickname: "archaeme@archae.me")
1759 user2 = insert(:user, local: false, nickname: "test@test.com")
1760 insert_pair(:note_activity, user: user)
1761 activity = insert(:note_activity, user: user2)
1762
1763 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1764
1765 response = json_response(ret_conn, 200)
1766
1767 assert length(response) == 2
1768
1769 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
1770
1771 response = json_response(ret_conn, 200)
1772
1773 assert length(response) == 1
1774
1775 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
1776
1777 response = json_response(ret_conn, 200)
1778
1779 assert Enum.empty?(response)
1780
1781 CommonAPI.repeat(activity.id, user)
1782
1783 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
1784 response = json_response(ret_conn, 200)
1785 assert length(response) == 2
1786
1787 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
1788 response = json_response(ret_conn, 200)
1789 assert length(response) == 3
1790 end
1791 end
1792
1793 describe "PATCH /confirm_email" do
1794 test "it confirms emails of two users", %{conn: conn, admin: admin} do
1795 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1796
1797 assert first_user.confirmation_pending == true
1798 assert second_user.confirmation_pending == true
1799
1800 ret_conn =
1801 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
1802 nicknames: [
1803 first_user.nickname,
1804 second_user.nickname
1805 ]
1806 })
1807
1808 assert ret_conn.status == 200
1809
1810 assert first_user.confirmation_pending == true
1811 assert second_user.confirmation_pending == true
1812
1813 log_entry = Repo.one(ModerationLog)
1814
1815 assert ModerationLog.get_log_entry_message(log_entry) ==
1816 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
1817 second_user.nickname
1818 }"
1819 end
1820 end
1821
1822 describe "PATCH /resend_confirmation_email" do
1823 test "it resend emails for two users", %{conn: conn, admin: admin} do
1824 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
1825
1826 ret_conn =
1827 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
1828 nicknames: [
1829 first_user.nickname,
1830 second_user.nickname
1831 ]
1832 })
1833
1834 assert ret_conn.status == 200
1835
1836 log_entry = Repo.one(ModerationLog)
1837
1838 assert ModerationLog.get_log_entry_message(log_entry) ==
1839 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
1840 second_user.nickname
1841 }"
1842 end
1843 end
1844
1845 describe "/api/pleroma/admin/stats" do
1846 test "status visibility count", %{conn: conn} do
1847 admin = insert(:user, is_admin: true)
1848 user = insert(:user)
1849 CommonAPI.post(user, %{visibility: "public", status: "hey"})
1850 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1851 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
1852
1853 response =
1854 conn
1855 |> assign(:user, admin)
1856 |> get("/api/pleroma/admin/stats")
1857 |> json_response(200)
1858
1859 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
1860 response["status_visibility"]
1861 end
1862
1863 test "by instance", %{conn: conn} do
1864 admin = insert(:user, is_admin: true)
1865 user1 = insert(:user)
1866 instance2 = "instance2.tld"
1867 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
1868
1869 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
1870 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
1871 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
1872
1873 response =
1874 conn
1875 |> assign(:user, admin)
1876 |> get("/api/pleroma/admin/stats", instance: instance2)
1877 |> json_response(200)
1878
1879 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
1880 response["status_visibility"]
1881 end
1882 end
1883 end
1884
1885 # Needed for testing
1886 defmodule Pleroma.Web.Endpoint.NotReal do
1887 end
1888
1889 defmodule Pleroma.Captcha.NotReal do
1890 end