fix: harden habit input and lifecycle
ci / gitleaks (push) Successful in 7s
ci / docker (push) Successful in 3m21s

This commit is contained in:
2026-09-09 14:08:19 +08:00
parent 489d120159
commit bc4c281658
10 changed files with 735 additions and 83 deletions
+28 -3
View File
@@ -1,7 +1,7 @@
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, model_validator
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
class InitializeRequest(BaseModel):
@@ -45,6 +45,14 @@ class SessionOut(BaseModel):
class NameUpdate(BaseModel):
name: str = Field(min_length=1, max_length=120)
@field_validator("name")
@classmethod
def clean_name(cls, value):
value = value.strip()
if not value:
raise ValueError("name cannot be blank")
return value
class FolderCreate(NameUpdate):
pass
@@ -56,8 +64,7 @@ class FolderOut(BaseModel):
name: str
class ListCreate(BaseModel):
name: str = Field(min_length=1, max_length=120)
class ListCreate(NameUpdate):
folder_id: UUID | None = None
@@ -80,6 +87,14 @@ class TaskCreate(BaseModel):
parent_id: UUID | None = None
rrule: str | None = Field(default=None, min_length=5, max_length=1000)
@field_validator("title")
@classmethod
def clean_title(cls, value):
value = value.strip()
if not value:
raise ValueError("title cannot be blank")
return value
class TaskUpdate(BaseModel):
title: str | None = Field(default=None, min_length=1, max_length=500)
@@ -91,6 +106,16 @@ class TaskUpdate(BaseModel):
list_id: UUID | None = None
version: int = Field(ge=1)
@field_validator("title")
@classmethod
def clean_title(cls, value):
if value is None:
return value
value = value.strip()
if not value:
raise ValueError("title cannot be blank")
return value
@model_validator(mode="after")
def reject_null_non_nullable_fields(self):
for field in ("title", "description", "priority", "completed", "list_id", "due_has_time"):