158 lines
5.5 KiB
Python
158 lines
5.5 KiB
Python
from pydantic import BaseModel, Field, validator
|
|
from typing import List, Optional
|
|
import re
|
|
|
|
|
|
class CustomTaskStatus(BaseModel):
|
|
"""Schema for a custom task status"""
|
|
id: str = Field(..., description="Unique identifier for the status")
|
|
name: str = Field(..., min_length=1, max_length=50, description="Display name")
|
|
color: str = Field(..., pattern=r'^#[0-9A-Fa-f]{6}$', description="Hex color code")
|
|
order: int = Field(..., ge=0, description="Display order")
|
|
is_default: bool = Field(default=False, description="Whether this is the default status")
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class CustomTaskStatusCreate(BaseModel):
|
|
"""Schema for creating a new custom task status"""
|
|
name: str = Field(..., min_length=1, max_length=50, description="Status name")
|
|
color: Optional[str] = Field(None, description="Hex color code (e.g., #FF5733)")
|
|
|
|
@validator('name')
|
|
def validate_name(cls, v):
|
|
"""Validate and normalize status name"""
|
|
# Trim whitespace
|
|
v = v.strip()
|
|
if not v:
|
|
raise ValueError('Status name cannot be empty')
|
|
if len(v) > 50:
|
|
raise ValueError('Status name cannot exceed 50 characters')
|
|
return v
|
|
|
|
@validator('color')
|
|
def validate_color(cls, v):
|
|
"""Validate color format if provided"""
|
|
if v is None:
|
|
return v
|
|
# Trim whitespace
|
|
v = v.strip()
|
|
# Check hex color format
|
|
if not re.match(r'^#[0-9A-Fa-f]{6}$', v):
|
|
raise ValueError('Color must be a valid hex code (e.g., #FF5733)')
|
|
return v.upper() # Normalize to uppercase
|
|
|
|
|
|
class CustomTaskStatusUpdate(BaseModel):
|
|
"""Schema for updating a custom task status"""
|
|
name: Optional[str] = Field(None, min_length=1, max_length=50, description="Status name")
|
|
color: Optional[str] = Field(None, description="Hex color code (e.g., #FF5733)")
|
|
is_default: Optional[bool] = Field(None, description="Set as default status")
|
|
|
|
@validator('name')
|
|
def validate_name(cls, v):
|
|
"""Validate and normalize status name"""
|
|
if v is None:
|
|
return v
|
|
# Trim whitespace
|
|
v = v.strip()
|
|
if not v:
|
|
raise ValueError('Status name cannot be empty')
|
|
if len(v) > 50:
|
|
raise ValueError('Status name cannot exceed 50 characters')
|
|
return v
|
|
|
|
@validator('color')
|
|
def validate_color(cls, v):
|
|
"""Validate color format if provided"""
|
|
if v is None:
|
|
return v
|
|
# Trim whitespace
|
|
v = v.strip()
|
|
# Check hex color format
|
|
if not re.match(r'^#[0-9A-Fa-f]{6}$', v):
|
|
raise ValueError('Color must be a valid hex code (e.g., #FF5733)')
|
|
return v.upper() # Normalize to uppercase
|
|
|
|
|
|
class CustomTaskStatusReorder(BaseModel):
|
|
"""Schema for reordering statuses"""
|
|
status_ids: List[str] = Field(..., min_items=1, description="Ordered list of status IDs")
|
|
|
|
@validator('status_ids')
|
|
def validate_status_ids(cls, v):
|
|
"""Validate status IDs list"""
|
|
if not v:
|
|
raise ValueError('Status IDs list cannot be empty')
|
|
# Check for duplicates
|
|
if len(v) != len(set(v)):
|
|
raise ValueError('Status IDs list contains duplicates')
|
|
return v
|
|
|
|
|
|
class CustomTaskStatusDelete(BaseModel):
|
|
"""Schema for deleting a status with optional reassignment"""
|
|
reassign_to_status_id: Optional[str] = Field(
|
|
None,
|
|
description="Status ID to reassign tasks to (required if status is in use)"
|
|
)
|
|
|
|
|
|
class SystemTaskStatus(BaseModel):
|
|
"""Schema for system (built-in) task statuses"""
|
|
id: str = Field(..., description="System status identifier")
|
|
name: str = Field(..., description="Display name")
|
|
color: str = Field(..., description="Hex color code")
|
|
is_system: bool = Field(default=True, description="Indicates this is a system status")
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class AllTaskStatusesResponse(BaseModel):
|
|
"""Schema for response containing all task statuses (system + custom)"""
|
|
statuses: List[CustomTaskStatus] = Field(
|
|
default_factory=list,
|
|
description="Custom task statuses defined for the project"
|
|
)
|
|
system_statuses: List[SystemTaskStatus] = Field(
|
|
default_factory=list,
|
|
description="Built-in system task statuses"
|
|
)
|
|
default_status_id: str = Field(
|
|
...,
|
|
description="ID of the default status for new tasks"
|
|
)
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class TaskStatusInUseError(BaseModel):
|
|
"""Schema for error when trying to delete a status that is in use"""
|
|
error: str = Field(..., description="Error message")
|
|
status_id: str = Field(..., description="ID of the status that cannot be deleted")
|
|
status_name: str = Field(..., description="Name of the status that cannot be deleted")
|
|
task_count: int = Field(..., ge=0, description="Number of tasks using this status")
|
|
task_ids: List[int] = Field(
|
|
default_factory=list,
|
|
description="IDs of tasks using this status"
|
|
)
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class CustomTaskStatusResponse(BaseModel):
|
|
"""Schema for successful custom task status operation response"""
|
|
message: str = Field(..., description="Success message")
|
|
status: Optional[CustomTaskStatus] = Field(None, description="The created or updated status")
|
|
all_statuses: Optional[AllTaskStatusesResponse] = Field(
|
|
None,
|
|
description="All statuses after the operation"
|
|
)
|
|
|
|
class Config:
|
|
from_attributes = True
|