feat(campaigns): delete campaign button + defer Jira to Activate
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled
- Backend: add DELETE /campaigns/{id}?delete_tests=bool endpoint
- Backend: add delete_campaign() service — handles draft-only restriction,
optional test deletion, nullifies child campaign FKs
- Backend: remove early Jira ticket creation from POST /campaigns,
POST /campaigns/{id}/tests, and POST /campaigns/from-threat-actor
- Backend: activate endpoint now creates campaign Jira ticket if missing,
then creates test tickets (all deferred from creation to activation)
- Frontend: add deleteCampaign() API function to campaigns.ts
- Frontend: two-step confirmation dialog on CampaignDetailPage —
first confirms deletion, then asks whether to also delete associated tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,6 +21,7 @@ from app.services.campaign_crud_service import (
|
||||
activate_campaign as crud_activate,
|
||||
complete_campaign as crud_complete,
|
||||
create_campaign as crud_create,
|
||||
delete_campaign as crud_delete,
|
||||
get_campaign_detail as crud_get_detail,
|
||||
get_campaign_history as crud_get_history,
|
||||
get_campaign_progress_data as crud_get_progress,
|
||||
@@ -133,17 +134,6 @@ def create_campaign(
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# Auto-create Jira ticket for campaign under OFS-9107 (non-fatal)
|
||||
try:
|
||||
from app.services.jira_service import auto_create_campaign_issue
|
||||
from app.models.campaign import Campaign as CampaignModel
|
||||
campaign_obj = db.query(CampaignModel).filter(CampaignModel.id == campaign_id).first()
|
||||
if campaign_obj:
|
||||
auto_create_campaign_issue(db, campaign_obj, current_user)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception("Jira campaign ticket creation failed for campaign %s", campaign_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -195,6 +185,37 @@ def update_campaign(
|
||||
return result
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# DELETE /campaigns/{id} — Delete campaign
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@router.delete("/{campaign_id}", status_code=204)
|
||||
def delete_campaign(
|
||||
campaign_id: str,
|
||||
delete_tests: bool = Query(False, description="Also delete associated tests"),
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Delete a campaign. Only draft campaigns can be deleted (admins can delete any)."""
|
||||
with UnitOfWork(db) as uow:
|
||||
crud_delete(
|
||||
db,
|
||||
campaign_id,
|
||||
deleter_id=current_user.id,
|
||||
deleter_role=current_user.role,
|
||||
delete_tests=delete_tests,
|
||||
)
|
||||
log_action(
|
||||
db,
|
||||
user_id=current_user.id,
|
||||
action="delete_campaign",
|
||||
entity_type="campaign",
|
||||
entity_id=campaign_id,
|
||||
details={"delete_tests": delete_tests},
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# POST /campaigns/{id}/tests — Add test to campaign
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -218,32 +239,6 @@ def add_test_to_campaign(
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# If the campaign has a Jira ticket and the test doesn't, create a test
|
||||
# ticket nested under the campaign ticket (non-fatal).
|
||||
try:
|
||||
from app.services.jira_service import (
|
||||
auto_create_test_issue,
|
||||
get_campaign_jira_key,
|
||||
get_test_jira_key,
|
||||
)
|
||||
from app.models.test import Test as TestModel
|
||||
campaign_jira_key = get_campaign_jira_key(db, campaign_id)
|
||||
if campaign_jira_key:
|
||||
existing_test_key = get_test_jira_key(db, payload.test_id)
|
||||
if not existing_test_key:
|
||||
test_obj = db.query(TestModel).filter(TestModel.id == payload.test_id).first()
|
||||
if test_obj:
|
||||
auto_create_test_issue(
|
||||
db, test_obj, current_user,
|
||||
parent_ticket_override=campaign_jira_key,
|
||||
)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Jira test ticket creation failed for test %s in campaign %s",
|
||||
payload.test_id, campaign_id,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -298,15 +293,18 @@ def activate_campaign(
|
||||
uow.commit()
|
||||
db.refresh(campaign)
|
||||
|
||||
# Create Jira test tickets for any campaign tests that don't have one yet,
|
||||
# nested under the campaign's Jira ticket (non-fatal).
|
||||
# Create Jira tickets for campaign and tests at activation time (non-fatal).
|
||||
# Campaign ticket is created here if it doesn't already exist (deferred from creation).
|
||||
try:
|
||||
from app.services.jira_service import (
|
||||
auto_create_campaign_issue,
|
||||
auto_create_test_issue,
|
||||
get_campaign_jira_key,
|
||||
get_test_jira_key,
|
||||
)
|
||||
campaign_jira_key = get_campaign_jira_key(db, campaign_id)
|
||||
if not campaign_jira_key:
|
||||
campaign_jira_key = auto_create_campaign_issue(db, campaign, current_user)
|
||||
if campaign_jira_key:
|
||||
for ct in campaign.campaign_tests:
|
||||
if ct.test and not get_test_jira_key(db, ct.test.id):
|
||||
@@ -314,10 +312,10 @@ def activate_campaign(
|
||||
db, ct.test, current_user,
|
||||
parent_ticket_override=campaign_jira_key,
|
||||
)
|
||||
db.commit()
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Jira test ticket creation failed during activation of campaign %s",
|
||||
"Jira ticket creation failed during activation of campaign %s",
|
||||
campaign_id,
|
||||
)
|
||||
|
||||
@@ -398,24 +396,6 @@ def generate_campaign_from_actor(
|
||||
)
|
||||
uow.commit()
|
||||
|
||||
# Auto-create Jira tickets: campaign under OFS-9107, each test under campaign ticket (non-fatal)
|
||||
try:
|
||||
from app.services.jira_service import auto_create_campaign_issue, auto_create_test_issue
|
||||
db.refresh(campaign)
|
||||
campaign_ticket = auto_create_campaign_issue(db, campaign, current_user)
|
||||
if campaign_ticket:
|
||||
for ct in campaign.campaign_tests:
|
||||
if ct.test:
|
||||
auto_create_test_issue(
|
||||
db, ct.test, current_user,
|
||||
parent_ticket_override=campaign_ticket,
|
||||
)
|
||||
db.commit()
|
||||
except Exception:
|
||||
logger.exception(
|
||||
"Jira ticket creation failed for auto-generated campaign %s", campaign.id
|
||||
)
|
||||
|
||||
return serialize_campaign(db, campaign)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user