| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- from typing import Any
- import httpx
- class IrisAdapter:
- def __init__(self, base_url: str, api_key: str) -> None:
- self.base_url = base_url.rstrip("/")
- self.api_key = api_key
- def _headers(self) -> dict[str, str]:
- return {"Authorization": f"Bearer {self.api_key}"} if self.api_key else {}
- async def create_case(self, payload: dict[str, Any]) -> dict[str, Any]:
- headers = self._headers()
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- v2_url = f"{self.base_url}/api/v2/cases"
- response = await client.post(v2_url, json=payload, headers=headers)
- if response.status_code == 404:
- legacy_url = f"{self.base_url}/manage/cases/add"
- response = await client.post(legacy_url, json=payload, headers=headers)
- active_url = legacy_url
- else:
- active_url = v2_url
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {"status_code": response.status_code}
- async def update_case(self, case_id: str, payload: dict[str, Any]) -> dict[str, Any]:
- headers = self._headers()
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- v2_url = f"{self.base_url}/api/v2/cases/{case_id}"
- response = await client.put(v2_url, json=payload, headers=headers)
- if response.status_code == 404:
- legacy_url = f"{self.base_url}/manage/cases/update/{case_id}"
- response = await client.post(legacy_url, json=payload, headers=headers)
- active_url = legacy_url
- else:
- active_url = v2_url
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {"status_code": response.status_code}
- async def whoami(self) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/user/whoami"
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.get(url, headers=headers)
- response.raise_for_status()
- return response.json() if response.content else {"status_code": response.status_code}
- async def list_cases(self, limit: int = 50, offset: int = 0) -> dict[str, Any]:
- headers = self._headers()
- safe_limit = max(1, limit)
- safe_offset = max(0, offset)
- page = (safe_offset // safe_limit) + 1
- v2_url = f"{self.base_url}/api/v2/cases"
- params = {"page": page, "per_page": safe_limit}
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.get(v2_url, params=params, headers=headers)
- active_url = v2_url
- # Older IRIS releases may not expose /api/v2/cases for listing.
- if response.status_code == 404:
- legacy_url = f"{self.base_url}/manage/cases/list"
- legacy_attempts: list[tuple[str, dict[str, Any] | None, dict[str, Any] | None]] = [
- ("post", None, {"start": safe_offset, "length": safe_limit, "draw": 1}),
- ("post", None, {"page": (safe_offset // safe_limit) + 1, "per_page": safe_limit}),
- ("get", {"limit": safe_limit, "offset": safe_offset}, None),
- ]
- for method, legacy_params, legacy_payload in legacy_attempts:
- if method == "post":
- response = await client.post(
- legacy_url,
- params=legacy_params,
- json=legacy_payload,
- headers=headers,
- )
- else:
- response = await client.get(
- legacy_url,
- params=legacy_params,
- headers=headers,
- )
- active_url = legacy_url
- if response.status_code not in {404, 405, 415}:
- break
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
- ) from exc
- if not response.content:
- return {"status_code": response.status_code}
- result = response.json()
- # IRIS v2 response: { "total": int, "data": [...], "last_page": int, ... }
- if isinstance(result, dict) and isinstance(result.get("total"), int) and isinstance(result.get("data"), list):
- return result # pass v2 response through directly
- if isinstance(result, dict) and isinstance(result.get("data"), list):
- total = result.get("recordsTotal")
- if not isinstance(total, int):
- total = len(result["data"])
- return {
- "items": result["data"],
- "total": total,
- "limit": safe_limit,
- "offset": safe_offset,
- "source": "legacy_manage_cases_list",
- "raw": result,
- }
- return result
- async def create_alert(self, payload: dict[str, Any]) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/alerts/add"
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.post(url, json=payload, headers=headers)
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {"status_code": response.status_code}
- async def get_case(self, case_id: int) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/api/v2/cases/{case_id}"
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.get(url, headers=headers)
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {}
- async def get_alert(self, alert_id: int) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/alerts/{alert_id}"
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.get(url, headers=headers)
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {url}. Response: {detail}"
- ) from exc
- result = response.json() if response.content else {}
- # Legacy endpoint returns {"status": "success", "data": {...}}
- return result.get("data", result)
- async def list_alerts(
- self,
- page: int = 1,
- per_page: int = 50,
- sort_by: str = "alert_id",
- sort_dir: str = "desc",
- filter_title: str | None = None,
- filter_owner_id: int | None = None,
- ) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/api/v2/alerts"
- params: dict[str, Any] = {
- "page": max(1, page),
- "per_page": max(1, per_page),
- "sort": f"{sort_by}:{sort_dir}",
- }
- if filter_title:
- params["alert_title"] = filter_title
- if filter_owner_id:
- params["alert_owner_id"] = filter_owner_id
- async with httpx.AsyncClient(verify=False, timeout=30.0) as client:
- response = await client.get(url, params=params, headers=headers)
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {"status_code": response.status_code}
- async def assign_alert(self, alert_id: int, owner_id: int) -> dict[str, Any]:
- headers = self._headers()
- url = f"{self.base_url}/api/v2/alerts/{alert_id}"
- payload = {"alert_owner_id": owner_id}
- async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
- response = await client.put(url, json=payload, headers=headers)
- try:
- response.raise_for_status()
- except httpx.HTTPStatusError as exc:
- detail = response.text.strip()
- raise RuntimeError(
- f"IRIS returned {response.status_code} for {url}. Response: {detail}"
- ) from exc
- return response.json() if response.content else {"status_code": response.status_code}
|