mitlist/be/app/schemas/chore.py
mohamad 0207c175ba feat: Enhance chore management with new update endpoint and structured logging
This commit introduces a new endpoint for updating chores of any type, allowing conversions between personal and group chores while enforcing permission checks. Additionally, structured logging has been implemented through a new middleware, improving request tracing and logging details for better monitoring and debugging. These changes aim to enhance the functionality and maintainability of the chore management system.
2025-06-21 15:00:13 +02:00

125 lines
4.6 KiB
Python

from __future__ import annotations
from datetime import date, datetime
from typing import Optional, List, Any
from pydantic import BaseModel, ConfigDict, field_validator, model_validator
from ..models import ChoreFrequencyEnum, ChoreTypeEnum, ChoreHistoryEventTypeEnum
from .user import UserPublic
class ChoreAssignmentPublic(BaseModel):
pass
class ChoreHistoryPublic(BaseModel):
id: int
event_type: ChoreHistoryEventTypeEnum
event_data: Optional[dict[str, Any]] = None
changed_by_user: Optional[UserPublic] = None
timestamp: datetime
model_config = ConfigDict(from_attributes=True)
class ChoreAssignmentHistoryPublic(BaseModel):
id: int
event_type: ChoreHistoryEventTypeEnum
event_data: Optional[dict[str, Any]] = None
changed_by_user: Optional[UserPublic] = None
timestamp: datetime
model_config = ConfigDict(from_attributes=True)
class ChoreBase(BaseModel):
name: str
description: Optional[str] = None
frequency: ChoreFrequencyEnum
custom_interval_days: Optional[int] = None
next_due_date: date # For creation, this will be the initial due date
type: ChoreTypeEnum
@model_validator(mode='after')
def validate_custom_frequency(self):
if self.frequency == ChoreFrequencyEnum.custom:
if self.custom_interval_days is None or self.custom_interval_days <= 0:
raise ValueError("custom_interval_days must be a positive integer when frequency is 'custom'")
return self
class ChoreCreate(ChoreBase):
group_id: Optional[int] = None
parent_chore_id: Optional[int] = None
@model_validator(mode='after')
def validate_group_id_with_type(self):
if self.type == ChoreTypeEnum.group and self.group_id is None:
raise ValueError("group_id is required for group chores")
if self.type == ChoreTypeEnum.personal and self.group_id is not None:
# Automatically clear group_id for personal chores instead of raising an error
self.group_id = None
return self
class ChoreUpdate(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
frequency: Optional[ChoreFrequencyEnum] = None
custom_interval_days: Optional[int] = None
next_due_date: Optional[date] = None # Allow updating next_due_date directly if needed
type: Optional[ChoreTypeEnum] = None
group_id: Optional[int] = None
parent_chore_id: Optional[int] = None # Allow moving a chore under a parent or removing association
# last_completed_at should generally not be updated directly by user
@model_validator(mode='after')
def validate_group_id_with_type(self):
if self.type == ChoreTypeEnum.group and self.group_id is None:
raise ValueError("group_id is required for group chores")
if self.type == ChoreTypeEnum.personal and self.group_id is not None:
# Automatically clear group_id for personal chores instead of raising an error
self.group_id = None
return self
class ChorePublic(ChoreBase):
id: int
group_id: Optional[int] = None
created_by_id: int
last_completed_at: Optional[datetime] = None
parent_chore_id: Optional[int] = None
created_at: datetime
updated_at: datetime
creator: Optional[UserPublic] = None # Embed creator UserPublic schema
assignments: List[ChoreAssignmentPublic] = []
history: List[ChoreHistoryPublic] = []
child_chores: List[ChorePublic] = []
model_config = ConfigDict(from_attributes=True)
# Chore Assignment Schemas
class ChoreAssignmentBase(BaseModel):
chore_id: int
assigned_to_user_id: int
due_date: date
class ChoreAssignmentCreate(ChoreAssignmentBase):
pass
class ChoreAssignmentUpdate(BaseModel):
# Only completion status and perhaps due_date can be updated for an assignment
is_complete: Optional[bool] = None
due_date: Optional[date] = None # If rescheduling an existing assignment is allowed
assigned_to_user_id: Optional[int] = None # For reassigning the chore
class ChoreAssignmentPublic(ChoreAssignmentBase):
id: int
is_complete: bool
completed_at: Optional[datetime] = None
created_at: datetime
updated_at: datetime
# Embed ChorePublic and UserPublic for richer responses
chore: Optional[ChorePublic] = None
assigned_user: Optional[UserPublic] = None
history: List[ChoreAssignmentHistoryPublic] = []
model_config = ConfigDict(from_attributes=True)
# To handle potential circular imports if ChorePublic needs GroupPublic and GroupPublic needs ChorePublic
# We can update forward refs after all models are defined.
ChorePublic.model_rebuild()
ChoreAssignmentPublic.model_rebuild()