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