from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.exc import SQLAlchemyError from app.services.db_manager import DatabaseManager from instance.configdb import get_database_manager from uuid import UUID from pydantic import BaseModel from fastapi import Response, status from enum import Enum from typing import List, Literal, Optional from datetime import datetime import logging logger = logging.getLogger(__name__) class UpdateTicketStatusRequest(BaseModel): new_status: str class TicketStatus(str, Enum): OPEN = "open" PENDING = "pending" CLOSED = "closed" class CreateTicketRequest(BaseModel): subject: str message: str class TicketResponse(BaseModel): id: int user_id: UUID subject: str message: str status: TicketStatus created_at: datetime updated_at: datetime class TicketMessageRequest(BaseModel): message: str class TicketMessageResponse(BaseModel): ticket_id: int sender: str message: str created_at: datetime router = APIRouter() def handle_exception(e: Exception, message: str): logger.error(f"{message}: {e}") raise HTTPException(status_code=500, detail=f"{message}: {str(e)}") @router.post("/support/tickets/{ticket_id}/messages", summary="Добавить сообщение") async def add_message( ticket_id: int, request: TicketMessageRequest, sender: Literal["user", "support"], # "user" или "support" database_manager: DatabaseManager = Depends(get_database_manager) ): """ Добавляет сообщение в тикет. Args: ticket_id (int): ID тикета. request (TicketMessageRequest): Данные сообщения. sender (str): Отправитель ("user" или "support"). database_manager (DatabaseManager): Управление базой данных. Returns: TicketMessageResponse: Данные созданного сообщения. """ try: message = await database_manager.add_message_to_ticket(ticket_id=ticket_id, sender=sender, message=request.message) if not message: raise HTTPException(status_code=404, detail="Тикет не найден или ошибка добавления сообщения") if message != "OK": raise HTTPException(status_code=500, detail="Ошибка добавления сообщения") return Response(status_code=status.HTTP_200_OK) except Exception as e: handle_exception(e,"Ошибка добавления сообщения") @router.get("/support/tickets/{ticket_id}/messages", response_model=List[TicketMessageResponse], summary="Получить сообщения") async def get_messages( ticket_id: int, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Возвращает список сообщений в тикете. Args: ticket_id (int): ID тикета, для которого нужно получить сообщения. database_manager (DatabaseManager): Менеджер базы данных. Returns: List[TicketMessageResponse]: Список сообщений, связанных с тикетом. Raises: HTTPException: 404, если сообщения для тикета не найдены. HTTPException: 500, если произошла ошибка на сервере. """ try: messages = await database_manager.get_ticket_messages(ticket_id=ticket_id) ticket_info = await database_manager.get_ticket(ticket_id) logger.info(messages) result_messages = [] if messages: for message in messages: correct_response = TicketMessageResponse( ticket_id=ticket_id, sender=message.sender, message=message.message, created_at=message.created_at ) result_messages.append(correct_response) result_messages.insert(0, TicketMessageResponse( ticket_id=ticket_id, sender="user", message=ticket_info['message'], created_at=ticket_info["created_at"] ) ) return result_messages except Exception as e: handle_exception(e,"Ошибка получения сообщения") @router.get("/support/ticket/{ticket_id}", response_model=TicketResponse, summary="Получить информацию о тикете") async def get_ticket( ticket_id: int, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Возвращает информацию о тикете. Args: ticket_id (int): ID тикета, информацию котрого хочет получить пользователь. database_manager (DatabaseManager): Менеджер базы данных. Returns: TicketResponse: Информация о тикете. Raises: HTTPException: 404, если тикет не найден. HTTPException: 500, если произошла ошибка на сервере. """ try: # Получаем данные о тикете ticket = await database_manager.get_ticket(ticket_id=ticket_id) if not ticket: raise HTTPException(status_code=404, detail="Тикет не найден") # Возвращаем данные через Pydantic-модель return TicketResponse(**ticket) except SQLAlchemyError as e: handle_exception(e, "Ошибка получения тикета") except Exception as e: handle_exception(e, "Неизвестная ошибка при получении тикета") @router.post("/support/tickets", response_model=TicketResponse, summary="Создать тикет") async def create_ticket( request: CreateTicketRequest, user_id: UUID, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Создаёт новый тикет для пользователя. Args: request (CreateTicketRequest): Данные для создания тикета (тема и сообщение). user_id (UUID): Идентификатор пользователя, создающего тикет. database_manager (DatabaseManager): Менеджер базы данных. Returns: TicketResponse: Данные созданного тикета. Raises: HTTPException: 500, если произошла ошибка при создании тикета. """ try: ticket = await database_manager.create_ticket( user_id=user_id, subject=request.subject, message=request.message ) return ticket except Exception as e: handle_exception(e,"Ошибка содания тикета") @router.get("/support/tickets", response_model=List[TicketResponse], summary="Получить список тикетов") async def list_tickets( user_id: UUID, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Возвращает список тикетов пользователя. Args: user_id (UUID): Идентификатор пользователя, чьи тикеты нужно получить. database_manager (DatabaseManager): Менеджер базы данных. Returns: List[TicketResponse]: Список тикетов пользователя. Raises: HTTPException: 404, если тикеты не найдены. HTTPException: 500, если произошла ошибка на сервере. """ try: tickets = await database_manager.get_active_tickets(user_id=user_id) if not tickets: raise HTTPException(status_code=404, detail="Тикеты не найдены") return tickets except Exception as e: handle_exception(e,"Ошибка получения тикетов") @router.patch("/support/ticket/{ticket_id}/status", summary="Обновить статус тикета") async def update_ticket_status( ticket_id: int, request: UpdateTicketStatusRequest, database_manager: DatabaseManager = Depends(get_database_manager) ): """ Обновляет статус тикета. Args: ticket_id (int): ID тикета. request (UpdateTicketStatusRequest): Запрос с новым статусом. database_manager (DatabaseManager): Менеджер базы данных. Returns: dict: Подтверждение обновления статуса. Raises: HTTPException: Если тикет не найден или произошла ошибка. """ try: result = await database_manager.update_ticket_status(ticket_id, request.new_status) if result != "OK": return "ERROR" return "OK" except ValueError as e: logger.error(f"Тикет с ID {ticket_id} не найден: {e}") raise HTTPException(status_code=404, detail="Тикет не найден.") except Exception as e: logger.error(f"Ошибка обновления статуса тикета {ticket_id}: {e}") raise HTTPException(status_code=500, detail="Не удалось обновить статус тикета.")