import re from datetime import datetime from typing import Dict, Optional from config import item_attributes from definitions.attribute import textAttribute, intAttribute, floatAttribute, dateAttribute, selectAttribute def _is_int(value: str) -> bool: """Check if a value is a valid integer.""" try: int(value) return True except (ValueError, TypeError): return False def _is_float(value: str) -> bool: """Check if a value is a valid float.""" try: float(value) return True except (ValueError, TypeError): return False def _is_date(value: str) -> bool: """Check if a value is a valid date in YYYY-MM-DD format.""" try: datetime.strptime(value, "%Y-%m-%d") return True except (ValueError, TypeError): return False def validate_values(form_data: Dict[str, str]) -> Optional[str]: """ Validate the submitted form values against the item_attributes configuration. Returns an error message if invalid, otherwise None. """ for attrib in item_attributes: value = form_data.get(attrib.attrib_name) # Check required fields if attrib.required and not value: return f"{attrib.display_name} is required." # Skip validation for empty optional fields if not value: continue # Validate based on attribute type if isinstance(attrib, textAttribute): if attrib.regex and not re.match(attrib.regex, value): return f"Invalid value for {attrib.display_name}. Must match the pattern: {attrib.regex}." elif isinstance(attrib, intAttribute): if not _is_int(value): return f"{attrib.display_name} must be an integer." value_int = int(value) if attrib.min_val is not None and value_int < attrib.min_val: return f"{attrib.display_name} must be greater than or equal to {attrib.min_val}." if attrib.max_val is not None and value_int > attrib.max_val: return f"{attrib.display_name} must be less than or equal to {attrib.max_val}." elif isinstance(attrib, floatAttribute): if not _is_float(value): return f"{attrib.display_name} must be a number." value_float = float(value) if attrib.min_val is not None and value_float < attrib.min_val: return f"{attrib.display_name} must be greater than or equal to {attrib.min_val}." if attrib.max_val is not None and value_float > attrib.max_val: return f"{attrib.display_name} must be less than or equal to {attrib.max_val}." elif isinstance(attrib, dateAttribute): if not _is_date(value): return f"{attrib.display_name} must be a valid date in YYYY-MM-DD format." value_date = datetime.strptime(value, "%Y-%m-%d").date() if attrib.min_val and value_date < datetime.strptime(attrib.min_val, "%Y-%m-%d").date(): return f"{attrib.display_name} cannot be earlier than {attrib.min_val}." if attrib.max_val and value_date > datetime.strptime(attrib.max_val, "%Y-%m-%d").date(): return f"{attrib.display_name} cannot be later than {attrib.max_val}." elif isinstance(attrib, selectAttribute): if value not in attrib.options: return f"{attrib.display_name} must be one of: {', '.join(attrib.options)}." return None # No errors