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