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