Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/rentals.picotech.app/public_html/server/middleware/ drwxr-xr-x | |
| Viewing file: Select action/file-type: import { body, param, query, validationResult } from 'express-validator';
// Middleware to handle validation errors
export const handleValidationErrors = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({
message: 'Validation failed',
errors: errors.array().map(err => ({
field: err.path,
message: err.msg,
value: err.value
}))
});
}
next();
};
// Common validators
export const validators = {
// ID parameter validation
id: param('id')
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('ID must be between 1 and 50 characters'),
// Email validation
email: body('email')
.trim()
.isEmail()
.withMessage('Must be a valid email address')
.normalizeEmail(),
// Password validation
password: body('password')
.isLength({ min: 6 })
.withMessage('Password must be at least 6 characters long')
.trim(),
// Optional password validation
optionalPassword: body('password')
.optional()
.isLength({ min: 6 })
.withMessage('Password must be at least 6 characters long')
.trim(),
// Phone validation
visitorPhone: body('visitor_phone')
.optional()
.trim()
.matches(/^[0-9+\-\s()]+$/)
.withMessage('Phone number contains invalid characters'),
phone: body('phone')
.optional()
.trim()
.matches(/^[0-9+\-\s()]+$/)
.withMessage('Phone number contains invalid characters'),
// Name validation
name: body('name')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Name must be between 1 and 255 characters')
.escape(),
emergencyContact: body('emergency_contact')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Emergency contact must be between 1 and 255 characters')
.escape(),
emergencyRelation: body('emergency_relation')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Emergency relation must be between 1 and 255 characters')
.escape(),
month: body('month')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Month must be between 1 and 255 characters')
.escape(),
year: body('year')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Year must be between 1 and 255 characters')
.escape(),
visitorName: body('visitor_name')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Visitor name must be between 1 and 255 characters')
.escape(),
purpose: body('purpose')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Purpose must be between 1 and 255 characters')
.escape(),
approvedBy: body('approved_by')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Approved by must be between 1 and 255 characters')
.escape(),
// Amount validation (for payments, expenses)
amount: body('amount')
.isFloat({ min: 0 })
.withMessage('Amount must be a positive number')
.toFloat(),
rentAmount: body('rent_amount')
.isFloat({ min: 0 })
.withMessage('Rent amount must be a positive number')
.toFloat(),
securityDeposit: body('security_deposit')
.isFloat({ min: 0 })
.withMessage('Security deposit must be a positive number')
.toFloat(),
// Date validation
date: body('date')
.optional()
.isISO8601()
.withMessage('Must be a valid date')
.toDate(),
dueDate: body('due_date')
.optional()
.isISO8601()
.withMessage('Must be a valid date')
.toDate(),
checkInDate: body('check_in_date')
.optional()
.isISO8601()
.withMessage('Must be a valid check in date')
.toDate(),
leaseStartDate: body('lease_start_date')
.optional()
.isISO8601()
.withMessage('Must be a valid lease start date')
.toDate(),
leaseEndDate: body('lease_end_date')
.optional()
.isISO8601()
.withMessage('Must be a valid lease end date')
.toDate(),
checkInTime: body('check_in_time')
.optional()
.isISO8601()
.withMessage('Must be a valid check in time')
.toDate(),
lastInspection: body('last_inspection')
.optional()
.isISO8601()
.withMessage('Must be a valid last inspection')
.toDate(),
// Status enum validation
status: (allowedValues) => body('status')
.optional()
.isIn(allowedValues)
.withMessage(`Status must be one of: ${allowedValues.join(', ')}`),
// Role enum validation
role: body('role')
.optional()
.isIn(['admin', 'manager', 'staff', 'renter'])
.withMessage('Role must be one of: admin, manager, staff, renter'),
type: (allowedValues) => body('type')
.optional()
.isIn(allowedValues)
.withMessage(`Type must be one of: ${allowedValues.join(', ')}`),
categoryType: (allowedValues) => body('category')
.optional()
.isIn(allowedValues)
.withMessage(`Category must be one of: ${allowedValues.join(', ')}`),
// Building ID validation
buildingId: body('building_id')
.optional()
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('Building ID must be between 1 and 50 characters'),
// Floor ID validation
floorId: body('floor_id')
.optional()
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('Floor ID must be between 1 and 50 characters'),
// Floors validation
floors: body('floors')
.isNumeric({ min: 1 })
.withMessage('Floors must be at least 1')
.toFloat(),
totalRooms: body('total_rooms')
.isNumeric({ min: 1 })
.withMessage('Rooms must be be at least 1')
.toFloat(),
// Room ID validation
roomId: body('room_id')
.optional()
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('Room ID must be between 1 and 50 characters'),
// Renter ID validation
renterId: body('renter_id')
.optional()
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('Renter ID must be between 1 and 50 characters'),
// Description validation
description: body('description')
.optional()
.trim()
.isLength({ max: 1000 })
.withMessage('Description must not exceed 1000 characters')
.escape(),
// Title validation
title: body('title')
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Title must be between 1 and 255 characters')
.escape(),
// Optional title validation
optionalTitle: body('title')
.optional()
.trim()
.isLength({ min: 1, max: 255 })
.withMessage('Title must be between 1 and 255 characters')
.escape(),
// Content validation (with XSS protection)
content: body('content')
.optional()
.trim()
.isLength({ max: 5000 })
.withMessage('Content must not exceed 5000 characters')
.escape(),
// Department validation
department: body('department')
.optional()
.trim()
.isLength({ max: 100 })
.withMessage('Department must not exceed 100 characters')
.escape(),
// Permissions array validation
permissions: body('permissions')
.optional()
.isArray()
.withMessage('Permissions must be an array'),
// Boolean validation
boolean: (field) => body(field)
.optional()
.isBoolean()
.withMessage(`${field} must be a boolean value`)
.toBoolean(),
// Bed number validation
bedNumber: body('bed_number')
.trim()
.notEmpty()
.withMessage('Bed number is required')
.isLength({ max: 50 })
.withMessage('Bed number must not exceed 50 characters')
.escape(),
// Optional bed number validation
optionalBedNumber: body('bed_number')
.optional()
.trim()
.isLength({ max: 50 })
.withMessage('Bed number must not exceed 50 characters')
.escape(),
// Floor number validation
floorNumber: body('floor_number')
.trim()
.notEmpty()
.withMessage('Floor number is required')
.isLength({ max: 50 })
.withMessage('Floor number must not exceed 50 characters')
.escape(),
// Optional floor number validation
optionalFloorNumber: body('floor_number')
.optional()
.trim()
.isLength({ max: 50 })
.withMessage('Floor number must not exceed 50 characters')
.escape(),
// Address validation
address: body('address')
.optional()
.trim()
.isLength({ max: 500 })
.withMessage('Address must not exceed 500 characters')
.escape(),
// Category validation
category: body('category')
.trim()
.notEmpty()
.withMessage('Category is required')
.isLength({ max: 100 })
.withMessage('Category must not exceed 100 characters')
.escape(),
// Optional category validation
optionalCategory: body('category')
.optional()
.trim()
.isLength({ max: 100 })
.withMessage('Category must not exceed 100 characters')
.escape(),
// Vendor validation
vendor: body('vendor')
.optional()
.trim()
.isLength({ max: 255 })
.withMessage('Vendor must not exceed 255 characters')
.escape(),
// Payment method validation
paymentMethod: body('payment_method')
.optional()
.trim()
.isLength({ max: 100 })
.withMessage('Payment method must not exceed 100 characters')
.escape(),
// Purpose validation
purpose: body('purpose')
.optional()
.trim()
.isLength({ max: 500 })
.withMessage('Purpose must not exceed 500 characters')
.escape(),
// Monthly rent validation
monthlyRent: body('monthly_rent')
.optional()
.isFloat({ min: 0 })
.withMessage('Monthly rent must be a positive number')
.toFloat(),
// Bed ID validation
bedId: body('bed_id')
.optional()
.trim()
.isLength({ min: 1, max: 50 })
.withMessage('Bed ID must be between 1 and 50 characters'),
};
// Auth route validators
export const authValidators = {
login: [
validators.email,
body('password')
.notEmpty()
.withMessage('Password is required')
.trim(),
handleValidationErrors
],
changePassword: [
body('currentPassword')
.notEmpty()
.withMessage('Current password is required')
.trim(),
body('newPassword')
.isLength({ min: 6 })
.withMessage('New password must be at least 6 characters long')
.trim(),
handleValidationErrors
]
};
// User route validators
export const userValidators = {
create: [
validators.name,
validators.email,
validators.password,
validators.role,
validators.phone,
validators.department,
validators.permissions,
// validators.buildingId,
handleValidationErrors
],
update: [
validators.id,
body('name').optional().trim().isLength({ min: 1, max: 255 }).escape(),
body('email').optional().trim().isEmail().normalizeEmail(),
// validators.optionalPassword,
validators.role,
validators.phone,
validators.department,
validators.permissions,
// validators.buildingId,
validators.boolean('is_active'),
handleValidationErrors
],
delete: [
validators.id,
handleValidationErrors
]
};
// Renter route validators
export const renterValidators = {
create: [
validators.name,
validators.email,
validators.password,
validators.phone,
validators.roomId,
validators.buildingId,
validators.floorId,
validators.rentAmount,
validators.securityDeposit,
validators.checkInDate,
validators.leaseStartDate,
validators.leaseEndDate,
validators.emergencyContact,
validators.emergencyRelation,
body('documentsMeta')
.optional()
.custom((value) => {
try {
if (value) JSON.parse(value);
return true;
} catch (e) {
throw new Error('documentsMeta must be valid JSON');
}
}),
handleValidationErrors
],
update: [
validators.id,
body('name').optional().trim().isLength({ min: 1, max: 255 }).escape(),
body('email').optional().trim().isEmail().normalizeEmail(),
// validators.optionalPassword,
validators.phone,
validators.roomId,
validators.buildingId,
validators.floorId,
validators.rentAmount,
validators.securityDeposit,
validators.checkInDate,
validators.leaseStartDate,
validators.leaseEndDate,
validators.emergencyContact,
validators.emergencyRelation,
handleValidationErrors
]
};
// Building route validators
export const buildingValidators = {
create: [
validators.name,
validators.address,
validators.floors,
validators.totalRooms,
body('address').optional().trim().isLength({ max: 500 }).escape(),
validators.description,
handleValidationErrors
],
update: [
validators.id,
validators.name,
validators.address,
validators.floors,
validators.totalRooms,
body('name').optional().trim().isLength({ min: 1, max: 255 }).escape(),
body('address').optional().trim().isLength({ max: 500 }).escape(),
validators.description,
handleValidationErrors
]
};
// Room route validators
export const roomValidators = {
create: [
validators.buildingId,
validators.floorId,
body('room_number').trim().notEmpty().escape(),
validators.status(['available', 'occupied', 'maintenance']),
handleValidationErrors
],
update: [
validators.id,
validators.buildingId,
validators.floorId,
body('room_number').optional().trim().notEmpty().escape(),
validators.status(['available', 'occupied', 'maintenance']),
handleValidationErrors
]
};
// Rent payment validators
export const rentValidators = {
create: [
validators.renterId,
validators.amount,
validators.dueDate,
body('payment_method').optional().trim().escape(),
validators.status(['paid', 'pending', 'overdue', 'partial']),
validators.description,
validators.month,
validators.year,
handleValidationErrors
],
update: [
validators.id,
validators.amount,
validators.dueDate,
body('payment_method').optional().trim().escape(),
validators.status(['paid', 'pending', 'overdue', 'partial']),
validators.description,
validators.month,
validators.year,
handleValidationErrors
]
};
// Maintenance validators
export const maintenanceValidators = {
create: [
// validators.title,
validators.buildingId,
validators.description,
validators.type(['cleaning', 'repair', 'inspection', 'upgrade', 'pest_control', 'painting']),
validators.status(['pending', 'in_progress', 'completed', 'cancelled']),
body('priority').optional().isIn(['low', 'medium', 'high', 'urgent']),
handleValidationErrors
],
update: [
validators.id,
// validators.optionalTitle,
validators.buildingId,
validators.description,
validators.type(['cleaning', 'repair', 'inspection', 'upgrade', 'pest_control', 'painting']),
validators.status(['pending', 'in_progress', 'completed', 'cancelled']),
body('priority').optional().isIn(['low', 'medium', 'high', 'urgent']),
handleValidationErrors
]
};
// Expense validators
export const expenseValidators = {
create: [
// validators.title,
// validators.buildingId,
validators.amount,
validators.date,
// body('category').optional().trim().escape(),
validators.categoryType(['maintenance', 'utilities', 'staff', 'supplies', 'insurance', 'taxes', 'marketing', 'other']),
validators.description,
handleValidationErrors
],
update: [
validators.id,
// validators.buildingId,
// validators.optionalTitle,
validators.amount,
validators.date,
// body('category').optional().trim().escape(),
validators.categoryType(['maintenance', 'utilities', 'staff', 'supplies', 'insurance', 'taxes', 'marketing', 'other']),
validators.description,
handleValidationErrors
]
};
// Notice validators
export const noticeValidators = {
create: [
validators.title,
validators.content,
handleValidationErrors
],
update: [
validators.id,
validators.optionalTitle,
validators.content,
handleValidationErrors
]
};
// Visitor validators
export const visitorValidators = {
create: [
validators.buildingId,
validators.visitorName,
validators.visitorPhone,
// body('visiting_renter_id').trim().isLength({ min: 1, max: 50 }).withMessage('Visiting renter ID must be between 1 and 50 characters'),
validators.checkInTime,
validators.purpose,
validators.approvedBy,
handleValidationErrors
],
update: [
validators.id,
validators.buildingId,
validators.visitorName,
validators.visitorPhone,
// body('visiting_renter_id').optional().trim().isLength({ min: 1, max: 50 }).withMessage('Visiting renter ID must be between 1 and 50 characters'),
validators.checkInTime,
validators.purpose,
validators.approvedBy,
handleValidationErrors
]
};
// Category validators
export const categoryValidators = {
create: [
validators.name,
validators.description,
handleValidationErrors
],
update: [
validators.id,
body('name').optional().trim().isLength({ min: 1, max: 255 }).escape(),
validators.description,
handleValidationErrors
]
};
// Floor route validators
export const floorValidators = {
create: [
validators.floorNumber,
validators.buildingId,
validators.description,
validators.lastInspection,
validators.totalRooms,
handleValidationErrors
],
update: [
validators.id,
validators.optionalFloorNumber,
validators.totalRooms,
validators.buildingId,
validators.lastInspection,
validators.description,
handleValidationErrors
]
};
// Bed route validators
export const bedValidators = {
create: [
validators.bedNumber,
validators.roomId,
validators.buildingId,
validators.floorId,
validators.monthlyRent,
validators.status(['available', 'occupied', 'maintenance', 'reserved']),
handleValidationErrors
],
update: [
validators.id,
validators.optionalBedNumber,
validators.roomId,
validators.buildingId,
validators.floorId,
validators.monthlyRent,
validators.status(['available', 'occupied', 'maintenance', 'reserved']),
handleValidationErrors
]
};
// Enhanced expense validators (replaces existing expenseValidators)
export const enhancedExpenseValidators = {
create: [
// validators.title,
validators.amount,
validators.date,
validators.optionalCategory,
validators.vendor,
validators.paymentMethod,
validators.description,
// validators.buildingId,
// validators.floorId,
body('subcategory').optional().trim().isLength({ max: 100 }).escape(),
body('budget_category').optional().trim().isLength({ max: 100 }).escape(),
handleValidationErrors
],
update: [
validators.id,
// validators.optionalTitle,
validators.amount,
validators.date,
validators.optionalCategory,
validators.vendor,
validators.paymentMethod,
validators.description,
// validators.buildingId,
// validators.floorId,
body('subcategory').optional().trim().isLength({ max: 100 }).escape(),
body('budget_category').optional().trim().isLength({ max: 100 }).escape(),
handleValidationErrors
]
};
// Settings validators
export const settingsValidators = {
update: [
body('*')
.optional()
.trim()
.isLength({ max: 5000 })
.withMessage('Setting value must not exceed 5000 characters')
.customSanitizer(value => {
// For JSON values, validate they are valid JSON
if (typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) {
try {
JSON.parse(value);
return value;
} catch (e) {
return value;
}
}
// For regular strings, escape HTML
return value;
}),
handleValidationErrors
]
};
// Request validators
export const requestValidators = {
create: [
validators.title,
validators.description,
validators.status(['pending', 'approved', 'rejected', 'in_progress', 'completed']),
body('priority').optional().isIn(['low', 'medium', 'high', 'urgent']),
validators.buildingId,
validators.floorId,
validators.roomId,
handleValidationErrors
],
update: [
validators.id,
validators.optionalTitle,
validators.description,
validators.status(['pending', 'approved', 'rejected', 'in_progress', 'completed']),
body('priority').optional().isIn(['low', 'medium', 'high', 'urgent']),
validators.buildingId,
validators.floorId,
validators.roomId,
handleValidationErrors
]
};
|
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.004 ]-- |