Skip to content

Commit

Permalink
Simplify File analysis/validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ivarne committed Dec 12, 2023
1 parent 159f0e0 commit 91bfcd1
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 332 deletions.
52 changes: 13 additions & 39 deletions src/Altinn.App.Api/Controllers/DataController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
using Altinn.App.Core.Constants;
using Altinn.App.Core.Extensions;
using Altinn.App.Core.Features;
using Altinn.App.Core.Features.FileAnalysis;
using Altinn.App.Core.Features.FileAnalyzis;
using Altinn.App.Core.Features.Validation;
using Altinn.App.Core.Helpers;
using Altinn.App.Core.Helpers.Serialization;
Expand Down Expand Up @@ -46,9 +44,8 @@ public class DataController : ControllerBase
private readonly IAppResources _appResourcesService;
private readonly IAppMetadata _appMetadata;
private readonly IPrefill _prefillService;
private readonly IFileAnalysisService _fileAnalyserService;
private readonly IFileValidationService _fileValidationService;
private readonly IFeatureManager _featureManager;
private readonly IValidationService _validationService;
private const long REQUEST_SIZE_LIMIT = 2000 * 1024 * 1024;

/// <summary>
Expand All @@ -64,8 +61,7 @@ public class DataController : ControllerBase
/// <param name="appMetadata">The app metadata service</param>
/// <param name="featureManager">The feature manager controlling enabled features.</param>
/// <param name="prefillService">A service with prefill related logic.</param>
/// <param name="fileAnalyserService">Service used to analyse files uploaded.</param>
/// <param name="fileValidationService">Service used to validate files uploaded.</param>
/// <param name="validationService">Service used to validate files uploaded.</param>
public DataController(
ILogger<DataController> logger,
IInstanceClient instanceClient,
Expand All @@ -75,10 +71,9 @@ public DataController(
IAppModel appModel,
IAppResources appResourcesService,
IPrefill prefillService,
IFileAnalysisService fileAnalyserService,
IFileValidationService fileValidationService,
IAppMetadata appMetadata,
IFeatureManager featureManager)
IFeatureManager featureManager,
IValidationService validationService)
{
_logger = logger;

Expand All @@ -90,9 +85,8 @@ public DataController(
_appResourcesService = appResourcesService;
_appMetadata = appMetadata;
_prefillService = prefillService;
_fileAnalyserService = fileAnalyserService;
_fileValidationService = fileValidationService;
_featureManager = featureManager;
_validationService = validationService;
}

/// <summary>
Expand Down Expand Up @@ -161,9 +155,8 @@ public async Task<ActionResult> Create(

StreamContent streamContent = Request.CreateContentStream();

using Stream fileStream = new MemoryStream();
await streamContent.CopyToAsync(fileStream);
if (fileStream.Length == 0)
var fileBytes = await streamContent.ReadAsByteArrayAsync();
if (fileBytes.Length == 0)
{
const string errorMessage = "Invalid data provided. Error: The file is zero bytes.";
var error = new ValidationIssue
Expand All @@ -179,25 +172,14 @@ public async Task<ActionResult> Create(
bool parseSuccess = Request.Headers.TryGetValue("Content-Disposition", out StringValues headerValues);
string? filename = parseSuccess ? DataRestrictionValidation.GetFileNameFromHeader(headerValues) : null;

IEnumerable<FileAnalysisResult> fileAnalysisResults = new List<FileAnalysisResult>();
if (FileAnalysisEnabledForDataType(dataTypeFromMetadata))
{
fileAnalysisResults = await _fileAnalyserService.Analyse(dataTypeFromMetadata, fileStream, filename);
}

bool fileValidationSuccess = true;
List<ValidationIssue> validationIssues = new();
if (FileValidationEnabledForDataType(dataTypeFromMetadata))
{
(fileValidationSuccess, validationIssues) = await _fileValidationService.Validate(dataTypeFromMetadata, fileAnalysisResults);
}
var fileAnalysisResults = await _validationService.ValidateFileUpload(instance, dataTypeFromMetadata, fileBytes, filename);

if (!fileValidationSuccess)
if (!fileAnalysisResults.All(r => r.Severity is ValidationIssueSeverity.Informational or ValidationIssueSeverity.Fixed))
{
return BadRequest(await GetErrorDetails(validationIssues));
return BadRequest(await GetErrorDetails(fileAnalysisResults));
}

fileStream.Seek(0, SeekOrigin.Begin);
using var fileStream = new MemoryStream(fileBytes);
return await CreateBinaryData(instance, dataType, streamContent.Headers.ContentType.ToString(), filename, fileStream);
}
}
Expand All @@ -220,16 +202,6 @@ private async Task<object> GetErrorDetails(List<ValidationIssue> errors)
return await _featureManager.IsEnabledAsync(FeatureFlags.JsonObjectInDataResponse) ? errors : string.Join(";", errors.Select(x => x.Description));
}

private static bool FileAnalysisEnabledForDataType(DataType dataTypeFromMetadata)
{
return dataTypeFromMetadata.EnabledFileAnalysers != null && dataTypeFromMetadata.EnabledFileAnalysers.Count > 0;
}

private static bool FileValidationEnabledForDataType(DataType dataTypeFromMetadata)
{
return dataTypeFromMetadata.EnabledFileValidators != null && dataTypeFromMetadata.EnabledFileValidators.Count > 0;
}

/// <summary>
/// Gets a data element from storage and applies business logic if nessesary.
/// </summary>
Expand Down Expand Up @@ -296,6 +268,8 @@ public async Task<ActionResult> Get(
/// <param name="dataGuid">unique id to identify the data element to update</param>
/// <returns>The updated data element, including the changed fields in the event of a calculation that changed data.</returns>
[Authorize(Policy = AuthzConstants.POLICY_INSTANCE_WRITE)]

// "{org}/{app}/instances/{instanceOwnerPartyId:int}/{instanceGuid:guid}/data/form/{dataGuid:guid}"
[HttpPut("{dataGuid:guid}")]
[DisableFormValueModelBinding]
[RequestSizeLimit(REQUEST_SIZE_LIMIT)]
Expand Down
15 changes: 0 additions & 15 deletions src/Altinn.App.Core/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Altinn.App.Core.Features.Action;
using Altinn.App.Core.Features.DataLists;
using Altinn.App.Core.Features.DataProcessing;
using Altinn.App.Core.Features.FileAnalyzis;
using Altinn.App.Core.Features.Options;
using Altinn.App.Core.Features.PageOrder;
using Altinn.App.Core.Features.Pdf;
Expand Down Expand Up @@ -163,8 +162,6 @@ public static void AddAppServices(this IServiceCollection services, IConfigurati
AddPdfServices(services);
AddEventServices(services);
AddProcessServices(services);
AddFileAnalyserServices(services);
AddFileValidatorServices(services);
AddMetricsDecorators(services, configuration);

if (!env.IsDevelopment())
Expand Down Expand Up @@ -255,18 +252,6 @@ private static void AddActionServices(IServiceCollection services)
services.AddTransientUserActionAuthorizerForActionInAllTasks<UniqueSignatureAuthorizer>("sign");
}

private static void AddFileAnalyserServices(IServiceCollection services)
{
services.TryAddTransient<IFileAnalysisService, FileAnalysisService>();
services.TryAddTransient<IFileAnalyserFactory, FileAnalyserFactory>();
}

private static void AddFileValidatorServices(IServiceCollection services)
{
services.TryAddTransient<IFileValidationService, FileValidationService>();
services.TryAddTransient<IFileValidatorFactory, FileValidatorFactory>();
}

private static void AddMetricsDecorators(IServiceCollection services, IConfiguration configuration)
{
MetricsSettings metricsSettings = configuration.GetSection("MetricsSettings")?.Get<MetricsSettings>() ?? new MetricsSettings();
Expand Down
41 changes: 41 additions & 0 deletions src/Altinn.App.Core/Features/FileAnalysis/FileAnalysisResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace Altinn.App.Core.Features.FileAnalysis;

/// <summary>
/// Results from a file analysis done based the content of the file, ie. the binary data.
/// </summary>
public class FileAnalysisResult
{
/// <summary>
/// Initializes a new instance of the <see cref="FileAnalysisService"/> class.
/// </summary>
public FileAnalysisResult(string analyserId)
{
AnalyserId = analyserId;
}

/// <summary>
/// The id of the analyser generating the result.
/// </summary>
public string AnalyserId { get; internal set; }

/// <summary>
/// The name of the analysed file.
/// </summary>
public string? Filename { get; set; }

/// <summary>
/// The file extension(s) without the . i.e. pdf | png | docx
/// Some mime types might have multiple extensions registered for ecample image/jpeg has both jpg and jpeg.
/// </summary>
public List<string> Extensions { get; set; } = new List<string>();

/// <summary>
/// The mime type
/// </summary>
public string? MimeType { get; set; }

/// <summary>
/// Key/Value pairs containing findings from the analysis.
/// </summary>
public IDictionary<string, string> Metadata { get; private set; } = new Dictionary<string, string>();
}
19 changes: 19 additions & 0 deletions src/Altinn.App.Core/Features/FileAnalysis/IFileAnalyser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Altinn.App.Core.Features.FileAnalysis;

/// <summary>
/// Interface for doing extended binary file analysing.
/// </summary>
public interface IFileAnalyser
{
/// <summary>
/// The id of the analyser to be used when enabling it from config.
/// </summary>
public string Id { get; }

/// <summary>
/// Analyses a stream with the intent to extract metadata.
/// </summary>
/// <param name="stream">The stream to analyse. One stream = one file.</param>
/// <param name="filename">Filename. Optional parameter if the implementation needs the name of the file, relative or absolute path.</param>
public Task<FileAnalysisResult> Analyse(Stream stream, string? filename = null);
}
29 changes: 0 additions & 29 deletions src/Altinn.App.Core/Features/FileAnalyzis/FileAnalyserFactory.cs

This file was deleted.

44 changes: 0 additions & 44 deletions src/Altinn.App.Core/Features/FileAnalyzis/FileAnalysisResult.cs

This file was deleted.

44 changes: 0 additions & 44 deletions src/Altinn.App.Core/Features/FileAnalyzis/FileAnalysisService.cs

This file was deleted.

20 changes: 0 additions & 20 deletions src/Altinn.App.Core/Features/FileAnalyzis/IFileAnalyser.cs

This file was deleted.

16 changes: 0 additions & 16 deletions src/Altinn.App.Core/Features/FileAnalyzis/IFileAnalyserFactory.cs

This file was deleted.

Loading

0 comments on commit 91bfcd1

Please sign in to comment.