- Sites schema with hierarchical parent-child relationships
- CRUD operations for sites
- Sites context with helper functions
- LiveView pages:
- /orgs/:slug/sites - List all sites
- /orgs/:slug/sites/new - Create new site
- /orgs/:slug/sites/:id - View site details
- /orgs/:slug/sites/:id/edit - Edit site
- Support for site locations and descriptions
- Site tree builder for hierarchy visualization
2. Equipment Management
- Equipment schema with monitoring fields
- IP address validation (IPv4 & IPv6)
- Equipment status tracking (up/down/unknown)
- Customizable check intervals per equipment
- Equipment context with CRUD operations
- LiveView pages:
- /orgs/:slug/equipment - List all equipment
- /orgs/:slug/equipment/new - Add equipment
- /orgs/:slug/equipment/:id - View equipment details
- /orgs/:slug/equipment/:id/edit - Edit equipment
- Equipment can be added from site pages
- Status badges and last checked timestamps
3. Database Schema
- sites table with self-referencing parent_site_id
- equipment table with status tracking
- All migrations run successfully
- Proper indexes on foreign keys and status
4. Features Implemented
- ✅ IP address validation using :inet.parse_address
- ✅ Site hierarchy with parent-child relationships
- ✅ Equipment linked to sites
- ✅ Monitoring enabled/disabled per equipment
- ✅ Customizable check intervals (30s - 3600s)
- ✅ Status tracking (up/down/unknown)
- ✅ Timestamps for last check and last status change
- ✅ Organization-scoped data (users only see their org's data)
114 lines
2.5 KiB
Elixir
114 lines
2.5 KiB
Elixir
defmodule Towerops.Sites do
|
|
@moduledoc """
|
|
The Sites context.
|
|
"""
|
|
|
|
import Ecto.Query
|
|
|
|
alias Towerops.Repo
|
|
alias Towerops.Sites.Site
|
|
|
|
@doc """
|
|
Returns the list of sites for an organization.
|
|
"""
|
|
def list_organization_sites(organization_id) do
|
|
Repo.all(
|
|
from(s in Site, where: s.organization_id == ^organization_id, order_by: [asc: s.name], preload: [:parent_site])
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Returns the list of root sites (sites without a parent) for an organization.
|
|
"""
|
|
def list_root_sites(organization_id) do
|
|
Repo.all(
|
|
from(s in Site,
|
|
where: s.organization_id == ^organization_id,
|
|
where: is_nil(s.parent_site_id),
|
|
order_by: [asc: s.name]
|
|
)
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Returns the list of child sites for a parent site.
|
|
"""
|
|
def list_child_sites(parent_site_id) do
|
|
Repo.all(from(s in Site, where: s.parent_site_id == ^parent_site_id, order_by: [asc: s.name]))
|
|
end
|
|
|
|
@doc """
|
|
Gets a single site.
|
|
"""
|
|
def get_site!(id) do
|
|
Site
|
|
|> Repo.get!(id)
|
|
|> Repo.preload([:parent_site, :child_sites, :equipment])
|
|
end
|
|
|
|
@doc """
|
|
Gets a single site belonging to an organization.
|
|
"""
|
|
def get_organization_site!(organization_id, site_id) do
|
|
Repo.one!(
|
|
from(s in Site,
|
|
where: s.id == ^site_id,
|
|
where: s.organization_id == ^organization_id,
|
|
preload: [:parent_site, :child_sites, :equipment]
|
|
)
|
|
)
|
|
end
|
|
|
|
@doc """
|
|
Creates a site.
|
|
"""
|
|
def create_site(attrs) do
|
|
%Site{}
|
|
|> Site.changeset(attrs)
|
|
|> Repo.insert()
|
|
end
|
|
|
|
@doc """
|
|
Updates a site.
|
|
"""
|
|
def update_site(%Site{} = site, attrs) do
|
|
site
|
|
|> Site.changeset(attrs)
|
|
|> Repo.update()
|
|
end
|
|
|
|
@doc """
|
|
Deletes a site.
|
|
"""
|
|
def delete_site(%Site{} = site) do
|
|
Repo.delete(site)
|
|
end
|
|
|
|
@doc """
|
|
Returns an `%Ecto.Changeset{}` for tracking site changes.
|
|
"""
|
|
def change_site(%Site{} = site, attrs \\ %{}) do
|
|
Site.changeset(site, attrs)
|
|
end
|
|
|
|
@doc """
|
|
Builds a hierarchical tree structure of sites.
|
|
"""
|
|
def build_site_tree(organization_id) do
|
|
sites = list_organization_sites(organization_id)
|
|
root_sites = Enum.filter(sites, &is_nil(&1.parent_site_id))
|
|
|
|
Enum.map(root_sites, fn root ->
|
|
build_tree_node(root, sites)
|
|
end)
|
|
end
|
|
|
|
defp build_tree_node(site, all_sites) do
|
|
children =
|
|
all_sites
|
|
|> Enum.filter(&(&1.parent_site_id == site.id))
|
|
|> Enum.map(&build_tree_node(&1, all_sites))
|
|
|
|
%{site: site, children: children}
|
|
end
|
|
end
|