- 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)
132 lines
3.1 KiB
Elixir
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
|