diff --git a/review_agent/file_summary/views.py b/review_agent/file_summary/views.py index cb701cf..b71ed75 100644 --- a/review_agent/file_summary/views.py +++ b/review_agent/file_summary/views.py @@ -1,4 +1,5 @@ from django.contrib.auth.decorators import login_required +from django.db import transaction from django.db.models import Count, Q import json import logging @@ -7,7 +8,14 @@ from pathlib import Path from django.http import FileResponse, Http404, JsonResponse from django.views.decorators.http import require_http_methods -from review_agent.models import ApplicationFormFillBatch, Conversation, ExportedSummaryFile, FileAttachment, Message +from review_agent.models import ( + ApplicationFormFillBatch, + Conversation, + ExportedSummaryFile, + FileAttachment, + Message, + RegulatoryReviewBatch, +) from review_agent.models import FileSummaryBatch, WorkflowEvent from review_agent.notifications.presenter import serialize_notification_records from .events import serialize_event @@ -152,7 +160,10 @@ def conversation_list(request): @login_required def conversation_detail(request, conversation_id: int): conversation = _conversation_for_user(request.user, conversation_id) - conversation.delete() + with transaction.atomic(): + ApplicationFormFillBatch.objects.filter(conversation=conversation).delete() + RegulatoryReviewBatch.objects.filter(conversation=conversation).delete() + conversation.delete() return JsonResponse({"ok": True, "conversation_id": conversation_id}) diff --git a/tests/test_file_summary_views.py b/tests/test_file_summary_views.py index b6b277f..c4a8a83 100644 --- a/tests/test_file_summary_views.py +++ b/tests/test_file_summary_views.py @@ -10,6 +10,7 @@ from review_agent.models import ( FileAttachment, FileSummaryBatch, Message, + RegulatoryReviewBatch, WorkflowNodeRun, ) @@ -269,6 +270,39 @@ def test_conversation_delete_api_removes_owned_conversation(client, django_user_ assert Conversation.objects.filter(pk=other_conversation.pk).exists() +def test_conversation_delete_api_removes_protected_workflow_dependents(client, django_user_model): + user = django_user_model.objects.create_user(username="owner", password="pass") + conversation = Conversation.objects.create(user=user, title="待删除") + summary_batch = FileSummaryBatch.objects.create( + conversation=conversation, + user=user, + batch_no="FS-DELETE-PROTECTED", + ) + regulatory_batch = RegulatoryReviewBatch.objects.create( + conversation=conversation, + user=user, + source_summary_batch=summary_batch, + batch_no="RR-DELETE-PROTECTED", + ) + form_batch = ApplicationFormFillBatch.objects.create( + conversation=conversation, + user=user, + source_summary_batch=summary_batch, + source_regulatory_batch=regulatory_batch, + batch_no="AFF-DELETE-PROTECTED", + ) + client.force_login(user) + + response = client.delete(reverse("review_agent_conversation_detail", args=[conversation.pk])) + + assert response.status_code == 200 + assert response.json()["ok"] is True + assert not Conversation.objects.filter(pk=conversation.pk).exists() + assert not FileSummaryBatch.objects.filter(pk=summary_batch.pk).exists() + assert not RegulatoryReviewBatch.objects.filter(pk=regulatory_batch.pk).exists() + assert not ApplicationFormFillBatch.objects.filter(pk=form_batch.pk).exists() + + def test_conversation_delete_api_rejects_unowned_conversation(client, django_user_model): user = django_user_model.objects.create_user(username="owner", password="pass") other = django_user_model.objects.create_user(username="other", password="pass")