import re from typing import Optional, Any from datetime import datetime from app.nodes.base import NodeExecutor from app.context import FlowContext class ValidateEmailExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' if re.match(email_pattern, str(value).strip()): return "valid" return "invalid" class ValidatePhoneExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") cleaned = re.sub(r'[\s\-\(\)\+]', '', str(value)) if cleaned.isdigit() and 8 <= len(cleaned) <= 15: return "valid" return "invalid" class ValidateNumberExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") min_val = config.get("min") max_val = config.get("max") try: num = float(str(value).strip()) if min_val is not None and num < float(min_val): return "invalid" if max_val is not None and num > float(max_val): return "invalid" return "valid" except ValueError: return "invalid" class ValidateDateExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") date_format = config.get("format", "%Y-%m-%d") try: datetime.strptime(str(value).strip(), date_format) return "valid" except ValueError: return "invalid" class ValidateRegexExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") pattern = config.get("pattern", ".*") try: if re.match(pattern, str(value).strip()): return "valid" return "invalid" except re.error: return "invalid" class ValidateOptionsExecutor(NodeExecutor): async def execute(self, config: dict, context: FlowContext, session: Any) -> Optional[str]: variable = config.get("variable", "") value = context.get(variable) or context.message.get("content", "") options = config.get("options", []) case_sensitive = config.get("case_sensitive", False) value_str = str(value).strip() if not case_sensitive: value_str = value_str.lower() options = [str(o).lower() for o in options] if value_str in options: return "valid" return "invalid"