"""Confluence REST API v1 client using httpx.""" from __future__ import annotations import os from dataclasses import dataclass import httpx @dataclass class PageData: """Confluence page data.""" page_id: str title: str body_html: str version: int @dataclass class Auth: """Confluence authentication credentials.""" base_url: str username: str api_token: str @classmethod def from_env(cls) -> Auth: """Load auth from environment variables.""" return cls( base_url=os.environ.get("CONFLUENCE_URL", ""), username=os.environ.get("CONFLUENCE_USERNAME", os.environ.get("CONFLUENCE_USER", "")), api_token=os.environ.get("CONFLUENCE_API_TOKEN", ""), ) @property def httpx_auth(self) -> tuple[str, str]: return (self.username, self.api_token) async def get_page(page_id: str, auth: Auth) -> PageData: """Fetch a Confluence page with body.storage and version.""" url = f"{auth.base_url}/rest/api/content/{page_id}" params = {"expand": "body.storage,version,title"} async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.get(url, params=params, auth=auth.httpx_auth) resp.raise_for_status() data = resp.json() return PageData( page_id=str(data["id"]), title=data["title"], body_html=data["body"]["storage"]["value"], version=data["version"]["number"], ) async def put_page( page_id: str, title: str, body_html: str, version: int, auth: Auth, ) -> PageData: """Update a Confluence page with version increment. Raises httpx.HTTPStatusError on 409 (version conflict) or other errors. """ url = f"{auth.base_url}/rest/api/content/{page_id}" payload = { "version": {"number": version}, "title": title, "type": "page", "body": { "storage": { "value": body_html, "representation": "storage", } }, } async with httpx.AsyncClient(timeout=15.0) as client: resp = await client.put(url, json=payload, auth=auth.httpx_auth) resp.raise_for_status() data = resp.json() return PageData( page_id=str(data["id"]), title=data["title"], body_html=data["body"]["storage"]["value"], version=data["version"]["number"], )