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 invite = UserInviteToken.find_by_token!(token)
295 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true})
298 |> json(AccountView.render("invite.json", %{invite: updated_invite}))
301 @doc "Get a password reset token (base64 string) for given nickname"
302 def get_password_reset(conn, %{"nickname" => nickname}) do
303 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
304 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
310 def list_reports(conn, params) do
313 |> Map.put("type", "Flag")
314 |> Map.put("skip_preload", true)
318 |> ActivityPub.fetch_activities(params)
322 |> put_view(ReportView)
323 |> render("index.json", %{reports: reports})
326 def report_show(conn, %{"id" => id}) do
327 with %Activity{} = report <- Activity.get_by_id(id) do
329 |> put_view(ReportView)
330 |> render("show.json", %{report: report})
332 _ -> {:error, :not_found}
336 def report_update_state(conn, %{"id" => id, "state" => state}) do
337 with {:ok, report} <- CommonAPI.update_report_state(id, state) do
339 |> put_view(ReportView)
340 |> render("show.json", %{report: report})
344 def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
345 with false <- is_nil(params["status"]),
346 %Activity{} <- Activity.get_by_id(id) do
349 |> Map.put("in_reply_to_status_id", id)
350 |> Map.put("visibility", "direct")
352 {:ok, activity} = CommonAPI.post(user, params)
355 |> put_view(StatusView)
356 |> render("status.json", %{activity: activity})
366 def status_update(conn, %{"id" => id} = params) do
367 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
369 |> put_view(StatusView)
370 |> render("status.json", %{activity: activity})
374 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
375 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
380 def config_show(conn, _params) do
381 configs = Pleroma.Repo.all(Config)
384 |> put_view(ConfigView)
385 |> render("index.json", %{configs: configs})
388 def config_update(conn, %{"configs" => configs}) do
390 if Pleroma.Config.get([:instance, :dynamic_configuration]) do
393 %{"group" => group, "key" => key, "delete" => "true"} ->
394 {:ok, _} = Config.delete(%{group: group, key: key})
397 %{"group" => group, "key" => key, "value" => value} ->
398 {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
401 |> Enum.reject(&is_nil(&1))
403 Pleroma.Config.TransferTask.load_and_update_env()
404 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"])
411 |> put_view(ConfigView)
412 |> render("index.json", %{configs: updated})
415 def errors(conn, {:error, :not_found}) do
417 |> put_status(:not_found)
418 |> json(dgettext("errors", "Not found"))
421 def errors(conn, {:error, reason}) do
423 |> put_status(:bad_request)
427 def errors(conn, {:param_cast, _}) do
429 |> put_status(:bad_request)
430 |> json(dgettext("errors", "Invalid parameters"))
433 def errors(conn, _) do
435 |> put_status(:internal_server_error)
436 |> json(dgettext("errors", "Something went wrong"))
439 defp page_params(params) do
440 {get_page(params["page"]), get_page_size(params["page_size"])}
443 defp get_page(page_string) when is_nil(page_string), do: 1
445 defp get_page(page_string) do
446 case Integer.parse(page_string) do
452 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
454 defp get_page_size(page_size_string) do
455 case Integer.parse(page_size_string) do
456 {page_size, _} -> page_size
457 :error -> @users_page_size