Merge branch 'feature/admin-api-follow' into 'develop'
[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.User
8 alias Pleroma.Web.ActivityPub.Relay
9 alias Pleroma.Web.AdminAPI.AccountView
10 alias Pleroma.Web.AdminAPI.Search
11
12 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
13
14 require Logger
15
16 @users_page_size 50
17
18 action_fallback(:errors)
19
20 def user_delete(conn, %{"nickname" => nickname}) do
21 User.get_by_nickname(nickname)
22 |> User.delete()
23
24 conn
25 |> json(nickname)
26 end
27
28 def user_follow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
29 with %User{} = follower <- User.get_by_nickname(follower_nick),
30 %User{} = followed <- User.get_by_nickname(followed_nick) do
31 User.follow(follower, followed)
32 end
33
34 conn
35 |> json("ok")
36 end
37
38 def user_unfollow(conn, %{"follower" => follower_nick, "followed" => followed_nick}) do
39 with %User{} = follower <- User.get_by_nickname(follower_nick),
40 %User{} = followed <- User.get_by_nickname(followed_nick) do
41 User.unfollow(follower, followed)
42 end
43
44 conn
45 |> json("ok")
46 end
47
48 def user_create(
49 conn,
50 %{"nickname" => nickname, "email" => email, "password" => password}
51 ) do
52 user_data = %{
53 nickname: nickname,
54 name: nickname,
55 email: email,
56 password: password,
57 password_confirmation: password,
58 bio: "."
59 }
60
61 changeset = User.register_changeset(%User{}, user_data, confirmed: true)
62 {:ok, user} = User.register(changeset)
63
64 conn
65 |> json(user.nickname)
66 end
67
68 def user_show(conn, %{"nickname" => nickname}) do
69 with %User{} = user <- User.get_by_nickname(nickname) do
70 conn
71 |> json(AccountView.render("show.json", %{user: user}))
72 else
73 _ -> {:error, :not_found}
74 end
75 end
76
77 def user_toggle_activation(conn, %{"nickname" => nickname}) do
78 user = User.get_by_nickname(nickname)
79
80 {:ok, updated_user} = User.deactivate(user, !user.info.deactivated)
81
82 conn
83 |> json(AccountView.render("show.json", %{user: updated_user}))
84 end
85
86 def tag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
87 with {:ok, _} <- User.tag(nicknames, tags),
88 do: json_response(conn, :no_content, "")
89 end
90
91 def untag_users(conn, %{"nicknames" => nicknames, "tags" => tags}) do
92 with {:ok, _} <- User.untag(nicknames, tags),
93 do: json_response(conn, :no_content, "")
94 end
95
96 def list_users(conn, params) do
97 {page, page_size} = page_params(params)
98 filters = maybe_parse_filters(params["filters"])
99
100 search_params = %{
101 query: params["query"],
102 page: page,
103 page_size: page_size
104 }
105
106 with {:ok, users, count} <- Search.user(Map.merge(search_params, filters)),
107 do:
108 conn
109 |> json(
110 AccountView.render("index.json",
111 users: users,
112 count: count,
113 page_size: page_size
114 )
115 )
116 end
117
118 @filters ~w(local external active deactivated)
119
120 defp maybe_parse_filters(filters) when is_nil(filters) or filters == "", do: %{}
121
122 @spec maybe_parse_filters(String.t()) :: %{required(String.t()) => true} | %{}
123 defp maybe_parse_filters(filters) do
124 filters
125 |> String.split(",")
126 |> Enum.filter(&Enum.member?(@filters, &1))
127 |> Enum.map(&String.to_atom(&1))
128 |> Enum.into(%{}, &{&1, true})
129 end
130
131 def right_add(conn, %{"permission_group" => permission_group, "nickname" => nickname})
132 when permission_group in ["moderator", "admin"] do
133 user = User.get_by_nickname(nickname)
134
135 info =
136 %{}
137 |> Map.put("is_" <> permission_group, true)
138
139 info_cng = User.Info.admin_api_update(user.info, info)
140
141 cng =
142 user
143 |> Ecto.Changeset.change()
144 |> Ecto.Changeset.put_embed(:info, info_cng)
145
146 {:ok, _user} = User.update_and_set_cache(cng)
147
148 json(conn, info)
149 end
150
151 def right_add(conn, _) do
152 conn
153 |> put_status(404)
154 |> json(%{error: "No such permission_group"})
155 end
156
157 def right_get(conn, %{"nickname" => nickname}) do
158 user = User.get_by_nickname(nickname)
159
160 conn
161 |> json(%{
162 is_moderator: user.info.is_moderator,
163 is_admin: user.info.is_admin
164 })
165 end
166
167 def right_delete(
168 %{assigns: %{user: %User{:nickname => admin_nickname}}} = conn,
169 %{
170 "permission_group" => permission_group,
171 "nickname" => nickname
172 }
173 )
174 when permission_group in ["moderator", "admin"] do
175 if admin_nickname == nickname do
176 conn
177 |> put_status(403)
178 |> json(%{error: "You can't revoke your own admin status."})
179 else
180 user = User.get_by_nickname(nickname)
181
182 info =
183 %{}
184 |> Map.put("is_" <> permission_group, false)
185
186 info_cng = User.Info.admin_api_update(user.info, info)
187
188 cng =
189 Ecto.Changeset.change(user)
190 |> Ecto.Changeset.put_embed(:info, info_cng)
191
192 {:ok, _user} = User.update_and_set_cache(cng)
193
194 json(conn, info)
195 end
196 end
197
198 def right_delete(conn, _) do
199 conn
200 |> put_status(404)
201 |> json(%{error: "No such permission_group"})
202 end
203
204 def set_activation_status(conn, %{"nickname" => nickname, "status" => status}) do
205 with {:ok, status} <- Ecto.Type.cast(:boolean, status),
206 %User{} = user <- User.get_by_nickname(nickname),
207 {:ok, _} <- User.deactivate(user, !status),
208 do: json_response(conn, :no_content, "")
209 end
210
211 def relay_follow(conn, %{"relay_url" => target}) do
212 with {:ok, _message} <- Relay.follow(target) do
213 json(conn, target)
214 else
215 _ ->
216 conn
217 |> put_status(500)
218 |> json(target)
219 end
220 end
221
222 def relay_unfollow(conn, %{"relay_url" => target}) do
223 with {:ok, _message} <- Relay.unfollow(target) do
224 json(conn, target)
225 else
226 _ ->
227 conn
228 |> put_status(500)
229 |> json(target)
230 end
231 end
232
233 @doc "Sends registration invite via email"
234 def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
235 with true <-
236 Pleroma.Config.get([:instance, :invites_enabled]) &&
237 !Pleroma.Config.get([:instance, :registrations_open]),
238 {:ok, invite_token} <- Pleroma.UserInviteToken.create_token(),
239 email <-
240 Pleroma.UserEmail.user_invitation_email(user, invite_token, email, params["name"]),
241 {:ok, _} <- Pleroma.Mailer.deliver(email) do
242 json_response(conn, :no_content, "")
243 end
244 end
245
246 @doc "Get a account registeration invite token (base64 string)"
247 def get_invite_token(conn, _params) do
248 {:ok, token} = Pleroma.UserInviteToken.create_token()
249
250 conn
251 |> json(token.token)
252 end
253
254 @doc "Get a password reset token (base64 string) for given nickname"
255 def get_password_reset(conn, %{"nickname" => nickname}) do
256 (%User{local: true} = user) = User.get_by_nickname(nickname)
257 {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
258
259 conn
260 |> json(token.token)
261 end
262
263 def errors(conn, {:error, :not_found}) do
264 conn
265 |> put_status(404)
266 |> json("Not found")
267 end
268
269 def errors(conn, {:param_cast, _}) do
270 conn
271 |> put_status(400)
272 |> json("Invalid parameters")
273 end
274
275 def errors(conn, _) do
276 conn
277 |> put_status(500)
278 |> json("Something went wrong")
279 end
280
281 defp page_params(params) do
282 {get_page(params["page"]), get_page_size(params["page_size"])}
283 end
284
285 defp get_page(page_string) when is_nil(page_string), do: 1
286
287 defp get_page(page_string) do
288 case Integer.parse(page_string) do
289 {page, _} -> page
290 :error -> 1
291 end
292 end
293
294 defp get_page_size(page_size_string) when is_nil(page_size_string), do: @users_page_size
295
296 defp get_page_size(page_size_string) do
297 case Integer.parse(page_size_string) do
298 {page_size, _} -> page_size
299 :error -> @users_page_size
300 end
301 end
302 end