diff --git a/src/validator/Validator.js b/src/validator/Validator.js index d3c76b3..bbd2704 100644 --- a/src/validator/Validator.js +++ b/src/validator/Validator.js @@ -4,381 +4,382 @@ export class Validator { - constructor(target) { - this.target = target; - } - - static INPUT_STR = 1; - static INPUT_NUM = 2; - static INPUT_FILE = 3; - - handlers = { - - required: (val, present) => present && val !== '' && val !== undefined && val !== null, - - not_empty: (val, present) => present && val !== '' && val !== undefined && val !== null && val !== 0 && val !== '0', - - sometimes: (_, present) => !present ? null : true, - - filled: (val, present) => !present ? null : val !== '' && val !== undefined && val !== null, - - present: (_, present) => present, - - missing: (_, present) => !present, - - nullable: (val, present) => (!present || val === '' || val === undefined || val === null) ? null: true, - - numeric: (val, present, arg, format) => { - format.value = Validator.INPUT_NUM; - return !present ? null : !isNaN(val); - }, - - integer: (val, present, arg, format) => { - format.value = Validator.INPUT_NUM; - return !present ? null : Number.isInteger(Number(val)); - }, - - boolean: (val, present, arg, format) => { - format.value = Validator.INPUT_NUM; - return !present ? null : [true, false, 0, 1, '0', '1'].includes(val); - }, - - string: (val, present, arg, format) => { - format.value = Validator.INPUT_STR; - return !present ? null : typeof val === 'string'; - }, - file: (val, present, arg, format) => { - - format.value = Validator.INPUT_FILE; - - return !present ? null : ( - typeof val === 'object' && - 'error' in val && - 'tmp_name' in val && - val.error === 0 - ); - }, - - image: (val, present, arg, format) => { - - format.value = Validator.INPUT_FILE; - - if (!present) return null; - - if ( - typeof val !== 'object' || - !('error' in val) || - !('tmp_name' in val) || - val.error !== 0 || - typeof val.name !== 'string' - ) { - return false; - } - - const ext = val.name.split('.').pop().toLowerCase(); - - return ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'svg', 'webp'].includes(ext); - }, - - mimes: (val, present, arg, format) => { - - if (!present) return null; - - if ( - typeof val !== 'object' || - !('error' in val) || - !('tmp_name' in val) || - val.error !== 0 || - typeof val.name !== 'string' - ) { - return false; - } - - const allowed = arg.split(',').map(ext => ext.trim().toLowerCase()); - const ext = val.name.split('.').pop().toLowerCase(); - - return allowed.includes(ext); - }, - - min: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length >= arg) || - (format.value === Validator.INPUT_NUM && Number(val) >= arg) - ); - }, - - max: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length <= arg) || - (format.value === Validator.INPUT_NUM && Number(val) <= arg) - ); - }, - - size: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length == arg) || - (format.value === Validator.INPUT_NUM && Number(val) == arg) - ); - }, - - gt: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length > arg) || - (format.value === Validator.INPUT_NUM && Number(val) > arg) - ); - }, - - gte: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length >= arg) || - (format.value === Validator.INPUT_NUM && Number(val) >= arg) - ); - }, - - lt: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length < arg) || - (format.value === Validator.INPUT_NUM && Number(val) < arg) - ); - }, - - lte: (val, present, arg, format) => { - - if (!present) return null; - - return ( - (format.value === Validator.INPUT_STR && val.length <= arg) || - (format.value === Validator.INPUT_NUM && Number(val) <= arg) - ); - }, - - between: (val, present, arg, format) => { - - if (!present) return null; - - const [min, max] = arg.split(',').map(Number); - - if (isNaN(min) || isNaN(max)) return false; - - if (format.value === Validator.INPUT_STR) { - const len = val.length; - return len >= min && len <= max; - } else if (format.value === Validator.INPUT_NUM) { - return Number(val) >= min && Number(val) <= max; - } - - return false; - }, - - accepted: (val, present) => !present ? null : ['yes', 'on', 1, '1', true, 'true'].includes(val), - - declined: (val, present) => !present ? null : ['no', 'off', 0, '0', false, 'false'].includes(val), - - starts_with: (val, present, arg) => { - - if (!present) return null; - - return arg.split(',').some(prefix => val.startsWith(prefix)); - }, - - ends_with: (val, present, arg) => { - - if (!present) return null; - - return arg.split(',').some(suffix => val.endsWith(suffix)); - }, - - alpha: (val, present) => !present ? null : /^[a-zA-Z]+$/.test(val), - - alpha_num: (val, present) => !present ? null : /^[a-zA-Z0-9]+$/.test(val), - - uppercase: (val, present) => !present ? null : val === val.toUpperCase(), - - lowercase: (val, present) => !present ? null : val === val.toLowerCase(), - - domain: (val, present) => !present ? null : /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(val), - - email: (val, present) => !present ? null : /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val), - - url: (val, present) => { - - if (!present) return null; - - try { - new URL(val); - return true; - } catch { - return false; - } - }, - - ip: (val, present) => !present ? null : (this.handlers.ipv4(val, present) || this.handlers.ipv6(val, present) ), - - ipv4: (val, present) => !present ? null : /^(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)$/.test(val), - - ipv6: (val, present) => !present ? null : /^([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4})$/.test(val), - - hash: (val, present) => !present ? null : /^[a-f0-9]+$/i.test(val), - - in: (val, present, arg) => !present ? null : arg.split(',').includes(val), - - same: (val, present, arg) => !present ? null : val === this.target.elements[arg].value, - - json: (val, present) => { - - if (!present) return null; - - try { - JSON.parse(val); - return true; - } catch { - return false; - } - }, + constructor(target) { + this.target = target; + } + + static INPUT_STR = 1; + static INPUT_NUM = 2; + static INPUT_FILE = 3; + + handlers = { + + required: (val, present) => present && val !== '' && val !== undefined && val !== null, + + not_empty: (val, present) => present && val !== '' && val !== undefined && val !== null && val !== 0 && val !== '0', + + sometimes: (_, present) => !present ? null : true, + + filled: (val, present) => !present ? null : val !== '' && val !== undefined && val !== null, + + present: (_, present) => present, + + missing: (_, present) => !present, + + nullable: (val, present) => (!present || val === '' || val === undefined || val === null) ? null: true, + + numeric: (val, present, arg, format) => { + format.value = Validator.INPUT_NUM; + return !present ? null : !isNaN(val); + }, + + integer: (val, present, arg, format) => { + format.value = Validator.INPUT_NUM; + return !present ? null : Number.isInteger(Number(val)); + }, + + boolean: (val, present, arg, format) => { + format.value = Validator.INPUT_NUM; + return !present ? null : [true, false, 0, 1, '0', '1'].includes(val); + }, + + string: (val, present, arg, format) => { + format.value = Validator.INPUT_STR; + return !present ? null : typeof val === 'string'; + }, + file: (val, present, arg, format) => { + + format.value = Validator.INPUT_FILE; + + return !present ? null : ( + typeof val === 'object' && + 'error' in val && + 'tmp_name' in val && + val.error === 0 + ); + }, + + image: (val, present, arg, format) => { + + format.value = Validator.INPUT_FILE; + + if (!present) return null; + + if ( + typeof val !== 'object' || + !('error' in val) || + !('tmp_name' in val) || + val.error !== 0 || + typeof val.name !== 'string' + ) { + return false; + } + + const ext = val.name.split('.').pop().toLowerCase(); + + return ['jpg', 'jpeg', 'png', 'bmp', 'gif', 'svg', 'webp'].includes(ext); + }, + + mimes: (val, present, arg, format) => { + + if (!present) return null; + + if ( + typeof val !== 'object' || + !('error' in val) || + !('tmp_name' in val) || + val.error !== 0 || + typeof val.name !== 'string' + ) { + return false; + } + + const allowed = arg.split(',').map(ext => ext.trim().toLowerCase()); + const ext = val.name.split('.').pop().toLowerCase(); + + return allowed.includes(ext); + }, + + min: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length >= arg) || + (format.value === Validator.INPUT_NUM && Number(val) >= arg) + ); + }, + + max: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length <= arg) || + (format.value === Validator.INPUT_NUM && Number(val) <= arg) + ); + }, + + size: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length == arg) || + (format.value === Validator.INPUT_NUM && Number(val) == arg) + ); + }, + + gt: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length > arg) || + (format.value === Validator.INPUT_NUM && Number(val) > arg) + ); + }, + + gte: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length >= arg) || + (format.value === Validator.INPUT_NUM && Number(val) >= arg) + ); + }, + + lt: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length < arg) || + (format.value === Validator.INPUT_NUM && Number(val) < arg) + ); + }, + + lte: (val, present, arg, format) => { + + if (!present) return null; + + return ( + (format.value === Validator.INPUT_STR && val.length <= arg) || + (format.value === Validator.INPUT_NUM && Number(val) <= arg) + ); + }, + + between: (val, present, arg, format) => { + + if (!present) return null; + + const [min, max] = arg.split(',').map(Number); + + if (isNaN(min) || isNaN(max)) return false; + + if (format.value === Validator.INPUT_STR) { + const len = val.length; + return len >= min && len <= max; + } else if (format.value === Validator.INPUT_NUM) { + return Number(val) >= min && Number(val) <= max; + } + + return false; + }, + + accepted: (val, present) => !present ? null : ['yes', 'on', 1, '1', true, 'true'].includes(val), + + declined: (val, present) => !present ? null : ['no', 'off', 0, '0', false, 'false'].includes(val), + + starts_with: (val, present, arg) => { + + if (!present) return null; + + return arg.split(',').some(prefix => val.startsWith(prefix)); + }, + + ends_with: (val, present, arg) => { + + if (!present) return null; + + return arg.split(',').some(suffix => val.endsWith(suffix)); + }, + + alpha: (val, present) => !present ? null : /^[a-zA-Z]+$/.test(val), + + alpha_num: (val, present) => !present ? null : /^[a-zA-Z0-9]+$/.test(val), + + uppercase: (val, present) => !present ? null : val === val.toUpperCase(), + + lowercase: (val, present) => !present ? null : val === val.toLowerCase(), + + domain: (val, present) => !present ? null : /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/.test(val), + + email: (val, present) => !present ? null : /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val), + + url: (val, present) => { + + if (!present) return null; + + try { + new URL(val); + return true; + } catch { + return false; + } + }, + + ip: (val, present) => !present ? null : (this.handlers.ipv4(val, present) || this.handlers.ipv6(val, present) ), + + ipv4: (val, present) => !present ? null : /^(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|1?[0-9][0-9]?)$/.test(val), + + ipv6: (val, present) => !present ? null : /^([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4})$/.test(val), + + hash: (val, present) => !present ? null : /^[a-f0-9]+$/i.test(val), + + in: (val, present, arg) => !present ? null : arg.split(',').includes(val), + + same: (val, present, arg) => !present ? null : val === this.target.elements[arg].value, + + json: (val, present) => { + + if (!present) return null; + + try { + JSON.parse(val); + return true; + } catch { + return false; + } + }, - date: (val, present, arg, format) => !present ? null : format.value === Validator.INPUT_STR && !isNaN(Date.parse(val)), + date: (val, present, arg, format) => !present ? null : format.value === Validator.INPUT_STR && !isNaN(Date.parse(val)), - cnp: (val, present, arg, format) => !present ? null : this.validCNP(val) - }; + cnp: (val, present, arg, format) => !present ? null : this.validCNP(val) + }; - getData() { + getData() { - let fdata = new FormData(); + let fdata = new FormData(); - [...this.target.elements].forEach(el => { + for (const el of [...this.target.elements]) { - if (!el.name || el.type == 'button' || el.type == 'submit') { - return true; - } + if (!el.name || el.type == 'button' || el.type == 'submit') { + continue; + } - let value; - let displayedVal = null; + let value; + let displayedVal = null; - const widget = el.dxWidget(); + const widget = el.dxWidget(); - if (widget) { - value = widget.getValue(); - displayedVal = el.value.trim(); - } - else { - value = el.value.trim(); - } + if (widget) { + value = widget.getValue(); + displayedVal = el.value.trim(); + } + else { + value = el.value.trim(); + } - switch (el.type) { + switch (el.type) { - case 'file': + case 'file': - let uploader = el.dxData('uploader'); + let uploader = el.dxData('uploader'); - if (uploader) { - uploader.getFiles().forEach(filename => fdata.append('file__' + el.name + '[]', filename)); - } - - break; - case 'radio': + if (uploader) { + uploader.getFiles().forEach(filename => fdata.append('file__' + el.name + '[]', filename)); + } + + break; + case 'radio': - if (!fdata.has(el.name)) { - fdata.set(el.name, ''); - } + if (!fdata.has(el.name)) { + fdata.set(el.name, ''); + } - if (el.checked) { - fdata.set(el.name, value); - } + if (el.checked) { + fdata.set(el.name, value); + } - break; - case 'checkbox': + break; + case 'checkbox': - if (el.checked) { - fdata.append(el.name + '[]', value ); - } + if (el.checked) { + fdata.append(el.name + '[]', value ); + } - break; - case 'select-multiple': + break; + case 'select-multiple': - for (let j = 0; j < el.options.length; j++) { - if (el.options[j].selected && el.options[j].value != 0) { - fdata.append(el.name + '[]', /^\d+$/.test(el.options[j].value) - ? parseInt(el.options[j].value) - : el.options[j].value - ); - } - } + for (let j = 0; j < el.options.length; j++) { + if (el.options[j].selected && el.options[j].value != 0) { + fdata.append(el.name + '[]', /^\d+$/.test(el.options[j].value) + ? parseInt(el.options[j].value) + : el.options[j].value + ); + } + } - break; - default: + break; + default: - if (fdata.has(el.name)) { - - fdata.append(el.name + '[]', fdata.get(el.name) ); - fdata.delete(el.name); - fdata.append(el.name + '[]', value); - } - else if (fdata.has(el.name + '[]')) { - fdata.append(el.name + '[]', value); - } - else { + if (fdata.has(el.name) ) { + + if (!el.name.endsWith('[]') ) { + fdata.delete(el.name); + fdata.append(el.name + '[]', value); + continue; + } - fdata.set(el.name, value); + fdata.append(el.name, value); + + continue; + } - if (displayedVal) { - fdata.set(el.name + '_value', displayedVal); - } - } - } - }); + fdata.set(el.name, value); - return fdata; - } + if (displayedVal) { + fdata.set(el.name + '_value', displayedVal); + } + } + } - validCNP(value) { + return fdata; + } - let i = 0 , year = 0 , hashResult = 0 , cnp = [] , hashTable = [ 2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9 ]; + validCNP(value) { - if ( value.length !== 13 ) { return false; } + let i = 0 , year = 0 , hashResult = 0 , cnp = [] , hashTable = [ 2, 7, 9, 1, 4, 6, 3, 5, 8, 2, 7, 9 ]; - for ( i = 0 ; i < 13 ; i++ ) { + if ( value.length !== 13 ) { return false; } - cnp[i] = parseInt( value.charAt(i) , 10 ); + for ( i = 0 ; i < 13 ; i++ ) { - if( isNaN( cnp[i] ) ) { return false; } + cnp[i] = parseInt( value.charAt(i) , 10 ); - if( i < 12 ) { hashResult = hashResult + ( cnp[i] * hashTable[i] ); } - } + if( isNaN( cnp[i] ) ) { return false; } - hashResult = hashResult % 11; + if( i < 12 ) { hashResult = hashResult + ( cnp[i] * hashTable[i] ); } + } - if( hashResult === 10 ) { hashResult = 1; } + hashResult = hashResult % 11; - year = (cnp[1]*10)+cnp[2]; + if( hashResult === 10 ) { hashResult = 1; } - switch( cnp[0] ) { - case 1 : case 2 : { year += 1900; } break; - case 3 : case 4 : { year += 1800; } break; - case 5 : case 6 : { year += 2000; } break; - case 7 : case 8 : case 9 : { year += 2000; if( year > ( parseInt( new Date().getFullYear() , 10 ) - 14 ) ) { year -= 100; } } break; - default : { return false; } - } + year = (cnp[1]*10)+cnp[2]; - if( year < 1800 || year > 2099 ) { return false; } + switch( cnp[0] ) { + case 1 : case 2 : { year += 1900; } break; + case 3 : case 4 : { year += 1800; } break; + case 5 : case 6 : { year += 2000; } break; + case 7 : case 8 : case 9 : { year += 2000; if( year > ( parseInt( new Date().getFullYear() , 10 ) - 14 ) ) { year -= 100; } } break; + default : { return false; } + } - return ( cnp[12] === hashResult ); - } + if( year < 1800 || year > 2099 ) { return false; } + + return ( cnp[12] === hashResult ); + } } \ No newline at end of file