111 lines
3.7 KiB
Python
111 lines
3.7 KiB
Python
from datetime import date, datetime
|
|
from enum import Enum
|
|
from typing import Any, Optional
|
|
|
|
from pydantic import 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_amsl: int = Field(..., ge=0)
|
|
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_amsl: Optional[int] = Field(None, ge=0)
|
|
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
|