towerops/lib/towerops_web/live/alert_live/index.ex
Graham McIntire 89a076fb67
feat: migrate equipment features to gettext and fix sudo mode tests
Migrates all equipment-related flash messages to gettext for internationalization:
- DeviceLive.Index: device discovery, reordering, error messages
- DeviceLive.Show: backup messages, permission errors
- DeviceLive.Form: device CRUD operations
- AlertLive.Index: alert acknowledgment messages
- SiteLive.Show: site discovery messages
- SiteLive.Form: site CRUD and SNMP/agent propagation

Fixes sudo mode test suite issues:
- Updates Accounts.sudo_mode?/2 test to check last_sudo_at instead of authenticated_at
- Adds register_and_log_in_user_with_sudo/1 helper to ConnCase
- Fixes UserAuth sudo mode tests to use session-based authentication
- Updates MyData tests to use sudo mode (now required per router config)
- Removes obsolete UserSettingsLive "without sudo mode" test
- Fixes grant_sudo_mode/1 DateTime truncation to seconds

All equipment module tests passing. Ready for Phase 3 (Admin Features).
2026-02-02 12:41:58 -06:00

92 lines
2.6 KiB
Elixir

defmodule ToweropsWeb.AlertLive.Index do
@moduledoc false
use ToweropsWeb, :live_view
alias Towerops.Alerts
alias Towerops.Repo
@impl true
def mount(_params, _session, socket) do
organization = socket.assigns.current_scope.organization
# Subscribe to alert events
_ =
if connected?(socket) do
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:new")
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:resolved")
end
{:ok,
socket
|> assign(:page_title, "Alerts")
|> assign(:filter, "active")
|> load_alerts(organization.id)}
end
@impl true
def handle_params(params, _url, socket) do
filter = Map.get(params, "filter", "active")
{:noreply,
socket
|> assign(:filter, filter)
|> load_alerts(socket.assigns.current_scope.organization.id)}
end
@impl true
def handle_event("acknowledge", %{"id" => id}, socket) do
organization = socket.assigns.current_scope.organization
user_id = socket.assigns.current_scope.user.id
case Alerts.get_alert(id) do
nil ->
{:noreply, put_flash(socket, :error, t_equipment("Alert not found"))}
alert ->
# Preload device and site to check organization access
alert = Repo.preload(alert, device: [site: :organization])
if alert.device.site.organization_id == organization.id do
perform_acknowledge_alert(socket, alert, user_id, organization.id)
else
{:noreply, put_flash(socket, :error, t_equipment("You don't have access to this alert"))}
end
end
end
defp perform_acknowledge_alert(socket, alert, user_id, organization_id) do
case Alerts.acknowledge_alert(alert, user_id) do
{:ok, _alert} ->
{:noreply,
socket
|> put_flash(:info, t_equipment("Alert acknowledged"))
|> load_alerts(organization_id)}
{:error, _changeset} ->
{:noreply, put_flash(socket, :error, t_equipment("Unable to acknowledge alert"))}
end
end
@impl true
def handle_info({:new_alert, _device_id, _alert_type}, socket) do
{:noreply, load_alerts(socket, socket.assigns.current_scope.organization.id)}
end
@impl true
def handle_info({:alert_resolved, _device_id, _alert_type}, socket) do
{:noreply, load_alerts(socket, socket.assigns.current_scope.organization.id)}
end
defp load_alerts(socket, organization_id) do
alerts =
case socket.assigns.filter do
"active" ->
Alerts.list_organization_active_alerts(organization_id)
_ ->
Alerts.list_organization_alerts(organization_id, 100)
end
assign(socket, :alerts, alerts)
end
end