de2a13c015c80d172ca224583d485f47a0819da5
[akkoma] / lib / pleroma / web / admin_api / admin_api_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.AdminAPI.AdminAPIController do
6 use Pleroma.Web, :controller
7 alias Pleroma.Activity
8 alias Pleroma.User
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.ReportView
14 alias Pleroma.Web.AdminAPI.Search
15 alias Pleroma.Web.CommonAPI
16 alias Pleroma.Web.MastodonAPI.StatusView
17
18 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
19
20 require Logger
21
22 @users_page_size 50
23
24 action_fallback(:errors)
25
26 def user_delete(conn, %{"nickname" => nickname}) do
27 User.get_cached_by_nickname(nickname)
28 |> User.delete()
29
30 conn
31 |> json(nickname)
32 end
33
34 def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
35 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
36 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
37 User.follow(follower, followed)
38 end
39
40 conn
41 |> json("ok")
42 end
43
44 def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
45 with %User{} = follower <- User.get_cached_by_nickname(follower_nick),
46 %User{} = followed <- User.get_cached_by_nickname(followed_nick) do
47 User.unfollow(follower, followed)
48 end
49
50 conn
51 |> json("ok")
52 end
53
54 def user_create(
55 conn,
56 %{"nickname" => nickname, "email" => email, "password" => password}
57 ) do
58 user_data = %{
59 nickname: nickname,
60 name: nickname,
61 email: email,
62 password: password,
63 password_confirmation: password,
64 bio: "."
65 }
66
67 changeset = User.register_changeset(%User{}, user_data, need_confirmation: false)
68 {:ok, user} = User.register(changeset)
69
70 conn
71 |> json(user.nickname)
72 end
73
74 def user_show(conn, %{"nickname" => nickname}) do
75 with %User{} = user <- User.get_cached_by_nickname(nickname) do
76 conn
77 |> json(AccountView.render("show.json", %{user: user}))
78 else
79 _ -> {:error, :not_found}
80 end
81 end
82
83 def user_toggle_activation(conn, %{"nickname" => nickname}) do
84 user = User.get_cached_by_nickname(nickname)
85
86 {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
87
88 conn
89 |> json(AccountView.render("show.json", %{user: updated_user}))
90 end
91
92 def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
93 with {:ok, _} <- User.tag(nicknames, tags),
94 do: json_response(conn, :no_content, "")
95 end
96
97 def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
98 with {:ok, _} <- User.untag(nicknames, tags),
99 do: json_response(conn, :no_content, "")
100 end
101
102 def list_users(conn, params) do
103 {page, page_size} = page_params(params)
104 filters = maybe_parse_filters(params["filters"])
105
106 search_params = %{
107 query: params["query"],
108 page: page,
109 page_size: page_size,
110 tags: params["tags"],
111 name: params["name"],
112 email: params["email"]
113 }
114
115 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
116 do:
117 conn
118 |> json(
119 AccountView.render("index.json",
120 users: users,
121 count: count,
122 page_size: page_size
123 )
124 )
125 end
126
127 @filters ~w(local external active deactivated is_admin is_moderator)
128
129 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
130 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
131
132 defp maybe_parse_filters(filters) do
133 filters
134 |> String.split(",")
135 |> Enum.filter(&Enum.member?(@filters, &1))
136 |> Enum.map(&String.to_atom(&1))
137 |> Enum.into(%{}, &{&1, true})
138 end
139
140 def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
141 when permission_group in ["moderator", "admin"] do
142 user = User.get_cached_by_nickname(nickname)
143
144 info =
145 %{}
146 |> Map.put("is_" <> permission_group, true)
147
148 info_cng = User.Info.admin_api_update(user.info, info)
149
150 cng =
151 user
152 |> Ecto.Changeset.change()
153 |> Ecto.Changeset.put_embed(:info, info_cng)
154
155 {:ok, _user} = User.update_and_set_cache(cng)
156
157 json(conn, info)
158 end
159
160 def right_add(conn, _) do
161 conn
162 |> put_status(404)
163 |> json(%{error: "No such permission_group"})
164 end
165
166 def right_get(conn, %{"nickname" => nickname}) do
167 user = User.get_cached_by_nickname(nickname)
168
169 conn
170 |> json(%{
171 is_moderator: user.info.is_moderator,
172 is_admin: user.info.is_admin
173 })
174 end
175
176 def right_delete(
177 %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
178 %{
179 "permission_group" => permission_group,
180 "nickname" => nickname
181 }
182 )
183 when permission_group in ["moderator", "admin"] do
184 if admin_nickname == nickname do
185 conn
186 |> put_status(403)
187 |> json(%{error: "You can't revoke your own admin status."})
188 else
189 user = User.get_cached_by_nickname(nickname)
190
191 info =
192 %{}
193 |> Map.put("is_" <> permission_group, false)
194
195 info_cng = User.Info.admin_api_update(user.info, info)
196
197 cng =
198 Ecto.Changeset.change(user)
199 |> Ecto.Changeset.put_embed(:info, info_cng)
200
201 {:ok, _user} = User.update_and_set_cache(cng)
202
203 json(conn, info)
204 end
205 end
206
207 def right_delete(conn, _) do
208 conn
209 |> put_status(404)
210 |> json(%{error: "No such permission_group"})
211 end
212
213 def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
214 with {:ok, status} <- Ecto.Type.cast(:boolean, status),
215 %User{} = user <- User.get_cached_by_nickname(nickname),
216 {:ok, _} <- User.deactivate(user, !status),
217 do: json_response(conn, :no_content, "")
218 end
219
220 def relay_follow(conn, %{"relay_url" => target}) do
221 with {:ok, _message} <- Relay.follow(target) do
222 json(conn, target)
223 else
224 _ ->
225 conn
226 |> put_status(500)
227 |> json(target)
228 end
229 end
230
231 def relay_unfollow(conn, %{"relay_url" => target}) do
232 with {:ok, _message} <- Relay.unfollow(target) do
233 json(conn, target)
234 else
235 _ ->
236 conn
237 |> put_status(500)
238 |> json(target)
239 end
240 end
241
242 @doc "Sends registration invite via email"
243 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
244 with true <-
245 Pleroma.Config.get([:instance, :invites_enabled]) &&
246 !Pleroma.Config.get([:instance, :registrations_open]),
247 {:ok, invite_token} <- UserInviteToken.create_invite(),
248 email <-
249 Pleroma.Emails.UserEmail.user_invitation_email(
250 user,
251 invite_token,
252 email,
253 params["name"]
254 ),
255 {:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
256 json_response(conn, :no_content, "")
257 end
258 end
259
260 @doc "Get a account registeration invite token (base64 string)"
261 def get_invite_token(conn, params) do
262 options = params["invite"] || %{}
263 {:ok, invite} = UserInviteToken.create_invite(options)
264
265 conn
266 |> json(invite.token)
267 end
268
269 @doc "Get list of created invites"
270 def invites(conn, _params) do
271 invites = UserInviteToken.list_invites()
272
273 conn
274 |> json(AccountView.render("invites.json", %{invites: invites}))
275 end
276
277 @doc "Revokes invite by token"
278 def revoke_invite(conn, %{"token" => token}) do
279 invite = UserInviteToken.find_by_token!(token)
280 {:ok, updated_invite} = UserInviteToken.update_invite(invite, %{used: true})
281
282 conn
283 |> json(AccountView.render("invite.json", %{invite: updated_invite}))
284 end
285
286 @doc "Get a password reset token (base64 string) for given nickname"
287 def get_password_reset(conn, %{"nickname" => nickname}) do
288 (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
289 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
290
291 conn
292 |> json(token.token)
293 end
294
295 def list_reports(conn, params) do
296 params =
297 params
298 |> Map.put("type", "Flag")
299 |> Map.put("skip_preload", true)
300
301 reports =
302 []
303 |> ActivityPub.fetch_activities(params)
304 |> Enum.reverse()
305
306 conn
307 |> put_view(ReportView)
308 |> render("index.json", %{reports: reports})
309 end
310
311 def report_show(conn, %{"id" => id}) do
312 with %Activity{} = report <- Activity.get_by_id(id) do
313 conn
314 |> put_view(ReportView)
315 |> render("show.json", %{report: report})
316 else
317 _ -> {:error, :not_found}
318 end
319 end
320
321 def report_update_state(conn, %{"id" => id, "state" => state}) do
322 with {:ok, report} <- CommonAPI.update_report_state(id, state) do
323 conn
324 |> put_view(ReportView)
325 |> render("show.json", %{report: report})
326 end
327 end
328
329 def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do
330 with false <- is_nil(params["status"]),
331 %Activity{} <- Activity.get_by_id(id) do
332 params =
333 params
334 |> Map.put("in_reply_to_status_id", id)
335 |> Map.put("visibility", "direct")
336
337 {:ok, activity} = CommonAPI.post(user, params)
338
339 conn
340 |> put_view(StatusView)
341 |> render("status.json", %{activity: activity})
342 else
343 true ->
344 {:param_cast, nil}
345
346 nil ->
347 {:error, :not_found}
348 end
349 end
350
351 def status_update(conn, %{"id" => id} = params) do
352 with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do
353 conn
354 |> put_view(StatusView)
355 |> render("status.json", %{activity: activity})
356 end
357 end
358
359 def status_delete(%{assigns: %{user: user}} = conn, %{"id" => id}) do
360 with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
361 json(conn, %{})
362 end
363 end
364
365 def errors(conn, {:error, :not_found}) do
366 conn
367 |> put_status(404)
368 |> json("Not found")
369 end
370
371 def errors(conn, {:error, reason}) do
372 conn
373 |> put_status(400)
374 |> json(reason)
375 end
376
377 def errors(conn, {:param_cast, _}) do
378 conn
379 |> put_status(400)
380 |> json("Invalid parameters")
381 end
382
383 def errors(conn, _) do
384 conn
385 |> put_status(500)
386 |> json("Something went wrong")
387 end
388
389 defp page_params(params) do
390 {get_page(params["page"]), get_page_size(params["page_size"])}
391 end
392
393 defp get_page(page_string) when is_nil(page_string), do: 1
394
395 defp get_page(page_string) do
396 case Integer.parse(page_string) do
397 {page, _} -> page
398 :error -> 1
399 end
400 end
401
402 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
403
404 defp get_page_size(page_size_string) do
405 case Integer.parse(page_size_string) do
406 {page_size, _} -> page_size
407 :error -> @users_page_size
408 end
409 end
410 end