Brak opisu

iris.py 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. from typing import Any
  2. import httpx
  3. class IrisAdapter:
  4. def __init__(self, base_url: str, api_key: str) -> None:
  5. self.base_url = base_url.rstrip("/")
  6. self.api_key = api_key
  7. def _headers(self) -> dict[str, str]:
  8. return {"Authorization": f"Bearer {self.api_key}"} if self.api_key else {}
  9. async def create_case(self, payload: dict[str, Any]) -> dict[str, Any]:
  10. headers = self._headers()
  11. async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
  12. v2_url = f"{self.base_url}/api/v2/cases"
  13. response = await client.post(v2_url, json=payload, headers=headers)
  14. if response.status_code == 404:
  15. legacy_url = f"{self.base_url}/manage/cases/add"
  16. response = await client.post(legacy_url, json=payload, headers=headers)
  17. active_url = legacy_url
  18. else:
  19. active_url = v2_url
  20. try:
  21. response.raise_for_status()
  22. except httpx.HTTPStatusError as exc:
  23. detail = response.text.strip()
  24. raise RuntimeError(
  25. f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
  26. ) from exc
  27. return response.json() if response.content else {"status_code": response.status_code}
  28. async def update_case(self, case_id: str, payload: dict[str, Any]) -> dict[str, Any]:
  29. headers = self._headers()
  30. async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
  31. v2_url = f"{self.base_url}/api/v2/cases/{case_id}"
  32. response = await client.put(v2_url, json=payload, headers=headers)
  33. if response.status_code == 404:
  34. legacy_url = f"{self.base_url}/manage/cases/update/{case_id}"
  35. response = await client.post(legacy_url, json=payload, headers=headers)
  36. active_url = legacy_url
  37. else:
  38. active_url = v2_url
  39. try:
  40. response.raise_for_status()
  41. except httpx.HTTPStatusError as exc:
  42. detail = response.text.strip()
  43. raise RuntimeError(
  44. f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
  45. ) from exc
  46. return response.json() if response.content else {"status_code": response.status_code}
  47. async def whoami(self) -> dict[str, Any]:
  48. headers = self._headers()
  49. url = f"{self.base_url}/user/whoami"
  50. async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
  51. response = await client.get(url, headers=headers)
  52. response.raise_for_status()
  53. return response.json() if response.content else {"status_code": response.status_code}
  54. async def list_cases(self, limit: int = 50, offset: int = 0) -> dict[str, Any]:
  55. headers = self._headers()
  56. safe_limit = max(1, limit)
  57. safe_offset = max(0, offset)
  58. v2_url = f"{self.base_url}/api/v2/cases"
  59. params = {"limit": safe_limit, "offset": safe_offset}
  60. async with httpx.AsyncClient(verify=False, timeout=20.0) as client:
  61. response = await client.get(v2_url, params=params, headers=headers)
  62. active_url = v2_url
  63. # Older IRIS releases may not expose /api/v2/cases for listing.
  64. if response.status_code == 404:
  65. legacy_url = f"{self.base_url}/manage/cases/list"
  66. legacy_attempts: list[tuple[str, dict[str, Any] | None, dict[str, Any] | None]] = [
  67. ("post", None, {"start": safe_offset, "length": safe_limit, "draw": 1}),
  68. ("post", None, {"page": (safe_offset // safe_limit) + 1, "per_page": safe_limit}),
  69. ("get", {"limit": safe_limit, "offset": safe_offset}, None),
  70. ]
  71. for method, legacy_params, legacy_payload in legacy_attempts:
  72. if method == "post":
  73. response = await client.post(
  74. legacy_url,
  75. params=legacy_params,
  76. json=legacy_payload,
  77. headers=headers,
  78. )
  79. else:
  80. response = await client.get(
  81. legacy_url,
  82. params=legacy_params,
  83. headers=headers,
  84. )
  85. active_url = legacy_url
  86. if response.status_code not in {404, 405, 415}:
  87. break
  88. try:
  89. response.raise_for_status()
  90. except httpx.HTTPStatusError as exc:
  91. detail = response.text.strip()
  92. raise RuntimeError(
  93. f"IRIS returned {response.status_code} for {active_url}. Response: {detail}"
  94. ) from exc
  95. if not response.content:
  96. return {"status_code": response.status_code}
  97. result = response.json()
  98. if isinstance(result, dict) and isinstance(result.get("data"), list):
  99. total = result.get("recordsTotal")
  100. if not isinstance(total, int):
  101. total = len(result["data"])
  102. return {
  103. "items": result["data"],
  104. "total": total,
  105. "limit": safe_limit,
  106. "offset": safe_offset,
  107. "source": "legacy_manage_cases_list",
  108. "raw": result,
  109. }
  110. return result