defmodule ToweropsWeb.AdminController do @moduledoc """ Controller for admin operations including user impersonation. """ use ToweropsWeb, :controller alias ToweropsWeb.UserAuth @doc """ Start impersonating a user. """ def start_impersonate(conn, %{"user_id" => user_id}) do UserAuth.start_impersonation(conn, user_id) end @doc """ Stop impersonating and return to superuser. """ def stop_impersonate(conn, _params) do UserAuth.stop_impersonation(conn) end @doc """ Emergency-only flush of Oban jobs by state. Directly deletes jobs in the given state(s). This bypasses Oban's cancellation hooks and telemetry — only use when a queue is poisoned and normal draining fails. All flushes are audit logged. POST /admin/oban/flush?states=scheduled,retryable """ def flush_oban(conn, %{"states" => states_param}) do import Ecto.Query require Logger valid_states = ~w(scheduled retryable available) requested = states_param |> String.split(",") |> Enum.map(&String.trim/1) states = Enum.filter(requested, &(&1 in valid_states)) if states == [] do conn |> put_status(400) |> json(%{error: "No valid states. Use: scheduled, retryable, available"}) else {count, _} = Oban.Job |> where([j], j.state in ^states) |> Towerops.Repo.delete_all() user = conn.assigns.current_scope.user Logger.warning("OBAN_FLUSH: user=#{user.email} (#{user.id}) deleted #{count} jobs in states #{inspect(states)}") json(conn, %{ok: true, deleted: count, states: states}) end end end