108 lines
4.9 KiB
Python
108 lines
4.9 KiB
Python
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": "Все сообщения удалены"}
|
||
|