Phase 1: Add Availability model and API

- Create Availability model with date, start_time, end_time
- Add availability schemas with 15-minute boundary validation
- Add admin endpoints:
  - GET /api/admin/availability - query by date range
  - PUT /api/admin/availability - set slots for a date
  - POST /api/admin/availability/copy - copy to multiple days
- Add 26 tests covering permissions, CRUD, and validation
This commit is contained in:
counterweight 2025-12-20 23:36:11 +01:00
parent 6c1a05d93d
commit 64d2e99d73
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
5 changed files with 788 additions and 4 deletions

View file

@ -1,8 +1,8 @@
"""Pydantic schemas for API request/response models."""
from datetime import datetime
from datetime import datetime, date, time
from typing import Generic, TypeVar
from pydantic import BaseModel, EmailStr
from pydantic import BaseModel, EmailStr, field_validator
class UserCredentials(BaseModel):
@ -140,6 +140,49 @@ class AdminUserResponse(BaseModel):
email: str
# =============================================================================
# Availability Schemas
# =============================================================================
class TimeSlot(BaseModel):
"""A single time slot (start and end time)."""
start_time: time
end_time: time
@field_validator("start_time", "end_time")
@classmethod
def validate_15min_boundary(cls, v: time) -> time:
"""Ensure times are on 15-minute boundaries."""
if v.minute not in (0, 15, 30, 45):
raise ValueError("Time must be on 15-minute boundary (:00, :15, :30, :45)")
if v.second != 0 or v.microsecond != 0:
raise ValueError("Time must not have seconds or microseconds")
return v
class AvailabilityDay(BaseModel):
"""Availability for a single day."""
date: date
slots: list[TimeSlot]
class AvailabilityResponse(BaseModel):
"""Response model for availability query."""
days: list[AvailabilityDay]
class SetAvailabilityRequest(BaseModel):
"""Request to set availability for a specific date."""
date: date
slots: list[TimeSlot]
class CopyAvailabilityRequest(BaseModel):
"""Request to copy availability from one day to others."""
source_date: date
target_dates: list[date]
# =============================================================================
# Meta/Constants Schemas
# =============================================================================