lib/http.ex

defmodule GogsHttp do
  @moduledoc """
  Documentation for the `HTTP` "verb" functions.
  Should be self-explanatory.
  Each function documented & typespecd.  
  If anything is unclear, please open an issue: 
  [github.com/dwyl/**gogs/issues**](https://github.com/dwyl/gogs/issues)
  """
  require Logger

  @access_token Envar.get("GOGS_ACCESS_TOKEN")
  # HTTP Headers don't change so hard-coded here:
  @headers [
    {"Accept", "application/json"},
    {"Authorization", "token #{@access_token}"},
    {"Content-Type", "application/json"}
  ]
  @mock Application.compile_env(:gogs, :mock)
  Logger.debug("GogsHttp > config :gogs, mock: #{to_string(@mock)}")
  @httpoison (@mock && Gogs.HTTPoisonMock) || HTTPoison

  @doc """
  `inject_poison/0` injects a TestDouble of HTTPoison in Test.
  see: https://github.com/dwyl/elixir-auth-google/issues/35
  """
  def inject_poison, do: @httpoison

  @doc """
  `parse_body_response/1` parses the response returned by the Gogs Server
  so your app can use the resulting JSON.
  """
  @spec parse_body_response({atom, String.t()} | {:error, any}) :: {:ok, map} | {:error, any}
  def parse_body_response({:error, err}), do: {:error, err}

  def parse_body_response({:ok, response}) do
    # Logger.debug(response) # very noisy!
    body = Map.get(response, :body)
    if body == nil || byte_size(body) == 0 do
      Logger.warning("GogsHttp.parse_body_response: response body is nil!")
      {:error, :no_body}
    else
      {:ok, str_key_map} = Jason.decode(body)
      # make keys of map atoms for easier access in templates etc.
      {:ok, Useful.atomize_map_keys(str_key_map)}
    end
  end

  @doc """
  `get/1` accepts one argument: `url` the REST API endpoint. 
  Makes an `HTTP GET` request to the specified `url`.
  Auth Headers and Content-Type are implicit.
  returns `{:ok, map}`
  """
  @spec get(String.t()) :: {:ok, map} | {:error, any}
  def get(url) do
    Logger.debug("GogsHttp.get #{url}")
    inject_poison().get(url, @headers)
    |> parse_body_response()
  end

  @doc """
  `get_raw/1` as it's name suggests gets the raw data
  (expects the reponse to be plaintext not JSON)
  accepts one argument: `url` the REST API endpoint. 
  Makes an `HTTP GET` request to the specified `url`.
  Auth Headers and Content-Type are implicit.
  returns `{:ok, map}`
  """
  @spec get_raw(String.t()) :: {:ok, map} | {:error, any}
  def get_raw(url) do
    Logger.debug("GogsHttp.get_raw #{url}")
    headers = [{"Authorization", "token #{@access_token}"}]
    inject_poison().get(url, headers)
  end

  @doc """
  `post/2` accepts two arguments: `url` and `params`. 
  Makes an `HTTP POST` request to the specified `url`
  passing in the `params` as the request body.
  Auth Headers and Content-Type are implicit.
  """
  @spec post(String.t(), map) :: {:ok, map} | {:error, any}
  def post(url, params \\ %{}) do
    Logger.debug("GogsHttp.post #{url}")
    body = Jason.encode!(params)
    inject_poison().post(url, body, @headers)
    |> parse_body_response()
  end

  @doc """
  `delete/1` accepts a single argument `url`; 
  the `url` for the repository to be deleted.
  """
  @spec delete(String.t()) :: {:ok, map} | {:error, any}
  def delete(url) do
    Logger.debug("GogsHttp.delete #{url}")
    inject_poison().delete(url <> "?token=#{@access_token}")
    |> parse_body_response()
  end
end