feat(chat): 单向聊天可二次激活 单向聊天可二次激活,未删除方聊天消息保留,双向删除后记录清空
This commit is contained in:
@@ -10,7 +10,7 @@ from fastapi import WebSocket
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from core.db.crud import CRUD
|
||||
from core.db.models import ReadStatus, User, Chat, Message
|
||||
from core.db.models import ChatParticipant, User, Chat, Message
|
||||
|
||||
from .managers import SocketManager
|
||||
from . import schema
|
||||
@@ -29,7 +29,6 @@ async def send_new_message(
|
||||
incoming_message: schema.WSMessage,
|
||||
):
|
||||
chat_guid: str = str(incoming_message.chat_guid)
|
||||
# chat: Chat | None = await CRUD(db_session, Chat).get(filters={'guid': chat_guid, 'is_deleted': False}
|
||||
chat: Chat | None = await get_chat(chat_guid, current_user, db_session)
|
||||
|
||||
# 判断是否为新聊天
|
||||
@@ -73,16 +72,7 @@ async def send_new_message(
|
||||
content=message.content,
|
||||
friend_user=current_user.dict(),
|
||||
)
|
||||
send_status_replay = schema.WSMessageOut(
|
||||
type='chat.send_status_reply',
|
||||
message_id=message.id,
|
||||
message_guid=message.guid,
|
||||
message_type=message.message_type,
|
||||
chat_guid=chat.guid,
|
||||
)
|
||||
|
||||
await socket_manager.broadcast_to_chat(chat_guid, send_message_schema.model_dump_json())
|
||||
await websocket.send_text(send_status_replay.model_dump_json())
|
||||
|
||||
|
||||
@socket_manager.handler('chat.message_read')
|
||||
@@ -90,16 +80,23 @@ async def read_message(
|
||||
websocket: WebSocket,
|
||||
db_session: AsyncSession,
|
||||
current_user: User,
|
||||
chats: dict,
|
||||
incoming_message: schema.WSMessage,
|
||||
):
|
||||
last_read_message_id: str | None = incoming_message.content
|
||||
if not last_read_message_id:
|
||||
return
|
||||
|
||||
db_crud = CRUD(db_session, ReadStatus)
|
||||
db_crud = CRUD(db_session, ChatParticipant)
|
||||
chat_guid: str = str(incoming_message.chat_guid)
|
||||
chat: Chat | None = await get_chat(chat_guid, current_user, db_session)
|
||||
if chat is None:
|
||||
await socket_manager.send_error('聊天尚未添加', websocket)
|
||||
return
|
||||
|
||||
condition = {
|
||||
'user_id': current_user.user_id,
|
||||
'chat_guid': incoming_message.chat_guid,
|
||||
'chat_id': chat.id,
|
||||
}
|
||||
result = await db_crud.update(filters=condition, data={'last_read_message_id': last_read_message_id})
|
||||
if result is None:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -11,7 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import aliased, selectinload
|
||||
|
||||
from core.base.exceptions import WebsocketTooManyRequests
|
||||
from core.db.models import User, Chat, ReadStatus, Message, ChatParticipant
|
||||
from core.db.models import User, Chat, Message, ChatParticipant
|
||||
from core.routers.auth.schema import LoginUser
|
||||
from core.utils.helper import format_date
|
||||
|
||||
@@ -44,7 +44,7 @@ async def get_user_active_direct_chats(
|
||||
async def get_chat_unread_messages_count(db_session: AsyncSession, login_user: LoginUser, chats):
|
||||
"""查询未读消息的预览"""
|
||||
# 查询消息情况
|
||||
read_status_alias = aliased(ReadStatus)
|
||||
read_status_alias = aliased(ChatParticipant)
|
||||
query = (
|
||||
select(Message.chat_id, func.count().label("message_count"))
|
||||
.join(
|
||||
|
||||
Reference in New Issue
Block a user