from __future__ import annotations import base64 import logging from urllib.parse import urljoin import httpx logger = logging.getLogger(__name__) OCS_ROOM_PATH = "/ocs/v2.php/apps/spreed/api/v4/room" OCS_ROOM_TOKEN_PATH = "/ocs/v2.php/apps/spreed/api/v4/room/{token}" DEFAULT_TIMEOUT = 30.0 def _auth_headers(api_user: str, api_password: str) -> dict: auth = base64.b64encode(f"{api_user}:{api_password}".encode()).decode() return { "Authorization": f"Basic {auth}", "OCS-APIRequest": "true", "Accept": "application/json", } async def list_conversations( base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> list[dict]: url = urljoin(base_url.rstrip("/") + "/", OCS_ROOM_PATH) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.get( url, headers=_auth_headers(api_user, api_password), ) if resp.status_code != 200: logger.warning("Nextcloud Talk list conversations failed: HTTP %s", resp.status_code) return [] data = resp.json() return data.get("ocs", {}).get("data", []) async def create_conversation( base_url: str, api_user: str, api_password: str, *, room_type: int, invite: str | None = None, room_name: str | None = None, timeout: float = DEFAULT_TIMEOUT, ) -> dict | None: url = urljoin(base_url.rstrip("/") + "/", OCS_ROOM_PATH) body: dict = {"roomType": room_type} if invite: body["invite"] = invite if room_name: body["roomName"] = room_name async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.post( url, json=body, headers=_auth_headers(api_user, api_password), ) if resp.status_code != 200: logger.warning("Nextcloud Talk create conversation failed: HTTP %s", resp.status_code) return None data = resp.json() return data.get("ocs", {}).get("data") async def delete_conversation( room_token: str, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", OCS_ROOM_TOKEN_PATH.format(token=room_token), ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.delete( url, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def rename_conversation( room_token: str, room_name: str, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", OCS_ROOM_TOKEN_PATH.format(token=room_token), ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.put( url, json={"roomName": room_name}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_conversation_description( room_token: str, description: str, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/description", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.put( url, json={"description": description}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_conversation_password( room_token: str, password: str, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/password", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.put( url, json={"password": password}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def remove_conversation_password( room_token: str, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/password", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.delete( url, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_read_only( room_token: str, state: int, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/read-only", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.put( url, json={"state": state}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_message_expiration( room_token: str, seconds: int, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/message-expiration", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.post( url, json={"seconds": seconds}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_favorite( room_token: str, base_url: str, api_user: str, api_password: str, *, favorite: bool = True, timeout: float = DEFAULT_TIMEOUT, ) -> bool: action = "favorite" if favorite else "unfavorite" url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/{action}", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.post( url, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200 async def set_notification_level( room_token: str, level: int, base_url: str, api_user: str, api_password: str, *, timeout: float = DEFAULT_TIMEOUT, ) -> bool: url = urljoin( base_url.rstrip("/") + "/", f"/ocs/v2.php/apps/spreed/api/v4/room/{room_token}/notify", ) async with httpx.AsyncClient(timeout=timeout) as client: resp = await client.post( url, json={"level": level}, headers=_auth_headers(api_user, api_password), ) return resp.status_code == 200