[Credo] Fix the consistency
[akkoma] / lib / pleroma / web / twitter_api / twitter_api_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.Controller do
6 use Pleroma.Web, :controller
7
8 import Pleroma.Web.ControllerHelper, only: [json_response: 3]
9
10 alias Ecto.Changeset
11 alias Pleroma.Web.TwitterAPI.TwitterAPI
12 alias Pleroma.Web.TwitterAPI.UserView
13 alias Pleroma.Web.TwitterAPI.ActivityView
14 alias Pleroma.Web.TwitterAPI.NotificationView
15 alias Pleroma.Web.TwitterAPI.TokenView
16 alias Pleroma.Web.CommonAPI
17 alias Pleroma.Repo
18 alias Pleroma.Activity
19 alias Pleroma.Object
20 alias Pleroma.User
21 alias Pleroma.Notification
22 alias Pleroma.Web.OAuth.Token
23 alias Pleroma.Web.ActivityPub.ActivityPub
24 alias Pleroma.Web.ActivityPub.Visibility
25 alias Pleroma.Web.ActivityPub.Utils
26 alias Pleroma.Web.CommonAPI
27 alias Pleroma.Web.TwitterAPI.ActivityView
28 alias Pleroma.Web.TwitterAPI.NotificationView
29 alias Pleroma.Web.TwitterAPI.TwitterAPI
30 alias Pleroma.Web.TwitterAPI.UserView
31 alias Pleroma.Activity
32 alias Pleroma.Object
33 alias Pleroma.Notification
34 alias Pleroma.Repo
35 alias Pleroma.User
36
37 require Logger
38
39 plug(:only_if_public_instance when action in [:public_timeline, :public_and_external_timeline])
40 action_fallback(:errors)
41
42 def verify_credentials(%{assigns: %{user: user}} = conn, _params) do
43 token = Phoenix.Token.sign(conn, "user socket", user.id)
44
45 conn
46 |> put_view(UserView)
47 |> render("show.json", %{user: user, token: token, for: user})
48 end
49
50 def status_update(%{assigns: %{user: user}} = conn, %{"status" => _} = status_data) do
51 with media_ids <- extract_media_ids(status_data),
52 {:ok, activity} <-
53 TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
54 conn
55 |> json(ActivityView.render("activity.json", activity: activity, for: user))
56 else
57 _ -> empty_status_reply(conn)
58 end
59 end
60
61 def status_update(conn, _status_data) do
62 empty_status_reply(conn)
63 end
64
65 defp empty_status_reply(conn) do
66 bad_request_reply(conn, "Client must provide a 'status' parameter with a value.")
67 end
68
69 defp extract_media_ids(status_data) do
70 with media_ids when not is_nil(media_ids) <- status_data["media_ids"],
71 split_ids <- String.split(media_ids, ","),
72 clean_ids <- Enum.reject(split_ids, fn id -> String.length(id) == 0 end) do
73 clean_ids
74 else
75 _e -> []
76 end
77 end
78
79 def public_and_external_timeline(%{assigns: %{user: user}} = conn, params) do
80 params =
81 params
82 |> Map.put("type", ["Create", "Announce"])
83 |> Map.put("blocking_user", user)
84
85 activities = ActivityPub.fetch_public_activities(params)
86
87 conn
88 |> put_view(ActivityView)
89 |> render("index.json", %{activities: activities, for: user})
90 end
91
92 def public_timeline(%{assigns: %{user: user}} = conn, params) do
93 params =
94 params
95 |> Map.put("type", ["Create", "Announce"])
96 |> Map.put("local_only", true)
97 |> Map.put("blocking_user", user)
98
99 activities = ActivityPub.fetch_public_activities(params)
100
101 conn
102 |> put_view(ActivityView)
103 |> render("index.json", %{activities: activities, for: user})
104 end
105
106 def friends_timeline(%{assigns: %{user: user}} = conn, params) do
107 params =
108 params
109 |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
110 |> Map.put("blocking_user", user)
111 |> Map.put("user", user)
112
113 activities =
114 ActivityPub.fetch_activities([user.ap_id | user.following], params)
115 |> ActivityPub.contain_timeline(user)
116
117 conn
118 |> put_view(ActivityView)
119 |> render("index.json", %{activities: activities, for: user})
120 end
121
122 def show_user(conn, params) do
123 for_user = conn.assigns.user
124
125 with {:ok, shown} <- TwitterAPI.get_user(params),
126 true <-
127 User.auth_active?(shown) ||
128 (for_user && (for_user.id == shown.id || User.superuser?(for_user))) do
129 params =
130 if for_user do
131 %{user: shown, for: for_user}
132 else
133 %{user: shown}
134 end
135
136 conn
137 |> put_view(UserView)
138 |> render("show.json", params)
139 else
140 {:error, msg} ->
141 bad_request_reply(conn, msg)
142
143 false ->
144 conn
145 |> put_status(404)
146 |> json(%{error: "Unconfirmed user"})
147 end
148 end
149
150 def user_timeline(%{assigns: %{user: user}} = conn, params) do
151 case TwitterAPI.get_user(user, params) do
152 {:ok, target_user} ->
153 # Twitter and ActivityPub use a different name and sense for this parameter.
154 {include_rts, params} = Map.pop(params, "include_rts")
155
156 params =
157 case include_rts do
158 x when x == "false" or x == "0" -> Map.put(params, "exclude_reblogs", "true")
159 _ -> params
160 end
161
162 activities = ActivityPub.fetch_user_activities(target_user, user, params)
163
164 conn
165 |> put_view(ActivityView)
166 |> render("index.json", %{activities: activities, for: user})
167
168 {:error, msg} ->
169 bad_request_reply(conn, msg)
170 end
171 end
172
173 def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
174 params =
175 params
176 |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
177 |> Map.put("blocking_user", user)
178 |> Map.put(:visibility, ~w[unlisted public private])
179
180 activities = ActivityPub.fetch_activities([user.ap_id], params)
181
182 conn
183 |> put_view(ActivityView)
184 |> render("index.json", %{activities: activities, for: user})
185 end
186
187 def dm_timeline(%{assigns: %{user: user}} = conn, params) do
188 params =
189 params
190 |> Map.put("type", "Create")
191 |> Map.put("blocking_user", user)
192 |> Map.put("user", user)
193 |> Map.put(:visibility, "direct")
194
195 activities =
196 ActivityPub.fetch_activities_query([user.ap_id], params)
197 |> Repo.all()
198
199 conn
200 |> put_view(ActivityView)
201 |> render("index.json", %{activities: activities, for: user})
202 end
203
204 def notifications(%{assigns: %{user: user}} = conn, params) do
205 notifications = Notification.for_user(user, params)
206
207 conn
208 |> put_view(NotificationView)
209 |> render("notification.json", %{notifications: notifications, for: user})
210 end
211
212 def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do
213 Notification.set_read_up_to(user, latest_id)
214
215 notifications = Notification.for_user(user, params)
216
217 conn
218 |> put_view(NotificationView)
219 |> render("notification.json", %{notifications: notifications, for: user})
220 end
221
222 def notifications_read(%{assigns: %{user: _user}} = conn, _) do
223 bad_request_reply(conn, "You need to specify latest_id")
224 end
225
226 def follow(%{assigns: %{user: user}} = conn, params) do
227 case TwitterAPI.follow(user, params) do
228 {:ok, user, followed, _activity} ->
229 conn
230 |> put_view(UserView)
231 |> render("show.json", %{user: followed, for: user})
232
233 {:error, msg} ->
234 forbidden_json_reply(conn, msg)
235 end
236 end
237
238 def block(%{assigns: %{user: user}} = conn, params) do
239 case TwitterAPI.block(user, params) do
240 {:ok, user, blocked} ->
241 conn
242 |> put_view(UserView)
243 |> render("show.json", %{user: blocked, for: user})
244
245 {:error, msg} ->
246 forbidden_json_reply(conn, msg)
247 end
248 end
249
250 def unblock(%{assigns: %{user: user}} = conn, params) do
251 case TwitterAPI.unblock(user, params) do
252 {:ok, user, blocked} ->
253 conn
254 |> put_view(UserView)
255 |> render("show.json", %{user: blocked, for: user})
256
257 {:error, msg} ->
258 forbidden_json_reply(conn, msg)
259 end
260 end
261
262 def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do
263 with {:ok, activity} <- TwitterAPI.delete(user, id) do
264 conn
265 |> put_view(ActivityView)
266 |> render("activity.json", %{activity: activity, for: user})
267 end
268 end
269
270 def unfollow(%{assigns: %{user: user}} = conn, params) do
271 case TwitterAPI.unfollow(user, params) do
272 {:ok, user, unfollowed} ->
273 conn
274 |> put_view(UserView)
275 |> render("show.json", %{user: unfollowed, for: user})
276
277 {:error, msg} ->
278 forbidden_json_reply(conn, msg)
279 end
280 end
281
282 def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
283 with %Activity{} = activity <- Repo.get(Activity, id),
284 true <- Visibility.visible_for_user?(activity, user) do
285 conn
286 |> put_view(ActivityView)
287 |> render("activity.json", %{activity: activity, for: user})
288 end
289 end
290
291 def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
292 with context when is_binary(context) <- TwitterAPI.conversation_id_to_context(id),
293 activities <-
294 ActivityPub.fetch_activities_for_context(context, %{
295 "blocking_user" => user,
296 "user" => user
297 }) do
298 conn
299 |> put_view(ActivityView)
300 |> render("index.json", %{activities: activities, for: user})
301 end
302 end
303
304 @doc """
305 Updates metadata of uploaded media object.
306 Derived from [Twitter API endpoint](https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create).
307 """
308 def update_media(%{assigns: %{user: user}} = conn, %{"media_id" => id} = data) do
309 object = Repo.get(Object, id)
310 description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"]
311
312 {conn, status, response_body} =
313 cond do
314 !object ->
315 {halt(conn), :not_found, ""}
316
317 !Object.authorize_mutation(object, user) ->
318 {halt(conn), :forbidden, "You can only update your own uploads."}
319
320 !is_binary(description) ->
321 {conn, :not_modified, ""}
322
323 true ->
324 new_data = Map.put(object.data, "name", description)
325
326 {:ok, _} =
327 object
328 |> Object.change(%{data: new_data})
329 |> Repo.update()
330
331 {conn, :no_content, ""}
332 end
333
334 conn
335 |> put_status(status)
336 |> json(response_body)
337 end
338
339 def upload(%{assigns: %{user: user}} = conn, %{"media" => media}) do
340 response = TwitterAPI.upload(media, user)
341
342 conn
343 |> put_resp_content_type("application/atom+xml")
344 |> send_resp(200, response)
345 end
346
347 def upload_json(%{assigns: %{user: user}} = conn, %{"media" => media}) do
348 response = TwitterAPI.upload(media, user, "json")
349
350 conn
351 |> json_reply(200, response)
352 end
353
354 def get_by_id_or_ap_id(id) do
355 activity = Repo.get(Activity, id) || Activity.get_create_by_object_ap_id(id)
356
357 if activity.data["type"] == "Create" do
358 activity
359 else
360 Activity.get_create_by_object_ap_id(activity.data["object"])
361 end
362 end
363
364 def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
365 with {:ok, activity} <- TwitterAPI.fav(user, id) do
366 conn
367 |> put_view(ActivityView)
368 |> render("activity.json", %{activity: activity, for: user})
369 else
370 _ -> json_reply(conn, 400, Jason.encode!(%{}))
371 end
372 end
373
374 def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
375 with {:ok, activity} <- TwitterAPI.unfav(user, id) do
376 conn
377 |> put_view(ActivityView)
378 |> render("activity.json", %{activity: activity, for: user})
379 else
380 _ -> json_reply(conn, 400, Jason.encode!(%{}))
381 end
382 end
383
384 def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
385 with {:ok, activity} <- TwitterAPI.repeat(user, id) do
386 conn
387 |> put_view(ActivityView)
388 |> render("activity.json", %{activity: activity, for: user})
389 else
390 _ -> json_reply(conn, 400, Jason.encode!(%{}))
391 end
392 end
393
394 def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
395 with {:ok, activity} <- TwitterAPI.unrepeat(user, id) do
396 conn
397 |> put_view(ActivityView)
398 |> render("activity.json", %{activity: activity, for: user})
399 else
400 _ -> json_reply(conn, 400, Jason.encode!(%{}))
401 end
402 end
403
404 def pin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
405 with {:ok, activity} <- TwitterAPI.pin(user, id) do
406 conn
407 |> put_view(ActivityView)
408 |> render("activity.json", %{activity: activity, for: user})
409 else
410 {:error, message} -> bad_request_reply(conn, message)
411 err -> err
412 end
413 end
414
415 def unpin(%{assigns: %{user: user}} = conn, %{"id" => id}) do
416 with {:ok, activity} <- TwitterAPI.unpin(user, id) do
417 conn
418 |> put_view(ActivityView)
419 |> render("activity.json", %{activity: activity, for: user})
420 else
421 {:error, message} -> bad_request_reply(conn, message)
422 err -> err
423 end
424 end
425
426 def register(conn, params) do
427 with {:ok, user} <- TwitterAPI.register_user(params) do
428 conn
429 |> put_view(UserView)
430 |> render("show.json", %{user: user})
431 else
432 {:error, errors} ->
433 conn
434 |> json_reply(400, Jason.encode!(errors))
435 end
436 end
437
438 def password_reset(conn, params) do
439 nickname_or_email = params["email"] || params["nickname"]
440
441 with {:ok, _} <- TwitterAPI.password_reset(nickname_or_email) do
442 json_response(conn, :no_content, "")
443 end
444 end
445
446 def confirm_email(conn, %{"user_id" => uid, "token" => token}) do
447 with %User{} = user <- Repo.get(User, uid),
448 true <- user.local,
449 true <- user.info.confirmation_pending,
450 true <- user.info.confirmation_token == token,
451 info_change <- User.Info.confirmation_changeset(user.info, :confirmed),
452 changeset <- Changeset.change(user) |> Changeset.put_embed(:info, info_change),
453 {:ok, _} <- User.update_and_set_cache(changeset) do
454 conn
455 |> redirect(to: "/")
456 end
457 end
458
459 def resend_confirmation_email(conn, params) do
460 nickname_or_email = params["email"] || params["nickname"]
461
462 with %User{} = user <- User.get_by_nickname_or_email(nickname_or_email),
463 {:ok, _} <- User.try_send_confirmation_email(user) do
464 conn
465 |> json_response(:no_content, "")
466 end
467 end
468
469 def update_avatar(%{assigns: %{user: user}} = conn, params) do
470 {:ok, object} = ActivityPub.upload(params, type: :avatar)
471 change = Changeset.change(user, %{avatar: object.data})
472 {:ok, user} = User.update_and_set_cache(change)
473 CommonAPI.update(user)
474
475 conn
476 |> put_view(UserView)
477 |> render("show.json", %{user: user, for: user})
478 end
479
480 def update_banner(%{assigns: %{user: user}} = conn, params) do
481 with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
482 new_info <- %{"banner" => object.data},
483 info_cng <- User.Info.profile_update(user.info, new_info),
484 changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
485 {:ok, user} <- User.update_and_set_cache(changeset) do
486 CommonAPI.update(user)
487 %{"url" => [%{"href" => href} | _]} = object.data
488 response = %{url: href} |> Jason.encode!()
489
490 conn
491 |> json_reply(200, response)
492 end
493 end
494
495 def update_background(%{assigns: %{user: user}} = conn, params) do
496 with {:ok, object} <- ActivityPub.upload(params, type: :background),
497 new_info <- %{"background" => object.data},
498 info_cng <- User.Info.profile_update(user.info, new_info),
499 changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
500 {:ok, _user} <- User.update_and_set_cache(changeset) do
501 %{"url" => [%{"href" => href} | _]} = object.data
502 response = %{url: href} |> Jason.encode!()
503
504 conn
505 |> json_reply(200, response)
506 end
507 end
508
509 def external_profile(%{assigns: %{user: current_user}} = conn, %{"profileurl" => uri}) do
510 with {:ok, user_map} <- TwitterAPI.get_external_profile(current_user, uri),
511 response <- Jason.encode!(user_map) do
512 conn
513 |> json_reply(200, response)
514 else
515 _e ->
516 conn
517 |> put_status(404)
518 |> json(%{error: "Can't find user"})
519 end
520 end
521
522 def followers(%{assigns: %{user: for_user}} = conn, params) do
523 {:ok, page} = Ecto.Type.cast(:integer, params["page"] || 1)
524
525 with {:ok, user} <- TwitterAPI.get_user(for_user, params),
526 {:ok, followers} <- User.get_followers(user, page) do
527 followers =
528 cond do
529 for_user && user.id == for_user.id -> followers
530 user.info.hide_followers -> []
531 true -> followers
532 end
533
534 conn
535 |> put_view(UserView)
536 |> render("index.json", %{users: followers, for: conn.assigns[:user]})
537 else
538 _e -> bad_request_reply(conn, "Can't get followers")
539 end
540 end
541
542 def friends(%{assigns: %{user: for_user}} = conn, params) do
543 {:ok, page} = Ecto.Type.cast(:integer, params["page"] || 1)
544 {:ok, export} = Ecto.Type.cast(:boolean, params["all"] || false)
545
546 page = if export, do: nil, else: page
547
548 with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
549 {:ok, friends} <- User.get_friends(user, page) do
550 friends =
551 cond do
552 for_user && user.id == for_user.id -> friends
553 user.info.hide_follows -> []
554 true -> friends
555 end
556
557 conn
558 |> put_view(UserView)
559 |> render("index.json", %{users: friends, for: conn.assigns[:user]})
560 else
561 _e -> bad_request_reply(conn, "Can't get friends")
562 end
563 end
564
565 def oauth_tokens(%{assigns: %{user: user}} = conn, _params) do
566 with oauth_tokens <- Token.get_user_tokens(user) do
567 conn
568 |> put_view(TokenView)
569 |> render("index.json", %{tokens: oauth_tokens})
570 end
571 end
572
573 def revoke_token(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
574 Token.delete_user_token(user, id)
575
576 json_reply(conn, 201, "")
577 end
578
579 def blocks(%{assigns: %{user: user}} = conn, _params) do
580 with blocked_users <- User.blocked_users(user) do
581 conn
582 |> put_view(UserView)
583 |> render("index.json", %{users: blocked_users, for: user})
584 end
585 end
586
587 def friend_requests(conn, params) do
588 with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
589 {:ok, friend_requests} <- User.get_follow_requests(user) do
590 conn
591 |> put_view(UserView)
592 |> render("index.json", %{users: friend_requests, for: conn.assigns[:user]})
593 else
594 _e -> bad_request_reply(conn, "Can't get friend requests")
595 end
596 end
597
598 def approve_friend_request(conn, %{"user_id" => uid} = _params) do
599 with followed <- conn.assigns[:user],
600 %User{} = follower <- Repo.get(User, uid),
601 {:ok, follower} <- User.maybe_follow(follower, followed),
602 %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
603 {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
604 {:ok, _activity} <-
605 ActivityPub.accept(%{
606 to: [follower.ap_id],
607 actor: followed,
608 object: follow_activity.data["id"],
609 type: "Accept"
610 }) do
611 conn
612 |> put_view(UserView)
613 |> render("show.json", %{user: follower, for: followed})
614 else
615 e -> bad_request_reply(conn, "Can't approve user: #{inspect(e)}")
616 end
617 end
618
619 def deny_friend_request(conn, %{"user_id" => uid} = _params) do
620 with followed <- conn.assigns[:user],
621 %User{} = follower <- Repo.get(User, uid),
622 %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
623 {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
624 {:ok, _activity} <-
625 ActivityPub.reject(%{
626 to: [follower.ap_id],
627 actor: followed,
628 object: follow_activity.data["id"],
629 type: "Reject"
630 }) do
631 conn
632 |> put_view(UserView)
633 |> render("show.json", %{user: follower, for: followed})
634 else
635 e -> bad_request_reply(conn, "Can't deny user: #{inspect(e)}")
636 end
637 end
638
639 def friends_ids(%{assigns: %{user: user}} = conn, _params) do
640 with {:ok, friends} <- User.get_friends(user) do
641 ids =
642 friends
643 |> Enum.map(fn x -> x.id end)
644 |> Jason.encode!()
645
646 json(conn, ids)
647 else
648 _e -> bad_request_reply(conn, "Can't get friends")
649 end
650 end
651
652 def empty_array(conn, _params) do
653 json(conn, Jason.encode!([]))
654 end
655
656 def raw_empty_array(conn, _params) do
657 json(conn, [])
658 end
659
660 defp build_info_cng(user, params) do
661 info_params =
662 ["no_rich_text", "locked", "hide_followers", "hide_follows", "show_role"]
663 |> Enum.reduce(%{}, fn key, res ->
664 if value = params[key] do
665 Map.put(res, key, value == "true")
666 else
667 res
668 end
669 end)
670
671 info_params =
672 if value = params["default_scope"] do
673 Map.put(info_params, "default_scope", value)
674 else
675 info_params
676 end
677
678 User.Info.profile_update(user.info, info_params)
679 end
680
681 defp parse_profile_bio(user, params) do
682 if bio = params["description"] do
683 Map.put(params, "bio", User.parse_bio(bio, user))
684 else
685 params
686 end
687 end
688
689 def update_profile(%{assigns: %{user: user}} = conn, params) do
690 params = parse_profile_bio(user, params)
691 info_cng = build_info_cng(user, params)
692
693 with changeset <- User.update_changeset(user, params),
694 changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
695 {:ok, user} <- User.update_and_set_cache(changeset) do
696 CommonAPI.update(user)
697
698 conn
699 |> put_view(UserView)
700 |> render("user.json", %{user: user, for: user})
701 else
702 error ->
703 Logger.debug("Can't update user: #{inspect(error)}")
704 bad_request_reply(conn, "Can't update user")
705 end
706 end
707
708 def search(%{assigns: %{user: user}} = conn, %{"q" => _query} = params) do
709 activities = TwitterAPI.search(user, params)
710
711 conn
712 |> put_view(ActivityView)
713 |> render("index.json", %{activities: activities, for: user})
714 end
715
716 def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do
717 users = User.search(query, resolve: true, for_user: user)
718
719 conn
720 |> put_view(UserView)
721 |> render("index.json", %{users: users, for: user})
722 end
723
724 defp bad_request_reply(conn, error_message) do
725 json = error_json(conn, error_message)
726 json_reply(conn, 400, json)
727 end
728
729 defp json_reply(conn, status, json) do
730 conn
731 |> put_resp_content_type("application/json")
732 |> send_resp(status, json)
733 end
734
735 defp forbidden_json_reply(conn, error_message) do
736 json = error_json(conn, error_message)
737 json_reply(conn, 403, json)
738 end
739
740 def only_if_public_instance(%{assigns: %{user: %User{}}} = conn, _), do: conn
741
742 def only_if_public_instance(conn, _) do
743 if Keyword.get(Application.get_env(:pleroma, :instance), :public) do
744 conn
745 else
746 conn
747 |> forbidden_json_reply("Invalid credentials.")
748 |> halt()
749 end
750 end
751
752 defp error_json(conn, error_message) do
753 %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()
754 end
755
756 def errors(conn, {:param_cast, _}) do
757 conn
758 |> put_status(400)
759 |> json("Invalid parameters")
760 end
761
762 def errors(conn, _) do
763 conn
764 |> put_status(500)
765 |> json("Something went wrong")
766 end
767 end