Skip to content

Commit

Permalink
Merge branch 'main' into chrrust/readstatus
Browse files Browse the repository at this point in the history
  • Loading branch information
Christer Rustand authored Nov 6, 2024
2 parents 2cd8997 + c45bc7c commit 331f378
Show file tree
Hide file tree
Showing 21 changed files with 491 additions and 227 deletions.
33 changes: 21 additions & 12 deletions src/Altinn.App.Api/Controllers/ActionsController.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Altinn.App.Api.Extensions;
using Altinn.App.Api.Infrastructure.Filters;
using Altinn.App.Api.Models;
using Altinn.App.Core.Extensions;
Expand Down Expand Up @@ -172,13 +173,32 @@ await _appMetadata.GetApplicationMetadata(),
);
}

if (dataMutator.AbandonIssues.Count > 0)
if (dataMutator.GetAbandonResponse() is not null)
{
throw new NotImplementedException(
"return an error response from UserActions instead of abandoning the dataMutator"
);
}

#pragma warning disable CS0618 // Type or member is obsolete

// Ensure that the data mutator has the previous binary data for the data elements
// that were updated so that it shows up in diff for validation
// and ensures that it gets saved to storage
if (result.UpdatedDataModels is { Count: > 0 })
{
await Task.WhenAll(
result.UpdatedDataModels.Select(row => dataMutator.GetFormData(new DataElementIdentifier(row.Key)))
);
foreach (var (elementId, data) in result.UpdatedDataModels)
{
// If the data mutator missed a that was returned with the deprecated UpdatedDataModels
// we still need to return it to the frontend, but we assume it was already saved to storage
dataMutator.SetFormData(new DataElementIdentifier(elementId), data);
}
}
#pragma warning restore CS0618 // Type or member is obsolete

var changes = dataMutator.GetDataElementChanges(initializeAltinnRowId: true);

await dataMutator.UpdateInstanceData(changes);
Expand All @@ -198,17 +218,6 @@ await _appMetadata.GetApplicationMetadata(),
c => c.CurrentFormData
);

