Spaces:
Sleeping
Sleeping
| """ | |
| Task model migrated to SQLModel with PostgreSQL support. | |
| Extended for 012-advanced-todo-features with due dates, recurrence, and reminders. | |
| """ | |
| from typing import Optional | |
| from datetime import datetime | |
| from enum import Enum | |
| from sqlmodel import SQLModel, Field, Column | |
| from sqlalchemy import DateTime | |
| class RecurrencePattern(str, Enum): | |
| """Recurrence pattern enumeration for recurring tasks.""" | |
| DAILY = "daily" | |
| WEEKLY = "weekly" | |
| BI_WEEKLY = "bi-weekly" | |
| MONTHLY = "monthly" | |
| YEARLY = "yearly" | |
| class Task(SQLModel, table=True): | |
| """Task entity for todo items.""" | |
| __tablename__ = "tasks" | |
| # Existing fields from 001-todo-ai-chatbot | |
| id: Optional[int] = Field(default=None, primary_key=True) | |
| user_id: int = Field(index=True) # Removed foreign_key constraint for demo users | |
| title: str = Field(max_length=200, min_length=1) | |
| description: str = Field(default="", max_length=1000) | |
| completed: bool = Field(default=False) | |
| created_at: datetime = Field(default_factory=datetime.utcnow) | |
| updated_at: datetime = Field(default_factory=datetime.utcnow) | |
| # Offline sync support | |
| client_id: Optional[str] = Field(default=None, max_length=100, index=True) | |
| version: int = Field(default=1) | |
| # NEW FIELDS for 012-advanced-todo-features (due dates, recurrence, reminders) | |
| due_date: Optional[datetime] = Field( | |
| default=None, | |
| sa_column=Column(DateTime(timezone=True)), | |
| description="Task deadline in UTC timezone" | |
| ) | |
| recurrence_pattern: Optional[RecurrencePattern] = Field( | |
| default=None, | |
| description="Recurrence type: daily/weekly/bi-weekly/monthly/yearly" | |
| ) | |
| is_recurring: bool = Field( | |
| default=False, | |
| description="Whether task auto-creates next instance on completion" | |
| ) | |
| reminder_minutes: int = Field( | |
| default=15, | |
| ge=0, | |
| le=1440, # Max 24 hours | |
| description="Minutes before due_date to send reminder (0-1440)" | |
| ) | |
| next_occurrence: Optional[datetime] = Field( | |
| default=None, | |
| sa_column=Column(DateTime(timezone=True)), | |
| description="Auto-calculated next due date for recurring tasks" | |
| ) | |
| def validate_due_date(self) -> None: | |
| """ | |
| Validate due date constraints. | |
| Raises: | |
| ValueError: If due_date is not timezone-aware | |
| """ | |
| if self.due_date and self.due_date.tzinfo is None: | |
| raise ValueError("due_date must be timezone-aware (UTC)") | |
| def validate_recurrence(self) -> None: | |
| """ | |
| Validate recurrence configuration. | |
| Raises: | |
| ValueError: If recurrence settings are invalid | |
| """ | |
| if self.is_recurring and not self.recurrence_pattern: | |
| raise ValueError("is_recurring requires recurrence_pattern to be set") | |
| if self.is_recurring and not self.due_date: | |
| raise ValueError("Recurring tasks must have a due_date") | |
| if self.recurrence_pattern and not self.is_recurring: | |
| # Auto-set is_recurring if pattern is set | |
| self.is_recurring = True | |
| def calculate_next_occurrence(self) -> datetime: | |
| """ | |
| Calculate next occurrence for recurring tasks. | |
| Returns: | |
| Next occurrence datetime in UTC | |
| Raises: | |
| ValueError: If not a recurring task or missing due_date | |
| """ | |
| if not self.is_recurring or not self.due_date or not self.recurrence_pattern: | |
| raise ValueError("Can only calculate next occurrence for recurring tasks") | |
| from ..utils.recurrence_calculator import RecurrenceCalculator | |
| return RecurrenceCalculator.calculate_next_occurrence( | |
| self.due_date, | |
| self.recurrence_pattern.value | |
| ) | |
| class TaskCreate(SQLModel): | |
| """Schema for creating a new task.""" | |
| title: str = Field(max_length=200, min_length=1) | |
| description: str = Field(default="", max_length=1000) | |
| client_id: Optional[str] = Field(default=None, max_length=100) | |
| class TaskUpdate(SQLModel): | |
| """Schema for updating a task.""" | |
| title: Optional[str] = Field(default=None, max_length=200, min_length=1) | |
| description: Optional[str] = Field(default=None, max_length=1000) | |
| completed: Optional[bool] = Field(default=None) | |
| class TaskResponse(SQLModel): | |
| """Schema for task response.""" | |
| id: int | |
| user_id: int | |
| title: str | |
| description: str | |
| completed: bool | |
| created_at: datetime | |
| updated_at: datetime | |
| client_id: Optional[str] = None | |
| version: int | |
| # NEW FIELDS for 012-advanced-todo-features | |
| due_date: Optional[datetime] = None | |
| recurrence_pattern: Optional[RecurrencePattern] = None | |
| is_recurring: bool = False | |
| reminder_minutes: int = 15 | |
| next_occurrence: Optional[datetime] = None | |