Source code for terminusgps.twilio.caller

import asyncio
from typing import Any

import twilio.rest
from django.conf import settings
from loguru import logger
from twilio.http.async_http_client import AsyncTwilioHttpClient


[docs] class TwilioCaller: def __init__( self, client_sid: str | None = None, client_token: str | None = None, from_number: str | None = None, messaging_sid: str | None = None, log_level: int = 10, log_days: int = 10, ) -> None: """ Sets Twilio client session variables. All parameters are optional, default values are pulled from a Django settings module. :param client_sid: A Twilio client session id. :type client_sid: :py:obj:`str` | :py:obj:`None` :param client_token: A Twilio client API token. :type client_token: :py:obj:`str` | :py:obj:`None` :param from_number: Phone number used to send notifications. :type from_number: :py:obj:`str` | :py:obj:`None` :param messaging_sid: A Twilio client messaging service session id. :type messaging_sid: :py:obj:`str` | :py:obj:`None` :returns: Nothing. :rtype: :py:obj:`None` """ logger.add( f"logs/{self.__class__.__name__}.log", level=log_level, retention=f"{log_days} days", diagnose=settings.DEBUG, ) self._client_sid = client_sid or settings.TWILIO_SID self._client_token = client_token or settings.TWILIO_TOKEN self._from_number = from_number or settings.TWILIO_FROM_NUMBER self._messaging_sid = messaging_sid or settings.TWILIO_MESSAGING_SID def __enter__(self) -> "TwilioCaller": """Opens a context manager and creates an asyncronous Twilio client.""" self.client = twilio.rest.Client( self.client_sid, self._client_token, http_client=AsyncTwilioHttpClient() ) return self def __exit__(self, exc_type, exc_value, exc_tb) -> None: """Closes the context manager.""" return None
[docs] def create_notification( self, to_number: str, message: str, method: str = "sms" ) -> asyncio.Task[Any]: """ Returns an awaitable notification task. Valid methods are ``"sms"``, ``"call"`` and ``"phone"``. :param to_number: A phone number to notify. :type to_number: :py:obj:`str` :param message: A notification message. :type message: :py:obj:`str` :param method: A notification method. Default is ``"sms"``. :type method: :py:obj:`str` :raises ValueError: If ``method`` is invalid. :returns: An awaitable task. :rtype: :py:obj:`~asyncio.Task` """ match method: case "sms": return asyncio.create_task( self.create_sms(to_number=to_number, message=message) ) case "call" | "phone": return asyncio.create_task( self.create_call(to_number=to_number, message=message) ) case _: raise ValueError(f"Unsupported TwilioCaller method '{method}'.")
[docs] async def create_call(self, to_number: str, message: str) -> None: """ Calls ``to_number`` and reads ``message`` aloud. :param to_number: A phone number. :type to_number: :py:obj:`str` :param message: A message to be read aloud. :type message: :py:obj:`str` :returns: Nothing. :rtype: :py:obj:`None` """ logger.info("Creating a call notification...") logger.debug(f"Reading '{message}' to '{to_number}'...") await self.client.calls.create_async( to=to_number, from_=self.from_number, twiml=f"<Response><Say>{message}</Say></Response>", )
[docs] async def create_sms(self, to_number: str, message: str) -> None: """ Texts ``message`` to ``to_number``. :param to_number: A phone number. :type to_number: :py:obj:`str` :param message: A message to be texted. :type message: :py:obj:`str` :returns: Nothing. :rtype: :py:obj:`None` """ logger.info("Creating an sms notification...") logger.debug(f"Texting '{message}' to '{to_number}'...") await self.client.messages.create_async( to=to_number, from_=self.from_number, body=message, messaging_service_sid=self.messaging_sid, )
@property def client_sid(self) -> str: """ Client session id. :type: :py:obj:`str` """ return self._client_sid @property def from_number(self) -> str: """ Origin phone number. :type: :py:obj:`str` """ return self._from_number @property def messaging_sid(self) -> str: """ Messaging service session id. :type: :py:obj:`str` """ return self._messaging_sid