"""消息路由""" from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_db, get_current_user from app.models.user import User from app.schemas.message import MessageSend, MessagePage, MarkReadRequest from app.services.message_service import MessageService from app.services.conversation_service import ConversationService router = APIRouter() @router.get("/{conversation_id}/messages", response_model=dict) async def get_messages( conversation_id: str, before: str | None = Query(None), limit: int = Query(50, ge=1, le=100), user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """获取消息列表(游标分页)""" service = MessageService(db) try: return await service.get_messages(conversation_id, user.id, before, limit) except ValueError as e: raise HTTPException(status_code=403, detail=str(e)) @router.get("/{conversation_id}/messages/search") async def search_messages( conversation_id: str, q: str = Query(..., min_length=1, max_length=200), limit: int = Query(20, ge=1, le=50), user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """在会话内搜索消息(用户级)""" # 验证成员身份 conv_service = ConversationService(db) detail = await conv_service.get_conversation_detail(conversation_id, user.id) if not detail: raise HTTPException(status_code=403, detail="无权访问该会话") service = MessageService(db) results = await service.search_messages( conversation_id=conversation_id, keyword=q, limit=limit, ) return {"results": results} @router.put("/{conversation_id}/messages/{message_id}/read") async def mark_as_read( conversation_id: str, message_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """标记消息已读""" service = MessageService(db) await service.mark_as_read(conversation_id, user.id, message_id) return {"success": True} @router.delete("/{conversation_id}/messages/{message_id}") async def delete_message( conversation_id: str, message_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """删除消息""" service = MessageService(db) try: await service.soft_delete(message_id, user.id) return {"success": True} except ValueError as e: raise HTTPException(status_code=403, detail=str(e)) @router.post("/{conversation_id}/messages/{message_id}/recall") async def recall_message( conversation_id: str, message_id: str, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """撤回消息(2 分钟内)""" service = MessageService(db) try: await service.recall_message(message_id, user.id) # 广播撤回事件 from app.services.conversation_service import ConversationService conv_service = ConversationService(db) detail = await conv_service.get_conversation_detail(conversation_id, user.id) if detail and "members" in detail: from app.websocket.events import EventType from app.websocket.manager import manager member_ids = [m["user_id"] for m in detail["members"]] for uid in member_ids: await manager.send_to_user(uid, EventType.CHAT_MESSAGE_RECALLED, { "conversation_id": conversation_id, "message_id": message_id, "recalled_by": user.id, }) return {"success": True} except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) @router.post("/{conversation_id}/messages/{message_id}/reactions") async def add_reaction( conversation_id: str, message_id: str, body: dict, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): """添加/取消表情回应(toggle)""" service = MessageService(db) result = await service.react(message_id, user.id, body.get("emoji", "")) # 广播回应变化 from app.services.conversation_service import ConversationService from app.websocket.events import EventType from app.websocket.manager import manager conv_service = ConversationService(db) detail = await conv_service.get_conversation_detail(conversation_id, user.id) if detail and "members" in detail: member_ids = [m["user_id"] for m in detail["members"]] etype = EventType.CHAT_REACTION_ADDED if result["action"] == "added" else EventType.CHAT_REACTION_REMOVED for uid in member_ids: await manager.send_to_user(uid, etype, { "conversation_id": conversation_id, "message_id": message_id, "emoji": result["emoji"], "user_id": user.id, }) return result