Merge develop into feature/770-add-emoji-tags
[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.Emoji
12 alias Pleroma.Notification
13 alias Pleroma.PasswordResetToken
14 alias Pleroma.Repo
15 alias Pleroma.User
16 alias Pleroma.Web
17 alias Pleroma.Web.ActivityPub.ActivityPub
18 alias Pleroma.Web.CommonAPI
19 alias Pleroma.Web.OStatus
20 alias Pleroma.Web.WebFinger
21
22 def show_password_reset(conn, %{"token" => token}) do
23 with %{used: false} = token <- Repo.get_by(PasswordResetToken, %{token: token}),
24 %User{} = user <- User.get_by_id(token.user_id) do
25 render(conn, "password_reset.html", %{
26 token: token,
27 user: user
28 })
29 else
30 _e -> render(conn, "invalid_token.html")
31 end
32 end
33
34 def password_reset(conn, %{"data" => data}) do
35 with {:ok, _} <- PasswordResetToken.reset_password(data["token"], data) do
36 render(conn, "password_reset_success.html")
37 else
38 _e -> render(conn, "password_reset_failed.html")
39 end
40 end
41
42 def help_test(conn, _params) do
43 json(conn, "ok")
44 end
45
46 def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
47 with %User{} = user <- User.get_cached_by_nickname(nick), avatar = User.avatar_url(user) do
48 conn
49 |> render("subscribe.html", %{nickname: nick, avatar: avatar, error: false})
50 else
51 _e ->
52 render(conn, "subscribe.html", %{
53 nickname: nick,
54 avatar: nil,
55 error: "Could not find user"
56 })
57 end
58 end
59
60 def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
61 with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
62 %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
63 conn
64 |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
65 else
66 _e ->
67 render(conn, "subscribe.html", %{
68 nickname: nick,
69 avatar: nil,
70 error: "Something went wrong."
71 })
72 end
73 end
74
75 def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
76 {err, followee} = OStatus.find_or_make_user(acct)
77 avatar = User.avatar_url(followee)
78 name = followee.nickname
79 id = followee.id
80
81 if !!user do
82 conn
83 |> render("follow.html", %{error: err, acct: acct, avatar: avatar, name: name, id: id})
84 else
85 conn
86 |> render("follow_login.html", %{
87 error: false,
88 acct: acct,
89 avatar: avatar,
90 name: name,
91 id: id
92 })
93 end
94 end
95
96 def do_remote_follow(conn, %{
97 "authorization" => %{"name" => username, "password" => password, "id" => id}
98 }) do
99 followee = User.get_by_id(id)
100 avatar = User.avatar_url(followee)
101 name = followee.nickname
102
103 with %User{} = user <- User.get_cached_by_nickname(username),
104 true <- Pbkdf2.checkpw(password, user.password_hash),
105 %User{} = _followed <- User.get_by_id(id),
106 {:ok, follower} <- User.follow(user, followee),
107 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
108 conn
109 |> render("followed.html", %{error: false})
110 else
111 # Was already following user
112 {:error, "Could not follow user:" <> _rest} ->
113 render(conn, "followed.html", %{error: false})
114
115 _e ->
116 conn
117 |> render("follow_login.html", %{
118 error: "Wrong username or password",
119 id: id,
120 name: name,
121 avatar: avatar
122 })
123 end
124 end
125
126 def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
127 with %User{} = followee <- User.get_by_id(id),
128 {:ok, follower} <- User.follow(user, followee),
129 {:ok, _activity} <- ActivityPub.follow(follower, followee) do
130 conn
131 |> render("followed.html", %{error: false})
132 else
133 # Was already following user
134 {:error, "Could not follow user:" <> _rest} ->
135 conn
136 |> render("followed.html", %{error: false})
137
138 e ->
139 Logger.debug("Remote follow failed with error #{inspect(e)}")
140
141 conn
142 |> render("followed.html", %{error: inspect(e)})
143 end
144 end
145
146 def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
147 with {:ok, _} <- Notification.read_one(user, notification_id) do
148 json(conn, %{status: "success"})
149 else
150 {:error, message} ->
151 conn
152 |> put_resp_content_type("application/json")
153 |> send_resp(403, Jason.encode!(%{"error" => message}))
154 end
155 end
156
157 def config(conn, _params) do
158 instance = Pleroma.Config.get(:instance)
159 instance_fe = Pleroma.Config.get(:fe)
160 instance_chat = Pleroma.Config.get(:chat)
161
162 case get_format(conn) do
163 "xml" ->
164 response = """
165 <config>
166 <site>
167 <name>#{Keyword.get(instance, :name)}</name>
168 <site>#{Web.base_url()}</site>
169 <textlimit>#{Keyword.get(instance, :limit)}</textlimit>
170 <closed>#{!Keyword.get(instance, :registrations_open)}</closed>
171 </site>
172 </config>
173 """
174
175 conn
176 |> put_resp_content_type("application/xml")
177 |> send_resp(200, response)
178
179 _ ->
180 vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
181
182 uploadlimit = %{
183 uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
184 avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
185 backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
186 bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
187 }
188
189 data = %{
190 name: Keyword.get(instance, :name),
191 description: Keyword.get(instance, :description),
192 server: Web.base_url(),
193 textlimit: to_string(Keyword.get(instance, :limit)),
194 uploadlimit: uploadlimit,
195 closed: if(Keyword.get(instance, :registrations_open), do: "0", else: "1"),
196 private: if(Keyword.get(instance, :public, true), do: "0", else: "1"),
197 vapidPublicKey: vapid_public_key,
198 accountActivationRequired:
199 if(Keyword.get(instance, :account_activation_required, false), do: "1", else: "0"),
200 invitesEnabled: if(Keyword.get(instance, :invites_enabled, false), do: "1", else: "0"),
201 safeDMMentionsEnabled:
202 if(Pleroma.Config.get([:instance, :safe_dm_mentions]), do: "1", else: "0")
203 }
204
205 pleroma_fe =
206 if instance_fe do
207 %{
208 theme: Keyword.get(instance_fe, :theme),
209 background: Keyword.get(instance_fe, :background),
210 logo: Keyword.get(instance_fe, :logo),
211 logoMask: Keyword.get(instance_fe, :logo_mask),
212 logoMargin: Keyword.get(instance_fe, :logo_margin),
213 redirectRootNoLogin: Keyword.get(instance_fe, :redirect_root_no_login),
214 redirectRootLogin: Keyword.get(instance_fe, :redirect_root_login),
215 chatDisabled: !Keyword.get(instance_chat, :enabled),
216 showInstanceSpecificPanel: Keyword.get(instance_fe, :show_instance_panel),
217 scopeOptionsEnabled: Keyword.get(instance_fe, :scope_options_enabled),
218 formattingOptionsEnabled: Keyword.get(instance_fe, :formatting_options_enabled),
219 collapseMessageWithSubject:
220 Keyword.get(instance_fe, :collapse_message_with_subject),
221 hidePostStats: Keyword.get(instance_fe, :hide_post_stats),
222 hideUserStats: Keyword.get(instance_fe, :hide_user_stats),
223 scopeCopy: Keyword.get(instance_fe, :scope_copy),
224 subjectLineBehavior: Keyword.get(instance_fe, :subject_line_behavior),
225 alwaysShowSubjectInput: Keyword.get(instance_fe, :always_show_subject_input)
226 }
227 else
228 Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
229 end
230
231 managed_config = Keyword.get(instance, :managed_config)
232
233 data =
234 if managed_config do
235 data |> Map.put("pleromafe", pleroma_fe)
236 else
237 data
238 end
239
240 json(conn, %{site: data})
241 end
242 end
243
244 def frontend_configurations(conn, _params) do
245 config =
246 Pleroma.Config.get(:frontend_configurations, %{})
247 |> Enum.into(%{})
248
249 json(conn, config)
250 end
251
252 def version(conn, _params) do
253 version = Pleroma.Application.named_version()
254
255 case get_format(conn) do
256 "xml" ->
257 response = "<version>#{version}</version>"
258
259 conn
260 |> put_resp_content_type("application/xml")
261 |> send_resp(200, response)
262
263 _ ->
264 json(conn, version)
265 end
266 end
267
268 def emoji(conn, _params) do
269 emoji =
270 Emoji.get_all()
271 |> Enum.map(fn {short_code, path, tags} ->
272 %{short_code => %{image_url: path, tags: String.split(tags, ",")}}
273 end)
274
275 json(conn, emoji)
276 end
277
278 def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
279 follow_import(conn, %{"list" => File.read!(listfile.path)})
280 end
281
282 def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
283 with followed_identifiers <- String.split(list),
284 {:ok, _} = Task.start(fn -> User.follow_import(follower, followed_identifiers) end) do
285 json(conn, "job started")
286 end
287 end
288
289 def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
290 blocks_import(conn, %{"list" => File.read!(listfile.path)})
291 end
292
293 def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
294 with blocked_identifiers <- String.split(list),
295 {:ok, _} = Task.start(fn -> User.blocks_import(blocker, blocked_identifiers) end) do
296 json(conn, "job started")
297 end
298 end
299
300 def change_password(%{assigns: %{user: user}} = conn, params) do
301 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
302 {:ok, user} ->
303 with {:ok, _user} <-
304 User.reset_password(user, %{
305 password: params["new_password"],
306 password_confirmation: params["new_password_confirmation"]
307 }) do
308 json(conn, %{status: "success"})
309 else
310 {:error, changeset} ->
311 {_, {error, _}} = Enum.at(changeset.errors, 0)
312 json(conn, %{error: "New password #{error}."})
313
314 _ ->
315 json(conn, %{error: "Unable to change password."})
316 end
317
318 {:error, msg} ->
319 json(conn, %{error: msg})
320 end
321 end
322
323 def delete_account(%{assigns: %{user: user}} = conn, params) do
324 case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
325 {:ok, user} ->
326 Task.start(fn -> User.delete(user) end)
327 json(conn, %{status: "success"})
328
329 {:error, msg} ->
330 json(conn, %{error: msg})
331 end
332 end
333
334 def captcha(conn, _params) do
335 json(conn, Pleroma.Captcha.new())
336 end
337 end