private async Task <TDocument> CreateDocumentAsync <TDocument>(DocumentCreate create) { Validator.ValidateNotNull(create, nameof(create)); Validator.Validate(create); Template template = null; try { template = await _templateRepository.GetTemplateAsync(create.TemplateId); } catch (EntityNotFoundException ex) { ThrowEntityNotFoundAsClientModelValidation(ex, nameof(create.TemplateId)); } ValidateDocumentAgainstTemplate(create, template); return(await _documentRenderer.RenderAsync <TDocument>( template.Markup, template.MarkupVersion, new DocumentRenderModel() { Items = create.InputValues.Select(kvp => new DocumentRenderModelItem() { Reference = kvp.Key, Value = ((object)kvp.Value).ToString() }), Sign = template.IsSignable ? create.GetIsSigned() : false, Exports = _documentExportsFactory.Create(template, create.InputValues) })); }
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(); }