init commit
This commit is contained in:
310
.history/middleware/validation_20251019163300.js
Normal file
310
.history/middleware/validation_20251019163300.js
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Validation middleware for various data types
|
||||
*/
|
||||
|
||||
const { body, validationResult } = require('express-validator');
|
||||
|
||||
/**
|
||||
* Validation error handler
|
||||
*/
|
||||
const handleValidationErrors = (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
// For API requests
|
||||
if (req.xhr || req.headers.accept?.includes('application/json')) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: 'Validation failed',
|
||||
errors: errors.array()
|
||||
});
|
||||
}
|
||||
|
||||
// For web requests
|
||||
const errorMessages = errors.array().map(error => error.msg);
|
||||
req.flash('error', errorMessages);
|
||||
return res.redirect('back');
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
/**
|
||||
* Contact form validation
|
||||
*/
|
||||
const validateContactForm = [
|
||||
body('name')
|
||||
.trim()
|
||||
.isLength({ min: 2, max: 50 })
|
||||
.withMessage('이름은 2-50자 사이여야 합니다.')
|
||||
.matches(/^[a-zA-Z가-힣\s]+$/)
|
||||
.withMessage('이름에는 한글, 영문, 공백만 사용할 수 있습니다.'),
|
||||
|
||||
body('email')
|
||||
.isEmail()
|
||||
.withMessage('유효한 이메일 주소를 입력해주세요.')
|
||||
.normalizeEmail(),
|
||||
|
||||
body('phone')
|
||||
.optional()
|
||||
.matches(/^[0-9\-\+\(\)\s]+$/)
|
||||
.withMessage('유효한 전화번호를 입력해주세요.'),
|
||||
|
||||
body('company')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ max: 100 })
|
||||
.withMessage('회사명은 100자 이하여야 합니다.'),
|
||||
|
||||
body('service')
|
||||
.isIn(['web-development', 'mobile-app', 'ui-ux-design', 'branding', 'digital-marketing', 'consulting', 'other'])
|
||||
.withMessage('유효한 서비스를 선택해주세요.'),
|
||||
|
||||
body('budget')
|
||||
.optional()
|
||||
.isIn(['under-500', '500-1000', '1000-3000', '3000-5000', '5000-10000', 'over-10000', 'discuss'])
|
||||
.withMessage('유효한 예산 범위를 선택해주세요.'),
|
||||
|
||||
body('message')
|
||||
.trim()
|
||||
.isLength({ min: 10, max: 2000 })
|
||||
.withMessage('메시지는 10-2000자 사이여야 합니다.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* User registration validation
|
||||
*/
|
||||
const validateRegistration = [
|
||||
body('name')
|
||||
.trim()
|
||||
.isLength({ min: 2, max: 50 })
|
||||
.withMessage('이름은 2-50자 사이여야 합니다.')
|
||||
.matches(/^[a-zA-Z가-힣\s]+$/)
|
||||
.withMessage('이름에는 한글, 영문, 공백만 사용할 수 있습니다.'),
|
||||
|
||||
body('email')
|
||||
.isEmail()
|
||||
.withMessage('유효한 이메일 주소를 입력해주세요.')
|
||||
.normalizeEmail(),
|
||||
|
||||
body('password')
|
||||
.isLength({ min: 8 })
|
||||
.withMessage('비밀번호는 최소 8자 이상이어야 합니다.')
|
||||
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/)
|
||||
.withMessage('비밀번호는 대소문자, 숫자, 특수문자를 포함해야 합니다.'),
|
||||
|
||||
body('confirmPassword')
|
||||
.custom((value, { req }) => {
|
||||
if (value !== req.body.password) {
|
||||
throw new Error('비밀번호 확인이 일치하지 않습니다.');
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* User login validation
|
||||
*/
|
||||
const validateLogin = [
|
||||
body('email')
|
||||
.isEmail()
|
||||
.withMessage('유효한 이메일 주소를 입력해주세요.')
|
||||
.normalizeEmail(),
|
||||
|
||||
body('password')
|
||||
.isLength({ min: 1 })
|
||||
.withMessage('비밀번호를 입력해주세요.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* Portfolio validation
|
||||
*/
|
||||
const validatePortfolio = [
|
||||
body('title')
|
||||
.trim()
|
||||
.isLength({ min: 2, max: 100 })
|
||||
.withMessage('제목은 2-100자 사이여야 합니다.'),
|
||||
|
||||
body('description')
|
||||
.trim()
|
||||
.isLength({ min: 10, max: 5000 })
|
||||
.withMessage('설명은 10-5000자 사이여야 합니다.'),
|
||||
|
||||
body('shortDescription')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ max: 200 })
|
||||
.withMessage('간단한 설명은 200자 이하여야 합니다.'),
|
||||
|
||||
body('category')
|
||||
.isIn(['web-development', 'mobile-app', 'ui-ux-design', 'branding', 'marketing'])
|
||||
.withMessage('유효한 카테고리를 선택해주세요.'),
|
||||
|
||||
body('technologies')
|
||||
.optional()
|
||||
.isArray()
|
||||
.withMessage('기술 스택은 배열이어야 합니다.'),
|
||||
|
||||
body('clientName')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ max: 100 })
|
||||
.withMessage('클라이언트 이름은 100자 이하여야 합니다.'),
|
||||
|
||||
body('projectUrl')
|
||||
.optional()
|
||||
.isURL()
|
||||
.withMessage('유효한 URL을 입력해주세요.'),
|
||||
|
||||
body('status')
|
||||
.optional()
|
||||
.isIn(['planning', 'in-progress', 'completed', 'on-hold'])
|
||||
.withMessage('유효한 상태를 선택해주세요.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* Service validation
|
||||
*/
|
||||
const validateService = [
|
||||
body('name')
|
||||
.trim()
|
||||
.isLength({ min: 2, max: 100 })
|
||||
.withMessage('서비스명은 2-100자 사이여야 합니다.'),
|
||||
|
||||
body('description')
|
||||
.trim()
|
||||
.isLength({ min: 10, max: 5000 })
|
||||
.withMessage('설명은 10-5000자 사이여야 합니다.'),
|
||||
|
||||
body('shortDescription')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ max: 200 })
|
||||
.withMessage('간단한 설명은 200자 이하여야 합니다.'),
|
||||
|
||||
body('category')
|
||||
.isIn(['development', 'design', 'marketing', 'consulting'])
|
||||
.withMessage('유효한 카테고리를 선택해주세요.'),
|
||||
|
||||
body('pricing.basePrice')
|
||||
.optional()
|
||||
.isNumeric()
|
||||
.withMessage('기본 가격은 숫자여야 합니다.'),
|
||||
|
||||
body('pricing.priceType')
|
||||
.optional()
|
||||
.isIn(['project', 'hourly', 'monthly'])
|
||||
.withMessage('유효한 가격 유형을 선택해주세요.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* Calculator validation
|
||||
*/
|
||||
const validateCalculator = [
|
||||
body('service')
|
||||
.isMongoId()
|
||||
.withMessage('유효한 서비스를 선택해주세요.'),
|
||||
|
||||
body('projectType')
|
||||
.optional()
|
||||
.isIn(['simple', 'medium', 'complex', 'enterprise'])
|
||||
.withMessage('유효한 프로젝트 유형을 선택해주세요.'),
|
||||
|
||||
body('timeline')
|
||||
.optional()
|
||||
.isIn(['urgent', 'normal', 'flexible'])
|
||||
.withMessage('유효한 타임라인을 선택해주세요.'),
|
||||
|
||||
body('features')
|
||||
.optional()
|
||||
.isArray()
|
||||
.withMessage('기능은 배열이어야 합니다.'),
|
||||
|
||||
body('contactInfo.name')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ min: 2, max: 50 })
|
||||
.withMessage('이름은 2-50자 사이여야 합니다.'),
|
||||
|
||||
body('contactInfo.email')
|
||||
.optional()
|
||||
.isEmail()
|
||||
.withMessage('유효한 이메일 주소를 입력해주세요.'),
|
||||
|
||||
body('contactInfo.phone')
|
||||
.optional()
|
||||
.matches(/^[0-9\-\+\(\)\s]+$/)
|
||||
.withMessage('유효한 전화번호를 입력해주세요.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
/**
|
||||
* Settings validation
|
||||
*/
|
||||
const validateSettings = [
|
||||
body('siteName')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ min: 1, max: 100 })
|
||||
.withMessage('사이트명은 1-100자 사이여야 합니다.'),
|
||||
|
||||
body('siteDescription')
|
||||
.optional()
|
||||
.trim()
|
||||
.isLength({ max: 500 })
|
||||
.withMessage('사이트 설명은 500자 이하여야 합니다.'),
|
||||
|
||||
body('contact.email')
|
||||
.optional()
|
||||
.isEmail()
|
||||
.withMessage('유효한 이메일 주소를 입력해주세요.'),
|
||||
|
||||
body('contact.phone')
|
||||
.optional()
|
||||
.matches(/^[0-9\-\+\(\)\s]+$/)
|
||||
.withMessage('유효한 전화번호를 입력해주세요.'),
|
||||
|
||||
body('social.facebook')
|
||||
.optional()
|
||||
.isURL()
|
||||
.withMessage('유효한 Facebook URL을 입력해주세요.'),
|
||||
|
||||
body('social.twitter')
|
||||
.optional()
|
||||
.isURL()
|
||||
.withMessage('유효한 Twitter URL을 입력해주세요.'),
|
||||
|
||||
body('social.linkedin')
|
||||
.optional()
|
||||
.isURL()
|
||||
.withMessage('유효한 LinkedIn URL을 입력해주세요.'),
|
||||
|
||||
body('social.instagram')
|
||||
.optional()
|
||||
.isURL()
|
||||
.withMessage('유효한 Instagram URL을 입력해주세요.'),
|
||||
|
||||
handleValidationErrors
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
handleValidationErrors,
|
||||
validateContactForm,
|
||||
validateRegistration,
|
||||
validateLogin,
|
||||
validatePortfolio,
|
||||
validateService,
|
||||
validateCalculator,
|
||||
validateSettings
|
||||
};
|
||||
Reference in New Issue
Block a user