Skip to content

Commit

Permalink
Save half finished work
Browse files Browse the repository at this point in the history
* new interface IValidator to rule them all
* Incremental validation is now a separate interface
* Try to add compatibility
  • Loading branch information
ivarne committed Jun 24, 2024
1 parent a73239f commit 3b8d8ec
Show file tree
Hide file tree
Showing 21 changed files with 779 additions and 382 deletions.
39 changes: 20 additions & 19 deletions src/Altinn.App.Api/Controllers/ActionsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Altinn.App.Core.Features.Action;
using Altinn.App.Core.Helpers;
using Altinn.App.Core.Internal.App;
using Altinn.App.Core.Internal.AppModel;
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Internal.Instances;
using Altinn.App.Core.Internal.Validation;
Expand Down Expand Up @@ -33,31 +34,27 @@ public class ActionsController : ControllerBase
private readonly IValidationService _validationService;
private readonly IDataClient _dataClient;
private readonly IAppMetadata _appMetadata;
private readonly IAppModel _appModel;

/// <summary>
/// Create new instance of the <see cref="ActionsController"/> class
/// </summary>
/// <param name="authorization">The authorization service</param>
/// <param name="instanceClient">The instance client</param>
/// <param name="userActionService">The user action service</param>
/// <param name="validationService">Service for performing validations of user data</param>
/// <param name="dataClient">Client for accessing data in storage</param>
/// <param name="appMetadata">Service for getting application metadata</param>
public ActionsController(
IAuthorizationService authorization,
IInstanceClient instanceClient,
UserActionService userActionService,
IValidationService validationService,
IDataClient dataClient,
IAppMetadata appMetadata
)
IAppMetadata appMetadata,
IAppModel appModel)
{
_authorization = authorization;
_instanceClient = instanceClient;
_userActionService = userActionService;
_validationService = validationService;
_dataClient = dataClient;
_appMetadata = appMetadata;
_appModel = appModel;
}

