defmodule Gitea.Http 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/**gitea/issues**](https://github.com/dwyl/gitea/issues) """ require Logger @mock Application.compile_env(:gitea, :mock) Logger.debug("GiteaHttp > config :gitea, mock: #{to_string(@mock)}") @httpoison (@mock && Gitea.HTTPoisonMock) || HTTPoison defp access_token do Envar.get("GITEA_ACCESS_TOKEN") end defp auth_header do {"Authorization", "token #{access_token()}"} end defp json_headers do [ {"Accept", "application/json"}, auth_header(), {"Content-Type", "application/json"} ] end @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 Gitea 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} # Deleting a repository or an organisation returns an empty string for the body value # Instead of returning {:error, :no_body) (see next parse_body_response definition) # the function returns {:ok, response} when the status code response is 204 # see https://github.com/dwyl/gitea/pull/8#discussion_r874618485 def parse_body_response({:ok, response = %{status_code: 204}}), do: {:ok, response} # Successful status are in 200..299, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Status def parse_body_response({:ok, %{status_code: status_code}}) when status_code not in 200..299, do: {:error, status_code} def parse_body_response({:ok, response}) do body = Map.get(response, :body) if body == nil || byte_size(body) == 0 do Logger.warning("GiteaHttp.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("GiteaHttp.get #{url}") inject_poison().get(url, json_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("GiteaHttp.get_raw #{url}") inject_poison().get(url, [auth_header()]) end @doc """ `post_raw_html/2` accepts two arguments: `url` and `raw_markdown`. Makes an `HTTP POST` request to the specified `url` passing in the `params` as the request body. Does NOT attempt to parse the response body as JSON. Auth Headers and Content-Type are implicit. """ @spec post_raw_html(String.t(), String.t()) :: {:ok, String.t()} | {:error, any} def post_raw_html(url, raw_markdown) do Logger.debug("GiteaHttp.post_raw #{url}") # Logger.debug("raw_markdown: #{raw_markdown}") headers = [ {"Accept", "text/html"}, auth_header() ] inject_poison().post(url, raw_markdown, 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("GiteaHttp.post #{url}") body = Jason.encode!(params) inject_poison().post(url, body, json_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("GiteaHttp.delete #{url}") inject_poison().delete(url <> "?token=#{access_token()}") |> parse_body_response() end end