Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fh-forms

Package Overview
Dependencies
Maintainers
1
Versions
178
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fh-forms - npm Package Compare versions

Comparing version 0.5.6 to 0.5.7

2233

lib/common/forms-rule-engine.js
(function () {
var async=require('async');
var async = require('async');
/*
* Sample Usage
*
* var engine = formsRulesEngine(form-definition);
*
* engine.validateForms(form-submission, function(err, res) {});
* res:
* {
* "validation": {
* "fieldId": {
* "fieldId": "",
* "valid": true,
* "errorMessages": [
* "length should be 3 to 5",
* "should not contain dammit",
* "should repeat at least 2 times"
* ]
* },
* "fieldId1": {
*
* }
* }
* }
*
*
* engine.validateField(fieldId, submissionJSON, function(err,res) {});
* // validate only field values on validation (no rules, no repeat checking)
* res:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*
* engine.checkRules(submissionJSON, unction(err, res) {})
* // check all rules actions
* res:
* {
* "actions": {
* "pages": {
* "targetId": {
* "targetId": "",
* "action": "show|hide"
* }
* },
* "fields": {
*
* }
* }
* }
*
*/
/*
* Sample Usage
*
* var engine = formsRulesEngine(form-definition);
*
* engine.validateForms(form-submission, function(err, res) {});
* res:
* {
* "validation": {
* "fieldId": {
* "fieldId": "",
* "valid": true,
* "errorMessages": [
* "length should be 3 to 5",
* "should not contain dammit",
* "should repeat at least 2 times"
* ]
* },
* "fieldId1": {
*
* }
* }
* }
*
*
* engine.validateField(fieldId, submissionJSON, function(err,res) {});
* // validate only field values on validation (no rules, no repeat checking)
* res:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*
* engine.checkRules(submissionJSON, unction(err, res) {})
* // check all rules actions
* res:
* {
* "actions": {
* "pages": {
* "targetId": {
* "targetId": "",
* "action": "show|hide"
* }
* },
* "fields": {
*
* }
* }
* }
*
*/
var FIELD_TYPE_CHECKBOX = "checkboxes";
var FIELD_TYPE_DATETIME = "dateTime";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY = "date";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY = "time";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME = "datetime";
var FIELD_TYPE_CHECKBOX = "checkboxes";
var FIELD_TYPE_DATETIME = "dateTime";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY = "date";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY = "time";
var FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME = "datetime";
var formsRulesEngine = function(formDef) {
var initialised;
var formsRulesEngine = function (formDef) {
var initialised;
var definition = formDef;
var submission;
var definition = formDef;
var submission;
var fieldMap = {};
var requiredFieldMap = {};
var submissionRequiredFieldsMap = {}; // map to hold the status of the required fields per submission
var fieldRulePredicateMap = {};
var fieldRuleSubjectMap = {};
var pageRulePredicateMap = {};
var pageRuleSubjectMap = {};
var submissionFieldsMap = {};
var validatorsMap = {
"text": validatorString,
"textarea": validatorString,
"number": validatorNumericString,
"emailAddress": validatorEmail,
"dropdown": validatorDropDown,
"radio": validatorDropDown,
"checkboxes": validatorCheckboxes,
"location": validatorLocation,
"locationMap": validatorLocationMap,
"photo": validatorFile,
"signature": validatorFile,
"file": validatorFile,
"dateTime": validatorDateTime,
"url": validatorString,
"sectionBreak": validatorSection
};
var fieldMap = {};
var requiredFieldMap = {};
var submissionRequiredFieldsMap = {}; // map to hold the status of the required fields per submission
var fieldRulePredicateMap = {};
var fieldRuleSubjectMap = {};
var pageRulePredicateMap = {};
var pageRuleSubjectMap = {};
var submissionFieldsMap = {};
var validatorsMap = {
"text": validatorString,
"textarea": validatorString,
"number": validatorNumericString,
"emailAddress": validatorEmail,
"dropdown": validatorDropDown,
"radio": validatorDropDown,
"checkboxes": validatorCheckboxes,
"location": validatorLocation,
"locationMap": validatorLocationMap,
"photo": validatorFile,
"signature": validatorFile,
"file": validatorFile,
"dateTime": validatorDateTime,
"url": validatorString,
"sectionBreak": validatorSection
};
var validatorsClientMap = {
"text": validatorString,
"textarea": validatorString,
"number": validatorNumericString,
"emailAddress": validatorEmail,
"dropdown": validatorDropDown,
"radio": validatorDropDown,
"checkboxes": validatorCheckboxes,
"location": validatorLocation,
"locationMap": validatorLocationMap,
"photo": validatorAnyFile,
"signature": validatorAnyFile,
"file": validatorAnyFile,
"dateTime": validatorDateTime,
"url": validatorString,
"sectionBreak": validatorSection
};
var validatorsClientMap = {
"text": validatorString,
"textarea": validatorString,
"number": validatorNumericString,
"emailAddress": validatorEmail,
"dropdown": validatorDropDown,
"radio": validatorDropDown,
"checkboxes": validatorCheckboxes,
"location": validatorLocation,
"locationMap": validatorLocationMap,
"photo": validatorAnyFile,
"signature": validatorAnyFile,
"file": validatorAnyFile,
"dateTime": validatorDateTime,
"url": validatorString,
"sectionBreak": validatorSection
};
var isFieldRuleSubject = function(fieldId) {
return !!fieldRuleSubjectMap[fieldId];
};
var isFieldRuleSubject = function (fieldId) {
return !!fieldRuleSubjectMap[fieldId];
};
var isPageRuleSubject = function(pageId) {
return !!pageRuleSubjectMap[pageId];
};
var isPageRuleSubject = function (pageId) {
return !!pageRuleSubjectMap[pageId];
};
function buildFieldMap(cb) {
// Iterate over all fields in form definition & build fieldMap
async.each(definition.pages, function(page, cbPages) {
async.each(page.fields, function(field, cbFields) {
field.pageId = page._id;
function buildFieldMap(cb) {
// Iterate over all fields in form definition & build fieldMap
async.each(definition.pages, function (page, cbPages) {
async.each(page.fields, function (field, cbFields) {
field.pageId = page._id;
field.fieldOptions = field.fieldOptions ? field.fieldOptions : {};
field.fieldOptions.definition = field.fieldOptions.definition ? field.fieldOptions.definition : {};
field.fieldOptions.validation = field.fieldOptions.validation ? field.fieldOptions.validation : {};
field.fieldOptions = field.fieldOptions ? field.fieldOptions : {};
field.fieldOptions.definition = field.fieldOptions.definition ? field.fieldOptions.definition : {};
field.fieldOptions.validation = field.fieldOptions.validation ? field.fieldOptions.validation : {};
fieldMap[field._id] = field;
if (field.required) {
requiredFieldMap[field._id] = {field: field, submitted: false, validated: false};
}
return cbFields();
}, function (err) {
return cbPages();
});
}, cb);
}
fieldMap[field._id] = field;
if (field.required) {
requiredFieldMap[field._id] = {
field: field,
submitted: false,
validated: false
};
}
return cbFields();
}, function (err) {
return cbPages();
});
}, cb);
}
function buildFieldRuleMaps(cb) {
// Iterate over all rules in form definition & build ruleSubjectMap
async.each(definition.fieldRules, function(rule, cbRules) {
async.each(rule.ruleConditionalStatements, function(ruleConditionalStatement, cbRuleConditionalStatements) {
var fieldId = ruleConditionalStatement.sourceField;
fieldRulePredicateMap[fieldId] = fieldRulePredicateMap[fieldId] || [];
fieldRulePredicateMap[fieldId].push(rule);
return cbRuleConditionalStatements();
}, function (err) {
fieldRuleSubjectMap[rule.targetField] = fieldRuleSubjectMap[rule.targetField] || [];
fieldRuleSubjectMap[rule.targetField].push(rule);
return cbRules();
});
}, cb);
}
function buildFieldRuleMaps(cb) {
// Iterate over all rules in form definition & build ruleSubjectMap
async.each(definition.fieldRules, function (rule, cbRules) {
async.each(rule.ruleConditionalStatements, function (ruleConditionalStatement, cbRuleConditionalStatements) {
var fieldId = ruleConditionalStatement.sourceField;
fieldRulePredicateMap[fieldId] = fieldRulePredicateMap[fieldId] || [];
fieldRulePredicateMap[fieldId].push(rule);
return cbRuleConditionalStatements();
}, function (err) {
fieldRuleSubjectMap[rule.targetField] = fieldRuleSubjectMap[rule.targetField] || [];
fieldRuleSubjectMap[rule.targetField].push(rule);
return cbRules();
});
}, cb);
}
function buildPageRuleMap(cb) {
// Iterate over all rules in form definition & build ruleSubjectMap
async.each(definition.pageRules, function(rule, cbRules) {
var rulesId = rule._id;
async.each(rule.ruleConditionalStatements, function(ruleConditionalStatement, cbRulePredicates) {
var fieldId = ruleConditionalStatement.sourceField;
pageRulePredicateMap[fieldId] = pageRulePredicateMap[fieldId] || [];
pageRulePredicateMap[fieldId].push(rule);
return cbRulePredicates();
}, function (err) {
pageRuleSubjectMap[rule.targetPage] = pageRuleSubjectMap[rule.targetPage] || [];
pageRuleSubjectMap[rule.targetPage].push(rule);
return cbRules();
});
}, cb);
}
function buildPageRuleMap(cb) {
// Iterate over all rules in form definition & build ruleSubjectMap
async.each(definition.pageRules, function (rule, cbRules) {
var rulesId = rule._id;
async.each(rule.ruleConditionalStatements, function (ruleConditionalStatement, cbRulePredicates) {
var fieldId = ruleConditionalStatement.sourceField;
pageRulePredicateMap[fieldId] = pageRulePredicateMap[fieldId] || [];
pageRulePredicateMap[fieldId].push(rule);
return cbRulePredicates();
}, function (err) {
pageRuleSubjectMap[rule.targetPage] = pageRuleSubjectMap[rule.targetPage] || [];
pageRuleSubjectMap[rule.targetPage].push(rule);
return cbRules();
});
}, cb);
}
function buildSubmissionFieldsMap(cb) {
submissionRequiredFieldsMap = JSON.parse(JSON.stringify(requiredFieldMap)); // clone the map for use with this submission
submissionFieldsMap = {}; // start with empty map, rulesEngine can be called with multiple submissions
function buildSubmissionFieldsMap(cb) {
submissionRequiredFieldsMap = JSON.parse(JSON.stringify(requiredFieldMap)); // clone the map for use with this submission
submissionFieldsMap = {}; // start with empty map, rulesEngine can be called with multiple submissions
// iterate over all the fields in the submissions and build a map for easier lookup
async.each(submission.formFields, function(formField, cb) {
if (!formField.fieldId) return cb(new Error("No fieldId in this submission entry: " + util.inspect(formField)));
// iterate over all the fields in the submissions and build a map for easier lookup
async.each(submission.formFields, function (formField, cb) {
if (!formField.fieldId) return cb(new Error("No fieldId in this submission entry: " + util.inspect(formField)));
submissionFieldsMap[formField.fieldId] = formField;
return cb();
}, cb);
}
submissionFieldsMap[formField.fieldId] = formField;
return cb();
}, cb);
}
function init(cb) {
if(initialised) return cb();
async.parallel([
buildFieldMap,
buildFieldRuleMaps,
buildPageRuleMap
], function(err) {
if (err) return cb(err);
initialised = true;
return cb();
});
}
function init(cb) {
if (initialised) return cb();
async.parallel([
buildFieldMap,
buildFieldRuleMaps,
buildPageRuleMap
], function (err) {
if (err) return cb(err);
initialised = true;
return cb();
});
}
function initSubmission(formSubmission, cb) {
init(function(err){
if (err) return cb(err);
function initSubmission(formSubmission, cb) {
init(function (err) {
if (err) return cb(err);
submission = formSubmission;
buildSubmissionFieldsMap(cb);
});
}
function getPreviousFieldValues(submittedField, previousSubmission, cb) {
if(previousSubmission && previousSubmission.formFields) {
async.filter(previousSubmission.formFields, function (formField, cb) {
return cb(formField.fieldId.toString() == submittedField.fieldId.toString());
}, function (results) {
var previousFieldValues = null;
if (results && results[0] && results[0].fieldValues) {
previousFieldValues = results[0].fieldValues;
}
return cb(undefined, previousFieldValues);
submission = formSubmission;
buildSubmissionFieldsMap(cb);
});
} else {
return cb();
}
}
function validateForm(submission, previousSubmission, cb) {
if ("function" === typeof previousSubmission) {
cb = previousSubmission;
previousSubmission = null;
function getPreviousFieldValues(submittedField, previousSubmission, cb) {
if (previousSubmission && previousSubmission.formFields) {
async.filter(previousSubmission.formFields, function (formField, cb) {
return cb(formField.fieldId.toString() == submittedField.fieldId.toString());
}, function (results) {
var previousFieldValues = null;
if (results && results[0] && results[0].fieldValues) {
previousFieldValues = results[0].fieldValues;
}
return cb(undefined, previousFieldValues);
});
} else {
return cb();
}
}
init(function(err){
if (err) return cb(err);
initSubmission(submission, function (err) {
function validateForm(submission, previousSubmission, cb) {
if ("function" === typeof previousSubmission) {
cb = previousSubmission;
previousSubmission = null;
}
init(function (err) {
if (err) return cb(err);
async.waterfall([
function (cb) {
return cb(undefined, {validation:{valid: true}}); // any invalid fields will set this to false
},
function (res, cb) {
validateSubmittedFields(res, previousSubmission, cb);
},
checkIfRequiredFieldsNotSubmitted
], function (err, results) {
initSubmission(submission, function (err) {
if (err) return cb(err);
return cb(undefined, results);
async.waterfall([
function (cb) {
return cb(undefined, {
validation: {
valid: true
}
}); // any invalid fields will set this to false
},
function (res, cb) {
validateSubmittedFields(res, previousSubmission, cb);
},
checkIfRequiredFieldsNotSubmitted
], function (err, results) {
if (err) return cb(err);
return cb(undefined, results);
});
});
});
});
}
}
function validateSubmittedFields(res, previousSubmission, cb) {
// for each field, call validateField
async.each(submission.formFields, function(submittedField, callback) {
var fieldID = submittedField.fieldId;
var fieldDef = fieldMap[fieldID];
function validateSubmittedFields(res, previousSubmission, cb) {
// for each field, call validateField
async.each(submission.formFields, function (submittedField, callback) {
var fieldID = submittedField.fieldId;
var fieldDef = fieldMap[fieldID];
getPreviousFieldValues(submittedField, previousSubmission, function (err, previousFieldValues) {
if(err) return callback(err);
getFieldValidationStatus(submittedField, fieldDef, previousFieldValues, function(err, fieldRes) {
if(err) return callback(err);
getPreviousFieldValues(submittedField, previousSubmission, function (err, previousFieldValues) {
if (err) return callback(err);
getFieldValidationStatus(submittedField, fieldDef, previousFieldValues, function (err, fieldRes) {
if (err) return callback(err);
if (!fieldRes.valid) {
res.validation.valid = false; // indicate invalid form if any fields invalid
res.validation[fieldID] = fieldRes; // add invalid field info to validate form result
}
if (!fieldRes.valid) {
res.validation.valid = false; // indicate invalid form if any fields invalid
res.validation[fieldID] = fieldRes; // add invalid field info to validate form result
}
return callback();
return callback();
});
});
}, function (err) {
if (err) {
return cb(err);
}
return cb(undefined, res);
});
}, function(err) {
if( err ) {
return cb(err);
}
return cb(undefined, res);
});
}
}
function checkIfRequiredFieldsNotSubmitted(res, cb) {
async.each(Object.keys(submissionRequiredFieldsMap), function (requiredFieldId, cb) {
var resField = {};
if (!submissionRequiredFieldsMap[requiredFieldId].submitted) {
isFieldVisible(requiredFieldId, true, function (err, visible) {
if (err) return cb(err);
if (visible) { // we only care about required fields if they are visible
resField.fieldId = requiredFieldId;
resField.valid = false;
resField.fieldErrorMessage = ["Required Field Not Submitted"];
res.validation[requiredFieldId] = resField;
res.validation.valid = false;
}
function checkIfRequiredFieldsNotSubmitted(res, cb) {
async.each(Object.keys(submissionRequiredFieldsMap), function (requiredFieldId, cb) {
var resField = {};
if (!submissionRequiredFieldsMap[requiredFieldId].submitted) {
isFieldVisible(requiredFieldId, true, function (err, visible) {
if (err) return cb(err);
if (visible) { // we only care about required fields if they are visible
resField.fieldId = requiredFieldId;
resField.valid = false;
resField.fieldErrorMessage = ["Required Field Not Submitted"];
res.validation[requiredFieldId] = resField;
res.validation.valid = false;
}
return cb();
});
} else { // was included in submission
return cb();
});
} else { // was included in submission
return cb();
}
}, function (err) {
if (err) return cb(err);
return cb(undefined, res);
});
}
}
}, function (err) {
if (err) return cb(err);
return cb(undefined, res);
});
}
/*
* validate only field values on validation (no rules, no repeat checking)
* res:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*/
function validateField(fieldId, submission, cb) {
init(function(err){
if (err) return cb(err);
initSubmission(submission, function (err) {
/*
* validate only field values on validation (no rules, no repeat checking)
* res:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*/
function validateField(fieldId, submission, cb) {
init(function (err) {
if (err) return cb(err);
var submissionField = submissionFieldsMap[fieldId];
var fieldDef = fieldMap[fieldId];
getFieldValidationStatus(submissionField, fieldDef, null, function (err, res) {
initSubmission(submission, function (err) {
if (err) return cb(err);
var ret = {validation: {}};
ret.validation[fieldId] = res;
return cb(undefined, ret);
var submissionField = submissionFieldsMap[fieldId];
var fieldDef = fieldMap[fieldId];
getFieldValidationStatus(submissionField, fieldDef, null, function (err, res) {
if (err) return cb(err);
var ret = {
validation: {}
};
ret.validation[fieldId] = res;
return cb(undefined, ret);
});
});
});
});
}
/*
* validate only single field value (no rules, no repeat checking)
* cb(err, result)
* example of result:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*/
function validateFieldValue(fieldId, inputValue, valueIndex, cb) {
if ("function" === typeof valueIndex) {
cb = valueIndex;
valueIndex = 0;
}
init(function(err){
if (err) return cb(err);
var fieldDefinition = fieldMap[fieldId];
var required = false;
if(fieldDefinition.repeating &&
fieldDefinition.fieldOptions &&
fieldDefinition.fieldOptions.definition &&
fieldDefinition.fieldOptions.definition.minRepeat) {
required = (valueIndex < fieldDefinition.fieldOptions.definition.minRepeat);
} else {
required = fieldDefinition.required;
/*
* validate only single field value (no rules, no repeat checking)
* cb(err, result)
* example of result:
* "validation":{
* "fieldId":{
* "fieldId":"",
* "valid":true,
* "errorMessages":[
* "length should be 3 to 5",
* "should not contain dammit"
* ]
* }
* }
*/
function validateFieldValue(fieldId, inputValue, valueIndex, cb) {
if ("function" === typeof valueIndex) {
cb = valueIndex;
valueIndex = 0;
}
var validation = (fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) ? fieldDefinition.fieldOptions.validation : undefined;
init(function (err) {
if (err) return cb(err);
var fieldDefinition = fieldMap[fieldId];
if( validation && false === validation.validateImmediately){
var ret = {validation: {}};
ret.validation[fieldId] = {"valid":true};
return cb(undefined, ret );
}
if(fieldEmpty(inputValue)) {
if(required) {
return formatResponse("No value specified for required input", cb);
var required = false;
if (fieldDefinition.repeating &&
fieldDefinition.fieldOptions &&
fieldDefinition.fieldOptions.definition &&
fieldDefinition.fieldOptions.definition.minRepeat) {
required = (valueIndex < fieldDefinition.fieldOptions.definition.minRepeat);
} else {
return formatResponse(undefined, cb); // optional field not supplied is valid
required = fieldDefinition.required;
}
}
// not empty need to validate
getClientValidatorFunction(fieldDefinition.type, function (err, validator) {
if (err) return cb(err);
var validation = (fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) ? fieldDefinition.fieldOptions.validation : undefined;
validator(inputValue, fieldDefinition, undefined, function (err) {
var message;
if(err) {
if(err.message) {
message = err.message;
} else {
message = "Unknown error message";
if (validation && false === validation.validateImmediately) {
var ret = {
validation: {}
};
ret.validation[fieldId] = {
"valid": true
};
return cb(undefined, ret);
}
if (fieldEmpty(inputValue)) {
if (required) {
return formatResponse("No value specified for required input", cb);
} else {
return formatResponse(undefined, cb); // optional field not supplied is valid
}
}
// not empty need to validate
getClientValidatorFunction(fieldDefinition.type, function (err, validator) {
if (err) return cb(err);
validator(inputValue, fieldDefinition, undefined, function (err) {
var message;
if (err) {
if (err.message) {
message = err.message;
} else {
message = "Unknown error message";
}
}
}
formatResponse(message, cb);
formatResponse(message, cb);
});
});
});
});
function formatResponse(msg, cb) {
var messages = {errorMessages: []};
if(msg) {
messages.errorMessages.push(msg);
function formatResponse(msg, cb) {
var messages = {
errorMessages: []
};
if (msg) {
messages.errorMessages.push(msg);
}
return createValidatorResponse(fieldId, messages, function (err, res) {
if (err) return cb(err);
var ret = {
validation: {}
};
ret.validation[fieldId] = res;
return cb(undefined, ret);
});
}
return createValidatorResponse(fieldId, messages, function (err, res) {
if (err) return cb(err);
var ret = {validation: {}};
ret.validation[fieldId] = res;
return cb(undefined, ret);
});
}
}
function createValidatorResponse(fieldId, messages, cb) {
// intentionally not checking err here, used further down to get validation errors
var res = {};
res.fieldId = fieldId;
res.errorMessages = messages.errorMessages || [];
res.fieldErrorMessage = messages.fieldErrorMessage || [];
async.some(res.errorMessages, function (item, cb) {
return cb(item !== null);
}, function (someErrors) {
res.valid = !someErrors && (res.fieldErrorMessage.length < 1);
function createValidatorResponse(fieldId, messages, cb) {
// intentionally not checking err here, used further down to get validation errors
var res = {};
res.fieldId = fieldId;
res.errorMessages = messages.errorMessages || [];
res.fieldErrorMessage = messages.fieldErrorMessage || [];
async.some(res.errorMessages, function (item, cb) {
return cb(item !== null);
}, function (someErrors) {
res.valid = !someErrors && (res.fieldErrorMessage.length < 1);
return cb(undefined, res);
});
}
return cb(undefined, res);
});
}
function getFieldValidationStatus(submittedField, fieldDef, previousFieldValues, cb) {
validateFieldInternal(submittedField, fieldDef, previousFieldValues, function (err, messages) {
if(err) return cb(err);
createValidatorResponse(submittedField.fieldId, messages, cb);
});
}
function getMapFunction(key, map, cb) {
var validator = map[key];
if (!validator) {
return cb(new Error("Invalid Field Type " + key));
function getFieldValidationStatus(submittedField, fieldDef, previousFieldValues, cb) {
validateFieldInternal(submittedField, fieldDef, previousFieldValues, function (err, messages) {
if (err) return cb(err);
createValidatorResponse(submittedField.fieldId, messages, cb);
});
}
return cb(undefined, validator);
}
function getMapFunction(key, map, cb) {
var validator = map[key];
if (!validator) {
return cb(new Error("Invalid Field Type " + key));
}
function getValidatorFunction(fieldType, cb) {
return getMapFunction(fieldType, validatorsMap, cb);
}
return cb(undefined, validator);
}
function getClientValidatorFunction(fieldType, cb) {
return getMapFunction(fieldType, validatorsClientMap, cb);
}
function getValidatorFunction(fieldType, cb) {
return getMapFunction(fieldType, validatorsMap, cb);
}
function fieldEmpty(fieldValue) {
return ('undefined' === typeof fieldValue || null === fieldValue || "" === fieldValue); // empty string also regarded as not specified
}
function getClientValidatorFunction(fieldType, cb) {
return getMapFunction(fieldType, validatorsClientMap, cb);
}
function validateFieldInternal(submittedField, fieldDef, previousFieldValues, cb) {
if ("function" === typeof previousFieldValues) {
cb = previousFieldValues;
previousFieldValues = null;
function fieldEmpty(fieldValue) {
return ('undefined' === typeof fieldValue || null === fieldValue || "" === fieldValue); // empty string also regarded as not specified
}
countSubmittedValues(submittedField, function(err, numSubmittedValues) {
if(err) return cb(err);
async.series({
valuesSubmitted:
async.apply(checkValueSubmitted, submittedField, fieldDef),
repeats:
async.apply(checkRepeat, numSubmittedValues, fieldDef),
values:
async.apply(checkValues, submittedField, fieldDef, previousFieldValues)
}, function (err, results) {
if(err) return cb(err);
function validateFieldInternal(submittedField, fieldDef, previousFieldValues, cb) {
if ("function" === typeof previousFieldValues) {
cb = previousFieldValues;
previousFieldValues = null;
}
var fieldErrorMessages = [];
if(results.valuesSubmitted) {
fieldErrorMessages.push(results.valuesSubmitted);
}
if(results.repeats) {
fieldErrorMessages.push(results.repeats);
}
return cb(undefined, {fieldErrorMessage: fieldErrorMessages, errorMessages: results.values});
countSubmittedValues(submittedField, function (err, numSubmittedValues) {
if (err) return cb(err);
async.series({
valuesSubmitted: async.apply(checkValueSubmitted, submittedField, fieldDef),
repeats: async.apply(checkRepeat, numSubmittedValues, fieldDef),
values: async.apply(checkValues, submittedField, fieldDef, previousFieldValues)
}, function (err, results) {
if (err) return cb(err);
var fieldErrorMessages = [];
if (results.valuesSubmitted) {
fieldErrorMessages.push(results.valuesSubmitted);
}
if (results.repeats) {
fieldErrorMessages.push(results.repeats);
}
return cb(undefined, {
fieldErrorMessage: fieldErrorMessages,
errorMessages: results.values
});
});
});
});
return; // just functions below this
return; // just functions below this
function checkValueSubmitted(submittedField, fieldDefinition, cb) {
if(! fieldDefinition.required) return cb(undefined, null);
var valueSubmitted = submittedField && submittedField.fieldValues && (submittedField.fieldValues.length > 0);
if (!valueSubmitted) {
return cb(undefined, "No value submitted for field " + fieldDefinition.name);
function checkValueSubmitted(submittedField, fieldDefinition, cb) {
if (!fieldDefinition.required) return cb(undefined, null);
var valueSubmitted = submittedField && submittedField.fieldValues && (submittedField.fieldValues.length > 0);
if (!valueSubmitted) {
return cb(undefined, "No value submitted for field " + fieldDefinition.name);
}
return cb(undefined, null);
}
return cb(undefined, null);
}
function countSubmittedValues(submittedField, cb) {
var numSubmittedValues = 0;
if(submittedField && submittedField.fieldValues && submittedField.fieldValues.length > 0) {
for(var i=0; i<submittedField.fieldValues.length; i += 1) {
if(submittedField.fieldValues[i]) {
numSubmittedValues += 1;
function countSubmittedValues(submittedField, cb) {
var numSubmittedValues = 0;
if (submittedField && submittedField.fieldValues && submittedField.fieldValues.length > 0) {
for (var i = 0; i < submittedField.fieldValues.length; i += 1) {
if (submittedField.fieldValues[i]) {
numSubmittedValues += 1;
}
}
}
return cb(undefined, numSubmittedValues);
}
return cb(undefined, numSubmittedValues);
}
function checkRepeat(numSubmittedValues, fieldDefinition, cb) {
function checkRepeat(numSubmittedValues, fieldDefinition, cb) {
if(fieldDefinition.repeating && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.definition){
if(fieldDefinition.fieldOptions.definition.minRepeat){
if(numSubmittedValues < fieldDefinition.fieldOptions.definition.minRepeat){
return cb(undefined, "Expected min of " + fieldDefinition.fieldOptions.definition.minRepeat + " values for field " + fieldDefinition.name + " but got " + numSubmittedValues);
if (fieldDefinition.repeating && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.definition) {
if (fieldDefinition.fieldOptions.definition.minRepeat) {
if (numSubmittedValues < fieldDefinition.fieldOptions.definition.minRepeat) {
return cb(undefined, "Expected min of " + fieldDefinition.fieldOptions.definition.minRepeat + " values for field " + fieldDefinition.name + " but got " + numSubmittedValues);
}
}
}
if (fieldDefinition.fieldOptions.definition.maxRepeat){
if(numSubmittedValues > fieldDefinition.fieldOptions.definition.maxRepeat){
return cb(undefined, "Expected max of " + fieldDefinition.fieldOptions.definition.maxRepeat + " values for field " + fieldDefinition.name + " but got " + numSubmittedValues);
if (fieldDefinition.fieldOptions.definition.maxRepeat) {
if (numSubmittedValues > fieldDefinition.fieldOptions.definition.maxRepeat) {
return cb(undefined, "Expected max of " + fieldDefinition.fieldOptions.definition.maxRepeat + " values for field " + fieldDefinition.name + " but got " + numSubmittedValues);
}
}
} else {
if (numSubmittedValues > 1) {
return cb(undefined, "Should not have multiple values for non-repeating field");
}
}
} else {
if(numSubmittedValues > 1) {
return cb(undefined, "Should not have multiple values for non-repeating field");
}
return cb(undefined, null);
}
return cb(undefined, null);
}
function checkValues(submittedField, fieldDefinition, previousFieldValues, cb) {
getValidatorFunction(fieldDefinition.type, function (err, validator) {
if (err) return cb(err);
async.map(submittedField.fieldValues, function (fieldValue, cb) {
if (fieldEmpty(fieldValue)) {
return cb(undefined, null);
} else {
validator(fieldValue, fieldDefinition, previousFieldValues, function (validationError) {
var errorMessage;
if (validationError) {
errorMessage = validationError.message || "Error during validation of field";
} else {
errorMessage = null;
}
function checkValues(submittedField, fieldDefinition, previousFieldValues, cb) {
getValidatorFunction(fieldDefinition.type, function (err, validator) {
if (err) return cb(err);
async.map(submittedField.fieldValues, function(fieldValue, cb){
if(fieldEmpty(fieldValue)) {
return cb(undefined, null);
} else {
validator(fieldValue, fieldDefinition, previousFieldValues, function(validationError) {
var errorMessage;
if(validationError) {
errorMessage = validationError.message || "Error during validation of field";
} else {
errorMessage = null;
}
if (submissionRequiredFieldsMap[fieldDefinition._id]) { // set to true if at least one value
submissionRequiredFieldsMap[fieldDefinition._id].submitted = true;
}
if (submissionRequiredFieldsMap[fieldDefinition._id]) { // set to true if at least one value
submissionRequiredFieldsMap[fieldDefinition._id].submitted = true;
}
return cb(undefined, errorMessage);
});
}
}, function (err, results) {
if (err) return cb(err);
return cb(undefined, errorMessage);
});
}
}, function (err, results) {
if (err) return cb(err);
return cb(undefined, results);
});
});
}
return cb(undefined, results);
});
});
}
}
function convertSimpleFormatToRegex(field_format_string) {
var regex = "^";
var C = "c".charCodeAt(0);
var N = "n".charCodeAt(0);
function convertSimpleFormatToRegex(field_format_string) {
var regex = "^";
var C = "c".charCodeAt(0);
var N = "n".charCodeAt(0);
var i;
var ch;
var match;
var len = field_format_string.length;
for (i = 0; i < len; i += 1) {
ch = field_format_string.charCodeAt(i);
switch (ch) {
case C:
match = "[a-zA-Z0-9]";
break;
case N:
match = "[0-9]";
break;
default:
var num = ch.toString(16).toUpperCase();
match = "\\u" + ("0000" + num).substr(-4);
break;
var i;
var ch;
var match;
var len = field_format_string.length;
for (i = 0; i < len; i += 1) {
ch = field_format_string.charCodeAt(i);
switch (ch) {
case C:
match = "[a-zA-Z0-9]";
break;
case N:
match = "[0-9]";
break;
default:
var num = ch.toString(16).toUpperCase();
match = "\\u" + ("0000" + num).substr(-4);
break;
}
regex += match;
}
regex += match;
return regex + "$";
}
return regex + "$";
}
function validFormatRegex(fieldValue, field_format_string) {
var pattern = new RegExp(field_format_string);
return pattern.test(fieldValue);
}
function validFormat(fieldValue, field_format_mode, field_format_string) {
var regex;
if ("simple" === field_format_mode) {
regex = convertSimpleFormatToRegex(field_format_string);
} else if ("regex" === field_format_mode) {
regex = field_format_string;
} else { // should never be anything else, but if it is then default to simple format
regex = convertSimpleFormatToRegex(field_format_string);
function validFormatRegex(fieldValue, field_format_string) {
var pattern = new RegExp(field_format_string);
return pattern.test(fieldValue);
}
return validFormatRegex(fieldValue, regex);
}
function validFormat(fieldValue, field_format_mode, field_format_string) {
var regex;
if ("simple" === field_format_mode) {
regex = convertSimpleFormatToRegex(field_format_string);
} else if ("regex" === field_format_mode) {
regex = field_format_string;
} else { // should never be anything else, but if it is then default to simple format
regex = convertSimpleFormatToRegex(field_format_string);
}
function validatorString (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof fieldValue !== "string"){
return cb(new Error("Expected string but got " + typeof(fieldValue)));
return validFormatRegex(fieldValue, regex);
}
var validation = {};
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
validation = fieldDefinition.fieldOptions.validation;
}
function validatorString(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof fieldValue !== "string") {
return cb(new Error("Expected string but got " + typeof(fieldValue)));
}
var field_format_mode = validation.field_format_mode || "";
field_format_mode = field_format_mode.trim();
var field_format_string = validation.field_format_string || "";
field_format_string = field_format_string.trim();
var validation = {};
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
validation = fieldDefinition.fieldOptions.validation;
}
if (field_format_string && (field_format_string.length > 0) && field_format_mode && (field_format_mode.length > 0)) {
if(!validFormat(fieldValue, field_format_mode, field_format_string)) {
return cb(new Error("field value in incorrect format, expected format: " + field_format_string + " but submission value is: " + fieldValue));
var field_format_mode = validation.field_format_mode || "";
field_format_mode = field_format_mode.trim();
var field_format_string = validation.field_format_string || "";
field_format_string = field_format_string.trim();
if (field_format_string && (field_format_string.length > 0) && field_format_mode && (field_format_mode.length > 0)) {
if (!validFormat(fieldValue, field_format_mode, field_format_string)) {
return cb(new Error("field value in incorrect format, expected format: " + field_format_string + " but submission value is: " + fieldValue));
}
}
}
if(fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.min){
if(fieldValue.length < fieldDefinition.fieldOptions.validation.min){
return cb(new Error("Expected minimum string length of " + fieldDefinition.fieldOptions.validation.min + " but submission is " + fieldValue.length + ". Submitted val: " + fieldValue));
if (fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.min) {
if (fieldValue.length < fieldDefinition.fieldOptions.validation.min) {
return cb(new Error("Expected minimum string length of " + fieldDefinition.fieldOptions.validation.min + " but submission is " + fieldValue.length + ". Submitted val: " + fieldValue));
}
}
}
if(fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.max){
if(fieldValue.length > fieldDefinition.fieldOptions.validation.max){
return cb(new Error("Expected maximum string length of " + fieldDefinition.fieldOptions.validation.max + " but submission is " + fieldValue.length + ". Submitted val: " + fieldValue));
if (fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.max) {
if (fieldValue.length > fieldDefinition.fieldOptions.validation.max) {
return cb(new Error("Expected maximum string length of " + fieldDefinition.fieldOptions.validation.max + " but submission is " + fieldValue.length + ". Submitted val: " + fieldValue));
}
}
}
return cb();
}
function validatorNumericString (fieldValue, fieldDefinition, previousFieldValues, cb) {
var testVal = (fieldValue - 0); // coerce to number (or NaN)
var numeric = (testVal == fieldValue); // testVal co-erced to numeric above, so numeric comparison and NaN != NaN
if(!numeric) {
return cb(new Error("Expected numeric but got: " + fieldValue));
return cb();
}
return validatorNumber(testVal, fieldDefinition, previousFieldValues, cb);
}
function validatorNumericString(fieldValue, fieldDefinition, previousFieldValues, cb) {
var testVal = (fieldValue - 0); // coerce to number (or NaN)
var numeric = (testVal == fieldValue); // testVal co-erced to numeric above, so numeric comparison and NaN != NaN
if (!numeric) {
return cb(new Error("Expected numeric but got: " + fieldValue));
}
function validatorNumber (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof fieldValue !== "number"){
return cb(new Error("Expected number but got " + typeof(fieldValue)));
return validatorNumber(testVal, fieldDefinition, previousFieldValues, cb);
}
if(fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.min){
if(fieldValue < fieldDefinition.fieldOptions.validation.min){
return cb(new Error("Expected minimum Number " + fieldDefinition.fieldOptions.validation.min + " but submission is " + fieldValue + ". Submitted number: " + fieldValue));
function validatorNumber(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof fieldValue !== "number") {
return cb(new Error("Expected number but got " + typeof(fieldValue)));
}
}
if (fieldDefinition.fieldOptions.validation.max){
if(fieldValue > fieldDefinition.fieldOptions.validation.max){
return cb(new Error("Expected maximum Number " + fieldDefinition.fieldOptions.validation.max + " but submission is " + fieldValue + ". Submitted number: " + fieldValue));
if (fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation && fieldDefinition.fieldOptions.validation.min) {
if (fieldValue < fieldDefinition.fieldOptions.validation.min) {
return cb(new Error("Expected minimum Number " + fieldDefinition.fieldOptions.validation.min + " but submission is " + fieldValue + ". Submitted number: " + fieldValue));
}
}
}
return cb();
}
if (fieldDefinition.fieldOptions.validation.max) {
if (fieldValue > fieldDefinition.fieldOptions.validation.max) {
return cb(new Error("Expected maximum Number " + fieldDefinition.fieldOptions.validation.max + " but submission is " + fieldValue + ". Submitted number: " + fieldValue));
}
}
function validatorEmail (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof(fieldValue) !== "string"){
return cb(new Error("Expected string but got " + typeof(fieldValue)));
}
if(fieldValue.match(/[-0-9a-zA-Z.+_]+@[-0-9a-zA-Z.+_]+\.[a-zA-Z]{2,4}/g) === null){
return cb(new Error("Invalid email address format: " + fieldValue));
} else {
return cb();
}
}
function validatorDropDown (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof(fieldValue) !== "string"){
return cb(new Error("Expected submission to be string but got " + typeof(fieldValue)));
}
function validatorEmail(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof(fieldValue) !== "string") {
return cb(new Error("Expected string but got " + typeof(fieldValue)));
}
//Check value exists in the field definition
if(!fieldDefinition.fieldOptions.definition.options){
return cb(new Error("No options exist for field " + fieldDefinition.name));
}
async.some(fieldDefinition.fieldOptions.definition.options, function (dropdownOption, cb) {
return cb(dropdownOption.label === fieldValue);
}, function (found) {
if (!found) {
return cb(new Error("Invalid option specified: " + fieldValue));
if (fieldValue.match(/[-0-9a-zA-Z.+_]+@[-0-9a-zA-Z.+_]+\.[a-zA-Z]{2,4}/g) === null) {
return cb(new Error("Invalid email address format: " + fieldValue));
} else {
return cb();
}
});
}
function validatorCheckboxes (fieldValue, fieldDefinition, previousFieldValues, cb) {
var minVal;
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
minVal = fieldDefinition.fieldOptions.validation.min;
}
var maxVal;
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
maxVal = fieldDefinition.fieldOptions.validation.max;
}
if (minVal) {
if(fieldValue.selections === null || fieldValue.selections === undefined || fieldValue.selections.length < minVal){
var len;
if(fieldValue.selections) {
len = fieldValue.selections.length;
}
return cb(new Error("Expected a minimum number of selections " + minVal + " but got " + len));
function validatorDropDown(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof(fieldValue) !== "string") {
return cb(new Error("Expected submission to be string but got " + typeof(fieldValue)));
}
}
if(maxVal){
if(fieldValue.selections){
if(fieldValue.selections.length > maxVal){
return cb(new Error("Expected a maximum number of selections " + maxVal + " but got " + fieldValue.selections.length));
//Check value exists in the field definition
if (!fieldDefinition.fieldOptions.definition.options) {
return cb(new Error("No options exist for field " + fieldDefinition.name));
}
async.some(fieldDefinition.fieldOptions.definition.options, function (dropdownOption, cb) {
return cb(dropdownOption.label === fieldValue);
}, function (found) {
if (!found) {
return cb(new Error("Invalid option specified: " + fieldValue));
} else {
return cb();
}
}
});
}
var optionsInCheckbox = [];
function validatorCheckboxes(fieldValue, fieldDefinition, previousFieldValues, cb) {
var minVal;
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
minVal = fieldDefinition.fieldOptions.validation.min;
}
var maxVal;
if (fieldDefinition && fieldDefinition.fieldOptions && fieldDefinition.fieldOptions.validation) {
maxVal = fieldDefinition.fieldOptions.validation.max;
}
async.eachSeries(fieldDefinition.fieldOptions.definition.options, function(choice, cb){
for(var choiceName in choice){
optionsInCheckbox.push(choice[choiceName]);
if (minVal) {
if (fieldValue.selections === null || fieldValue.selections === undefined || fieldValue.selections.length < minVal) {
var len;
if (fieldValue.selections) {
len = fieldValue.selections.length;
}
return cb(new Error("Expected a minimum number of selections " + minVal + " but got " + len));
}
}
return cb();
}, function(err){
async.eachSeries(fieldValue.selections, function(selection, cb){
if(typeof(selection) !== "string"){
return cb(new Error("Expected checkbox submission to be string but got " + typeof(selection)));
if (maxVal) {
if (fieldValue.selections) {
if (fieldValue.selections.length > maxVal) {
return cb(new Error("Expected a maximum number of selections " + maxVal + " but got " + fieldValue.selections.length));
}
}
}
if(optionsInCheckbox.indexOf(selection) === -1){
return cb(new Error("Checkbox Option " + selection + " does not exist in the field."));
var optionsInCheckbox = [];
async.eachSeries(fieldDefinition.fieldOptions.definition.options, function (choice, cb) {
for (var choiceName in choice) {
optionsInCheckbox.push(choice[choiceName]);
}
return cb();
}, cb);
});
}
}, function (err) {
async.eachSeries(fieldValue.selections, function (selection, cb) {
if (typeof(selection) !== "string") {
return cb(new Error("Expected checkbox submission to be string but got " + typeof(selection)));
}
function validatorLocationMap (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(fieldValue.lat && fieldValue["long"]) {
if(isNaN(parseFloat(fieldValue.lat)) || isNaN(parseFloat(fieldValue["long"]))) {
return cb(new Error("Invalid latitude and longitude values"));
} else {
return cb();
}
} else {
return cb(new Error("Invalid object for locationMap submission"));
if (optionsInCheckbox.indexOf(selection) === -1) {
return cb(new Error("Checkbox Option " + selection + " does not exist in the field."));
}
return cb();
}, cb);
});
}
}
function validatorLocation (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(fieldDefinition.fieldOptions.definition.locationUnit === "latlong") {
if(fieldValue.lat && fieldValue["long"]){
if(isNaN(parseFloat(fieldValue.lat)) || isNaN(parseFloat(fieldValue["long"]))){
function validatorLocationMap(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (fieldValue.lat && fieldValue["long"]) {
if (isNaN(parseFloat(fieldValue.lat)) || isNaN(parseFloat(fieldValue["long"]))) {
return cb(new Error("Invalid latitude and longitude values"));

@@ -795,529 +800,593 @@ } else {

} else {
return cb(new Error("Invalid object for latitude longitude submission"));
return cb(new Error("Invalid object for locationMap submission"));
}
} else {
if(fieldValue.zone && fieldValue.eastings && fieldValue.northings){
//Zone must be 3 characters, eastings 6 and northings 9
return validateNorthingsEastings(fieldValue, cb);
} else {
return cb(new Error("Invalid object for northings easting submission. Zone, Eastings and Northings elemets are required"));
}
}
function validateNorthingsEastings(fieldValue, cb){
if(typeof(fieldValue.zone) !== "string" || fieldValue.zone.length === 0){
return cb(new Error("Invalid zone definition for northings and eastings location. " + fieldValue.zone));
}
var east = parseInt(fieldValue.eastings,10);
if(isNaN(east)){
return cb(new Error("Invalid eastings definition for northings and eastings location. " + fieldValue.eastings));
function validatorLocation(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (fieldDefinition.fieldOptions.definition.locationUnit === "latlong") {
if (fieldValue.lat && fieldValue["long"]) {
if (isNaN(parseFloat(fieldValue.lat)) || isNaN(parseFloat(fieldValue["long"]))) {
return cb(new Error("Invalid latitude and longitude values"));
} else {
return cb();
}
} else {
return cb(new Error("Invalid object for latitude longitude submission"));
}
} else {
if (fieldValue.zone && fieldValue.eastings && fieldValue.northings) {
//Zone must be 3 characters, eastings 6 and northings 9
return validateNorthingsEastings(fieldValue, cb);
} else {
return cb(new Error("Invalid object for northings easting submission. Zone, Eastings and Northings elemets are required"));
}
}
var north = parseInt(fieldValue.northings, 10);
if(isNaN(north)){
return cb(new Error("Invalid northings definition for northings and eastings location. " + fieldValue.northings));
}
function validateNorthingsEastings(fieldValue, cb) {
if (typeof(fieldValue.zone) !== "string" || fieldValue.zone.length === 0) {
return cb(new Error("Invalid zone definition for northings and eastings location. " + fieldValue.zone));
}
return cb();
}
}
var east = parseInt(fieldValue.eastings, 10);
if (isNaN(east)) {
return cb(new Error("Invalid eastings definition for northings and eastings location. " + fieldValue.eastings));
}
function validatorAnyFile(fieldValue, fieldDefinition, previousFieldValues, cb) {
// if any of the following validators return ok, then return ok.
validatorBase64(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if(!err) {
var north = parseInt(fieldValue.northings, 10);
if (isNaN(north)) {
return cb(new Error("Invalid northings definition for northings and eastings location. " + fieldValue.northings));
}
return cb();
}
validatorFile(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if(!err) {
}
function validatorAnyFile(fieldValue, fieldDefinition, previousFieldValues, cb) {
// if any of the following validators return ok, then return ok.
validatorBase64(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if (!err) {
return cb();
}
validatorFileObj(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if(!err) {
validatorFile(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if (!err) {
return cb();
}
return cb(err);
validatorFileObj(fieldValue, fieldDefinition, previousFieldValues, function (err) {
if (!err) {
return cb();
}
return cb(err);
});
});
});
});
}
function validatorFile (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof fieldValue !== "object"){
return cb(new Error("Expected object but got " + typeof(fieldValue)));
}
var keyTypes = [
{ keyName: "fileName", valueType: "string" },
{ keyName: "fileSize", valueType: "number" },
{ keyName: "fileType", valueType: "string" },
{ keyName: "fileUpdateTime", valueType: "number" },
{ keyName: "hashName", valueType: "string" }
];
function checkFileSize(fieldDefinition, fieldValue, sizeKey, cb) {
fieldDefinition = fieldDefinition || {};
var fieldOptions = fieldDefinition.fieldOptions || {};
var fieldOptionsDef = fieldOptions.definition || {};
var fileSizeMax = fieldOptionsDef.file_size || null; //FileSizeMax will be in KB. File size is in bytes
async.each(keyTypes, function (keyType, cb) {
var actualType = typeof fieldValue[keyType.keyName];
if (actualType !== keyType.valueType) {
return cb(new Error("Expected " + keyType.valueType + " but got " + actualType));
if (fileSizeMax !== null) {
var fieldValueSize = fieldValue[sizeKey];
var fieldValueSizeKB = 1;
if (fieldValueSize > 1000) {
fieldValueSizeKB = fieldValueSize / 1000;
}
console.log("Comparing File Size: ", fileSizeMax, fieldValueSize);
if (fieldValueSize > (fileSizeMax * 1000)) {
return cb(new Error("File size is too large. File can be a maximum of " + fileSizeMax + "KB. Size of file selected: " + fieldValueSizeKB + "KB"));
} else {
return cb();
}
} else {
return cb();
}
if (keyType.keyName === "fileName" && fieldValue[keyType.keyName].length <=0) {
return cb(new Error("Expected value for " + keyType.keyName));
}
function validatorFile(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof fieldValue !== "object") {
return cb(new Error("Expected object but got " + typeof(fieldValue)));
}
return cb();
}, function (err) {
if (err) return cb(err);
var keyTypes = [
{
keyName: "fileName",
valueType: "string"
},
{
keyName: "fileSize",
valueType: "number"
},
{
keyName: "fileType",
valueType: "string"
},
{
keyName: "fileUpdateTime",
valueType: "number"
},
{
keyName: "hashName",
valueType: "string"
}
];
if(fieldValue.hashName.indexOf("filePlaceHolder") > -1){ //TODO abstract out to config
async.each(keyTypes, function (keyType, cb) {
var actualType = typeof fieldValue[keyType.keyName];
if (actualType !== keyType.valueType) {
return cb(new Error("Expected " + keyType.valueType + " but got " + actualType));
}
if (keyType.keyName === "fileName" && fieldValue[keyType.keyName].length <= 0) {
return cb(new Error("Expected value for " + keyType.keyName));
}
return cb();
} else if (previousFieldValues && previousFieldValues.hashName && previousFieldValues.hashName.indexOf(fieldValue.hashName) > -1){
return cb();
} else {
return cb(new Error("Invalid file placeholder text" + fieldValue.hashName));
}
}, function (err) {
if (err) return cb(err);
});
}
checkFileSize(fieldDefinition, fieldValue, "fileSize", function (err) {
if (err) {
return cb(err);
}
function validatorFileObj (fieldValue, fieldDefinition, previousFieldValues, cb) {
if((typeof File !== "function") || !(fieldValue instanceof File)) {
return cb(new Error("Expected File object but got " + typeof(fieldValue)));
if (fieldValue.hashName.indexOf("filePlaceHolder") > -1) { //TODO abstract out to config
return cb();
} else if (previousFieldValues && previousFieldValues.hashName && previousFieldValues.hashName.indexOf(fieldValue.hashName) > -1) {
return cb();
} else {
return cb(new Error("Invalid file placeholder text" + fieldValue.hashName));
}
});
});
}
var keyTypes = [
{ keyName: "name", valueType: "string" },
{ keyName: "size", valueType: "number" }
];
async.each(keyTypes, function (keyType, cb) {
var actualType = typeof fieldValue[keyType.keyName];
if (actualType !== keyType.valueType) {
return cb(new Error("Expected " + keyType.valueType + " but got " + actualType));
function validatorFileObj(fieldValue, fieldDefinition, previousFieldValues, cb) {
if ((typeof File !== "function") || !(fieldValue instanceof File)) {
return cb(new Error("Expected File object but got " + typeof(fieldValue)));
}
if (actualType === "string" && fieldValue[keyType.keyName].length <=0) {
return cb(new Error("Expected value for " + keyType.keyName));
}
if (actualType === "number" && fieldValue[keyType.keyName] <=0) {
return cb(new Error("Expected > 0 value for " + keyType.keyName));
}
return cb();
}, function (err) {
if (err) return cb(err);
return cb();
});
var keyTypes = [
{
keyName: "name",
valueType: "string"
},
{
keyName: "size",
valueType: "number"
}
];
}
async.each(keyTypes, function (keyType, cb) {
var actualType = typeof fieldValue[keyType.keyName];
if (actualType !== keyType.valueType) {
return cb(new Error("Expected " + keyType.valueType + " but got " + actualType));
}
if (actualType === "string" && fieldValue[keyType.keyName].length <= 0) {
return cb(new Error("Expected value for " + keyType.keyName));
}
if (actualType === "number" && fieldValue[keyType.keyName] <= 0) {
return cb(new Error("Expected > 0 value for " + keyType.keyName));
}
function validatorBase64 (fieldValue, fieldDefinition, previousFieldValues, cb) {
if(typeof fieldValue !== "string"){
return cb(new Error("Expected base64 string but got " + typeof(fieldValue)));
}
return cb();
}, function (err) {
if (err) return cb(err);
if(fieldValue.length <= 0){
return cb(new Error("Expected base64 string but was empty"));
checkFileSize(fieldDefinition, fieldValue, "size", function (err) {
if (err) {
return cb(err);
}
return cb();
});
});
}
return cb();
}
function validatorBase64(fieldValue, fieldDefinition, previousFieldValues, cb) {
if (typeof fieldValue !== "string") {
return cb(new Error("Expected base64 string but got " + typeof(fieldValue)));
}
function validatorDateTime (fieldValue, fieldDefinition, previousFieldValues, cb) {
var testDate;
if (fieldValue.length <= 0) {
return cb(new Error("Expected base64 string but was empty"));
}
if(typeof(fieldValue) !== "string"){
return cb(new Error("Expected string but got " + typeof(fieldValue)));
return cb();
}
switch (fieldDefinition.fieldOptions.definition.datetimeUnit)
{
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try{
testDate = new Date(fieldValue);
valid = (testDate.toString() !== "Invalid Date");
}catch(e){
valid = false;
}
if (valid) {
return cb();
} else {
return cb(new Error("Invalid date value " + fieldValue));
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
var parts = fieldValue.split(':');
valid = (parts.length === 2) || (parts.length === 3);
if (valid) {
valid = isNumberBetween(parts[0], 0, 23);
}
if (valid) {
valid = isNumberBetween(parts[1], 0, 59);
}
if (valid && (parts.length === 3)) {
valid = isNumberBetween(parts[2], 0, 59);
}
if (valid) {
return cb();
} else {
return cb(new Error("Invalid date value " + fieldValue));
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try{
testDate = new Date(fieldValue);
function validatorDateTime(fieldValue, fieldDefinition, previousFieldValues, cb) {
var testDate;
if(testDate.toString() === "Invalid Date"){
return cb(new Error("Invalid dateTime string " + fieldValue));
if (typeof(fieldValue) !== "string") {
return cb(new Error("Expected string but got " + typeof(fieldValue)));
}
switch (fieldDefinition.fieldOptions.definition.datetimeUnit) {
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try {
testDate = new Date(fieldValue);
valid = (testDate.toString() !== "Invalid Date");
} catch (e) {
valid = false;
}
if (valid) {
return cb();
} else {
return cb(new Error("Invalid date value " + fieldValue));
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
var parts = fieldValue.split(':');
valid = (parts.length === 2) || (parts.length === 3);
if (valid) {
valid = isNumberBetween(parts[0], 0, 23);
}
if (valid) {
valid = isNumberBetween(parts[1], 0, 59);
}
if (valid && (parts.length === 3)) {
valid = isNumberBetween(parts[2], 0, 59);
}
if (valid) {
return cb();
} else {
return cb(new Error("Invalid date value " + fieldValue));
}
}catch(e){
return cb(new Error("Invalid dateTime string " + fieldValue));
}
break;
default:
return cb(new Error("Invalid dateTime fieldtype " + fieldDefinition.fieldOptions.definition.datetimeUnit));
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try {
testDate = new Date(fieldValue);
if (testDate.toString() === "Invalid Date") {
return cb(new Error("Invalid dateTime string " + fieldValue));
} else {
return cb();
}
} catch (e) {
return cb(new Error("Invalid dateTime string " + fieldValue));
}
break;
default:
return cb(new Error("Invalid dateTime fieldtype " + fieldDefinition.fieldOptions.definition.datetimeUnit));
}
}
}
function validatorSection (value, fieldDefinition, previousFieldValues, cb) {
return cb(new Error("Should not submit section field: " + fieldDefinition.name));
}
function validatorSection(value, fieldDefinition, previousFieldValues, cb) {
return cb(new Error("Should not submit section field: " + fieldDefinition.name));
}
function rulesResult(rules, cb) {
var visible = true;
function rulesResult(rules, cb) {
var visible = true;
// Itterate over each rule that this field is a predicate of
async.each(rules, function(rule, cbRule) {
// For each rule, itterate over the predicate fields and evaluate the rule
var predicateMapQueries = [];
var predicateMapPassed = [];
async.each(rule.ruleConditionalStatements, function(ruleConditionalStatement, cbPredicates) {
var field = fieldMap[ruleConditionalStatement.sourceField];
var passed = false;
var submissionValues = [];
var condition;
var testValue;
if (submissionFieldsMap[ruleConditionalStatement.sourceField] && submissionFieldsMap[ruleConditionalStatement.sourceField].fieldValues) {
submissionValues = submissionFieldsMap[ruleConditionalStatement.sourceField].fieldValues;
condition = ruleConditionalStatement.restriction;
testValue = ruleConditionalStatement.sourceValue;
// Itterate over each rule that this field is a predicate of
async.each(rules, function (rule, cbRule) {
// For each rule, itterate over the predicate fields and evaluate the rule
var predicateMapQueries = [];
var predicateMapPassed = [];
async.each(rule.ruleConditionalStatements, function (ruleConditionalStatement, cbPredicates) {
var field = fieldMap[ruleConditionalStatement.sourceField];
var passed = false;
var submissionValues = [];
var condition;
var testValue;
if (submissionFieldsMap[ruleConditionalStatement.sourceField] && submissionFieldsMap[ruleConditionalStatement.sourceField].fieldValues) {
submissionValues = submissionFieldsMap[ruleConditionalStatement.sourceField].fieldValues;
condition = ruleConditionalStatement.restriction;
testValue = ruleConditionalStatement.sourceValue;
// Validate rule predictes on the first entry only.
passed = isConditionActive(field, submissionValues[0], testValue, condition);
}
predicateMapQueries.push({"field": field,
"submissionValues": submissionValues,
"condition": condition,
"testValue": testValue,
"passed" : passed
});
// Validate rule predictes on the first entry only.
passed = isConditionActive(field, submissionValues[0], testValue, condition);
}
predicateMapQueries.push({
"field": field,
"submissionValues": submissionValues,
"condition": condition,
"testValue": testValue,
"passed": passed
});
if( passed ) {
predicateMapPassed.push(field);
}
return cbPredicates();
}, function(err) {
if(err) cbRule(err);
if (passed) {
predicateMapPassed.push(field);
}
return cbPredicates();
}, function (err) {
if (err) cbRule(err);
function rulesPassed (condition, passed, queries) {
return ( (condition === "and" ) && (( passed.length == queries.length ))) || // "and" condition - all rules must pass
( (condition === "or" ) && (( passed.length > 0 ))); // "or" condition - only one rule must pass
}
function rulesPassed(condition, passed, queries) {
return ((condition === "and") && ((passed.length == queries.length))) || // "and" condition - all rules must pass
((condition === "or") && ((passed.length > 0))); // "or" condition - only one rule must pass
}
if (rulesPassed(rule.ruleConditionalOperator, predicateMapPassed, predicateMapQueries)) {
visible = (rule.type === "show");
if (rulesPassed(rule.ruleConditionalOperator, predicateMapPassed, predicateMapQueries)) {
visible = (rule.type === "show");
} else {
visible = (rule.type !== "show");
}
return cbRule();
});
}, function (err) {
if (err) return cb(err);
return cb(undefined, visible);
});
}
function isPageVisible(pageId, cb) {
init(function (err) {
if (err) return cb(err);
if (isPageRuleSubject(pageId)) { // if the page is the target of a rule
return rulesResult(pageRuleSubjectMap[pageId], cb); // execute page rules
} else {
visible = (rule.type !== "show");
return cb(undefined, true); // if page is not subject of any rule then must be visible
}
return cbRule();
});
}, function(err) {
if (err) return cb(err);
}
return cb(undefined, visible);
});
}
function isFieldVisible(fieldId, checkContainingPage, cb) {
/*
* fieldId = Id of field to check for reule predeciate references
* checkContainingPage = if true check page containing field, and return false if the page is hidden
*/
init(function (err) {
if (err) return cb(err);
function isPageVisible(pageId, cb) {
init(function(err){
if (err) return cb(err);
// Fields are visable by default
var visible = true;
if (isPageRuleSubject(pageId)) { // if the page is the target of a rule
return rulesResult(pageRuleSubjectMap[pageId], cb); // execute page rules
} else {
return cb(undefined, true); // if page is not subject of any rule then must be visible
}
});
}
var field = fieldMap[fieldId];
if (!fieldId) return cb(new Error("Field does not exist in form"));
function isFieldVisible(fieldId, checkContainingPage, cb) {
/*
* fieldId = Id of field to check for reule predeciate references
* checkContainingPage = if true check page containing field, and return false if the page is hidden
*/
init(function(err){
if (err) return cb(err);
async.waterfall([
// Fields are visable by default
var visible = true;
function testPage(cb) {
if (checkContainingPage) {
isPageVisible(field.pageId, cb);
} else {
return cb(undefined, true);
}
},
function testField(pageVisible, cb) {
if (!pageVisible) { // if page containing field is not visible then don't need to check field
return cb(undefined, false);
}
var field = fieldMap[fieldId];
if (!fieldId) return cb(new Error("Field does not exist in form"));
async.waterfall([
function testPage(cb) {
if (checkContainingPage) {
isPageVisible(field.pageId, cb);
} else {
return cb(undefined, true);
if (isFieldRuleSubject(fieldId)) { // If the field is the subject of a rule it may have been hidden
return rulesResult(fieldRuleSubjectMap[fieldId], cb); // execute field rules
} else {
return cb(undefined, true); // if not subject of field rules then can't be hidden
}
}
},
function testField(pageVisible, cb) {
if (!pageVisible) { // if page containing field is not visible then don't need to check field
return cb(undefined, false);
}
], cb);
});
}
if (isFieldRuleSubject(fieldId) ) { // If the field is the subject of a rule it may have been hidden
return rulesResult(fieldRuleSubjectMap[fieldId], cb); // execute field rules
} else {
return cb(undefined, true); // if not subject of field rules then can't be hidden
}
}
], cb);
});
}
/*
* check all rules actions
* res:
* {
* "actions": {
* "pages": {
* "targetId": {
* "targetId": "",
* "action": "show|hide"
* }
* },
* "fields": {
* }
* }
* }
*/
function checkRules(submissionJSON, cb) {
init(function (err) {
if (err) return cb(err);
/*
* check all rules actions
* res:
* {
* "actions": {
* "pages": {
* "targetId": {
* "targetId": "",
* "action": "show|hide"
* }
* },
* "fields": {
* }
* }
* }
*/
function checkRules(submissionJSON, cb) {
init(function(err){
if (err) return cb(err);
initSubmission(submissionJSON, function (err) {
if (err) return cb(err);
var actions = {};
initSubmission(submissionJSON, function (err) {
if(err) return cb(err);
var actions = {};
async.parallel([
async.parallel([
function (cb) {
actions.fields = {};
async.eachSeries(Object.keys(fieldRuleSubjectMap), function (fieldId, cb) {
isFieldVisible(fieldId, false, function (err, fieldVisible) {
if (err) return cb(err);
actions.fields[fieldId] = {targetId: fieldId, action: (fieldVisible?"show":"hide")};
return cb();
});
}, cb);
},
function (cb) {
actions.pages = {};
async.eachSeries(Object.keys(pageRuleSubjectMap), function (pageId, cb) {
isPageVisible(pageId, function (err, pageVisible) {
if (err) return cb(err);
actions.pages[pageId] = {targetId: pageId, action: (pageVisible?"show":"hide")};
return cb();
});
}, cb);
}
], function (err) {
if(err) return cb(err);
function (cb) {
actions.fields = {};
async.eachSeries(Object.keys(fieldRuleSubjectMap), function (fieldId, cb) {
isFieldVisible(fieldId, false, function (err, fieldVisible) {
if (err) return cb(err);
actions.fields[fieldId] = {
targetId: fieldId,
action: (fieldVisible ? "show" : "hide")
};
return cb();
});
}, cb);
},
function (cb) {
actions.pages = {};
async.eachSeries(Object.keys(pageRuleSubjectMap), function (pageId, cb) {
isPageVisible(pageId, function (err, pageVisible) {
if (err) return cb(err);
actions.pages[pageId] = {
targetId: pageId,
action: (pageVisible ? "show" : "hide")
};
return cb();
});
}, cb);
}
], function (err) {
if (err) return cb(err);
return cb(undefined, {actions: actions});
return cb(undefined, {
actions: actions
});
});
});
});
});
}
}
return {
validateForm: validateForm,
validateField: validateField,
validateFieldValue: validateFieldValue,
checkRules: checkRules,
return {
validateForm: validateForm,
validateField: validateField,
validateFieldValue: validateFieldValue,
checkRules: checkRules,
// The following are used internally, but exposed for tests
validateFieldInternal: validateFieldInternal,
initSubmission: initSubmission,
isFieldVisible: isFieldVisible,
isConditionActive: isConditionActive
// The following are used internally, but exposed for tests
validateFieldInternal: validateFieldInternal,
initSubmission: initSubmission,
isFieldVisible: isFieldVisible,
isConditionActive: isConditionActive
};
};
};
function isNumberBetween(num, min, max) {
var numVal = parseInt(num,10);
return (!isNaN(numVal) && (numVal >= min) && (numVal <= max));
}
function isNumberBetween(num, min, max) {
var numVal = parseInt(num, 10);
return (!isNaN(numVal) && (numVal >= min) && (numVal <= max));
}
function cvtTimeToSeconds(fieldValue) {
var seconds = 0;
if (typeof fieldValue === "string") {
var parts = fieldValue.split(':');
valid = (parts.length === 2) || (parts.length === 3);
if (valid) {
valid = isNumberBetween(parts[0], 0, 23);
seconds += (parseInt(parts[0], 10) * 60 * 60);
function cvtTimeToSeconds(fieldValue) {
var seconds = 0;
if (typeof fieldValue === "string") {
var parts = fieldValue.split(':');
valid = (parts.length === 2) || (parts.length === 3);
if (valid) {
valid = isNumberBetween(parts[0], 0, 23);
seconds += (parseInt(parts[0], 10) * 60 * 60);
}
if (valid) {
valid = isNumberBetween(parts[1], 0, 59);
seconds += (parseInt(parts[1], 10) * 60);
}
if (valid && (parts.length === 3)) {
valid = isNumberBetween(parts[2], 0, 59);
seconds += parseInt(parts[2], 10);
}
}
if (valid) {
valid = isNumberBetween(parts[1], 0, 59);
seconds += (parseInt(parts[1], 10) * 60);
}
if (valid && (parts.length === 3)) {
valid = isNumberBetween(parts[2], 0, 59);
seconds += parseInt(parts[2], 10);
}
return seconds;
}
return seconds;
}
function isConditionActive(field, fieldValue, testValue, condition) {
function isConditionActive(field, fieldValue, testValue, condition) {
var fieldType = field.type;
var fieldOptions = field.fieldOptions ? field.fieldOptions : {};
var fieldType = field.type;
var fieldOptions = field.fieldOptions ? field.fieldOptions : {};
var valid = true;
if( "is equal to" === condition) {
valid = fieldValue === testValue;
}
else if( "is greater than" === condition) {
// TODO - do numeric checking
valid = fieldValue > testValue;
}
else if( "is less than" === condition) {
// TODO - do numeric checking
valid = fieldValue < testValue;
}
else if( "is at" === condition) {
valid = false;
if( fieldType === FIELD_TYPE_DATETIME ) {
switch (fieldOptions.definition.datetimeUnit)
{
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try{
valid = (new Date(new Date(fieldValue).toDateString()).getTime() == new Date(new Date(testValue).toDateString()).getTime());
}catch(e){
valid = false;
var valid = true;
if ("is equal to" === condition) {
valid = fieldValue === testValue;
} else if ("is greater than" === condition) {
// TODO - do numeric checking
valid = fieldValue > testValue;
} else if ("is less than" === condition) {
// TODO - do numeric checking
valid = fieldValue < testValue;
} else if ("is at" === condition) {
valid = false;
if (fieldType === FIELD_TYPE_DATETIME) {
switch (fieldOptions.definition.datetimeUnit) {
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try {
valid = (new Date(new Date(fieldValue).toDateString()).getTime() == new Date(new Date(testValue).toDateString()).getTime());
} catch (e) {
valid = false;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) === cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try {
valid = (new Date(fieldValue).getTime() == new Date(testValue).getTime());
} catch (e) {
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) === cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try{
valid = (new Date(fieldValue).getTime() == new Date(testValue).getTime());
}catch(e){
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
}
}
else if( "is before" === condition) {
valid = false;
if( fieldType === FIELD_TYPE_DATETIME ) {
switch (fieldOptions.definition.datetimeUnit)
{
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try{
valid = (new Date(new Date(fieldValue).toDateString()).getTime() < new Date(new Date(testValue).toDateString()).getTime());
}catch(e){
valid = false;
} else if ("is before" === condition) {
valid = false;
if (fieldType === FIELD_TYPE_DATETIME) {
switch (fieldOptions.definition.datetimeUnit) {
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try {
valid = (new Date(new Date(fieldValue).toDateString()).getTime() < new Date(new Date(testValue).toDateString()).getTime());
} catch (e) {
valid = false;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) < cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try {
valid = (new Date(fieldValue).getTime() < new Date(testValue).getTime());
} catch (e) {
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) < cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try{
valid = (new Date(fieldValue).getTime() < new Date(testValue).getTime());
}catch(e){
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
}
}
else if( "is after" === condition) {
valid = false;
if( fieldType === FIELD_TYPE_DATETIME ) {
switch (fieldOptions.definition.datetimeUnit)
{
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try{
valid = (new Date(new Date(fieldValue).toDateString()).getTime() > new Date(new Date(testValue).toDateString()).getTime());
}catch(e){
valid = false;
} else if ("is after" === condition) {
valid = false;
if (fieldType === FIELD_TYPE_DATETIME) {
switch (fieldOptions.definition.datetimeUnit) {
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATEONLY:
try {
valid = (new Date(new Date(fieldValue).toDateString()).getTime() > new Date(new Date(testValue).toDateString()).getTime());
} catch (e) {
valid = false;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) > cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try {
valid = (new Date(fieldValue).getTime() > new Date(testValue).getTime());
} catch (e) {
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_TIMEONLY:
valid = cvtTimeToSeconds(fieldValue) > cvtTimeToSeconds(testValue);
break;
case FIELD_TYPE_DATETIME_DATETIMEUNIT_DATETIME:
try{
valid = (new Date(fieldValue).getTime() > new Date(testValue).getTime());
}catch(e){
valid = false;
}
break;
default:
valid = false; // TODO should raise error here?
break;
}
}
}
else if( "is" === condition) {
if (fieldType === FIELD_TYPE_CHECKBOX) {
valid = fieldValue && fieldValue.selections && fieldValue.selections.indexOf(testValue) !== -1;
} else if ("is" === condition) {
if (fieldType === FIELD_TYPE_CHECKBOX) {
valid = fieldValue && fieldValue.selections && fieldValue.selections.indexOf(testValue) !== -1;
} else {
valid = fieldValue === testValue;
}
} else if ("is not" === condition) {
if (fieldType === FIELD_TYPE_CHECKBOX) {
valid = fieldValue && fieldValue.selections && fieldValue.selections.indexOf(testValue) === -1;
} else {
valid = fieldValue !== testValue;
}
} else if ("contains" === condition) {
valid = fieldValue.indexOf(testValue) !== -1;
} else if ("does not contain" === condition) {
valid = fieldValue.indexOf(testValue) === -1;
} else if ("begins with" === condition) {
valid = fieldValue.substring(0, testValue.length) === testValue;
} else if ("ends with" === condition) {
valid = fieldValue.substring(Math.max(0, (fieldValue.length - testValue.length)), fieldValue.length) === testValue;
} else {
valid = fieldValue === testValue;
valid = false;
}
return valid;
}
else if( "is not" === condition) {
if (fieldType === FIELD_TYPE_CHECKBOX) {
valid = fieldValue && fieldValue.selections && fieldValue.selections.indexOf(testValue) === -1;
} else {
valid = fieldValue !== testValue;
}
}
else if( "contains" === condition) {
valid = fieldValue.indexOf(testValue) !== -1;
}
else if( "does not contain" === condition) {
valid = fieldValue.indexOf(testValue) === -1;
}
else if( "begins with" === condition) {
valid = fieldValue.substring(0, testValue.length) === testValue;
}
else if( "ends with" === condition) {
valid = fieldValue.substring(Math.max(0, (fieldValue.length - testValue.length)), fieldValue.length) === testValue;
}
else {
valid = false;
}
return valid;
}
if (typeof module !== 'undefined' && module.exports) {
if (typeof module !== 'undefined' && module.exports) {
module.exports = formsRulesEngine;
}
}
}());
}());
{
"name": "fh-forms",
"version": "0.5.6",
"version": "0.5.7",
"description": "Cloud Forms API for form submission",

@@ -5,0 +5,0 @@ "main": "lib/forms.js",

@@ -1,1 +0,1 @@

0.5.6-37
0.5.7-38
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc