twitter_api_controller.ex 17.3 KB
Newer Older
1
2
defmodule Pleroma.Web.TwitterAPI.Controller do
  use Pleroma.Web, :controller
3
  alias Pleroma.Formatter
4
  alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView}
lain's avatar
lain committed
5
  alias Pleroma.Web.CommonAPI
6
  alias Pleroma.Web.CommonAPI.Utils, as: CommonUtils
7
  alias Pleroma.{Repo, Activity, Object, User, Notification}
lain's avatar
lain committed
8
  alias Pleroma.Web.ActivityPub.ActivityPub
9
  alias Pleroma.Web.ActivityPub.Utils
10
  alias Ecto.Changeset
11

lain's avatar
lain committed
12
13
  require Logger

href's avatar
href committed
14
  plug(:only_if_public_instance when action in [:public_timeline, :public_and_external_timeline])
15
16
  action_fallback(:errors)

17
  def verify_credentials(%{assigns: %{user: user}} = conn, _params) do
lain's avatar
lain committed
18
19
    token = Phoenix.Token.sign(conn, "user socket", user.id)
    render(conn, UserView, "show.json", %{user: user, token: token})
20
21
  end

Thog's avatar
Thog committed
22
  def status_update(%{assigns: %{user: user}} = conn, %{"status" => _} = status_data) do
23
    with media_ids <- extract_media_ids(status_data),
lain's avatar
lain committed
24
25
         {:ok, activity} <-
           TwitterAPI.create_status(user, Map.put(status_data, "media_ids", media_ids)) do
dtluna's avatar
dtluna committed
26
      conn
lain's avatar
lain committed
27
      |> json(ActivityView.render("activity.json", activity: activity, for: user))
dtluna's avatar
dtluna committed
28
    else
29
      _ -> empty_status_reply(conn)
dtluna's avatar
dtluna committed
30
    end
lain's avatar
lain committed
31
32
  end

dtluna's avatar
dtluna committed
33
34
35
36
37
38
39
40
  def status_update(conn, _status_data) do
    empty_status_reply(conn)
  end

  defp empty_status_reply(conn) do
    bad_request_reply(conn, "Client must provide a 'status' parameter with a value.")
  end

lain's avatar
lain committed
41
42
43
  defp extract_media_ids(status_data) do
    with media_ids when not is_nil(media_ids) <- status_data["media_ids"],
         split_ids <- String.split(media_ids, ","),
lain's avatar
lain committed
44
45
46
47
         clean_ids <- Enum.reject(split_ids, fn id -> String.length(id) == 0 end) do
      clean_ids
    else
      _e -> []
lain's avatar
lain committed
48
49
50
    end
  end

lain's avatar
lain committed
51
  def public_and_external_timeline(%{assigns: %{user: user}} = conn, params) do
lain's avatar
lain committed
52
53
    params =
      params
54
      |> Map.put("type", ["Create", "Announce"])
lain's avatar
lain committed
55
56
57
      |> Map.put("blocking_user", user)

    activities = ActivityPub.fetch_public_activities(params)
lain's avatar
lain committed
58
59

    conn
lain's avatar
lain committed
60
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
lain's avatar
lain committed
61
62
  end

63
  def public_timeline(%{assigns: %{user: user}} = conn, params) do
lain's avatar
lain committed
64
65
    params =
      params
66
      |> Map.put("type", ["Create", "Announce"])
lain's avatar
lain committed
67
68
69
70
      |> Map.put("local_only", true)
      |> Map.put("blocking_user", user)

    activities = ActivityPub.fetch_public_activities(params)
lain's avatar
lain committed
71
72

    conn
lain's avatar
lain committed
73
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
lain's avatar
lain committed
74
75
  end

lain's avatar
lain committed
76
  def friends_timeline(%{assigns: %{user: user}} = conn, params) do
lain's avatar
lain committed
77
78
79
80
81
82
    params =
      params
      |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
      |> Map.put("blocking_user", user)
      |> Map.put("user", user)

