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