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, start_date, due_date, custom_fields") operator: str = Field(..., description="Operator: equals, not_equals, changed_to, changed_from, before, after, in") value: Any = Field(..., description="Value to compare against") field_id: Optional[str] = Field(None, description="Custom field ID when field is custom_fields") class TriggerRule(BaseModel): """Rule for composite field_change triggers.""" field: str = Field(..., description="Field to check: status_id, assignee_id, priority, start_date, due_date, custom_fields") operator: str = Field(..., description="Operator: equals, not_equals, changed_to, changed_from, before, after, in") value: Any = Field(..., description="Value to compare against") field_id: Optional[str] = Field(None, description="Custom field ID when field is custom_fields") 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, start_date, due_date, custom_fields") operator: Optional[str] = Field(None, description="Operator: equals, not_equals, changed_to, changed_from, before, after, in") value: Optional[Any] = Field(None, description="Value to compare against") field_id: Optional[str] = Field(None, description="Custom field ID when field is custom_fields") logic: Optional[str] = Field(None, description="Composite logic: and") rules: Optional[List[TriggerRule]] = None # 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): """Action configuration for triggers. Supported action types: - notify: Send notification (requires target, optional template) - update_field: Update task field (requires field, value) - auto_assign: Auto-assign task (requires strategy, optional user_id for specific_user) """ type: str = Field(..., description="Action type: notify, update_field, auto_assign") # Notify action fields target: Optional[str] = Field(None, description="Target: assignee, creator, project_owner, project_members, department:, role:, user:") template: Optional[str] = Field(None, description="Message template with variables") # update_field action fields (FEAT-014) field: Optional[str] = Field(None, description="Field to update: priority, status_id, due_date") value: Optional[Any] = Field(None, description="New value for the field") # auto_assign action fields (FEAT-015) strategy: Optional[str] = Field(None, description="Strategy: round_robin, least_loaded, specific_user") user_id: Optional[str] = Field(None, description="User ID for specific_user strategy") 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