2025-12-17 15:37:32 +01:00
|
|
|
|
"""
|
|
|
|
|
|
Analysis Sessions API endpoints.
|
|
|
|
|
|
|
|
|
|
|
|
Управление сессиями анализа (создание, получение, удаление).
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, status, Query
|
|
|
|
|
|
from typing import Optional
|
2025-12-25 07:44:52 +01:00
|
|
|
|
from app.models.analysis import SessionCreate, SessionResponse, SessionList, SessionUpdate
|
2025-12-17 15:37:32 +01:00
|
|
|
|
from app.interfaces.db_api_client import DBApiClient
|
|
|
|
|
|
from app.dependencies import get_db_client, get_current_user
|
|
|
|
|
|
import httpx
|
|
|
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/analysis", tags=["analysis"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/sessions", response_model=SessionResponse, status_code=status.HTTP_201_CREATED)
|
|
|
|
|
|
async def create_session(
|
|
|
|
|
|
session: SessionCreate,
|
|
|
|
|
|
current_user: dict = Depends(get_current_user),
|
|
|
|
|
|
db_client: DBApiClient = Depends(get_db_client)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Создать новую сессию анализа.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
session: Данные сессии (environment, api_mode, request, response, annotations)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
SessionResponse: Созданная сессия с session_id
|
|
|
|
|
|
"""
|
|
|
|
|
|
user_id = current_user["user_id"]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
created_session = await db_client.save_session(user_id, session)
|
|
|
|
|
|
return created_session
|
|
|
|
|
|
except httpx.HTTPStatusError as e:
|
|
|
|
|
|
if e.response.status_code == 404:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="User not found"
|
|
|
|
|
|
)
|
|
|
|
|
|
elif e.response.status_code == 400:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail="Invalid session data format"
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.error(f"Failed to create session: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
|
|
|
|
detail="Failed to create session in DB API"
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Unexpected error creating session: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="Internal server error"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/sessions", response_model=SessionList)
|
|
|
|
|
|
async def get_sessions(
|
|
|
|
|
|
environment: Optional[str] = Query(None, description="Фильтр по окружению (ift/psi/prod)"),
|
|
|
|
|
|
limit: int = Query(50, ge=1, le=200, description="Лимит результатов"),
|
|
|
|
|
|
offset: int = Query(0, ge=0, description="Смещение для пагинации"),
|
|
|
|
|
|
current_user: dict = Depends(get_current_user),
|
|
|
|
|
|
db_client: DBApiClient = Depends(get_db_client)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Получить список сессий пользователя.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
environment: Фильтр по окружению (опционально)
|
|
|
|
|
|
limit: Лимит результатов (default: 50, max: 200)
|
|
|
|
|
|
offset: Смещение для пагинации (default: 0)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
SessionList: Список сессий с total count
|
|
|
|
|
|
"""
|
|
|
|
|
|
user_id = current_user["user_id"]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
sessions = await db_client.get_sessions(user_id, environment, limit, offset)
|
|
|
|
|
|
return sessions
|
|
|
|
|
|
except httpx.HTTPStatusError as e:
|
|
|
|
|
|
if e.response.status_code == 404:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="User not found"
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.error(f"Failed to get sessions: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
|
|
|
|
detail="Failed to retrieve sessions from DB API"
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Unexpected error getting sessions: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="Internal server error"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/sessions/{session_id}", response_model=SessionResponse)
|
|
|
|
|
|
async def get_session(
|
|
|
|
|
|
session_id: str,
|
|
|
|
|
|
current_user: dict = Depends(get_current_user),
|
|
|
|
|
|
db_client: DBApiClient = Depends(get_db_client)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Получить конкретную сессию по ID.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
session_id: UUID сессии
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
SessionResponse: Полная информация о сессии
|
|
|
|
|
|
"""
|
|
|
|
|
|
user_id = current_user["user_id"]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
session = await db_client.get_session(user_id, session_id)
|
|
|
|
|
|
return session
|
|
|
|
|
|
except httpx.HTTPStatusError as e:
|
|
|
|
|
|
if e.response.status_code == 404:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="Session not found"
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.error(f"Failed to get session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
|
|
|
|
detail="Failed to retrieve session from DB API"
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Unexpected error getting session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="Internal server error"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-25 07:44:52 +01:00
|
|
|
|
@router.patch("/sessions/{session_id}", response_model=SessionResponse)
|
|
|
|
|
|
async def update_session(
|
|
|
|
|
|
session_id: str,
|
|
|
|
|
|
update_data: SessionUpdate,
|
|
|
|
|
|
current_user: dict = Depends(get_current_user),
|
|
|
|
|
|
db_client: DBApiClient = Depends(get_db_client)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Обновить аннотации сессии (например, после ревью).
|
|
|
|
|
|
|
|
|
|
|
|
Полностью заменяет существующие аннотации новыми.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
session_id: UUID сессии
|
|
|
|
|
|
update_data: Новые аннотации с ключами в виде числовых строк ('0', '1', ...)
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
SessionResponse: Обновленная сессия
|
|
|
|
|
|
"""
|
|
|
|
|
|
user_id = current_user["user_id"]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
updated_session = await db_client.update_session(user_id, session_id, update_data)
|
|
|
|
|
|
return updated_session
|
|
|
|
|
|
except httpx.HTTPStatusError as e:
|
|
|
|
|
|
if e.response.status_code == 404:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="Session not found"
|
|
|
|
|
|
)
|
|
|
|
|
|
elif e.response.status_code == 400:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
|
|
|
detail="Invalid annotations format"
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.error(f"Failed to update session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
|
|
|
|
detail="Failed to update session in DB API"
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Unexpected error updating session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="Internal server error"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-17 15:37:32 +01:00
|
|
|
|
@router.delete("/sessions/{session_id}", status_code=status.HTTP_204_NO_CONTENT)
|
|
|
|
|
|
async def delete_session(
|
|
|
|
|
|
session_id: str,
|
|
|
|
|
|
current_user: dict = Depends(get_current_user),
|
|
|
|
|
|
db_client: DBApiClient = Depends(get_db_client)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""
|
|
|
|
|
|
Удалить сессию.
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
session_id: UUID сессии
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
204 No Content при успехе
|
|
|
|
|
|
"""
|
|
|
|
|
|
user_id = current_user["user_id"]
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
await db_client.delete_session(user_id, session_id)
|
|
|
|
|
|
return None
|
|
|
|
|
|
except httpx.HTTPStatusError as e:
|
|
|
|
|
|
if e.response.status_code == 404:
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
|
|
|
|
detail="Session not found"
|
|
|
|
|
|
)
|
|
|
|
|
|
logger.error(f"Failed to delete session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_502_BAD_GATEWAY,
|
|
|
|
|
|
detail="Failed to delete session in DB API"
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"Unexpected error deleting session {session_id}: {e}")
|
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
|
|
detail="Internal server error"
|
|
|
|
|
|
)
|