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