Files
Pac-cogs/videoarchiver/config/validation_manager.py
2024-11-18 01:21:40 +00:00

149 lines
5.7 KiB
Python

"""Module for validating configuration settings"""
import logging
from typing import Any, Dict, List, Union
# try:
# Try relative imports first
from .exceptions import ConfigurationError as ConfigError
# except ImportError:
# Fall back to absolute imports if relative imports fail
# from videoarchiver.config.exceptions import ConfigurationError as ConfigError
logger = logging.getLogger("ConfigValidation")
class ValidationManager:
"""Manages validation of configuration settings"""
# Valid settings constraints
VALID_VIDEO_FORMATS = ["mp4", "webm", "mkv"]
MAX_QUALITY_RANGE = (144, 4320) # 144p to 4K
MAX_FILE_SIZE_RANGE = (1, 100) # 1MB to 100MB
MAX_CONCURRENT_DOWNLOADS = 5
MAX_MESSAGE_DURATION = 168 # 1 week in hours
MAX_RETRIES = 10
MAX_RETRY_DELAY = 30
def validate_setting(self, setting: str, value: Any) -> None:
"""Validate a setting value against constraints
Args:
setting: Name of the setting to validate
value: Value to validate
Raises:
ConfigError: If validation fails
"""
try:
validator = getattr(self, f"_validate_{setting}", None)
if validator:
validator(value)
else:
self._validate_generic(setting, value)
except Exception as e:
logger.error(f"Validation error for {setting}: {e}")
raise ConfigError(f"Validation error for {setting}: {str(e)}")
def _validate_video_format(self, value: str) -> None:
"""Validate video format setting"""
if value not in self.VALID_VIDEO_FORMATS:
raise ConfigError(
f"Invalid video format. Must be one of: {', '.join(self.VALID_VIDEO_FORMATS)}"
)
def _validate_video_quality(self, value: int) -> None:
"""Validate video quality setting"""
if not isinstance(value, int) or not (
self.MAX_QUALITY_RANGE[0] <= value <= self.MAX_QUALITY_RANGE[1]
):
raise ConfigError(
f"Video quality must be between {self.MAX_QUALITY_RANGE[0]} and {self.MAX_QUALITY_RANGE[1]}"
)
def _validate_max_file_size(self, value: Union[int, float]) -> None:
"""Validate max file size setting"""
if not isinstance(value, (int, float)) or not (
self.MAX_FILE_SIZE_RANGE[0] <= value <= self.MAX_FILE_SIZE_RANGE[1]
):
raise ConfigError(
f"Max file size must be between {self.MAX_FILE_SIZE_RANGE[0]} and {self.MAX_FILE_SIZE_RANGE[1]} MB"
)
def _validate_concurrent_downloads(self, value: int) -> None:
"""Validate concurrent downloads setting"""
if not isinstance(value, int) or not (
1 <= value <= self.MAX_CONCURRENT_DOWNLOADS
):
raise ConfigError(
f"Concurrent downloads must be between 1 and {self.MAX_CONCURRENT_DOWNLOADS}"
)
def _validate_message_duration(self, value: int) -> None:
"""Validate message duration setting"""
if not isinstance(value, int) or not (0 <= value <= self.MAX_MESSAGE_DURATION):
raise ConfigError(
f"Message duration must be between 0 and {self.MAX_MESSAGE_DURATION} hours"
)
def _validate_max_retries(self, value: int) -> None:
"""Validate max retries setting"""
if not isinstance(value, int) or not (0 <= value <= self.MAX_RETRIES):
raise ConfigError(f"Max retries must be between 0 and {self.MAX_RETRIES}")
def _validate_retry_delay(self, value: int) -> None:
"""Validate retry delay setting"""
if not isinstance(value, int) or not (1 <= value <= self.MAX_RETRY_DELAY):
raise ConfigError(
f"Retry delay must be between 1 and {self.MAX_RETRY_DELAY} seconds"
)
def _validate_message_template(self, value: str) -> None:
"""Validate message template setting"""
if not isinstance(value, str):
raise ConfigError("Message template must be a string")
# Check for required placeholders
required_placeholders = ["{username}", "{channel}"]
for placeholder in required_placeholders:
if placeholder not in value:
raise ConfigError(f"Message template must contain {placeholder}")
def _validate_boolean(self, value: bool) -> None:
"""Validate boolean settings"""
if not isinstance(value, bool):
raise ConfigError("Value must be a boolean")
def _validate_list(self, value: List[Any]) -> None:
"""Validate list settings"""
if not isinstance(value, list):
raise ConfigError("Value must be a list")
def _validate_generic(self, setting: str, value: Any) -> None:
"""Generic validation for settings without specific validators"""
if setting.endswith("_channel") and value is not None:
if not isinstance(value, int):
raise ConfigError(f"{setting} must be a channel ID (int) or None")
elif setting in [
"enabled",
"delete_after_repost",
"disable_update_check",
"use_database",
]:
self._validate_boolean(value)
elif setting in ["monitored_channels", "allowed_roles", "enabled_sites"]:
self._validate_list(value)
def validate_all_settings(self, settings: Dict[str, Any]) -> None:
"""Validate all settings in a configuration dictionary
Args:
settings: Dictionary of settings to validate
Raises:
ConfigError: If any validation fails
"""
for setting, value in settings.items():
self.validate_setting(setting, value)