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