BE-CAL-API-003: implement Calendar edit API for real and virtual slots
- Add TimeSlotEdit schema (partial update, all fields optional)
- Add TimeSlotEditResponse schema
- Add PATCH /calendar/slots/{slot_id} for editing real slots
- Add PATCH /calendar/slots/virtual/{virtual_id} for editing virtual slots
- Triggers materialization before applying edits
- Detaches from plan after edit
- Both endpoints enforce past-slot immutability, overlap detection, plan
detachment, and workload warnings
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
BE-CAL-004: MinimumWorkload read/write schemas.
|
||||
BE-CAL-API-001: TimeSlot create / response schemas.
|
||||
BE-CAL-API-002: Calendar day-view query schemas.
|
||||
BE-CAL-API-003: TimeSlot edit schemas.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -155,6 +156,49 @@ class TimeSlotCreateResponse(BaseModel):
|
||||
warnings: list[WorkloadWarningItem] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TimeSlot edit (BE-CAL-API-003)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TimeSlotEdit(BaseModel):
|
||||
"""Request body for editing a calendar slot.
|
||||
|
||||
All fields are optional — only provided fields are updated.
|
||||
The caller must supply either ``slot_id`` (for real slots) or
|
||||
``virtual_id`` (for plan-generated virtual slots) in the URL path.
|
||||
"""
|
||||
slot_type: Optional[SlotTypeEnum] = Field(None, description="New slot type")
|
||||
scheduled_at: Optional[time] = Field(None, description="New start time HH:MM")
|
||||
estimated_duration: Optional[int] = Field(None, ge=1, le=50, description="New duration in minutes (1-50)")
|
||||
event_type: Optional[EventTypeEnum] = Field(None, description="New event type")
|
||||
event_data: Optional[dict[str, Any]] = Field(None, description="New event details JSON")
|
||||
priority: Optional[int] = Field(None, ge=0, le=99, description="New priority 0-99")
|
||||
|
||||
@field_validator("scheduled_at")
|
||||
@classmethod
|
||||
def _validate_scheduled_at(cls, v: Optional[time]) -> Optional[time]:
|
||||
if v is not None and v.hour > 23:
|
||||
raise ValueError("scheduled_at hour must be between 00 and 23")
|
||||
return v
|
||||
|
||||
@model_validator(mode="after")
|
||||
def _at_least_one_field(self) -> "TimeSlotEdit":
|
||||
"""Ensure at least one editable field is provided."""
|
||||
if all(
|
||||
getattr(self, f) is None
|
||||
for f in ("slot_type", "scheduled_at", "estimated_duration",
|
||||
"event_type", "event_data", "priority")
|
||||
):
|
||||
raise ValueError("At least one field must be provided for edit")
|
||||
return self
|
||||
|
||||
|
||||
class TimeSlotEditResponse(BaseModel):
|
||||
"""Response after editing a slot — includes the updated slot and any warnings."""
|
||||
slot: TimeSlotResponse
|
||||
warnings: list[WorkloadWarningItem] = Field(default_factory=list)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Calendar day-view query (BE-CAL-API-002)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user