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