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