1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.AdminAPI.UserController do
6 use Pleroma.Web, :controller
8 import Pleroma.Web.ControllerHelper,
9 only: [fetch_integer_param: 3]
11 alias Pleroma.ModerationLog
13 alias Pleroma.Web.ActivityPub.Builder
14 alias Pleroma.Web.ActivityPub.Pipeline
15 alias Pleroma.Web.AdminAPI
16 alias Pleroma.Web.AdminAPI.AccountView
17 alias Pleroma.Web.AdminAPI.Search
18 alias Pleroma.Web.Plugs.OAuthScopesPlug
24 %{scopes: ["admin:read:accounts"]}
25 when action in [:list, :show]
30 %{scopes: ["admin:write:accounts"]}
43 %{scopes: ["admin:write:follows"]}
44 when action in [:follow, :unfollow]
47 action_fallback(AdminAPI.FallbackController)
49 def delete(conn, %{"nickname" => nickname}) do
50 delete(conn, %{"nicknames" => [nickname]})
53 def delete(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
54 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
56 Enum.each(users, fn user ->
57 {:ok, delete_data, _} = Builder.delete(admin, user.ap_id)
58 Pipeline.common_pipeline(delete_data, local: true)
61 ModerationLog.insert_log(%{
70 def follow(%{assigns: %{user: admin}} = conn, %{
71 "follower" => follower_nick,
72 "followed" => followed_nick
74 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
75 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
76 User.follow(follower, followed)
78 ModerationLog.insert_log(%{
89 def unfollow(%{assigns: %{user: admin}} = conn, %{
90 "follower" => follower_nick,
91 "followed" => followed_nick
93 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
94 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
95 User.unfollow(follower, followed)
97 ModerationLog.insert_log(%{
108 def create(%{assigns: %{user: admin}} = conn, %{"users" => users}) do
110 Enum.map(users, fn %{"nickname" => nickname, "email" => email, "password" => password} ->
116 password_confirmation: password,
120 User.register_changeset(%User{}, user_data, need_confirmation: false)
122 |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
123 Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
126 case Pleroma.Repo.transaction(changesets) do
131 |> Enum.map(fn user ->
132 {:ok, user} = User.post_register_action(user)
136 |> Enum.map(&AccountView.render("created.json", %{user: &1}))
138 ModerationLog.insert_log(%{
140 subjects: Map.values(users),
146 {:error, id, changeset, _} ->
148 Enum.map(changesets.operations, fn
149 {current_id, {:changeset, _current_changeset, _}} when current_id == id ->
150 AccountView.render("create-error.json", %{changeset: changeset})
152 {_, {:changeset, current_changeset, _}} ->
153 AccountView.render("create-error.json", %{changeset: current_changeset})
157 |> put_status(:conflict)
162 def show(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
163 with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
165 |> put_view(AccountView)
166 |> render("show.json", %{user: user})
168 _ -> {:error, :not_found}
172 def toggle_activation(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
173 user = User.get_cached_by_nickname(nickname)
175 {:ok, updated_user} = User.set_activation(user, !user.is_active)
177 action = if !user.is_active, do: "activate", else: "deactivate"
179 ModerationLog.insert_log(%{
186 |> put_view(AccountView)
187 |> render("show.json", %{user: updated_user})
190 def activate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
191 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
192 {:ok, updated_users} = User.set_activation(users, true)
194 ModerationLog.insert_log(%{
201 |> put_view(AccountView)
202 |> render("index.json", %{users: Keyword.values(updated_users)})
205 def deactivate(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
206 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
207 {:ok, updated_users} = User.set_activation(users, false)
209 ModerationLog.insert_log(%{
216 |> put_view(AccountView)
217 |> render("index.json", %{users: Keyword.values(updated_users)})
220 def approve(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
221 users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
222 {:ok, updated_users} = User.approve(users)
224 ModerationLog.insert_log(%{
231 |> put_view(AccountView)
232 |> render("index.json", %{users: updated_users})
235 def list(conn, params) do
236 {page, page_size} = page_params(params)
237 filters = maybe_parse_filters(params["filters"])
241 query: params["query"],
243 page_size: page_size,
244 tags: params["tags"],
245 name: params["name"],
246 email: params["email"],
247 actor_types: params["actor_types"]
249 |> Map.merge(filters)
251 with {:ok, users, count} <- Search.user(search_params) do
254 AccountView.render("index.json",
263 @filters ~w(local external active deactivated need_approval unconfirmed is_admin is_moderator)
265 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
266 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
268 defp maybe_parse_filters(filters) do
271 |> Enum.filter(&Enum.member?(@filters, &1))
272 |> Map.new(&{String.to_existing_atom(&1), true})
275 defp page_params(params) do
277 fetch_integer_param(params, "page", 1),
278 fetch_integer_param(params, "page_size", @users_page_size)