Example #1
0
        private void ValidateTemplateSteps(TemplateCreate create, IEnumerable <TemplateStepCreate> steps)
        {
            steps
            .Where(step => step.ParentReference?.Split(Constants.TemplateComponentReferenceSeparator).Count() > 1)
            .ForEach((step) =>
            {
                throw new NotImplementedException("Only one level of step nesting is supported");
            });

            var stepsByIdLookup = steps.ToIndexedLookup(s => s.Id);

            stepsByIdLookup
            .Where(g => g.Count() > 1)
            .Select(g => g.Skip(1).First())
            .ForEach(indexedStep =>
            {
                throw new ClientModelValidationException(
                    $"A step with the name {indexedStep.Element.Name} already exists (case-insensitive)",
                    $"{nameof(TemplateCreate.Steps)}[{indexedStep.Index}]");     // TODO: Make exception take params of object and resolve member name
            });

            var stepErrors = new ModelErrorDictionary();
            var stepsById  = stepsByIdLookup.ToDictionary(g => g.Key, g => g.Single());

            stepsById.ForEach(kvp => ValidateTemplateStep(create, kvp.Key, stepsById, stepErrors));

            if (stepErrors.HasErrors)
            {
                throw new ClientModelValidationException(stepErrors);
            }
        }
Example #2
0
        public async Task <Template> CreateTemplateAsync(TemplateCreate create, bool dryRun = false)
        {
            Validator.ValidateNotNull(create, nameof(create));
            Validator.Validate(create);
            ValidateTemplateSteps(create, create.Steps);

            var template = _mapper.Map <Template>(create);

            await ValidateTemplateHasUniqueIdAsync(template);

            ValidateTemplateMarkup(template, create.ErrorSuppressions);

            if (dryRun)
            {
                return(template);
            }
            else
            {
                return(await _templateRepository.CreateTemplateAsync(template));
            }
        }
Example #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);
        }