first version able to send
This commit is contained in:
@@ -351,6 +351,7 @@ def validate_version(
|
||||
tenant_id=principal.tenant_id,
|
||||
version_id=version_id,
|
||||
check_files=payload.check_files if payload else False,
|
||||
user_id=principal.user.id,
|
||||
)
|
||||
audit_from_principal(
|
||||
session,
|
||||
@@ -536,7 +537,14 @@ def email_campaign_report(
|
||||
|
||||
|
||||
# Queue / delivery control -------------------------------------------------
|
||||
from app.api.v1.schemas import AppendSentRequest, CampaignActionResponse, QueueCampaignRequest, QueueCampaignResponse
|
||||
from app.api.v1.schemas import (
|
||||
AppendSentRequest,
|
||||
CampaignActionResponse,
|
||||
QueueCampaignRequest,
|
||||
QueueCampaignResponse,
|
||||
SendCampaignNowRequest,
|
||||
SendCampaignNowResponse,
|
||||
)
|
||||
from app.mailer.sending.jobs import (
|
||||
QueueingError,
|
||||
cancel_campaign_jobs,
|
||||
@@ -544,6 +552,7 @@ from app.mailer.sending.jobs import (
|
||||
pause_campaign_jobs,
|
||||
queue_campaign_jobs,
|
||||
resume_campaign_jobs,
|
||||
send_campaign_now,
|
||||
)
|
||||
|
||||
|
||||
@@ -579,6 +588,78 @@ def queue_campaign(
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.post("/{campaign_id}/send-now", response_model=SendCampaignNowResponse)
|
||||
def send_campaign_now_endpoint(
|
||||
campaign_id: str,
|
||||
payload: SendCampaignNowRequest | None = None,
|
||||
session: Session = Depends(get_session),
|
||||
principal: ApiPrincipal = Depends(require_scope("campaign:send")),
|
||||
):
|
||||
"""Validate/build/queue and synchronously send a small campaign version.
|
||||
|
||||
This endpoint is intentionally conservative and suitable for a first small
|
||||
test campaign. Larger campaigns should use the queue/Celery flow.
|
||||
"""
|
||||
|
||||
payload = payload or SendCampaignNowRequest()
|
||||
try:
|
||||
campaign = _get_campaign_for_tenant(session, campaign_id, principal.tenant_id)
|
||||
version_id = payload.version_id or campaign.current_version_id
|
||||
if not version_id:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="Campaign has no current version")
|
||||
|
||||
validation_result: dict[str, object] | None = None
|
||||
build_result: dict[str, object] | None = None
|
||||
if payload.validate_before_send:
|
||||
validation_result = validate_campaign_version(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
version_id=version_id,
|
||||
check_files=payload.check_files,
|
||||
user_id=principal.user.id,
|
||||
)
|
||||
if not validation_result.get("ok"):
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail={"message": "Campaign validation failed", "validation": validation_result})
|
||||
|
||||
if payload.build_before_send:
|
||||
build_result = build_campaign_version(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
version_id=version_id,
|
||||
write_eml=True,
|
||||
)
|
||||
|
||||
result = send_campaign_now(
|
||||
session,
|
||||
tenant_id=principal.tenant_id,
|
||||
campaign_id=campaign_id,
|
||||
version_id=version_id,
|
||||
include_warnings=payload.include_warnings,
|
||||
dry_run=payload.dry_run,
|
||||
use_rate_limit=payload.use_rate_limit,
|
||||
enqueue_imap_task=payload.enqueue_imap_task,
|
||||
).as_dict()
|
||||
result["validation"] = validation_result
|
||||
result["build"] = build_result
|
||||
audit_from_principal(
|
||||
session,
|
||||
principal,
|
||||
action="campaign.sent_now" if not payload.dry_run else "campaign.send_now_dry_run",
|
||||
object_type="campaign",
|
||||
object_id=campaign_id,
|
||||
details=result,
|
||||
commit=True,
|
||||
)
|
||||
return SendCampaignNowResponse(result=result)
|
||||
except HTTPException:
|
||||
raise
|
||||
except (CampaignPersistenceError, QueueingError) as exc:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)) from exc
|
||||
except Exception as exc:
|
||||
raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)) from exc
|
||||
|
||||
|
||||
|
||||
@router.post("/{campaign_id}/pause", response_model=CampaignActionResponse)
|
||||
def pause_campaign(
|
||||
campaign_id: str,
|
||||
|
||||
Reference in New Issue
Block a user