mirror of
https://github.com/openmax-server/server.git
synced 2026-05-23 12:01:43 +03:00
feat: 23 опкод для регистрации, смс шлюз, докер
This commit is contained in:
0
sms-gateway/app/routers/__init__.py
Normal file
0
sms-gateway/app/routers/__init__.py
Normal file
51
sms-gateway/app/routers/admin.py
Normal file
51
sms-gateway/app/routers/admin.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends
|
||||
from pydantic import BaseModel
|
||||
from app.config import reload_config
|
||||
from app.deps import get_sms_service, init_service
|
||||
from app.service import SmsService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/admin", tags=["Admin"])
|
||||
|
||||
class RoutingInfo(BaseModel):
|
||||
phone: str
|
||||
primary_provider: str
|
||||
fallback_provider: str | None
|
||||
|
||||
@router.post("/reload", response_model=dict)
|
||||
async def reload() -> dict:
|
||||
"""Перечитать config.yaml без перезапуска сервиса."""
|
||||
new_config = reload_config()
|
||||
init_service()
|
||||
providers = list(new_config.providers.keys())
|
||||
rules_count = len(new_config.routing.rules)
|
||||
logger.info("Конфиг перезагружен: провайдеры=%s правил=%d", providers, rules_count)
|
||||
return {"success": True, "providers": providers, "routing_rules": rules_count}
|
||||
|
||||
@router.get("/routing/resolve", response_model=RoutingInfo)
|
||||
async def resolve_routing(
|
||||
phone: str,
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> RoutingInfo:
|
||||
"""Проверить, какой провайдер будет выбран для номера."""
|
||||
primary, fallback = service.config.resolve_provider(phone)
|
||||
return RoutingInfo(phone=phone, primary_provider=primary, fallback_provider=fallback)
|
||||
|
||||
@router.get("/routing/rules", response_model=list[dict])
|
||||
async def list_rules(
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> list[dict]:
|
||||
"""Список всех правил маршрутизации."""
|
||||
return [rule.model_dump() for rule in service.config.routing.rules]
|
||||
|
||||
@router.get("/providers", response_model=list[dict])
|
||||
async def list_providers(
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> list[dict]:
|
||||
"""Список активных провайдеров."""
|
||||
return [
|
||||
{"name": name, "type": name, "enabled": True}
|
||||
for name in service.providers.keys()
|
||||
]
|
||||
43
sms-gateway/app/routers/lk.py
Normal file
43
sms-gateway/app/routers/lk.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
from app.deps import get_sms_service
|
||||
from app.service import SmsService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/lk", tags=["Личный кабинет"])
|
||||
|
||||
class PendingCode(BaseModel):
|
||||
phone: str
|
||||
code: str
|
||||
expires_in: int
|
||||
|
||||
@router.get("/codes", response_model=list[PendingCode])
|
||||
async def list_codes(
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> list[PendingCode]:
|
||||
items = await service.list_pending_codes()
|
||||
return [PendingCode(**item) for item in items]
|
||||
|
||||
@router.get("/code", response_model=PendingCode)
|
||||
async def get_code(
|
||||
phone: str = Query(..., description="Номер телефона"),
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> PendingCode:
|
||||
items = await service.list_pending_codes()
|
||||
normalized = phone if phone.startswith("+") else f"+{phone}"
|
||||
for item in items:
|
||||
if item["phone"] == normalized:
|
||||
return PendingCode(**item)
|
||||
raise HTTPException(status_code=404, detail="Код не найден или истёк")
|
||||
|
||||
@router.delete("/code", response_model=dict)
|
||||
async def consume_code(
|
||||
phone: str = Query(..., description="Номер телефона"),
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> dict:
|
||||
code = await service.consume_code(phone)
|
||||
if code is None:
|
||||
raise HTTPException(status_code=404, detail="Код не найден или истёк")
|
||||
return {"success": True, "phone": phone, "consumed_code": code}
|
||||
41
sms-gateway/app/routers/sms.py
Normal file
41
sms-gateway/app/routers/sms.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from app.deps import get_sms_service
|
||||
from app.service import RateLimitExceeded, SmsService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/sms", tags=["SMS"])
|
||||
|
||||
class SendCodeRequest(BaseModel):
|
||||
phone_number: str
|
||||
|
||||
class SendCodeResponse(BaseModel):
|
||||
success: bool
|
||||
provider: str
|
||||
phone_number: str
|
||||
code: str | None = None
|
||||
error: str | None = None
|
||||
|
||||
@router.post("/send", response_model=SendCodeResponse)
|
||||
async def send_code(
|
||||
request: SendCodeRequest,
|
||||
service: SmsService = Depends(get_sms_service),
|
||||
) -> SendCodeResponse:
|
||||
try:
|
||||
result = await service.send_code(request.phone_number)
|
||||
except RateLimitExceeded as e:
|
||||
raise HTTPException(
|
||||
status_code=429,
|
||||
detail={"error": "Слишком много запросов для этого номера", "retry_after": e.retry_after},
|
||||
headers={"Retry-After": str(e.retry_after)},
|
||||
)
|
||||
if not result.success:
|
||||
raise HTTPException(status_code=502, detail=result.error or "Ошибка отправки SMS")
|
||||
return SendCodeResponse(
|
||||
success=True,
|
||||
provider=result.provider,
|
||||
phone_number=request.phone_number,
|
||||
code=result.code,
|
||||
)
|
||||
Reference in New Issue
Block a user