예제 #1
0
        private void ValidateTemplateMarkup(Template template, IEnumerable <TemplateErrorSuppression> errorSuppressions)
        {
            var references = template.Steps.SelectMany(s => s.Inputs.Select(i =>
            {
                var inputId = s.Id;
                if (!string.IsNullOrEmpty(i.Key))
                {
                    inputId += $".{i.Key}";
                }

                if (i.Type == TemplateStepInputType.Text)
                {
                    return(ReferenceDefinition.String(inputId));
                }
                else if (i.Type == TemplateStepInputType.Checkbox)
                {
                    return(ReferenceDefinition.Boolean(inputId));
                }
                else if (i.Type == TemplateStepInputType.Radio)
                {
                    var values = DynamicUtility.Unwrap(() => (IEnumerable <dynamic>)i.TypeData)
                                 .Select(d => DynamicUtility.Unwrap <string>(() => d.Value));
                    return(ReferenceDefinition.StringFrom(inputId, values));
                }
                else
                {
                    throw new Exception($"Unknown {nameof(TemplateStepInputType)}");
                }
            }));

            _templateMarkupValidator.Validate(template.Markup, template.MarkupVersion, references, errorSuppressions);
        }
예제 #2
0
        private void ValidateDocumentAgainstTemplate(DocumentCreate create, Template template)
        {
            var inputValueErrors = new ModelErrorDictionary();

            // Store the traversed values so we can easily analyse conditional inputs. It's fine to just store them as strings as we
            // have already validated their types and value comparison will work for stringified booleans and numbers.
            var validInputStringValues = new Dictionary <string, string>();

            template.Steps.ForEach(templateStep =>
            {
                var allConditionsMet = templateStep.Conditions.All(condition =>
                {
                    if (condition.Type == TemplateComponentConditionType.EqualsPreviousInputValue)
                    {
                        var expectedPreviousInputValue = DynamicUtility.Unwrap <string>(() => condition.TypeData.PreviousInputValue);
                        var previousInputId            = DynamicUtility.Unwrap <string>(() => condition.TypeData.PreviousInputId);

                        if (string.IsNullOrEmpty(expectedPreviousInputValue) || string.IsNullOrEmpty(previousInputId))
                        {
                            throw new Exception("Internal error: invalid template");
                        }

                        return(validInputStringValues.ContainsKey(previousInputId) && expectedPreviousInputValue.Equals(validInputStringValues[previousInputId]));
                    }
                    else if (condition.Type == TemplateComponentConditionType.IsDocumentSigned)
                    {
                        // Skip this step if the contract won't be signed
                        return(create.GetIsSigned());
                    }
                    return(false);
                });

                if (!allConditionsMet)
                {
                    return;
                }

                var templateStepId = templateStep.Id;

                var defaultTemplateStepInput = templateStep.Inputs.SingleOrDefault(i => string.IsNullOrEmpty(i.Key));
                if (defaultTemplateStepInput != null)
                {
                    var result = ValidateTemplateStepInput(templateStep, defaultTemplateStepInput, create.InputValues, inputValueErrors, isDefaultInput: true);
                    if (result.success)
                    {
                        validInputStringValues.Add(result.templateStepInputId, result.inputValueString);
                    }
                }

                templateStep.Inputs
                .Where(templateStepInput => !string.IsNullOrEmpty(templateStepInput.Key))
                .ForEach(templateStepInput =>
                {
                    var result = ValidateTemplateStepInput(templateStep, templateStepInput, create.InputValues, inputValueErrors, isDefaultInput: false);
                    if (result.success)
                    {
                        validInputStringValues.Add(result.templateStepInputId, result.inputValueString);
                    }
                });
            });

            inputValueErrors.AssertValid();
        }
예제 #3
0
        private void ValidateTemplateStep(TemplateCreate create, string stepId, Dictionary <string, IndexedElement <TemplateStepCreate> > stepsById, ModelErrorDictionary stepErrors)
        {
            var indexedStep = stepsById[stepId];
            var step        = indexedStep.Element;
            var stepIndex   = indexedStep.Index;

            var stepErrorPath = new object[] { nameof(TemplateCreate.Steps), stepIndex };

            var isParentStep = stepsById.Any(kvp => kvp.Key.StartsWith(stepId) && kvp.Value.Index != stepIndex);

            if (!isParentStep && !step.Inputs.Any())
            {
                // Steps that do not have child steps must have inputs.
                // FUTURE: Maybe we want to add "informational" steps, with no inputs.
                stepErrors.Add("Step must have at least one inputs", stepErrorPath);
            }

            var stepConditionsErrorPath = stepErrorPath.Concat(nameof(TemplateStepCreate.Conditions));

            step.Conditions.ForEach((condition, conditionIndex) =>
            {
                var stepConditionErrorPath         = stepConditionsErrorPath.Concat(conditionIndex);
                var stepConditionTypeErrorPath     = stepConditionErrorPath.Concat(nameof(TemplateStepCondition.Type));
                var stepConditionTypeDataErrorPath = stepConditionErrorPath.Concat(nameof(TemplateStepCondition.TypeData));

                if (condition.Type == TemplateComponentConditionType.EqualsPreviousInputValue)
                {
                    var previousInputIdErrorPath    = stepConditionTypeDataErrorPath.Concat(nameof(TemplateStepConditionTypeData_EqualsPreviousInputValue.PreviousInputId));
                    var previousInputValueErrorPath = stepConditionTypeDataErrorPath.Concat(nameof(TemplateStepConditionTypeData_EqualsPreviousInputValue.PreviousInputValue));

                    var previousInputId = DynamicUtility.Unwrap <string>(() => condition.TypeData.PreviousInputId);
                    var(previousInputSuccess, previousInputError, previousInput) = GetPreviousInputReference(stepId, previousInputId, stepsById);
                    if (previousInputSuccess)
                    {
                        if (previousInput.Type == TemplateStepInputType.Checkbox)
                        {
                            try
                            {
                                DynamicUtility.UnwrapValue <bool>(() => condition.TypeData.PreviousInputValue);
                            }
                            catch (RuntimeBinderException)
                            {
                                stepErrors.Add("Expected boolean", previousInputValueErrorPath);
                            }
                        }
                        else if (previousInput.Type == TemplateStepInputType.Radio)
                        {
                            try
                            {
                                DynamicUtility.Unwrap <string>(() => condition.TypeData.PreviousInputValue);
                            }
                            catch (RuntimeBinderException)
                            {
                                throw;
                            }
                        }
                        else
                        {
                            stepErrors.Add("Type of previous input is not supported for conditions", previousInputValueErrorPath);
                        }
                    }
                    else
                    {
                        stepErrors.Add(previousInputError, previousInputIdErrorPath);
                    }
                }
                else if (condition.Type == TemplateComponentConditionType.IsDocumentSigned)
                {
                    if (!create.IsSignable)
                    {
                        stepErrors.Add("Step condition cannot be on document signing if the template does not allow signing", stepConditionTypeErrorPath);
                    }
                }
            });

            ValidateTemplateStepInputs(step, stepErrors, stepErrorPath);
        }