feat: harden campaign delivery and editing
This commit is contained in:
@@ -7,7 +7,12 @@ from typing import Any
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.orm.exc import StaleDataError
|
||||
|
||||
from govoplan_core.core.concurrency import (
|
||||
RevisionConflictError,
|
||||
strong_resource_etag,
|
||||
)
|
||||
from govoplan_campaign.backend.db.models import (
|
||||
Campaign,
|
||||
CampaignIssue,
|
||||
@@ -720,12 +725,31 @@ def update_campaign_version(
|
||||
source_base_path: str | None = None,
|
||||
autosave: bool = False,
|
||||
migrate_legacy_mail_settings: bool = False,
|
||||
expected_revision: int | None = None,
|
||||
commit: bool = True,
|
||||
) -> CampaignVersion:
|
||||
_assert_update_paths_safe(raw_json, source_filename=source_filename, source_base_path=source_base_path)
|
||||
version = get_campaign_version_for_tenant(session, tenant_id=tenant_id, campaign_id=campaign_id, version_id=version_id)
|
||||
campaign = _require_campaign(session, campaign_id)
|
||||
ensure_current_working_version(campaign, version, action="edit")
|
||||
if (
|
||||
expected_revision is not None
|
||||
and version.edit_revision != int(expected_revision)
|
||||
):
|
||||
raise RevisionConflictError(
|
||||
resource_type="campaign_version",
|
||||
resource_id=version.id,
|
||||
current_revision=version.edit_revision,
|
||||
submitted_base_revision=int(expected_revision),
|
||||
refresh_path=(
|
||||
f"/api/v1/campaigns/{campaign.id}/versions/{version.id}"
|
||||
),
|
||||
current_etag=strong_resource_etag(
|
||||
"campaign_version",
|
||||
version.id,
|
||||
version.edit_revision,
|
||||
),
|
||||
)
|
||||
|
||||
if is_version_locked(version):
|
||||
raise LockedCampaignVersionError(
|
||||
@@ -761,7 +785,42 @@ def update_campaign_version(
|
||||
# Changes invalidate previous build and validation summaries.
|
||||
if raw_json is not None:
|
||||
_invalidate_version_content(session, campaign=campaign, version=version)
|
||||
_persist_updated_version(session, campaign=campaign, version=version, commit=commit)
|
||||
try:
|
||||
_persist_updated_version(
|
||||
session,
|
||||
campaign=campaign,
|
||||
version=version,
|
||||
commit=commit,
|
||||
)
|
||||
except StaleDataError as exc:
|
||||
session.rollback()
|
||||
current_revision = (
|
||||
session.query(CampaignVersion.edit_revision)
|
||||
.filter(CampaignVersion.id == version_id)
|
||||
.scalar()
|
||||
)
|
||||
if current_revision is None:
|
||||
raise CampaignPersistenceError(
|
||||
f"Campaign version not found: {version_id}"
|
||||
) from exc
|
||||
raise RevisionConflictError(
|
||||
resource_type="campaign_version",
|
||||
resource_id=version_id,
|
||||
current_revision=int(current_revision),
|
||||
submitted_base_revision=int(
|
||||
expected_revision
|
||||
if expected_revision is not None
|
||||
else version.edit_revision
|
||||
),
|
||||
refresh_path=(
|
||||
f"/api/v1/campaigns/{campaign_id}/versions/{version_id}"
|
||||
),
|
||||
current_etag=strong_resource_etag(
|
||||
"campaign_version",
|
||||
version_id,
|
||||
int(current_revision),
|
||||
),
|
||||
) from exc
|
||||
return version
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user