
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.
125 lines
4.6 KiB
Python
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()
|