83
84
85
    activities =
      ActivityPub.fetch_activities([user.ap_id | user.following], params)
      |> ActivityPub.contain_timeline(user)
lain's avatar
lain committed
86
87

    conn
lain's avatar
lain committed
88
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
lain's avatar
lain committed
89
90
  end

eal's avatar
eal committed
91
92
93
  def show_user(conn, params) do
    with {:ok, shown} <- TwitterAPI.get_user(params) do
      if user = conn.assigns.user do
lain's avatar
lain committed
94
        render(conn, UserView, "show.json", %{user: shown, for: user})
eal's avatar
eal committed
95
      else
lain's avatar
lain committed
96
        render(conn, UserView, "show.json", %{user: shown})
eal's avatar
eal committed
97
98
99
100
101
102
103
      end
    else
      {:error, msg} ->
        bad_request_reply(conn, msg)
    end
  end

dtluna's avatar
dtluna committed
104
  def user_timeline(%{assigns: %{user: user}} = conn, params) do
105
106
    case TwitterAPI.get_user(user, params) do
      {:ok, target_user} ->
107
        activities = ActivityPub.fetch_user_activities(target_user, user, params)
lain's avatar
lain committed
108

109
        conn
lain's avatar
lain committed
110
        |> render(ActivityView, "index.json", %{activities: activities, for: user})
lain's avatar
lain committed
111

112
113
114
      {:error, msg} ->
        bad_request_reply(conn, msg)
    end
dtluna's avatar
dtluna committed
115
116
  end

dtluna's avatar
dtluna committed
117
  def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
118
119
120
121
122
    params =
      params
      |> Map.put("type", ["Create", "Announce", "Follow", "Like"])
      |> Map.put("blocking_user", user)

lain's avatar
lain committed
123
    activities = ActivityPub.fetch_activities([user.ap_id], params)
dtluna's avatar
dtluna committed
124
125

    conn
lain's avatar
lain committed
126
127
128
129
130
131
132
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
  end

  def dm_timeline(%{assigns: %{user: user}} = conn, params) do
    query =
      ActivityPub.fetch_activities_query(
        [user.ap_id],
133
        Map.merge(params, %{"type" => "Create", "user" => user, visibility: "direct"})
lain's avatar
lain committed
134
135
136
137
138
      )

    activities = Repo.all(query)

    conn
lain's avatar
lain committed
139
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
dtluna's avatar
dtluna committed
140
141
  end

142
143
144
145
146
147
148
  def notifications(%{assigns: %{user: user}} = conn, params) do
    notifications = Notification.for_user(user, params)

    conn
    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
  end

149
150
151
152
153
154
155
156
157
158
159
160
161
  def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do
    Notification.set_read_up_to(user, latest_id)

    notifications = Notification.for_user(user, params)

    conn
    |> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
  end

  def notifications_read(%{assigns: %{user: user}} = conn, _) do
    bad_request_reply(conn, "You need to specify latest_id")
  end

162
163
  def follow(%{assigns: %{user: user}} = conn, params) do
    case TwitterAPI.follow(user, params) do
164
      {:ok, user, followed, _activity} ->
dtluna's avatar
dtluna committed
165
        render(conn, UserView, "show.json", %{user: followed, for: user})
lain's avatar
lain committed
166
167
168

      {:error, msg} ->
        forbidden_json_reply(conn, msg)
169
    end
lain's avatar
lain committed
170
171
  end

eal's avatar
eal committed
172
173
174
  def block(%{assigns: %{user: user}} = conn, params) do
    case TwitterAPI.block(user, params) do
      {:ok, user, blocked} ->
lain's avatar
lain committed
175
176
177
178
        render(conn, UserView, "show.json", %{user: blocked, for: user})

      {:error, msg} ->
        forbidden_json_reply(conn, msg)
eal's avatar
eal committed
179
180
181
182
183
184
    end
  end

  def unblock(%{assigns: %{user: user}} = conn, params) do
    case TwitterAPI.unblock(user, params) do
      {:ok, user, blocked} ->
