dialyzer: fix all unmatched_return warnings (154 → 0)
Prefix fire-and-forget calls (PubSub.broadcast, Oban enqueue, Logger, update_*, etc.) with `_ =` so dialyzer knows the return value is intentionally discarded. Wrap a few if/case expressions whose branches produce mixed types the same way. No behavior changes — only explicit acknowledgement of discarded returns. Warnings: 242 → 88.
This commit is contained in:
parent
2d6c7d28e2
commit
91e3181bbc
62 changed files with 470 additions and 406 deletions
|
|
@ -364,7 +364,7 @@ defmodule Towerops.Agents do
|
|||
|
||||
case ReleaseChecker.asset_for_arch(assets, arch) do
|
||||
{:ok, asset} ->
|
||||
update_agent(agent.id, asset.url, asset.checksum)
|
||||
_ = update_agent(agent.id, asset.url, asset.checksum)
|
||||
{notified + 1, skipped}
|
||||
|
||||
{:error, :no_matching_asset} ->
|
||||
|
|
@ -470,11 +470,12 @@ defmodule Towerops.Agents do
|
|||
|
||||
# 5. Disconnect any active agent channel AFTER successful deletion (inside transaction)
|
||||
# This ensures we only broadcast if the deletion actually succeeds
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{id}:lifecycle",
|
||||
:token_disabled
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{id}:lifecycle",
|
||||
:token_disabled
|
||||
)
|
||||
|
||||
agent_token
|
||||
end)
|
||||
|
|
@ -774,7 +775,7 @@ defmodule Towerops.Agents do
|
|||
{:ok, AgentAssignment.t() | nil} | {:error, Ecto.Changeset.t()}
|
||||
def update_device_assignment(device_id, nil) do
|
||||
# Remove assignment if setting to nil
|
||||
unassign_device(device_id)
|
||||
_ = unassign_device(device_id)
|
||||
{:ok, nil}
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ defmodule Towerops.Agents.AgentCache do
|
|||
@impl GenServer
|
||||
def init(_opts) do
|
||||
table = :ets.new(@table, [:named_table, :public, :set, read_concurrency: true])
|
||||
refresh_global_default()
|
||||
_ = refresh_global_default()
|
||||
schedule_cleanup()
|
||||
{:ok, %{table: table}}
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ defmodule Towerops.Alerts do
|
|||
|> enrich_with_organization_id()
|
||||
|
||||
with {:ok, alert} <- Repo.insert(Alert.changeset(%Alert{}, attrs)) do
|
||||
maybe_compute_gaiia_impact(alert)
|
||||
broadcast_alert_change(alert)
|
||||
_ = maybe_compute_gaiia_impact(alert)
|
||||
_ = broadcast_alert_change(alert)
|
||||
Subscriptions.publish_alert_event(alert, "created")
|
||||
{:ok, alert}
|
||||
end
|
||||
|
|
@ -283,7 +283,7 @@ defmodule Towerops.Alerts do
|
|||
def acknowledge_alert(alert, user_id) do
|
||||
case do_acknowledge_alert(alert, user_id) do
|
||||
{:ok, updated_alert} ->
|
||||
AlertNotificationWorker.enqueue_acknowledge(updated_alert.id)
|
||||
_ = AlertNotificationWorker.enqueue_acknowledge(updated_alert.id)
|
||||
Subscriptions.publish_alert_event(updated_alert, "acknowledged")
|
||||
{:ok, updated_alert}
|
||||
|
||||
|
|
@ -298,8 +298,8 @@ defmodule Towerops.Alerts do
|
|||
def resolve_alert(alert) do
|
||||
case do_resolve_alert(alert) do
|
||||
{:ok, updated_alert} ->
|
||||
AlertNotificationWorker.enqueue_resolve(updated_alert.id)
|
||||
broadcast_alert_change(updated_alert)
|
||||
_ = AlertNotificationWorker.enqueue_resolve(updated_alert.id)
|
||||
_ = broadcast_alert_change(updated_alert)
|
||||
Subscriptions.publish_alert_event(updated_alert, "resolved")
|
||||
{:ok, updated_alert}
|
||||
|
||||
|
|
@ -314,7 +314,7 @@ defmodule Towerops.Alerts do
|
|||
def resolve_alert_silent(alert) do
|
||||
case do_resolve_alert(alert) do
|
||||
{:ok, updated_alert} ->
|
||||
broadcast_alert_change(updated_alert)
|
||||
_ = broadcast_alert_change(updated_alert)
|
||||
{:ok, updated_alert}
|
||||
|
||||
error ->
|
||||
|
|
|
|||
|
|
@ -244,11 +244,12 @@ defmodule Towerops.Alerts.StormDetector do
|
|||
now = Towerops.Time.now()
|
||||
|
||||
# Check maintenance window for the site (single check instead of N)
|
||||
if Maintenance.site_in_maintenance?(site_id) do
|
||||
Logger.info("Site #{site_id} outage (#{device_count} devices) suppressed — in maintenance window")
|
||||
else
|
||||
do_create_site_outage_alert(site_id, devices, device_names, device_count, storm_mode, now)
|
||||
end
|
||||
_ =
|
||||
if Maintenance.site_in_maintenance?(site_id) do
|
||||
Logger.info("Site #{site_id} outage (#{device_count} devices) suppressed — in maintenance window")
|
||||
else
|
||||
do_create_site_outage_alert(site_id, devices, device_names, device_count, storm_mode, now)
|
||||
end
|
||||
|
||||
# Also mark each individual device as down (status update only, no individual alerts)
|
||||
Enum.each(devices, fn device ->
|
||||
|
|
@ -307,9 +308,10 @@ defmodule Towerops.Alerts.StormDetector do
|
|||
storm_suppressed: false
|
||||
}) do
|
||||
{:ok, alert} ->
|
||||
if !storm_mode do
|
||||
AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
end
|
||||
_ =
|
||||
if !storm_mode do
|
||||
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
end
|
||||
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
|
|
@ -386,9 +388,10 @@ defmodule Towerops.Alerts.StormDetector do
|
|||
message: alert_message
|
||||
}) do
|
||||
{:ok, alert} ->
|
||||
if !storm_mode do
|
||||
AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
end
|
||||
_ =
|
||||
if !storm_mode do
|
||||
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
end
|
||||
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ defmodule Towerops.ApiTokens do
|
|||
{:error, :invalid_token}
|
||||
else
|
||||
# Update last_used_at
|
||||
update_last_used(token)
|
||||
_ = update_last_used(token)
|
||||
|
||||
# Load user if present
|
||||
token = Repo.preload(token, :user)
|
||||
|
|
|
|||
|
|
@ -147,11 +147,12 @@ defmodule Towerops.Application do
|
|||
|
||||
# Run post-startup cleanup tasks (production only)
|
||||
# This ensures all polling jobs use the latest worker code after deployment
|
||||
Task.start(fn ->
|
||||
# Wait for supervisor to fully initialize
|
||||
Process.sleep(2000)
|
||||
JobCleanupTask.run()
|
||||
end)
|
||||
_ =
|
||||
Task.start(fn ->
|
||||
# Wait for supervisor to fully initialize
|
||||
Process.sleep(2000)
|
||||
JobCleanupTask.run()
|
||||
end)
|
||||
|
||||
result
|
||||
end
|
||||
|
|
|
|||
|
|
@ -576,7 +576,7 @@ defmodule Towerops.Devices do
|
|||
Logger.warning("Failed to create ping check for device #{device.id}: #{Exception.message(e)}")
|
||||
end
|
||||
|
||||
broadcast_device_change(device.organization_id, :device_created)
|
||||
_ = broadcast_device_change(device.organization_id, :device_created)
|
||||
|
||||
{:ok, device}
|
||||
|
||||
|
|
@ -699,7 +699,7 @@ defmodule Towerops.Devices do
|
|||
_ = Monitoring.ensure_default_ping_check(updated_device)
|
||||
end
|
||||
|
||||
broadcast_device_change(updated_device.organization_id, :device_updated)
|
||||
_ = broadcast_device_change(updated_device.organization_id, :device_updated)
|
||||
result
|
||||
|
||||
error ->
|
||||
|
|
@ -885,21 +885,22 @@ defmodule Towerops.Devices do
|
|||
# Delete the device (cascades to SNMP device, sensors, interfaces, etc.)
|
||||
result = Repo.delete(device)
|
||||
|
||||
case result do
|
||||
{:ok, _} ->
|
||||
# Notify agent to stop processing jobs for this device
|
||||
if agent_token_id do
|
||||
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
|
||||
end
|
||||
_ =
|
||||
case result do
|
||||
{:ok, _} ->
|
||||
# Notify agent to stop processing jobs for this device
|
||||
if agent_token_id do
|
||||
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
|
||||
end
|
||||
|
||||
broadcast_device_change(organization_id, :device_deleted)
|
||||
broadcast_device_change(organization_id, :device_deleted)
|
||||
|
||||
_ ->
|
||||
# Notify agent even on failure (preserves original behavior)
|
||||
if agent_token_id do
|
||||
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
|
||||
end
|
||||
end
|
||||
_ ->
|
||||
# Notify agent even on failure (preserves original behavior)
|
||||
if agent_token_id do
|
||||
Agents.broadcast_assignment_change(agent_token_id, :device_deleted)
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -932,11 +933,12 @@ defmodule Towerops.Devices do
|
|||
|
||||
case device |> Ecto.Changeset.change(changes) |> Repo.update() do
|
||||
{:ok, updated_device} = result ->
|
||||
if status_changed do
|
||||
broadcast_device_change(updated_device.organization_id, :device_status_changed)
|
||||
else
|
||||
broadcast_device_change(updated_device.organization_id, :device_updated)
|
||||
end
|
||||
_ =
|
||||
if status_changed do
|
||||
broadcast_device_change(updated_device.organization_id, :device_status_changed)
|
||||
else
|
||||
broadcast_device_change(updated_device.organization_id, :device_updated)
|
||||
end
|
||||
|
||||
result
|
||||
|
||||
|
|
|
|||
|
|
@ -124,11 +124,12 @@ defmodule Towerops.Devices.Firmware do
|
|||
new_version: new_version
|
||||
)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{snmp_device_id}",
|
||||
{:firmware_changed, snmp_device_id, old_version, new_version}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{snmp_device_id}",
|
||||
{:firmware_changed, snmp_device_id, old_version, new_version}
|
||||
)
|
||||
|
||||
result
|
||||
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ defmodule Towerops.Devices.MikrotikBackups.Differ do
|
|||
error ->
|
||||
{:error, "Failed to generate diff: #{inspect(error)}"}
|
||||
after
|
||||
File.rm(tmp_a)
|
||||
File.rm(tmp_b)
|
||||
_ = File.rm(tmp_a)
|
||||
_ = File.rm(tmp_b)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -185,10 +185,11 @@ defmodule Towerops.Monitoring do
|
|||
|> Repo.insert()
|
||||
end
|
||||
|
||||
case result do
|
||||
{:ok, check} -> broadcast_check_change(check)
|
||||
_ -> :ok
|
||||
end
|
||||
_ =
|
||||
case result do
|
||||
{:ok, check} -> broadcast_check_change(check)
|
||||
_ -> :ok
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -202,10 +203,11 @@ defmodule Towerops.Monitoring do
|
|||
|> Check.changeset(attrs)
|
||||
|> Repo.update()
|
||||
|
||||
case result do
|
||||
{:ok, updated} -> broadcast_check_change(updated)
|
||||
_ -> :ok
|
||||
end
|
||||
_ =
|
||||
case result do
|
||||
{:ok, updated} -> broadcast_check_change(updated)
|
||||
_ -> :ok
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -216,10 +218,11 @@ defmodule Towerops.Monitoring do
|
|||
def delete_check(%Check{} = check) do
|
||||
result = Repo.delete(check)
|
||||
|
||||
case result do
|
||||
{:ok, deleted} -> broadcast_check_change(deleted)
|
||||
_ -> :ok
|
||||
end
|
||||
_ =
|
||||
case result do
|
||||
{:ok, deleted} -> broadcast_check_change(deleted)
|
||||
_ -> :ok
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -429,10 +432,11 @@ defmodule Towerops.Monitoring do
|
|||
|> Check.state_changeset(attrs)
|
||||
|> Repo.update()
|
||||
|
||||
case result do
|
||||
{:ok, updated} -> broadcast_check_change(updated)
|
||||
_ -> :ok
|
||||
end
|
||||
_ =
|
||||
case result do
|
||||
{:ok, updated} -> broadcast_check_change(updated)
|
||||
_ -> :ok
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ defmodule Towerops.Monitoring.Executors.PingExecutor do
|
|||
end
|
||||
|
||||
nil ->
|
||||
Task.shutdown(task, :brutal_kill)
|
||||
_ = Task.shutdown(task, :brutal_kill)
|
||||
{:error, "Ping command timed out"}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ defmodule Towerops.OnCall.Escalation do
|
|||
}
|
||||
|
||||
with {:ok, incident} <- create_incident(attrs) do
|
||||
execute_current_rule(incident, policy)
|
||||
schedule_escalation_check(incident, policy)
|
||||
_ = execute_current_rule(incident, policy)
|
||||
_ = schedule_escalation_check(incident, policy)
|
||||
{:ok, incident}
|
||||
end
|
||||
end
|
||||
|
|
@ -131,8 +131,8 @@ defmodule Towerops.OnCall.Escalation do
|
|||
users = resolve_targets(rule.targets)
|
||||
|
||||
Enum.each(users, fn user ->
|
||||
Notifier.notify(user, incident)
|
||||
log_notification(incident, user)
|
||||
_ = Notifier.notify(user, incident)
|
||||
_ = log_notification(incident, user)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ defmodule Towerops.Preseem.Baseline do
|
|||
metrics = get_metrics_in_window(ap.id, cutoff)
|
||||
|
||||
if length(metrics) >= 3 do
|
||||
compute_and_upsert_baselines(ap.id, metrics, now)
|
||||
_ = compute_and_upsert_baselines(ap.id, metrics, now)
|
||||
acc + 1
|
||||
else
|
||||
acc
|
||||
|
|
|
|||
|
|
@ -70,14 +70,15 @@ defmodule Towerops.Security.BruteForce do
|
|||
|> IpWhitelist.changeset(attrs)
|
||||
|> Repo.insert()
|
||||
|
||||
case result do
|
||||
{:ok, _} ->
|
||||
clear_whitelist_cache()
|
||||
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
|
||||
_ =
|
||||
case result do
|
||||
{:ok, _} ->
|
||||
clear_whitelist_cache()
|
||||
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
|
||||
|
||||
{:error, _} ->
|
||||
:ok
|
||||
end
|
||||
{:error, _} ->
|
||||
:ok
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -93,7 +94,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
entry ->
|
||||
Repo.delete(entry)
|
||||
clear_whitelist_cache()
|
||||
PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
|
||||
_ = PubSub.broadcast(Towerops.PubSub, "security:whitelist", :whitelist_updated)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
@ -167,7 +168,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
# Delete the block record entirely
|
||||
Repo.delete(block)
|
||||
Logger.info("Manually unblocked IP: #{ip_address}")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
{:ok, block}
|
||||
end
|
||||
end
|
||||
|
|
@ -232,10 +233,11 @@ defmodule Towerops.Security.BruteForce do
|
|||
)
|
||||
)
|
||||
|
||||
if count > 0 do
|
||||
Logger.info("Deleted #{count} expired ban(s)")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
end
|
||||
_ =
|
||||
if count > 0 do
|
||||
Logger.info("Deleted #{count} expired ban(s)")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -281,7 +283,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
case result do
|
||||
{:ok, block} ->
|
||||
Logger.warning("IP banned (offense #{offense_count}): #{ip_address} until #{banned_until}")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
{:ok, block}
|
||||
|
||||
error ->
|
||||
|
|
@ -305,7 +307,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
case result do
|
||||
{:ok, updated} ->
|
||||
Logger.warning("IP ban reset (offense #{offense_count}): #{block.ip_address} until #{banned_until}")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
{:ok, updated}
|
||||
|
||||
error ->
|
||||
|
|
@ -342,12 +344,13 @@ defmodule Towerops.Security.BruteForce do
|
|||
case result do
|
||||
{:ok, updated} ->
|
||||
Logger.warning("IP ban escalated to #{log_msg} (offense #{new_count}): #{block.ip_address}")
|
||||
PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
_ = PubSub.broadcast(Towerops.PubSub, "security:blocks", :blocks_updated)
|
||||
|
||||
# Push to Cloudflare for permanent bans
|
||||
if new_count >= 3 do
|
||||
CloudflareBanWorker.enqueue(block.ip_address)
|
||||
end
|
||||
_ =
|
||||
if new_count >= 3 do
|
||||
CloudflareBanWorker.enqueue(block.ip_address)
|
||||
end
|
||||
|
||||
{:ok, updated}
|
||||
|
||||
|
|
@ -362,7 +365,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
defp get_cached_whitelist do
|
||||
case :ets.whereis(@whitelist_cache_table) do
|
||||
:undefined ->
|
||||
create_cache_table()
|
||||
_ = create_cache_table()
|
||||
load_whitelist()
|
||||
|
||||
_ ->
|
||||
|
|
@ -373,7 +376,7 @@ defmodule Towerops.Security.BruteForce do
|
|||
end
|
||||
rescue
|
||||
ArgumentError ->
|
||||
create_cache_table()
|
||||
_ = create_cache_table()
|
||||
load_whitelist()
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ defmodule Towerops.Security.FourOhFourTracker do
|
|||
|
||||
try do
|
||||
# Add path to set
|
||||
Redix.command(conn, ["SADD", key, path])
|
||||
_ = Redix.command(conn, ["SADD", key, path])
|
||||
# Set TTL if this is the first path
|
||||
Redix.command(conn, ["EXPIRE", key, @window_seconds])
|
||||
_ = Redix.command(conn, ["EXPIRE", key, @window_seconds])
|
||||
|
||||
# Get unique count
|
||||
case Redix.command(conn, ["SCARD", key]) do
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ defmodule Towerops.Snmp do
|
|||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
# Schedule first execution
|
||||
Monitoring.schedule_check(check)
|
||||
_ = Monitoring.schedule_check(check)
|
||||
{:ok, check}
|
||||
|
||||
error ->
|
||||
|
|
@ -219,7 +219,7 @@ defmodule Towerops.Snmp do
|
|||
|
||||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
Monitoring.schedule_check(check)
|
||||
_ = Monitoring.schedule_check(check)
|
||||
{:ok, check}
|
||||
|
||||
error ->
|
||||
|
|
@ -247,7 +247,7 @@ defmodule Towerops.Snmp do
|
|||
|
||||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
Monitoring.schedule_check(check)
|
||||
_ = Monitoring.schedule_check(check)
|
||||
{:ok, check}
|
||||
|
||||
error ->
|
||||
|
|
@ -277,7 +277,7 @@ defmodule Towerops.Snmp do
|
|||
|
||||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
Monitoring.schedule_check(check)
|
||||
_ = Monitoring.schedule_check(check)
|
||||
{:ok, check}
|
||||
|
||||
error ->
|
||||
|
|
|
|||
|
|
@ -1767,18 +1767,22 @@ defmodule Towerops.Snmp.Discovery do
|
|||
}
|
||||
|
||||
# Publish event for EventLogger to persist
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:events",
|
||||
{:device_event, event_attrs}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:events",
|
||||
{:device_event, event_attrs}
|
||||
)
|
||||
|
||||
# Also publish to org-scoped topic for targeted LiveView subscriptions
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device_events:org:#{device.organization_id}",
|
||||
{:device_event, event_attrs}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device_events:org:#{device.organization_id}",
|
||||
{:device_event, event_attrs}
|
||||
)
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
# Sanitizes data structures to ensure they are JSON-encodable
|
||||
|
|
|
|||
|
|
@ -294,14 +294,15 @@ defmodule Towerops.Snmp.SensorChangeDetector do
|
|||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:#{event.device_id}", {:device_event, event})
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:events", {:device_event, event})
|
||||
|
||||
case get_org_id_from_device(event.device_id) do
|
||||
nil ->
|
||||
:ok
|
||||
_ =
|
||||
case get_org_id_from_device(event.device_id) do
|
||||
nil ->
|
||||
:ok
|
||||
|
||||
org_id ->
|
||||
event_with_org = Map.put(event, :org_id, org_id)
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event_with_org})
|
||||
end
|
||||
org_id ->
|
||||
event_with_org = Map.put(event, :org_id, org_id)
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event_with_org})
|
||||
end
|
||||
|
||||
Logger.debug("Sensor event: #{event.message}")
|
||||
end)
|
||||
|
|
|
|||
|
|
@ -386,11 +386,12 @@ defmodule Towerops.Topology do
|
|||
# maybe_update_device_role(device)
|
||||
|
||||
if has_changes do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"topology:#{organization_id}",
|
||||
{:topology_updated, organization_id}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"topology:#{organization_id}",
|
||||
{:topology_updated, organization_id}
|
||||
)
|
||||
|
||||
{:ok, :changed}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ defmodule Towerops.Workers.AlertNotificationWorker do
|
|||
defp should_suppress_for_user?(user_id, org_id, alert_id) do
|
||||
case NotificationRateLimiter.check_rate(user_id, org_id, alert_id) do
|
||||
:suppress ->
|
||||
AlertDigestWorker.enqueue(user_id)
|
||||
_ = AlertDigestWorker.enqueue(user_id)
|
||||
true
|
||||
|
||||
:allow ->
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ defmodule Towerops.Workers.CheckExecutorWorker do
|
|||
:ok
|
||||
|
||||
check ->
|
||||
execute_or_skip(check)
|
||||
_ = execute_or_skip(check)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,11 +35,12 @@ defmodule Towerops.Workers.CloudLatencyProbeWorker do
|
|||
)
|
||||
|
||||
for poller <- cloud_pollers do
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{poller.id}:latency_probe",
|
||||
{:latency_probe_jobs, devices}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{poller.id}:latency_probe",
|
||||
{:latency_probe_jobs, devices}
|
||||
)
|
||||
end
|
||||
|
||||
:ok
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
device ->
|
||||
# Only reschedule if device still has monitoring enabled
|
||||
if should_continue_monitoring?(device) do
|
||||
maybe_perform_check(device)
|
||||
_ = maybe_perform_check(device)
|
||||
schedule_next_check_with_error_handling(device_id)
|
||||
else
|
||||
Logger.debug("Device #{device_id} monitoring disabled, not rescheduling",
|
||||
|
|
@ -213,7 +213,7 @@ defmodule Towerops.Workers.DeviceMonitorWorker do
|
|||
}) do
|
||||
{:ok, alert} ->
|
||||
# Enqueue notification job - Oban handles retries and persistence
|
||||
AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
_ = AlertNotificationWorker.enqueue_trigger(alert.id)
|
||||
|
||||
resolve_down_alert(device)
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
@impl Oban.Worker
|
||||
@spec perform(Oban.Job.t()) :: :ok
|
||||
def perform(%Oban.Job{args: %{"device_id" => device_id}} = job) do
|
||||
Events.broadcast_job_event(job, :started)
|
||||
_ = Events.broadcast_job_event(job, :started)
|
||||
start_time = System.monotonic_time(:second)
|
||||
|
||||
result =
|
||||
|
|
@ -71,7 +71,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
|
||||
duration = System.monotonic_time(:second) - start_time
|
||||
|
||||
Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
_ = Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -232,7 +232,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
)
|
||||
|
||||
nil ->
|
||||
Task.shutdown(task, :brutal_kill)
|
||||
_ = Task.shutdown(task, :brutal_kill)
|
||||
|
||||
Logger.warning("Polling task '#{name}' timed out for #{device.name}",
|
||||
device_id: device.id,
|
||||
|
|
@ -305,7 +305,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
end
|
||||
|
||||
defp poll_device_interfaces(device, snmp_device, client_opts, now) do
|
||||
poll_interfaces(snmp_device.interfaces, client_opts, now, snmp_device)
|
||||
_ = poll_interfaces(snmp_device.interfaces, client_opts, now, snmp_device)
|
||||
Logger.debug("Polled #{length(snmp_device.interfaces)} interfaces for #{device.name}")
|
||||
|
||||
_ =
|
||||
|
|
@ -600,7 +600,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
[]
|
||||
end)
|
||||
|
||||
Snmp.create_storage_readings_batch(reading_entries)
|
||||
_ = Snmp.create_storage_readings_batch(reading_entries)
|
||||
|
||||
# Process metadata updates individually
|
||||
Enum.each(poll_results, fn
|
||||
|
|
@ -660,7 +660,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
build_processor_reading_entry(processor, result, timestamp)
|
||||
end)
|
||||
|
||||
Snmp.create_processor_readings_batch(reading_entries)
|
||||
_ = Snmp.create_processor_readings_batch(reading_entries)
|
||||
|
||||
# Process metadata updates individually
|
||||
Enum.each(poll_results, fn {processor, result} ->
|
||||
|
|
@ -785,7 +785,7 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
[]
|
||||
end)
|
||||
|
||||
Snmp.create_mempool_readings_batch(reading_entries)
|
||||
_ = Snmp.create_mempool_readings_batch(reading_entries)
|
||||
|
||||
# Process metadata updates individually
|
||||
Enum.each(poll_results, fn
|
||||
|
|
@ -991,9 +991,10 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:#{device_id}", {:device_event, event})
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device:events", {:device_event, event})
|
||||
|
||||
if org_id do
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event})
|
||||
end
|
||||
_ =
|
||||
if org_id do
|
||||
_ = Phoenix.PubSub.broadcast(Towerops.PubSub, "device_events:org:#{org_id}", {:device_event, event})
|
||||
end
|
||||
|
||||
Logger.info("State sensor change: #{event.message}")
|
||||
end
|
||||
|
|
@ -1489,14 +1490,15 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
{:device_event, event_with_org}
|
||||
)
|
||||
|
||||
if org_id do
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device_events:org:#{org_id}",
|
||||
{:device_event, event_with_org}
|
||||
)
|
||||
end
|
||||
_ =
|
||||
if org_id do
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device_events:org:#{org_id}",
|
||||
{:device_event, event_with_org}
|
||||
)
|
||||
end
|
||||
|
||||
Logger.debug("Broadcast event: #{event_attrs.message}")
|
||||
end)
|
||||
|
|
@ -1727,13 +1729,14 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
end)
|
||||
|
||||
# Insert readings (even if some metrics are nil)
|
||||
case reading_entries do
|
||||
[] ->
|
||||
:ok
|
||||
_ =
|
||||
case reading_entries do
|
||||
[] ->
|
||||
:ok
|
||||
|
||||
entries ->
|
||||
Snmp.create_transceiver_readings_batch(entries)
|
||||
end
|
||||
entries ->
|
||||
Snmp.create_transceiver_readings_batch(entries)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -1826,13 +1829,14 @@ defmodule Towerops.Workers.DevicePollerWorker do
|
|||
end)
|
||||
|
||||
# Insert readings (even if some statuses are nil)
|
||||
case reading_entries do
|
||||
[] ->
|
||||
:ok
|
||||
_ =
|
||||
case reading_entries do
|
||||
[] ->
|
||||
:ok
|
||||
|
||||
entries ->
|
||||
Snmp.create_entity_physical_readings_batch(entries)
|
||||
end
|
||||
entries ->
|
||||
Snmp.create_entity_physical_readings_batch(entries)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ defmodule Towerops.Workers.DiscoveryWorker do
|
|||
@impl Oban.Worker
|
||||
@spec perform(Oban.Job.t()) :: :ok | :discard | {:error, term()}
|
||||
def perform(%Oban.Job{args: %{"device_id" => device_id}} = job) do
|
||||
Events.broadcast_job_event(job, :started)
|
||||
_ = Events.broadcast_job_event(job, :started)
|
||||
start_time = System.monotonic_time(:second)
|
||||
|
||||
try do
|
||||
|
|
@ -57,19 +57,20 @@ defmodule Towerops.Workers.DiscoveryWorker do
|
|||
|
||||
duration = System.monotonic_time(:second) - start_time
|
||||
|
||||
case result do
|
||||
:ok ->
|
||||
Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
_ =
|
||||
case result do
|
||||
:ok ->
|
||||
Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
|
||||
:discard ->
|
||||
Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
:discard ->
|
||||
Events.broadcast_job_event(job, :completed, %{duration: duration})
|
||||
|
||||
{:error, reason} ->
|
||||
Events.broadcast_job_event(job, :failed, %{
|
||||
error: inspect(reason),
|
||||
duration: duration
|
||||
})
|
||||
end
|
||||
{:error, reason} ->
|
||||
Events.broadcast_job_event(job, :failed, %{
|
||||
error: inspect(reason),
|
||||
duration: duration
|
||||
})
|
||||
end
|
||||
|
||||
result
|
||||
rescue
|
||||
|
|
@ -83,10 +84,11 @@ defmodule Towerops.Workers.DiscoveryWorker do
|
|||
error: error_string
|
||||
)
|
||||
|
||||
Events.broadcast_job_event(job, :failed, %{
|
||||
error: error_string,
|
||||
duration: duration
|
||||
})
|
||||
_ =
|
||||
Events.broadcast_job_event(job, :failed, %{
|
||||
error: error_string,
|
||||
duration: duration
|
||||
})
|
||||
|
||||
# Crashes are not retryable - they indicate a code bug, not a transient issue
|
||||
:discard
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ defmodule Towerops.Workers.EscalationCheckWorker do
|
|||
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{args: %{"incident_id" => incident_id}}) do
|
||||
Escalation.check_and_escalate(incident_id)
|
||||
_ = Escalation.check_and_escalate(incident_id)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ defmodule Towerops.Workers.GaiiaInsightWorker do
|
|||
maybe_dismiss_resolved_insights(organization_id, "ghost", result.ghost_devices)
|
||||
maybe_dismiss_resolved_insights(organization_id, "mismatch", result.data_mismatches)
|
||||
|
||||
generate_untracked_insights(organization_id, result.untracked_devices)
|
||||
generate_ghost_insights(organization_id, result.ghost_devices)
|
||||
_ = generate_untracked_insights(organization_id, result.untracked_devices)
|
||||
_ = generate_ghost_insights(organization_id, result.ghost_devices)
|
||||
generate_mismatch_insights(organization_id, result.data_mismatches)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -122,11 +122,12 @@ defmodule Towerops.Workers.MikrotikBackupWorker do
|
|||
case BackupRequests.create_request(device.id, job_id) do
|
||||
{:ok, _request} ->
|
||||
# Broadcast to agent via PubSub
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:backup",
|
||||
{:backup_requested, job}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:backup",
|
||||
{:backup_requested, job}
|
||||
)
|
||||
|
||||
Logger.info("Backup job sent to agent",
|
||||
device_id: device.id,
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ defmodule Towerops.Workers.WeatherSyncWorker do
|
|||
:ok
|
||||
else
|
||||
sync_all_sites()
|
||||
Weather.cleanup_old_observations(30)
|
||||
schedule_next()
|
||||
_ = Weather.cleanup_old_observations(30)
|
||||
_ = schedule_next()
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ defmodule Towerops.Workers.WelcomeEmailWorker do
|
|||
:ok
|
||||
|
||||
user ->
|
||||
UserNotifier.deliver_welcome_email(user)
|
||||
_ = UserNotifier.deliver_welcome_email(user)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -117,9 +117,10 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:lifecycle")
|
||||
|
||||
# Subscribe to latency probe requests (cloud pollers only)
|
||||
if agent_token.is_cloud_poller do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:latency_probe")
|
||||
end
|
||||
_ =
|
||||
if agent_token.is_cloud_poller do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agent:#{agent_token.id}:latency_probe")
|
||||
end
|
||||
|
||||
# Update last_seen_at and IP on join
|
||||
now = DateTime.utc_now()
|
||||
|
|
@ -160,14 +161,15 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
@impl true
|
||||
def terminate(_reason, socket) do
|
||||
# Broadcast agent disconnection for real-time UI updates
|
||||
if Map.has_key?(socket.assigns, :agent_token_id) do
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agents:health",
|
||||
{:agent_disconnected, socket.assigns.agent_token_id, socket.assigns.organization_id}
|
||||
)
|
||||
end
|
||||
_ =
|
||||
if Map.has_key?(socket.assigns, :agent_token_id) do
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agents:health",
|
||||
{:agent_disconnected, socket.assigns.agent_token_id, socket.assigns.organization_id}
|
||||
)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
@ -175,7 +177,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
@impl true
|
||||
@spec handle_info(:send_jobs, Phoenix.Socket.t()) :: {:noreply, Phoenix.Socket.t()}
|
||||
def handle_info(:send_jobs, socket) do
|
||||
cancel_poll_timer(socket)
|
||||
_ = cancel_poll_timer(socket)
|
||||
|
||||
updated_socket = build_and_push_jobs(socket)
|
||||
build_and_push_check_jobs(updated_socket)
|
||||
|
|
@ -281,7 +283,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
)
|
||||
|
||||
# Cancel any existing poll timer (regular cycle or pending debounce)
|
||||
cancel_poll_timer(socket)
|
||||
_ = cancel_poll_timer(socket)
|
||||
|
||||
# Schedule new refresh after debounce delay (configurable, defaults to 500ms in prod, 50ms in test)
|
||||
debounce_ms = Application.get_env(:towerops, :agent_channel_debounce_ms, 500)
|
||||
|
|
@ -403,11 +405,12 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
def handle_info({:live_poll_timeout, reply_topic}, socket) do
|
||||
Logger.warning("Live poll timed out", reply_topic: reply_topic)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
reply_topic,
|
||||
{:live_poll_error, :timeout}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
reply_topic,
|
||||
{:live_poll_error, :timeout}
|
||||
)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
|
@ -550,11 +553,12 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
|
||||
# Broadcast result to the requesting LiveView via PubSub
|
||||
# The test_id contains the device_id, so we can broadcast to that topic
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"credential_test:#{result.test_id}",
|
||||
{:credential_test_result, result}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"credential_test:#{result.test_id}",
|
||||
{:credential_test_result, result}
|
||||
)
|
||||
|
||||
{:noreply, socket}
|
||||
else
|
||||
|
|
@ -746,11 +750,12 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
)
|
||||
|
||||
# Check if this is a live poll result
|
||||
if String.starts_with?(result.job_id, "live_poll:") do
|
||||
handle_live_poll_result(result, socket)
|
||||
else
|
||||
process_and_log_snmp_result(socket, result)
|
||||
end
|
||||
_ =
|
||||
if String.starts_with?(result.job_id, "live_poll:") do
|
||||
handle_live_poll_result(result, socket)
|
||||
else
|
||||
process_and_log_snmp_result(socket, result)
|
||||
end
|
||||
|
||||
{:noreply, socket}
|
||||
else
|
||||
|
|
@ -1477,7 +1482,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
with {:ok, device} <- fetch_device(result.device_id),
|
||||
:ok <- verify_device_organization(device, organization_id),
|
||||
:ok <- verify_device_assignment(device, socket.assigns.agent_token_id) do
|
||||
process_job_result(device, result, socket)
|
||||
_ = process_job_result(device, result, socket)
|
||||
:ok
|
||||
else
|
||||
{:error, :device_not_found} = error ->
|
||||
|
|
@ -1598,7 +1603,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
old_state = check.current_state
|
||||
{:ok, updated_check} = Monitoring.update_check_state(check, result.status, result.output)
|
||||
handle_check_state_change(old_state, updated_check, result.output)
|
||||
broadcast_check_update(check.device_id)
|
||||
_ = broadcast_check_update(check.device_id)
|
||||
:ok
|
||||
|
||||
{:error, changeset} ->
|
||||
|
|
@ -1623,9 +1628,10 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
|
||||
defp handle_check_state_change(old_state, check, output) do
|
||||
# State changed from OK to problem and is now hard state
|
||||
if old_state == 0 and check.current_state in [1, 2] and check.current_state_type == "hard" do
|
||||
maybe_create_check_alert(check, output)
|
||||
end
|
||||
_ =
|
||||
if old_state == 0 and check.current_state in [1, 2] and check.current_state_type == "hard" do
|
||||
maybe_create_check_alert(check, output)
|
||||
end
|
||||
|
||||
# State changed from problem to OK
|
||||
if old_state in [1, 2] and check.current_state == 0 do
|
||||
|
|
@ -1680,15 +1686,17 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
|
||||
Devices.update_device_status(device, new_status)
|
||||
|
||||
if old_status != new_status do
|
||||
handle_agent_status_change(device, old_status, new_status)
|
||||
end
|
||||
_ =
|
||||
if old_status != new_status do
|
||||
handle_agent_status_change(device, old_status, new_status)
|
||||
end
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
|
||||
Subscriptions.publish_device_status(
|
||||
device.id,
|
||||
|
|
@ -1706,12 +1714,13 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
do: "Device is not responding to SNMP",
|
||||
else: "Device is not responding to ping"
|
||||
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_down,
|
||||
triggered_at: now,
|
||||
message: message
|
||||
})
|
||||
_ =
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_down,
|
||||
triggered_at: now,
|
||||
message: message
|
||||
})
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
|
|
@ -1729,13 +1738,14 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
do: "Device is now responding to SNMP",
|
||||
else: "Device is now responding to ping"
|
||||
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_up,
|
||||
triggered_at: now,
|
||||
resolved_at: now,
|
||||
message: message
|
||||
})
|
||||
_ =
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_up,
|
||||
triggered_at: now,
|
||||
resolved_at: now,
|
||||
message: message
|
||||
})
|
||||
|
||||
case Alerts.get_active_alert(device.id, :device_down) do
|
||||
nil -> :ok
|
||||
|
|
@ -1755,40 +1765,42 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
now = Towerops.Time.now()
|
||||
|
||||
# Resolve stuck device_down alerts
|
||||
case Alerts.get_active_alert(device.id, :device_down) do
|
||||
nil ->
|
||||
:ok
|
||||
_ =
|
||||
case Alerts.get_active_alert(device.id, :device_down) do
|
||||
nil ->
|
||||
:ok
|
||||
|
||||
alert ->
|
||||
Logger.info(
|
||||
"Resolving stuck device_down alert for #{device.name} - device is UP but alert was not resolved",
|
||||
device_id: device.id,
|
||||
alert_id: alert.id
|
||||
)
|
||||
alert ->
|
||||
Logger.info(
|
||||
"Resolving stuck device_down alert for #{device.name} - device is UP but alert was not resolved",
|
||||
device_id: device.id,
|
||||
alert_id: alert.id
|
||||
)
|
||||
|
||||
# Create device_up alert (informational)
|
||||
message =
|
||||
if device.snmp_enabled,
|
||||
do: "Device is now responding to SNMP",
|
||||
else: "Device is now responding to ping"
|
||||
# Create device_up alert (informational)
|
||||
message =
|
||||
if device.snmp_enabled,
|
||||
do: "Device is now responding to SNMP",
|
||||
else: "Device is now responding to ping"
|
||||
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_up,
|
||||
triggered_at: now,
|
||||
resolved_at: now,
|
||||
message: message
|
||||
})
|
||||
_ =
|
||||
Alerts.create_alert(%{
|
||||
device_id: device.id,
|
||||
alert_type: :device_up,
|
||||
triggered_at: now,
|
||||
resolved_at: now,
|
||||
message: message
|
||||
})
|
||||
|
||||
# Resolve the stuck alert
|
||||
Alerts.resolve_alert(alert)
|
||||
# Resolve the stuck alert
|
||||
Alerts.resolve_alert(alert)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:org:#{device.organization_id}:resolved",
|
||||
{:alert_resolved, device.id, :device_down}
|
||||
)
|
||||
end
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"alerts:org:#{device.organization_id}:resolved",
|
||||
{:alert_resolved, device.id, :device_down}
|
||||
)
|
||||
end
|
||||
|
||||
# Also resolve any stuck device_up alerts (should have been created with resolved_at)
|
||||
case Alerts.get_active_alert(device.id, :device_up) do
|
||||
|
|
@ -1937,11 +1949,12 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
if old_status != new_status do
|
||||
Devices.update_device_status(device, new_status)
|
||||
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"device:#{device.id}",
|
||||
{:device_status_changed, device.id, new_status, nil}
|
||||
)
|
||||
|
||||
Subscriptions.publish_device_status(
|
||||
device.id,
|
||||
|
|
@ -1970,13 +1983,14 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
publish_sensor_readings_to_graphql(device, snmp_device.sensors, oid_values, timestamp)
|
||||
|
||||
# Batch insert interface stats
|
||||
process_interface_stats_batch(snmp_device.interfaces, oid_values, timestamp)
|
||||
_ = process_interface_stats_batch(snmp_device.interfaces, oid_values, timestamp)
|
||||
|
||||
# Process complex SNMP data (neighbors, ARP, MAC, IP addresses, processors, storage)
|
||||
# using Replay adapter to reuse existing parsing logic
|
||||
if map_size(oid_values) > length(snmp_device.sensors) + length(snmp_device.interfaces) * 6 do
|
||||
process_additional_polling_data(device, oid_values)
|
||||
end
|
||||
_ =
|
||||
if map_size(oid_values) > length(snmp_device.sensors) + length(snmp_device.interfaces) * 6 do
|
||||
process_additional_polling_data(device, oid_values)
|
||||
end
|
||||
|
||||
# Notify LiveViews that new sensor/interface data is available for graphing
|
||||
Phoenix.PubSub.broadcast(
|
||||
|
|
@ -2021,7 +2035,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
process_arp_entries(client_opts, device_id, interfaces)
|
||||
|
||||
# Process MAC addresses
|
||||
process_mac_addresses(client_opts, device_id, interfaces)
|
||||
_ = process_mac_addresses(client_opts, device_id, interfaces)
|
||||
|
||||
# Process IP addresses
|
||||
process_ip_addresses(client_opts, device_id, interfaces)
|
||||
|
|
@ -2142,7 +2156,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
end)
|
||||
|
||||
# Batch insert all sensor readings in one SQL statement
|
||||
Snmp.create_sensor_readings_batch(reading_entries)
|
||||
_ = Snmp.create_sensor_readings_batch(reading_entries)
|
||||
|
||||
# Process change detection and metadata updates individually
|
||||
Enum.each(sensor_updates, fn {sensor, final_value} ->
|
||||
|
|
@ -2279,7 +2293,7 @@ defmodule ToweropsWeb.AgentChannel do
|
|||
{:error, :backup_request_not_found}
|
||||
|
||||
request ->
|
||||
handle_backup_request(request, result)
|
||||
_ = handle_backup_request(request, result)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ defmodule ToweropsWeb.MobileChannel do
|
|||
user_id = socket.assigns.user_id
|
||||
|
||||
if Organizations.user_has_access?(user_id, org_id) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{org_id}:alerts")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{org_id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{org_id}:alerts")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{org_id}")
|
||||
|
||||
{:ok, socket}
|
||||
else
|
||||
|
|
@ -35,7 +35,7 @@ defmodule ToweropsWeb.MobileChannel do
|
|||
|
||||
device ->
|
||||
if Organizations.user_has_access?(user_id, device.organization_id) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "device:#{device_id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "device:#{device_id}")
|
||||
{:ok, socket}
|
||||
else
|
||||
{:error, %{reason: "unauthorized"}}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ defmodule ToweropsWeb.MobileSocket do
|
|||
|
||||
session ->
|
||||
session = Towerops.Repo.preload(session, :user)
|
||||
Task.start(fn -> MobileSessions.touch_session(session) end)
|
||||
_ = Task.start(fn -> MobileSessions.touch_session(session) end)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -17,12 +17,13 @@ defmodule ToweropsWeb.Api.AccountDataController do
|
|||
user = conn.assigns.current_scope.user
|
||||
|
||||
# Verify user account is confirmed before allowing data export
|
||||
if !user.confirmed_at do
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: "Email address must be confirmed before exporting account data"})
|
||||
|> halt()
|
||||
end
|
||||
_ =
|
||||
if !user.confirmed_at do
|
||||
conn
|
||||
|> put_status(:forbidden)
|
||||
|> json(%{error: "Email address must be confirmed before exporting account data"})
|
||||
|> halt()
|
||||
end
|
||||
|
||||
# Log the data export for audit trail
|
||||
AuditLogger.log_user_data_exported(conn, user.id)
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ defmodule ToweropsWeb.Api.V1.ChecksController do
|
|||
defp create_and_respond(conn, attrs) do
|
||||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
if check.enabled, do: Monitoring.schedule_check(check)
|
||||
_ = if check.enabled, do: Monitoring.schedule_check(check)
|
||||
|
||||
conn
|
||||
|> put_status(:created)
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ defmodule ToweropsWeb.Api.V1.DevicesController do
|
|||
|
||||
case Devices.create_device(device_params, opts) do
|
||||
{:ok, device} ->
|
||||
maybe_enqueue_discovery(device)
|
||||
_ = maybe_enqueue_discovery(device)
|
||||
|
||||
conn
|
||||
|> put_status(:created)
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ defmodule ToweropsWeb.Api.V1.MibController do
|
|||
:ok ->
|
||||
# Safe to copy to vendor directory - vendor_dir constructed from validated vendor name
|
||||
# and all paths in temp_dir have been validated by validate_extracted_paths/1
|
||||
File.cp_r!(temp_dir, vendor_dir)
|
||||
_ = File.cp_r!(temp_dir, vendor_dir)
|
||||
files_count = count_files(vendor_dir)
|
||||
Logger.info("Extracted #{files_count} MIB files for vendor: #{vendor}")
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ defmodule ToweropsWeb.Api.V1.MibController do
|
|||
:ok ->
|
||||
# Safe to copy to vendor directory - vendor_dir constructed from validated vendor name
|
||||
# and all paths in temp_dir have been validated by validate_extracted_paths/1
|
||||
File.cp_r!(temp_dir, vendor_dir)
|
||||
_ = File.cp_r!(temp_dir, vendor_dir)
|
||||
files_count = count_files(vendor_dir)
|
||||
Logger.info("Extracted #{files_count} MIB files for vendor: #{vendor}")
|
||||
|
||||
|
|
|
|||
|
|
@ -8,14 +8,15 @@ defmodule ToweropsWeb.UserConfirmationController do
|
|||
end
|
||||
|
||||
def create(conn, %{"user" => %{"email" => email}}) do
|
||||
if user = Accounts.get_user_by_email(email) do
|
||||
if is_nil(user.confirmed_at) do
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
_ =
|
||||
if user = Accounts.get_user_by_email(email) do
|
||||
if is_nil(user.confirmed_at) do
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Always show success to prevent email enumeration
|
||||
conn
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ defmodule ToweropsWeb.UserRegistrationController do
|
|||
defp create_with_organization(conn, user_params) do
|
||||
case Accounts.register_user_with_organization(user_params) do
|
||||
{:ok, user} ->
|
||||
WelcomeEmailWorker.enqueue(user.id)
|
||||
_ = WelcomeEmailWorker.enqueue(user.id)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, t("Account created successfully."))
|
||||
|
|
@ -57,7 +57,7 @@ defmodule ToweropsWeb.UserRegistrationController do
|
|||
with {:ok, invitation} <- get_valid_invitation(invitation_token),
|
||||
{:ok, user} <- Accounts.register_user(user_params),
|
||||
{:ok, _membership} <- Organizations.accept_invitation(invitation, user.id) do
|
||||
WelcomeEmailWorker.enqueue(user.id)
|
||||
_ = WelcomeEmailWorker.enqueue(user.id)
|
||||
|
||||
conn
|
||||
|> put_flash(:info, t("Account created successfully. Welcome to %{org}!", org: invitation.organization.name))
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ defmodule ToweropsWeb.GraphQL.Resolvers.Check do
|
|||
defp create_and_schedule_check(attrs) do
|
||||
case Monitoring.create_check(attrs) do
|
||||
{:ok, check} ->
|
||||
if check.enabled, do: Monitoring.schedule_check(check)
|
||||
_ = if check.enabled, do: Monitoring.schedule_check(check)
|
||||
{:ok, check}
|
||||
|
||||
{:error, changeset} ->
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ defmodule ToweropsWeb.ActivityFeedLive do
|
|||
timer_ref =
|
||||
if connected?(socket) do
|
||||
# Subscribe to all relevant PubSub topics for real-time updates
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "config:org:#{organization.id}")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "sync:org:#{organization.id}")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "device_events:org:#{organization.id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "config:org:#{organization.id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "sync:org:#{organization.id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "device_events:org:#{organization.id}")
|
||||
|
||||
# Timer for relative timestamp refresh
|
||||
{:ok, ref} = :timer.send_interval(@tick_interval_ms, self(), :tick)
|
||||
|
|
@ -143,9 +143,10 @@ defmodule ToweropsWeb.ActivityFeedLive do
|
|||
|
||||
@impl true
|
||||
def terminate(_reason, socket) do
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
:timer.cancel(timer_ref)
|
||||
end
|
||||
_ =
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
:timer.cancel(timer_ref)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ defmodule ToweropsWeb.Admin.AgentLive.Index do
|
|||
def mount(_params, _session, socket) do
|
||||
timer_ref =
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "admin:agents")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "agents:health")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "admin:agents")
|
||||
{:ok, ref} = :timer.send_interval(1000, :tick)
|
||||
ref
|
||||
end
|
||||
|
|
@ -110,9 +110,10 @@ defmodule ToweropsWeb.Admin.AgentLive.Index do
|
|||
|
||||
@impl true
|
||||
def terminate(_reason, socket) do
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
:timer.cancel(timer_ref)
|
||||
end
|
||||
_ =
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
:timer.cancel(timer_ref)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ defmodule ToweropsWeb.Admin.MonitoringLive do
|
|||
|
||||
@impl Phoenix.LiveView
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, @topic)
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, @topic)
|
||||
end
|
||||
|
||||
socket =
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ defmodule ToweropsWeb.Admin.SecurityLive.Index do
|
|||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "security:whitelist")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "security:blocks")
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "security:whitelist")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "security:blocks")
|
||||
end
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -491,9 +491,10 @@ defmodule ToweropsWeb.AgentLive.Index do
|
|||
|
||||
@impl true
|
||||
def terminate(_reason, socket) do
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
:timer.cancel(timer_ref)
|
||||
end
|
||||
_ =
|
||||
if timer_ref = socket.assigns[:timer_ref] do
|
||||
_ = :timer.cancel(timer_ref)
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ defmodule ToweropsWeb.AgentLive.Show do
|
|||
|
||||
def handle_event("restart_agent", _params, socket) do
|
||||
if socket.assigns.current_scope.user.is_superuser do
|
||||
Agents.restart_agent(socket.assigns.agent_token.id)
|
||||
_ = Agents.restart_agent(socket.assigns.agent_token.id)
|
||||
|
||||
{:noreply, put_flash(socket, :info, t("Restart command sent to agent"))}
|
||||
else
|
||||
|
|
@ -72,7 +72,7 @@ defmodule ToweropsWeb.AgentLive.Show do
|
|||
defp send_update_command(socket, agent_token, arch) do
|
||||
with {:ok, release} <- ReleaseChecker.get_latest_release(),
|
||||
{:ok, asset} <- ReleaseChecker.asset_for_arch(release.assets, arch) do
|
||||
Agents.update_agent(agent_token.id, asset.url, asset.checksum)
|
||||
_ = Agents.update_agent(agent_token.id, asset.url, asset.checksum)
|
||||
put_flash(socket, :info, t("Update command sent to agent (v%{version})", version: release.version))
|
||||
else
|
||||
{:error, :no_matching_asset} ->
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ defmodule ToweropsWeb.CheckLive.FormComponent do
|
|||
|
||||
case Monitoring.create_check(check_params) do
|
||||
{:ok, check} ->
|
||||
Monitoring.schedule_check(check)
|
||||
_ = Monitoring.schedule_check(check)
|
||||
notify_parent({:check_created, check})
|
||||
{:noreply, socket}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,10 +15,11 @@ defmodule ToweropsWeb.DashboardLive do
|
|||
def mount(_params, _session, socket) do
|
||||
organization = socket.assigns.current_scope.organization
|
||||
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:new")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "alerts:org:#{organization.id}:resolved")
|
||||
end
|
||||
|
||||
status_counts = Devices.get_device_status_counts(organization.id)
|
||||
device_count = status_counts |> Map.values() |> Enum.sum()
|
||||
|
|
@ -99,9 +100,10 @@ defmodule ToweropsWeb.DashboardLive do
|
|||
@dashboard_debounce_ms 1_500
|
||||
|
||||
defp schedule_debounced_dashboard_reload(socket) do
|
||||
if ref = socket.assigns.pending_dashboard_reload_ref do
|
||||
Process.cancel_timer(ref)
|
||||
end
|
||||
_ =
|
||||
if ref = socket.assigns.pending_dashboard_reload_ref do
|
||||
_ = Process.cancel_timer(ref)
|
||||
end
|
||||
|
||||
ref = Process.send_after(self(), :debounced_dashboard_reload, @dashboard_debounce_ms)
|
||||
assign(socket, :pending_dashboard_reload_ref, ref)
|
||||
|
|
|
|||
|
|
@ -436,7 +436,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
|
||||
case send_credential_test_to_agent(effective_agent_id, device_map, test_id) do
|
||||
:ok ->
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "credential_test:#{test_id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "credential_test:#{test_id}")
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -472,7 +472,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
AuditLogger.log_device_created(nil, user.id, device.id, device.name)
|
||||
|
||||
# Handle agent assignment after device creation
|
||||
handle_agent_assignment(device.id, agent_token_id)
|
||||
_ = handle_agent_assignment(device.id, agent_token_id)
|
||||
|
||||
flash_message = handle_device_creation(device)
|
||||
|
||||
|
|
@ -531,7 +531,7 @@ defmodule ToweropsWeb.DeviceLive.Form do
|
|||
AuditLogger.log_device_updated(nil, user.id, device.id, fields_changed)
|
||||
|
||||
# device update
|
||||
handle_agent_assignment(device.id, agent_token_id)
|
||||
_ = handle_agent_assignment(device.id, agent_token_id)
|
||||
|
||||
flash_message = handle_device_update(old_device, device)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ defmodule ToweropsWeb.DeviceLive.Index do
|
|||
devices = Devices.list_organization_devices(organization.id)
|
||||
sites = Sites.list_organization_sites(organization.id)
|
||||
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
|
||||
schedule_tick()
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "devices:org:#{organization.id}")
|
||||
_ = schedule_tick()
|
||||
end
|
||||
|
||||
# Load device quota
|
||||
{current, limit} = SubscriptionLimits.device_quota(organization)
|
||||
|
|
@ -256,7 +257,7 @@ defmodule ToweropsWeb.DeviceLive.Index do
|
|||
# Periodic tick to refresh "time ago" timestamps between poll events
|
||||
@impl true
|
||||
def handle_info(:tick, socket) do
|
||||
schedule_tick()
|
||||
_ = schedule_tick()
|
||||
|
||||
if socket.assigns.active_tab == "existing" do
|
||||
{:noreply, schedule_debounced_reload(socket, :tick)}
|
||||
|
|
@ -310,9 +311,10 @@ defmodule ToweropsWeb.DeviceLive.Index do
|
|||
|
||||
defp schedule_debounced_reload(socket, event) do
|
||||
# Cancel any pending debounced reload
|
||||
if ref = socket.assigns.pending_reload_ref do
|
||||
Process.cancel_timer(ref)
|
||||
end
|
||||
_ =
|
||||
if ref = socket.assigns.pending_reload_ref do
|
||||
_ = Process.cancel_timer(ref)
|
||||
end
|
||||
|
||||
# For status changes, skip reload entirely if viewing the discovered tab
|
||||
if event == :device_status_changed && socket.assigns.active_tab == "discovered" do
|
||||
|
|
|
|||
|
|
@ -988,11 +988,12 @@ defmodule ToweropsWeb.DeviceLive.Show do
|
|||
|
||||
case BackupRequests.create_request(device.id, job_id, "manual") do
|
||||
{:ok, _request} ->
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:backup",
|
||||
{:backup_requested, job}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:backup",
|
||||
{:backup_requested, job}
|
||||
)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -995,7 +995,7 @@ defmodule ToweropsWeb.GraphLive.Show do
|
|||
socket
|
||||
|
||||
timer_ref ->
|
||||
Process.cancel_timer(timer_ref)
|
||||
_ = Process.cancel_timer(timer_ref)
|
||||
assign(socket, :live_poll_timer, nil)
|
||||
end
|
||||
end
|
||||
|
|
@ -1122,11 +1122,12 @@ defmodule ToweropsWeb.GraphLive.Show do
|
|||
sensor_oids = Enum.map(sensors, & &1.sensor_oid)
|
||||
|
||||
# Broadcast live poll request with reply topic and sensor OIDs
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:live_poll",
|
||||
{:live_poll_requested, device_id, sensor_oids, reply_topic}
|
||||
)
|
||||
_ =
|
||||
Phoenix.PubSub.broadcast(
|
||||
Towerops.PubSub,
|
||||
"agent:#{agent_token_id}:live_poll",
|
||||
{:live_poll_requested, device_id, sensor_oids, reply_topic}
|
||||
)
|
||||
|
||||
# Wait for response with timeout
|
||||
receive do
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ defmodule ToweropsWeb.MobileQRLive do
|
|||
defp cancel_timer(nil), do: :ok
|
||||
|
||||
defp cancel_timer(timer_ref) when is_reference(timer_ref) do
|
||||
Process.cancel_timer(timer_ref)
|
||||
_ = Process.cancel_timer(timer_ref)
|
||||
:ok
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ defmodule ToweropsWeb.Org.SettingsLive do
|
|||
{:ok, invitation} ->
|
||||
invitation = Map.put(invitation, :organization, organization)
|
||||
accept_url = url(~p"/invitations/#{invitation.token}")
|
||||
UserNotifier.deliver_invitation_email(invitation, accept_url)
|
||||
_ = UserNotifier.deliver_invitation_email(invitation, accept_url)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@ defmodule ToweropsWeb.RfLinkHealthLive do
|
|||
def mount(_params, _session, socket) do
|
||||
organization = socket.assigns.current_scope.organization
|
||||
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "wireless_clients:org:#{organization.id}")
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "wireless_clients:org:#{organization.id}")
|
||||
end
|
||||
|
||||
summary = RfLinks.get_summary(organization.id)
|
||||
links = RfLinks.list_rf_links(organization.id)
|
||||
|
|
|
|||
|
|
@ -20,9 +20,10 @@ defmodule ToweropsWeb.StatusPageLive do
|
|||
|> assign(:page_title, "Not Found")}
|
||||
|
||||
config ->
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "status_page:#{config.id}")
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "status_page:#{config.id}")
|
||||
end
|
||||
|
||||
components = StatusPages.list_components(config.id)
|
||||
active_incidents = StatusPages.list_active_incidents(config.id)
|
||||
|
|
|
|||
|
|
@ -94,12 +94,13 @@ defmodule ToweropsWeb.UserRegistrationLive do
|
|||
|
||||
case Accounts.register_user_with_organization(user_params_with_timezone) do
|
||||
{:ok, user} ->
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
_ =
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
|
||||
WelcomeEmailWorker.enqueue(user.id)
|
||||
_ = WelcomeEmailWorker.enqueue(user.id)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
@ -119,12 +120,13 @@ defmodule ToweropsWeb.UserRegistrationLive do
|
|||
with {:ok, invitation} <- get_valid_invitation(invitation_token),
|
||||
{:ok, user} <- Accounts.register_user(user_params_with_timezone),
|
||||
{:ok, _membership} <- Organizations.accept_invitation(invitation, user.id) do
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
_ =
|
||||
Accounts.deliver_user_confirmation_instructions(
|
||||
user,
|
||||
&url(~p"/users/confirm/#{&1}")
|
||||
)
|
||||
|
||||
WelcomeEmailWorker.enqueue(user.id)
|
||||
_ = WelcomeEmailWorker.enqueue(user.id)
|
||||
|
||||
{:noreply,
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ defmodule ToweropsWeb.UserSettingsLive do
|
|||
case Accounts.delete_account(user, password) do
|
||||
{:ok, _} ->
|
||||
# Send farewell email after deletion
|
||||
UserNotifier.deliver_account_deleted_notification(user.email, user.first_name)
|
||||
_ = UserNotifier.deliver_account_deleted_notification(user.email, user.first_name)
|
||||
|
||||
socket =
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -77,10 +77,11 @@ defmodule ToweropsWeb.UserSettingsLive.TotpManager do
|
|||
"""
|
||||
def close_device_qr_modal(socket) do
|
||||
# Delete the unverified device if user cancels
|
||||
if device_id = socket.assigns.new_device_id do
|
||||
user = socket.assigns.current_scope.user
|
||||
Accounts.delete_totp_device(device_id, user.id)
|
||||
end
|
||||
_ =
|
||||
if device_id = socket.assigns.new_device_id do
|
||||
user = socket.assigns.current_scope.user
|
||||
Accounts.delete_totp_device(device_id, user.id)
|
||||
end
|
||||
|
||||
socket
|
||||
|> Phoenix.Component.assign(:show_device_qr_modal, false)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ defmodule ToweropsWeb.WeathermapLive do
|
|||
# Subscribe to topology changes and capacity updates if connected
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "topology:#{organization.id}")
|
||||
_ = Phoenix.PubSub.subscribe(Towerops.PubSub, "topology:#{organization.id}")
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "capacity:#{organization.id}")
|
||||
end
|
||||
|
||||
|
|
@ -34,9 +34,10 @@ defmodule ToweropsWeb.WeathermapLive do
|
|||
}
|
||||
|
||||
# Schedule auto-refresh every 60 seconds
|
||||
if connected?(socket) do
|
||||
Process.send_after(self(), :refresh_data, 60_000)
|
||||
end
|
||||
_ =
|
||||
if connected?(socket) do
|
||||
_ = Process.send_after(self(), :refresh_data, 60_000)
|
||||
end
|
||||
|
||||
{:ok,
|
||||
socket
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ defmodule ToweropsWeb.Plugs.UpdateSessionActivity do
|
|||
|
||||
token ->
|
||||
live_socket_id = get_session(conn, :live_socket_id)
|
||||
Task.start(fn -> handle_session_activity(token, live_socket_id) end)
|
||||
_ = Task.start(fn -> handle_session_activity(token, live_socket_id) end)
|
||||
conn
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -343,10 +343,11 @@ defmodule ToweropsWeb.UserAuth do
|
|||
Plug for routes that require the user to be authenticated.
|
||||
"""
|
||||
def set_user_locale(conn, _opts) do
|
||||
if conn.assigns[:current_scope] && conn.assigns.current_scope.user do
|
||||
locale = conn.assigns.current_scope.user.language || "en"
|
||||
Gettext.put_locale(ToweropsWeb.Gettext, locale)
|
||||
end
|
||||
_ =
|
||||
if conn.assigns[:current_scope] && conn.assigns.current_scope.user do
|
||||
locale = conn.assigns.current_scope.user.language || "en"
|
||||
Gettext.put_locale(ToweropsWeb.Gettext, locale)
|
||||
end
|
||||
|
||||
conn
|
||||
end
|
||||
|
|
@ -499,7 +500,7 @@ defmodule ToweropsWeb.UserAuth do
|
|||
|
||||
if socket.assigns.current_scope && socket.assigns.current_scope.user do
|
||||
locale = socket.assigns.current_scope.user.language || "en"
|
||||
Gettext.put_locale(ToweropsWeb.Gettext, locale)
|
||||
_ = Gettext.put_locale(ToweropsWeb.Gettext, locale)
|
||||
{:cont, socket}
|
||||
else
|
||||
socket =
|
||||
|
|
@ -1000,9 +1001,10 @@ defmodule ToweropsWeb.UserAuth do
|
|||
defp determine_login_method(_conn, _params), do: "password"
|
||||
|
||||
defp maybe_subscribe_to_status_updates(socket, organization) do
|
||||
if organization && LiveView.connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{organization.id}:alerts")
|
||||
end
|
||||
_ =
|
||||
if organization && LiveView.connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(Towerops.PubSub, "organization:#{organization.id}:alerts")
|
||||
end
|
||||
|
||||
socket
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue