feature: added exception handling
This commit is contained in:
@@ -1,39 +1,79 @@
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import List
|
||||
import logging
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
from pydantic import BaseModel, HttpUrl, Field, field_validator
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.infrastructure.database import get_db
|
||||
from app import crud
|
||||
from app.core.exceptions import CallEventAlreadyExistsError, DatabaseError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CallDirection(str, Enum):
|
||||
"""Направление звонка"""
|
||||
in_ = "in"
|
||||
out = "out"
|
||||
|
||||
|
||||
class UisCallEvent(BaseModel):
|
||||
eventType: str
|
||||
call_session_id: int
|
||||
direction: CallDirection
|
||||
employee_id: int
|
||||
employee_full_name: str
|
||||
contact_phone_number: str
|
||||
called_phone_number: str
|
||||
communication_group_name: str
|
||||
start_time: datetime
|
||||
finish_time: datetime
|
||||
talk_time_duration: int
|
||||
full_record_file_link: HttpUrl
|
||||
campaign_name: str
|
||||
"""Схема события звонка от UIS"""
|
||||
eventType: str = Field(..., description="Тип события")
|
||||
call_session_id: int = Field(..., gt=0, description="Уникальный ID сессии звонка")
|
||||
direction: CallDirection = Field(..., description="Направление звонка")
|
||||
employee_id: int = Field(..., gt=0, description="ID сотрудника")
|
||||
employee_full_name: str = Field(..., min_length=1, description="ФИО сотрудника")
|
||||
contact_phone_number: str = Field(..., description="Телефон контакта")
|
||||
called_phone_number: str = Field(..., description="Набранный телефон")
|
||||
communication_group_name: str = Field(..., description="Группа коммуникации")
|
||||
start_time: datetime = Field(..., description="Время начала звонка")
|
||||
finish_time: datetime = Field(..., description="Время окончания звонка")
|
||||
talk_time_duration: int = Field(..., ge=0, description="Длительность разговора (сек)")
|
||||
full_record_file_link: HttpUrl = Field(..., description="Ссылка на запись")
|
||||
campaign_name: str = Field(..., description="Название кампании")
|
||||
|
||||
@field_validator('finish_time')
|
||||
@classmethod
|
||||
def validate_finish_time(cls, v: datetime, info) -> datetime:
|
||||
"""Проверяем, что finish_time >= start_time"""
|
||||
if 'start_time' in info.data and v < info.data['start_time']:
|
||||
raise ValueError('finish_time must be greater than or equal to start_time')
|
||||
return v
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/webhook", status_code=204)
|
||||
async def create_call_event(callEvent: UisCallEvent, db: AsyncSession = Depends(get_db)) -> None:
|
||||
"""Webhook для получения событий звонков от UIS"""
|
||||
async def create_call_event(
|
||||
callEvent: UisCallEvent,
|
||||
db: AsyncSession = Depends(get_db)
|
||||
) -> None:
|
||||
"""
|
||||
Webhook для получения событий звонков от UIS
|
||||
|
||||
**Обрабатывает события:**
|
||||
- Сохраняет событие звонка в базу данных
|
||||
- Проверяет уникальность call_session_id
|
||||
- Логирует успешную обработку
|
||||
|
||||
**Возможные ошибки:**
|
||||
- 409 Conflict: Событие с таким call_session_id уже существует
|
||||
- 422 Unprocessable Entity: Ошибка валидации данных
|
||||
- 500 Internal Server Error: Ошибка сервера/БД
|
||||
"""
|
||||
logger.info(
|
||||
f"Received webhook event",
|
||||
extra={
|
||||
"event_type": callEvent.eventType,
|
||||
"call_session_id": callEvent.call_session_id,
|
||||
"employee_id": callEvent.employee_id
|
||||
}
|
||||
)
|
||||
|
||||
# Преобразуем UisCallEvent в данные для CallEvent (БД)
|
||||
event_data = {
|
||||
@@ -53,5 +93,5 @@ async def create_call_event(callEvent: UisCallEvent, db: AsyncSession = Depends(
|
||||
"clean_talk_time_duration": callEvent.talk_time_duration, # Упрощение
|
||||
}
|
||||
|
||||
# Сохраняем в БД
|
||||
# Сохраняем в БД (исключения обрабатываются в exception handlers)
|
||||
await crud.create_call_event(db, event_data)
|
||||
Reference in New Issue
Block a user