lain's avatar
lain committed
185
186
187
188
        render(conn, UserView, "show.json", %{user: blocked, for: user})

      {:error, msg} ->
        forbidden_json_reply(conn, msg)
eal's avatar
eal committed
189
190
191
    end
  end

lain's avatar
lain committed
192
  def delete_post(%{assigns: %{user: user}} = conn, %{"id" => id}) do
normandy's avatar
normandy committed
193
    with {:ok, activity} <- TwitterAPI.delete(user, id) do
normandy's avatar
normandy committed
194
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
lain's avatar
lain committed
195
196
197
    end
  end

198
  def unfollow(%{assigns: %{user: user}} = conn, params) do
199
    case TwitterAPI.unfollow(user, params) do
200
      {:ok, user, unfollowed} ->
dtluna's avatar
dtluna committed
201
        render(conn, UserView, "show.json", %{user: unfollowed, for: user})
lain's avatar
lain committed
202
203
204

      {:error, msg} ->
        forbidden_json_reply(conn, msg)
205
    end
lain's avatar
lain committed
206
207
  end

208
  def fetch_status(%{assigns: %{user: user}} = conn, %{"id" => id}) do
lain's avatar
lain committed
209
210
    with %Activity{} = activity <- Repo.get(Activity, id),
         true <- ActivityPub.visible_for_user?(activity, user) do
lain's avatar
lain committed
211
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
lain's avatar
lain committed
212
    end
lain's avatar
lain committed
213
214
  end

215
  def fetch_conversation(%{assigns: %{user: user}} = conn, %{"id" => id}) do
216
217
    id = String.to_integer(id)

lain's avatar
lain committed
218
219
220
221
222
223
224
225
226
    with context when is_binary(context) <- TwitterAPI.conversation_id_to_context(id),
         activities <-
           ActivityPub.fetch_activities_for_context(context, %{
             "blocking_user" => user,
             "user" => user
           }) do
      conn
      |> render(ActivityView, "index.json", %{activities: activities, for: user})
    end
227
228
  end

229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  @doc "https://developer.twitter.com/en/docs/media/upload-media/api-reference/post-media-metadata-create"
  def update_media(%{assigns: %{user: _}} = conn, %{"media_id" => id} = data) do
    description = get_in(data, ["alt_text", "text"]) || data["name"] || data["description"]

    with %Object{} = object <- Repo.get(Object, id), is_binary(description) do
      new_data = Map.put(object.data, "name", description)

      change = Object.change(object, %{data: new_data})
      {:ok, _} = Repo.update(change)
    end

    conn
    |> put_status(:no_content)
    |> json("")
  end

lain's avatar
lain committed
245
246
  def upload(conn, %{"media" => media}) do
    response = TwitterAPI.upload(media)
lain's avatar
lain committed
247

lain's avatar
lain committed
248
249
250
251
    conn
    |> put_resp_content_type("application/atom+xml")
    |> send_resp(200, response)
  end
252

253
254
  def upload_json(conn, %{"media" => media}) do
    response = TwitterAPI.upload(media, "json")
lain's avatar
lain committed
255

256
257
258
259
    conn
    |> json_reply(200, response)
  end

lain's avatar
lain committed
260
  def get_by_id_or_ap_id(id) do
261
    activity = Repo.get(Activity, id) || Activity.get_create_activity_by_object_ap_id(id)
lain's avatar
lain committed
262

263
264
265
266
267
    if activity.data["type"] == "Create" do
      activity
    else
      Activity.get_create_activity_by_object_ap_id(activity.data["object"])
    end
lain's avatar
lain committed
268
269
  end

lain's avatar
lain committed
270
  def favorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
271
272
    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
         {:ok, activity} <- TwitterAPI.fav(user, id) do
273
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
lain's avatar
lain committed
274
    end
lain's avatar
lain committed
275
276
  end

