Implement flight filtering

This commit is contained in:
april 2024-01-11 11:49:30 -06:00
parent c1050d8234
commit ab126ceb06
4 changed files with 74 additions and 21 deletions

View File

@ -1,5 +1,8 @@
from typing import Any
from bson import ObjectId from bson import ObjectId
from fastapi import HTTPException from fastapi import HTTPException
from pymongo.errors import WriteError
from database.db import aircraft_collection from database.db import aircraft_collection
from schemas.aircraft import AircraftDisplaySchema, AircraftCreateSchema, aircraft_display_helper, aircraft_add_helper from schemas.aircraft import AircraftDisplaySchema, AircraftCreateSchema, aircraft_display_helper, aircraft_add_helper
@ -71,7 +74,7 @@ async def update_aircraft(body: AircraftCreateSchema, id: str) -> AircraftDispla
:param body: Updated aircraft data :param body: Updated aircraft data
:param id: ID of aircraft to update :param id: ID of aircraft to update
:return: ID of updated aircraft :return: Updated aircraft
""" """
aircraft = await aircraft_collection.find_one({"_id": ObjectId(id)}) aircraft = await aircraft_collection.find_one({"_id": ObjectId(id)})
@ -82,7 +85,32 @@ async def update_aircraft(body: AircraftCreateSchema, id: str) -> AircraftDispla
if updated_aircraft is None: if updated_aircraft is None:
raise HTTPException(500, "Failed to update flight") raise HTTPException(500, "Failed to update flight")
return id return AircraftDisplaySchema(**body.model_dump())
async def update_aircraft_field(field: str, value: Any, id: str) -> AircraftDisplaySchema:
"""
Update a single field of the given aircraft in the database
:param field: Field to update
:param value: Value to set field to
:param id: ID of aircraft to update
:return: Updated aircraft
"""
aircraft = await aircraft_collection.find_one({"_id": ObjectId(id)})
if aircraft is None:
raise HTTPException(404, "Aircraft not found")
try:
updated_aircraft = await aircraft_collection.update_one({"_id": ObjectId(id)}, {"$set": {field: value}})
except WriteError as e:
raise HTTPException(400, e.details)
if updated_aircraft is None:
raise HTTPException(500, "Failed to update flight")
return AircraftDisplaySchema(**aircraft.model_dump())
async def delete_aircraft(id: str) -> AircraftDisplaySchema: async def delete_aircraft(id: str) -> AircraftDisplaySchema:

View File

