fix(campaigns): start_date modal + hide future-campaign tests from queue
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled

Backend: activate endpoint returns 409 with structured warning when
start_date is in the future; accepts force=true to bypass.
test_crud_service: always excludes tests from draft campaigns with future
start_date so they do not appear in the team queue prematurely.

Frontend: catches 409 on activate and shows amber confirmation modal
with Keep scheduled / Activate now anyway options.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kitos
2026-06-04 14:05:58 +02:00
parent f8418bc7ea
commit 4c230caa32
4 changed files with 91 additions and 19 deletions

View File

@@ -273,28 +273,33 @@ def remove_test_from_campaign(
@router.post("/{campaign_id}/activate")
def activate_campaign(
campaign_id: str,
force: bool = Query(False, description="Activate even if start_date is in the future"),
db: Session = Depends(get_db),
current_user: User = Depends(require_any_role("red_lead", "blue_lead")),
):
"""Activate a campaign, moving it from draft to active.
If the campaign has a start_date in the future, manual activation is blocked —
the campaign will be auto-activated by the scheduler when the date arrives.
If the campaign has a start_date in the future and force=False, returns a 409
with a warning so the frontend can show a confirmation modal. If force=True,
activates immediately regardless of start_date.
"""
# Guard: start_date must have been reached before manual activation
from fastapi import HTTPException
campaign_obj = db.query(Campaign).filter(Campaign.id == campaign_id).first()
if campaign_obj and campaign_obj.start_date:
if campaign_obj and campaign_obj.start_date and not force:
now = datetime.utcnow()
if campaign_obj.start_date > now:
from fastapi import HTTPException
raise HTTPException(
status_code=422,
detail=(
f"This campaign is scheduled to start on "
f"{campaign_obj.start_date.strftime('%Y-%m-%d')}. "
f"It will be activated automatically on that date. "
f"To activate it now, remove the start date first."
),
status_code=409,
detail={
"code": "start_date_in_future",
"start_date": campaign_obj.start_date.strftime("%Y-%m-%d"),
"message": (
f"This campaign is scheduled to start on "
f"{campaign_obj.start_date.strftime('%d %b %Y')}. "
f"It will activate automatically on that date. "
f"Do you want to activate it now anyway?"
),
},
)
with UnitOfWork(db) as uow: