Spaces:
Sleeping
Sleeping
| import asyncio | |
| import logging | |
| import httpx | |
| from app.lib.graph.auth import GraphAuthProvider | |
| _BASE_URL = "https://graph.microsoft.com/v1.0" | |
| logger = logging.getLogger(__name__) | |
| def _raise_with_detail(resp: httpx.Response) -> None: | |
| if resp.is_error: | |
| logger.error("Graph %s %s → %s: %s", resp.request.method, resp.request.url, resp.status_code, resp.text) | |
| resp.raise_for_status() | |
| class GraphClient: | |
| def __init__(self, auth: GraphAuthProvider) -> None: | |
| self._auth = auth | |
| self._client = httpx.AsyncClient(timeout=30.0) | |
| async def _headers(self) -> dict[str, str]: | |
| token = await asyncio.to_thread(self._auth.get_access_token) | |
| return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"} | |
| async def get(self, path: str, params: dict | None = None) -> dict: | |
| resp = await self._client.get( | |
| f"{_BASE_URL}{path}", headers=await self._headers(), params=params | |
| ) | |
| _raise_with_detail(resp) | |
| return resp.json() | |
| async def get_raw(self, path: str) -> bytes: | |
| resp = await self._client.get( | |
| f"{_BASE_URL}{path}", headers=await self._headers() | |
| ) | |
| _raise_with_detail(resp) | |
| return resp.content | |
| async def post(self, path: str, body: dict) -> dict: | |
| resp = await self._client.post( | |
| f"{_BASE_URL}{path}", headers=await self._headers(), json=body | |
| ) | |
| _raise_with_detail(resp) | |
| return resp.json() | |
| async def patch(self, path: str, body: dict) -> dict: | |
| resp = await self._client.patch( | |
| f"{_BASE_URL}{path}", headers=await self._headers(), json=body | |
| ) | |
| _raise_with_detail(resp) | |
| return resp.json() | |
| async def delete(self, path: str) -> None: | |
| resp = await self._client.delete( | |
| f"{_BASE_URL}{path}", headers=await self._headers() | |
| ) | |
| _raise_with_detail(resp) | |
| async def aclose(self) -> None: | |
| await self._client.aclose() | |