flask_crud_app/functions/validate_config.py

121 lines
6.4 KiB
Python

from datetime import datetime
import re
from typing import List, Optional
from definitions.attribute import textAttribute, intAttribute, dateAttribute, selectAttribute
def _is_int(value) -> bool:
"""Check if a value is a valid integer."""
return isinstance(value, int)
def _is_date(value) -> bool:
"""Check if a value is a valid date in YYYY-MM-DD format."""
if not isinstance(value, str):
return False
try:
datetime.strptime(value, "%Y-%m-%d")
return True
except ValueError:
return False
def _validate_number(attrib: intAttribute) -> Optional[str]:
"""Validate number-specific attributes. Returns an error message if invalid, otherwise None."""
if attrib.min_val is not None and not _is_int(attrib.min_val):
return f"min_val must be an integer for attribute '{attrib.attrib_name}'."
if attrib.max_val is not None and not _is_int(attrib.max_val):
return f"max_val must be an integer for attribute '{attrib.attrib_name}'."
if attrib.min_val is not None and attrib.max_val is not None and attrib.min_val > attrib.max_val:
return f"min_val cannot be greater than max_val for attribute '{attrib.attrib_name}'."
if attrib.default_val is not None and not _is_int(attrib.default_val):
return f"default_val must be an integer for attribute '{attrib.attrib_name}'."
if attrib.default_val is not None:
if attrib.min_val is not None and attrib.default_val < attrib.min_val:
return f"default_val cannot be less than min_val for attribute '{attrib.attrib_name}'."
if attrib.max_val is not None and attrib.default_val > attrib.max_val:
return f"default_val cannot be greater than max_val for attribute '{attrib.attrib_name}'."
return None
def _validate_date(attrib: dateAttribute) -> Optional[str]:
"""Validate date-specific attributes. Returns an error message if invalid, otherwise None."""
if attrib.min_val is not None and not _is_date(attrib.min_val):
return f"min_val must be a valid date (YYYY-MM-DD) for attribute '{attrib.attrib_name}'."
if attrib.max_val is not None and not _is_date(attrib.max_val):
return f"max_val must be a valid date (YYYY-MM-DD) for attribute '{attrib.attrib_name}'."
if attrib.min_val is not None and attrib.max_val is not None:
min_date = datetime.strptime(attrib.min_val, "%Y-%m-%d")
max_date = datetime.strptime(attrib.max_val, "%Y-%m-%d")
if max_date < min_date:
return f"max_val cannot be earlier than min_val for attribute '{attrib.attrib_name}'."
if attrib.default_val is not None and not _is_date(attrib.default_val):
return f"default_val must be a valid date (YYYY-MM-DD) for attribute '{attrib.attrib_name}'."
if attrib.default_val is not None:
default_date = datetime.strptime(attrib.default_val, "%Y-%m-%d")
if attrib.min_val is not None:
min_date = datetime.strptime(attrib.min_val, "%Y-%m-%d")
if default_date < min_date:
return f"default_val cannot be earlier than min_val for attribute '{attrib.attrib_name}'."
if attrib.max_val is not None:
max_date = datetime.strptime(attrib.max_val, "%Y-%m-%d")
if default_date > max_date:
return f"default_val cannot be later than max_val for attribute '{attrib.attrib_name}'."
return None
def _validate_text(attrib: textAttribute) -> Optional[str]:
"""Validate text-specific attributes. Returns an error message if invalid, otherwise None."""
if attrib.default_val is not None and attrib.regex is not None:
if not re.match(attrib.regex, str(attrib.default_val)):
return f"default_val does not match the regex pattern for attribute '{attrib.attrib_name}'."
return None
def _validate_select(attrib: selectAttribute) -> Optional[str]:
"""Validate select-specific attributes. Returns an error message if invalid, otherwise None."""
if not attrib.options:
return f"options cannot be empty for attribute '{attrib.attrib_name}'."
if attrib.default_val is not None and attrib.default_val not in attrib.options:
return f"default_val must be one of the options for attribute '{attrib.attrib_name}'."
return None
def validate_config(item_attributes: List) -> str:
"""
Validate the configuration file to ensure all attributes are properly defined.
Returns "Ok" if everything is valid, otherwise returns an error message.
"""
for attrib in item_attributes:
# Validate essential properties
if not attrib.attrib_name:
return f"Missing attribute name for the {item_attributes.index(attrib) + 1}th attribute."
if not attrib.display_name:
return f"Missing display name for attribute '{attrib.attrib_name}'."
if not attrib.html_input_type:
return f"Missing input type for attribute '{attrib.attrib_name}'."
if attrib.html_input_type not in ["text", "number", "date", "select"]:
return f"Invalid input type for attribute '{attrib.attrib_name}'."
# Validate type-specific attributes
if isinstance(attrib, intAttribute):
error = _validate_number(attrib)
if error:
return error
elif isinstance(attrib, dateAttribute):
error = _validate_date(attrib)
if error:
return error
elif isinstance(attrib, textAttribute):
error = _validate_text(attrib)
if error:
return error
elif isinstance(attrib, selectAttribute):
error = _validate_select(attrib)
if error:
return error
# Validate comparison (if applicable)
if attrib.compareto:
if not isinstance(attrib.compareto, list) or not all(isinstance(pair, tuple) and len(pair) == 2 for pair in attrib.compareto):
return f"Invalid comparison format for attribute '{attrib.attrib_name}'. Expected a list of tuples."
for cmp, ref_attr in attrib.compareto:
if cmp not in ["lt", "gt", "le", "ge", "eq"]:
return f"Invalid comparison operator '{cmp}' for attribute '{attrib.attrib_name}'."
if ref_attr not in [a.attrib_name for a in item_attributes]:
return f"Invalid reference attribute '{ref_attr}' for comparison in attribute '{attrib.attrib_name}'."
return "Ok"