File size: 3,778 Bytes
1e4fc28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
"""
Request validation utilities.
"""
import os
from typing import Tuple, Optional
from werkzeug.utils import secure_filename
from PIL import Image


def validate_image_file(file, max_size: int, allowed_extensions: tuple) -> Tuple[bool, Optional[str], Optional[str]]:
    """
    Validate uploaded image file.
    
    Args:
        file: FileStorage object from Flask
        max_size: Maximum file size in bytes
        allowed_extensions: Tuple of allowed extensions (e.g., (".jpg", ".png"))
    
    Returns:
        Tuple of (is_valid, error_message, sanitized_filename)
        If valid: (True, None, filename)
        If invalid: (False, error_message, None)
    """
    if not file or not file.filename:
        return False, "No file provided", None
    
    # Check filename
    filename = secure_filename(file.filename)
    if not filename:
        return False, "Invalid filename", None
    
    # Check extension
    ext = os.path.splitext(filename)[1].lower()
    if ext not in allowed_extensions:
        return False, f"Unsupported file type. Allowed: {', '.join(allowed_extensions)}", None
    
    # Check file size (if available)
    try:
        file.seek(0, os.SEEK_END)
        file_size = file.tell()
        file.seek(0)  # Reset to beginning
        
        if file_size > max_size:
            max_mb = max_size / (1024 * 1024)
            return False, f"File too large. Maximum size: {max_mb:.1f}MB", None
        
        if file_size == 0:
            return False, "File is empty", None
    except Exception:
        # If we can't check size, continue (will be caught by MAX_CONTENT_LENGTH)
        pass
    
    # Validate it's actually an image by trying to open it
    try:
        file.seek(0)
        img = Image.open(file)
        img.verify()  # Verify it's a valid image
        file.seek(0)  # Reset after verification
    except Exception as e:
        return False, f"Invalid image file: {str(e)}", None
    
    return True, None, filename


def validate_pagination_params(limit: Optional[str], offset: Optional[str]) -> Tuple[int, int, Optional[str]]:
    """
    Validate pagination parameters.
    
    Returns:
        Tuple of (limit, offset, error_message)
    """
    try:
        limit_val = int(limit) if limit else 20
        limit_val = max(1, min(200, limit_val))
    except ValueError:
        return 20, 0, "Invalid limit parameter. Must be an integer."
    
    try:
        offset_val = int(offset) if offset else 0
        offset_val = max(0, offset_val)
    except ValueError:
        return limit_val, 0, "Invalid offset parameter. Must be an integer."
    
    return limit_val, offset_val, None


def validate_confidence_range(min_conf: Optional[str], max_conf: Optional[str]) -> Tuple[Optional[float], Optional[float], Optional[str]]:
    """
    Validate confidence range parameters.
    
    Returns:
        Tuple of (min_confidence, max_confidence, error_message)
    """
    min_val = None
    max_val = None
    
    if min_conf:
        try:
            min_val = float(min_conf)
            if not 0 <= min_val <= 1:
                return None, None, "min_confidence must be between 0 and 1"
        except ValueError:
            return None, None, "Invalid min_confidence parameter. Must be a number."
    
    if max_conf:
        try:
            max_val = float(max_conf)
            if not 0 <= max_val <= 1:
                return None, None, "max_confidence must be between 0 and 1"
        except ValueError:
            return None, None, "Invalid max_confidence parameter. Must be a number."
    
    if min_val is not None and max_val is not None and min_val > max_val:
        return None, None, "min_confidence cannot be greater than max_confidence"
    
    return min_val, max_val, None