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