lib/reddex.ex

defmodule Breddit do
  require Logger
  use OAuth2.Strategy
  alias OAuth2.Strategy.AuthCode

  # @scopes "identity edit flair history mysubreddits privatemessages read report save submit"
  @site "https://oauth.reddit.com"
  @root_url @site

  @default_config [
    strategy: Breddit,
    site: "https://oauth.reddit.com/",
    authorize_url: "https://www.reddit.com/api/v1/authorize",
    token_url: "https://www.reddit.com/api/v1/access_token",
    params: %{duration: "permanent"},
    headers: [
      {"User-Agent", "web:breddit:v.0.0.1 (by u/andrex092)"},
      {"Content-Type", "application/x-www-form-urlencoded"}
    ]
  ]

  @type response :: {:ok, any()} | {:error, OAuth2.Error.t()}

  # TODO: extract to mix config
  defp config do
    @default_config
    |> Config.Reader.merge(Application.get_env(:breddit, :oauth))
    |> Keyword.update!(:params, &Map.merge(&1, Application.get_env(:breddit, :params)))
    #FIXME
    # |> Keyword.update!(:headers, &([Application.get_env(:breddit, :headers) | &1]))
  end

  defp url(uri, params, opts \\ []) do
    opts
    |> Keyword.get(:site, @root_url)
    |> URI.parse()
    |> URI.merge(uri)
    |> Map.put(:query, URI.encode_query(params))
    |> URI.to_string()
  end

  # Public API
  def client(args \\ []) do
    config()
    |> Keyword.merge(args)
    |> OAuth2.Client.new()
    |> OAuth2.Client.put_serializer("application/json", Jason)
  end

  def get(client, uri, opts \\ [], headers \\ []) do
    url = url(uri, Keyword.get(opts, :params))

    Logger.info("Getting: #{url}")

    client
    |> OAuth2.Client.put_serializer("application/json", Breddit.Serializer)
    |> OAuth2.Client.get(url, headers, opts)
    |> parse_response()
  end

  @spec parse_response({:ok, OAuth2.Response.t()} | {:error, OAuth2.Error.t()}) :: response()
  defp parse_response({:ok, %OAuth2.Response{body: body}}) do
    {:ok, body}
  end

  defp parse_response({:error, error}), do: {:error, error}

  def authorize_url!(params \\ []) do
    OAuth2.Client.authorize_url!(
      client(),
      Keyword.merge(params, client_secret: client().client_secret)
    )
  end

  def get_token!(params \\ [], _headers \\ []) do
    OAuth2.Client.get_token!(
      client(),
      Keyword.merge(params, client_secret: client().client_secret)
    )
  end

  # Strats
  def authorize_url(client, params) do
    AuthCode.authorize_url(client, params)
  end

  def get_token(client, params, headers) do
    client
    |> put_header("Accept", "application/json")
    |> AuthCode.get_token(params, headers)
  end
end