Files
grateful-journal/backend/models.py
2026-03-05 12:43:44 +05:30

217 lines
5.5 KiB
Python

from pydantic import BaseModel, Field # type: ignore
from datetime import datetime
from typing import Optional, List
from enum import Enum
from bson import ObjectId
# ========== Helper for ObjectId handling ==========
class PyObjectId(ObjectId):
"""Custom type for ObjectId serialization"""
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v):
if isinstance(v, ObjectId):
return v
if isinstance(v, str):
return ObjectId(v)
raise ValueError(f"Invalid ObjectId: {v}")
def __repr__(self):
return f"ObjectId('{self}')"
# ========== User Models ==========
class UserCreate(BaseModel):
email: str
displayName: Optional[str] = None
photoURL: Optional[str] = None
class UserUpdate(BaseModel):
displayName: Optional[str] = None
photoURL: Optional[str] = None
theme: Optional[str] = None
class Config:
json_schema_extra = {
"example": {
"displayName": "John Doe",
"theme": "dark"
}
}
class User(BaseModel):
id: str = Field(alias="_id")
email: str
displayName: Optional[str] = None
photoURL: Optional[str] = None
createdAt: datetime
updatedAt: datetime
theme: str = "light"
class Config:
from_attributes = True
populate_by_name = True
json_schema_extra = {
"example": {
"_id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"displayName": "John Doe",
"photoURL": "https://example.com/photo.jpg",
"createdAt": "2026-03-05T00:00:00Z",
"updatedAt": "2026-03-05T00:00:00Z",
"theme": "light"
}
}
# ========== Journal Entry Models ==========
class MoodEnum(str, Enum):
happy = "happy"
sad = "sad"
neutral = "neutral"
anxious = "anxious"
grateful = "grateful"
class EncryptionMetadata(BaseModel):
"""Optional encryption metadata for entries"""
encrypted: bool = False
iv: Optional[str] = None # Initialization vector as base64 string
algorithm: Optional[str] = None # e.g., "AES-256-GCM"
class Config:
json_schema_extra = {
"example": {
"encrypted": False,
"iv": None,
"algorithm": None
}
}
class JournalEntryCreate(BaseModel):
title: str
content: str
mood: Optional[MoodEnum] = None
tags: Optional[List[str]] = None
isPublic: Optional[bool] = False
entryDate: Optional[datetime] = None # Logical journal date; defaults to today
encryption: Optional[EncryptionMetadata] = None
class Config:
json_schema_extra = {
"example": {
"title": "Today's Gratitude",
"content": "I'm grateful for...",
"mood": "grateful",
"tags": ["work", "family"],
"isPublic": False,
"entryDate": "2026-03-05T00:00:00Z"
}
}
class JournalEntryUpdate(BaseModel):
title: Optional[str] = None
content: Optional[str] = None
mood: Optional[MoodEnum] = None
tags: Optional[List[str]] = None
isPublic: Optional[bool] = None
encryption: Optional[EncryptionMetadata] = None
class Config:
json_schema_extra = {
"example": {
"title": "Updated Title",
"mood": "happy"
}
}
class JournalEntry(BaseModel):
id: str = Field(alias="_id")
userId: str # ObjectId as string
title: str
content: str
mood: Optional[MoodEnum] = None
tags: Optional[List[str]] = []
isPublic: bool = False
entryDate: datetime # Logical journal date
createdAt: datetime
updatedAt: datetime
encryption: EncryptionMetadata = Field(default_factory=lambda: EncryptionMetadata())
class Config:
from_attributes = True
populate_by_name = True
json_schema_extra = {
"example": {
"_id": "507f1f77bcf86cd799439011",
"userId": "507f1f77bcf86cd799439012",
"title": "Today's Gratitude",
"content": "I'm grateful for...",
"mood": "grateful",
"tags": ["work", "family"],
"isPublic": False,
"entryDate": "2026-03-05T00:00:00Z",
"createdAt": "2026-03-05T12:00:00Z",
"updatedAt": "2026-03-05T12:00:00Z",
"encryption": {
"encrypted": False,
"iv": None,
"algorithm": None
}
}
}
# ========== Pagination Models ==========
class PaginationMeta(BaseModel):
"""Pagination metadata for list responses"""
total: int
limit: int
skip: int
hasMore: bool
class Config:
json_schema_extra = {
"example": {
"total": 42,
"limit": 20,
"skip": 0,
"hasMore": True
}
}
class EntriesListResponse(BaseModel):
"""Response model for paginated entries"""
entries: List[JournalEntry]
pagination: PaginationMeta
class Config:
json_schema_extra = {
"example": {
"entries": [],
"pagination": {
"total": 42,
"limit": 20,
"skip": 0,
"hasMore": True
}
}
}