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