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); } }
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)); } }
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); }