feat: v3.0 - canvas editor, JSON-only, no Excel, new UI
Some checks failed
Build & Push Docker / build (push) Has been cancelled
Some checks failed
Build & Push Docker / build (push) Has been cancelled
- Remove all Excel code (import, export, template, pandas, openpyxl) - New canvas-based schedule editor with drag & drop (interact.js) - Modern 3-panel UI: sidebar, canvas, documentation tab - New data model: Block with id/date/start/end, ProgramType with id/name/color - Clean API: GET /api/health, POST /api/validate, GET /api/sample, POST /api/generate-pdf - Rewritten PDF generator using ScenarioDocument directly (no DataFrame) - Professional PDF output: dark header, colored blocks, merged cells, legend, footer - Sample JSON: "Zimní výjezd oddílu" with 11 blocks, 3 program types - 30 tests passing (API, core models, PDF generation) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,18 +1,9 @@
|
||||
"""
|
||||
Validation logic for Scenar Creator.
|
||||
Extracted from scenar/core.py — validate_inputs, validate_excel_template, overlap detection.
|
||||
"""
|
||||
"""Validation logic for Scenar Creator v3."""
|
||||
|
||||
import pandas as pd
|
||||
from datetime import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_COLOR = "#ffffff"
|
||||
MAX_FILE_SIZE_MB = 10
|
||||
REQUIRED_COLUMNS = ["Datum", "Zacatek", "Konec", "Program", "Typ", "Garant", "Poznamka"]
|
||||
|
||||
|
||||
class ScenarsError(Exception):
|
||||
"""Base exception for Scenar Creator."""
|
||||
@@ -22,48 +13,3 @@ class ScenarsError(Exception):
|
||||
class ValidationError(ScenarsError):
|
||||
"""Raised when input validation fails."""
|
||||
pass
|
||||
|
||||
|
||||
class TemplateError(ScenarsError):
|
||||
"""Raised when Excel template is invalid."""
|
||||
pass
|
||||
|
||||
|
||||
def validate_inputs(title: str, detail: str, file_size: int) -> None:
|
||||
"""Validate user inputs for security and sanity."""
|
||||
if not title or not isinstance(title, str):
|
||||
raise ValidationError("Title is required and must be a string")
|
||||
if len(title.strip()) == 0:
|
||||
raise ValidationError("Title cannot be empty")
|
||||
if len(title) > 200:
|
||||
raise ValidationError("Title is too long (max 200 characters)")
|
||||
|
||||
if not detail or not isinstance(detail, str):
|
||||
raise ValidationError("Detail is required and must be a string")
|
||||
if len(detail.strip()) == 0:
|
||||
raise ValidationError("Detail cannot be empty")
|
||||
if len(detail) > 500:
|
||||
raise ValidationError("Detail is too long (max 500 characters)")
|
||||
|
||||
if file_size > MAX_FILE_SIZE_MB * 1024 * 1024:
|
||||
raise ValidationError(f"File size exceeds {MAX_FILE_SIZE_MB} MB limit")
|
||||
|
||||
|
||||
def normalize_time(time_str: str):
|
||||
"""Parse time string in formats %H:%M or %H:%M:%S."""
|
||||
for fmt in ('%H:%M', '%H:%M:%S'):
|
||||
try:
|
||||
return datetime.strptime(time_str, fmt).time()
|
||||
except ValueError:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def validate_excel_template(df: pd.DataFrame) -> None:
|
||||
"""Validate that Excel has required columns."""
|
||||
missing_cols = set(REQUIRED_COLUMNS) - set(df.columns)
|
||||
if missing_cols:
|
||||
raise TemplateError(
|
||||
f"Excel template missing required columns: {', '.join(missing_cols)}. "
|
||||
f"Expected: {', '.join(REQUIRED_COLUMNS)}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user