Files
vip-coordinator/backend-old-20260125/dist/services/flightService.js
kyle 868f7efc23
Some checks failed
CI/CD Pipeline / Backend Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Tests (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
Major Enhancement: NestJS Migration + CASL Authorization + Error Handling
Complete rewrite from Express to NestJS with enterprise-grade features:

## Backend Improvements
- Migrated from Express to NestJS 11.0.1 with TypeScript
- Implemented Prisma ORM 7.3.0 for type-safe database access
- Added CASL authorization system replacing role-based guards
- Created global exception filters with structured logging
- Implemented Auth0 JWT authentication with Passport.js
- Added vehicle management with conflict detection
- Enhanced event scheduling with driver/vehicle assignment
- Comprehensive error handling and logging

## Frontend Improvements
- Upgraded to React 19.2.0 with Vite 7.2.4
- Implemented CASL-based permission system
- Added AbilityContext for declarative permissions
- Created ErrorHandler utility for consistent error messages
- Enhanced API client with request/response logging
- Added War Room (Command Center) dashboard
- Created VIP Schedule view with complete itineraries
- Implemented Vehicle Management UI
- Added mock data generators for testing (288 events across 20 VIPs)

## New Features
- Vehicle fleet management (types, capacity, status tracking)
- Complete 3-day Jamboree schedule generation
- Individual VIP schedule pages with PDF export (planned)
- Real-time War Room dashboard with auto-refresh
- Permission-based navigation filtering
- First user auto-approval as administrator

## Documentation
- Created CASL_AUTHORIZATION.md (comprehensive guide)
- Created ERROR_HANDLING.md (error handling patterns)
- Updated CLAUDE.md with new architecture
- Added migration guides and best practices

## Technical Debt Resolved
- Removed custom authentication in favor of Auth0
- Replaced role checks with CASL abilities
- Standardized error responses across API
- Implemented proper TypeScript typing
- Added comprehensive logging

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-31 08:50:25 +01:00

196 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use strict";
// Real Flight tracking service with Google scraping
// No mock data - only real flight information
Object.defineProperty(exports, "__esModule", { value: true });
class FlightService {
constructor() {
this.flightCache = new Map();
this.updateIntervals = new Map();
// No API keys needed for Google scraping
}
// Real flight lookup - no mock data
async getFlightInfo(params) {
const cacheKey = `${params.flightNumber}_${params.date}`;
// Check cache first (shorter cache for real data)
const cached = this.flightCache.get(cacheKey);
if (cached && cached.expires > Date.now()) {
return cached.data;
}
try {
// Try Google scraping first
let flightData = await this.scrapeGoogleFlights(params);
// If Google fails, try AviationStack (if API key available)
if (!flightData) {
flightData = await this.getFromAviationStack(params);
}
// Cache the result for 2 minutes (shorter for real data)
if (flightData) {
this.flightCache.set(cacheKey, {
data: flightData,
expires: Date.now() + (2 * 60 * 1000)
});
}
return flightData;
}
catch (error) {
console.error('Error fetching flight data:', error);
return null; // Return null instead of mock data
}
}
// Google Flights scraping implementation
async scrapeGoogleFlights(params) {
try {
// Google Flights URL format
const googleUrl = `https://www.google.com/travel/flights/search?tfs=CBwQAhoeEgoyMDI1LTA3LTAxagcIARIDTEFYcgcIARIDSkZLQAFIAXABggELCP___________wFAAUgBmAEB&hl=en`;
// For now, return null to indicate no real scraping implementation
// In production, you would implement actual web scraping here
console.log(`Would scrape Google for flight ${params.flightNumber} on ${params.date}`);
return null;
}
catch (error) {
console.error('Google scraping error:', error);
return null;
}
}
// AviationStack API integration (only if API key available)
async getFromAviationStack(params) {
const apiKey = process.env.AVIATIONSTACK_API_KEY;
console.log('Checking AviationStack API key:', apiKey ? `Key present (${apiKey.length} chars)` : 'No key');
if (!apiKey || apiKey === 'demo_key' || apiKey === '') {
console.log('No valid AviationStack API key available');
return null; // No API key available
}
try {
// Format flight number: Remove spaces and convert to uppercase
const formattedFlightNumber = params.flightNumber.replace(/\s+/g, '').toUpperCase();
console.log(`Formatted flight number: ${params.flightNumber} -> ${formattedFlightNumber}`);
// Note: Free tier doesn't support date filtering, so we get recent flights
// For future dates, this won't work well - consider upgrading subscription
const url = `http://api.aviationstack.com/v1/flights?access_key=${apiKey}&flight_iata=${formattedFlightNumber}&limit=10`;
console.log('AviationStack API URL:', url.replace(apiKey, '***'));
console.log('Note: Free tier returns recent flights only, not future scheduled flights');
const response = await fetch(url);
const data = await response.json();
console.log('AviationStack response status:', response.status);
if (!response.ok) {
console.error('AviationStack API error - HTTP status:', response.status);
return null;
}
// Check for API errors in response
if (data.error) {
console.error('AviationStack API error:', data.error);
return null;
}
if (data.data && data.data.length > 0) {
// This is a valid flight number that exists!
console.log(`✅ Valid flight number: ${formattedFlightNumber} exists in the system`);
// Try to find a flight matching the requested date
let flight = data.data.find((f) => f.flight_date === params.date);
// If no exact date match, use most recent for validation
if (!flight) {
flight = data.data[0];
console.log(` Flight ${formattedFlightNumber} is valid`);
console.log(`Recent flight: ${flight.departure.airport}${flight.arrival.airport}`);
console.log(`Operated by: ${flight.airline?.name || 'Unknown'}`);
console.log(`Note: Showing recent data from ${flight.flight_date} for validation`);
}
else {
console.log(`✅ Flight found for exact date: ${params.date}`);
}
console.log('Flight route:', `${flight.departure.iata}${flight.arrival.iata}`);
console.log('Status:', flight.flight_status);
return {
flightNumber: flight.flight.iata,
flightDate: flight.flight_date,
status: this.normalizeStatus(flight.flight_status),
airline: flight.airline?.name,
aircraft: flight.aircraft?.registration,
departure: {
airport: flight.departure.iata,
airportName: flight.departure.airport,
scheduled: flight.departure.scheduled,
estimated: flight.departure.estimated,
actual: flight.departure.actual,
terminal: flight.departure.terminal,
gate: flight.departure.gate
},
arrival: {
airport: flight.arrival.iata,
airportName: flight.arrival.airport,
scheduled: flight.arrival.scheduled,
estimated: flight.arrival.estimated,
actual: flight.arrival.actual,
terminal: flight.arrival.terminal,
gate: flight.arrival.gate
},
delay: flight.departure.delay || 0,
lastUpdated: new Date().toISOString(),
source: 'aviationstack'
};
}
console.log(`❌ Invalid flight number: ${formattedFlightNumber} not found`);
console.log('This flight number does not exist or has not operated recently');
return null;
}
catch (error) {
console.error('AviationStack API error:', error);
return null;
}
}
// Start periodic updates for a flight
startPeriodicUpdates(params, intervalMinutes = 5) {
const key = `${params.flightNumber}_${params.date}`;
// Clear existing interval if any
this.stopPeriodicUpdates(key);
// Set up new interval
const interval = setInterval(async () => {
try {
await this.getFlightInfo(params); // This will update the cache
console.log(`Updated flight data for ${params.flightNumber} on ${params.date}`);
}
catch (error) {
console.error(`Error updating flight ${params.flightNumber}:`, error);
}
}, intervalMinutes * 60 * 1000);
this.updateIntervals.set(key, interval);
}
// Stop periodic updates for a flight
stopPeriodicUpdates(key) {
const interval = this.updateIntervals.get(key);
if (interval) {
clearInterval(interval);
this.updateIntervals.delete(key);
}
}
// Get multiple flights with date specificity
async getMultipleFlights(flightParams) {
const results = {};
for (const params of flightParams) {
const key = `${params.flightNumber}_${params.date}`;
results[key] = await this.getFlightInfo(params);
}
return results;
}
// Normalize flight status across different APIs
normalizeStatus(status) {
const statusMap = {
'scheduled': 'scheduled',
'active': 'active',
'landed': 'landed',
'cancelled': 'cancelled',
'incident': 'delayed',
'diverted': 'diverted'
};
return statusMap[status.toLowerCase()] || status;
}
// Clean up resources
cleanup() {
for (const [key, interval] of this.updateIntervals) {
clearInterval(interval);
}
this.updateIntervals.clear();
this.flightCache.clear();
}
}
exports.default = new FlightService();
//# sourceMappingURL=flightService.js.map