/// <summary>
Expand Down Expand Up @@ -166,7 +163,7 @@ public async Task<ActionResult<UserActionResponse>> Perform(
{
await SaveChangedModels(instance, result.UpdatedDataModels);
}

IInstanceDataAccessor dataAccessor = new CachedInstanceDataAccessor(_dataClient, _appMetadata, _appModel);
return new OkObjectResult(
new UserActionResponse()
{
Expand All @@ -175,6 +172,7 @@ public async Task<ActionResult<UserActionResponse>> Perform(
UpdatedValidationIssues = await GetValidations(
instance,
result.UpdatedDataModels,
dataAccessor,
actionRequest.IgnoredValidators,
language
),
Expand Down Expand Up @@ -212,11 +210,12 @@ await _dataClient.UpdateData(
private async Task<Dictionary<string, Dictionary<string, List<ValidationIssue>>>?> GetValidations(
Instance instance,
Dictionary<string, object>? resultUpdatedDataModels,
IInstanceDataAccessor dataAccessor,
List<string>? ignoredValidators,
string? language
)
{
if (resultUpdatedDataModels is null || resultUpdatedDataModels.Count < 1)
if (resultUpdatedDataModels is null || resultUpdatedDataModels.Count == 0)
{
return null;
}
Expand Down Expand Up @@ -249,21 +248,23 @@ await _dataClient.UpdateData(
Guid.Parse(dataElement.Id)
);

var validationIssues = await _validationService.ValidateFormData(
instance,
dataElement,
dataType,
newModel,
oldData,
ignoredValidators,
language
);
if (validationIssues.Count > 0)
{
updatedValidationIssues.Add(elementId, validationIssues);
}
}

var taskId = instance.Process.CurrentTask.ElementId;
var validationIssues = await _validationService.ValidateIncrementalFormData(instance, taskId, changes,
dataAccessor, ignoredValidators, language);








return updatedValidationIssues;
}
}
97 changes: 76 additions & 21 deletions src/Altinn.App.Api/Controllers/DataController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,53 @@ public async Task<ActionResult<DataPatchResponse>> PatchFormData(
[FromBody] DataPatchRequest dataPatchRequest,
[FromQuery] string? language = null
)
{
var request = new DataPatchRequestMultiple()
{
Patches = new() { [dataGuid] = dataPatchRequest.Patch },
IgnoredValidators = dataPatchRequest.IgnoredValidators
};
var response = await PatchFormDataMultiple(org, app, instanceOwnerPartyId, instanceGuid, request, language);

if (response.Result is OkObjectResult { Value: DataPatchResponseMultiple newResponse })
{
// Map the new response to the old response
return Ok(
new DataPatchResponse()
{
ValidationIssues = newResponse.ValidationIssues,
NewDataModel = newResponse.NewDataModels[dataGuid],
}
);
}

// Return the error object unchanged
return response.Result ?? throw new InvalidOperationException("Response is null");
}

/// <summary>
/// Updates an existing form data element with a patch of changes.
/// </summary>
/// <param name="org">unique identfier of the organisation responsible for the app</param>
/// <param name="app">application identifier which is unique within an organisation</param>
/// <param name="instanceOwnerPartyId">unique id of the party that is the owner of the instance</param>
/// <param name="instanceGuid">unique id to identify the instance</param>
/// <param name="dataPatchRequest">Container object for the <see cref="JsonPatch" /> and list of ignored validators</param>
/// <param name="language">The language selected by the user.</param>
/// <returns>A response object with the new full model and validation issues from all the groups that run</returns>
[Authorize(Policy = AuthzConstants.POLICY_INSTANCE_WRITE)]
[HttpPatch]
[ProducesResponseType(typeof(DataPatchResponseMultiple), 200)]
[ProducesResponseType(typeof(ProblemDetails), 409)]
[ProducesResponseType(typeof(ProblemDetails), 422)]
public async Task<ActionResult<DataPatchResponseMultiple>> PatchFormDataMultiple(
[FromRoute] string org,
[FromRoute] string app,
[FromRoute] int instanceOwnerPartyId,
[FromRoute] Guid instanceGuid,
[FromBody] DataPatchRequestMultiple dataPatchRequest,
[FromQuery] string? language = null
)
{
try
{
Expand All @@ -464,39 +511,47 @@ public async Task<ActionResult<DataPatchResponse>> PatchFormData(
);
}

var dataElement = instance.Data.First(m => m.Id.Equals(dataGuid.ToString(), StringComparison.Ordinal));

if (dataElement == null)
foreach (Guid dataGuid in dataPatchRequest.Patches.Keys)
{
return NotFound("Did not find data element");
}
var dataElement = instance.Data.First(m => m.Id.Equals(dataGuid.ToString(), StringComparison.Ordinal));

var dataType = await GetDataType(dataElement);
if (dataElement == null)
{
return NotFound("Did not find data element");
}

if (dataType?.AppLogic?.ClassRef is null)
{
_logger.LogError(
"Could not determine if {dataType} requires app logic for application {org}/{app}",
dataType,
org,
app
);
return BadRequest($"Could not determine if data type {dataType?.Id} requires application logic.");
var dataType = await GetDataType(dataElement);

if (dataType?.AppLogic?.ClassRef is null)
{
_logger.LogError(
"Could not determine if {dataType} requires app logic for application {org}/{app}",
dataType,
org,
app
);
return BadRequest($"Could not determine if data type {dataType?.Id} requires application logic.");
}
}

ServiceResult<DataPatchResult, DataPatchError> res = await _patchService.ApplyPatch(
ServiceResult<DataPatchResultMultiple, DataPatchError> res = await _patchService.ApplyPatches(
instance,
dataType,
dataElement,
dataPatchRequest.Patch,
dataPatchRequest.Patches,
language,
dataPatchRequest.IgnoredValidators
);

if (res.Success)
{
await UpdateDataValuesOnInstance(instance, dataType.Id, res.Ok.NewDataModel);
await UpdatePresentationTextsOnInstance(instance, dataType.Id, res.Ok.NewDataModel);
foreach (var dataGuid in dataPatchRequest.Patches.Keys)
{
await UpdateDataValuesOnInstance(instance, dataGuid.ToString(), res.Ok.NewDataModels[dataGuid]);
await UpdatePresentationTextsOnInstance(
instance,
dataGuid.ToString(),
res.Ok.NewDataModels[dataGuid]
);
}

return Ok(
new DataPatchResponse
Expand Down
22 changes: 20 additions & 2 deletions src/Altinn.App.Api/Controllers/ProcessController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
using Altinn.App.Api.Infrastructure.Filters;
using Altinn.App.Api.Models;
using Altinn.App.Core.Helpers;
using Altinn.App.Core.Internal.App;
using Altinn.App.Core.Internal.AppModel;
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Internal.Instances;
using Altinn.App.Core.Internal.Process;
using Altinn.App.Core.Internal.Process.Elements;
Expand Down Expand Up @@ -37,6 +40,9 @@ public class ProcessController : ControllerBase
private readonly IAuthorizationService _authorization;
private readonly IProcessEngine _processEngine;
private readonly IProcessReader _processReader;
private readonly IDataClient _dataClient;
private readonly IAppMetadata _appMetadata;
private readonly IAppModel _appModel;

/// <summary>
/// Initializes a new instance of the <see cref="ProcessController"/>
Expand All @@ -48,7 +54,10 @@ public ProcessController(
IValidationService validationService,
IAuthorizationService authorization,
IProcessReader processReader,
IProcessEngine processEngine
IProcessEngine processEngine,
IDataClient dataClient,
IAppMetadata appMetadata,
IAppModel appModel
)
{
_logger = logger;
Expand All @@ -58,6 +67,9 @@ IProcessEngine processEngine
_authorization = authorization;
_processReader = processReader;
_processEngine = processEngine;
_dataClient = dataClient;
_appMetadata = appMetadata;
_appModel = appModel;
}

/// <summary>
Expand Down Expand Up @@ -236,7 +248,13 @@ [FromRoute] Guid instanceGuid
string? language
)
{
var validationIssues = await _validationService.ValidateInstanceAtTask(instance, currentTaskId, language);
var dataAcceesor = new CachedInstanceDataAccessor(_dataClient, _appMetadata, _appModel);
var validationIssues = await _validationService.ValidateInstanceAtTask(
instance,
currentTaskId,
dataAcceesor,
language
);
var success = validationIssues.TrueForAll(v => v.Severity != ValidationIssueSeverity.Error);

if (!success)
Expand Down
Loading

0 comments on commit 3b8d8ec

Please sign in to comment.