/// <summary> /// Method that maps the MVC Model state to the ApiResult /// </summary> /// <param name="modelState">The model state</param> /// <param name="apiResult">The api result</param> /// <param name="serviceContext">The service context</param> private void MapModelStateToApiResult(ModelStateDictionary modelState, ApiResult apiResult, ServiceContext serviceContext) { apiResult.ModelStateEntries = new List <ApiModelStateEntry>(); foreach (string modelKey in modelState.Keys) { ApiModelStateEntry apiEntry = null; ModelState.TryGetValue(modelKey, out ModelStateEntry entry); if (entry != null && entry.ValidationState == ModelValidationState.Invalid) { apiEntry = new ApiModelStateEntry { Key = modelKey, ValidationState = (ApiModelValidationState)(int)entry.ValidationState, Errors = new List <ApiModelError>() }; foreach (ModelError error in entry.Errors) { apiEntry.Errors.Add(new ApiModelError() { ErrorMessage = ServiceTextHelper.GetServiceText(error.ErrorMessage, serviceContext.ServiceText, null, "nb-NO") }); } apiResult.ModelStateEntries.Add(apiEntry); apiResult.Status = ApiStatusType.ContainsError; } } }
/// <summary> /// Method which processes the element and updates the content /// if all conditions are met and the given parameters are valid /// </summary> /// <param name="context">The current tag helper context</param> /// <param name="output">The output of this tag helper, the result is written here</param> /// <returns>Task indicating when the processing is completed</returns> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; RequestContext requestContext = ViewContext.ViewBag.RequestContext; if (!string.IsNullOrEmpty(AltinnTextKey)) { if (serviceContext.ServiceText.ContainsKey(AltinnTextKey) && serviceContext.ServiceText[AltinnTextKey].ContainsKey(serviceContext.CurrentCulture)) { var href = output.Attributes["href"]; var serverurl = ViewContext.HttpContext.Request.Host; var url = "/ui/" + serviceContext.ServiceMetaData.Org + "/" + serviceContext.ServiceMetaData.RepositoryName + "/" + requestContext.InstanceId + "/" + output.Attributes["name"].Value; var protocol = ViewContext.HttpContext.Request.Protocol.Split('/')[0]; // Strips away the protocol version in the last part href = new TagHelperAttribute("href", protocol + "://" + serverurl + url, href.ValueStyle); output.Attributes.SetAttribute(href); var content = ServiceTextHelper.SetTextParams( serviceContext.ServiceText[AltinnTextKey][serviceContext.CurrentCulture], requestContext, serviceContext); output.Content.SetHtmlContent(content); } } }
private List <ValidationIssue> MapModelStateToIssueList( Instance instance, List <System.ComponentModel.DataAnnotations.ValidationResult> validationResult, string elementId, string dataType, Dictionary <string, Dictionary <string, string> > serviceText) { List <ValidationIssue> messages = new List <ValidationIssue>(); foreach (System.ComponentModel.DataAnnotations.ValidationResult validationIssue in validationResult) { if (validationIssue != null) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, DataElementId = elementId, Code = validationIssue.ErrorMessage, Field = string.Join(",", validationIssue.MemberNames), Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText(validationIssue.ErrorMessage, serviceText, null, "nb") }; messages.Add(message); } } return(messages); }
/// <summary> /// Method which processes the element and updates the content /// if all conditions are met and the given parameters are valid /// </summary> /// <param name="context">The current tag helper context</param> /// <param name="output">The output of this tag helper, the result is written here</param> /// <returns>Task indicating when the processing is completed</returns> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { var childContent = await output.GetChildContentAsync(); ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; RequestContext requestContext = ViewContext.ViewBag.RequestContext; if (!string.IsNullOrEmpty(AltinnTextKey)) { if (serviceContext.ServiceText.ContainsKey(AltinnTextKey) && serviceContext.ServiceText[AltinnTextKey].ContainsKey(serviceContext.CurrentCulture)) { output.Content.SetHtmlContent(ServiceTextHelper.SetTextParams(serviceContext.ServiceText[AltinnTextKey][serviceContext.CurrentCulture], requestContext, serviceContext)); } } }
/// <summary> /// This method replaces the error text key in validation attribute comming from model /// https://github.com/aspnet/Mvc/tree/a78f77afde003c4a3fcf5dd7b6dc13dd9c85f825/src/Microsoft.AspNetCore.Mvc.DataAnnotations/Internal /// and other attributes that uses altinn text key /// </summary> /// <param name="tagHelperOutput"></param> /// <param name="serviceContext"></param> private void ReplaceAttributeTextKeysWithText(TagHelperOutput tagHelperOutput, ServiceContext serviceContext) { for (int i = 0; i < tagHelperOutput.Attributes.Count; i++) { string attributeKey = tagHelperOutput.Attributes[i].Name; // Look for the known jquery-validation-unobtrusive attribute tags if (attributeKey.Equals("data-val-equalto") || attributeKey.Equals("data-val-maxlength") || attributeKey.Equals("data-val-minlength") || attributeKey.Equals("data-val-range") || attributeKey.Equals("data-val-regex") || attributeKey.Equals("data-val-required") || attributeKey.Equals("data-val-length") || attributeKey.Equals("placeholder")) { // Replaces the attribute tagHelperOutput.Attributes[i] = new TagHelperAttribute(tagHelperOutput.Attributes[i].Name, ServiceTextHelper.GetServiceText(tagHelperOutput.Attributes[i].Value.ToString(), serviceContext.ServiceText, null, serviceContext.CurrentCulture)); } } }
/// <summary> /// Method that maps the MVC Model state to the ApiResult for the client. /// </summary> /// <param name="modelState">The model state.</param> /// <param name="apiResult">The api result.</param> /// <param name="serviceContext">The service context.</param> private void MapModelStateToApiResultForClient(ModelStateDictionary modelState, ApiResult apiResult, ServiceContext serviceContext) { apiResult.ValidationResult = new ApiValidationResult { Messages = new Dictionary <string, ApiValidationMessages>() }; bool containsErrors = false; bool containsWarnings = false; foreach (string modelKey in modelState.Keys) { ModelState.TryGetValue(modelKey, out ModelStateEntry entry); if (entry != null && entry.ValidationState == ModelValidationState.Invalid) { foreach (ModelError error in entry.Errors) { if (error.ErrorMessage.StartsWith(_generalSettings.SoftValidationPrefix)) { containsWarnings = true; // Remove prefix for soft validation string errorMesssage = error.ErrorMessage.Substring(9); if (apiResult.ValidationResult.Messages.ContainsKey(modelKey)) { apiResult.ValidationResult.Messages[modelKey].Warnings.Add(ServiceTextHelper.GetServiceText(errorMesssage, serviceContext.ServiceText, null, "nb-NO")); } else { apiResult.ValidationResult.Messages.Add(modelKey, new ApiValidationMessages { Errors = new List <string>(), Warnings = new List <string> { ServiceTextHelper.GetServiceText(errorMesssage, serviceContext.ServiceText, null, "nb-NO") } }); } } else { containsErrors = true; if (apiResult.ValidationResult.Messages.ContainsKey(modelKey)) { apiResult.ValidationResult.Messages[modelKey].Errors.Add(ServiceTextHelper.GetServiceText(error.ErrorMessage, serviceContext.ServiceText, null, "nb-NO")); } else { apiResult.ValidationResult.Messages.Add(modelKey, new ApiValidationMessages { Errors = new List <string> { ServiceTextHelper.GetServiceText(error.ErrorMessage, serviceContext.ServiceText, null, "nb-NO") }, Warnings = new List <string>(), }); } } } } } if (containsErrors) { apiResult.Status = ApiStatusType.ContainsError; } else if (containsWarnings) { apiResult.Status = ApiStatusType.ContainsWarnings; } }
public async Task <IActionResult> ValidateData( [FromRoute] string org, [FromRoute] string app, [FromRoute] int instanceOwnerId, [FromRoute] Guid instanceId, [FromRoute] Guid dataGuid) { Instance instance = await _instanceService.GetInstance(app, org, instanceOwnerId, instanceId); if (instance == null) { return(NotFound()); } // Todo. Figure out where to get this from Dictionary <string, Dictionary <string, string> > serviceText = new Dictionary <string, Dictionary <string, string> >(); if (instance.Process?.CurrentTask?.ElementId == null) { throw new ValidationException("Unable to validate instance without a started process."); } List <ValidationIssue> messages = new List <ValidationIssue>(); DataElement element = instance.Data.FirstOrDefault(d => d.Id == dataGuid.ToString()); if (element == null) { throw new ValidationException("Unable to validate data element."); } Application application = await _appService.GetApplication(org, app); DataType dataType = application.DataTypes.FirstOrDefault(et => et.Id == element.DataType); if (dataType == null) { throw new ValidationException("Unknown element type."); } messages.AddRange(await _validationService.ValidateDataElement(instance, dataType, element)); string taskId = instance.Process.CurrentTask.ElementId; if (!dataType.TaskId.Equals(taskId, StringComparison.OrdinalIgnoreCase)) { ValidationIssue message = new ValidationIssue { Code = ValidationIssueCodes.DataElementCodes.DataElementValidatedAtWrongTask, InstanceId = instance.Id, Severity = ValidationIssueSeverity.Warning, DataElementId = element.Id, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.DataElementCodes.DataElementValidatedAtWrongTask, serviceText, null, "nb") }; messages.Add(message); } return(Ok(messages)); }
/// <summary> /// Builds the validation summary /// </summary> /// <param name="context">The current tag helper context</param> /// <param name="output">The output of the tag helper, is written to when creating the result</param> /// <returns>A task</returns> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { output.TagName = "div"; var childContent = await output.GetChildContentAsync(); RequestContext requestContext = ViewContext.ViewBag.RequestContext; ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; if (requestContext != null && requestContext.ValidationResult != null) { int numberOfValidationErrors = requestContext.ValidationResult.Where(vs => vs.ValidationStatusType.Equals(ValidationStatusType.Error)).ToList().Count; if (numberOfValidationErrors > 0) { output.Attributes.Add("class", "card card-inverse card-danger"); TagBuilder cardBlockTag = new TagBuilder("div"); cardBlockTag.AddCssClass("card-body"); TagBuilder cardTitleTag = new TagBuilder("h3"); cardTitleTag.InnerHtml.AppendHtml("Du har " + numberOfValidationErrors + " feil"); cardTitleTag.AddCssClass("card-title"); cardBlockTag.InnerHtml.AppendHtml(cardTitleTag); TagBuilder listBuilder = new TagBuilder("ul"); listBuilder.AddCssClass("card-text"); foreach (ValidationResult validationResult in requestContext.ValidationResult.OrderBy(w => w.ValidationGroup)) { TagBuilder errorListItem = new TagBuilder("li"); TagBuilder errorLink = new TagBuilder("a"); string url = "/ui/" + requestContext.InstanceId + "/" + validationResult.ViewID; if (validationResult.CustomParameters != null && validationResult.CustomParameters.Count > 0) { url += "?"; string splitter = string.Empty; foreach (KeyValuePair <string, string> kvp in validationResult.CustomParameters) { url += splitter; url += kvp.Key + "=" + kvp.Value; splitter = "&"; } url += '#' + validationResult.ModelKey.Replace('.', '_').Replace("[", "_").Replace("]", "_"); } errorLink.Attributes.Add("href", url); errorLink.InnerHtml.AppendHtml(ServiceTextHelper.SetTextParams(ServiceTextHelper.GetServiceText(validationResult.ValidationMessageKey, serviceContext.ServiceText, validationResult.MessageParams, serviceContext.CurrentCulture), requestContext, serviceContext)); errorListItem.InnerHtml.AppendHtml(errorLink); listBuilder.InnerHtml.AppendHtml(errorListItem); } cardBlockTag.InnerHtml.AppendHtml(listBuilder); output.Content.AppendHtml(cardBlockTag); } else { output.Attributes.Add("class", "card card-inverse card-success"); } } else { output.Content.Clear(); } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } var tagBuilder = Generator.GenerateLabel( ViewContext, For.ModelExplorer, For.Name, labelText: null, htmlAttributes: null); if (tagBuilder != null) { output.MergeAttributes(tagBuilder); ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; RequestContext requestContext = ViewContext.ViewBag.RequestContext; // We check for whitespace to detect scenarios such as: // <label for="Name"> // </label> if (!output.IsContentModified) { var childContent = await output.GetChildContentAsync(); string labelText = string.Empty; string modelpath = serviceContext.RootName + "." + ModelHelper.GetMetadataModelPath(For.Name); bool textSet = false; // Check if specific Text key is used (for reuse of textkey) if (!string.IsNullOrEmpty(AltinnTextKey)) { if (serviceContext.ServiceText.ContainsKey(AltinnTextKey) && serviceContext.ServiceText[AltinnTextKey].ContainsKey(serviceContext.CurrentCulture)) { output.Content.SetHtmlContent(serviceContext.ServiceText[AltinnTextKey][serviceContext.CurrentCulture]); textSet = true; } } // First see if the text is defined in the Service Metadata if (!textSet && serviceContext.ServiceMetaData?.Elements?.ContainsKey(modelpath) == true) { ElementMetadata elementMetaData = serviceContext.ServiceMetaData?.Elements[modelpath]; if (elementMetaData.Texts?.ContainsKey(TextCategoryType.Label.ToString()) == true) { string textKey = elementMetaData.Texts[TextCategoryType.Label.ToString()]; if (serviceContext.ServiceText.ContainsKey(serviceContext.CurrentCulture) && serviceContext.ServiceText[serviceContext.CurrentCulture].ContainsKey(textKey)) { output.Content.SetHtmlContent(ServiceTextHelper.SetTextParams(serviceContext.ServiceText[serviceContext.CurrentCulture][textKey], requestContext, serviceContext)); textSet = true; } } else { // Try to collect the text from model path string textKey = TextCategoryType.Label + "." + modelpath; if (serviceContext.ServiceText.ContainsKey(serviceContext.CurrentCulture) && serviceContext.ServiceText[serviceContext.CurrentCulture].ContainsKey(textKey)) { output.Content.SetHtmlContent(ServiceTextHelper.SetTextParams(serviceContext.ServiceText[serviceContext.CurrentCulture][textKey], requestContext, serviceContext)); textSet = true; } } } if (!textSet) { if (childContent.IsEmptyOrWhiteSpace) { // Provide default label text since there was nothing useful in the Razor source. output.Content.SetHtmlContent(tagBuilder.InnerHtml); } else { output.Content.SetHtmlContent(childContent); } } } } }
/// <inheritdoc /> /// <remarks>Does nothing if <see cref="For"/> is <c>null</c>.</remarks> public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } if (For != null) { var tagBuilder = Generator.GenerateValidationMessage( ViewContext, For.ModelExplorer, For.Name, message: null, tag: null, htmlAttributes: null); if (tagBuilder != null) { RequestContext requestContext = ViewContext.ViewBag.RequestContext; ServiceContext serviceContext = ViewContext.ViewBag.ServiceContext; var fullName = GetFullHtmlFieldName(ViewContext, For.Name); var tryGetModelStateResult = ViewContext.ViewData.ModelState.TryGetValue(fullName, out ModelStateEntry entry); var modelErrors = tryGetModelStateResult ? entry.Errors : null; ModelError modelError = null; if (modelErrors != null && modelErrors.Count != 0) { modelError = modelErrors[0]; } output.MergeAttributes(tagBuilder); // We check for whitespace to detect scenarios such as: // <span validation-for="Name"> // </span> if (!output.IsContentModified) { var childContent = await output.GetChildContentAsync(); if (modelError != null) { output.Content.SetHtmlContent(ServiceTextHelper.SetTextParams(ServiceTextHelper.GetServiceText(modelError.ErrorMessage, serviceContext.ServiceText, null, serviceContext.CurrentCulture), requestContext, serviceContext)); } else if (childContent.IsEmptyOrWhiteSpace) { // Provide default label text since there was nothing useful in the Razor source. output.Content.SetHtmlContent(tagBuilder.InnerHtml); } else { output.Content.SetHtmlContent(childContent); } } } } }
public async Task <System.Collections.Generic.List <ValidationIssue> > ValidateAndUpdateInstance(Instance instance, string taskId) { string org = instance.Org; string app = instance.AppId.Split("/")[1]; _logger.LogInformation($"Validation of {instance.Id}"); Application application = _appResourcesService.GetApplication(); // Todo. Figure out where to get this from Dictionary <string, Dictionary <string, string> > serviceText = new Dictionary <string, Dictionary <string, string> >(); List <ValidationIssue> messages = new List <ValidationIssue>(); foreach (DataType dataType in application.DataTypes.Where(et => et.TaskId == taskId)) { List <DataElement> elements = instance.Data.Where(d => d.DataType == dataType.Id).ToList(); if (dataType.MaxCount > 0 && dataType.MaxCount < elements.Count) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, Code = ValidationIssueCodes.InstanceCodes.TooManyDataElementsOfType, Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.InstanceCodes.TooManyDataElementsOfType, serviceText, null, "nb") }; messages.Add(message); } if (dataType.MinCount > 0 && dataType.MinCount > elements.Count) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, Code = ValidationIssueCodes.InstanceCodes.TooFewDataElementsOfType, Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.InstanceCodes.TooFewDataElementsOfType, null, null, "nb") }; messages.Add(message); } foreach (DataElement dataElement in elements) { messages.AddRange(await ValidateDataElement(instance, dataType, dataElement)); } } if (messages.Count == 0) { instance.Process.CurrentTask.Validated = new ValidationStatus { CanCompleteTask = true, Timestamp = DateTime.Now }; } else { instance.Process.CurrentTask.Validated = new ValidationStatus { CanCompleteTask = false, Timestamp = DateTime.Now }; } return(messages); }
public async Task <List <ValidationIssue> > ValidateDataElement(Instance instance, DataType dataType, DataElement dataElement) { _logger.LogInformation($"Validation of data element {dataElement.Id} of instance {instance.Id}"); // Todo. Figure out where to get this from Dictionary <string, Dictionary <string, string> > serviceText = new Dictionary <string, Dictionary <string, string> >(); List <ValidationIssue> messages = new List <ValidationIssue>(); if (dataElement.ContentType == null) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, Code = ValidationIssueCodes.DataElementCodes.MissingContentType, DataElementId = dataElement.Id, Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.DataElementCodes.MissingContentType, serviceText, null, "nb") }; messages.Add(message); } else { string contentTypeWithoutEncoding = dataElement.ContentType.Split(";")[0]; if (dataType.AllowedContentTypes.All(ct => !ct.Equals(contentTypeWithoutEncoding, StringComparison.OrdinalIgnoreCase))) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, DataElementId = dataElement.Id, Code = ValidationIssueCodes.DataElementCodes.ContentTypeNotAllowed, Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.DataElementCodes.ContentTypeNotAllowed, serviceText, null, "nb") }; messages.Add(message); } } if (dataType.MaxSize.HasValue && dataType.MaxSize > 0 && (long)dataType.MaxSize * 1024 * 1024 < dataElement.Size) { ValidationIssue message = new ValidationIssue { InstanceId = instance.Id, DataElementId = dataElement.Id, Code = ValidationIssueCodes.DataElementCodes.DataElementTooLarge, Severity = ValidationIssueSeverity.Error, Description = ServiceTextHelper.GetServiceText( ValidationIssueCodes.DataElementCodes.DataElementTooLarge, serviceText, null, "nb") }; messages.Add(message); } if (dataType.AppLogic != null) { Type modelType = _altinnApp.GetAppModelType(dataType.AppLogic.ClassRef); Guid instanceGuid = Guid.Parse(instance.Id.Split("/")[1]); string app = instance.AppId.Split("/")[1]; int instanceOwnerPartyId = int.Parse(instance.InstanceOwner.PartyId); dynamic data = _dataService.GetFormData(instanceGuid, modelType, instance.Org, app, instanceOwnerPartyId, Guid.Parse(dataElement.Id)); var context = new ValidationContext(data); List <System.ComponentModel.DataAnnotations.ValidationResult> validationResults = new List <System.ComponentModel.DataAnnotations.ValidationResult>(); bool isValid = await _altinnApp.RunValidation(data.Result, modelType, validationResults); isValid = Validator.TryValidateObject(data, context, validationResults, true) && isValid; if (!isValid) { messages.AddRange(MapModelStateToIssueList(instance, validationResults, dataElement.Id, dataElement.DataType, serviceText)); } } return(messages); }