From 18548eb78fcc6db524e63b05c0456ac899b46f0a Mon Sep 17 00:00:00 2001 From: bruce Date: Tue, 9 Jun 2026 08:22:45 +0800 Subject: [PATCH] =?UTF-8?q?fix(file-summary):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E5=AF=B9=E8=AF=9D=E6=97=B6=E5=8F=97=E4=BF=9D?= =?UTF-8?q?=E6=8A=A4=E6=89=B9=E6=AC=A1=E9=98=BB=E5=A1=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- review_agent/file_summary/views.py | 15 +++++++++++-- tests/test_file_summary_views.py | 34 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) 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")