import logging from pathlib import Path from yuxi.channel.extensions.confluence.gateway import ConfluenceGateway from yuxi.channel.extensions.confluence.types import OutboundResult logger = logging.getLogger(__name__) class ConfluenceAttachmentManager: def __init__(self, gateway: ConfluenceGateway): self._gateway = gateway async def list_attachments( self, page_id: str, account_id: str = "default", ) -> list[dict]: client = self._gateway.get_client(account_id) if client is None: return [] try: result = await client._request( "GET", f"/wiki/api/v2/pages/{page_id}/attachments", ) return result.get("results", []) except Exception as e: logger.error("Failed to list attachments for page %s: %s", page_id, e) return [] async def get_attachment( self, attachment_id: str, account_id: str = "default", ) -> dict | None: client = self._gateway.get_client(account_id) if client is None: return None try: return await client._request( "GET", f"/wiki/api/v2/attachments/{attachment_id}", ) except Exception as e: logger.error("Failed to get attachment %s: %s", attachment_id, e) return None async def upload_attachment( self, page_id: str, file_path: str, filename: str | None = None, account_id: str = "default", ) -> OutboundResult: client = self._gateway.get_client(account_id) if client is None: return OutboundResult(success=False, error="Client not found") path = Path(file_path) if not path.exists(): return OutboundResult(success=False, error=f"File not found: {file_path}") fname = filename or path.name try: result = await client._request( "POST", f"/wiki/api/v2/pages/{page_id}/attachments", files={"file": (fname, path.read_bytes(), "application/octet-stream")}, ) return OutboundResult(success=True, comment_id=result.get("id", "")) except Exception as e: logger.error("Failed to upload attachment to page %s: %s", page_id, e) return OutboundResult(success=False, error=str(e)) async def download_attachment( self, page_id: str, filename: str, save_path: str, account_id: str = "default", ) -> str | None: client = self._gateway.get_client(account_id) if client is None: return None try: url = f"/download/attachments/{page_id}/{filename}" if client._http is None: raise RuntimeError("Client not initialized") resp = await client._http.get(url) resp.raise_for_status() Path(save_path).write_bytes(resp.content) return save_path except Exception as e: logger.error("Failed to download attachment %s: %s", filename, e) return None async def delete_attachment( self, attachment_id: str, account_id: str = "default", ) -> OutboundResult: client = self._gateway.get_client(account_id) if client is None: return OutboundResult(success=False, error="Client not found") try: await client._request( "DELETE", f"/wiki/api/v2/attachments/{attachment_id}", ) return OutboundResult(success=True, comment_id=attachment_id) except Exception as e: logger.error("Failed to delete attachment %s: %s", attachment_id, e) return OutboundResult(success=False, error=str(e))