lain's avatar
lain committed
277
  def unfavorite(%{assigns: %{user: user}} = conn, %{"id" => id}) do
278
279
    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
         {:ok, activity} <- TwitterAPI.unfav(user, id) do
280
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
lain's avatar
lain committed
281
    end
lain's avatar
lain committed
282
283
  end

lain's avatar
lain committed
284
  def retweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
285
286
    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
         {:ok, activity} <- TwitterAPI.repeat(user, id) do
287
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
dtluna's avatar
dtluna committed
288
    end
lain's avatar
lain committed
289
290
  end

291
292
293
294
295
296
297
  def unretweet(%{assigns: %{user: user}} = conn, %{"id" => id}) do
    with {_, {:ok, id}} <- {:param_cast, Ecto.Type.cast(:integer, id)},
         {:ok, activity} <- TwitterAPI.unrepeat(user, id) do
      render(conn, ActivityView, "activity.json", %{activity: activity, for: user})
    end
  end

298
299
  def register(conn, params) do
    with {:ok, user} <- TwitterAPI.register_user(params) do
dtluna's avatar
dtluna committed
300
      render(conn, UserView, "show.json", %{user: user})
301
302
    else
      {:error, errors} ->
lain's avatar
lain committed
303
304
        conn
        |> json_reply(400, Jason.encode!(errors))
305
306
307
    end
  end

lain's avatar
lain committed
308
  def update_avatar(%{assigns: %{user: user}} = conn, params) do
href's avatar
href committed
309
    {:ok, object} = ActivityPub.upload(params, type: :avatar)
310
    change = Changeset.change(user, %{avatar: object.data})
lain's avatar
lain committed
311
    {:ok, user} = User.update_and_set_cache(change)
lain's avatar
lain committed
312
    CommonAPI.update(user)
lain's avatar
lain committed
313

dtluna's avatar
dtluna committed
314
    render(conn, UserView, "show.json", %{user: user, for: user})
lain's avatar
lain committed
315
316
  end

lain's avatar
lain committed
317
  def update_banner(%{assigns: %{user: user}} = conn, params) do
href's avatar
href committed
318
    with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
319
320
321
322
         new_info <- %{"banner" => object.data},
         info_cng <- User.Info.profile_update(user.info, new_info),
         changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
         {:ok, user} <- User.update_and_set_cache(changeset) do
lain's avatar
lain committed
323
      CommonAPI.update(user)
lain's avatar
lain committed
324
325
326
      %{"url" => [%{"href" => href} | _]} = object.data
      response = %{url: href} |> Jason.encode!()

lain's avatar
lain committed
327
328
329
330
331
332
      conn
      |> json_reply(200, response)
    end
  end

  def update_background(%{assigns: %{user: user}} = conn, params) do
href's avatar
href committed
333
    with {:ok, object} <- ActivityPub.upload(params, type: :background),
334
335
336
337
         new_info <- %{"background" => object.data},
         info_cng <- User.Info.profile_update(user.info, new_info),
         changeset <- Ecto.Changeset.change(user) |> Ecto.Changeset.put_embed(:info, info_cng),
         {:ok, _user} <- User.update_and_set_cache(changeset) do
lain's avatar
lain committed
338
339
340
      %{"url" => [%{"href" => href} | _]} = object.data
      response = %{url: href} |> Jason.encode!()

lain's avatar
lain committed
341
342
343
344
345
      conn
      |> json_reply(200, response)
    end
  end

lain's avatar
lain committed
346
347
  def external_profile(%{assigns: %{user: current_user}} = conn, %{"profileurl" => uri}) do
    with {:ok, user_map} <- TwitterAPI.get_external_profile(current_user, uri),
lain's avatar
lain committed
348
         response <- Jason.encode!(user_map) do
lain's avatar
lain committed
349
350
      conn
      |> json_reply(200, response)
lain's avatar
lain committed
351
352
353
354
355
    else
      _e ->
        conn
        |> put_status(404)
        |> json(%{error: "Can't find user"})
