feat(infra): add persistence and SMS adapters

This commit is contained in:
2026-07-14 09:32:58 +03:30
parent 4fc0ee1107
commit 61f7b5c322
7 changed files with 440 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
import logging
from typing import Any
import httpx
from gapido_auth.domain.errors import ExternalServiceError
from gapido_auth.domain.ports import SmsClient
logger = logging.getLogger(__name__)
class KavenegarSmsClient(SmsClient):
def __init__(
self,
api_key: str,
timeout_seconds: float = 10.0,
transport: httpx.AsyncBaseTransport | None = None,
) -> None:
self._api_key = api_key
self._timeout_seconds = timeout_seconds
self._transport = transport
async def send_otp(self, mobile: str, code: str, template: str) -> None:
url = f"https://api.kavenegar.com/v1/{self._api_key}/verify/lookup.json"
payload = {"receptor": mobile, "template": template, "token": code, "type": "sms"}
try:
async with httpx.AsyncClient(
timeout=self._timeout_seconds, transport=self._transport
) as client:
response = await client.post(url, data=payload)
except httpx.HTTPError as exc:
logger.warning("Kavenegar network error for mobile=%s", mobile, exc_info=True)
raise ExternalServiceError("Kavenegar network error") from exc
if response.status_code != 200:
logger.warning("Kavenegar HTTP error status=%s mobile=%s", response.status_code, mobile)
raise ExternalServiceError("Kavenegar HTTP error")
data: dict[str, Any] = response.json()
status = data.get("return", {}).get("status")
if status != 200:
logger.warning("Kavenegar API error status=%s mobile=%s", status, mobile)
raise ExternalServiceError("Kavenegar API error")
logger.info("OTP SMS sent successfully to mobile=%s", mobile)