defmodule ToweropsWeb.Api.V1.AlertsController do @moduledoc "API controller for alerts." use ToweropsWeb, :controller alias Towerops.Alerts def index(conn, params) do organization_id = conn.assigns.current_organization_id filters = params |> Map.take(~w(status limit)) |> then(fn f -> case params["device_id"] do nil -> f device_id -> Map.put(f, "device_id", device_id) end end) alerts = organization_id |> Alerts.list_organization_alerts(filters) |> Enum.map(&format_alert/1) json(conn, %{data: alerts}) end def show(conn, %{"id" => id}) do organization_id = conn.assigns.current_organization_id alert = Alerts.get_alert!(id) device = alert.device if device && device.organization_id == organization_id do json(conn, %{data: format_alert(alert)}) else conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end rescue Ecto.NoResultsError -> conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end def acknowledge(conn, %{"id" => id}) do organization_id = conn.assigns.current_organization_id user = conn.assigns[:current_user] alert = Alerts.get_alert!(id) device = alert.device if device && device.organization_id == organization_id do user_id = if user, do: user.id, else: nil case Alerts.acknowledge_alert(alert, user_id) do {:ok, updated} -> json(conn, %{data: format_alert(Towerops.Repo.preload(updated, [:device, :acknowledged_by], force: true))}) {:error, _changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "Could not acknowledge alert"}) end else conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end rescue Ecto.NoResultsError -> conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end def resolve(conn, %{"id" => id}) do organization_id = conn.assigns.current_organization_id alert = Alerts.get_alert!(id) device = alert.device if device && device.organization_id == organization_id do case Alerts.resolve_alert(alert) do {:ok, updated} -> json(conn, %{data: format_alert(Towerops.Repo.preload(updated, [:device, :acknowledged_by], force: true))}) {:error, _changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{error: "Could not resolve alert"}) end else conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end rescue Ecto.NoResultsError -> conn |> put_status(:not_found) |> json(%{error: "Alert not found"}) end defp format_alert(alert) do %{ id: alert.id, alert_type: alert.alert_type, message: alert.message, triggered_at: alert.triggered_at, acknowledged_at: alert.acknowledged_at, resolved_at: alert.resolved_at, device_id: alert.device_id, device_name: get_in_loaded(alert, :device, :name), acknowledged_by_email: get_in_loaded(alert, :acknowledged_by, :email), gaiia_impact: alert.gaiia_impact, inserted_at: alert.inserted_at } end defp get_in_loaded(struct, assoc, field) do case Map.get(struct, assoc) do %Ecto.Association.NotLoaded{} -> nil nil -> nil loaded -> Map.get(loaded, field) end end end