Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
7.3KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.AdminAPI.UserController do
  5. use Pleroma.Web, :controller
  6. import Pleroma.Web.ControllerHelper,
  7. only: [fetch_integer_param: 3]
  8. alias Pleroma.ModerationLog
  9. alias Pleroma.User
  10. alias Pleroma.Web.ActivityPub.Builder
  11. alias Pleroma.Web.ActivityPub.Pipeline
  12. alias Pleroma.Web.AdminAPI
  13. alias Pleroma.Web.AdminAPI.Search
  14. alias Pleroma.Web.Plugs.OAuthScopesPlug
  15. @users_page_size 50
  16. plug(Pleroma.Web.ApiSpec.CastAndValidate)
  17. plug(
  18. OAuthScopesPlug,
  19. %{scopes: ["admin:read:accounts"]}
  20. when action in [:index, :show]
  21. )
  22. plug(
  23. OAuthScopesPlug,
  24. %{scopes: ["admin:write:accounts"]}
  25. when action in [
  26. :delete,
  27. :create,
  28. :toggle_activation,
  29. :activate,
  30. :deactivate,
  31. :approve
  32. ]
  33. )
  34. plug(
  35. OAuthScopesPlug,
  36. %{scopes: ["admin:write:follows"]}
  37. when action in [:follow, :unfollow]
  38. )
  39. action_fallback(AdminAPI.FallbackController)
  40. defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.Admin.UserOperation
  41. def delete(conn, %{nickname: nickname}) do
  42. conn
  43. |> Map.put(:body_params, %{nicknames: [nickname]})
  44. |> delete(%{})
  45. end
  46. def delete(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
  47. users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
  48. Enum.each(users, fn user ->
  49. {:ok, delete_data, _} = Builder.delete(admin, user.ap_id)
  50. Pipeline.common_pipeline(delete_data, local: true)
  51. end)
  52. ModerationLog.insert_log(%{
  53. actor: admin,
  54. subject: users,
  55. action: "delete"
  56. })
  57. json(conn, nicknames)
  58. end
  59. def follow(
  60. %{
  61. assigns: %{user: admin},
  62. body_params: %{
  63. follower: follower_nick,
  64. followed: followed_nick
  65. }
  66. } = conn,
  67. _
  68. ) do
  69. with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
  70. %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
  71. User.follow(follower, followed)
  72. ModerationLog.insert_log(%{
  73. actor: admin,
  74. followed: followed,
  75. follower: follower,
  76. action: "follow"
  77. })
  78. end
  79. json(conn, "ok")
  80. end
  81. def unfollow(
  82. %{
  83. assigns: %{user: admin},
  84. body_params: %{
  85. follower: follower_nick,
  86. followed: followed_nick
  87. }
  88. } = conn,
  89. _
  90. ) do
  91. with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
  92. %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
  93. User.unfollow(follower, followed)
  94. ModerationLog.insert_log(%{
  95. actor: admin,
  96. followed: followed,
  97. follower: follower,
  98. action: "unfollow"
  99. })
  100. end
  101. json(conn, "ok")
  102. end
  103. def create(%{assigns: %{user: admin}, body_params: %{users: users}} = conn, _) do
  104. changesets =
  105. users
  106. |> Enum.map(fn %{nickname: nickname, email: email, password: password} ->
  107. user_data = %{
  108. nickname: nickname,
  109. name: nickname,
  110. email: email,
  111. password: password,
  112. password_confirmation: password,
  113. bio: "."
  114. }
  115. User.register_changeset(%User{}, user_data, need_confirmation: false)
  116. end)
  117. |> Enum.reduce(Ecto.Multi.new(), fn changeset, multi ->
  118. Ecto.Multi.insert(multi, Ecto.UUID.generate(), changeset)
  119. end)
  120. case Pleroma.Repo.transaction(changesets) do
  121. {:ok, users_map} ->
  122. users =
  123. users_map
  124. |> Map.values()
  125. |> Enum.map(fn user ->
  126. {:ok, user} = User.post_register_action(user)
  127. user
  128. end)
  129. ModerationLog.insert_log(%{
  130. actor: admin,
  131. subjects: users,
  132. action: "create"
  133. })
  134. render(conn, "created_many.json", users: users)
  135. {:error, id, changeset, _} ->
  136. changesets =
  137. Enum.map(changesets.operations, fn
  138. {^id, {:changeset, _current_changeset, _}} ->
  139. changeset
  140. {_, {:changeset, current_changeset, _}} ->
  141. current_changeset
  142. end)
  143. conn
  144. |> put_status(:conflict)
  145. |> render("create_errors.json", changesets: changesets)
  146. end
  147. end
  148. def show(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
  149. with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
  150. render(conn, "show.json", %{user: user})
  151. else
  152. _ -> {:error, :not_found}
  153. end
  154. end
  155. def toggle_activation(%{assigns: %{user: admin}} = conn, %{nickname: nickname}) do
  156. user = User.get_cached_by_nickname(nickname)
  157. {:ok, updated_user} = User.set_activation(user, !user.is_active)
  158. action = if !user.is_active, do: "activate", else: "deactivate"
  159. ModerationLog.insert_log(%{
  160. actor: admin,
  161. subject: [user],
  162. action: action
  163. })
  164. render(conn, "show.json", user: updated_user)
  165. end
  166. def activate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
  167. users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
  168. {:ok, updated_users} = User.set_activation(users, true)
  169. ModerationLog.insert_log(%{
  170. actor: admin,
  171. subject: users,
  172. action: "activate"
  173. })
  174. render(conn, "index.json", users: Keyword.values(updated_users))
  175. end
  176. def deactivate(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
  177. users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
  178. {:ok, updated_users} = User.set_activation(users, false)
  179. ModerationLog.insert_log(%{
  180. actor: admin,
  181. subject: users,
  182. action: "deactivate"
  183. })
  184. render(conn, "index.json", users: Keyword.values(updated_users))
  185. end
  186. def approve(%{assigns: %{user: admin}, body_params: %{nicknames: nicknames}} = conn, _) do
  187. users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
  188. {:ok, updated_users} = User.approve(users)
  189. ModerationLog.insert_log(%{
  190. actor: admin,
  191. subject: users,
  192. action: "approve"
  193. })
  194. render(conn, "index.json", users: updated_users)
  195. end
  196. def index(conn, params) do
  197. {page, page_size} = page_params(params)
  198. filters = maybe_parse_filters(params[:filters])
  199. search_params =
  200. %{
  201. query: params[:query],
  202. page: page,
  203. page_size: page_size,
  204. tags: params[:tags],
  205. name: params[:name],
  206. email: params[:email],
  207. actor_types: params[:actor_types]
  208. }
  209. |> Map.merge(filters)
  210. with {:ok, users, count} <- Search.user(search_params) do
  211. render(conn, "index.json", users: users, count: count, page_size: page_size)
  212. end
  213. end
  214. @filters ~w(local external active deactivated need_approval unconfirmed is_admin is_moderator)
  215. @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
  216. defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
  217. defp maybe_parse_filters(filters) do
  218. filters
  219. |> String.split(",")
  220. |> Enum.filter(&Enum.member?(@filters, &1))
  221. |> Map.new(&{String.to_existing_atom(&1), true})
  222. end
  223. defp page_params(params) do
  224. {
  225. fetch_integer_param(params, :page, 1),
  226. fetch_integer_param(params, :page_size, @users_page_size)
  227. }
  228. end
  229. end