Add OpenAPI spec for StatusController
[akkoma] / lib / pleroma / web / admin_api / admin_api_controller.ex
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.AdminAPIController do
6 use Pleroma.Web, :controller
7
8 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
9
10 alias Pleroma.Activity
11 alias Pleroma.Config
12 alias Pleroma.ConfigDB
13 alias Pleroma.MFA
14 alias Pleroma.ModerationLog
15 alias Pleroma.Plugs.OAuthScopesPlug
16 alias Pleroma.ReportNote
17 alias Pleroma.Stats
18 alias Pleroma.User
19 alias Pleroma.UserInviteToken
20 alias Pleroma.Web.ActivityPub.ActivityPub
21 alias Pleroma.Web.ActivityPub.Builder
22 alias Pleroma.Web.ActivityPub.Pipeline
23 alias Pleroma.Web.ActivityPub.Relay
24 alias Pleroma.Web.ActivityPub.Utils
25 alias Pleroma.Web.AdminAPI.AccountView
26 alias Pleroma.Web.AdminAPI.ConfigView
27 alias Pleroma.Web.AdminAPI.ModerationLogView
28 alias Pleroma.Web.AdminAPI.Report
29 alias Pleroma.Web.AdminAPI.ReportView
30 alias Pleroma.Web.AdminAPI.Search
31 alias Pleroma.Web.CommonAPI
32 alias Pleroma.Web.Endpoint
33 alias Pleroma.Web.MastodonAPI.AppView
34 alias Pleroma.Web.MastodonAPI.StatusView
35 alias Pleroma.Web.OAuth.App
36 alias Pleroma.Web.Router
37
38 require Logger
39
40 @descriptions_json Pleroma.Docs.JSON.compile()
41 @users_page_size 50
42
43 plug(
44 OAuthScopesPlug,
45 %{scopes: ["read:accounts"], admin: true}
46 when action in [:list_users, :user_show, :right_get, :show_user_credentials]
47 )
48
49 plug(
50 OAuthScopesPlug,
51 %{scopes: ["write:accounts"], admin: true}
52 when action in [
53 :get_password_reset,
54 :force_password_reset,
55 :user_delete,
56 :users_create,
57 :user_toggle_activation,
58 :user_activate,
59 :user_deactivate,
60 :tag_users,
61 :untag_users,
62 :right_add,
63 :right_add_multiple,
64 :right_delete,
65 :disable_mfa,
66 :right_delete_multiple,
67 :update_user_credentials
68 ]
69 )
70
71 plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites)
72
73 plug(
74 OAuthScopesPlug,
75 %{scopes: ["write:invites"], admin: true}
76 when action in [:create_invite_token, :revoke_invite, :email_invite]
77 )
78
79 plug(
80 OAuthScopesPlug,
81 %{scopes: ["write:follows"], admin: true}
82 when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow]
83 )
84
85 plug(
86 OAuthScopesPlug,
87 %{scopes: ["read:reports"], admin: true}
88 when action in [:list_reports, :report_show]
89 )
90
91 plug(
92 OAuthScopesPlug,
93 %{scopes: ["write:reports"], admin: true}
94 when action in [:reports_update, :report_notes_create, :report_notes_delete]
95 )
96
97 plug(
98 OAuthScopesPlug,
99 %{scopes: ["read:statuses"], admin: true}
100 when action in [:list_statuses, :list_user_statuses, :list_instance_statuses, :status_show]
101 )
102
103 plug(
104 OAuthScopesPlug,
105 %{scopes: ["write:statuses"], admin: true}
106 when action in [:status_update, :status_delete]
107 )
108
109 plug(
110 OAuthScopesPlug,
111 %{scopes: ["read"], admin: true}
112 when action in [
113 :config_show,
114 :list_log,
115 :stats,
116 :relay_list,
117 :config_descriptions,
118 :need_reboot
119 ]
120 )
121
122 plug(
123 OAuthScopesPlug,
124 %{scopes: ["write"], admin: true}
125 when action in [
126 :restart,
127 :config_update,
128 :resend_confirmation_email,
129 :confirm_email,
130 :oauth_app_create,
131 :oauth_app_list,
132 :oauth_app_update,
133 :oauth_app_delete,
134 :reload_emoji
135 ]
136 )
137
138 action_fallback(:errors)
139
140 def user_delete(conn, %{"nickname" => nickname}) do
141 user_delete(conn, %{"nicknames" => [nickname]})
142 end
143
144 def user_delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
145 users =
146 nicknames
147 |> Enum.map(&User.get_cached_by_nickname/1)
148
149 users
150 |> Enum.each(fn user ->
151 {:ok, delete_data, _} = Builder.delete(admin, user.ap_id)
152 Pipeline.common_pipeline(delete_data, local: true)
153 end)
154
155 ModerationLog.insert_log(%{
156 actor: admin,
157 subject: users,
158 action: "delete"
159 })
160
161 conn
162 |> json(nicknames)
163 end
164
165 def user_follow(%{assigns: %{user: admin}} = conn, %{
166 "follower" => follower_nick,
167 "followed" => followed_nick
168 }) do
169 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
170 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
171 User.follow(follower, followed)
172
173 ModerationLog.insert_log(%{
174 actor: admin,
175 followed: followed,
176 follower: follower,
177 action: "follow"
178 })
179 end
180
181 conn
182 |> json("ok")
183 end
184
185 def user_unfollow(%{assigns: %{user: admin}} = conn, %{
186 "follower" => follower_nick,
187 "followed" => followed_nick
188 }) do
189 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
190 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
191 User.unfollow(follower, followed)
192
193 ModerationLog.insert_log(%{
194 actor: admin,
195 followed: followed,
196 follower: follower,
197 action: "unfollow"
198 })
199 end
200
201 conn
202 |> json("ok")
203 end
204
205 def users_create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
206 changesets =
207 Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
208 user_data = %{
209 nickname: nickname,
210 name: nickname,
211 email: email,
212 password: password,
213 password_confirmation: password,
214 bio: "."
215 }
216
217 User.register_changeset(%User{}, user_data, need_confirmation: false)
218 end)
219 |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
220 Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
221 end)
222
223 case Pleroma.Repo.transaction(changesets) do
224 {:ok, users} ->
225 res =
226 users
227 |> Map.values()
228 |> Enum.map(fn user ->
229 {:ok, user} = User.post_register_action(user)
230
231 user
232 end)
233 |> Enum.map(&AccountView.render("created.json", %{user: &1}))
234
235 ModerationLog.insert_log(%{
236 actor: admin,
237 subjects: Map.values(users),
238 action: "create"
239 })
240
241 conn
242 |> json(res)
243
244 {:error, id, changeset, _} ->
245 res =
246 Enum.map(changesets.operations, fn
247 {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
248 AccountView.render("create-error.json", %{changeset: changeset})
249
250 {_, {:changeset, current_changeset, _}} ->
251 AccountView.render("create-error.json", %{changeset: current_changeset})
252 end)
253
254 conn
255 |> put_status(:conflict)
256 |> json(res)
257 end
258 end
259
260 def user_show(conn, %{"nickname" => nickname}) do
261 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
262 conn
263 |> put_view(AccountView)
264 |> render("show.json", %{user: user})
265 else
266 _ -> {:error, :not_found}
267 end
268 end
269
270 def list_instance_statuses(conn, %{"instance" => instance} = params) do
271 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
272 {page, page_size} = page_params(params)
273
274 activities =
275 ActivityPub.fetch_statuses(nil, %{
276 "instance" => instance,
277 "limit" => page_size,
278 "offset" => (page - 1) * page_size,
279 "exclude_reblogs" => !with_reblogs && "true"
280 })
281
282 conn
283 |> put_view(Pleroma.Web.AdminAPI.StatusView)
284 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
285 end
286
287 def list_user_statuses(conn, %{"nickname" => nickname} = params) do
288 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
289 godmode = params["godmode"] == "true" || params["godmode"] == true
290
291 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
292 {_, page_size} = page_params(params)
293
294 activities =
295 ActivityPub.fetch_user_activities(user, nil, %{
296 "limit" => page_size,
297 "godmode" => godmode,
298 "exclude_reblogs" => !with_reblogs && "true"
299 })
300
301 conn
302 |> put_view(StatusView)
303 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
304 else
305 _ -> {:error, :not_found}
306 end
307 end
308
309 def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
310 user = User.get_cached_by_nickname(nickname)
311
312 {:ok, updated_user} = User.deactivate(user, !user.deactivated)
313
314 action = if user.deactivated, do: "activate", else: "deactivate"
315
316 ModerationLog.insert_log(%{
317 actor: admin,
318 subject: [user],
319 action: action
320 })
321
322 conn
323 |> put_view(AccountView)
324 |> render("show.json", %{user: updated_user})
325 end
326
327 def user_activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
328 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
329 {:ok, updated_users} = User.deactivate(users, false)
330
331 ModerationLog.insert_log(%{
332 actor: admin,
333 subject: users,
334 action: "activate"
335 })
336
337 conn
338 |> put_view(AccountView)
339 |> render("index.json", %{users: Keyword.values(updated_users)})
340 end
341
342 def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
343 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
344 {:ok, updated_users} = User.deactivate(users, true)
345
346 ModerationLog.insert_log(%{
347 actor: admin,
348 subject: users,
349 action: "deactivate"
350 })
351
352 conn
353 |> put_view(AccountView)
354 |> render("index.json", %{users: Keyword.values(updated_users)})
355 end
356
357 def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
358 with {:ok, _} <- User.tag(nicknames, tags) do
359 ModerationLog.insert_log(%{
360 actor: admin,
361 nicknames: nicknames,
362 tags: tags,
363 action: "tag"
364 })
365
366 json_response(conn, :no_content, "")
367 end
368 end
369
370 def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
371 with {:ok, _} <- User.untag(nicknames, tags) do
372 ModerationLog.insert_log(%{
373 actor: admin,
374 nicknames: nicknames,
375 tags: tags,
376 action: "untag"
377 })
378
379 json_response(conn, :no_content, "")
380 end
381 end
382
383 def list_users(conn, params) do
384 {page, page_size} = page_params(params)
385 filters = maybe_parse_filters(params["filters"])
386
387 search_params = %{
388 query: params["query"],
389 page: page,
390 page_size: page_size,
391 tags: params["tags"],
392 name: params["name"],
393 email: params["email"]
394 }
395
396 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)) do
397 json(
398 conn,
399 AccountView.render("index.json", users: users, count: count, page_size: page_size)
400 )
401 end
402 end
403
404 @filters ~w(local external active deactivated is_admin is_moderator)
405
406 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
407 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
408
409 defp maybe_parse_filters(filters) do
410 filters
411 |> String.split(",")
412 |> Enum.filter(&Enum.member?(@filters, &1))
413 |> Enum.map(&String.to_atom(&1))
414 |> Enum.into(%{}, &{&1, true})
415 end
416
417 def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
418 "permission_group" => permission_group,
419 "nicknames" => nicknames
420 })
421 when permission_group in ["moderator", "admin"] do
422 update = %{:"is_#{permission_group}" => true}
423
424 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
425
426 for u <- users, do: User.admin_api_update(u, update)
427
428 ModerationLog.insert_log(%{
429 action: "grant",
430 actor: admin,
431 subject: users,
432 permission: permission_group
433 })
434
435 json(conn, update)
436 end
437
438 def right_add_multiple(conn, _) do
439 render_error(conn, :not_found, "No such permission_group")
440 end
441
442 def right_add(%{assigns: %{user: admin}} = conn, %{
443 "permission_group" => permission_group,
444 "nickname" => nickname
445 })
446 when permission_group in ["moderator", "admin"] do
447 fields = %{:"is_#{permission_group}" => true}
448
449 {:ok, user} =
450 nickname
451 |> User.get_cached_by_nickname()
452 |> User.admin_api_update(fields)
453
454 ModerationLog.insert_log(%{
455 action: "grant",
456 actor: admin,
457 subject: [user],
458 permission: permission_group
459 })
460
461 json(conn, fields)
462 end
463
464 def right_add(conn, _) do
465 render_error(conn, :not_found, "No such permission_group")
466 end
467
468 def right_get(conn, %{"nickname" => nickname}) do
469 user = User.get_cached_by_nickname(nickname)
470
471 conn
472 |> json(%{
473 is_moderator: user.is_moderator,
474 is_admin: user.is_admin
475 })
476 end
477
478 def right_delete_multiple(
479 %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
480 %{
481 "permission_group" => permission_group,
482 "nicknames" => nicknames
483 }
484 )
485 when permission_group in ["moderator", "admin"] do
486 with false <- Enum.member?(nicknames, admin_nickname) do
487 update = %{:"is_#{permission_group}" => false}
488
489 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
490
491 for u <- users, do: User.admin_api_update(u, update)
492
493 ModerationLog.insert_log(%{
494 action: "revoke",
495 actor: admin,
496 subject: users,
497 permission: permission_group
498 })
499
500 json(conn, update)
501 else
502 _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
503 end
504 end
505
506 def right_delete_multiple(conn, _) do
507 render_error(conn, :not_found, "No such permission_group")
508 end
509
510 def right_delete(
511 %{assigns: %{user: admin}} = conn,
512 %{
513 "permission_group" => permission_group,
514 "nickname" => nickname
515 }
516 )
517 when permission_group in ["moderator", "admin"] do
518 fields = %{:"is_#{permission_group}" => false}
519
520 {:ok, user} =
521 nickname
522 |> User.get_cached_by_nickname()
523 |> User.admin_api_update(fields)
524
525 ModerationLog.insert_log(%{
526 action: "revoke",
527 actor: admin,
528 subject: [user],
529 permission: permission_group
530 })
531
532 json(conn, fields)
533 end
534
535 def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
536 render_error(conn, :forbidden, "You can't revoke your own admin status.")
537 end
538
539 def relay_list(conn, _params) do
540 with {:ok, list} <- Relay.list() do
541 json(conn, %{relays: list})
542 else
543 _ ->
544 conn
545 |> put_status(500)
546 end
547 end
548
549 def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
550 with {:ok, _message} <- Relay.follow(target) do
551 ModerationLog.insert_log(%{
552 action: "relay_follow",
553 actor: admin,
554 target: target
555 })
556
557 json(conn, target)
558 else
559 _ ->
560 conn
561 |> put_status(500)
562 |> json(target)
563 end
564 end
565
566 def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
567 with {:ok, _message} <- Relay.unfollow(target) do
568 ModerationLog.insert_log(%{
569 action: "relay_unfollow",
570 actor: admin,
571 target: target
572 })
573
574 json(conn, target)
575 else
576 _ ->
577 conn
578 |> put_status(500)
579 |> json(target)
580 end
581 end
582
583 @doc "Sends registration invite via email"
584 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
585 with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
586 {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
587 {:ok, invite_token} <- UserInviteToken.create_invite(),
588 email <-
589 Pleroma.Emails.UserEmail.user_invitation_email(
590 user,
591 invite_token,
592 email,
593 params["name"]
594 ),
595 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
596 json_response(conn, :no_content, "")
597 else
598 {:registrations_open, _} ->
599 errors(
600 conn,
601 {:error, "To send invites you need to set the `registrations_open` option to false."}
602 )
603
604 {:invites_enabled, _} ->
605 errors(
606 conn,
607 {:error, "To send invites you need to set the `invites_enabled` option to true."}
608 )
609 end
610 end
611
612 @doc "Create an account registration invite token"
613 def create_invite_token(conn, params) do
614 opts = %{}
615
616 opts =
617 if params["max_use"],
618 do: Map.put(opts, :max_use, params["max_use"]),
619 else: opts
620
621 opts =
622 if params["expires_at"],
623 do: Map.put(opts, :expires_at, params["expires_at"]),
624 else: opts
625
626 {:ok, invite} = UserInviteToken.create_invite(opts)
627
628 json(conn, AccountView.render("invite.json", %{invite: invite}))
629 end
630
631 @doc "Get list of created invites"
632 def invites(conn, _params) do
633 invites = UserInviteToken.list_invites()
634
635 conn
636 |> put_view(AccountView)
637 |> render("invites.json", %{invites: invites})
638 end
639
640 @doc "Revokes invite by token"
641 def revoke_invite(conn, %{"token" => token}) do
642 with {:ok, invite} <- UserInviteToken.find_by_token(token),
643 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
644 conn
645 |> put_view(AccountView)
646 |> render("invite.json", %{invite: updated_invite})
647 else
648 nil -> {:error, :not_found}
649 end
650 end
651
652 @doc "Get a password reset token (base64 string) for given nickname"
653 def get_password_reset(conn, %{"nickname" => nickname}) do
654 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
655 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
656
657 conn
658 |> json(%{
659 token: token.token,
660 link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
661 })
662 end
663
664 @doc "Force password reset for a given user"
665 def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
666 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
667
668 Enum.each(users, &User.force_password_reset_async/1)
669
670 ModerationLog.insert_log(%{
671 actor: admin,
672 subject: users,
673 action: "force_password_reset"
674 })
675
676 json_response(conn, :no_content, "")
677 end
678
679 @doc "Disable mfa for user's account."
680 def disable_mfa(conn, %{"nickname" => nickname}) do
681 case User.get_by_nickname(nickname) do
682 %User{} = user ->
683 MFA.disable(user)
684 json(conn, nickname)
685
686 _ ->
687 {:error, :not_found}
688 end
689 end
690
691 @doc "Show a given user's credentials"
692 def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
693 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
694 conn
695 |> put_view(AccountView)
696 |> render("credentials.json", %{user: user, for: admin})
697 else
698 _ -> {:error, :not_found}
699 end
700 end
701
702 @doc "Updates a given user"
703 def update_user_credentials(
704 %{assigns: %{user: admin}} = conn,
705 %{"nickname" => nickname} = params
706 ) do
707 with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
708 {:ok, _user} <-
709 User.update_as_admin(user, params) do
710 ModerationLog.insert_log(%{
711 actor: admin,
712 subject: [user],
713 action: "updated_users"
714 })
715
716 if params["password"] do
717 User.force_password_reset_async(user)
718 end
719
720 ModerationLog.insert_log(%{
721 actor: admin,
722 subject: [user],
723 action: "force_password_reset"
724 })
725
726 json(conn, %{status: "success"})
727 else
728 {:error, changeset} ->
729 {_, {error, _}} = Enum.at(changeset.errors, 0)
730 json(conn, %{error: "New password #{error}."})
731
732 _ ->
733 json(conn, %{error: "Unable to change password."})
734 end
735 end
736
737 def list_reports(conn, params) do
738 {page, page_size} = page_params(params)
739
740 reports = Utils.get_reports(params, page, page_size)
741
742 conn
743 |> put_view(ReportView)
744 |> render("index.json", %{reports: reports})
745 end
746
747 def report_show(conn, %{"id" => id}) do
748 with %Activity{} = report <- Activity.get_by_id(id) do
749 conn
750 |> put_view(ReportView)
751 |> render("show.json", Report.extract_report_info(report))
752 else
753 _ -> {:error, :not_found}
754 end
755 end
756
757 def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
758 result =
759 reports
760 |> Enum.map(fn report ->
761 with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
762 ModerationLog.insert_log(%{
763 action: "report_update",
764 actor: admin,
765 subject: activity
766 })
767
768 activity
769 else
770 {:error, message} -> %{id: report["id"], error: message}
771 end
772 end)
773
774 case Enum.any?(result, &Map.has_key?(&1, :error)) do
775 true -> json_response(conn, :bad_request, result)
776 false -> json_response(conn, :no_content, "")
777 end
778 end
779
780 def report_notes_create(%{assigns: %{user: user}} = conn, %{
781 "id" => report_id,
782 "content" => content
783 }) do
784 with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
785 ModerationLog.insert_log(%{
786 action: "report_note",
787 actor: user,
788 subject: Activity.get_by_id(report_id),
789 text: content
790 })
791
792 json_response(conn, :no_content, "")
793 else
794 _ -> json_response(conn, :bad_request, "")
795 end
796 end
797
798 def report_notes_delete(%{assigns: %{user: user}} = conn, %{
799 "id" => note_id,
800 "report_id" => report_id
801 }) do
802 with {:ok, note} <- ReportNote.destroy(note_id) do
803 ModerationLog.insert_log(%{
804 action: "report_note_delete",
805 actor: user,
806 subject: Activity.get_by_id(report_id),
807 text: note.content
808 })
809
810 json_response(conn, :no_content, "")
811 else
812 _ -> json_response(conn, :bad_request, "")
813 end
814 end
815
816 def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
817 godmode = params["godmode"] == "true" || params["godmode"] == true
818 local_only = params["local_only"] == "true" || params["local_only"] == true
819 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
820 {page, page_size} = page_params(params)
821
822 activities =
823 ActivityPub.fetch_statuses(nil, %{
824 "godmode" => godmode,
825 "local_only" => local_only,
826 "limit" => page_size,
827 "offset" => (page - 1) * page_size,
828 "exclude_reblogs" => !with_reblogs && "true"
829 })
830
831 conn
832 |> put_view(Pleroma.Web.AdminAPI.StatusView)
833 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
834 end
835
836 def status_show(conn, %{"id" => id}) do
837 with %Activity{} = activity <- Activity.get_by_id(id) do
838 conn
839 |> put_view(StatusView)
840 |> render("show.json", %{activity: activity})
841 else
842 _ -> errors(conn, {:error, :not_found})
843 end
844 end
845
846 def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
847 params =
848 params
849 |> Map.take(["sensitive", "visibility"])
850 |> Map.new(fn {key, value} -> {String.to_existing_atom(key), value} end)
851
852 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
853 {:ok, sensitive} = Ecto.Type.cast(:boolean, params[:sensitive])
854
855 ModerationLog.insert_log(%{
856 action: "status_update",
857 actor: admin,
858 subject: activity,
859 sensitive: sensitive,
860 visibility: params[:visibility]
861 })
862
863 conn
864 |> put_view(StatusView)
865 |> render("show.json", %{activity: activity})
866 end
867 end
868
869 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
870 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
871 ModerationLog.insert_log(%{
872 action: "status_delete",
873 actor: user,
874 subject_id: id
875 })
876
877 json(conn, %{})
878 end
879 end
880
881 def list_log(conn, params) do
882 {page, page_size} = page_params(params)
883
884 log =
885 ModerationLog.get_all(%{
886 page: page,
887 page_size: page_size,
888 start_date: params["start_date"],
889 end_date: params["end_date"],
890 user_id: params["user_id"],
891 search: params["search"]
892 })
893
894 conn
895 |> put_view(ModerationLogView)
896 |> render("index.json", %{log: log})
897 end
898
899 def config_descriptions(conn, _params) do
900 conn
901 |> Plug.Conn.put_resp_content_type("application/json")
902 |> Plug.Conn.send_resp(200, @descriptions_json)
903 end
904
905 def config_show(conn, %{"only_db" => true}) do
906 with :ok <- configurable_from_database(conn) do
907 configs = Pleroma.Repo.all(ConfigDB)
908
909 conn
910 |> put_view(ConfigView)
911 |> render("index.json", %{configs: configs})
912 end
913 end
914
915 def config_show(conn, _params) do
916 with :ok <- configurable_from_database(conn) do
917 configs = ConfigDB.get_all_as_keyword()
918
919 merged =
920 Config.Holder.default_config()
921 |> ConfigDB.merge(configs)
922 |> Enum.map(fn {group, values} ->
923 Enum.map(values, fn {key, value} ->
924 db =
925 if configs[group][key] do
926 ConfigDB.get_db_keys(configs[group][key], key)
927 end
928
929 db_value = configs[group][key]
930
931 merged_value =
932 if !is_nil(db_value) and Keyword.keyword?(db_value) and
933 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
934 ConfigDB.merge_group(group, key, value, db_value)
935 else
936 value
937 end
938
939 setting = %{
940 group: ConfigDB.convert(group),
941 key: ConfigDB.convert(key),
942 value: ConfigDB.convert(merged_value)
943 }
944
945 if db, do: Map.put(setting, :db, db), else: setting
946 end)
947 end)
948 |> List.flatten()
949
950 json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
951 end
952 end
953
954 def config_update(conn, %{"configs" => configs}) do
955 with :ok <- configurable_from_database(conn) do
956 {_errors, results} =
957 Enum.map(configs, fn
958 %{"group" => group, "key" => key, "delete" => true} = params ->
959 ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
960
961 %{"group" => group, "key" => key, "value" => value} ->
962 ConfigDB.update_or_create(%{group: group, key: key, value: value})
963 end)
964 |> Enum.split_with(fn result -> elem(result, 0) == :error end)
965
966 {deleted, updated} =
967 results
968 |> Enum.map(fn {:ok, config} ->
969 Map.put(config, :db, ConfigDB.get_db_keys(config))
970 end)
971 |> Enum.split_with(fn config ->
972 Ecto.get_meta(config, :state) == :deleted
973 end)
974
975 Config.TransferTask.load_and_update_env(deleted, false)
976
977 if !Restarter.Pleroma.need_reboot?() do
978 changed_reboot_settings? =
979 (updated ++ deleted)
980 |> Enum.any?(fn config ->
981 group = ConfigDB.from_string(config.group)
982 key = ConfigDB.from_string(config.key)
983 value = ConfigDB.from_binary(config.value)
984 Config.TransferTask.pleroma_need_restart?(group, key, value)
985 end)
986
987 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
988 end
989
990 conn
991 |> put_view(ConfigView)
992 |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()})
993 end
994 end
995
996 def restart(conn, _params) do
997 with :ok <- configurable_from_database(conn) do
998 Restarter.Pleroma.restart(Config.get(:env), 50)
999
1000 json(conn, %{})
1001 end
1002 end
1003
1004 def need_reboot(conn, _params) do
1005 json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
1006 end
1007
1008 defp configurable_from_database(conn) do
1009 if Config.get(:configurable_from_database) do
1010 :ok
1011 else
1012 errors(
1013 conn,
1014 {:error, "To use this endpoint you need to enable configuration from database."}
1015 )
1016 end
1017 end
1018
1019 def reload_emoji(conn, _params) do
1020 Pleroma.Emoji.reload()
1021
1022 conn |> json("ok")
1023 end
1024
1025 def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
1026 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
1027
1028 User.toggle_confirmation(users)
1029
1030 ModerationLog.insert_log(%{
1031 actor: admin,
1032 subject: users,
1033 action: "confirm_email"
1034 })
1035
1036 conn |> json("")
1037 end
1038
1039 def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
1040 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
1041
1042 User.try_send_confirmation_email(users)
1043
1044 ModerationLog.insert_log(%{
1045 actor: admin,
1046 subject: users,
1047 action: "resend_confirmation_email"
1048 })
1049
1050 conn |> json("")
1051 end
1052
1053 def oauth_app_create(conn, params) do
1054 params =
1055 if params["name"] do
1056 Map.put(params, "client_name", params["name"])
1057 else
1058 params
1059 end
1060
1061 result =
1062 case App.create(params) do
1063 {:ok, app} ->
1064 AppView.render("show.json", %{app: app, admin: true})
1065
1066 {:error, changeset} ->
1067 App.errors(changeset)
1068 end
1069
1070 json(conn, result)
1071 end
1072
1073 def oauth_app_update(conn, params) do
1074 params =
1075 if params["name"] do
1076 Map.put(params, "client_name", params["name"])
1077 else
1078 params
1079 end
1080
1081 with {:ok, app} <- App.update(params) do
1082 json(conn, AppView.render("show.json", %{app: app, admin: true}))
1083 else
1084 {:error, changeset} ->
1085 json(conn, App.errors(changeset))
1086
1087 nil ->
1088 json_response(conn, :bad_request, "")
1089 end
1090 end
1091
1092 def oauth_app_list(conn, params) do
1093 {page, page_size} = page_params(params)
1094
1095 search_params = %{
1096 client_name: params["name"],
1097 client_id: params["client_id"],
1098 page: page,
1099 page_size: page_size
1100 }
1101
1102 search_params =
1103 if Map.has_key?(params, "trusted") do
1104 Map.put(search_params, :trusted, params["trusted"])
1105 else
1106 search_params
1107 end
1108
1109 with {:ok, apps, count} <- App.search(search_params) do
1110 json(
1111 conn,
1112 AppView.render("index.json",
1113 apps: apps,
1114 count: count,
1115 page_size: page_size,
1116 admin: true
1117 )
1118 )
1119 end
1120 end
1121
1122 def oauth_app_delete(conn, params) do
1123 with {:ok, _app} <- App.destroy(params["id"]) do
1124 json_response(conn, :no_content, "")
1125 else
1126 _ -> json_response(conn, :bad_request, "")
1127 end
1128 end
1129
1130 def stats(conn, _) do
1131 count = Stats.get_status_visibility_count()
1132
1133 conn
1134 |> json(%{"status_visibility" => count})
1135 end
1136
1137 defp errors(conn, {:error, :not_found}) do
1138 conn
1139 |> put_status(:not_found)
1140 |> json(dgettext("errors", "Not found"))
1141 end
1142
1143 defp errors(conn, {:error, reason}) do
1144 conn
1145 |> put_status(:bad_request)
1146 |> json(reason)
1147 end
1148
1149 defp errors(conn, {:param_cast, _}) do
1150 conn
1151 |> put_status(:bad_request)
1152 |> json(dgettext("errors", "Invalid parameters"))
1153 end
1154
1155 defp errors(conn, _) do
1156 conn
1157 |> put_status(:internal_server_error)
1158 |> json(dgettext("errors", "Something went wrong"))
1159 end
1160
1161 defp page_params(params) do
1162 {get_page(params["page"]), get_page_size(params["page_size"])}
1163 end
1164
1165 defp get_page(page_string) when is_nil(page_string), do: 1
1166
1167 defp get_page(page_string) do
1168 case Integer.parse(page_string) do
1169 {page, _} -> page
1170 :error -> 1
1171 end
1172 end
1173
1174 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
1175
1176 defp get_page_size(page_size_string) do
1177 case Integer.parse(page_size_string) do
1178 {page_size, _} -> page_size
1179 :error -> @users_page_size
1180 end
1181 end
1182 end