Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions api/models/entry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pydantic import BaseModel, Field
from typing import Optional
from pydantic import BaseModel, Field, field_validator, model_validator
from typing import Optional, ClassVar
from datetime import datetime
from uuid import uuid4

Expand All @@ -23,26 +23,31 @@ class EntryCreate(BaseModel):

class Entry(BaseModel):
# TODO: Add field validation rules
# TODO: Add custom validators

# TODO: Add schema versioning
# TODO: Add data sanitization methods
schema_version: ClassVar[int] = 1

id: str = Field(
default_factory=lambda: str(uuid4()),
description="Unique identifier for the entry (UUID)."
description="Unique identifier for the entry (UUID).",
min_length=36, # Enforce UUID format length
max_length=36
)
work: str = Field(
...,
min_length=5, # Ensure work is not too short
max_length=256,
description="What did you work on today?"
)
struggle: str = Field(
...,
min_length=5, # Ensure struggle is not too short
max_length=256,
description="What’s one thing you struggled with today?"
)
intention: str = Field(
...,
min_length=5, # Ensures intention is not too short
max_length=256,
description="What will you study/work on tomorrow?"
)
Expand All @@ -54,7 +59,42 @@ class Entry(BaseModel):
default_factory=datetime.utcnow,
description="Timestamp when the entry was last updated."
)

# TODO: Add custom validators
@field_validator('id', mode='before')
@classmethod
def validate_uuid_format(cls, v: str):
"""Custom validator to ensure the ID is a valid UUID string."""
if v is not None and len(v) != 36:
raise ValueError('ID must be a 36-character UUID string.')
return v

@model_validator(mode='after')
def check_intention_for_tomorrow(self) -> 'Entry':
"""Custom model validator to check a business rule across fields."""
if "sleep" in self.intention.lower():
# This is an example of checking a rule across fields
print("Warning: Intention includes 'sleep'. Ensure productive work is planned.")
return self

# TODO: Add data sanitization methods
@field_validator('work', 'struggle', 'intention', mode='before')
@classmethod
def sanitize_input(cls, v: str):
"""Sanitization: Strip whitespace from input fields."""
if isinstance(v, str):
# Strip leading/trailing whitespace from user input
v = v.strip()
return v

@field_validator('work', 'struggle', 'intention', mode='after')
@classmethod
def normalize_case(cls, v: str):
"""Sanitization: Normalize text to sentence case (Capitalize first letter)."""
if v:
return v[0].upper() + v[1:]
return v

model_config = {
"json_encoders": {
datetime: lambda v: v.isoformat()
Expand Down