Merge branch 'tagline' into 'develop'
[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, 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 errors = Map.new(changeset.errors, fn {key, {error, _}} -> {key, error} end)
647
648 json(conn, %{errors: errors})
649
650 _ ->
651 json(conn, %{error: "Unable to update user."})
652 end
653 end
654
655 def list_reports(conn, params) do
656 {page, page_size} = page_params(params)
657
658 reports = Utils.get_reports(params, page, page_size)
659
660 conn
661 |> put_view(ReportView)
662 |> render("index.json", %{reports: reports})
663 end
664
665 def report_show(conn, %{"id" => id}) do
666 with %Activity{} = report <- Activity.get_by_id(id) do
667 conn
668 |> put_view(ReportView)
669 |> render("show.json", Report.extract_report_info(report))
670 else
671 _ -> {:error, :not_found}
672 end
673 end
674
675 def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
676 result =
677 reports
678 |> Enum.map(fn report ->
679 with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
680 ModerationLog.insert_log(%{
681 action: "report_update",
682 actor: admin,
683 subject: activity
684 })
685
686 activity
687 else
688 {:error, message} -> %{id: report["id"], error: message}
689 end
690 end)
691
692 case Enum.any?(result, &Map.has_key?(&1, :error)) do
693 true -> json_response(conn, :bad_request, result)
694 false -> json_response(conn, :no_content, "")
695 end
696 end
697
698 def report_notes_create(%{assigns: %{user: user}} = conn, %{
699 "id" => report_id,
700 "content" => content
701 }) do
702 with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
703 ModerationLog.insert_log(%{
704 action: "report_note",
705 actor: user,
706 subject: Activity.get_by_id(report_id),
707 text: content
708 })
709
710 json_response(conn, :no_content, "")
711 else
712 _ -> json_response(conn, :bad_request, "")
713 end
714 end
715
716 def report_notes_delete(%{assigns: %{user: user}} = conn, %{
717 "id" => note_id,
718 "report_id" => report_id
719 }) do
720 with {:ok, note} <- ReportNote.destroy(note_id) do
721 ModerationLog.insert_log(%{
722 action: "report_note_delete",
723 actor: user,
724 subject: Activity.get_by_id(report_id),
725 text: note.content
726 })
727
728 json_response(conn, :no_content, "")
729 else
730 _ -> json_response(conn, :bad_request, "")
731 end
732 end
733
734 def list_log(conn, params) do
735 {page, page_size} = page_params(params)
736
737 log =
738 ModerationLog.get_all(%{
739 page: page,
740 page_size: page_size,
741 start_date: params["start_date"],
742 end_date: params["end_date"],
743 user_id: params["user_id"],
744 search: params["search"]
745 })
746
747 conn
748 |> put_view(ModerationLogView)
749 |> render("index.json", %{log: log})
750 end
751
752 def config_descriptions(conn, _params) do
753 descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
754
755 json(conn, descriptions)
756 end
757
758 def config_show(conn, %{"only_db" => true}) do
759 with :ok <- configurable_from_database() do
760 configs = Pleroma.Repo.all(ConfigDB)
761
762 conn
763 |> put_view(ConfigView)
764 |> render("index.json", %{configs: configs})
765 end
766 end
767
768 def config_show(conn, _params) do
769 with :ok <- configurable_from_database() do
770 configs = ConfigDB.get_all_as_keyword()
771
772 merged =
773 Config.Holder.default_config()
774 |> ConfigDB.merge(configs)
775 |> Enum.map(fn {group, values} ->
776 Enum.map(values, fn {key, value} ->
777 db =
778 if configs[group][key] do
779 ConfigDB.get_db_keys(configs[group][key], key)
780 end
781
782 db_value = configs[group][key]
783
784 merged_value =
785 if !is_nil(db_value) and Keyword.keyword?(db_value) and
786 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
787 ConfigDB.merge_group(group, key, value, db_value)
788 else
789 value
790 end
791
792 setting = %{
793 group: ConfigDB.convert(group),
794 key: ConfigDB.convert(key),
795 value: ConfigDB.convert(merged_value)
796 }
797
798 if db, do: Map.put(setting, :db, db), else: setting
799 end)
800 end)
801 |> List.flatten()
802
803 json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
804 end
805 end
806
807 def config_update(conn, %{"configs" => configs}) do
808 with :ok <- configurable_from_database() do
809 {_errors, results} =
810 configs
811 |> Enum.filter(&whitelisted_config?/1)
812 |> Enum.map(fn
813 %{"group" => group, "key" => key, "delete" => true} = params ->
814 ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
815
816 %{"group" => group, "key" => key, "value" => value} ->
817 ConfigDB.update_or_create(%{group: group, key: key, value: value})
818 end)
819 |> Enum.split_with(fn result -> elem(result, 0) == :error end)
820
821 {deleted, updated} =
822 results
823 |> Enum.map(fn {:ok, config} ->
824 Map.put(config, :db, ConfigDB.get_db_keys(config))
825 end)
826 |> Enum.split_with(fn config ->
827 Ecto.get_meta(config, :state) == :deleted
828 end)
829
830 Config.TransferTask.load_and_update_env(deleted, false)
831
832 if !Restarter.Pleroma.need_reboot?() do
833 changed_reboot_settings? =
834 (updated ++ deleted)
835 |> Enum.any?(fn config ->
836 group = ConfigDB.from_string(config.group)
837 key = ConfigDB.from_string(config.key)
838 value = ConfigDB.from_binary(config.value)
839 Config.TransferTask.pleroma_need_restart?(group, key, value)
840 end)
841
842 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
843 end
844
845 conn
846 |> put_view(ConfigView)
847 |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()})
848 end
849 end
850
851 def restart(conn, _params) do
852 with :ok <- configurable_from_database() do
853 Restarter.Pleroma.restart(Config.get(:env), 50)
854
855 json(conn, %{})
856 end
857 end
858
859 def need_reboot(conn, _params) do
860 json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
861 end
862
863 defp configurable_from_database do
864 if Config.get(:configurable_from_database) do
865 :ok
866 else
867 {:error, "To use this endpoint you need to enable configuration from database."}
868 end
869 end
870
871 defp whitelisted_config?(group, key) do
872 if whitelisted_configs = Config.get(:database_config_whitelist) do
873 Enum.any?(whitelisted_configs, fn
874 {whitelisted_group} ->
875 group == inspect(whitelisted_group)
876
877 {whitelisted_group, whitelisted_key} ->
878 group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
879 end)
880 else
881 true
882 end
883 end
884
885 defp whitelisted_config?(%{"group" => group, "key" => key}) do
886 whitelisted_config?(group, key)
887 end
888
889 defp whitelisted_config?(%{:group => group} = config) do
890 whitelisted_config?(group, config[:key])
891 end
892
893 def reload_emoji(conn, _params) do
894 Pleroma.Emoji.reload()
895
896 conn |> json("ok")
897 end
898
899 def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
900 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
901
902 User.toggle_confirmation(users)
903
904 ModerationLog.insert_log(%{
905 actor: admin,
906 subject: users,
907 action: "confirm_email"
908 })
909
910 conn |> json("")
911 end
912
913 def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
914 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
915
916 User.try_send_confirmation_email(users)
917
918 ModerationLog.insert_log(%{
919 actor: admin,
920 subject: users,
921 action: "resend_confirmation_email"
922 })
923
924 conn |> json("")
925 end
926
927 def oauth_app_create(conn, params) do
928 params =
929 if params["name"] do
930 Map.put(params, "client_name", params["name"])
931 else
932 params
933 end
934
935 result =
936 case App.create(params) do
937 {:ok, app} ->
938 AppView.render("show.json", %{app: app, admin: true})
939
940 {:error, changeset} ->
941 App.errors(changeset)
942 end
943
944 json(conn, result)
945 end
946
947 def oauth_app_update(conn, params) do
948 params =
949 if params["name"] do
950 Map.put(params, "client_name", params["name"])
951 else
952 params
953 end
954
955 with {:ok, app} <- App.update(params) do
956 json(conn, AppView.render("show.json", %{app: app, admin: true}))
957 else
958 {:error, changeset} ->
959 json(conn, App.errors(changeset))
960
961 nil ->
962 json_response(conn, :bad_request, "")
963 end
964 end
965
966 def oauth_app_list(conn, params) do
967 {page, page_size} = page_params(params)
968
969 search_params = %{
970 client_name: params["name"],
971 client_id: params["client_id"],
972 page: page,
973 page_size: page_size
974 }
975
976 search_params =
977 if Map.has_key?(params, "trusted") do
978 Map.put(search_params, :trusted, params["trusted"])
979 else
980 search_params
981 end
982
983 with {:ok, apps, count} <- App.search(search_params) do
984 json(
985 conn,
986 AppView.render("index.json",
987 apps: apps,
988 count: count,
989 page_size: page_size,
990 admin: true
991 )
992 )
993 end
994 end
995
996 def oauth_app_delete(conn, params) do
997 with {:ok, _app} <- App.destroy(params["id"]) do
998 json_response(conn, :no_content, "")
999 else
1000 _ -> json_response(conn, :bad_request, "")
1001 end
1002 end
1003
1004 def stats(conn, _) do
1005 count = Stats.get_status_visibility_count()
1006
1007 conn
1008 |> json(%{"status_visibility" => count})
1009 end
1010
1011 defp page_params(params) do
1012 {get_page(params["page"]), get_page_size(params["page_size"])}
1013 end
1014
1015 defp get_page(page_string) when is_nil(page_string), do: 1
1016
1017 defp get_page(page_string) do
1018 case Integer.parse(page_string) do
1019 {page, _} -> page
1020 :error -> 1
1021 end
1022 end
1023
1024 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
1025
1026 defp get_page_size(page_size_string) do
1027 case Integer.parse(page_size_string) do
1028 {page_size, _} -> page_size
1029 :error -> @users_page_size
1030 end
1031 end
1032 end