1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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
9 alias Pleroma.UserInviteToken
10 alias Pleroma.Web.ActivityPub.ActivityPub
11 alias Pleroma.Web.ActivityPub.Relay
12 alias Pleroma.Web.AdminAPI.AccountView
13 alias Pleroma.Web.AdminAPI.Config
14 alias Pleroma.Web.AdminAPI.ConfigView
15 alias Pleroma.Web.AdminAPI.ReportView
16 alias Pleroma.Web.AdminAPI.Search
17 alias Pleroma.Web.CommonAPI
18 alias Pleroma.Web.MastodonAPI.StatusView
20 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
26 action_fallback(:errors)
28 def user_delete(conn, %{"nickname" => nickname}) do
29 User.get_cached_by_nickname(nickname)
36 def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
37 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
38 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
39 User.follow(follower, followed)
46 def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
47 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
48 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
49 User.unfollow(follower, followed)
58 %{"nickname" => nickname, "email" => email, "password" => password}
65 password_confirmation: password,
69 changeset = User.register_changeset(%User{}, user_data, need_confirmation: false)
70 {:ok, user} = User.register(changeset)
73 |> json(user.nickname)
76 def user_show(conn, %{"nickname" => nickname}) do
77 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
79 |> json(AccountView.render("show.json", %{user: user}))
81 _ -> {:error, :not_found}
85 def list_user_statuses(conn, %{"nickname" => nickname} = params) do
86 godmode = params["godmode"] == "true" || params["godmode"] == true
88 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
89 {_, page_size} = page_params(params)
92 ActivityPub.fetch_user_activities(user, nil, %{
98 |> json(StatusView.render("index.json", %{activities: activities, as: :activity}))
100 _ -> {:error, :not_found}
104 def user_toggle_activation(conn, %{"nickname" => nickname}) do
105 user = User.get_cached_by_nickname(nickname)
107 {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
110 |> json(AccountView.render("show.json", %{user: updated_user}))
113 def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
114 with {:ok, _} <- User.tag(nicknames, tags),
115 do: json_response(conn, :no_content, "")
118 def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
119 with {:ok, _} <- User.untag(nicknames, tags),
120 do: json_response(conn, :no_content, "")
123 def list_users(conn, params) do
124 {page, page_size} = page_params(params)
125 filters = maybe_parse_filters(params["filters"])
128 query: params["query"],
130 page_size: page_size,
131 tags: params["tags"],
132 name: params["name"],
133 email: params["email"]
136 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
140 AccountView.render("index.json",
148 @filters ~w(local external active deactivated is_admin is_moderator)
150 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
151 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
153 defp maybe_parse_filters(filters) do
156 |> Enum.filter(&Enum.member?(@filters, &1))
157 |> Enum.map(&String.to_atom(&1))
158 |> Enum.into(%{}, &{&1, true})
161 def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
162 when permission_group in ["moderator", "admin"] do
163 user = User.get_cached_by_nickname(nickname)
167 |> Map.put("is_" <> permission_group, true)
169 info_cng = User.Info.admin_api_update(user.info, info)
173 |> Ecto.Changeset.change()
174 |> Ecto.Changeset.put_embed(:info, info_cng)
176 {:ok, _user} = User.update_and_set_cache(cng)
181 def right_add(conn, _) do
182 render_error(conn, :not_found, "No such permission_group")
185 def right_get(conn, %{"nickname" => nickname}) do
186 user = User.get_cached_by_nickname(nickname)
190 is_moderator: user.info.is_moderator,
191 is_admin: user.info.is_admin
196 %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
198 "permission_group" => permission_group,
199 "nickname" => nickname
202 when permission_group in ["moderator", "admin"] do
203 if admin_nickname == nickname do
204 render_error(conn, :forbidden, "You can't revoke your own admin status.")
206 user = User.get_cached_by_nickname(nickname)
210 |> Map.put("is_" <> permission_group, false)
212 info_cng = User.Info.admin_api_update(user.info, info)
215 Ecto.Changeset.change(user)
216 |> Ecto.Changeset.put_embed(:info, info_cng)
218 {:ok, _user} = User.update_and_set_cache(cng)
224 def right_delete(conn, _) do
225 render_error(conn, :not_found, "No such permission_group")
228 def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
229 with {:ok, status} <- Ecto.Type.cast(:boolean, status),
230 %User{} = user <- User.get_cached_by_nickname(nickname),
231 {:ok, _} <- User.deactivate(user, !status),
232 do: json_response(conn, :no_content, "")
235 def relay_follow(conn, %{"relay_url" => target}) do
236 with {:ok, _message} <- Relay.follow(target) do
246 def relay_unfollow(conn, %{"relay_url" => target}) do
247 with {:ok, _message} <- Relay.unfollow(target) do
257 @doc "Sends registration invite via email"
258 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
260 Pleroma.Config.get([:instance, :invites_enabled]) &&
261 !Pleroma.Config.get([:instance, :registrations_open]),
262 {:ok, invite_token} <- UserInviteToken.create_invite(),
264 Pleroma.Emails.UserEmail.user_invitation_email(
270 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
271 json_response(conn, :no_content, "")
275 @doc "Get a account registeration invite token (base64 string)"
276 def get_invite_token(conn, params) do
277 options = params["invite"] || %{}
278 {:ok, invite} = UserInviteToken.create_invite(options)
281 |> json(invite.token)
284 @doc "Get list of created invites"
285 def invites(conn, _params) do
286 invites = UserInviteToken.list_invites()
289 |> json(AccountView.render("invites.json", %{invites: invites}))
292 @doc "Revokes invite by token"
293 def revoke_invite(conn, %{"token" => token}) do
294 with {:ok, invite} <- UserInviteToken.find_by_token(token),
295 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true}) do
297 |> json(AccountView.render("invite.json", %{invite: updated_invite}))
299 nil -> {:error, :not_found}
303 @doc "Get a password reset token (base64 string) for given nickname"
304 def get_password_reset(conn, %{"nickname" => nickname}) do
305 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
306 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
312 def list_reports(conn, params) do
315 |> Map.put("type", "Flag")
316 |> Map.put("skip_preload", true)
320 |> ActivityPub.fetch_activities(params)
324 |> put_view(ReportView)
325 |> render("index.json", %{reports: reports})
328 def report_show(conn, %{"id" => id}) do
329 with %Activity{} = report <- Activity.get_by_id(id) do
331 |> put_view(ReportView)
332 |> render("show.json", %{report: report})
334 _ -> {:error, :not_found}
338 def report_update_state(conn, %{"id" => id, "state" => state}) do
339 with {:ok, report} <- CommonAPI.update_report_state(id, state) do
341 |> put_view(ReportView)
342 |> render("show.json", %{report: report})
346 def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
347 with false <- is_nil(params["status"]),
348 %Activity{} <- Activity.get_by_id(id) do
351 |> Map.put("in_reply_to_status_id", id)
352 |> Map.put("visibility", "direct")
354 {:ok, activity} = CommonAPI.post(user, params)
357 |> put_view(StatusView)
358 |> render("status.json", %{activity: activity})
368 def status_update(conn, %{"id" => id} = params) do
369 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
371 |> put_view(StatusView)
372 |> render("status.json", %{activity: activity})
376 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
377 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
382 def migrate_to_db(conn, _params) do
383 Mix.Tasks.Pleroma.Config.run(["migrate_to_db"])
387 def migrate_from_db(conn, _params) do
388 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "true"])
392 def config_show(conn, _params) do
393 configs = Pleroma.Repo.all(Config)
396 |> put_view(ConfigView)
397 |> render("index.json", %{configs: configs})
400 def config_update(conn, %{"configs" => configs}) do
402 if Pleroma.Config.get([:instance, :dynamic_configuration]) do
405 %{"group" => group, "key" => key, "delete" => "true"} = params ->
406 {:ok, config} = Config.delete(%{group: group, key: key, subkeys: params["subkeys"]})
409 %{"group" => group, "key" => key, "value" => value} ->
410 {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
413 |> Enum.reject(&is_nil(&1))
415 Pleroma.Config.TransferTask.load_and_update_env()
416 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"])
423 |> put_view(ConfigView)
424 |> render("index.json", %{configs: updated})
427 def errors(conn, {:error, :not_found}) do
429 |> put_status(:not_found)
430 |> json(dgettext("errors", "Not found"))
433 def errors(conn, {:error, reason}) do
435 |> put_status(:bad_request)
439 def errors(conn, {:param_cast, _}) do
441 |> put_status(:bad_request)
442 |> json(dgettext("errors", "Invalid parameters"))
445 def errors(conn, _) do
447 |> put_status(:internal_server_error)
448 |> json(dgettext("errors", "Something went wrong"))
451 defp page_params(params) do
452 {get_page(params["page"]), get_page_size(params["page_size"])}
455 defp get_page(page_string) when is_nil(page_string), do: 1
457 defp get_page(page_string) do
458 case Integer.parse(page_string) do
464 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
466 defp get_page_size(page_size_string) do
467 case Integer.parse(page_size_string) do
468 {page_size, _} -> page_size
469 :error -> @users_page_size