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 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
87 {_, page_size} = page_params(params)
90 ActivityPub.fetch_user_activities(user, nil, %{
95 |> json(StatusView.render("index.json", %{activities: activities, as: :activity}))
97 _ -> {:error, :not_found}
101 def user_toggle_activation(conn, %{"nickname" => nickname}) do
102 user = User.get_cached_by_nickname(nickname)
104 {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
107 |> json(AccountView.render("show.json", %{user: updated_user}))
110 def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
111 with {:ok, _} <- User.tag(nicknames, tags),
112 do: json_response(conn, :no_content, "")
115 def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
116 with {:ok, _} <- User.untag(nicknames, tags),
117 do: json_response(conn, :no_content, "")
120 def list_users(conn, params) do
121 {page, page_size} = page_params(params)
122 filters = maybe_parse_filters(params["filters"])
125 query: params["query"],
127 page_size: page_size,
128 tags: params["tags"],
129 name: params["name"],
130 email: params["email"]
133 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
137 AccountView.render("index.json",
145 @filters ~w(local external active deactivated is_admin is_moderator)
147 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
148 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
150 defp maybe_parse_filters(filters) do
153 |> Enum.filter(&Enum.member?(@filters, &1))
154 |> Enum.map(&String.to_atom(&1))
155 |> Enum.into(%{}, &{&1, true})
158 def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
159 when permission_group in ["moderator", "admin"] do
160 user = User.get_cached_by_nickname(nickname)
164 |> Map.put("is_" <> permission_group, true)
166 info_cng = User.Info.admin_api_update(user.info, info)
170 |> Ecto.Changeset.change()
171 |> Ecto.Changeset.put_embed(:info, info_cng)
173 {:ok, _user} = User.update_and_set_cache(cng)
178 def right_add(conn, _) do
179 render_error(conn, :not_found, "No such permission_group")
182 def right_get(conn, %{"nickname" => nickname}) do
183 user = User.get_cached_by_nickname(nickname)
187 is_moderator: user.info.is_moderator,
188 is_admin: user.info.is_admin
193 %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
195 "permission_group" => permission_group,
196 "nickname" => nickname
199 when permission_group in ["moderator", "admin"] do
200 if admin_nickname == nickname do
201 render_error(conn, :forbidden, "You can't revoke your own admin status.")
203 user = User.get_cached_by_nickname(nickname)
207 |> Map.put("is_" <> permission_group, false)
209 info_cng = User.Info.admin_api_update(user.info, info)
212 Ecto.Changeset.change(user)
213 |> Ecto.Changeset.put_embed(:info, info_cng)
215 {:ok, _user} = User.update_and_set_cache(cng)
221 def right_delete(conn, _) do
222 render_error(conn, :not_found, "No such permission_group")
225 def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
226 with {:ok, status} <- Ecto.Type.cast(:boolean, status),
227 %User{} = user <- User.get_cached_by_nickname(nickname),
228 {:ok, _} <- User.deactivate(user, !status),
229 do: json_response(conn, :no_content, "")
232 def relay_follow(conn, %{"relay_url" => target}) do
233 with {:ok, _message} <- Relay.follow(target) do
243 def relay_unfollow(conn, %{"relay_url" => target}) do
244 with {:ok, _message} <- Relay.unfollow(target) do
254 @doc "Sends registration invite via email"
255 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
257 Pleroma.Config.get([:instance, :invites_enabled]) &&
258 !Pleroma.Config.get([:instance, :registrations_open]),
259 {:ok, invite_token} <- UserInviteToken.create_invite(),
261 Pleroma.Emails.UserEmail.user_invitation_email(
267 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
268 json_response(conn, :no_content, "")
272 @doc "Get a account registeration invite token (base64 string)"
273 def get_invite_token(conn, params) do
274 options = params["invite"] || %{}
275 {:ok, invite} = UserInviteToken.create_invite(options)
278 |> json(invite.token)
281 @doc "Get list of created invites"
282 def invites(conn, _params) do
283 invites = UserInviteToken.list_invites()
286 |> json(AccountView.render("invites.json", %{invites: invites}))
289 @doc "Revokes invite by token"
290 def revoke_invite(conn, %{"token" => token}) do
291 invite = UserInviteToken.find_by_token!(token)
292 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true})
295 |> json(AccountView.render("invite.json", %{invite: updated_invite}))
298 @doc "Get a password reset token (base64 string) for given nickname"
299 def get_password_reset(conn, %{"nickname" => nickname}) do
300 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
301 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
307 def list_reports(conn, params) do
310 |> Map.put("type", "Flag")
311 |> Map.put("skip_preload", true)
315 |> ActivityPub.fetch_activities(params)
319 |> put_view(ReportView)
320 |> render("index.json", %{reports: reports})
323 def report_show(conn, %{"id" => id}) do
324 with %Activity{} = report <- Activity.get_by_id(id) do
326 |> put_view(ReportView)
327 |> render("show.json", %{report: report})
329 _ -> {:error, :not_found}
333 def report_update_state(conn, %{"id" => id, "state" => state}) do
334 with {:ok, report} <- CommonAPI.update_report_state(id, state) do
336 |> put_view(ReportView)
337 |> render("show.json", %{report: report})
341 def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
342 with false <- is_nil(params["status"]),
343 %Activity{} <- Activity.get_by_id(id) do
346 |> Map.put("in_reply_to_status_id", id)
347 |> Map.put("visibility", "direct")
349 {:ok, activity} = CommonAPI.post(user, params)
352 |> put_view(StatusView)
353 |> render("status.json", %{activity: activity})
363 def status_update(conn, %{"id" => id} = params) do
364 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
366 |> put_view(StatusView)
367 |> render("status.json", %{activity: activity})
371 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
372 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
377 def config_show(conn, _params) do
378 configs = Pleroma.Repo.all(Config)
381 |> put_view(ConfigView)
382 |> render("index.json", %{configs: configs})
385 def config_update(conn, %{"configs" => configs}) do
387 if Pleroma.Config.get([:instance, :dynamic_configuration]) do
390 %{"group" => group, "key" => key, "delete" => "true"} ->
391 {:ok, _} = Config.delete(%{group: group, key: key})
394 %{"group" => group, "key" => key, "value" => value} ->
395 {:ok, config} = Config.update_or_create(%{group: group, key: key, value: value})
398 |> Enum.reject(&is_nil(&1))
400 Pleroma.Config.TransferTask.load_and_update_env()
401 Mix.Tasks.Pleroma.Config.run(["migrate_from_db", Pleroma.Config.get(:env), "false"])
408 |> put_view(ConfigView)
409 |> render("index.json", %{configs: updated})
412 def errors(conn, {:error, :not_found}) do
414 |> put_status(:not_found)
415 |> json(dgettext("errors", "Not found"))
418 def errors(conn, {:error, reason}) do
420 |> put_status(:bad_request)
424 def errors(conn, {:param_cast, _}) do
426 |> put_status(:bad_request)
427 |> json(dgettext("errors", "Invalid parameters"))
430 def errors(conn, _) do
432 |> put_status(:internal_server_error)
433 |> json(dgettext("errors", "Something went wrong"))
436 defp page_params(params) do
437 {get_page(params["page"]), get_page_size(params["page_size"])}
440 defp get_page(page_string) when is_nil(page_string), do: 1
442 defp get_page(page_string) do
443 case Integer.parse(page_string) do
449 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
451 defp get_page_size(page_size_string) do
452 case Integer.parse(page_size_string) do
453 {page_size, _} -> page_size
454 :error -> @users_page_size