Refactor duplicate site API logic

This commit is contained in:
Graham McIntire 2026-03-10 16:27:35 -05:00
parent 48270f5e35
commit 91a051f14d
No known key found for this signature in database

View file

@ -0,0 +1,186 @@
defmodule ToweropsWeb.Api.V1.SitesController do
@moduledoc """
API controller for managing sites.
All endpoints require API token authentication and operations are scoped
to the organization associated with the token.
"""
use ToweropsWeb, :controller
import ToweropsWeb.Api.ErrorHelpers, only: [translate_errors: 1]
alias Towerops.Sites
alias Towerops.Sites.Site
alias ToweropsWeb.ScopedResource
@doc """
GET /api/v1/sites
Lists all sites for the authenticated organization.
Response:
{
"sites": [
{
"id": "uuid",
"name": "Main Office",
"location": "New York, NY",
"snmp_community": "public",
"inserted_at": "2026-01-15T19:44:25Z"
}
]
}
"""
def index(conn, _params) do
organization_id = conn.assigns.current_organization_id
sites =
organization_id
|> Sites.list_organization_sites()
|> Enum.map(&format_site/1)
json(conn, %{sites: sites})
end
@doc """
POST /api/v1/sites
Creates a new site for the authenticated organization.
"""
def create(conn, %{"site" => site_params}) do
organization_id = conn.assigns.current_organization_id
attrs = Map.put(site_params, "organization_id", organization_id)
case Sites.create_site(attrs) do
{:ok, site} ->
conn
|> put_status(:created)
|> json(format_site(site))
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{errors: translate_errors(changeset)})
end
end
def create(conn, _params) do
conn
|> put_status(:bad_request)
|> json(%{error: "Missing 'site' parameter"})
end
@doc """
GET /api/v1/sites/:id
Gets a single site by ID.
"""
def show(conn, %{"id" => id}) do
organization_id = conn.assigns.current_organization_id
case ScopedResource.fetch(Site, id, organization_id) do
{:ok, site} ->
json(conn, format_site(site))
{:error, :forbidden} ->
conn
|> put_status(:forbidden)
|> json(%{error: "Access denied to this site"})
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Site not found"})
end
end
@doc """
PATCH /api/v1/sites/:id
Updates a site.
"""
def update(conn, %{"id" => id, "site" => site_params}) do
organization_id = conn.assigns.current_organization_id
case ScopedResource.fetch(Site, id, organization_id) do
{:ok, site} ->
case Sites.update_site(site, site_params) do
{:ok, updated_site} ->
json(conn, format_site(updated_site))
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{errors: translate_errors(changeset)})
end
{:error, :forbidden} ->
conn
|> put_status(:forbidden)
|> json(%{error: "Access denied to this site"})
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Site not found"})
end
end
def update(conn, _params) do
conn
|> put_status(:bad_request)
|> json(%{error: "Missing 'site' parameter"})
end
@doc """
DELETE /api/v1/sites/:id
Deletes a site.
"""
def delete(conn, %{"id" => id}) do
organization_id = conn.assigns.current_organization_id
case ScopedResource.fetch(Site, id, organization_id) do
{:ok, site} ->
case Sites.delete_site(site) do
{:ok, _site} ->
json(conn, %{success: true})
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> json(%{errors: translate_errors(changeset)})
end
{:error, :forbidden} ->
conn
|> put_status(:forbidden)
|> json(%{error: "Access denied to this site"})
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{error: "Site not found"})
end
end
defp format_site(site) do
%{
id: site.id,
name: site.name,
description: site.description,
location: site.location,
address: site.address,
latitude: site.latitude,
longitude: site.longitude,
display_order: site.display_order,
snmp_community: site.snmp_community,
snmp_version: site.snmp_version,
snmp_port: site.snmp_port,
snmp_transport: site.snmp_transport,
agent_token_id: site.agent_token_id,
parent_site_id: site.parent_site_id,
inserted_at: site.inserted_at
}
end
end