From af411d93a2bab19acf21558f2daf83358492847c Mon Sep 17 00:00:00 2001 From: "ross.buggins" <78215796+RossBugginsNHS@users.noreply.github.com> Date: Thu, 23 Nov 2023 13:58:53 +0000 Subject: [PATCH] Reduce dob and postcode granularity. --- .../src/Api/CommsCheckQuestionRequestDto.cs | 47 ++----------------- commcheck-api/src/src/Api/PostalCode.cs | 32 +++++++++++++ .../src/src/Api/PostalCodeJsonConverter.cs | 25 ++++++++++ .../src/Benchmarks/CommsCheckBenchmarks.cs | 1 + .../src/src/CommsCheck/CommsCheckItem.cs | 20 ++++---- .../RuleRunMethodResultCacheService.cs | 2 +- .../src/Extensions/SwaggerGenExtensions.cs | 5 +- commcheck-api/src/src/Program.cs | 35 +++++++++++++- 8 files changed, 111 insertions(+), 56 deletions(-) create mode 100644 commcheck-api/src/src/Api/PostalCode.cs create mode 100644 commcheck-api/src/src/Api/PostalCodeJsonConverter.cs diff --git a/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs b/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs index cd61660..60c4fa3 100644 --- a/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs +++ b/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs @@ -1,52 +1,9 @@ namespace CommsCheck; using System.Globalization; -using System.Text.Json; -using System.Text.Json.Serialization; - - public class PostalCodeJsonConverter : JsonConverter - { - public override PostalCode Read( - ref Utf8JsonReader reader, - Type typeToConvert, - JsonSerializerOptions options) => - PostalCode.Parse(reader.GetString()!); - - public override void Write( - Utf8JsonWriter writer, - PostalCode postCodeValue, - JsonSerializerOptions options) => - writer.WriteStringValue(postCodeValue.PostCode); - } - -public readonly record struct PostalCode -{ - public string PostCode {get;init;} - - public bool IsZZ99 => PostCode!=null && PostCode.StartsWith("ZZ99"); - - [JsonConstructor] - public PostalCode(string postCode) - { - ArgumentNullException.ThrowIfNullOrWhiteSpace(postCode, nameof(postCode)); - PostCode = ParsePostcodeString(postCode); - } - - public static PostalCode Parse(string postCode) - { - return new PostalCode(postCode); - } - - private static string ParsePostcodeString(string postcode) - { - ArgumentNullException.ThrowIfNullOrWhiteSpace(postcode, nameof(postcode)); - return postcode.ToUpper().Replace(" ", ""); - } - - public static PostalCode Empty => new PostalCode(); -} public readonly record struct CommsCheckQuestionRequestDto( + DateOnly RelativeDate, DateOnly DateOfBirth, DateOnly DateOfSmsMostRecentUpdate, DateOnly DateOfEmailMostRecentUpdate, @@ -59,9 +16,11 @@ public readonly record struct CommsCheckQuestionRequestDto( { public static CommsCheckQuestionRequestDto DobOnly( + DateOnly relativeDate, DateOnly dateOfBirth, ReasonForRemovals?reasonForRemoval) => new CommsCheckQuestionRequestDto( + relativeDate, dateOfBirth, DateOnly.MinValue, DateOnly.MinValue, diff --git a/commcheck-api/src/src/Api/PostalCode.cs b/commcheck-api/src/src/Api/PostalCode.cs new file mode 100644 index 0000000..9f5fe03 --- /dev/null +++ b/commcheck-api/src/src/Api/PostalCode.cs @@ -0,0 +1,32 @@ +namespace CommsCheck; + +using System.Text.Json.Serialization; + +public readonly record struct PostalCode +{ + public string PostCode {get;init;} + + public bool IsZZ99 => PostCode!=null && PostCode.StartsWith("ZZ99"); + + [JsonConstructor] + public PostalCode(string postCode) + { + ArgumentNullException.ThrowIfNullOrWhiteSpace(postCode, nameof(postCode)); + PostCode = ParsePostcodeString(postCode); + } + + public static PostalCode Parse(string postCode) + { + return new PostalCode(postCode); + } + + private static string ParsePostcodeString(string postcode) + { + ArgumentNullException.ThrowIfNullOrWhiteSpace(postcode, nameof(postcode)); + return postcode.ToUpper().Replace(" ", ""); + } + + public static PostalCode Empty => new PostalCode(); + + public PostalCode DistrictOnly() => new PostalCode(string.Concat(PostCode.Take(4))); +} diff --git a/commcheck-api/src/src/Api/PostalCodeJsonConverter.cs b/commcheck-api/src/src/Api/PostalCodeJsonConverter.cs new file mode 100644 index 0000000..b4423c9 --- /dev/null +++ b/commcheck-api/src/src/Api/PostalCodeJsonConverter.cs @@ -0,0 +1,25 @@ +namespace CommsCheck; + +using System.Text.Json; +using System.Text.Json.Serialization; + +public class PostalCodeJsonConverter : JsonConverter + { + public override PostalCode Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + PostalCode.Parse(reader.GetString()!); + + public override void Write( + Utf8JsonWriter writer, + PostalCode postCodeValue, + JsonSerializerOptions options) + { + writer.WriteStartObject(); + writer.WriteString("postcode", postCodeValue.PostCode); + writer.WriteBoolean("isZZ99", postCodeValue.IsZZ99); + writer.WriteEndObject(); + // writer.WriteStringValue(postCodeValue.PostCode); + } + } diff --git a/commcheck-api/src/src/Benchmarks/CommsCheckBenchmarks.cs b/commcheck-api/src/src/Benchmarks/CommsCheckBenchmarks.cs index 957a197..b1e021a 100644 --- a/commcheck-api/src/src/Benchmarks/CommsCheckBenchmarks.cs +++ b/commcheck-api/src/src/Benchmarks/CommsCheckBenchmarks.cs @@ -115,6 +115,7 @@ public async Task SendAndWait(ISender sender, IDistributedCache cache, CommsChec public CommsCheckQuestionRequestDto BuildRequestDto(DateTime thisDate) => CommsCheckQuestionRequestDto.DobOnly( + new DateOnly(2000,1,1), DateOnly.FromDateTime(thisDate), null); diff --git a/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs b/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs index dfaf0fa..e7ae981 100644 --- a/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs +++ b/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs @@ -1,6 +1,6 @@ namespace CommsCheck; public readonly record struct CommsCheckItem( - DateOnly UtcDateCheckItemCreated, + DateOnly RelativeDate, DateOnly DateOfBirth, DateOnly DateOfSmsMostRecentUpdate, DateOnly DateOfEmailMostRecentUpdate, @@ -13,10 +13,10 @@ public readonly record struct CommsCheckItem( CommsCheckQuestionRequestDtoCopy CopyOfSource) { public int DaysOld => - UtcDateCheckItemCreated.DayNumber - DateOfBirth.DayNumber; + RelativeDate.DayNumber - DateOfBirth.DayNumber; public int DaySinceSmsUpdate => - UtcDateCheckItemCreated.DayNumber - DateOfSmsMostRecentUpdate.DayNumber; + RelativeDate.DayNumber - DateOfSmsMostRecentUpdate.DayNumber; public DateOnly DateOfMostRecentCommsUpdate => Enumerable.Max( @@ -37,18 +37,18 @@ public readonly record struct CommsCheckItem( public int YearsOld => (int)Math.Floor(DaysOld / (float)365); public int DaysSinceMostRecentCommsUpdate => - UtcDateCheckItemCreated.DayNumber - DateOfMostRecentCommsUpdate.DayNumber; + RelativeDate.DayNumber - DateOfMostRecentCommsUpdate.DayNumber; public int DaysSinceOldestCommsUpdate => - UtcDateCheckItemCreated.DayNumber - DateOfOldestCommsUpdate.DayNumber; + RelativeDate.DayNumber - DateOfOldestCommsUpdate.DayNumber; } -public class CommsCheckItemFactory(TimeProvider timeProvider) +public class CommsCheckItemFactory { public CommsCheckItem FromDtoRelativeToToday(CommsCheckQuestionRequestDto dto) { return new CommsCheckItem( - DateOnly.FromDateTime(timeProvider.GetUtcNow().UtcDateTime), + dto.RelativeDate, dto.DateOfBirth, dto.DateOfSmsMostRecentUpdate, dto.DateOfEmailMostRecentUpdate, @@ -62,7 +62,9 @@ public CommsCheckItem FromDtoRelativeToToday(CommsCheckQuestionRequestDto dto) } } -public readonly record struct CommsCheckQuestionRequestDtoCopy(DateOnly DateOfBirth, +public readonly record struct CommsCheckQuestionRequestDtoCopy( + DateOnly RelativeDate, + DateOnly DateOfBirth, DateOnly DateOfSmsMostRecentUpdate, DateOnly DateOfEmailMostRecentUpdate, DateOnly DateOfAppMostRecentUpdate, @@ -75,6 +77,7 @@ PostalCode PostCode { public static CommsCheckQuestionRequestDtoCopy FromDto(CommsCheckQuestionRequestDto dto) => new CommsCheckQuestionRequestDtoCopy( + dto.RelativeDate, dto.DateOfBirth, dto.DateOfSmsMostRecentUpdate, dto.DateOfEmailMostRecentUpdate, @@ -87,6 +90,7 @@ public static CommsCheckQuestionRequestDtoCopy FromDto(CommsCheckQuestionRequest public CommsCheckQuestionRequestDto ToDto() => new CommsCheckQuestionRequestDto( + RelativeDate, DateOfBirth, DateOfSmsMostRecentUpdate, DateOfEmailMostRecentUpdate, diff --git a/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/Services/RuleRunMethodResultCacheService.cs b/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/Services/RuleRunMethodResultCacheService.cs index 8f82f31..40c33ba 100644 --- a/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/Services/RuleRunMethodResultCacheService.cs +++ b/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/Services/RuleRunMethodResultCacheService.cs @@ -94,7 +94,7 @@ private CommsCheckAnswer BuildNewItem(RuleOutcomeComputedEvent notification) notification.RuleHash, notification.ToCheck, notification.ToCheck.Item.CopyOfSource, - notification.ToCheck.Item.UtcDateCheckItemCreated, + notification.ToCheck.Item.RelativeDate, now, now, 1, diff --git a/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs b/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs index 95f18da..cf982af 100644 --- a/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs +++ b/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs @@ -1,6 +1,7 @@ namespace CommsCheck; using System.Reflection; +using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; @@ -17,7 +18,9 @@ public static SwaggerGenOptions AddDateAndEnumFormatters( options.MapType(() => new OpenApiSchema() { - Type = "string" + Type = "string", + Default = new OpenApiString("None"), + Example = new OpenApiString("None") }); diff --git a/commcheck-api/src/src/Program.cs b/commcheck-api/src/src/Program.cs index f8b0746..5c03bd9 100644 --- a/commcheck-api/src/src/Program.cs +++ b/commcheck-api/src/src/Program.cs @@ -61,12 +61,34 @@ builder.Services.AddSwaggerGen( options => { + var desc = """ + Rules engine for providing a standardised and central decision tree for deciding + if there should be communication with a person. + + This API makes its decision based on the data provided in the request payload, and does + not use data sources directly. + + - Submit data using the POST /check endpoint + - The response contains a Location header with a url and unique id + - Retrieve answer from GET /check/results/{resultId} endpoint + - View the current rules at the GET /rules endpoint + + Available at the readme github repo is source for a cli tool for directly calling the api. + + + GET /check/results provides a list of the last 100 queries + + GET /check/results/stream can be used to provide a realtime stream of requests. + """; + + options.AddDateAndEnumFormatters(); options.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "Comms Check API v1", - Description = "Rules engine for communication with persons.", + Description = desc, + Contact = new OpenApiContact { Name = "Readme", @@ -97,7 +119,16 @@ async Task { - var result = await sender.Send(new CheckCommsCommand(request)); + var filteredRequest = request with + { + DateOfBirth = new DateOnly( + request.DateOfBirth.Year, + request.DateOfBirth.Month, + 1), + PostCode = request.PostCode.DistrictOnly() + }; + + var result = await sender.Send(new CheckCommsCommand(filteredRequest)); var itemBytes = await cache.GetAsync(result.ResultId); if (itemBytes == null) {