136 lines
3.5 KiB
Elixir
136 lines
3.5 KiB
Elixir
defmodule Towerops.Uisp.Client do
|
|
@moduledoc """
|
|
HTTP client for the UISP API.
|
|
|
|
Uses Req with built-in test support via `Req.Test`.
|
|
Auth: x-auth-token header.
|
|
Base URL is configured per-integration (user provides their UISP URL).
|
|
"""
|
|
|
|
require Logger
|
|
|
|
@doc """
|
|
Tests the connection to the UISP API by fetching one site.
|
|
|
|
Returns `{:ok, body}` on success, `{:error, reason}` on failure.
|
|
"""
|
|
def test_connection(base_url, api_key) do
|
|
case request(:get, "#{base_url}/sites?count=1", api_key) do
|
|
{:ok, %{status: status, body: body}} when status in 200..299 ->
|
|
{:ok, body}
|
|
|
|
{:ok, %{status: 401}} ->
|
|
{:error, :unauthorized}
|
|
|
|
{:ok, %{status: 403}} ->
|
|
{:error, :forbidden}
|
|
|
|
{:ok, %{status: status, body: body}} ->
|
|
Logger.warning("UISP API unexpected status #{status}: #{inspect(body)}")
|
|
{:error, {:unexpected_status, status}}
|
|
|
|
{:error, reason} ->
|
|
Logger.error("UISP API connection error: #{inspect(reason)}")
|
|
{:error, reason}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Lists all sites from the UISP API.
|
|
|
|
Returns `{:ok, [site]}` on success.
|
|
"""
|
|
def list_sites(base_url, api_key) do
|
|
case request(:get, "#{base_url}/sites", api_key) do
|
|
{:ok, %{status: status, body: body}} when status in 200..299 ->
|
|
{:ok, normalize_list(body)}
|
|
|
|
{:ok, %{status: 401}} ->
|
|
{:error, :unauthorized}
|
|
|
|
{:ok, %{status: 403}} ->
|
|
{:error, :forbidden}
|
|
|
|
{:ok, %{status: status, body: body}} ->
|
|
{:error, {:unexpected_status, status, body}}
|
|
|
|
{:error, reason} ->
|
|
{:error, reason}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Lists all devices from the UISP API.
|
|
|
|
Returns `{:ok, [device]}` on success.
|
|
"""
|
|
def list_devices(base_url, api_key) do
|
|
case request(:get, "#{base_url}/devices", api_key) do
|
|
{:ok, %{status: status, body: body}} when status in 200..299 ->
|
|
{:ok, normalize_list(body)}
|
|
|
|
{:ok, %{status: 401}} ->
|
|
{:error, :unauthorized}
|
|
|
|
{:ok, %{status: 403}} ->
|
|
{:error, :forbidden}
|
|
|
|
{:ok, %{status: status, body: body}} ->
|
|
{:error, {:unexpected_status, status, body}}
|
|
|
|
{:error, reason} ->
|
|
{:error, reason}
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Makes a raw request to any UISP API endpoint.
|
|
Returns `{:ok, body}` or `{:error, reason}`.
|
|
"""
|
|
def request_raw(method, url, api_key) do
|
|
case request(method, url, api_key) do
|
|
{:ok, %{status: status, body: body}} when status in 200..299 ->
|
|
{:ok, body}
|
|
|
|
{:ok, %{status: 401}} ->
|
|
{:error, :unauthorized}
|
|
|
|
{:ok, %{status: 404}} ->
|
|
{:error, :not_found}
|
|
|
|
{:ok, %{status: status, body: body}} ->
|
|
{:error, {:unexpected_status, status, body}}
|
|
|
|
{:error, reason} ->
|
|
{:error, reason}
|
|
end
|
|
end
|
|
|
|
defp normalize_list(body) when is_list(body), do: body
|
|
defp normalize_list(%{"items" => items}) when is_list(items), do: items
|
|
defp normalize_list(_), do: []
|
|
|
|
defp request(method, url, api_key) do
|
|
opts = [
|
|
method: method,
|
|
url: url,
|
|
headers: [{"x-auth-token", api_key}, {"accept", "application/json"}]
|
|
]
|
|
|
|
# Only use Req.Test plug in test environment
|
|
# Also disable retry in tests to avoid 7s timeout (1s + 2s + 4s exponential backoff)
|
|
opts =
|
|
if Application.get_env(:towerops, :env) == :test do
|
|
opts
|
|
|> Keyword.put(:plug, {Req.Test, __MODULE__})
|
|
|> Keyword.put(:retry, false)
|
|
else
|
|
opts
|
|
end
|
|
|
|
Req.request(opts)
|
|
rescue
|
|
exception ->
|
|
{:error, Exception.message(exception)}
|
|
end
|
|
end
|