Drones to use AGL

This commit is contained in:
2026-06-29 06:26:37 -04:00
parent 4b6dd9c93c
commit 8d8cb9ccad
12 changed files with 82 additions and 23 deletions
+4 -4
View File
@@ -52,7 +52,7 @@ async def _send_drone_email(drone_request, subject: str, message: str):
"takeoff_time": drone_request.estimated_takeoff_at.strftime("%Y-%m-%d %H:%M"),
"completion_time": drone_request.estimated_completion_at.strftime("%Y-%m-%d %H:%M"),
"location": drone_request.location_description or f"{drone_request.location_latitude}, {drone_request.location_longitude}",
"maximum_elevation_ft_amsl": drone_request.maximum_elevation_ft_amsl,
"maximum_elevation_ft_agl": drone_request.maximum_elevation_ft_agl,
"edit_url": f"{settings.base_url}/drone-request.html?token={drone_request.public_token}" if drone_request.public_token else None,
},
)
@@ -70,7 +70,7 @@ async def _send_drone_submitted_email(drone_request):
"takeoff_time": drone_request.estimated_takeoff_at.strftime("%Y-%m-%d %H:%M"),
"completion_time": drone_request.estimated_completion_at.strftime("%Y-%m-%d %H:%M"),
"location": drone_request.location_description or f"{drone_request.location_latitude}, {drone_request.location_longitude}",
"maximum_elevation_ft_amsl": drone_request.maximum_elevation_ft_amsl,
"maximum_elevation_ft_agl": drone_request.maximum_elevation_ft_agl,
"edit_url": f"{settings.base_url}/drone-request.html?token={drone_request.public_token}" if drone_request.public_token else None,
},
)
@@ -93,7 +93,7 @@ async def _send_drone_tower_notification(drone_request):
"takeoff_time": drone_request.estimated_takeoff_at.strftime("%Y-%m-%d %H:%M"),
"completion_time": drone_request.estimated_completion_at.strftime("%Y-%m-%d %H:%M"),
"location": drone_request.location_description or f"{drone_request.location_latitude}, {drone_request.location_longitude}",
"maximum_elevation_ft_amsl": drone_request.maximum_elevation_ft_amsl,
"maximum_elevation_ft_agl": drone_request.maximum_elevation_ft_agl,
"inside_frz": "Yes" if drone_request.location_inside_frz else "No",
"notes": drone_request.applicant_notes,
"requests_url": f"{settings.base_url}/drone-requests",
@@ -115,7 +115,7 @@ async def _send_drone_approved_email(drone_request, message: Optional[str] = Non
"takeoff_time": drone_request.estimated_takeoff_at.strftime("%Y-%m-%d %H:%M"),
"completion_time": drone_request.estimated_completion_at.strftime("%Y-%m-%d %H:%M"),
"location": drone_request.location_description or f"{drone_request.location_latitude}, {drone_request.location_longitude}",
"maximum_elevation_ft_amsl": drone_request.maximum_elevation_ft_amsl,
"maximum_elevation_ft_agl": drone_request.maximum_elevation_ft_agl,
"edit_url": f"{settings.base_url}/drone-request.html?token={drone_request.public_token}" if drone_request.public_token else None,
},
)
+1 -1
View File
@@ -35,7 +35,7 @@ class DroneRequest(Base):
estimated_completion_time = Column(String(8), nullable=True)
estimated_takeoff_at = Column(DateTime, nullable=False, index=True)
estimated_completion_at = Column(DateTime, nullable=False, index=True)
maximum_elevation_ft_amsl = Column(Integer, nullable=False)
maximum_elevation_ft_agl = Column(Integer, nullable=False)
location_description = Column(Text, nullable=True)
location_latitude = Column(Float, nullable=False)
+11 -3
View File
@@ -2,7 +2,7 @@ from datetime import date, datetime
from enum import Enum
from typing import Any, Optional
from pydantic import BaseModel, EmailStr, Field, validator
from pydantic import AliasChoices, BaseModel, EmailStr, Field, validator
class DroneRequestStatus(str, Enum):
@@ -20,7 +20,11 @@ class DroneRequestBase(BaseModel):
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)
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)
@@ -68,7 +72,11 @@ class DroneRequestUpdate(BaseModel):
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)
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)
@@ -53,7 +53,7 @@
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #dfe5eb; background: #f8fafc;"><strong>Max elevation</strong></td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_amsl }} ft AMSL</td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_agl }} ft AGL</td>
</tr>
</table>
@@ -47,7 +47,7 @@
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #dfe5eb; background: #f8fafc;"><strong>Max elevation</strong></td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_amsl }} ft AMSL</td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_agl }} ft AGL</td>
</tr>
</table>
@@ -31,7 +31,7 @@
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Completion</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ completion_time }}</td></tr>
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Location</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ location }}</td></tr>
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Inside FRZ</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ inside_frz }}</td></tr>
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Max elevation</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_amsl }} ft AMSL</td></tr>
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Max elevation</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_agl }} ft AGL</td></tr>
<tr><td style="padding: 10px; border: 1px solid #dfe5eb; font-weight: bold;">Applicant notes</td><td style="padding: 10px; border: 1px solid #dfe5eb;">{{ notes or '-' }}</td></tr>
</table>
</td>
@@ -47,7 +47,7 @@
</tr>
<tr>
<td style="padding: 12px; border: 1px solid #dfe5eb; background: #f8fafc;"><strong>Max elevation</strong></td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_amsl }} ft AMSL</td>
<td style="padding: 12px; border: 1px solid #dfe5eb;">{{ maximum_elevation_ft_agl }} ft AGL</td>
</tr>
</table>