Add new alert architecture
This commit is contained in:
@@ -30,6 +30,17 @@ class WhatsAppService:
|
||||
self.from_number = settings.WHATSAPP_FROM_NUMBER
|
||||
self.enabled = settings.ENABLE_WHATSAPP_NOTIFICATIONS
|
||||
|
||||
def _parse_api_credentials(self):
|
||||
"""Parse API key into username and password for Twilio basic auth"""
|
||||
if not self.api_key or ":" not in self.api_key:
|
||||
raise ValueError("WhatsApp API key must be in format 'username:password'")
|
||||
|
||||
api_parts = self.api_key.split(":", 1)
|
||||
if len(api_parts) != 2:
|
||||
raise ValueError("Invalid WhatsApp API key format")
|
||||
|
||||
return api_parts[0], api_parts[1]
|
||||
|
||||
async def send_message(
|
||||
self,
|
||||
to_phone: str,
|
||||
@@ -181,10 +192,22 @@ class WhatsAppService:
|
||||
return False
|
||||
|
||||
# Test API connectivity with a simple request
|
||||
# Parse API key (expected format: username:password for Twilio basic auth)
|
||||
if ":" not in self.api_key:
|
||||
logger.error("WhatsApp API key must be in format 'username:password'")
|
||||
return False
|
||||
|
||||
api_parts = self.api_key.split(":", 1) # Split on first : only
|
||||
if len(api_parts) != 2:
|
||||
logger.error("Invalid WhatsApp API key format")
|
||||
return False
|
||||
|
||||
username, password = api_parts
|
||||
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.base_url}/v1/Account", # Twilio account info endpoint
|
||||
auth=(self.api_key.split(":")[0], self.api_key.split(":")[1])
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
@@ -206,6 +229,13 @@ class WhatsAppService:
|
||||
async def _send_text_message(self, to_phone: str, message: str) -> bool:
|
||||
"""Send regular text message via Twilio"""
|
||||
try:
|
||||
# Parse API credentials
|
||||
try:
|
||||
username, password = self._parse_api_credentials()
|
||||
except ValueError as e:
|
||||
logger.error(f"WhatsApp API key configuration error: {e}")
|
||||
return False
|
||||
|
||||
# Prepare request data
|
||||
data = {
|
||||
"From": f"whatsapp:{self.from_number}",
|
||||
@@ -216,9 +246,9 @@ class WhatsAppService:
|
||||
# Send via Twilio API
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.post(
|
||||
f"{self.base_url}/2010-04-01/Accounts/{self.api_key.split(':')[0]}/Messages.json",
|
||||
f"{self.base_url}/2010-04-01/Accounts/{username}/Messages.json",
|
||||
data=data,
|
||||
auth=(self.api_key.split(":")[0], self.api_key.split(":")[1])
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
@@ -245,6 +275,13 @@ class WhatsAppService:
|
||||
) -> bool:
|
||||
"""Send WhatsApp template message via Twilio"""
|
||||
try:
|
||||
# Parse API credentials
|
||||
try:
|
||||
username, password = self._parse_api_credentials()
|
||||
except ValueError as e:
|
||||
logger.error(f"WhatsApp API key configuration error: {e}")
|
||||
return False
|
||||
|
||||
# Prepare template data
|
||||
content_variables = {str(i+1): param for i, param in enumerate(parameters)}
|
||||
|
||||
@@ -258,9 +295,9 @@ class WhatsAppService:
|
||||
# Send via Twilio API
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.post(
|
||||
f"{self.base_url}/2010-04-01/Accounts/{self.api_key.split(':')[0]}/Messages.json",
|
||||
f"{self.base_url}/2010-04-01/Accounts/{username}/Messages.json",
|
||||
data=data,
|
||||
auth=(self.api_key.split(":")[0], self.api_key.split(":")[1])
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
if response.status_code == 201:
|
||||
@@ -315,10 +352,17 @@ class WhatsAppService:
|
||||
async def _get_message_status(self, message_sid: str) -> Optional[str]:
|
||||
"""Get message delivery status from Twilio"""
|
||||
try:
|
||||
# Parse API credentials
|
||||
try:
|
||||
username, password = self._parse_api_credentials()
|
||||
except ValueError as e:
|
||||
logger.error(f"WhatsApp API key configuration error: {e}")
|
||||
return None
|
||||
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
response = await client.get(
|
||||
f"{self.base_url}/2010-04-01/Accounts/{self.api_key.split(':')[0]}/Messages/{message_sid}.json",
|
||||
auth=(self.api_key.split(":")[0], self.api_key.split(":")[1])
|
||||
f"{self.base_url}/2010-04-01/Accounts/{username}/Messages/{message_sid}.json",
|
||||
auth=(username, password)
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
|
||||
Reference in New Issue
Block a user