File size: 3,824 Bytes
dc3879e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
"""Validation utilities for the application.

[Task]: T008
[From]: specs/004-ai-chatbot/plan.md
"""
from pydantic import ValidationError, model_validator
from pydantic_core import PydanticUndefined
from typing import Any
from sqlmodel import Field


# Constants from spec
MAX_MESSAGE_LENGTH = 10000  # FR-042: Maximum message content length


class ValidationError(Exception):
    """Custom validation error."""

    def __init__(self, message: str, field: str | None = None):
        self.message = message
        self.field = field
        super().__init__(self.message)


def validate_message_length(content: str) -> str:
    """Validate message content length.

    [From]: specs/004-ai-chatbot/spec.md - FR-042

    Args:
        content: Message content to validate

    Returns:
        str: The validated content

    Raises:
        ValidationError: If content exceeds maximum length
    """
    if not content:
        raise ValidationError("Message content cannot be empty", "content")

    if len(content) > MAX_MESSAGE_LENGTH:
        raise ValidationError(
            f"Message content exceeds maximum length of {MAX_MESSAGE_LENGTH} characters "
            f"(got {len(content)} characters)",
            "content"
        )

    return content


def validate_conversation_id(conversation_id: Any) -> int | None:
    """Validate conversation ID.

    Args:
        conversation_id: Conversation ID to validate

    Returns:
        int | None: Validated conversation ID or None

    Raises:
        ValidationError: If conversation_id is invalid
    """
    if conversation_id is None:
        return None

    if isinstance(conversation_id, int):
        if conversation_id <= 0:
            raise ValidationError("Conversation ID must be positive", "conversation_id")
        return conversation_id

    if isinstance(conversation_id, str):
        try:
            conv_id = int(conversation_id)
            if conv_id <= 0:
                raise ValidationError("Conversation ID must be positive", "conversation_id")
            return conv_id
        except ValueError:
            raise ValidationError("Conversation ID must be a valid integer", "conversation_id")

    raise ValidationError("Conversation ID must be an integer or null", "conversation_id")


# Task validation constants
MAX_TASK_TITLE_LENGTH = 255  # From Task model
MAX_TASK_DESCRIPTION_LENGTH = 2000  # From Task model


def validate_task_title(title: str) -> str:
    """Validate task title.

    [From]: models/task.py - Task.title

    Args:
        title: Task title to validate

    Returns:
        str: The validated title

    Raises:
        ValidationError: If title is empty or exceeds max length
    """
    if not title or not title.strip():
        raise ValidationError("Task title cannot be empty", "title")

    title = title.strip()

    if len(title) > MAX_TASK_TITLE_LENGTH:
        raise ValidationError(
            f"Task title exceeds maximum length of {MAX_TASK_TITLE_LENGTH} characters "
            f"(got {len(title)} characters)",
            "title"
        )

    return title


def validate_task_description(description: str | None) -> str:
    """Validate task description.

    [From]: models/task.py - Task.description

    Args:
        description: Task description to validate

    Returns:
        str: The validated description

    Raises:
        ValidationError: If description exceeds max length
    """
    if description is None:
        return ""

    description = description.strip()

    if len(description) > MAX_TASK_DESCRIPTION_LENGTH:
        raise ValidationError(
            f"Task description exceeds maximum length of {MAX_TASK_DESCRIPTION_LENGTH} characters "
            f"(got {len(description)} characters)",
            "description"
        )

    return description