feat(chat): 单向聊天可二次激活 单向聊天可二次激活,未删除方聊天消息保留,双向删除后记录清空

This commit is contained in:
xingc
2025-05-16 23:20:02 +08:00
parent 2bbb39529b
commit 72dec3b757
5 changed files with 117 additions and 47 deletions

View File

@@ -17,7 +17,7 @@ from sqlalchemy.orm import selectinload
from core.base import schema as base_schema
from core.db.crud import CRUD
from core.db.engine import get_async_session
from core.db.models import Message, Chat, User, ReadStatus, ChatParticipant
from core.db.models import Message, Chat, User, ChatParticipant
from core.routers.auth.schema import LoginUser
from core.routers.auth.services import get_current_user_form_http, get_current_user_form_ws
from core.base.exceptions import WebsocketTooManyRequests
@@ -100,10 +100,14 @@ async def get_single_chat_messages(
if not chat:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='您访问的聊天不存在')
read_status = await CRUD(db_session, ChatParticipant).get(
filters={'chat_id': chat.id, 'user_id': login_user.user_id})
# 组装查询条件
conditions = and_(
Message.chat_id == chat.id,
Message.id <= last_read_message_id
Message.id > (read_status.last_del_message_id or 0),
Message.id <= last_read_message_id,
)
# 记录总数查询
@@ -152,11 +156,13 @@ async def create_new_chat(
if payload.recipient_user_id == login_user.user_id:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail='操作禁止')
recipient_user: User | None = await CRUD(db_session, User).get(filters={'user_id': payload.recipient_user_id})
db_crud = CRUD(db_session, User)
recipient_user: User | None = await db_crud.get(filters={'user_id': payload.recipient_user_id})
if recipient_user is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='收件人不存在')
initiator_user: User = await CRUD(db_session, User).get(filters={'user_id': login_user.user_id})
initiator_user: User = await db_crud.get(filters={'user_id': login_user.user_id})
# 查询是否已存在 对应且未关闭的聊天
query = (
select(Chat)
@@ -170,7 +176,7 @@ async def create_new_chat(
(ChatParticipant.chat_id == Chat.id) &
(ChatParticipant.user_id == recipient_user.user_id)
),
Chat.is_deleted == False
# Chat.is_deleted == False
)
).order_by(Chat.created_at.desc())
)
@@ -184,16 +190,16 @@ async def create_new_chat(
chat.users.append(recipient_user)
db_session.add(chat)
await db_session.flush()
initiator_read_status = ReadStatus(chat_id=chat.id, user_id=initiator_user.user_id, last_read_message_id=0)
recipient_read_status = ReadStatus(chat_id=chat.id, user_id=recipient_user.user_id, last_read_message_id=0)
db_session.add_all([initiator_read_status, recipient_read_status])
await db_session.commit()
except Exception as exc_info:
await db_session.rollback()
raise exc_info
if chat.is_deleted is True:
await db_crud.updates(model=Chat, data={'is_deleted': False}, filters={'id': chat.id})
await db_crud.updates(model=ChatParticipant, data={'is_deleted': False}, filters={'chat_id': chat.id})
return {
'data': {
'chat_guid': chat.guid,
@@ -219,12 +225,21 @@ async def delete_single_chat(
Chat.id.in_(subquery),
Chat.guid == chat_guid
))
.options(selectinload(Chat.chat_participants))
)
result = await db_session.execute(query)
chat = result.scalar_one_or_none()
if chat is None:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail='聊天不存在')
deleted_status = [
chat_participant.is_deleted
for chat_participant in chat.chat_participants if chat_participant.user_id != login_user.user_id
]
if all(deleted_status):
await db_session.delete(chat)
await db_session.commit()
else:
db_curd = CRUD(db_session, Chat)
await db_curd.update(
@@ -232,10 +247,21 @@ async def delete_single_chat(
filters={'id': chat.id},
)
message_query = (
select(Message).where(Message.chat_id == chat.id).order_by(Message.id.desc()).limit(1)
)
message_result = await db_session.execute(message_query)
message: Message | None = message_result.scalar()
condition = {'user_id': login_user.user_id, 'chat_id': chat.id}
data = {'is_deleted': True}
if message:
data['last_del_message_id'] = message.id
await db_curd.update(
model=ChatParticipant,
data={'is_deleted': True},
filters={'user_id': login_user.user_id, 'chat_id': chat.id},
data=data,
filters=condition,
)
return {'message': '聊天已删除'}
@@ -287,6 +313,15 @@ async def get_chat_websocket(
incoming_message=message,
)
send_status_replay = schema.WSMessageOut(
type='chat.send_status_reply',
message_id=-1,
message_guid=message.message_guid,
message_type=message.message_type,
chat_guid=message.chat_guid,
)
await websocket.send_text(send_status_replay.model_dump_json(exclude_none=True))
except (JSONDecodeError, AttributeError) as exc:
logger.exception(f'Websocket error, detail: {exc}')
await socket_manager.send_error('Wrong message format', websocket)