"""Module for interacting with the objects returned by the API.""" from enum import Enum from typing import Any from typing import Literal from typing import NotRequired from typing import TypedDict from .auth import AbstractAuth class FunctionQuotas(TypedDict): free: int used: int class SystemResponse(TypedDict): systemName: str systemId: str ownSystem: bool functionWebhookQuotas: FunctionQuotas class WebhookResponse(TypedDict): functionWebhookId: str integrationName: str locationName: str functionName: str expiresAt: str modificationState: str | None class WebhookDefinitionMethods(Enum): GET = "Get" POST = "Post" PUT = "Put" DELETE = "Delete" PATCH = "Patch" HEAD = "Head" class WebhookDefinitionSecurityLevel(Enum): TLSWITHCACHECK = "TlsWithCACheck" TLSALLOWSELFFIGNED = "TlsAllowSelfSigned" ALLOWHTTP = "AllowHttp" TLSPINNEDCERTIFICATE = "TlsPinnedCertificate" class WebhookDefinitionBody(TypedDict): contentType: NotRequired[str] content: str | dict class WebhookDefinitionAuthenticationType(Enum): NONE = "None" OAUTH2ACCESSTOKEN = "OAuth2IssuedAccessToken" OAUTH2REFRESHTOKEN = "OAuth2IssuedRefreshToken" class WebhookDefinitionAuthentication(TypedDict): apiAuthenticationType: ( WebhookDefinitionAuthenticationType | Literal["None", "OAuth2IssuedAccessToken", "OAuth2IssuedRefreshToken"] ) expiresIn: NotRequired[int] clientId: NotRequired[str] accessToken: NotRequired[str] refreshToken: NotRequired[str] tokenEndoint: NotRequired[str] scope: NotRequired[str] authorizationEndpoint: NotRequired[str] class WebhookDefinition(TypedDict): method: WebhookDefinitionMethods | Literal["Get", "Post", "Put", "Delete", "Patch", "Head"] url: str body: NotRequired[WebhookDefinitionBody] securityLevel: ( WebhookDefinitionSecurityLevel | Literal["AllowHttp", "TlsWithCACheck", "TlsAllowSelfSigned", "TlsPinnedCertificate"] ) pinnedCertificate: NotRequired[str] timeout: NotRequired[int] additionalHttpHeaders: NotRequired[Any] authentication: WebhookDefinitionAuthentication class WebhookData(TypedDict): functionWebhookId: NotRequired[str] integrationName: str locationName: NotRequired[str] functionName: NotRequired[str] expiresAt: NotRequired[str] modificationState: NotRequired[str] definition: WebhookDefinition class WebhookRename(TypedDict): locationName: NotRequired[str] functionName: NotRequired[str] class Webhook: """Class for interacting with webhooks.""" def __init__(self, raw_data: WebhookResponse, system_id: str, auth: AbstractAuth) -> None: self._system_id = system_id self._auth = auth self._update_values(raw_data) def _update_values(self, data: WebhookResponse) -> None: self._webhook_id = data["functionWebhookId"] self._webhook_function_name = data["functionName"] self._webhook_location_name = data["locationName"] self._expires_at = data["expiresAt"] self._modification_state = data["modificationState"] @property def webhook_id(self) -> str: return self._webhook_id @property def webhook_function_name(self) -> str: return self._webhook_function_name @property def webhook_location_name(self) -> str: return self._webhook_location_name @property def expires_at(self) -> str: return self._expires_at @property def modification_state(self) -> str: return self._modification_state async def get_update(self) -> None: """Gets the current version of the webhook as stored in the ekey system.""" resp = await self._auth.request("GET", f"systems/{self._system_id}/function-webhooks/{self._webhook_id}") resp.raise_for_status() json_data = await resp.json() self._update_values(json_data) async def delete(self) -> None: """Requests deletion of the webhook. User needs to confirm.""" resp = await self._auth.request("DELETE", f"systems/{self._system_id}/function-webhooks/{self._webhook_id}") resp.raise_for_status() self._modification_state = "DeleteRequested" async def update(self, webhook_data: WebhookData) -> None: """Updates the definition of the webhook. User needs to confirm. Args: webhook_data (WebhookData): The new data for the webhook. """ resp = await self._auth.request( "PUT", f"systems/{self._system_id}/function-webhooks/{self._webhook_id}", json=webhook_data ) resp.raise_for_status() self._modification_state = "UpdateRequested" async def update_name(self, webhook_data: WebhookRename) -> None: """Renames the webhook. User does not need to confirm. Args: webhook_data (WebhookRename): The new name and location """ resp = await self._auth.request( "PATCH", f"systems/{self._system_id}/function-webhooks/{self._webhook_id}/name", json=webhook_data ) resp.raise_for_status() class System: """Class for interacting with a single system.""" def __init__(self, raw_data: SystemResponse, auth: AbstractAuth): self._system_id = raw_data["systemId"] self._system_name = raw_data["systemName"] self._own_system = raw_data["ownSystem"] self._function_webhook_quotas = raw_data["functionWebhookQuotas"] self._auth = auth @property def system_id(self) -> str: return self._system_id @property def system_name(self) -> str: return self._system_name @property def own_system(self) -> bool: return self._own_system @property def function_webhook_quotas(self) -> FunctionQuotas: return self._function_webhook_quotas async def get_webhooks(self) -> list[Webhook]: """Getting all the webhooks in the system that were set by this client_id. Returns: list[Webhook]: registered Webhooks """ resp = await self._auth.request("GET", f"systems/{self._system_id}/function-webhooks") resp.raise_for_status() return [Webhook(wh_data, self._system_id, self._auth) for wh_data in await resp.json()] async def get_webhook(self, webhook_id: str) -> Webhook: """Gets the webhook with the provided id. Args: webhook_id (str): ID of the webhook Returns: Webhook: registerd Webhook Raises: aiohttp.ClientResponseError: If `Unauthorized - Authorization failed` or `Forbidden - Invalid or expired authentication token` or `Not Found` """ resp = await self._auth.request("GET", f"systems/{self._system_id}/function-webhooks/{webhook_id}") resp.raise_for_status() return Webhook(await resp.json(), self._system_id, self._auth) async def add_webhook(self, webhook_data: WebhookData) -> Webhook: """Adds a new webhook with the provided data. Args: webhook_data (WebhookData): Data of the Webhook Returns: Webhook: registerd webhook """ resp = await self._auth.request("POST", f"systems/{self._system_id}/function-webhooks", json=webhook_data) resp.raise_for_status() return Webhook(await resp.json(), self._system_id, self._auth) class BionyxAPI: """Base class for interacting with the API and get all systems attached to the user.""" def __init__(self, auth: AbstractAuth) -> None: """Initialize the API with an Auth object. Args: auth (AbstractAuth): Auth object that provides the base URL """ self._auth = auth async def get_systems(self) -> list[System]: """Gets all the Systems attached to the currently logged in user. Returns: list[System]: List of Systems the user has access to """ resp = await self._auth.request("GET", "systems") resp.raise_for_status() return [System(system_data, self._auth) for system_data in await resp.json()]