towerops/lib/towerops_web/controllers/api/v1/sites_controller.ex
Graham McIntire a4e08b2aca Major codebase cleanup: DRY schemas, remove dead config, consolidate modules
- Created Towerops.Schema base macro (95+ schemas updated to use it)
- Created Towerops.Snmp.Reading macro (7 reading schemas consolidated)
- Created Towerops.Gaiia.BaseSchema macro (4 Gaiia schemas consolidated)
- Created Towerops.SyncLog shared module (UISP + Preseem merge)
- Created Towerops.LogFilters (3 log filter modules merged into 1)
- Created Towerops.OnCall.ChangesetHelpers (9 on-call schemas simplified)
- Created API v1 ResourceController shared helpers (7 controllers)
- Extracted ConnectionHelpers.format_connection_result (2 LiveViews)
- Removed 5 dead config keys (scopes, mib_dirs, stripe_meter_id, etc.)
- Fixed 2 pre-existing broken tests
- All 13,219 tests pass, Credo clean (0 issues)
2026-06-16 15:29:22 -05:00

132 lines
3.1 KiB
Elixir

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
alias Towerops.Sites
alias Towerops.Sites.Site
alias ToweropsWeb.Api.ParamFilter
alias ToweropsWeb.Api.V1.ResourceController, as: Resources
@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 =
site_params
|> ParamFilter.strip_sensitive()
|> Map.put("organization_id", organization_id)
Resources.created_or_error(conn, Sites.create_site(attrs), &format_site/1)
end
def create(conn, _params) do
Resources.missing_param(conn, "site")
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
Resources.fetch_and_render(conn, Site, id, organization_id, &format_site/1, "Site not found")
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
Resources.update_and_render(
conn,
Site,
id,
organization_id,
%{
context: Sites,
update_fn: :update_site,
params: ParamFilter.strip_sensitive(site_params),
format_fn: &format_site/1,
not_found_msg: "Site not found"
}
)
end
def update(conn, _params) do
Resources.missing_param(conn, "site")
end
@doc """
DELETE /api/v1/sites/:id
Deletes a site.
"""
def delete(conn, %{"id" => id}) do
organization_id = conn.assigns.current_organization_id
Resources.delete_and_render(conn, Site, id, organization_id, Sites, :delete_site, "Site not found")
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