lain's avatar
lain committed
356
357
358
    end
  end

eal's avatar
eal committed
359
  def followers(conn, params) do
360
    with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
eal's avatar
eal committed
361
         {:ok, followers} <- User.get_followers(user) do
362
      render(conn, UserView, "index.json", %{users: followers, for: conn.assigns[:user]})
lain's avatar
lain committed
363
364
365
366
367
    else
      _e -> bad_request_reply(conn, "Can't get followers")
    end
  end

eal's avatar
eal committed
368
  def friends(conn, params) do
369
    with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
eal's avatar
eal committed
370
         {:ok, friends} <- User.get_friends(user) do
371
      render(conn, UserView, "index.json", %{users: friends, for: conn.assigns[:user]})
lain's avatar
lain committed
372
373
374
375
376
    else
      _e -> bad_request_reply(conn, "Can't get friends")
    end
  end

377
  def friend_requests(conn, params) do
378
    with {:ok, user} <- TwitterAPI.get_user(conn.assigns[:user], params),
379
         {:ok, friend_requests} <- User.get_follow_requests(user) do
380
      render(conn, UserView, "index.json", %{users: friend_requests, for: conn.assigns[:user]})
381
382
383
384
385
    else
      _e -> bad_request_reply(conn, "Can't get friend requests")
    end
  end

386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  def approve_friend_request(conn, %{"user_id" => uid} = params) do
    with followed <- conn.assigns[:user],
         uid when is_number(uid) <- String.to_integer(uid),
         %User{} = follower <- Repo.get(User, uid),
         {:ok, follower} <- User.maybe_follow(follower, followed),
         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "accept"),
         {:ok, _activity} <-
           ActivityPub.accept(%{
             to: [follower.ap_id],
             actor: followed.ap_id,
             object: follow_activity.data["id"],
             type: "Accept"
           }) do
      render(conn, UserView, "show.json", %{user: follower, for: followed})
    else
      e -> bad_request_reply(conn, "Can't approve user: #{inspect(e)}")
    end
  end

  def deny_friend_request(conn, %{"user_id" => uid} = params) do
    with followed <- conn.assigns[:user],
         uid when is_number(uid) <- String.to_integer(uid),
         %User{} = follower <- Repo.get(User, uid),
         %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
         {:ok, follow_activity} <- Utils.update_follow_state(follow_activity, "reject"),
         {:ok, _activity} <-
           ActivityPub.reject(%{
             to: [follower.ap_id],
             actor: followed.ap_id,
             object: follow_activity.data["id"],
             type: "Reject"
           }) do
      render(conn, UserView, "show.json", %{user: follower, for: followed})
    else
      e -> bad_request_reply(conn, "Can't deny user: #{inspect(e)}")
    end
  end

eal's avatar
eal committed
425
426
  def friends_ids(%{assigns: %{user: user}} = conn, _params) do
    with {:ok, friends} <- User.get_friends(user) do
lain's avatar
lain committed
427
428
429
430
      ids =
        friends
        |> Enum.map(fn x -> x.id end)
        |> Jason.encode!()
431

eal's avatar
eal committed
432
433
434
435
436
437
      json(conn, ids)
    else
      _e -> bad_request_reply(conn, "Can't get friends")
    end
  end

438
  def empty_array(conn, _params) do
lain's avatar
lain committed
439
    json(conn, Jason.encode!([]))
440
  end
eal's avatar
eal committed
441

442
443
444
445
  def raw_empty_array(conn, _params) do
    json(conn, [])
  end

lain's avatar
lain committed
446
447
448
449
450
451
  defp build_info_cng(user, params) do
    info_params =
      ["no_rich_text", "locked"]
      |> Enum.reduce(%{}, fn key, res ->
        if value = params[key] do
          Map.put(res, key, value == "true")
452
        else
lain's avatar
lain committed
453
          res
454
        end
lain's avatar
lain committed
455
      end)
456

