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