52 lines
2.2 KiB
Python
52 lines
2.2 KiB
Python
from __future__ import annotations
|
|
import logging
|
|
import httpx
|
|
from app.config import ProviderConfig
|
|
from app.providers import SendResult
|
|
from app.providers.base import BaseProvider
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class SmsApiProvider(BaseProvider):
|
|
"""
|
|
Внешний SMS-сервис.
|
|
Отправляет реальное SMS, возвращает код и uuid.
|
|
Используется для России (+7).
|
|
"""
|
|
name = "sms_api"
|
|
|
|
def __init__(self, config: ProviderConfig) -> None:
|
|
extra = config.extra()
|
|
self.base_url: str = extra.get("base_url", "").rstrip("/")
|
|
self.send_endpoint: str = extra.get("send_endpoint", "/auth/code")
|
|
self.timeout: int = int(extra.get("timeout", 10))
|
|
|
|
async def send(self, phone_number: str, code: str | None = None) -> SendResult:
|
|
normalized = phone_number if phone_number.startswith("+") else f"+{phone_number}"
|
|
url = f"{self.base_url}{self.send_endpoint}"
|
|
payload: dict = {"phone_number": normalized}
|
|
if code:
|
|
payload["code"] = code
|
|
try:
|
|
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
response = await client.post(
|
|
url,
|
|
json=payload,
|
|
headers={"accept": "application/json", "Content-Type": "application/json"},
|
|
)
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
code = str(data.get("code", ""))
|
|
logger.info("sms_api: SMS отправлен на %s | uuid=%s code=%s", normalized, data.get("uuid"), code)
|
|
return SendResult(
|
|
success=True,
|
|
provider=self.name,
|
|
code=code,
|
|
raw_response=data,
|
|
)
|
|
except httpx.HTTPStatusError as e:
|
|
logger.error("sms_api HTTP %s для %s: %s", e.response.status_code, normalized, e)
|
|
return SendResult(success=False, provider=self.name, error=str(e))
|
|
except Exception as e:
|
|
logger.error("sms_api ошибка для %s: %s", normalized, e)
|
|
return SendResult(success=False, provider=self.name, error=str(e)) |