const Joi = require('joi'); // User validation schemas const registerSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#+])[A-Za-z\d@$!%*?&#+]/).required() .messages({ 'string.pattern.base': 'Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character' }), firstName: Joi.string().max(100).required(), lastName: Joi.string().max(100).required() }); const loginSchema = Joi.object({ email: Joi.string().email().required(), password: Joi.string().required() }); const updateUserSchema = Joi.object({ firstName: Joi.string().max(100), lastName: Joi.string().max(100), email: Joi.string().email() }); const changePasswordSchema = Joi.object({ currentPassword: Joi.string().required(), newPassword: Joi.string().min(8).pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#+])[A-Za-z\d@$!%*?&#+]/).required() .messages({ 'string.pattern.base': 'Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character' }) }); // Property validation schemas const propertySchema = Joi.object({ name: Joi.string().max(255).required(), address: Joi.string().max(500), latitude: Joi.number().min(-90).max(90), longitude: Joi.number().min(-180).max(180), totalArea: Joi.number().positive() }); const lawnSectionSchema = Joi.object({ name: Joi.string().max(255).required(), area: Joi.number().positive().required(), polygonData: Joi.object(), grassType: Joi.string().max(100).allow(null, '').optional(), soilType: Joi.string().max(100).allow(null, '').optional() }); // Equipment validation schemas const equipmentSchema = Joi.object({ equipmentTypeId: Joi.number().integer().positive().required(), customName: Joi.string().max(255), tankSize: Joi.number().positive(), pumpGpm: Joi.number().positive(), nozzleGpm: Joi.number().positive(), nozzleCount: Joi.number().integer().positive(), spreaderWidth: Joi.number().positive() }); // Product validation schemas const productSchema = Joi.object({ name: Joi.string().max(255).required(), brand: Joi.string().max(100), categoryId: Joi.number().integer().positive().required(), productType: Joi.string().valid('granular', 'liquid').required(), activeIngredients: Joi.string(), description: Joi.string() }); const productRateSchema = Joi.object({ applicationType: Joi.string().max(100).required(), rateAmount: Joi.number().positive().required(), rateUnit: Joi.string().max(50).required(), notes: Joi.string() }); const userProductSchema = Joi.object({ productId: Joi.number().integer().positive().allow(null).optional(), customName: Joi.string().max(255).allow(null).optional(), customRateAmount: Joi.number().positive().allow(null).optional(), customRateUnit: Joi.string().max(50).allow(null).optional(), notes: Joi.string().allow(null, '').optional(), // Additional fields for advanced editing brand: Joi.string().max(100).allow(null).optional(), categoryId: Joi.number().integer().positive().allow(null).optional(), productType: Joi.string().valid('granular', 'liquid', 'seed', 'powder').allow(null).optional(), activeIngredients: Joi.string().allow(null).optional(), description: Joi.string().allow(null).optional(), isAdvancedEdit: Joi.boolean().optional() }); // Application validation schemas const applicationPlanSchema = Joi.object({ lawnSectionId: Joi.number().integer().positive().required(), equipmentId: Joi.number().integer().positive().required(), plannedDate: Joi.date().required(), notes: Joi.string().allow('').optional(), products: Joi.array().items(Joi.object({ productId: Joi.number().integer().positive().optional(), userProductId: Joi.number().integer().positive().optional(), rateAmount: Joi.number().positive().required(), rateUnit: Joi.string().max(50).required() })).min(1).required() }); const applicationLogSchema = Joi.object({ planId: Joi.number().integer().positive(), lawnSectionId: Joi.number().integer().positive().required(), equipmentId: Joi.number().integer().positive().required(), weatherConditions: Joi.object(), gpsTrack: Joi.object(), averageSpeed: Joi.number().positive(), areaCovered: Joi.number().positive(), notes: Joi.string(), products: Joi.array().items(Joi.object({ productId: Joi.number().integer().positive(), userProductId: Joi.number().integer().positive(), rateAmount: Joi.number().positive().required(), rateUnit: Joi.string().max(50).required(), actualProductAmount: Joi.number().positive(), actualWaterAmount: Joi.number().positive(), actualSpeedMph: Joi.number().positive() })).min(1).required() }); // Validation middleware const validateRequest = (schema) => { return (req, res, next) => { const { error } = schema.validate(req.body, { abortEarly: false }); if (error) { return next(error); } next(); }; }; const validateParams = (schema) => { return (req, res, next) => { const { error } = schema.validate(req.params, { abortEarly: false }); if (error) { return next(error); } next(); }; }; const idParamSchema = Joi.object({ id: Joi.number().integer().positive().required() }); module.exports = { // Schemas registerSchema, loginSchema, updateUserSchema, changePasswordSchema, propertySchema, lawnSectionSchema, equipmentSchema, productSchema, productRateSchema, userProductSchema, applicationPlanSchema, applicationLogSchema, idParamSchema, // Middleware validateRequest, validateParams };