File size: 2,890 Bytes
8576e2e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""

Data validation utilities

"""
import re
from math import gcd
from typing import Set

# --- Aspect ratio validation ---

_ASPECT_RATIO_PATTERN = re.compile(r"^\d+:\d+$")
_ASPECT_RATIO_MIN = 0.2
_ASPECT_RATIO_MAX = 5.0


def normalize_aspect_ratio(raw_value) -> str:
    """

    Normalize and validate aspect ratio input.



    - Accepts "W:H" where W/H are positive integers.

    - Reduces by gcd (e.g., "1920:1080" -> "16:9").

    - Rejects obviously invalid or extreme ratios.

    - Returns the normalized string like "16:9".

    """
    if raw_value is None:
        raise ValueError("Image aspect ratio is required")

    value = str(raw_value).strip()
    if value == "":
        raise ValueError("Image aspect ratio is required")

    if not _ASPECT_RATIO_PATTERN.fullmatch(value):
        raise ValueError(
            "Image aspect ratio must match \\d+:\\d+ (e.g., 16:9, 4:3, 1:1)"
        )

    width, height = (int(part) for part in value.split(":", 1))
    if width <= 0 or height <= 0:
        raise ValueError("Image aspect ratio must be positive integers (e.g., 16:9)")

    divisor = gcd(width, height)
    width //= divisor
    height //= divisor

    ratio_value = width / height
    if ratio_value < _ASPECT_RATIO_MIN or ratio_value > _ASPECT_RATIO_MAX:
        raise ValueError(
            f"Image aspect ratio must be between {_ASPECT_RATIO_MIN:.1f} and {_ASPECT_RATIO_MAX:.1f} (e.g., 16:9)"
        )

    normalized = f"{width}:{height}"
    if len(normalized) > 10:
        raise ValueError("Image aspect ratio is too long")

    return normalized

# Project status states
PROJECT_STATUSES = {
    'DRAFT', 
    'OUTLINE_GENERATED', 
    'DESCRIPTIONS_GENERATED', 
    'GENERATING_IMAGES', 
    'COMPLETED'
}

# Page status states
PAGE_STATUSES = {
    'DRAFT', 
    'DESCRIPTION_GENERATED', 
    'GENERATING', 
    'COMPLETED', 
    'FAILED'
}

# Task status states
TASK_STATUSES = {
    'PENDING',
    'PROCESSING',
    'COMPLETED',
    'FAILED'
}

# Task types
TASK_TYPES = {
    'GENERATE_DESCRIPTIONS',
    'GENERATE_IMAGES',
    'EXPORT_EDITABLE_PPTX'
}


def validate_project_status(status: str) -> bool:
    """Validate project status"""
    return status in PROJECT_STATUSES


def validate_page_status(status: str) -> bool:
    """Validate page status"""
    return status in PAGE_STATUSES


def validate_task_status(status: str) -> bool:
    """Validate task status"""
    return status in TASK_STATUSES


def validate_task_type(task_type: str) -> bool:
    """Validate task type"""
    return task_type in TASK_TYPES


def allowed_file(filename: str, allowed_extensions: Set[str]) -> bool:
    """Check if file extension is allowed"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in allowed_extensions