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
14 alias Pleroma.ModerationLog
15 alias Pleroma.Plugs.OAuthScopesPlug
16 alias Pleroma.ReportNote
19 alias Pleroma.UserInviteToken
20 alias Pleroma.Web.ActivityPub.ActivityPub
21 alias Pleroma.Web.ActivityPub.Builder
22 alias Pleroma.Web.ActivityPub.Pipeline
23 alias Pleroma.Web.ActivityPub.Relay
24 alias Pleroma.Web.ActivityPub.Utils
25 alias Pleroma.Web.AdminAPI
26 alias Pleroma.Web.AdminAPI.AccountView
27 alias Pleroma.Web.AdminAPI.ConfigView
28 alias Pleroma.Web.AdminAPI.ModerationLogView
29 alias Pleroma.Web.AdminAPI.Report
30 alias Pleroma.Web.AdminAPI.ReportView
31 alias Pleroma.Web.AdminAPI.Search
32 alias Pleroma.Web.CommonAPI
33 alias Pleroma.Web.Endpoint
34 alias Pleroma.Web.MastodonAPI
35 alias Pleroma.Web.MastodonAPI.AppView
36 alias Pleroma.Web.OAuth.App
37 alias Pleroma.Web.Router
41 @descriptions Pleroma.Docs.JSON.compile()
46 %{scopes: ["read:accounts"], admin: true}
47 when action in [:list_users, :user_show, :right_get, :show_user_credentials]
52 %{scopes: ["write:accounts"], admin: true}
55 :force_password_reset,
58 :user_toggle_activation,
67 :right_delete_multiple,
68 :update_user_credentials
72 plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites)
76 %{scopes: ["write:invites"], admin: true}
77 when action in [:create_invite_token, :revoke_invite, :email_invite]
82 %{scopes: ["write:follows"], admin: true}
83 when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow]
88 %{scopes: ["read:reports"], admin: true}
89 when action in [:list_reports, :report_show]
94 %{scopes: ["write:reports"], admin: true}
95 when action in [:reports_update, :report_notes_create, :report_notes_delete]
100 %{scopes: ["read:statuses"], admin: true}
101 when action in [:list_statuses, :list_user_statuses, :list_instance_statuses, :status_show]
106 %{scopes: ["write:statuses"], admin: true}
107 when action in [:status_update, :status_delete]
112 %{scopes: ["read"], admin: true}
118 :config_descriptions,
125 %{scopes: ["write"], admin: true}
129 :resend_confirmation_email,
139 action_fallback(:errors)
141 def user_delete(conn, %{"nickname" => nickname}) do
142 user_delete(conn, %{"nicknames" => [nickname]})
145 def user_delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
148 |> Enum.map(&User.get_cached_by_nickname/1)
151 |> Enum.each(fn user ->
152 {:ok, delete_data, _} = Builder.delete(admin, user.ap_id)
153 Pipeline.common_pipeline(delete_data, local: true)
156 ModerationLog.insert_log(%{
166 def user_follow(%{assigns: %{user: admin}} = conn, %{
167 "follower" => follower_nick,
168 "followed" => followed_nick
170 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
171 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
172 User.follow(follower, followed)
174 ModerationLog.insert_log(%{
186 def user_unfollow(%{assigns: %{user: admin}} = conn, %{
187 "follower" => follower_nick,
188 "followed" => followed_nick
190 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
191 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
192 User.unfollow(follower, followed)
194 ModerationLog.insert_log(%{
206 def users_create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
208 Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
214 password_confirmation: password,
218 User.register_changeset(%User{}, user_data, need_confirmation: false)
220 |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
221 Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
224 case Pleroma.Repo.transaction(changesets) do
229 |> Enum.map(fn user ->
230 {:ok, user} = User.post_register_action(user)
234 |> Enum.map(&AccountView.render("created.json", %{user: &1}))
236 ModerationLog.insert_log(%{
238 subjects: Map.values(users),
245 {:error, id, changeset, _} ->
247 Enum.map(changesets.operations, fn
248 {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
249 AccountView.render("create-error.json", %{changeset: changeset})
251 {_, {:changeset, current_changeset, _}} ->
252 AccountView.render("create-error.json", %{changeset: current_changeset})
256 |> put_status(:conflict)
261 def user_show(conn, %{"nickname" => nickname}) do
262 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
264 |> put_view(AccountView)
265 |> render("show.json", %{user: user})
267 _ -> {:error, :not_found}
271 def list_instance_statuses(conn, %{"instance" => instance} = params) do
272 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
273 {page, page_size} = page_params(params)
276 ActivityPub.fetch_statuses(nil, %{
277 "instance" => instance,
278 "limit" => page_size,
279 "offset" => (page - 1) * page_size,
280 "exclude_reblogs" => !with_reblogs && "true"
284 |> put_view(AdminAPI.StatusView)
285 |> render("index.json", %{activities: activities, as: :activity})
288 def list_user_statuses(conn, %{"nickname" => nickname} = params) do
289 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
290 godmode = params["godmode"] == "true" || params["godmode"] == true
292 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
293 {_, page_size} = page_params(params)
296 ActivityPub.fetch_user_activities(user, nil, %{
297 "limit" => page_size,
298 "godmode" => godmode,
299 "exclude_reblogs" => !with_reblogs && "true"
303 |> put_view(MastodonAPI.StatusView)
304 |> render("index.json", %{activities: activities, as: :activity})
306 _ -> {:error, :not_found}
310 def user_toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
311 user = User.get_cached_by_nickname(nickname)
313 {:ok, updated_user} = User.deactivate(user, !user.deactivated)
315 action = if user.deactivated, do: "activate", else: "deactivate"
317 ModerationLog.insert_log(%{
324 |> put_view(AccountView)
325 |> render("show.json", %{user: updated_user})
328 def user_activate(%{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, false)
332 ModerationLog.insert_log(%{
339 |> put_view(AccountView)
340 |> render("index.json", %{users: Keyword.values(updated_users)})
343 def user_deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
344 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
345 {:ok, updated_users} = User.deactivate(users, true)
347 ModerationLog.insert_log(%{
354 |> put_view(AccountView)
355 |> render("index.json", %{users: Keyword.values(updated_users)})
358 def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
359 with {:ok, _} <- User.tag(nicknames, tags) do
360 ModerationLog.insert_log(%{
362 nicknames: nicknames,
367 json_response(conn, :no_content, "")
371 def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
372 with {:ok, _} <- User.untag(nicknames, tags) do
373 ModerationLog.insert_log(%{
375 nicknames: nicknames,
380 json_response(conn, :no_content, "")
384 def list_users(conn, params) do
385 {page, page_size} = page_params(params)
386 filters = maybe_parse_filters(params["filters"])
389 query: params["query"],
391 page_size: page_size,
392 tags: params["tags"],
393 name: params["name"],
394 email: params["email"]
397 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)) do
400 AccountView.render("index.json", users: users, count: count, page_size: page_size)
405 @filters ~w(local external active deactivated is_admin is_moderator)
407 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
408 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
410 defp maybe_parse_filters(filters) do
413 |> Enum.filter(&Enum.member?(@filters, &1))
414 |> Enum.map(&String.to_atom(&1))
415 |> Enum.into(%{}, &{&1, true})
418 def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
419 "permission_group" => permission_group,
420 "nicknames" => nicknames
422 when permission_group in ["moderator", "admin"] do
423 update = %{:"is_#{permission_group}" => true}
425 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
427 for u <- users, do: User.admin_api_update(u, update)
429 ModerationLog.insert_log(%{
433 permission: permission_group
439 def right_add_multiple(conn, _) do
440 render_error(conn, :not_found, "No such permission_group")
443 def right_add(%{assigns: %{user: admin}} = conn, %{
444 "permission_group" => permission_group,
445 "nickname" => nickname
447 when permission_group in ["moderator", "admin"] do
448 fields = %{:"is_#{permission_group}" => true}
452 |> User.get_cached_by_nickname()
453 |> User.admin_api_update(fields)
455 ModerationLog.insert_log(%{
459 permission: permission_group
465 def right_add(conn, _) do
466 render_error(conn, :not_found, "No such permission_group")
469 def right_get(conn, %{"nickname" => nickname}) do
470 user = User.get_cached_by_nickname(nickname)
474 is_moderator: user.is_moderator,
475 is_admin: user.is_admin
479 def right_delete_multiple(
480 %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
482 "permission_group" => permission_group,
483 "nicknames" => nicknames
486 when permission_group in ["moderator", "admin"] do
487 with false <- Enum.member?(nicknames, admin_nickname) do
488 update = %{:"is_#{permission_group}" => false}
490 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
492 for u <- users, do: User.admin_api_update(u, update)
494 ModerationLog.insert_log(%{
498 permission: permission_group
503 _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
507 def right_delete_multiple(conn, _) do
508 render_error(conn, :not_found, "No such permission_group")
512 %{assigns: %{user: admin}} = conn,
514 "permission_group" => permission_group,
515 "nickname" => nickname
518 when permission_group in ["moderator", "admin"] do
519 fields = %{:"is_#{permission_group}" => false}
523 |> User.get_cached_by_nickname()
524 |> User.admin_api_update(fields)
526 ModerationLog.insert_log(%{
530 permission: permission_group
536 def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
537 render_error(conn, :forbidden, "You can't revoke your own admin status.")
540 def relay_list(conn, _params) do
541 with {:ok, list} <- Relay.list() do
542 json(conn, %{relays: list})
550 def relay_follow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
551 with {:ok, _message} <- Relay.follow(target) do
552 ModerationLog.insert_log(%{
553 action: "relay_follow",
567 def relay_unfollow(%{assigns: %{user: admin}} = conn, %{"relay_url" => target}) do
568 with {:ok, _message} <- Relay.unfollow(target) do
569 ModerationLog.insert_log(%{
570 action: "relay_unfollow",
584 @doc "Sends registration invite via email"
585 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
586 with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
587 {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
588 {:ok, invite_token} <- UserInviteToken.create_invite(),
590 Pleroma.Emails.UserEmail.user_invitation_email(
596 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
597 json_response(conn, :no_content, "")
599 {:registrations_open, _} ->
602 {:error, "To send invites you need to set the `registrations_open` option to false."}
605 {:invites_enabled, _} ->
608 {:error, "To send invites you need to set the `invites_enabled` option to true."}
613 @doc "Create an account registration invite token"
614 def create_invite_token(conn, params) do
618 if params["max_use"],
619 do: Map.put(opts, :max_use, params["max_use"]),
623 if params["expires_at"],
624 do: Map.put(opts, :expires_at, params["expires_at"]),
627 {:ok, invite} = UserInviteToken.create_invite(opts)
629 json(conn, AccountView.render("invite.json", %{invite: invite}))
632 @doc "Get list of created invites"
633 def invites(conn, _params) do
634 invites = UserInviteToken.list_invites()
637 |> put_view(AccountView)
638 |> render("invites.json", %{invites: invites})
641 @doc "Revokes invite by token"
642 def revoke_invite(conn, %{"token" => token}) do
643 with {:ok, invite} <- UserInviteToken.find_by_token(token),
644 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
646 |> put_view(AccountView)
647 |> render("invite.json", %{invite: updated_invite})
649 nil -> {:error, :not_found}
653 @doc "Get a password reset token (base64 string) for given nickname"
654 def get_password_reset(conn, %{"nickname" => nickname}) do
655 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
656 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
661 link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
665 @doc "Force password reset for a given user"
666 def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
667 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
669 Enum.each(users, &User.force_password_reset_async/1)
671 ModerationLog.insert_log(%{
674 action: "force_password_reset"
677 json_response(conn, :no_content, "")
680 @doc "Disable mfa for user's account."
681 def disable_mfa(conn, %{"nickname" => nickname}) do
682 case User.get_by_nickname(nickname) do
692 @doc "Show a given user's credentials"
693 def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
694 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
696 |> put_view(AccountView)
697 |> render("credentials.json", %{user: user, for: admin})
699 _ -> {:error, :not_found}
703 @doc "Updates a given user"
704 def update_user_credentials(
705 %{assigns: %{user: admin}} = conn,
706 %{"nickname" => nickname} = params
708 with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
710 User.update_as_admin(user, params) do
711 ModerationLog.insert_log(%{
714 action: "updated_users"
717 if params["password"] do
718 User.force_password_reset_async(user)
721 ModerationLog.insert_log(%{
724 action: "force_password_reset"
727 json(conn, %{status: "success"})
729 {:error, changeset} ->
730 {_, {error, _}} = Enum.at(changeset.errors, 0)
731 json(conn, %{error: "New password #{error}."})
734 json(conn, %{error: "Unable to change password."})
738 def list_reports(conn, params) do
739 {page, page_size} = page_params(params)
741 reports = Utils.get_reports(params, page, page_size)
744 |> put_view(ReportView)
745 |> render("index.json", %{reports: reports})
748 def report_show(conn, %{"id" => id}) do
749 with %Activity{} = report <- Activity.get_by_id(id) do
751 |> put_view(ReportView)
752 |> render("show.json", Report.extract_report_info(report))
754 _ -> {:error, :not_found}
758 def reports_update(%{assigns: %{user: admin}} = conn, %{"reports" => reports}) do
761 |> Enum.map(fn report ->
762 with {:ok, activity} <- CommonAPI.update_report_state(report["id"], report["state"]) do
763 ModerationLog.insert_log(%{
764 action: "report_update",
771 {:error, message} -> %{id: report["id"], error: message}
775 case Enum.any?(result, &Map.has_key?(&1, :error)) do
776 true -> json_response(conn, :bad_request, result)
777 false -> json_response(conn, :no_content, "")
781 def report_notes_create(%{assigns: %{user: user}} = conn, %{
785 with {:ok, _} <- ReportNote.create(user.id, report_id, content) do
786 ModerationLog.insert_log(%{
787 action: "report_note",
789 subject: Activity.get_by_id(report_id),
793 json_response(conn, :no_content, "")
795 _ -> json_response(conn, :bad_request, "")
799 def report_notes_delete(%{assigns: %{user: user}} = conn, %{
801 "report_id" => report_id
803 with {:ok, note} <- ReportNote.destroy(note_id) do
804 ModerationLog.insert_log(%{
805 action: "report_note_delete",
807 subject: Activity.get_by_id(report_id),
811 json_response(conn, :no_content, "")
813 _ -> json_response(conn, :bad_request, "")
817 def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
818 godmode = params["godmode"] == "true" || params["godmode"] == true
819 local_only = params["local_only"] == "true" || params["local_only"] == true
820 with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
821 {page, page_size} = page_params(params)
824 ActivityPub.fetch_statuses(nil, %{
825 "godmode" => godmode,
826 "local_only" => local_only,
827 "limit" => page_size,
828 "offset" => (page - 1) * page_size,
829 "exclude_reblogs" => !with_reblogs && "true"
833 |> put_view(AdminAPI.StatusView)
834 |> render("index.json", %{activities: activities, as: :activity})
837 def status_show(conn, %{"id" => id}) do
838 with %Activity{} = activity <- Activity.get_by_id(id) do
840 |> put_view(MastodonAPI.StatusView)
841 |> render("show.json", %{activity: activity})
843 _ -> errors(conn, {:error, :not_found})
847 def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
850 |> Map.take(["sensitive", "visibility"])
851 |> Map.new(fn {key, value} -> {String.to_existing_atom(key), value} end)
853 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
854 {:ok, sensitive} = Ecto.Type.cast(:boolean, params[:sensitive])
856 ModerationLog.insert_log(%{
857 action: "status_update",
860 sensitive: sensitive,
861 visibility: params[:visibility]
865 |> put_view(MastodonAPI.StatusView)
866 |> render("show.json", %{activity: activity})
870 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
871 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
872 ModerationLog.insert_log(%{
873 action: "status_delete",
882 def list_log(conn, params) do
883 {page, page_size} = page_params(params)
886 ModerationLog.get_all(%{
888 page_size: page_size,
889 start_date: params["start_date"],
890 end_date: params["end_date"],
891 user_id: params["user_id"],
892 search: params["search"]
896 |> put_view(ModerationLogView)
897 |> render("index.json", %{log: log})
900 def config_descriptions(conn, _params) do
901 descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
903 json(conn, descriptions)
906 def config_show(conn, %{"only_db" => true}) do
907 with :ok <- configurable_from_database(conn) do
908 configs = Pleroma.Repo.all(ConfigDB)
911 |> put_view(ConfigView)
912 |> render("index.json", %{configs: configs})
916 def config_show(conn, _params) do
917 with :ok <- configurable_from_database(conn) do
918 configs = ConfigDB.get_all_as_keyword()
921 Config.Holder.default_config()
922 |> ConfigDB.merge(configs)
923 |> Enum.map(fn {group, values} ->
924 Enum.map(values, fn {key, value} ->
926 if configs[group][key] do
927 ConfigDB.get_db_keys(configs[group][key], key)
930 db_value = configs[group][key]
933 if !is_nil(db_value) and Keyword.keyword?(db_value) and
934 ConfigDB.sub_key_full_update?(group, key, Keyword.keys(db_value)) do
935 ConfigDB.merge_group(group, key, value, db_value)
941 group: ConfigDB.convert(group),
942 key: ConfigDB.convert(key),
943 value: ConfigDB.convert(merged_value)
946 if db, do: Map.put(setting, :db, db), else: setting
951 json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
955 def config_update(conn, %{"configs" => configs}) do
956 with :ok <- configurable_from_database(conn) do
959 |> Enum.filter(&whitelisted_config?/1)
961 %{"group" => group, "key" => key, "delete" => true} = params ->
962 ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
964 %{"group" => group, "key" => key, "value" => value} ->
965 ConfigDB.update_or_create(%{group: group, key: key, value: value})
967 |> Enum.split_with(fn result -> elem(result, 0) == :error end)
971 |> Enum.map(fn {:ok, config} ->
972 Map.put(config, :db, ConfigDB.get_db_keys(config))
974 |> Enum.split_with(fn config ->
975 Ecto.get_meta(config, :state) == :deleted
978 Config.TransferTask.load_and_update_env(deleted, false)
980 if !Restarter.Pleroma.need_reboot?() do
981 changed_reboot_settings? =
983 |> Enum.any?(fn config ->
984 group = ConfigDB.from_string(config.group)
985 key = ConfigDB.from_string(config.key)
986 value = ConfigDB.from_binary(config.value)
987 Config.TransferTask.pleroma_need_restart?(group, key, value)
990 if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
994 |> put_view(ConfigView)
995 |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()})
999 def restart(conn, _params) do
1000 with :ok <- configurable_from_database(conn) do
1001 Restarter.Pleroma.restart(Config.get(:env), 50)
1007 def need_reboot(conn, _params) do
1008 json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
1011 defp configurable_from_database(conn) do
1012 if Config.get(:configurable_from_database) do
1017 {:error, "To use this endpoint you need to enable configuration from database."}
1022 defp whitelisted_config?(group, key) do
1023 if whitelisted_configs = Config.get(:database_config_whitelist) do
1024 Enum.any?(whitelisted_configs, fn
1025 {whitelisted_group} ->
1026 group == inspect(whitelisted_group)
1028 {whitelisted_group, whitelisted_key} ->
1029 group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
1036 defp whitelisted_config?(%{"group" => group, "key" => key}) do
1037 whitelisted_config?(group, key)
1040 defp whitelisted_config?(%{:group => group} = config) do
1041 whitelisted_config?(group, config[:key])
1044 def reload_emoji(conn, _params) do
1045 Pleroma.Emoji.reload()
1050 def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
1051 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
1053 User.toggle_confirmation(users)
1055 ModerationLog.insert_log(%{
1058 action: "confirm_email"
1064 def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
1065 users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
1067 User.try_send_confirmation_email(users)
1069 ModerationLog.insert_log(%{
1072 action: "resend_confirmation_email"
1078 def oauth_app_create(conn, params) do
1080 if params["name"] do
1081 Map.put(params, "client_name", params["name"])
1087 case App.create(params) do
1089 AppView.render("show.json", %{app: app, admin: true})
1091 {:error, changeset} ->
1092 App.errors(changeset)
1098 def oauth_app_update(conn, params) do
1100 if params["name"] do
1101 Map.put(params, "client_name", params["name"])
1106 with {:ok, app} <- App.update(params) do
1107 json(conn, AppView.render("show.json", %{app: app, admin: true}))
1109 {:error, changeset} ->
1110 json(conn, App.errors(changeset))
1113 json_response(conn, :bad_request, "")
1117 def oauth_app_list(conn, params) do
1118 {page, page_size} = page_params(params)
1121 client_name: params["name"],
1122 client_id: params["client_id"],
1124 page_size: page_size
1128 if Map.has_key?(params, "trusted") do
1129 Map.put(search_params, :trusted, params["trusted"])
1134 with {:ok, apps, count} <- App.search(search_params) do
1137 AppView.render("index.json",
1140 page_size: page_size,
1147 def oauth_app_delete(conn, params) do
1148 with {:ok, _app} <- App.destroy(params["id"]) do
1149 json_response(conn, :no_content, "")
1151 _ -> json_response(conn, :bad_request, "")
1155 def stats(conn, _) do
1156 count = Stats.get_status_visibility_count()
1159 |> json(%{"status_visibility" => count})
1162 defp errors(conn, {:error, :not_found}) do
1164 |> put_status(:not_found)
1165 |> json(dgettext("errors", "Not found"))
1168 defp errors(conn, {:error, reason}) do
1170 |> put_status(:bad_request)
1174 defp errors(conn, {:param_cast, _}) do
1176 |> put_status(:bad_request)
1177 |> json(dgettext("errors", "Invalid parameters"))
1180 defp errors(conn, _) do
1182 |> put_status(:internal_server_error)
1183 |> json(dgettext("errors", "Something went wrong"))
1186 defp page_params(params) do
1187 {get_page(params["page"]), get_page_size(params["page_size"])}
1190 defp get_page(page_string) when is_nil(page_string), do: 1
1192 defp get_page(page_string) do
1193 case Integer.parse(page_string) do
1199 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
1201 defp get_page_size(page_size_string) do
1202 case Integer.parse(page_size_string) do
1203 {page_size, _} -> page_size
1204 :error -> @users_page_size