Phase 3.1: Enhanced Chore Logging and Reporting System
This commit is contained in:
4
backend/app/schemas/__init__.py
Normal file
4
backend/app/schemas/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# Schemas package
|
||||
from app.schemas import auth, chore, user, chore_completion_log
|
||||
|
||||
__all__ = ["auth", "chore", "user", "chore_completion_log"]
|
||||
11
backend/app/schemas/auth.py
Normal file
11
backend/app/schemas/auth.py
Normal file
@@ -0,0 +1,11 @@
|
||||
"""Authentication schemas."""
|
||||
from pydantic import BaseModel
|
||||
|
||||
class Token(BaseModel):
|
||||
"""Token response schema."""
|
||||
access_token: str
|
||||
token_type: str
|
||||
|
||||
class TokenData(BaseModel):
|
||||
"""Token data schema."""
|
||||
username: str | None = None
|
||||
99
backend/app/schemas/chore.py
Normal file
99
backend/app/schemas/chore.py
Normal file
@@ -0,0 +1,99 @@
|
||||
"""Chore schemas."""
|
||||
from pydantic import BaseModel, ConfigDict, field_validator
|
||||
from typing import Optional, Union, List
|
||||
from datetime import datetime, date
|
||||
|
||||
from app.models.chore import ChoreFrequency, ChoreStatus, ChoreAssignmentType
|
||||
|
||||
|
||||
class ChoreBase(BaseModel):
|
||||
"""Base chore schema."""
|
||||
title: str
|
||||
description: Optional[str] = None
|
||||
room: str
|
||||
frequency: ChoreFrequency
|
||||
points: Optional[int] = 0
|
||||
image_url: Optional[str] = None
|
||||
assignment_type: Optional[ChoreAssignmentType] = ChoreAssignmentType.ANY_ONE
|
||||
due_date: Optional[Union[datetime, date, str]] = None
|
||||
|
||||
@field_validator('due_date', mode='before')
|
||||
@classmethod
|
||||
def parse_due_date(cls, v):
|
||||
"""Parse due_date to handle various formats."""
|
||||
if v is None or v == '' or isinstance(v, (datetime, date)):
|
||||
return None if v == '' else v
|
||||
if isinstance(v, str):
|
||||
# Try parsing as datetime first
|
||||
for fmt in ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%d']:
|
||||
try:
|
||||
return datetime.strptime(v, fmt)
|
||||
except ValueError:
|
||||
continue
|
||||
# If no format matches, return None instead of the invalid string
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
class ChoreCreate(ChoreBase):
|
||||
"""Schema for creating a chore."""
|
||||
assigned_user_ids: Optional[List[int]] = [] # Multiple users can be assigned
|
||||
|
||||
|
||||
class ChoreUpdate(BaseModel):
|
||||
"""Schema for updating a chore."""
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
room: Optional[str] = None
|
||||
frequency: Optional[ChoreFrequency] = None
|
||||
points: Optional[int] = None
|
||||
status: Optional[ChoreStatus] = None
|
||||
assignment_type: Optional[ChoreAssignmentType] = None
|
||||
assigned_user_ids: Optional[List[int]] = None # Multiple users
|
||||
due_date: Optional[Union[datetime, date, str]] = None
|
||||
|
||||
@field_validator('due_date', mode='before')
|
||||
@classmethod
|
||||
def parse_due_date(cls, v):
|
||||
"""Parse due_date to handle various formats."""
|
||||
if v is None or v == '' or isinstance(v, (datetime, date)):
|
||||
return None if v == '' else v
|
||||
if isinstance(v, str):
|
||||
# Try parsing as datetime first
|
||||
for fmt in ['%Y-%m-%dT%H:%M:%S', '%Y-%m-%d']:
|
||||
try:
|
||||
return datetime.strptime(v, fmt)
|
||||
except ValueError:
|
||||
continue
|
||||
# If no format matches, return None instead of the invalid string
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
class AssignedUserDetail(BaseModel):
|
||||
"""User info for chore assignment."""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
username: str
|
||||
full_name: str
|
||||
avatar_url: Optional[str] = None
|
||||
birthday: Optional[date] = None
|
||||
completed_at: Optional[datetime] = None # When this user completed the chore
|
||||
|
||||
|
||||
class Chore(ChoreBase):
|
||||
"""Schema for a chore response."""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
status: ChoreStatus
|
||||
points: int
|
||||
assignment_type: ChoreAssignmentType
|
||||
assigned_users: List[AssignedUserDetail] = [] # Multiple users with completion status
|
||||
completed_at: Optional[datetime] = None
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
# Legacy field for backward compatibility
|
||||
assigned_user_id: Optional[int] = None
|
||||
66
backend/app/schemas/chore_completion_log.py
Normal file
66
backend/app/schemas/chore_completion_log.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""Schemas for Chore Completion Logs."""
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class ChoreCompletionLogBase(BaseModel):
|
||||
"""Base schema for chore completion log."""
|
||||
notes: Optional[str] = Field(None, description="Optional notes about the completion")
|
||||
|
||||
|
||||
class ChoreCompletionLogCreate(ChoreCompletionLogBase):
|
||||
"""Schema for creating a chore completion log."""
|
||||
chore_id: int = Field(..., description="ID of the chore being completed")
|
||||
user_id: int = Field(..., description="ID of the user completing the chore")
|
||||
completed_at: Optional[datetime] = Field(None, description="When the chore was completed (defaults to now)")
|
||||
|
||||
|
||||
class ChoreCompletionLogUpdate(BaseModel):
|
||||
"""Schema for updating a chore completion log."""
|
||||
notes: Optional[str] = Field(None, description="Update notes about the completion")
|
||||
verified_by_user_id: Optional[int] = Field(None, description="ID of user verifying the completion")
|
||||
|
||||
|
||||
class ChoreCompletionLog(ChoreCompletionLogBase):
|
||||
"""Schema for chore completion log response."""
|
||||
id: int
|
||||
chore_id: int
|
||||
user_id: int
|
||||
completed_at: datetime
|
||||
verified_by_user_id: Optional[int] = None
|
||||
created_at: datetime
|
||||
|
||||
# Nested objects for expanded responses
|
||||
chore_title: Optional[str] = None
|
||||
user_name: Optional[str] = None
|
||||
user_avatar: Optional[str] = None
|
||||
verified_by_name: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class WeeklyChoreReport(BaseModel):
|
||||
"""Schema for weekly chore completion report."""
|
||||
start_date: datetime
|
||||
end_date: datetime
|
||||
total_completions: int
|
||||
completions_by_user: dict[str, int] # {username: count}
|
||||
completions_by_chore: dict[str, int] # {chore_title: count}
|
||||
completions_by_day: dict[str, int] # {day: count}
|
||||
top_performers: list[dict] # [{username, count, avatar_url}]
|
||||
recent_completions: list[ChoreCompletionLog]
|
||||
|
||||
|
||||
class UserChoreStats(BaseModel):
|
||||
"""Schema for user-specific chore statistics."""
|
||||
user_id: int
|
||||
username: str
|
||||
full_name: Optional[str] = None
|
||||
avatar_url: Optional[str] = None
|
||||
total_completions: int
|
||||
completions_this_week: int
|
||||
completions_this_month: int
|
||||
favorite_chore: Optional[str] = None
|
||||
recent_completions: list[ChoreCompletionLog]
|
||||
47
backend/app/schemas/user.py
Normal file
47
backend/app/schemas/user.py
Normal file
@@ -0,0 +1,47 @@
|
||||
"""User schemas."""
|
||||
from pydantic import BaseModel, Field
|
||||
from datetime import datetime, date
|
||||
from typing import Optional
|
||||
|
||||
class UserBase(BaseModel):
|
||||
"""Base user schema."""
|
||||
username: str
|
||||
email: str # Changed from EmailStr to allow .local domains for home networks
|
||||
full_name: Optional[str] = None
|
||||
discord_id: Optional[str] = None
|
||||
profile_picture: Optional[str] = None
|
||||
avatar_url: Optional[str] = None
|
||||
birthday: Optional[date] = None
|
||||
|
||||
class UserCreate(UserBase):
|
||||
"""Schema for creating a user."""
|
||||
password: str
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
"""Schema for updating a user."""
|
||||
email: Optional[str] = None
|
||||
full_name: Optional[str] = None
|
||||
discord_id: Optional[str] = None
|
||||
profile_picture: Optional[str] = None
|
||||
birthday: Optional[date] = None
|
||||
password: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
class UserAdminUpdate(UserUpdate):
|
||||
"""Schema for admin updating a user (includes admin-only fields)."""
|
||||
is_admin: Optional[bool] = None
|
||||
|
||||
class UserResponse(UserBase):
|
||||
"""Schema for user response."""
|
||||
id: int
|
||||
is_active: bool
|
||||
is_admin: bool
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
"""Schema for user login."""
|
||||
username: str
|
||||
password: str
|
||||
Reference in New Issue
Block a user