From 159f0e0cf7ffd8ddfa649a18fa5395ace4e7cc19 Mon Sep 17 00:00:00 2001 From: Ivar Nesje Date: Tue, 12 Dec 2023 21:11:22 +0100 Subject: [PATCH] Add DataType as input to validators --- .../Validation/IDataElementValidator.cs | 20 ++++++++++++++++++- .../Features/Validation/IValidationService.cs | 9 +++++++-- .../Features/Validation/ValidationService.cs | 6 +++--- .../Validators/ValidationServiceTests.cs | 8 ++++---- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/Altinn.App.Core/Features/Validation/IDataElementValidator.cs b/src/Altinn.App.Core/Features/Validation/IDataElementValidator.cs index 1efce28c8..ba4da23df 100644 --- a/src/Altinn.App.Core/Features/Validation/IDataElementValidator.cs +++ b/src/Altinn.App.Core/Features/Validation/IDataElementValidator.cs @@ -7,14 +7,32 @@ namespace Altinn.App.Core.Features.Validation; /// Validator for data elements. /// See for an alternative validator for data elements with app logic. /// and that support incremental validation on save. +/// For validating the content of files, see and /// public interface IDataElementValidator { + /// + /// The data type that this validator should run for. This is the id of the data type from applicationmetadata.json + /// + /// + /// Used by default in . Overrides might ignore this. + /// + string DataType { get; } + /// + /// Override this method to customize what data elements this validator should run for. + /// bool CanValidateDataType(DataType dataType) { return DataType == dataType.Id; } - string DataType { get; } + + /// + /// Run validations for a data element. This is supposed to run quickly + /// + /// The instance to validate + /// + /// + /// public Task> ValidateDataElement(Instance instance, DataElement dataElement, DataType dataType); } \ No newline at end of file diff --git a/src/Altinn.App.Core/Features/Validation/IValidationService.cs b/src/Altinn.App.Core/Features/Validation/IValidationService.cs index 75bd19675..1f9ac0739 100644 --- a/src/Altinn.App.Core/Features/Validation/IValidationService.cs +++ b/src/Altinn.App.Core/Features/Validation/IValidationService.cs @@ -39,10 +39,15 @@ public interface IValidationService Task> ValidateDataElement(Instance instance, DataElement dataElement, DataType dataType); /// - /// Validates a single data element. Used by frontend to continuously validate form data. + /// Validates a single data element. Used by frontend to continuously validate form data as it changes. /// /// /// This method executes validations for /// - Task>> ValidateFormData(Instance instance, DataElement dataElement, object data, List? changedFields = null); + /// The instance to validate + /// The data element to run validations for + /// The type of the data element + /// The data deserialized to the strongly typed object that represents the form data + /// List of json paths for the fields that have changed (used for incremental validation) + Task>> ValidateFormData(Instance instance, DataElement dataElement, DataType dataType, object data, List? changedFields = null); } \ No newline at end of file diff --git a/src/Altinn.App.Core/Features/Validation/ValidationService.cs b/src/Altinn.App.Core/Features/Validation/ValidationService.cs index 6fb8ff537..4280cd386 100644 --- a/src/Altinn.App.Core/Features/Validation/ValidationService.cs +++ b/src/Altinn.App.Core/Features/Validation/ValidationService.cs @@ -105,7 +105,7 @@ public async Task> ValidateDataElement(Instance instance, string app = instance.AppId.Split("/")[1]; int instanceOwnerPartyId = int.Parse(instance.InstanceOwner.PartyId); var data = await _dataClient.GetFormData(instanceGuid, modelType, instance.Org, app, instanceOwnerPartyId, Guid.Parse(dataElement.Id)); // TODO: Add method that accepts instance and dataElement - var formDataIssuesDictionary = await ValidateFormData(instance, dataElement, data, null); + var formDataIssuesDictionary = await ValidateFormData(instance, dataElement, dataType, data, null); return (await dataElementsIssuesTask).SelectMany(x=>x) .Concat(formDataIssuesDictionary.SelectMany(kv=>kv.Value)) @@ -117,7 +117,7 @@ public async Task> ValidateDataElement(Instance instance, /// public async Task>> ValidateFormData(Instance instance, - DataElement dataElement, object data, List? changedFields = null) + DataElement dataElement, DataType dataType, object data, List? changedFields = null) { ArgumentNullException.ThrowIfNull(instance); ArgumentNullException.ThrowIfNull(dataElement); @@ -141,7 +141,7 @@ public async Task>> ValidateFormData(In try { _logger.LogDebug("Start running validator {validatorName} on {dataType} for data element {dataElementId} in instance {instanceId}", v.GetType().Name, dataElement.DataType, dataElement.Id, instance.Id); - var issues = await v.ValidateFormData(instance,dataElement, data, changedFields); + var issues = await v.ValidateFormData(instance, dataElement, data, changedFields); if (v.Code is not null) { issues.ForEach(i=>i.Code = v.Code);// Ensure that the code is set to the validator code diff --git a/test/Altinn.App.Core.Tests/Features/Validators/ValidationServiceTests.cs b/test/Altinn.App.Core.Tests/Features/Validators/ValidationServiceTests.cs index 0b50d998f..37afdd1b2 100644 --- a/test/Altinn.App.Core.Tests/Features/Validators/ValidationServiceTests.cs +++ b/test/Altinn.App.Core.Tests/Features/Validators/ValidationServiceTests.cs @@ -69,7 +69,7 @@ public async Task ValidateFormData_WithNoValidators_ReturnsNoErrors() var validatorService = serviceProvider.GetRequiredService(); var data = new MyModel { Name = "Ola" }; - var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, data); + var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, null!, data); result.Should().BeEmpty(); } @@ -81,7 +81,7 @@ public async Task ValidateFormData_WithMyNameValidator_ReturnsNoErrorsWhenNameIs var validatorService = serviceProvider.GetRequiredService(); var data = new MyModel { Name = "Ola" }; - var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, data); + var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, null!, data); result.Should().ContainKey("Altinn.App.Core.Tests.Features.Validators.ValidationServiceTests+MyNameValidator-MyType").WhoseValue.Should().HaveCount(0); result.Should().HaveCount(1); } @@ -94,7 +94,7 @@ public async Task ValidateFormData_WithMyNameValidator_ReturnsErrorsWhenNameIsKa var validatorService = serviceProvider.GetRequiredService(); var data = new MyModel { Name = "Kari" }; - var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, data); + var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, null!, data); result.Should().ContainKey("Altinn.App.Core.Tests.Features.Validators.ValidationServiceTests+MyNameValidator-MyType").WhoseValue.Should().ContainSingle().Which.CustomTextKey.Should().Be("NameNotOla"); result.Should().HaveCount(1); } @@ -107,7 +107,7 @@ public async Task ValidateFormData_WithMyNameValidator_ReturnsNoErrorsWhenOnlyAg var validatorService = serviceProvider.GetRequiredService(); var data = new MyModel { Name = "Kari" }; - var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, data, new List { "age" }); + var result = await validatorService.ValidateFormData(new Instance(), DefaultDataElement, null!, data, new List { "age" }); result.Should() .NotContainKey("Altinn.App.Core.Tests.Features.Validators.ValidationServiceTests+MyNameValidator"); result.Should().HaveCount(0);