lain's avatar
lain committed
457
458
459
    info_params =
      if value = params["default_scope"] do
        Map.put(info_params, "default_scope", value)
460
      else
lain's avatar
lain committed
461
        info_params
462
463
      end

lain's avatar
lain committed
464
465
466
    User.Info.profile_update(user.info, info_params)
  end

Maxim Filippov's avatar
Maxim Filippov committed
467
  defp parse_profile_bio(user, params) do
lain's avatar
lain committed
468
    if bio = params["description"] do
Maxim Filippov's avatar
Maxim Filippov committed
469
      Map.put(params, "bio", User.parse_bio(bio, user))
lain's avatar
lain committed
470
471
472
473
474
475
    else
      params
    end
  end

  def update_profile(%{assigns: %{user: user}} = conn, params) do
Maxim Filippov's avatar
Maxim Filippov committed
476
    params = parse_profile_bio(user, params)
lain's avatar
lain committed
477
    info_cng = build_info_cng(user, params)
478

lain's avatar
lain committed
479
    with changeset <- User.update_changeset(user, params),
lain's avatar
lain committed
480
         changeset <- Ecto.Changeset.put_embed(changeset, :info, info_cng),
lain's avatar
lain committed
481
         {:ok, user} <- User.update_and_set_cache(changeset) do
lain's avatar
lain committed
482
      CommonAPI.update(user)
lain's avatar
lain committed
483
484
485
486
487
488
489
490
      render(conn, UserView, "user.json", %{user: user, for: user})
    else
      error ->
        Logger.debug("Can't update user: #{inspect(error)}")
        bad_request_reply(conn, "Can't update user")
    end
  end

Thog's avatar
Thog committed
491
  def search(%{assigns: %{user: user}} = conn, %{"q" => _query} = params) do
lain's avatar
lain committed
492
493
    activities = TwitterAPI.search(user, params)

lain's avatar
lain committed
494
    conn
lain's avatar
lain committed
495
    |> render(ActivityView, "index.json", %{activities: activities, for: user})
lain's avatar
lain committed
496
497
  end

498
499
500
501
502
503
504
  def search_user(%{assigns: %{user: user}} = conn, %{"query" => query}) do
    users = User.search(query, true)

    conn
    |> render(UserView, "index.json", %{users: users, for: user})
  end

505
  defp bad_request_reply(conn, error_message) do
dtluna's avatar
dtluna committed
506
    json = error_json(conn, error_message)
507
508
509
    json_reply(conn, 400, json)
  end

510
511
512
513
514
  defp json_reply(conn, status, json) do
    conn
    |> put_resp_content_type("application/json")
    |> send_resp(status, json)
  end
515
516

  defp forbidden_json_reply(conn, error_message) do
dtluna's avatar
dtluna committed
517
    json = error_json(conn, error_message)
518
519
    json_reply(conn, 403, json)
  end
dtluna's avatar
dtluna committed
520

href's avatar
href committed
521
522
523
524
525
526
527
528
  def only_if_public_instance(conn = %{conn: %{assigns: %{user: _user}}}, _), do: conn

  def only_if_public_instance(conn, _) do
    if Keyword.get(Application.get_env(:pleroma, :instance), :public) do
      conn
    else
      conn
      |> forbidden_json_reply("Invalid credentials.")
href's avatar
href committed
529
      |> halt()
href's avatar
href committed
530
531
532
    end
  end

dtluna's avatar
dtluna committed
533
  defp error_json(conn, error_message) do
lain's avatar
lain committed
534
    %{"error" => error_message, "request" => conn.request_path} |> Jason.encode!()
dtluna's avatar
dtluna committed
535
  end
536
537
538
539
540
541
542
543
544
545
546
547

  def errors(conn, {:param_cast, _}) do
    conn
    |> put_status(400)
    |> json("Invalid parameters")
  end

  def errors(conn, _) do
    conn
    |> put_status(500)
    |> json("Something went wrong")
  end
548
end