#pragma warning disable CS0618 // Type or member is obsolete
if (result.UpdatedDataModels is { Count: > 0 })
{
foreach (var (elementId, data) in result.UpdatedDataModels)
{
// If the data mutator missed a that was returned with the deprecated UpdatedDataModels
// we still need to return it to the frontend, but we assume it was already saved to storage
updatedDataModels.TryAdd(elementId, data);
}
}
#pragma warning restore CS0618 // Type or member is obsolete
return Ok(
new UserActionResponse()
{
Expand Down
63 changes: 11 additions & 52 deletions src/Altinn.App.Api/Controllers/DataController.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Globalization;
using System.Net;
using System.Text.Json;
using Altinn.App.Api.Extensions;
using Altinn.App.Api.Helpers;
using Altinn.App.Api.Helpers.Patch;
using Altinn.App.Api.Helpers.RequestHandling;
using Altinn.App.Api.Infrastructure.Filters;
using Altinn.App.Api.Models;
Expand All @@ -16,7 +18,6 @@
using Altinn.App.Core.Internal.AppModel;
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Internal.Instances;
using Altinn.App.Core.Internal.Patch;
using Altinn.App.Core.Internal.Prefill;
using Altinn.App.Core.Internal.Validation;
using Altinn.App.Core.Models;
Expand Down Expand Up @@ -52,7 +53,7 @@ public class DataController : ControllerBase
private readonly IFileAnalysisService _fileAnalyserService;
private readonly IFileValidationService _fileValidationService;
private readonly IFeatureManager _featureManager;
private readonly IPatchService _patchService;
private readonly InternalPatchService _patchService;
private readonly ModelSerializationService _modelDeserializer;

private const long REQUEST_SIZE_LIMIT = 2000 * 1024 * 1024;
Expand Down Expand Up @@ -85,7 +86,7 @@ public DataController(
IFileValidationService fileValidationService,
IAppMetadata appMetadata,
IFeatureManager featureManager,
IPatchService patchService,
InternalPatchService patchService,
ModelSerializationService modelDeserializer
)
{
Expand Down Expand Up @@ -366,14 +367,9 @@ await _patchService.RunDataProcessors(
language
);

if (dataMutator.AbandonIssues.Count > 1)
if (dataMutator.GetAbandonResponse() is { } abandonResponse)
{
return new DataPostErrorResponse(
"Data Processing abandoned",
dataMutator
.AbandonIssues.Select(i => ValidationIssueWithSource.FromIssue(i, "dataProcessing", true))
.ToList()
);
return abandonResponse;
}

var finalChanges = dataMutator.GetDataElementChanges(initializeAltinnRowId: true);
Expand Down Expand Up @@ -715,7 +711,7 @@ public async Task<ActionResult<DataPatchResponseMultiple>> PatchFormDataMultiple
}
}

ServiceResult<DataPatchResult, DataPatchError> res = await _patchService.ApplyPatches(
ServiceResult<DataPatchResult, ProblemDetails> res = await _patchService.ApplyPatches(
instance,
dataPatchRequest.Patches.ToDictionary(i => i.DataElementId, i => i.Patch),
language,
Expand Down Expand Up @@ -800,16 +796,9 @@ await _appMetadata.GetApplicationMetadata(),
var changes = dataMutator.GetDataElementChanges(initializeAltinnRowId: false);
await _patchService.RunDataProcessors(dataMutator, changes, taskId, language);

if (dataMutator.AbandonIssues.Count > 1)
if (dataMutator.GetAbandonResponse() is { } abandonResponse)
{
return BadRequest(
new DataPostErrorResponse(
"DataProcessing abandoned",
dataMutator
.AbandonIssues.Select(i => ValidationIssueWithSource.FromIssue(i, "dataProcessing", true))
.ToList()
)
);
return Problem(abandonResponse);
}
// Get the updated changes for saving
changes = dataMutator.GetDataElementChanges(initializeAltinnRowId: false);
Expand Down Expand Up @@ -1105,16 +1094,9 @@ await _patchService.RunDataProcessors(
);
var jsonAfterDataProcessors = JsonSerializer.Serialize(serviceModel);

if (dataMutator.AbandonIssues.Count > 1)
if (dataMutator.GetAbandonResponse() is { } abandonResponse)
{
return BadRequest(
new DataPostErrorResponse(
"DataProcessing abandoned",
dataMutator
.AbandonIssues.Select(i => ValidationIssueWithSource.FromIssue(i, "dataProcessing", true))
.ToList()
)
);
return Problem(abandonResponse);
}

// Save changes
Expand Down Expand Up @@ -1153,29 +1135,6 @@ private ActionResult HandlePlatformHttpException(PlatformHttpException e, string
};
}

private ObjectResult Problem(DataPatchError error)
{
var code = error.ErrorType switch
{
DataPatchErrorType.PatchTestFailed => HttpStatusCode.Conflict,
DataPatchErrorType.DeserializationFailed => HttpStatusCode.UnprocessableContent,
DataPatchErrorType.AbandonedRequest => HttpStatusCode.BadRequest,
_ => HttpStatusCode.InternalServerError
};

return StatusCode(
(int)code,
new ProblemDetails()
{
Title = error.Title,
Detail = error.Detail,
Type = "https://datatracker.ietf.org/doc/html/rfc6902/",
Status = (int)code,
Extensions = error.Extensions ?? new Dictionary<string, object?>(StringComparer.Ordinal)
}
);
}

private ObjectResult Problem(ProblemDetails error)
{
return StatusCode(error.Status ?? (int)HttpStatusCode.InternalServerError, error);
Expand Down
27 changes: 11 additions & 16 deletions src/Altinn.App.Api/Controllers/InstancesController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Globalization;
using System.Net;
using System.Text.Json;
using Altinn.App.Api.Extensions;
using Altinn.App.Api.Helpers.Patch;
using Altinn.App.Api.Helpers.RequestHandling;
using Altinn.App.Api.Infrastructure.Filters;
using Altinn.App.Api.Mappers;
Expand All @@ -16,7 +18,6 @@
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Internal.Events;
using Altinn.App.Core.Internal.Instances;
using Altinn.App.Core.Internal.Patch;
using Altinn.App.Core.Internal.Prefill;
using Altinn.App.Core.Internal.Process;
using Altinn.App.Core.Internal.Profile;
Expand Down Expand Up @@ -69,7 +70,7 @@ public class InstancesController : ControllerBase
private readonly IOrganizationClient _orgClient;
private readonly IHostEnvironment _env;
private readonly ModelSerializationService _serializationService;
private readonly IPatchService _patchService;
private readonly InternalPatchService _patchService;
private static readonly JsonSerializerOptions _jsonSerializerOptionsWeb = new(JsonSerializerDefaults.Web);
private const long RequestSizeLimit = 2000 * 1024 * 1024;

Expand All @@ -94,7 +95,7 @@ public InstancesController(
IOrganizationClient orgClient,
IHostEnvironment env,
ModelSerializationService serializationService,
IPatchService patchService
InternalPatchService patchService
)
{
_logger = logger;
Expand Down Expand Up @@ -348,6 +349,11 @@ public async Task<ActionResult<Instance>> Post(
var prefillProblem = await StorePrefillParts(instance, application, requestParts, language);
if (prefillProblem is not null)
{
await _instanceClient.DeleteInstance(
int.Parse(instance.InstanceOwner.PartyId, CultureInfo.InvariantCulture),
Guid.Parse(instance.Id.Split("/")[1]),
hard: true
);
return StatusCode(prefillProblem.Status ?? 500, prefillProblem);
}

Expand Down Expand Up @@ -1193,23 +1199,12 @@ string action
var changes = dataMutator.GetDataElementChanges(initializeAltinnRowId: true);
await _patchService.RunDataProcessors(dataMutator, changes, taskId, language);

if (dataMutator.AbandonIssues.Count > 0)
if (dataMutator.GetAbandonResponse() is { } abandonResponse)
{
_logger.LogWarning(
"Data processing failed for one or more data elements, the instance was created, but we try to delete the instance"
);
await _instanceClient.DeleteInstance(
int.Parse(instance.Id.Split("/")[0], CultureInfo.InvariantCulture),
Guid.Parse(instance.Id.Split("/")[1]),
hard: true
);
return new ProblemDetails
{
Title = "Data processing failed",
Detail =
"Data processing failed for one or more data elements, the instance was created, but the data was ignored",
Extensions = { { "issues", dataMutator.AbandonIssues }, { "instance", instance } }
};
return abandonResponse;
}

// Update the changes list if it changed in data processors
Expand Down
34 changes: 34 additions & 0 deletions src/Altinn.App.Api/Extensions/InstanceDataUnitOfWorkExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Altinn.App.Core.Internal.Data;
using Altinn.App.Core.Models.Validation;
using Microsoft.AspNetCore.Mvc;

namespace Altinn.App.Api.Extensions;

internal static class InstanceDataUnitOfWorkExtensions
{
internal class FileValidationIssueProblemDetails : ProblemDetails
{
public List<ValidationIssueWithSource>? UploadValidationIssues { get; set; }
}

public static ProblemDetails? GetAbandonResponse(this InstanceDataUnitOfWork instanceDataUnitOfWork)
{
if (instanceDataUnitOfWork.HasAbandonIssues)
{
var issues = instanceDataUnitOfWork
.AbandonIssues.Select(issue =>
ValidationIssueWithSource.FromIssue(issue, "DataProcessorAbandon", noIncrementalUpdates: false)
)
.ToList();
return new FileValidationIssueProblemDetails
{
Title = "File validation failed",
Detail = "Validation issues were found in the file upload",
Status = 400,
UploadValidationIssues = issues,
};
}

return null;
}
}
2 changes: 2 additions & 0 deletions src/Altinn.App.Api/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Altinn.App.Api.Controllers.Attributes;
using Altinn.App.Api.Controllers.Conventions;
using Altinn.App.Api.Helpers;
using Altinn.App.Api.Helpers.Patch;
using Altinn.App.Api.Infrastructure.Filters;
using Altinn.App.Api.Infrastructure.Health;
using Altinn.App.Api.Infrastructure.Middleware;
Expand Down Expand Up @@ -101,6 +102,7 @@ IWebHostEnvironment env
AddAntiforgery(services);

services.AddSingleton<IAuthorizationHandler, AppAccessHandler>();
services.AddTransient<InternalPatchService>();

services.Configure<KestrelServerOptions>(options =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
using Altinn.App.Core.Models.Validation;
using Altinn.Platform.Storage.Interface.Models;

namespace Altinn.App.Core.Internal.Patch;
namespace Altinn.App.Api.Helpers.Patch;

/// <summary>
/// Result of a data patch operation in the <see cref="IPatchService"/>.
/// Result of a data patch operation in the <see cref="InternalPatchService"/>.
/// </summary>
public class DataPatchResult
{
/// <summary>
/// The updated instance after the patch and dataProcessing operations.
/// </summary>
public required Instance Instance { get; set; }
public required Instance Instance { get; init; }

/// <summary>
/// The validation issues that were found during the patch operation.
Expand All @@ -23,11 +23,4 @@ public class DataPatchResult
/// Get updated data elements that have app logic in a dictionary with the data element id as key.
/// </summary>
public required DataElementChanges FormDataChanges { get; init; }

/// <summary>
/// Store a pair with Id and Data
/// </summary>
/// <param name="Identifier">The data element id</param>
/// <param name="Data">The deserialized data</param>
public record DataModelPair(DataElementIdentifier Identifier, object Data);
}
Loading

0 comments on commit 331f378

Please sign in to comment.