/
euorik
/
devAPP
Обзор
Документация
Войти
/
euorik
/
devAPP
Код
Запросы
0
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
app/api/v1/endpoints/chat.py
150 строк
4 KB
euorik
Добавил эндпоинт Chats
01 авг 2026, 03:50
01 авг 2026, 03:50
6af92bc
Код
Авторство
О чём код?
import os from datetime import datetime from typing import List, Optional from fastapi import APIRouter, HTTPException, Depends, Header, Cookie, Query, status from pydantic import BaseModel # Импортируем функции авторизации из auth.py from api.v1.endpoints.auth import ( decode_token, get_cached_user, is_token_blacklisted, get_session, get_redis, User, UserOut, ACCESS_TOKEN_EXPIRE_MINUTES, SECRET_KEY, ALGORITHM ) chat_rout = APIRouter(tags=["Chat"]) # --- In-memory хранилище сообщений --- messages: List[dict] = [] message_id_counter = 0 # --- Pydantic схемы --- class MessageCreate(BaseModel): text: str reply_to_id: Optional[int] = None class MessageOut(BaseModel): id: int user_id: int username: str text: str reply_to_id: Optional[int] = None created_at: datetime # --- Авторизация через Header или Cookie --- async def get_current_user( authorization: Optional[str] = Header(None), access_token: Optional[str] = Cookie(None), session=Depends(get_session), ) -> User: token = None if authorization and authorization.startswith("Bearer "): token = authorization.split(" ", 1)[1] elif access_token: token = access_token if not token: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated. Provide Bearer token in Authorization header or access_token cookie.", ) if await is_token_blacklisted(token): raise HTTPException(status_code=401, detail="Token has been revoked") payload = decode_token(token) email = payload.get("sub") if not email: raise HTTPException(status_code=401, detail="Invalid token payload") cached_user = await get_cached_user(email) if cached_user: return User( id=cached_user["id"], username=cached_user["username"], email=cached_user["email"], password="", created_at=datetime.fromisoformat(cached_user["created_at"]), ) from sqlalchemy import select result = await session.execute(select(User).where(User.email == email)) db_user = result.scalar_one_or_none() if not db_user: raise HTTPException(status_code=404, detail="User not found") return db_user # --- Вспомогательная функция поиска сообщения --- def find_message_by_id(message_id: int) -> Optional[dict]: for msg in messages: if msg["id"] == message_id: return msg return None # --- Эндпоинты --- @chat_rout.post("/send", response_model=MessageOut, status_code=status.HTTP_201_CREATED) async def send_message( message: MessageCreate, current_user: User = Depends(get_current_user), ): global message_id_counter # Проверка: если указан reply_to_id, такое сообщение должно существовать replied_message = None if message.reply_to_id is not None: replied_message = find_message_by_id(message.reply_to_id) if not replied_message: raise HTTPException(status_code=404, detail="Message to reply not found") message_id_counter += 1 new_message = { "id": message_id_counter, "user_id": current_user.id, "username": current_user.username, "text": message.text, "reply_to_id": message.reply_to_id, "created_at": datetime.utcnow(), } messages.append(new_message) # Сохраняем в Redis (опционально) r = await get_redis() await r.lpush("chat:messages", str(new_message)) await r.ltrim("chat:messages", 0, 99) return MessageOut(**new_message) @chat_rout.get("/history", response_model=List[MessageOut]) async def get_history( limit: int = Query(50, ge=1, le=100), current_user: User = Depends(get_current_user), ): return [MessageOut(**msg) for msg in messages[-limit:]] @chat_rout.get("/me", response_model=UserOut) async def get_my_profile(current_user: User = Depends(get_current_user)): return UserOut( id=current_user.id, username=current_user.username, email=current_user.email, created_at=current_user.created_at, )