fd2aee17569c241ca4d715349f27e0a65a8ad40c
[akkoma] / lib / pleroma / web / twitter_api / controllers / util_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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.Config
11 alias Pleroma.Emoji
12 alias Pleroma.Healthcheck
13 alias Pleroma.Notification
14 alias Pleroma.Plugs.OAuthScopesPlug
15 alias Pleroma.User
16 alias Pleroma.Web
17 alias Pleroma.Web.CommonAPI
18 alias Pleroma.Web.WebFinger
19
20 plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe)
21
22 plug(
23 OAuthScopesPlug,
24 %{scopes: ["follow", "write:follows"]}
25 when action == :follow_import
26 )
27
28 plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import)
29
30 plug(
31 OAuthScopesPlug,
32 %{scopes: ["write:accounts"]}
33 when action in [
34 :change_email,
35 :change_password,
36 :delete_account,
37 :update_notificaton_settings,
38 :disable_account
39 ]
40 )
41
42 plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
43
44 plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version])
45
46 def help_test(conn, _params) do
47 json(conn, "ok")
48 end
49
50 def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
51 with %User{} = user <- User.get_cached_by_nickname(nick),
52 avatar = User.avatar_url(user) do
53 conn
54 |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
55 else
56 _e ->
57 render(conn, "subscribe.html", %{
58 nickname: nick,
59 avatar: nil,
60 error: "Could not find user"
61 })
62 end
63 end
64
65 def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
66 with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
67 %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
68 conn
69 |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
70 else
71 _e ->
72 render(conn, "subscribe.html", %{
73 nickname: nick,
74 avatar: nil,
75 error: "Something went wrong."
76 })
77 end
78 end
79
80 def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
81 with {:ok, _} <- Notification.read_one(user, notification_id) do
82 json(conn, %{status: "success"})
83 else
84 {:error, message} ->
85 conn
86 |> put_resp_content_type("application/json")
87 |> send_resp(403, Jason.encode!(%{"error" => message}))
88 end
89 end
90
91 def config(%{assigns: %{format: "xml"}} = conn, _params) do
92 instance = Pleroma.Config.get(:instance)
93
94 response = """
95 <config>
96 <site>
97 <name>#{Keyword.get(instance, :name)}</name>
98 <site>#{Web.base_url()}</site>
99 <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
100 <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
101 </site>
102 </config>
103 """
104
105 conn
106 |> put_resp_content_type("application/xml")
107 |> send_resp(200, response)
108 end
109
110 def config(conn, _params) do
111 instance = Pleroma.Config.get(:instance)
112
113 vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
114
115 uploadlimit = %{
116 uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
117 avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
118 backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
119 bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
120 }
121
122 data = %{
123 name: Keyword.get(instance, :name),
124 description: Keyword.get(instance, :description),
125 server: Web.base_url(),
126 textlimit: to_string(Keyword.get(instance, :limit)),
127 uploadlimit: uploadlimit,
128 closed: bool_to_val(Keyword.get(instance, :registrations_open), "0", "1"),
129 private: bool_to_val(Keyword.get(instance, :public, true), "0", "1"),
130 vapidPublicKey: vapid_public_key,
131 accountActivationRequired:
132 bool_to_val(Keyword.get(instance, :account_activation_required, false)),
133 invitesEnabled: bool_to_val(Keyword.get(instance, :invites_enabled, false)),
134 safeDMMentionsEnabled: bool_to_val(Pleroma.Config.get([:instance, :safe_dm_mentions]))
135 }
136
137 managed_config = Keyword.get(instance, :managed_config)
138
139 data =
140 if managed_config do
141 pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
142 Map.put(data, "pleromafe", pleroma_fe)
143 else
144 data
145 end
146
147 json(conn, %{site: data})
148 end
149
150 defp bool_to_val(true), do: "1"
151 defp bool_to_val(_), do: "0"
152 defp bool_to_val(true, val, _), do: val
153 defp bool_to_val(_, _, val), do: val
154
155 def frontend_configurations(conn, _params) do
156 config =
157 Pleroma.Config.get(:frontend_configurations, %{})
158 |> Enum.into(%{})
159
160 json(conn, config)
161 end
162
163 def version(%{assigns: %{format: "xml"}} = conn, _params) do
164 version = Pleroma.Application.named_version()
165
166 conn
167 |> put_resp_content_type("application/xml")
168 |> send_resp(200, "<version>#{version}</version>")
169 end
170
171 def version(conn, _params) do
172 json(conn, Pleroma.Application.named_version())
173 end
174
175 def emoji(conn, _params) do
176 emoji =
177 Enum.reduce(Emoji.get_all(), %{}, fn {code, %Emoji{file: file, tags: tags}}, acc ->
178 Map.put(acc, code, %{image_url: file, tags: tags})
179 end)
180
181 json(conn, emoji)
182 end
183
184 def update_notificaton_settings(%{assigns: %{user: user}} = conn, params) do
185 with {:ok, _} <- User.update_notification_settings(user, params) do
186 json(conn, %{status: "success"})
187 end
188 end
189
190 def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
191 follow_import(conn, %{"list" => File.read!(listfile.path)})
192 end
193
194 def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
195 followed_identifiers =
196 list
197 |> String.split("\n")
198 |> Enum.map(&(&1 |> String.split(",") |> List.first()))
199 |> List.delete("Account address")
200 |> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
201 |> Enum.reject(&(&1 == ""))
202
203 User.follow_import(follower, followed_identifiers)
204 json(conn, "job started")
205 end
206
207 def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
208 blocks_import(conn, %{"list" => File.read!(listfile.path)})
209 end
210
211 def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
212 blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@"))
213 User.blocks_import(blocker, blocked_identifiers)
214 json(conn, "job started")
215 end
216
217 def change_password(%{assigns: %{user: user}} = conn, params) do
218 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
219 {:ok, user} ->
220 with {:ok, _user} <-
221 User.reset_password(user, %{
222 password: params["new_password"],
223 password_confirmation: params["new_password_confirmation"]
224 }) do
225 json(conn, %{status: "success"})
226 else
227 {:error, changeset} ->
228 {_, {error, _}} = Enum.at(changeset.errors, 0)
229 json(conn, %{error: "New password #{error}."})
230
231 _ ->
232 json(conn, %{error: "Unable to change password."})
233 end
234
235 {:error, msg} ->
236 json(conn, %{error: msg})
237 end
238 end
239
240 def change_email(%{assigns: %{user: user}} = conn, params) do
241 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
242 {:ok, user} ->
243 with {:ok, _user} <- User.change_email(user, params["email"]) do
244 json(conn, %{status: "success"})
245 else
246 {:error, changeset} ->
247 {_, {error, _}} = Enum.at(changeset.errors, 0)
248 json(conn, %{error: "Email #{error}."})
249
250 _ ->
251 json(conn, %{error: "Unable to change email."})
252 end
253
254 {:error, msg} ->
255 json(conn, %{error: msg})
256 end
257 end
258
259 def delete_account(%{assigns: %{user: user}} = conn, params) do
260 password = params["password"] || ""
261
262 case CommonAPI.Utils.confirm_current_password(user, password) do
263 {:ok, user} ->
264 User.delete(user)
265 json(conn, %{status: "success"})
266
267 {:error, msg} ->
268 json(conn, %{error: msg})
269 end
270 end
271
272 def disable_account(%{assigns: %{user: user}} = conn, params) do
273 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
274 {:ok, user} ->
275 User.deactivate_async(user)
276 json(conn, %{status: "success"})
277
278 {:error, msg} ->
279 json(conn, %{error: msg})
280 end
281 end
282
283 def captcha(conn, _params) do
284 json(conn, Pleroma.Captcha.new())
285 end
286
287 def healthcheck(conn, _params) do
288 with true <- Config.get([:instance, :healthcheck]),
289 %{healthy: true} = info <- Healthcheck.system_info() do
290 json(conn, info)
291 else
292 %{healthy: false} = info ->
293 service_unavailable(conn, info)
294
295 _ ->
296 service_unavailable(conn, %{})
297 end
298 end
299
300 defp service_unavailable(conn, info) do
301 conn
302 |> put_status(:service_unavailable)
303 |> json(info)
304 end
305 end