Files
2026-06-29 06:26:37 -04:00

119 lines
3.9 KiB
Python

from datetime import date, datetime
from enum import Enum
from typing import Any, Optional
from pydantic import AliasChoices, BaseModel, EmailStr, Field, validator
class DroneRequestStatus(str, Enum):
NEW = "NEW"
APPROVED = "APPROVED"
DENIED = "DENIED"
CANCELED = "CANCELED"
INFLIGHT = "INFLIGHT"
COMPLETED = "COMPLETED"
class DroneRequestBase(BaseModel):
operator_name: str = Field(..., max_length=128)
operator_id: Optional[str] = Field(None, max_length=64)
flight_date: Optional[date] = None
estimated_takeoff_time: Optional[str] = Field(None, max_length=8)
estimated_completion_time: Optional[str] = Field(None, max_length=8)
maximum_elevation_ft_agl: int = Field(
...,
ge=0,
validation_alias=AliasChoices("maximum_elevation_ft_agl", "maximum_elevation_ft_amsl"),
)
location_description: Optional[str] = None
location_latitude: float = Field(..., ge=-90, le=90)
location_longitude: float = Field(..., ge=-180, le=180)
location_inside_frz: Optional[bool] = None
flyer_name: Optional[str] = Field(None, max_length=128)
flyer_id: Optional[str] = Field(None, max_length=64)
email: EmailStr
phone: Optional[str] = Field(None, max_length=32)
notes: Optional[str] = None
estimated_takeoff_at: datetime
estimated_completion_at: datetime
prototype_overlay: Optional[dict[str, Any]] = None
@validator("operator_name")
def validate_operator_name(cls, value):
value = value.strip()
if not value:
raise ValueError("Operator name is required")
return value
@validator("location_inside_frz", pre=True)
def parse_inside_frz(cls, value):
if isinstance(value, str):
normalized = value.strip().lower()
if normalized in {"yes", "true", "1", "y"}:
return True
if normalized in {"no", "false", "0", "n"}:
return False
return value
class DroneRequestCreate(DroneRequestBase):
pass
class DroneRequestUpdate(BaseModel):
operator_name: Optional[str] = Field(None, max_length=128)
operator_id: Optional[str] = Field(None, max_length=64)
flyer_name: Optional[str] = Field(None, max_length=128)
flyer_id: Optional[str] = Field(None, max_length=64)
email: Optional[EmailStr] = None
phone: Optional[str] = Field(None, max_length=32)
flight_date: Optional[date] = None
estimated_takeoff_time: Optional[str] = Field(None, max_length=8)
estimated_completion_time: Optional[str] = Field(None, max_length=8)
estimated_takeoff_at: Optional[datetime] = None
estimated_completion_at: Optional[datetime] = None
maximum_elevation_ft_agl: Optional[int] = Field(
None,
ge=0,
validation_alias=AliasChoices("maximum_elevation_ft_agl", "maximum_elevation_ft_amsl"),
)
location_description: Optional[str] = None
location_latitude: Optional[float] = Field(None, ge=-90, le=90)
location_longitude: Optional[float] = Field(None, ge=-180, le=180)
location_inside_frz: Optional[bool] = None
notes: Optional[str] = None
prototype_overlay: Optional[dict[str, Any]] = None
operator_comments: Optional[str] = None
class DroneRequestStatusUpdate(BaseModel):
status: DroneRequestStatus
comment: Optional[str] = None
class DroneRequestComment(BaseModel):
comment: str = Field(..., min_length=1)
email_applicant: bool = True
class DroneRequest(DroneRequestBase):
id: int
reference_number: str
status: DroneRequestStatus
operator_comments: Optional[str] = None
submitted_via: str
submitted_ip: Optional[str] = None
created_by: Optional[str] = None
submitted_at: datetime
updated_at: datetime
status_changed_at: Optional[datetime] = None
status_changed_by: Optional[str] = None
class Config:
from_attributes = True
class DroneRequestPublicSubmission(DroneRequest):
request_id: str
secure_link: str