Files
ppr-ng/backend/app/crud/crud_drone_request.py
T
2026-06-20 06:41:40 -04:00

190 lines
6.4 KiB
Python

from datetime import date, datetime
import secrets
from typing import List, Optional
from sqlalchemy import desc, func
from sqlalchemy.orm import Session
from app.core.frz import point_inside_swansea_frz
from app.crud.crud_journal import journal as crud_journal
from app.models.drone_request import DroneRequest, DroneRequestStatus
from app.models.journal import EntityType
from app.schemas.drone_request import DroneRequestCreate, DroneRequestUpdate
class CRUDDroneRequest:
def get(self, db: Session, request_id: int) -> Optional[DroneRequest]:
return db.query(DroneRequest).filter(DroneRequest.id == request_id).first()
def get_by_reference(self, db: Session, reference_number: str) -> Optional[DroneRequest]:
return db.query(DroneRequest).filter(DroneRequest.reference_number == reference_number).first()
def get_by_public_token(self, db: Session, token: str) -> Optional[DroneRequest]:
return db.query(DroneRequest).filter(DroneRequest.public_token == token).first()
def get_multi(
self,
db: Session,
skip: int = 0,
limit: int = 100,
status: Optional[DroneRequestStatus] = None,
date_from: Optional[date] = None,
date_to: Optional[date] = None,
) -> List[DroneRequest]:
query = db.query(DroneRequest)
if status:
query = query.filter(DroneRequest.status == status)
if date_from:
query = query.filter(func.date(DroneRequest.estimated_takeoff_at) >= date_from)
if date_to:
query = query.filter(func.date(DroneRequest.estimated_takeoff_at) <= date_to)
return query.order_by(desc(DroneRequest.submitted_at)).offset(skip).limit(limit).all()
def create(
self,
db: Session,
obj_in: DroneRequestCreate,
created_by: str = "public",
user_ip: str = "127.0.0.1",
submitted_via: str = "PUBLIC",
) -> DroneRequest:
reference_number = self._generate_reference(db)
payload = obj_in.dict()
notes = payload.pop("notes", None)
payload.pop("prototype_overlay", None)
payload.pop("location_inside_frz", None)
db_obj = DroneRequest(
**payload,
applicant_notes=notes,
location_inside_frz=point_inside_swansea_frz(payload["location_latitude"], payload["location_longitude"]),
reference_number=reference_number,
public_token=secrets.token_urlsafe(64),
status=DroneRequestStatus.NEW,
created_by=created_by,
submitted_ip=user_ip,
submitted_via=submitted_via,
)
db.add(db_obj)
db.commit()
db.refresh(db_obj)
crud_journal.log_change(
db,
EntityType.DRONE_REQUEST,
db_obj.id,
f"Drone request {db_obj.reference_number} created",
created_by,
user_ip,
)
return db_obj
def update(
self,
db: Session,
db_obj: DroneRequest,
obj_in: DroneRequestUpdate,
user: str = "system",
user_ip: str = "127.0.0.1",
) -> DroneRequest:
update_data = obj_in.dict(exclude_unset=True)
if "notes" in update_data:
update_data["applicant_notes"] = update_data.pop("notes")
update_data.pop("prototype_overlay", None)
update_data.pop("location_inside_frz", None)
if "location_latitude" in update_data or "location_longitude" in update_data:
lat = update_data.get("location_latitude", db_obj.location_latitude)
lng = update_data.get("location_longitude", db_obj.location_longitude)
update_data["location_inside_frz"] = point_inside_swansea_frz(lat, lng)
changes = []
for field, value in update_data.items():
old_value = getattr(db_obj, field)
if old_value != value:
changes.append(f"{field} changed from '{old_value}' to '{value}'")
setattr(db_obj, field, value)
if changes:
db.add(db_obj)
db.commit()
db.refresh(db_obj)
for change in changes:
crud_journal.log_change(db, EntityType.DRONE_REQUEST, db_obj.id, change, user, user_ip)
return db_obj
def update_status(
self,
db: Session,
request_id: int,
status: DroneRequestStatus,
comment: Optional[str] = None,
user: str = "system",
user_ip: str = "127.0.0.1",
) -> Optional[DroneRequest]:
db_obj = self.get(db, request_id)
if not db_obj:
return None
old_status = db_obj.status
db_obj.status = status
db_obj.status_changed_at = datetime.utcnow()
db_obj.status_changed_by = user
if comment:
db_obj.operator_comments = comment
db.add(db_obj)
db.commit()
db.refresh(db_obj)
entry = f"Status changed from {old_status.value} to {status.value}"
if comment:
entry = f"{entry}: {comment}"
crud_journal.log_change(db, EntityType.DRONE_REQUEST, db_obj.id, entry, user, user_ip)
return db_obj
def add_comment(
self,
db: Session,
request_id: int,
comment: str,
user: str = "system",
user_ip: str = "127.0.0.1",
) -> Optional[DroneRequest]:
db_obj = self.get(db, request_id)
if not db_obj:
return None
db_obj.operator_comments = comment
db.add(db_obj)
db.commit()
db.refresh(db_obj)
crud_journal.log_change(db, EntityType.DRONE_REQUEST, db_obj.id, f"Comment added: {comment}", user, user_ip)
return db_obj
def _generate_reference(self, db: Session) -> str:
prefix = f"DRN-{datetime.utcnow().strftime('%y%m%d')}"
references = db.query(DroneRequest.reference_number).filter(
DroneRequest.reference_number.like(f"{prefix}-%")
).all()
highest_sequence = 0
for (reference_number,) in references:
suffix = reference_number.rsplit("-", 1)[-1]
if suffix.isdigit():
highest_sequence = max(highest_sequence, int(suffix))
for sequence in range(highest_sequence + 1, highest_sequence + 11):
candidate = f"{prefix}-{sequence}"
if not self.get_by_reference(db, candidate):
return candidate
return f"{prefix}-{highest_sequence + 11}"
drone_request = CRUDDroneRequest()