@ -1,10 +1,13 @@
import logging import logging
from datetime import datetime from datetime import datetime
from typing import Dict, Union
from bson import ObjectId from bson import ObjectId
from bson.errors import InvalidId from bson.errors import InvalidId
from fastapi import HTTPException from fastapi import HTTPException
from schemas.aircraft import AircraftCreateSchema, aircraft_add_helper
from .aircraft import retrieve_aircraft_by_tail, update_aircraft, update_aircraft_field
from .db import flight_collection from .db import flight_collection
from schemas.flight import FlightConciseSchema, FlightDisplaySchema, FlightCreateSchema, flight_display_helper, \ from schemas.flight import FlightConciseSchema, FlightDisplaySchema, FlightCreateSchema, flight_display_helper, \
flight_add_helper flight_add_helper
@ -12,22 +15,30 @@ from schemas.flight import FlightConciseSchema, FlightDisplaySchema, FlightCreat
logger = logging.getLogger("api") logger = logging.getLogger("api")
async def retrieve_flights(user: str = "", sort: str = "date", order: int = -1) -> list[FlightConciseSchema]: async def retrieve_flights(user: str = "", sort: str = "date", order: int = -1, filter: str = "",
filter_val: str = "") -> list[FlightConciseSchema]:
""" """
Retrieve a list of flights, optionally filtered by user Retrieve a list of flights, optionally filtered by user
:param user: User to filter flights by :param user: User to filter flights by
:param sort: Parameter to sort results by :param sort: Parameter to sort results by
:param order: Sort order :param order: Sort order
:param filter: Field to filter flights by
:param filter_val: Value to filter field by
:return: List of flights :return: List of flights
""" """
filter_options = {}
if user != "":
filter_options["user"] = ObjectId(user)
if filter != "":
filter_options[filter] = filter_val
print(filter_options)
flights = [] flights = []
if user == "": async for flight in flight_collection.find(filter_options).sort({sort: order}):
async for flight in flight_collection.find().sort({sort: order}):
flights.append(FlightConciseSchema(**flight_display_helper(flight)))
else:
async for flight in flight_collection.find({"user": ObjectId(user)}).sort({sort: order}):
flights.append(FlightConciseSchema(**flight_display_helper(flight))) flights.append(FlightConciseSchema(**flight_display_helper(flight)))
return flights return flights
@ -37,7 +48,7 @@ async def retrieve_totals(user: str, start_date: datetime = None, end_date: date
:param user: :param user:
:return: :return:
""" """
match = {"user": ObjectId(user)} match: Dict[str, Union[Dict, ObjectId]] = {"user": ObjectId(user)}
if start_date is not None: if start_date is not None:
match.setdefault("date", {}).setdefault("$gte", start_date) match.setdefault("date", {}).setdefault("$gte", start_date)
@ -122,19 +133,22 @@ async def insert_flight(body: FlightCreateSchema, id: str) -> ObjectId:
:param id: ID of creating user :param id: ID of creating user
:return: ID of inserted flight :return: ID of inserted flight
""" """
try: aircraft = await retrieve_aircraft_by_tail(body.aircraft)
aircraft = await flight_collection.find_one({"_id": ObjectId(body.aircraft)})
except InvalidId:
raise HTTPException(400, "Invalid aircraft ID")
if aircraft is None: if aircraft is None:
raise HTTPException(404, "Aircraft not found") raise HTTPException(404, "Aircraft not found")
# Update hobbs of aircraft to reflect new hobbs end
if body.hobbs_end > 0 and body.hobbs_end != aircraft.hobbs:
await update_aircraft_field("hobbs", body.hobbs_end, aircraft.id)
# Insert flight into database
flight = await flight_collection.insert_one(flight_add_helper(body.model_dump(), id)) flight = await flight_collection.insert_one(flight_add_helper(body.model_dump(), id))
return flight.inserted_id return flight.inserted_id
async def update_flight(body: FlightCreateSchema, id: str) -> FlightDisplaySchema: async def update_flight(body: FlightCreateSchema, id: str) -> str:
""" """
Update given flight in the database Update given flight in the database
@ -147,12 +161,18 @@ async def update_flight(body: FlightCreateSchema, id: str) -> FlightDisplaySchem
if flight is None: if flight is None:
raise HTTPException(404, "Flight not found") raise HTTPException(404, "Flight not found")
aircraft = await flight_collection.find_ond({"_id": ObjectId(body.aircraft)}) aircraft = await retrieve_aircraft_by_tail(body.aircraft)
if aircraft is None: if aircraft is None:
raise HTTPException(404, "Aircraft not found") raise HTTPException(404, "Aircraft not found")
# Update hobbs of aircraft to reflect new hobbs end
if body.hobbs_end > 0 and body.hobbs_end != aircraft.hobbs:
await update_aircraft_field("hobbs", body.hobbs_end, aircraft.id)
# Update flight in database
updated_flight = await flight_collection.update_one({"_id": ObjectId(id)}, {"$set": body.model_dump()}) updated_flight = await flight_collection.update_one({"_id": ObjectId(id)}, {"$set": body.model_dump()})
if updated_flight is None: if updated_flight is None:
raise HTTPException(500, "Failed to update flight") raise HTTPException(500, "Failed to update flight")

View File

@ -15,7 +15,8 @@ logger = logging.getLogger("flights")
@router.get('/', summary="Get flights logged by the currently logged-in user", status_code=200) @router.get('/', summary="Get flights logged by the currently logged-in user", status_code=200)
async def get_flights(user: UserDisplaySchema = Depends(get_current_user), sort: str = "date", order: int = -1) -> list[ async def get_flights(user: UserDisplaySchema = Depends(get_current_user), sort: str = "date", order: int = -1,
filter: str = "", filter_val: str = "") -> list[
FlightConciseSchema]: FlightConciseSchema]:
""" """
Get a list of the flights logged by the currently logged-in user Get a list of the flights logged by the currently logged-in user
@ -23,25 +24,29 @@ async def get_flights(user: UserDisplaySchema = Depends(get_current_user), sort:
:param user: Current user :param user: Current user
:param sort: Attribute to sort results by :param sort: Attribute to sort results by
:param order: Order of sorting (asc/desc) :param order: Order of sorting (asc/desc)
:param filter: Field to filter results by
:param filter_val: Value to filter field by
:return: List of flights :return: List of flights
""" """
flights = await db.retrieve_flights(user.id, sort, order) flights = await db.retrieve_flights(user.id, sort, order, filter, filter_val)
return flights return flights
@router.get('/by-date', summary="Get flights logged by the current user, categorized by date", status_code=200, @router.get('/by-date', summary="Get flights logged by the current user, categorized by date", status_code=200,
response_model=dict) response_model=dict)
async def get_flights_by_date(user: UserDisplaySchema = Depends(get_current_user), sort: str = "date", async def get_flights_by_date(user: UserDisplaySchema = Depends(get_current_user), sort: str = "date",
order: int = -1) -> dict: order: int = -1, filter: str = "", filter_val: str = "") -> dict:
""" """
Get a list of the flights logged by the currently logged-in user, categorized by year, month, and day Get a list of the flights logged by the currently logged-in user, categorized by year, month, and day
:param user: Current user :param user: Current user
:param sort: Attribute to sort results by :param sort: Attribute to sort results by
:param order: Order of sorting (asc/desc) :param order: Order of sorting (asc/desc)
:param filter: Field to filter results by
:param filter_val: Value to filter field by
:return: :return:
""" """
flights = await db.retrieve_flights(user.id, sort, order) flights = await db.retrieve_flights(user.id, sort, order, filter, filter_val)
flights_ordered: FlightByDateSchema = {} flights_ordered: FlightByDateSchema = {}
for flight in flights: for flight in flights:

View File

@ -71,7 +71,7 @@ class FlightConciseSchema(BaseModel):
comments: Optional[str] = None comments: Optional[str] = None
FlightByDateSchema = Dict[int, Union[List['FlightByDateSchema'], FlightConciseSchema]] FlightByDateSchema = Dict[int, Union[Dict[int, 'FlightByDateSchema'], FlightConciseSchema]]
# HELPERS # # HELPERS #