defmodule ToweropsWeb.Live.Helpers.AccessControl do @moduledoc """ Centralized organization-based access control for LiveViews. Provides functions to verify that users have access to resources (devices, sites, alerts) within their organization scope. """ alias Towerops.Alerts alias Towerops.Devices alias Towerops.Repo alias Towerops.Sites @doc """ Verifies that a device belongs to the specified organization. Returns `{:ok, device}` if access is granted, or an error tuple. ## Examples iex> verify_device_access(device_id, org_id) {:ok, %Device{}} iex> verify_device_access(device_id, wrong_org_id) {:error, :unauthorized} iex> verify_device_access("nonexistent", org_id) {:error, :not_found} """ @spec verify_device_access(binary(), binary()) :: {:ok, Devices.Device.t()} | {:error, :not_found | :unauthorized} def verify_device_access(device_id, organization_id) do case Devices.get_device(device_id) do nil -> {:error, :not_found} device -> if device.organization_id == organization_id do {:ok, device} else {:error, :unauthorized} end end end @doc """ Verifies that a site belongs to the specified organization. Returns `{:ok, site}` if access is granted, or an error tuple. ## Examples iex> verify_site_access(site_id, org_id) {:ok, %Site{}} iex> verify_site_access(site_id, wrong_org_id) {:error, :unauthorized} iex> verify_site_access("nonexistent", org_id) {:error, :not_found} """ @spec verify_site_access(binary(), binary()) :: {:ok, Sites.Site.t()} | {:error, :not_found | :unauthorized} def verify_site_access(site_id, organization_id) do case Sites.get_site(site_id) do nil -> {:error, :not_found} site -> if site.organization_id == organization_id do {:ok, site} else {:error, :unauthorized} end end end @doc """ Verifies that an alert's device belongs to the specified organization. Returns `{:ok, alert}` if access is granted, or an error tuple. The alert is preloaded with `device: [site: :organization]` for access checking. ## Examples iex> verify_alert_access(alert_id, org_id) {:ok, %Alert{device: %Device{site: %Site{organization: %Organization{}}}}} iex> verify_alert_access(alert_id, wrong_org_id) {:error, :unauthorized} iex> verify_alert_access("nonexistent", org_id) {:error, :not_found} """ @spec verify_alert_access(binary(), binary()) :: {:ok, Alerts.Alert.t()} | {:error, :not_found | :unauthorized} def verify_alert_access(alert_id, organization_id) do case Alerts.get_alert(alert_id) do nil -> {:error, :not_found} alert -> alert = Repo.preload(alert, device: [site: :organization]) if alert.device.site.organization_id == organization_id do {:ok, alert} else {:error, :unauthorized} end end end end