summaryrefslogtreecommitdiff
path: root/lib/pleroma/web/controller_helper.ex
blob: 6445966e020c09b6e363599afb66baf2e2f51d53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# Pleroma: A lightweight social networking server
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only

defmodule Pleroma.Web.ControllerHelper do
  use Pleroma.Web, :controller

  alias Pleroma.Pagination

  # As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
  @falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]

  def explicitly_falsy_param?(value), do: value in @falsy_param_values

  # Note: `nil` and `""` are considered falsy values in Pleroma
  def falsy_param?(value),
    do: explicitly_falsy_param?(value) or value in [nil, ""]

  def truthy_param?(value), do: not falsy_param?(value)

  def json_response(conn, status, _) when status in [204, :no_content] do
    conn
    |> put_resp_header("content-type", "application/json")
    |> send_resp(status, "")
  end

  def json_response(conn, status, json) do
    conn
    |> put_status(status)
    |> json(json)
  end

  @spec fetch_integer_param(map(), String.t(), integer() | nil) :: integer() | nil
  def fetch_integer_param(params, name, default \\ nil) do
    params
    |> Map.get(name, default)
    |> param_to_integer(default)
  end

  defp param_to_integer(val, _) when is_integer(val), do: val

  defp param_to_integer(val, default) when is_binary(val) do
    case Integer.parse(val) do
      {res, _} -> res
      _ -> default
    end
  end

  defp param_to_integer(_, default), do: default

  def add_link_headers(conn, activities, extra_params \\ %{})

  def add_link_headers(%{assigns: %{skip_link_headers: true}} = conn, _activities, _extra_params),
    do: conn

  def add_link_headers(conn, activities, extra_params) do
    case get_pagination_fields(conn, activities, extra_params) do
      %{"next" => next_url, "prev" => prev_url} ->
        put_resp_header(conn, "link", "<#{next_url}>; rel=\"next\", <#{prev_url}>; rel=\"prev\"")

      _ ->
        conn
    end
  end

  @id_keys Pagination.page_keys() -- ["limit", "order"]
  defp build_pagination_fields(conn, min_id, max_id, extra_params) do
    params =
      conn.params
      |> Map.drop(Map.keys(conn.path_params))
      |> Map.merge(extra_params)
      |> Map.drop(@id_keys)

    %{
      "next" => current_url(conn, Map.put(params, :max_id, max_id)),
      "prev" => current_url(conn, Map.put(params, :min_id, min_id)),
      "id" => current_url(conn)
    }
  end

  def get_pagination_fields(conn, activities, extra_params \\ %{}) do
    case List.last(activities) do
      %{pagination_id: max_id} when not is_nil(max_id) ->
        %{pagination_id: min_id} =
          activities
          |> List.first()

        build_pagination_fields(conn, min_id, max_id, extra_params)

      %{id: max_id} ->
        %{id: min_id} =
          activities
          |> List.first()

        build_pagination_fields(conn, min_id, max_id, extra_params)

      _ ->
        %{}
    end
  end

  def assign_account_by_id(conn, _) do
    case Pleroma.User.get_cached_by_id(conn.params.id) do
      %Pleroma.User{} = account -> assign(conn, :account, account)
      nil -> Pleroma.Web.MastodonAPI.FallbackController.call(conn, {:error, :not_found}) |> halt()
    end
  end

  def try_render(conn, target, params) when is_binary(target) do
    case render(conn, target, params) do
      nil -> render_error(conn, :not_implemented, "Can't display this activity")
      res -> res
    end
  end

  def try_render(conn, _, _) do
    render_error(conn, :not_implemented, "Can't display this activity")
  end

  @doc """
  Returns true if request specifies to include embedded relationships in account objects.
  May only be used in selected account-related endpoints; has no effect for status- or
    notification-related endpoints.
  """
  # Intended for PleromaFE: https://git.pleroma.social/pleroma/pleroma-fe/-/issues/838
  def embed_relationships?(params) do
    # To do once OpenAPI transition mess is over: just `truthy_param?(params[:with_relationships])`
    params
    |> Map.get(:with_relationships, params["with_relationships"])
    |> truthy_param?()
  end
end