feat(dashboard_api): GET /webhook/inc-search route (ticket explorer)
Some checks failed
Static Analysis / static (push) Waiting to run
Tests / test (push) Waiting to run
Static Analysis / static (pull_request) Has been cancelled
Tests / test (pull_request) Has been cancelled

Thin passthrough over reporting.fn_inc_search (fleettickets migration 13):
ad-hoc ticket lookup by ticket_id / owner / cluster / status / state / time for
the FleetOps ticket explorer. Mirrors /webhook/inc-dashboard (read-only conn,
jsonb passthrough); validates state in {open,closed,all} and ISO-8601 from/to.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
david kiania 2026-06-19 11:48:42 +03:00
parent 1d4bd6000e
commit e27933b1cb

View file

@ -368,6 +368,63 @@ def inc_dashboard(
)
# ── INC ticket explorer (search) ──────────────────────────────────────────────
# Thin passthrough over reporting.fn_inc_search (fleettickets migration 13): ad-hoc
# ticket lookup by id / engineer / cluster / status / state / time, for historical +
# current tracking. Returns { count, truncated, limit, state, rows }.
_INC_STATES = {"open", "closed", "all"}
@app.get("/webhook/inc-search")
def inc_search(
ticket_id: str | None = None, # substring match on ticket_id
owner: str | None = None, # engineer — case-insensitive substring on owner
cluster: str | None = None, # exact tickets.inc.cluster
status: str | None = None, # exact normalized_status
state: str = "closed", # closed | open | all
from_: str | None = Query(None, alias="from"), # closed-at range start (ISO-8601)
to: str | None = None, # closed-at range end (exclusive, ISO-8601)
):
state = (state or "closed").lower()
if state not in _INC_STATES:
return _bad_request("state must be one of open|closed|all")
f, t = _clean(from_), _clean(to)
def _parse(v):
if not v:
return None
try:
return datetime.fromisoformat(v)
except ValueError:
return False
pf, pt = _parse(f), _parse(t)
if pf is False or pt is False:
return _bad_request("from/to must be ISO-8601 timestamps with an offset/Z")
if pf and pt and pf >= pt:
return _bad_request("from must be earlier than to")
try:
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute(
"SELECT reporting.fn_inc_search(%s, %s, %s, %s, %s, %s, %s)",
(_clean(ticket_id), _clean(owner), _clean(cluster), _clean(status), state, f, t),
)
payload = cur.fetchone()[0] or {}
return JSONResponse(payload) # jsonb body returned unchanged
except Exception:
log.exception("inc-search failed")
return JSONResponse(
{
"error": {
"type": "unknown",
"message": "Ticket search is unavailable. Try again in a few seconds.",
}
}
)
# ── Fleet trips (#002) ───────────────────────────────────────────────────────
_FILTER_OPTIONS_SQL = """