#1110 fixed /api/pleroma/healthcheck
[akkoma] / lib / pleroma / web / twitter_api / controllers / util_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.TwitterAPI.UtilController do
6 use Pleroma.Web, :controller
7
8 require Logger
9
10 alias Pleroma.Activity
11 alias Pleroma.Config
12 alias Pleroma.Emoji
13 alias Pleroma.Healthcheck
14 alias Pleroma.Notification
15 alias Pleroma.Plugs.AuthenticationPlug
16 alias Pleroma.User
17 alias Pleroma.Web
18 alias Pleroma.Web.ActivityPub.ActivityPub
19 alias Pleroma.Web.CommonAPI
20 alias Pleroma.Web.OStatus
21 alias Pleroma.Web.WebFinger
22
23 def help_test(conn, _params) do
24 json(conn, "ok")
25 end
26
27 def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
28 with %User{} = user <- User.get_cached_by_nickname(nick),
29 avatar = User.avatar_url(user) do
30 conn
31 |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
32 else
33 _e ->
34 render(conn, "subscribe.html", %{
35 nickname: nick,
36 avatar: nil,
37 error: "Could not find user"
38 })
39 end
40 end
41
42 def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
43 with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
44 %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
45 conn
46 |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
47 else
48 _e ->
49 render(conn, "subscribe.html", %{
50 nickname: nick,
51 avatar: nil,
52 error: "Something went wrong."
53 })
54 end
55 end
56
57 def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
58 if is_status?(acct) do
59 {:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct)
60 %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
61 redirect(conn, to: "/notice/#{activity_id}")
62 else
63 {err, followee} = OStatus.find_or_make_user(acct)
64 avatar = User.avatar_url(followee)
65 name = followee.nickname
66 id = followee.id
67
68 if !!user do
69 conn
70 |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
71 else
72 conn
73 |> render("follow_login.html", %{
74 error: false,
75 acct: acct,
76 avatar: avatar,
77 name: name,
78 id: id
79 })
80 end
81 end
82 end
83
84 defp is_status?(acct) do
85 case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
86 {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
87 true
88
89 _ ->
90 false
91 end
92 end
93
94 def do_remote_follow(conn, %{
95 "authorization" => %{"name" => username, "password" => password, "id" => id}
96 }) do
97 followee = User.get_cached_by_id(id)
98 avatar = User.avatar_url(followee)
99 name = followee.nickname
100
101 with %User{} = user <- User.get_cached_by_nickname(username),
102 true <- AuthenticationPlug.checkpw(password, user.password_hash),
103 %User{} = _followed <- User.get_cached_by_id(id),
104 {:ok, follower} <- User.follow(user, followee),
105 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
106 conn
107 |> render("followed.html", %{error: false})
108 else
109 # Was already following user
110 {:error, "Could not follow user:" <> _rest} ->
111 render(conn, "followed.html", %{error: false})
112
113 _e ->
114 conn
115 |> render("follow_login.html", %{
116 error: "Wrong username or password",
117 id: id,
118 name: name,
119 avatar: avatar
120 })
121 end
122 end
123
124 def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
125 with %User{} = followee <- User.get_cached_by_id(id),
126 {:ok, follower} <- User.follow(user, followee),
127 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
128 conn
129 |> render("followed.html", %{error: false})
130 else
131 # Was already following user
132 {:error, "Could not follow user:" <> _rest} ->
133 conn
134 |> render("followed.html", %{error: false})
135
136 e ->
137 Logger.debug("Remote follow failed with error #{inspect(e)}")
138
139 conn
140 |> render("followed.html", %{error: inspect(e)})
141 end
142 end
143
144 def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
145 with {:ok, _} <- Notification.read_one(user, notification_id) do
146 json(conn, %{status: "success"})
147 else
148 {:error, message} ->
149 conn
150 |> put_resp_content_type("application/json")
151 |> send_resp(403, Jason.encode!(%{"error" => message}))
152 end
153 end
154
155 def config(conn, _params) do
156 instance = Pleroma.Config.get(:instance)
157
158 case get_format(conn) do
159 "xml" ->
160 response = """
161 <config>
162 <site>
163 <name>#{Keyword.get(instance, :name)}</name>
164 <site>#{Web.base_url()}</site>
165 <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
166 <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
167 </site>
168 </config>
169 """
170
171 conn
172 |> put_resp_content_type("application/xml")
173 |> send_resp(200, response)
174
175 _ ->
176 vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
177
178 uploadlimit = %{
179 uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
180 avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
181 backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
182 bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
183 }
184
185 data = %{
186 name: Keyword.get(instance, :name),
187 description: Keyword.get(instance, :description),
188 server: Web.base_url(),
189 textlimit: to_string(Keyword.get(instance, :limit)),
190 uploadlimit: uploadlimit,
191 closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
192 private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
193 vapidPublicKey: vapid_public_key,
194 accountActivationRequired:
195 if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
196 invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"),
197 safeDMMentionsEnabled:
198 if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0")
199 }
200
201 pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
202
203 managed_config = Keyword.get(instance, :managed_config)
204
205 data =
206 if managed_config do
207 data |> Map.put("pleromafe", pleroma_fe)
208 else
209 data
210 end
211
212 json(conn, %{site: data})
213 end
214 end
215
216 def frontend_configurations(conn, _params) do
217 config =
218 Pleroma.Config.get(:frontend_configurations, %{})
219 |> Enum.into(%{})
220
221 json(conn, config)
222 end
223
224 def version(conn, _params) do
225 version = Pleroma.Application.named_version()
226
227 case get_format(conn) do
228 "xml" ->
229 response = "<version>#{version}</version>"
230
231 conn
232 |> put_resp_content_type("application/xml")
233 |> send_resp(200, response)
234
235 _ ->
236 json(conn, version)
237 end
238 end
239
240 def emoji(conn, _params) do
241 emoji =
242 Emoji.get_all()
243 |> Enum.map(fn {short_code, path, tags} ->
244 {short_code, %{image_url: path, tags: tags}}
245 end)
246 |> Enum.into(%{})
247
248 json(conn, emoji)
249 end
250
251 def update_notificaton_settings(%{assigns: %{user: user}} = conn, params) do
252 with {:ok, _} <- User.update_notification_settings(user, params) do
253 json(conn, %{status: "success"})
254 end
255 end
256
257 def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
258 follow_import(conn, %{"list" => File.read!(listfile.path)})
259 end
260
261 def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
262 with lines <- String.split(list, "\n"),
263 followed_identifiers <-
264 Enum.map(lines, fn line ->
265 String.split(line, ",") |> List.first()
266 end)
267 |> List.delete("Account address") do
268 PleromaJobQueue.enqueue(:background, User, [
269 :follow_import,
270 follower,
271 followed_identifiers
272 ])
273
274 json(conn, "job started")
275 end
276 end
277
278 def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
279 blocks_import(conn, %{"list" => File.read!(listfile.path)})
280 end
281
282 def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
283 with blocked_identifiers <- String.split(list) do
284 PleromaJobQueue.enqueue(:background, User, [
285 :blocks_import,
286 blocker,
287 blocked_identifiers
288 ])
289
290 json(conn, "job started")
291 end
292 end
293
294 def change_password(%{assigns: %{user: user}} = conn, params) do
295 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
296 {:ok, user} ->
297 with {:ok, _user} <-
298 User.reset_password(user, %{
299 password: params["new_password"],
300 password_confirmation: params["new_password_confirmation"]
301 }) do
302 json(conn, %{status: "success"})
303 else
304 {:error, changeset} ->
305 {_, {error, _}} = Enum.at(changeset.errors, 0)
306 json(conn, %{error: "New password #{error}."})
307
308 _ ->
309 json(conn, %{error: "Unable to change password."})
310 end
311
312 {:error, msg} ->
313 json(conn, %{error: msg})
314 end
315 end
316
317 def delete_account(%{assigns: %{user: user}} = conn, params) do
318 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
319 {:ok, user} ->
320 User.delete(user)
321 json(conn, %{status: "success"})
322
323 {:error, msg} ->
324 json(conn, %{error: msg})
325 end
326 end
327
328 def disable_account(%{assigns: %{user: user}} = conn, params) do
329 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
330 {:ok, user} ->
331 User.deactivate_async(user)
332 json(conn, %{status: "success"})
333
334 {:error, msg} ->
335 json(conn, %{error: msg})
336 end
337 end
338
339 def captcha(conn, _params) do
340 json(conn, Pleroma.Captcha.new())
341 end
342
343 def healthcheck(conn, _params) do
344 with true <- Config.get([:instance, :healthcheck]),
345 %{healthy: true} = info <- Healthcheck.system_info() do
346 json(conn, info)
347 else
348 %{healthy: false} = info ->
349 service_unavailable(conn, info)
350
351 _ ->
352 service_unavailable(conn, %{})
353 end
354 end
355
356 defp service_unavailable(conn, info) do
357 conn
358 |> put_status(:service_unavailable)
359 |> json(info)
360 end
361 end