新增历史会话删除接口
This commit is contained in:
parent
0eecb9dc3c
commit
736a6653de
@ -57,6 +57,16 @@ async def get_conversation(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/{conversation_id}", response_model=ApiResponse[None])
|
||||||
|
async def delete_conversation(
|
||||||
|
conversation_id: int,
|
||||||
|
session: DatabaseSession,
|
||||||
|
current_user: Annotated[UserAccount, Depends(require_permission("risk.assess", operate=True))],
|
||||||
|
) -> ApiResponse[None]:
|
||||||
|
await ConversationService(session).delete(conversation_id, current_user)
|
||||||
|
return ApiResponse(data=None, message="对话已删除")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{conversation_id}/messages", response_model=ApiResponse[ConversationData])
|
@router.post("/{conversation_id}/messages", response_model=ApiResponse[ConversationData])
|
||||||
async def send_conversation_message(
|
async def send_conversation_message(
|
||||||
conversation_id: int,
|
conversation_id: int,
|
||||||
|
|||||||
@ -71,3 +71,13 @@ class ConversationRepository:
|
|||||||
.options(selectinload(Conversation.messages))
|
.options(selectinload(Conversation.messages))
|
||||||
)
|
)
|
||||||
return await self.session.scalar(statement)
|
return await self.session.scalar(statement)
|
||||||
|
|
||||||
|
async def delete_for_user(self, conversation_id: int, user_id: int) -> bool:
|
||||||
|
"""Delete a conversation only when it belongs to the requesting user."""
|
||||||
|
|
||||||
|
conversation = await self.get_for_user(conversation_id, user_id)
|
||||||
|
if conversation is None:
|
||||||
|
return False
|
||||||
|
await self.session.delete(conversation)
|
||||||
|
await self.session.flush()
|
||||||
|
return True
|
||||||
|
|||||||
@ -128,6 +128,24 @@ class ConversationService:
|
|||||||
raise AppException("对话创建失败", code=500, status_code=500)
|
raise AppException("对话创建失败", code=500, status_code=500)
|
||||||
return self._data(persisted, messages=[], total=0, offset=0)
|
return self._data(persisted, messages=[], total=0, offset=0)
|
||||||
|
|
||||||
|
async def delete(self, conversation_id: int, user: UserAccount) -> None:
|
||||||
|
"""Delete one user-owned conversation and retain an audit trail."""
|
||||||
|
|
||||||
|
conversation = await self.repository.get_for_user(conversation_id, user.id)
|
||||||
|
if conversation is None:
|
||||||
|
raise AppException("对话不存在或无权访问", code=404, status_code=404)
|
||||||
|
self.session.add(
|
||||||
|
OperationAudit(
|
||||||
|
actor_user_id=user.id,
|
||||||
|
actor_emp_no=user.emp_no,
|
||||||
|
action="conversation.delete",
|
||||||
|
resource_type="conversation",
|
||||||
|
resource_id=str(conversation_id),
|
||||||
|
audit_metadata={"title": conversation.title[:120]},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await self.repository.delete_for_user(conversation_id, user.id)
|
||||||
|
|
||||||
async def send(
|
async def send(
|
||||||
self,
|
self,
|
||||||
conversation_id: int,
|
conversation_id: int,
|
||||||
|
|||||||
19
tests/test_conversation_delete.py
Normal file
19
tests/test_conversation_delete.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from app.models.entities import Conversation, UserAccount
|
||||||
|
from app.services.conversations import ConversationService
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delete_conversation_rejects_conversation_owned_by_another_user() -> None:
|
||||||
|
service = object.__new__(ConversationService)
|
||||||
|
|
||||||
|
class Repository:
|
||||||
|
async def get_for_user(self, conversation_id, user_id):
|
||||||
|
return None
|
||||||
|
|
||||||
|
service.repository = Repository()
|
||||||
|
service.session = object()
|
||||||
|
with pytest.raises(Exception) as exc_info:
|
||||||
|
await service.delete(10, UserAccount(id=2, emp_no="u2", name="用户", role="user"))
|
||||||
|
assert getattr(exc_info.value, "status_code", None) == 404
|
||||||
Loading…
x
Reference in New Issue
Block a user