Refactor campaign validation to return optional broken directory path on failure
This commit is contained in:
parent
835a0e0e2a
commit
bd73f8d250
1 changed files with 42 additions and 8 deletions
|
|
@ -336,7 +336,7 @@ class Command(BaseCommand):
|
||||||
campaigns_found: list[dict[str, Any]],
|
campaigns_found: list[dict[str, Any]],
|
||||||
file_path: Path,
|
file_path: Path,
|
||||||
options: dict[str, Any],
|
options: dict[str, Any],
|
||||||
) -> list[GraphQLResponse]:
|
) -> tuple[list[GraphQLResponse], Path | None]:
|
||||||
"""Validate campaign data using Pydantic schema.
|
"""Validate campaign data using Pydantic schema.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -345,13 +345,15 @@ class Command(BaseCommand):
|
||||||
options: Command options.
|
options: Command options.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List of validated Pydantic GraphQLResponse models.
|
Tuple of validated Pydantic GraphQLResponse models and an optional
|
||||||
|
broken directory path when the file was moved during validation.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
ValidationError: If campaign data fails Pydantic validation
|
ValidationError: If campaign data fails Pydantic validation
|
||||||
and crash-on-error is enabled.
|
and crash-on-error is enabled.
|
||||||
"""
|
"""
|
||||||
valid_campaigns: list[GraphQLResponse] = []
|
valid_campaigns: list[GraphQLResponse] = []
|
||||||
|
broken_dir: Path | None = None
|
||||||
|
|
||||||
if isinstance(campaigns_found, list):
|
if isinstance(campaigns_found, list):
|
||||||
for campaign in campaigns_found:
|
for campaign in campaigns_found:
|
||||||
|
|
@ -369,7 +371,10 @@ class Command(BaseCommand):
|
||||||
# Move invalid inputs out of the hot path so future runs can progress.
|
# Move invalid inputs out of the hot path so future runs can progress.
|
||||||
if not options.get("skip_broken_moves"):
|
if not options.get("skip_broken_moves"):
|
||||||
op_name: str | None = extract_operation_name_from_parsed(campaign)
|
op_name: str | None = extract_operation_name_from_parsed(campaign)
|
||||||
move_failed_validation_file(file_path, operation_name=op_name)
|
broken_dir = move_failed_validation_file(file_path, operation_name=op_name)
|
||||||
|
|
||||||
|
# Once the file has been moved, bail out so we don't try to move it again later.
|
||||||
|
return [], broken_dir
|
||||||
|
|
||||||
# optionally crash early to surface schema issues.
|
# optionally crash early to surface schema issues.
|
||||||
if options.get("crash_on_error"):
|
if options.get("crash_on_error"):
|
||||||
|
|
@ -377,7 +382,7 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return valid_campaigns
|
return valid_campaigns, broken_dir
|
||||||
|
|
||||||
def _get_or_create_organization(
|
def _get_or_create_organization(
|
||||||
self,
|
self,
|
||||||
|
|
@ -493,7 +498,7 @@ class Command(BaseCommand):
|
||||||
campaigns_found: list[dict[str, Any]],
|
campaigns_found: list[dict[str, Any]],
|
||||||
file_path: Path,
|
file_path: Path,
|
||||||
options: dict[str, Any],
|
options: dict[str, Any],
|
||||||
) -> None:
|
) -> tuple[bool, Path | None]:
|
||||||
"""Process, validate, and import campaign data.
|
"""Process, validate, and import campaign data.
|
||||||
|
|
||||||
With dependency resolution and caching.
|
With dependency resolution and caching.
|
||||||
|
|
@ -506,13 +511,20 @@ class Command(BaseCommand):
|
||||||
Raises:
|
Raises:
|
||||||
ValueError: If datetime parsing fails for campaign dates and
|
ValueError: If datetime parsing fails for campaign dates and
|
||||||
crash-on-error is enabled.
|
crash-on-error is enabled.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (success flag, broken directory path if moved).
|
||||||
"""
|
"""
|
||||||
valid_campaigns: list[GraphQLResponse] = self._validate_campaigns(
|
valid_campaigns, broken_dir = self._validate_campaigns(
|
||||||
campaigns_found=campaigns_found,
|
campaigns_found=campaigns_found,
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
options=options,
|
options=options,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if broken_dir:
|
||||||
|
# File already moved due to validation failure; signal caller to skip further handling.
|
||||||
|
return False, broken_dir
|
||||||
|
|
||||||
for response in valid_campaigns:
|
for response in valid_campaigns:
|
||||||
if not response.data.current_user:
|
if not response.data.current_user:
|
||||||
continue
|
continue
|
||||||
|
|
@ -592,6 +604,8 @@ class Command(BaseCommand):
|
||||||
campaign_obj=campaign_obj,
|
campaign_obj=campaign_obj,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return True, None
|
||||||
|
|
||||||
def _process_time_based_drops(
|
def _process_time_based_drops(
|
||||||
self,
|
self,
|
||||||
time_based_drops_schema: list[TimeBasedDropSchema],
|
time_based_drops_schema: list[TimeBasedDropSchema],
|
||||||
|
|
@ -875,12 +889,20 @@ class Command(BaseCommand):
|
||||||
return {"success": False, "broken_dir": str(broken_dir), "reason": "no dropCampaign present"}
|
return {"success": False, "broken_dir": str(broken_dir), "reason": "no dropCampaign present"}
|
||||||
return {"success": False, "broken_dir": "(skipped)", "reason": "no dropCampaign present"}
|
return {"success": False, "broken_dir": "(skipped)", "reason": "no dropCampaign present"}
|
||||||
campaigns_found: list[dict[str, Any]] = [parsed_json]
|
campaigns_found: list[dict[str, Any]] = [parsed_json]
|
||||||
self.process_campaigns(
|
processed, broken_dir = self.process_campaigns(
|
||||||
campaigns_found=campaigns_found,
|
campaigns_found=campaigns_found,
|
||||||
file_path=file_path,
|
file_path=file_path,
|
||||||
options=options,
|
options=options,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if not processed:
|
||||||
|
# File was already moved to broken during validation
|
||||||
|
return {
|
||||||
|
"success": False,
|
||||||
|
"broken_dir": str(broken_dir) if broken_dir else "(unknown)",
|
||||||
|
"reason": "validation failed",
|
||||||
|
}
|
||||||
|
|
||||||
move_completed_file(file_path=file_path, operation_name=operation_name)
|
move_completed_file(file_path=file_path, operation_name=operation_name)
|
||||||
|
|
||||||
except (ValidationError, json.JSONDecodeError):
|
except (ValidationError, json.JSONDecodeError):
|
||||||
|
|
@ -964,7 +986,19 @@ class Command(BaseCommand):
|
||||||
|
|
||||||
campaigns_found: list[dict[str, Any]] = [parsed_json]
|
campaigns_found: list[dict[str, Any]] = [parsed_json]
|
||||||
|
|
||||||
self.process_campaigns(campaigns_found=campaigns_found, file_path=file_path, options=options)
|
processed, broken_dir = self.process_campaigns(
|
||||||
|
campaigns_found=campaigns_found,
|
||||||
|
file_path=file_path,
|
||||||
|
options=options,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not processed:
|
||||||
|
# File already moved during validation; nothing more to do here.
|
||||||
|
progress_bar.write(
|
||||||
|
f"{Fore.RED}✗{Style.RESET_ALL} {file_path.name} → "
|
||||||
|
f"{broken_dir}/{file_path.name} (validation failed)",
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
move_completed_file(file_path=file_path, operation_name=operation_name)
|
move_completed_file(file_path=file_path, operation_name=operation_name)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue