-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #59 from DEFRA/feature/cdms-165
Added the ability to redact data without Deserializing to an object.
- Loading branch information
Showing
12 changed files
with
366 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
using System.Dynamic; | ||
using System.IO; | ||
using System.IO.Compression; | ||
using System.Text.Json.Serialization; | ||
using Bogus; | ||
using Cdms.BlobService; | ||
using System.Threading; | ||
using MediatR; | ||
using Newtonsoft.Json; | ||
using JsonSerializer = System.Text.Json.JsonSerializer; | ||
using SharpCompress.Writers; | ||
using Cdms.SensitiveData; | ||
using Cdms.Types.Ipaffs; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Cdms.SyncJob; | ||
using Cdms.Types.Alvs; | ||
using Cdms.Types.Gvms; | ||
|
||
namespace Cdms.Business.Commands; | ||
|
||
public class DownloadCommand : IRequest, ISyncJob | ||
{ | ||
[System.Text.Json.Serialization.JsonConverter(typeof(JsonStringEnumConverter<SyncPeriod>))] | ||
public SyncPeriod SyncPeriod { get; set; } | ||
|
||
public Guid JobId { get; } = Guid.NewGuid(); | ||
public string Timespan { get; } = null!; | ||
public string Resource { get; } = null!; | ||
|
||
internal class Handler(IBlobService blobService, ISensitiveDataSerializer sensitiveDataSerializer, IWebHostEnvironment env) : IRequestHandler<DownloadCommand> | ||
{ | ||
|
||
public async Task Handle(DownloadCommand request, CancellationToken cancellationToken) | ||
{ | ||
string subFolder = $"temp\\{request.JobId}"; | ||
string rootFolder = Path.Combine(env.ContentRootPath, subFolder); | ||
Directory.CreateDirectory(rootFolder); | ||
|
||
await Download(request, rootFolder, "RAW/IPAFFS/CHEDA", typeof(ImportNotification), cancellationToken); | ||
await Download(request, rootFolder, "RAW/IPAFFS/CHEDD", typeof(ImportNotification), cancellationToken); | ||
await Download(request, rootFolder, "RAW/IPAFFS/CHEDP", typeof(ImportNotification), cancellationToken); | ||
await Download(request, rootFolder, "RAW/IPAFFS/CHEDPP", typeof(ImportNotification), cancellationToken); | ||
|
||
await Download(request, rootFolder, "RAW/ALVS", typeof(AlvsClearanceRequest), cancellationToken); | ||
|
||
await Download(request, rootFolder, "RAW/GVMSAPIRESPONSE", typeof(SearchGmrsForDeclarationIdsResponse), cancellationToken); | ||
|
||
await Download(request, rootFolder, "RAW/DECISIONS", typeof(AlvsClearanceRequest), cancellationToken); | ||
|
||
ZipFile.CreateFromDirectory(rootFolder, $"{env.ContentRootPath}\\{request.JobId}.zip"); | ||
|
||
Directory.Delete(rootFolder, true); | ||
} | ||
|
||
private async Task Download(DownloadCommand request, string rootFolder, string folder, Type type, CancellationToken cancellationToken) | ||
{ | ||
|
||
ParallelOptions options = new() { CancellationToken = cancellationToken, MaxDegreeOfParallelism = 10 }; | ||
var result = blobService.GetResourcesAsync($"{folder}{request.SyncPeriod.GetPeriodPath()}", cancellationToken); | ||
|
||
//Write local files | ||
await Parallel.ForEachAsync(result, options, async (item, token) => | ||
{ | ||
var blobContent = await blobService.GetResource(item, cancellationToken); | ||
string redactedContent = sensitiveDataSerializer.RedactRawJson(blobContent, type); | ||
var filename = System.IO.Path.Combine(rootFolder, item.Name.Replace('/', System.IO.Path.DirectorySeparatorChar)); | ||
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filename)!); | ||
await File.WriteAllTextAsync(filename, redactedContent, cancellationToken); | ||
}); | ||
} | ||
|
||
} | ||
|
||
public record Result(byte[] Zip); | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
namespace Cdms.Business.Commands; | ||
|
||
public static class SyncPeriodExtensions | ||
{ | ||
public static string GetPeriodPath(this SyncPeriod period) | ||
{ | ||
if (period == SyncPeriod.LastMonth) | ||
{ | ||
return DateTime.Today.AddMonths(-1).ToString("/yyyy/MM/"); | ||
} | ||
else if (period == SyncPeriod.ThisMonth) | ||
{ | ||
return DateTime.Today.ToString("/yyyy/MM/"); | ||
} | ||
else if (period == SyncPeriod.Today) | ||
{ | ||
return DateTime.Today.ToString("/yyyy/MM/dd/"); | ||
} | ||
else if (period == SyncPeriod.All) | ||
{ | ||
return "/"; | ||
} | ||
else | ||
{ | ||
throw new ArgumentException($"Unexpected SyncPeriod {period}"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
using System.Reflection; | ||
using System.Text.Json; | ||
|
||
namespace Cdms.SensitiveData; | ||
|
||
public static class SensitiveFieldsProvider | ||
{ | ||
private static Dictionary<Type, List<string>> cache = new(); | ||
private static readonly object cacheLock = new (); | ||
public static List<string> Get<T>() | ||
{ | ||
lock (cacheLock) | ||
{ | ||
if (cache.TryGetValue(typeof(T), out var value)) | ||
{ | ||
return value; | ||
} | ||
|
||
var type = typeof(T); | ||
|
||
var list = GetSensitiveFields(string.Empty, type); | ||
cache.Add(typeof(T), list); | ||
return list; | ||
} | ||
|
||
|
||
} | ||
|
||
public static List<string> Get(Type type) | ||
{ | ||
lock (cacheLock) | ||
{ | ||
if (cache.TryGetValue(type, out var value)) | ||
{ | ||
return value; | ||
} | ||
|
||
var list = GetSensitiveFields(string.Empty, type); | ||
cache.Add(type, list); | ||
return list; | ||
} | ||
|
||
|
||
} | ||
|
||
private static List<string> GetSensitiveFields(string root, Type type) | ||
{ | ||
var namingPolicy = JsonNamingPolicy.CamelCase; | ||
var list = new List<string>(); | ||
foreach (var property in type.GetProperties()) | ||
{ | ||
string currentPath; | ||
currentPath = string.IsNullOrEmpty(root) ? $"{namingPolicy.ConvertName(property.Name)}" : $"{namingPolicy.ConvertName(root)}.{namingPolicy.ConvertName(property.Name)}"; | ||
|
||
if (property.CustomAttributes.Any(x => x.AttributeType == typeof(SensitiveDataAttribute))) | ||
{ | ||
list.Add(currentPath); | ||
} | ||
else | ||
{ | ||
Type elementType = GetElementType(property)!; | ||
|
||
if (elementType != null && elementType.Namespace != "System") | ||
{ | ||
list.AddRange(GetSensitiveFields($"{currentPath}", elementType!)); | ||
} | ||
} | ||
} | ||
|
||
return list; | ||
} | ||
|
||
private static Type? GetElementType(PropertyInfo property) | ||
{ | ||
if (property.PropertyType.IsArray) | ||
{ | ||
return property.PropertyType.GetElementType()!; | ||
} | ||
else if (property.PropertyType.IsGenericType) | ||
{ | ||
return property.PropertyType.GetGenericArguments()[0]; | ||
|
||
} | ||
else if (property.PropertyType.IsClass) | ||
{ | ||
return property.PropertyType; | ||
|
||
} | ||
|
||
return default; | ||
} | ||
} |
Oops, something went wrong.