1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.AdminAPI.AdminAPIController do
6 use Pleroma.Web, :controller
8 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
10 alias Pleroma.Activity
12 alias Pleroma.ConfigDB
13 alias Pleroma.ModerationLog
14 alias Pleroma.Plugs.OAuthScopesPlug
15 alias Pleroma.ReportNote
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.AppView
31 alias Pleroma.Web.MastodonAPI.StatusView
32 alias Pleroma.Web.OAuth.App
33 alias Pleroma.Web.Router
37 @descriptions_json Pleroma.Docs.JSON.compile()
42 %{scopes: ["read:accounts"], admin: true}
43 when action in [:list_users, :user_show, :right_get, :show_user_credentials]
48 %{scopes: ["write:accounts"], admin: true}
53 :user_toggle_activation,
60 :update_user_credentials
64 plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites)
68 %{scopes: ["write:invites"], admin: true}
69 when action in [:create_invite_token, :revoke_invite, :email_invite]
74 %{scopes: ["write:follows"], admin: true}
75 when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow]
80 %{scopes: ["read:reports"], admin: true}
81 when action in [:list_reports, :report_show]
86 %{scopes: ["write:reports"], admin: true}
87 when action in [:reports_update]
92 %{scopes: ["read:statuses"], admin: true}
93 when action == :list_user_statuses
98 %{scopes: ["write:statuses"], admin: true}
99 when action in [:status_update, :status_delete]
104 %{scopes: ["read"], admin: true}
105 when action in [:config_show, :list_log, :stats]
110 %{scopes: ["write"], admin: true}
111 when action == :config_update
114 action_fallback(:errors)
116 def user_delete(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
117 user = User.get_cached_by_nickname(nickname)
120 ModerationLog.insert_log(%{
130 def user_delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
131 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
134 ModerationLog.insert_log(%{
144 def user_follow(%{assigns: %{user: admin}} = conn, %{
145 "follower" => follower_nick,
146 "followed" => followed_nick
148 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
149 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
150 User.follow(follower, followed)
152 ModerationLog.insert_log(%{
164 def user_unfollow(%{assigns: %{user: admin}} = conn, %{
165 "follower" => follower_nick,
166 "followed" => followed_nick
168 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
169 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
170 User.unfollow(follower, followed)
172 ModerationLog.insert_log(%{
184 def users_create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
186 Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
192 password_confirmation: password,
196 User.register_changeset(%User{}, user_data, need_confirmation: false)
198 |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
199 Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
202 case Pleroma.Repo.transaction(changesets) do
207 |> Enum.map(fn user ->
208 {:ok, user} = User.post_register_action(user)
212 |> Enum.map(&AccountView.render("created.json", %{user: &1}))
214 ModerationLog.insert_log(%{
216 subjects: Map.values(users),
223 {:error, id, changeset, _} ->
225 Enum.map(changesets.operations, fn
226 {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
227 AccountView.render("create-error.json", %{changeset: changeset})
229 {_, {:changeset, current_changeset, _}} ->
230 AccountView.render("create-error.json", %{changeset: current_changeset})
234 |> put_status(:conflict)
239 def user_show(conn, %{"nickname" => nickname}) do
240 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
242 |> put_view(AccountView)
243 |> render("show.json", %{user: user})
245 _ -> {:error, :not_found}
249 def list_instance_statuses(conn, %{"instance" => instance} = params) do
250 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
251 {page, page_size} = page_params(params)
254 ActivityPub.fetch_statuses(nil, %{
255 "instance" => instance,
256 "limit" => page_size,
257 "offset" => (page - 1) * page_size,
258 "exclude_reblogs" => !with_reblogs && "true"
262 |> put_view(Pleroma.Web.AdminAPI.StatusView)
263 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
266 def list_user_statuses(conn, %{"nickname" => nickname} = params) do
267 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
268 godmode = params["godmode"] == "true" || params["godmode"] == true
270 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
271 {_, page_size} = page_params(params)
274 ActivityPub.fetch_user_activities(user, nil, %{
275 "limit" => page_size,
276 "godmode" => godmode,
277 "exclude_reblogs" => !with_reblogs && "true"
281 |> put_view(StatusView)
282 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
284 _ -> {:error, :not_found}
288 def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
289 user = User.get_cached_by_nickname(nickname)
291 {:ok, updated_user} = User.deactivate(user, !user.deactivated)
293 action = if user.deactivated, do: "activate", else: "deactivate"
295 ModerationLog.insert_log(%{
302 |> put_view(AccountView)
303 |> render("show.json", %{user: updated_user})
306 def user_activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
307 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
308 {:ok, updated_users} = User.deactivate(users, false)
310 ModerationLog.insert_log(%{
317 |> put_view(AccountView)
318 |> render("index.json", %{users: Keyword.values(updated_users)})
321 def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
322 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
323 {:ok, updated_users} = User.deactivate(users, true)
325 ModerationLog.insert_log(%{
332 |> put_view(AccountView)
333 |> render("index.json", %{users: Keyword.values(updated_users)})
336 def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
337 with {:ok, _} <- User.tag(nicknames, tags) do
338 ModerationLog.insert_log(%{
340 nicknames: nicknames,
345 json_response(conn, :no_content, "")
349 def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
350 with {:ok, _} <- User.untag(nicknames, tags) do
351 ModerationLog.insert_log(%{
353 nicknames: nicknames,
358 json_response(conn, :no_content, "")
362 def list_users(conn, params) do
363 {page, page_size} = page_params(params)
364 filters = maybe_parse_filters(params["filters"])
367 query: params["query"],
369 page_size: page_size,
370 tags: params["tags"],
371 name: params["name"],
372 email: params["email"]
375 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
376 {:ok, users, count} <- filter_service_users(users, count),
380 AccountView.render("index.json",
388 defp filter_service_users(users, count) do
389 filtered_users = Enum.reject(users, &service_user?/1)
390 count = if Enum.any?(users, &service_user?/1), do: length(filtered_users), else: count
392 {:ok, filtered_users, count}
395 defp service_user?(user) do
396 String.match?(user.ap_id, ~r/.*\/relay$/) or
397 String.match?(user.ap_id, ~r/.*\/internal\/fetch$/)
400 @filters ~w(local external active deactivated is_admin is_moderator)
402 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
403 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
405 defp maybe_parse_filters(filters) do
408 |> Enum.filter(&Enum.member?(@filters, &1))
409 |> Enum.map(&String.to_atom(&1))
410 |> Enum.into(%{}, &{&1, true})
413 def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
414 "permission_group" => permission_group,
415 "nicknames" => nicknames
417 when permission_group in ["moderator", "admin"] do
418 update = %{:"is_#{permission_group}" => true}
420 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
422 for u <- users, do: User.admin_api_update(u, update)
424 ModerationLog.insert_log(%{
428 permission: permission_group
434 def right_add_multiple(conn, _) do
435 render_error(conn, :not_found, "No such permission_group")
438 def right_add(%{assigns: %{user: admin}} = conn, %{
439 "permission_group" => permission_group,
440 "nickname" => nickname
442 when permission_group in ["moderator", "admin"] do
443 fields = %{:"is_#{permission_group}" => true}
447 |> User.get_cached_by_nickname()
448 |> User.admin_api_update(fields)
450 ModerationLog.insert_log(%{
454 permission: permission_group
460 def right_add(conn, _) do
461 render_error(conn, :not_found, "No such permission_group")
464 def right_get(conn, %{"nickname" => nickname}) do
465 user = User.get_cached_by_nickname(nickname)
469 is_moderator: user.is_moderator,
470 is_admin: user.is_admin
474 def right_delete_multiple(
475 %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
477 "permission_group" => permission_group,
478 "nicknames" => nicknames
481 when permission_group in ["moderator", "admin"] do
482 with false <- Enum.member?(nicknames, admin_nickname) do
483 update = %{:"is_#{permission_group}" => false}
485 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
487 for u <- users, do: User.admin_api_update(u, update)
489 ModerationLog.insert_log(%{
493 permission: permission_group
498 _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
502 def right_delete_multiple(conn, _) do
503 render_error(conn, :not_found, "No such permission_group")
507 %{assigns: %{user: admin}} = conn,
509 "permission_group" => permission_group,
510 "nickname" => nickname
513 when permission_group in ["moderator", "admin"] do
514 fields = %{:"is_#{permission_group}" => false}
518 |> User.get_cached_by_nickname()
519 |> User.admin_api_update(fields)
521 ModerationLog.insert_log(%{
525 permission: permission_group
531 def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
532 render_error(conn, :forbidden, "You can't revoke your own admin status.")
535 def relay_list(conn, _params) do
536 with {:ok, list} <- Relay.list() do
537 json(conn, %{relays: list})
545 def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
546 with {:ok, _message} <- Relay.follow(target) do
547 ModerationLog.insert_log(%{
548 action: "relay_follow",
562 def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
563 with {:ok, _message} <- Relay.unfollow(target) do
564 ModerationLog.insert_log(%{
565 action: "relay_unfollow",
579 @doc "Sends registration invite via email"
580 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
581 with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
582 {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
583 {:ok, invite_token} <- UserInviteToken.create_invite(),
585 Pleroma.Emails.UserEmail.user_invitation_email(
591 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
592 json_response(conn, :no_content, "")
594 {:registrations_open, _} ->
597 {:error, "To send invites you need to set the `registrations_open` option to false."}
600 {:invites_enabled, _} ->
603 {:error, "To send invites you need to set the `invites_enabled` option to true."}
608 @doc "Create an account registration invite token"
609 def create_invite_token(conn, params) do
613 if params["max_use"],
614 do: Map.put(opts, :max_use, params["max_use"]),
618 if params["expires_at"],
619 do: Map.put(opts, :expires_at, params["expires_at"]),
622 {:ok, invite} = UserInviteToken.create_invite(opts)
624 json(conn, AccountView.render("invite.json", %{invite: invite}))
627 @doc "Get list of created invites"
628 def invites(conn, _params) do
629 invites = UserInviteToken.list_invites()
632 |> put_view(AccountView)
633 |> render("invites.json", %{invites: invites})
636 @doc "Revokes invite by token"
637 def revoke_invite(conn, %{"token" => token}) do
638 with {:ok, invite} <- UserInviteToken.find_by_token(token),
639 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
641 |> put_view(AccountView)
642 |> render("invite.json", %{invite: updated_invite})
644 nil -> {:error, :not_found}
648 @doc "Get a password reset token (base64 string) for given nickname"
649 def get_password_reset(conn, %{"nickname" => nickname}) do
650 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
651 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
656 link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
660 @doc "Force password reset for a given user"
661 def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
662 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
664 Enum.each(users, &User.force_password_reset_async/1)
666 ModerationLog.insert_log(%{
669 action: "force_password_reset"
672 json_response(conn, :no_content, "")
675 @doc "Show a given user's credentials"
676 def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
677 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
679 |> put_view(AccountView)
680 |> render("credentials.json", %{user: user, for: admin})
682 _ -> {:error, :not_found}
686 @doc "Updates a given user"
687 def update_user_credentials(
688 %{assigns: %{user: admin}} = conn,
689 %{"nickname" => nickname} = params
691 with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
693 User.update_as_admin(user, params) do
694 ModerationLog.insert_log(%{
697 action: "updated_users"
700 if params["password"] do
701 User.force_password_reset_async(user)
704 ModerationLog.insert_log(%{
707 action: "force_password_reset"
710 json(conn, %{status: "success"})
712 {:error, changeset} ->
713 {_, {error, _}} = Enum.at(changeset.errors, 0)
714 json(conn, %{error: "New password #{error}."})
717 json(conn, %{error: "Unable to change password."})
721 def list_reports(conn, params) do
722 {page, page_size} = page_params(params)
724 reports = Utils.get_reports(params, page, page_size)
727 |> put_view(ReportView)
728 |> render("index.json", %{reports: reports})
731 def report_show(conn, %{"id" => id}) do
732 with %Activity{} = report <- Activity.get_by_id(id) do
734 |> put_view(ReportView)
735 |> render("show.json", Report.extract_report_info(report))
737 _ -> {:error, :not_found}
741 def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
744 |> Enum.map(fn report ->
745 with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
746 ModerationLog.insert_log(%{
747 action: "report_update",
754 {:error, message} -> %{id: report["id"], error: message}
758 case Enum.any?(result, &Map.has_key?(&1, :error)) do
759 true -> json_response(conn, :bad_request, result)
760 false -> json_response(conn, :no_content, "")
764 def report_notes_create(%{assigns: %{user: user}} = conn, %{
768 with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
769 ModerationLog.insert_log(%{
770 action: "report_note",
772 subject: Activity.get_by_id(report_id),
776 json_response(conn, :no_content, "")
778 _ -> json_response(conn, :bad_request, "")
782 def report_notes_delete(%{assigns: %{user: user}} = conn, %{
784 "report_id" => report_id
786 with {:ok, note} <- ReportNote.destroy(note_id) do
787 ModerationLog.insert_log(%{
788 action: "report_note_delete",
790 subject: Activity.get_by_id(report_id),
794 json_response(conn, :no_content, "")
796 _ -> json_response(conn, :bad_request, "")
800 def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
801 godmode = params["godmode"] == "true" || params["godmode"] == true
802 local_only = params["local_only"] == "true" || params["local_only"] == true
803 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
804 {page, page_size} = page_params(params)
807 ActivityPub.fetch_statuses(nil, %{
808 "godmode" => godmode,
809 "local_only" => local_only,
810 "limit" => page_size,
811 "offset" => (page - 1) * page_size,
812 "exclude_reblogs" => !with_reblogs && "true"
816 |> put_view(Pleroma.Web.AdminAPI.StatusView)
817 |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
820 def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
821 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
822 {:ok, sensitive} = Ecto.Type.cast(:boolean, params["sensitive"])
824 ModerationLog.insert_log(%{
825 action: "status_update",
828 sensitive: sensitive,
829 visibility: params["visibility"]
833 |> put_view(StatusView)
834 |> render("show.json", %{activity: activity})
838 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
839 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
840 ModerationLog.insert_log(%{
841 action: "status_delete",
850 def list_log(conn, params) do
851 {page, page_size} = page_params(params)
854 ModerationLog.get_all(%{
856 page_size: page_size,
857 start_date: params["start_date"],
858 end_date: params["end_date"],
859 user_id: params["user_id"],
860 search: params["search"]
864 |> put_view(ModerationLogView)
865 |> render("index.json", %{log: log})
868 def config_descriptions(conn, _params) do
870 |> Plug.Conn.put_resp_content_type("application/json")
871 |> Plug.Conn.send_resp(200, @descriptions_json)
874 def config_show(conn, %{"only_db" => true}) do
875 with :ok <- configurable_from_database(conn) do
876 configs = Pleroma.Repo.all(ConfigDB)
879 |> put_view(ConfigView)
880 |> render("index.json", %{configs: configs})
884 def config_show(conn, _params) do
885 with :ok <- configurable_from_database(conn) do
886 configs = ConfigDB.get_all_as_keyword()
889 Config.Holder.default_config()
890 |> ConfigDB.merge(configs)
891 |> Enum.map(fn {group, values} ->
892 Enum.map(values, fn {key, value} ->
894 if configs[group][key] do
895 ConfigDB.get_db_keys(configs[group][key], key)
898 db_value = configs[group][key]
901 if !is_nil(db_value) and Keyword.keyword?(db_value) and
902 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
903 ConfigDB.merge_group(group, key, value, db_value)
909 group: ConfigDB.convert(group),
910 key: ConfigDB.convert(key),
911 value: ConfigDB.convert(merged_value)
914 if db, do: Map.put(setting, :db, db), else: setting
919 json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
923 def config_update(conn, %{"configs" => configs}) do
924 with :ok <- configurable_from_database(conn) do
927 %{"group" => group, "key" => key, "delete" => true} = params ->
928 ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
930 %{"group" => group, "key" => key, "value" => value} ->
931 ConfigDB.update_or_create(%{group: group, key: key, value: value})
933 |> Enum.split_with(fn result -> elem(result, 0) == :error end)
937 |> Enum.map(fn {:ok, config} ->
938 Map.put(config, :db, ConfigDB.get_db_keys(config))
940 |> Enum.split_with(fn config ->
941 Ecto.get_meta(config, :state) == :deleted
944 Config.TransferTask.load_and_update_env(deleted, false)
946 if !Restarter.Pleroma.need_reboot?() do
947 changed_reboot_settings? =
949 |> Enum.any?(fn config ->
950 group = ConfigDB.from_string(config.group)
951 key = ConfigDB.from_string(config.key)
952 value = ConfigDB.from_binary(config.value)
953 Config.TransferTask.pleroma_need_restart?(group, key, value)
956 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
960 |> put_view(ConfigView)
961 |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()})
965 def restart(conn, _params) do
966 with :ok <- configurable_from_database(conn) do
967 Restarter.Pleroma.restart(Config.get(:env), 50)
973 def need_reboot(conn, _params) do
974 json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
977 defp configurable_from_database(conn) do
978 if Config.get(:configurable_from_database) do
983 {:error, "To use this endpoint you need to enable configuration from database."}
988 def reload_emoji(conn, _params) do
989 Pleroma.Emoji.reload()
994 def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
995 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
997 User.toggle_confirmation(users)
999 ModerationLog.insert_log(%{
1002 action: "confirm_email"
1008 def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
1009 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
1011 User.try_send_confirmation_email(users)
1013 ModerationLog.insert_log(%{
1016 action: "resend_confirmation_email"
1022 def oauth_app_create(conn, params) do
1024 if params["name"] do
1025 Map.put(params, "client_name", params["name"])
1031 case App.create(params) do
1033 AppView.render("show.json", %{app: app, admin: true})
1035 {:error, changeset} ->
1036 App.errors(changeset)
1042 def oauth_app_update(conn, params) do
1044 if params["name"] do
1045 Map.put(params, "client_name", params["name"])
1050 with {:ok, app} <- App.update(params) do
1051 json(conn, AppView.render("show.json", %{app: app, admin: true}))
1053 {:error, changeset} ->
1054 json(conn, App.errors(changeset))
1057 json_response(conn, :bad_request, "")
1061 def oauth_app_list(conn, params) do
1062 {page, page_size} = page_params(params)
1065 client_name: params["name"],
1066 client_id: params["client_id"],
1068 page_size: page_size
1072 if Map.has_key?(params, "trusted") do
1073 Map.put(search_params, :trusted, params["trusted"])
1078 with {:ok, apps, count} <- App.search(search_params) do
1081 AppView.render("index.json",
1084 page_size: page_size,
1091 def oauth_app_delete(conn, params) do
1092 with {:ok, _app} <- App.destroy(params["id"]) do
1093 json_response(conn, :no_content, "")
1095 _ -> json_response(conn, :bad_request, "")
1099 def stats(conn, _) do
1100 count = Stats.get_status_visibility_count()
1103 |> json(%{"status_visibility" => count})
1106 def errors(conn, {:error, :not_found}) do
1108 |> put_status(:not_found)
1109 |> json(dgettext("errors", "Not found"))
1112 def errors(conn, {:error, reason}) do
1114 |> put_status(:bad_request)
1118 def errors(conn, {:param_cast, _}) do
1120 |> put_status(:bad_request)
1121 |> json(dgettext("errors", "Invalid parameters"))
1124 def errors(conn, _) do
1126 |> put_status(:internal_server_error)
1127 |> json(dgettext("errors", "Something went wrong"))
1130 defp page_params(params) do
1131 {get_page(params["page"]), get_page_size(params["page_size"])}
1134 defp get_page(page_string) when is_nil(page_string), do: 1
1136 defp get_page(page_string) do
1137 case Integer.parse(page_string) do
1143 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
1145 defp get_page_size(page_size_string) do
1146 case Integer.parse(page_size_string) do
1147 {page_size, _} -> page_size
1148 :error -> @users_page_size