from datetime import datetime from typing import Optional, List, Dict, Any, Union from pydantic import BaseModel, Field class FieldChangeCondition(BaseModel): """Condition for field_change triggers.""" field: str = Field(..., description="Field to check: status_id, assignee_id, priority") operator: str = Field(..., description="Operator: equals, not_equals, changed_to, changed_from") value: str = Field(..., description="Value to compare against") class ScheduleCondition(BaseModel): """Condition for schedule triggers.""" cron_expression: Optional[str] = Field(None, description="Cron expression (e.g., '0 9 * * 1' for Monday 9am)") deadline_reminder_days: Optional[int] = Field(None, ge=1, le=365, description="Days before due date to send reminder") class TriggerCondition(BaseModel): """Union condition that supports both field_change and schedule triggers.""" # Field change conditions field: Optional[str] = Field(None, description="Field to check: status_id, assignee_id, priority") operator: Optional[str] = Field(None, description="Operator: equals, not_equals, changed_to, changed_from") value: Optional[str] = Field(None, description="Value to compare against") # Schedule conditions cron_expression: Optional[str] = Field(None, description="Cron expression for schedule triggers") deadline_reminder_days: Optional[int] = Field(None, ge=1, le=365, description="Days before due date to send reminder") class TriggerAction(BaseModel): type: str = Field(default="notify", description="Action type: notify") target: str = Field(default="assignee", description="Target: assignee, creator, project_owner, user:") template: Optional[str] = Field(None, description="Message template with variables") class TriggerCreate(BaseModel): name: str = Field(..., min_length=1, max_length=200) description: Optional[str] = Field(None, max_length=2000) trigger_type: str = Field(default="field_change") conditions: TriggerCondition actions: List[TriggerAction] is_active: bool = Field(default=True) class TriggerUpdate(BaseModel): name: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = Field(None, max_length=2000) conditions: Optional[TriggerCondition] = None actions: Optional[List[TriggerAction]] = None is_active: Optional[bool] = None class TriggerUserInfo(BaseModel): id: str name: str email: str class Config: from_attributes = True class TriggerResponse(BaseModel): id: str project_id: str name: str description: Optional[str] trigger_type: str conditions: Dict[str, Any] actions: List[Dict[str, Any]] is_active: bool created_by: Optional[str] created_at: datetime updated_at: datetime creator: Optional[TriggerUserInfo] = None class Config: from_attributes = True class TriggerListResponse(BaseModel): triggers: List[TriggerResponse] total: int class TriggerLogResponse(BaseModel): id: str trigger_id: str task_id: Optional[str] executed_at: datetime status: str details: Optional[Dict[str, Any]] error_message: Optional[str] class Config: from_attributes = True class TriggerLogListResponse(BaseModel): logs: List[TriggerLogResponse] total: int