From 91e820b9a8b218c0823a2fdf27a53f7c49a92fff Mon Sep 17 00:00:00 2001 From: James Pattinson Date: Sat, 25 Oct 2025 12:59:07 +0000 Subject: [PATCH] Public PPR submission --- backend/app/api/endpoints/aircraft.py | 24 ++ backend/app/api/endpoints/airport.py | 37 +- backend/app/api/endpoints/pprs.py | 25 ++ web/ppr.html | 587 ++++++++++++++++++++++++++ 4 files changed, 672 insertions(+), 1 deletion(-) create mode 100644 web/ppr.html diff --git a/backend/app/api/endpoints/aircraft.py b/backend/app/api/endpoints/aircraft.py index b6dba8b..0d702e9 100644 --- a/backend/app/api/endpoints/aircraft.py +++ b/backend/app/api/endpoints/aircraft.py @@ -33,6 +33,30 @@ async def lookup_aircraft_by_registration( return aircraft_list +@router.get("/public/lookup/{registration}", response_model=List[AircraftSchema]) +async def public_lookup_aircraft_by_registration( + registration: str, + db: Session = Depends(get_db) +): + """ + Public lookup aircraft by registration (clean match). + Removes non-alphanumeric characters from input for matching. + No authentication required. + """ + # Clean the input registration (remove non-alphanumeric characters) + clean_input = ''.join(c for c in registration if c.isalnum()).upper() + + if len(clean_input) < 4: + return [] + + # Query aircraft table using clean_reg column + aircraft_list = db.query(Aircraft).filter( + Aircraft.clean_reg.like(f"{clean_input}%") + ).limit(10).all() + + return aircraft_list + + @router.get("/search", response_model=List[AircraftSchema]) async def search_aircraft( q: Optional[str] = Query(None, description="Search query for registration, type, or manufacturer"), diff --git a/backend/app/api/endpoints/airport.py b/backend/app/api/endpoints/airport.py index 0b42211..a5e05d0 100644 --- a/backend/app/api/endpoints/airport.py +++ b/backend/app/api/endpoints/airport.py @@ -68,4 +68,39 @@ async def search_airports( (Airport.city.ilike("%" + search_term + "%")) ).limit(limit).all() - return airports \ No newline at end of file + return airports + + +@router.get("/public/lookup/{code_or_name}", response_model=List[AirportSchema]) +async def public_lookup_airport_by_code_or_name( + code_or_name: str, + db: Session = Depends(get_db) +): + """ + Public lookup airport by ICAO code or name. + If input is 4 characters and all uppercase letters, treat as ICAO code. + Otherwise, search by name. + No authentication required. + """ + clean_input = code_or_name.strip().upper() + + if len(clean_input) < 2: + return [] + + # Check if input looks like an ICAO code (4 letters) + if len(clean_input) == 4 and clean_input.isalpha(): + # Exact ICAO match first + airport = db.query(Airport).filter(Airport.icao == clean_input).first() + if airport: + return [airport] + # Then search ICAO codes that start with input + airports = db.query(Airport).filter( + Airport.icao.like(clean_input + "%") + ).limit(5).all() + return airports + else: + # Search by name (case-insensitive partial match) + airports = db.query(Airport).filter( + Airport.name.ilike("%" + code_or_name + "%") + ).limit(10).all() + return airports \ No newline at end of file diff --git a/backend/app/api/endpoints/pprs.py b/backend/app/api/endpoints/pprs.py index 5aad588..57eed55 100644 --- a/backend/app/api/endpoints/pprs.py +++ b/backend/app/api/endpoints/pprs.py @@ -56,6 +56,31 @@ async def create_ppr( return ppr +@router.post("/public", response_model=PPR) +async def create_public_ppr( + request: Request, + ppr_in: PPRCreate, + db: Session = Depends(get_db) +): + """Create a new PPR record (public endpoint, no authentication required)""" + client_ip = get_client_ip(request) + # For public submissions, use a default created_by or None + ppr = crud_ppr.create(db, obj_in=ppr_in, created_by="public", user_ip=client_ip) + + # Send real-time update via WebSocket + if hasattr(request.app.state, 'connection_manager'): + await request.app.state.connection_manager.broadcast({ + "type": "ppr_created", + "data": { + "id": ppr.id, + "ac_reg": ppr.ac_reg, + "status": ppr.status.value + } + }) + + return ppr + + @router.get("/{ppr_id}", response_model=PPR) async def get_ppr( ppr_id: int, diff --git a/web/ppr.html b/web/ppr.html new file mode 100644 index 0000000..acfd308 --- /dev/null +++ b/web/ppr.html @@ -0,0 +1,587 @@ + + + + + + Swansea PPR Request + + + +
+
+

✈️ Swansea Airport PPR Request

+

Please fill out the form below to submit a Prior Permission Required (PPR) request for Swansea Airport.

+
+ +
+
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+ +
+
+ Submitting your PPR request... +
+ +
+

✅ PPR Request Submitted Successfully!

+

Your Prior Permission Required request has been submitted and will be reviewed by airport operations. You will receive confirmation via email if provided.

+

Please note: This is not confirmation of approval. Airport operations will contact you if additional information is required.

+
+
+ + +
+ + + + \ No newline at end of file