Chepuhagram/srv/app/api/endpoints/messages.py

108 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from fastapi import Depends, APIRouter, HTTPException, Depends
from sqlalchemy.orm import Session
from app.db import models
from app.core.security import get_current_user
from app.api import schemas
from fastapi.encoders import jsonable_encoder
# бд
def get_db():
db = models.SessionLocal()
try:
yield db
finally:
db.close()
messagesRouter = APIRouter(
prefix="/messages",
tags=[],
)
@messagesRouter.get("/history/{contact_id}")
async def get_chat_history(
contact_id: int,
current_user: models.User = Depends(get_current_user),
db: Session = Depends(get_db),
anchor_id: int = None, # ID сообщения, вокруг которого строим выборку
limit_before: int = 20, # Сколько сообщений загрузить ДО (старше анкера)
limit_after: int = 20 # Сколько сообщений загрузить ПОСЛЕ (новее анкера)
):
# Базовый фильтр для получения сообщений конкретного диалога
chat_filter = (
((models.Message.sender_id == current_user.id) & (models.Message.receiver_id == contact_id)) |
((models.Message.sender_id == contact_id) & (models.Message.receiver_id == current_user.id))
)
# КЕЙС 1: Анкер не передан — отдаем самый "хвост" чата (последние свежие сообщения)
if anchor_id is None:
messages = db.query(models.Message).filter(chat_filter)\
.order_by(models.Message.id.desc())\
.limit(limit_before)\
.all()
print(f"DEBUG history (Tail): user={current_user.id}, contact={contact_id}, count={len(messages)}")
return jsonable_encoder(messages)
# КЕЙС 2: Передан anchor_id — собираем данные "вокруг" него
print(f"DEBUG history (Anchor): user={current_user.id}, contact={contact_id}, anchor={anchor_id}")
# 1. Тянем сообщения СТАРШЕ анкера (id < anchor_id)
# Сортируем DESC, чтобы взять ближайшие к анкеру сообщения
older_messages = db.query(models.Message).filter(chat_filter, models.Message.id < anchor_id)\
.order_by(models.Message.id.desc())\
.limit(limit_before)\
.all()
# 2. Тянем само якорное сообщение (чтобы оно гарантированно попало в выборку)
anchor_message = db.query(models.Message).filter(chat_filter, models.Message.id == anchor_id).first()
# 3. Тянем сообщения НОВЕЕ анкера (id > anchor_id)
# Сортируем ASC, чтобы взять идущие строго за анкером сообщения
newer_messages = db.query(models.Message).filter(chat_filter, models.Message.id > anchor_id)\
.order_by(models.Message.id.asc())\
.limit(limit_after)\
.all()
# Собираем все три куска в единый плоский список
combined_messages = older_messages + ([anchor_message] if anchor_message else []) + newer_messages
# ВАЖНО: Сортируем итоговый массив по убыванию (DESC),
# чтобы фронтенд получил структуру в привычном для него хронологическом порядке (от новых к старым)
combined_messages.sort(key=lambda msg: msg.id, reverse=True)
print(f"DEBUG history (Combined): total_count={len(combined_messages)}, older={len(older_messages)}, newer={len(newer_messages)}")
return jsonable_encoder(combined_messages)
@messagesRouter.get("/last")
async def get_last_messages(
contact_id: int,
current_user: models.User = Depends(get_current_user),
db: Session = Depends(get_db),
limit: int = 2
):
messages = db.query(models.Message).filter(
(models.Message.sender_id == current_user.id) & (models.Message.receiver_id == contact_id) |
(models.Message.sender_id == contact_id) & (models.Message.receiver_id == current_user.id)
).order_by(models.Message.timestamp.desc()).limit(limit).all()
return jsonable_encoder(messages)
@messagesRouter.delete("/all")
async def delete_all_messages(
current_user: models.User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""Удалить все сообщения пользователя"""
# Удаляем все сообщения, где пользователь либо отправитель, либо получатель
db.query(models.Message).filter(
(models.Message.sender_id == current_user.id) | (models.Message.receiver_id == current_user.id)
).delete()
db.commit()
return {"status": "ok", "detail": "Все сообщения удалены"}