mirror of
https://github.com/mblanke/Gov_Travel_App.git
synced 2026-03-01 14:10:22 -05:00
- Implemented Python scraper using BeautifulSoup and pandas to automatically collect travel rates from official NJC website - Added currency extraction from table titles (supports EUR, USD, AUD, CAD, ARS, etc.) - Added country extraction from table titles for international rates - Flatten pandas MultiIndex columns for cleaner data structure - Default to CAD for domestic Canadian sources (accommodations and domestic tables) - Created SQLite database schema (raw_tables, rate_entries, exchange_rates, accommodations) - Successfully scraped 92 tables with 17,205 rate entries covering 25 international cities - Added migration script to convert scraped data to Node.js database format - Updated .gitignore for Python files (.venv/, __pycache__, *.pyc, *.sqlite3) - Fixed city validation and currency conversion in main app - Added comprehensive debug and verification scripts This replaces manual JSON maintenance with automated data collection from official government source.
130 lines
3.4 KiB
JavaScript
130 lines
3.4 KiB
JavaScript
const Joi = require('joi');
|
|
|
|
// Flight search validation
|
|
const flightSearchSchema = Joi.object({
|
|
origin: Joi.string()
|
|
.min(2)
|
|
.max(100)
|
|
.required()
|
|
.trim()
|
|
.messages({
|
|
'string.empty': 'Origin city is required',
|
|
'string.min': 'Origin city must be at least 2 characters',
|
|
'string.max': 'Origin city cannot exceed 100 characters'
|
|
}),
|
|
destination: Joi.string()
|
|
.min(2)
|
|
.max(100)
|
|
.required()
|
|
.trim()
|
|
.messages({
|
|
'string.empty': 'Destination city is required',
|
|
'string.min': 'Destination city must be at least 2 characters',
|
|
'string.max': 'Destination city cannot exceed 100 characters'
|
|
}),
|
|
departureDate: Joi.date()
|
|
.iso()
|
|
.min('now')
|
|
.required()
|
|
.messages({
|
|
'date.base': 'Departure date must be a valid date',
|
|
'date.min': 'Departure date cannot be in the past',
|
|
'any.required': 'Departure date is required'
|
|
}),
|
|
returnDate: Joi.date()
|
|
.iso()
|
|
.min(Joi.ref('departureDate'))
|
|
.optional()
|
|
.allow(null, '')
|
|
.messages({
|
|
'date.base': 'Return date must be a valid date',
|
|
'date.min': 'Return date must be after departure date'
|
|
}),
|
|
adults: Joi.number()
|
|
.integer()
|
|
.min(1)
|
|
.max(9)
|
|
.default(1)
|
|
.messages({
|
|
'number.base': 'Number of adults must be a number',
|
|
'number.min': 'At least 1 adult is required',
|
|
'number.max': 'Maximum 9 adults allowed'
|
|
})
|
|
});
|
|
|
|
// Accommodation search validation
|
|
const accommodationSearchSchema = Joi.object({
|
|
city: Joi.string()
|
|
.min(2)
|
|
.max(100)
|
|
.required()
|
|
.trim()
|
|
.messages({
|
|
'string.empty': 'City name is required',
|
|
'string.min': 'City name must be at least 2 characters',
|
|
'string.max': 'City name cannot exceed 100 characters'
|
|
})
|
|
});
|
|
|
|
// City key validation
|
|
const cityKeySchema = Joi.object({
|
|
cityKey: Joi.string()
|
|
.min(2)
|
|
.max(100)
|
|
.required()
|
|
.trim()
|
|
.messages({
|
|
'string.empty': 'City key is required'
|
|
})
|
|
});
|
|
|
|
// Month validation
|
|
const monthSchema = Joi.object({
|
|
cityKey: Joi.string().required(),
|
|
month: Joi.number()
|
|
.integer()
|
|
.min(1)
|
|
.max(12)
|
|
.required()
|
|
.messages({
|
|
'number.min': 'Month must be between 1 and 12',
|
|
'number.max': 'Month must be between 1 and 12',
|
|
'any.required': 'Month is required'
|
|
})
|
|
});
|
|
|
|
// Validation middleware factory
|
|
const validate = (schema) => {
|
|
return (req, res, next) => {
|
|
const { error, value } = schema.validate(req.query, {
|
|
abortEarly: false,
|
|
stripUnknown: true
|
|
});
|
|
|
|
if (error) {
|
|
const errors = error.details.map(detail => ({
|
|
field: detail.path.join('.'),
|
|
message: detail.message
|
|
}));
|
|
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: 'Validation failed',
|
|
errors
|
|
});
|
|
}
|
|
|
|
// Replace req.query with validated and sanitized values
|
|
req.query = value;
|
|
next();
|
|
};
|
|
};
|
|
|
|
module.exports = {
|
|
validate,
|
|
flightSearchSchema,
|
|
accommodationSearchSchema,
|
|
cityKeySchema,
|
|
monthSchema
|
|
};
|