diff --git a/commcheck-api/cli/.vscode/launch.json b/commcheck-api/cli/.vscode/launch.json index 814dc57..75d1237 100644 --- a/commcheck-api/cli/.vscode/launch.json +++ b/commcheck-api/cli/.vscode/launch.json @@ -11,7 +11,7 @@ "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/bin/Debug/net8.0/cli.dll", - "args": [], + "args": ["--dob=2020-01-01", "--rfr=DEA"], "cwd": "${workspaceFolder}", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", diff --git a/commcheck-api/cli/Program.cs b/commcheck-api/cli/Program.cs index 1a4116a..f193f47 100644 --- a/commcheck-api/cli/Program.cs +++ b/commcheck-api/cli/Program.cs @@ -8,25 +8,42 @@ using Microsoft.Extensions.Logging; -var fileOption = new Option( +var dobOption = new Option( name: "--dob", - description: "Date of birth (yyyy-mm-dd)"); + description: "Date of birth (yyyy-mm-dd)") +{ + IsRequired = true +}; + +var baseUrl = new Option( + name: "--host", + description: "Base url. defaults to https://commchecks.azurewebsites.net"); +baseUrl.SetDefaultValue(new Uri("https://commchecks.azurewebsites.net")); + +var rfrCode = new Option( + name: "--rfr", + description: "Reason for removal code") + { + IsRequired = true + }; var rootCommand = new RootCommand("Commcheck cli v1"); -rootCommand.AddOption(fileOption); +rootCommand.AddOption(dobOption); +rootCommand.AddOption(baseUrl); +rootCommand.AddOption(rfrCode); -rootCommand.SetHandler(async (dob) => +rootCommand.SetHandler(async (dob, url, rfr) => { var builder = Host.CreateApplicationBuilder(args); builder.Services.AddHttpClient(options=> { - options.BaseAddress = new Uri("https://commchecks.azurewebsites.net"); + options.BaseAddress = url; }); var host = builder.Build(); var check = host.Services.GetRequiredService(); - var content = await check.Check(dob); + var content = await check.Check(dob, Enum.Parse(rfr)); }, - fileOption); + dobOption, baseUrl, rfrCode); return await rootCommand.InvokeAsync(args); @@ -34,13 +51,15 @@ public class CommsCheck(HttpClient client, ILogger logger) { - public async Task Check(DateOnly dob) + public async Task Check( + DateOnly dob, + ReasonForRemovals rfr) { var response = await client.PostAsJsonAsync( "check", CommsCheckQuestionRequestDto.DobOnly( dob, - ReasonForRemovals.None)); + rfr)); var location = response.Headers.Location; diff --git a/commcheck-api/src/rules.json b/commcheck-api/src/rules.json index 2d83016..24f0f3b 100644 --- a/commcheck-api/src/rules.json +++ b/commcheck-api/src/rules.json @@ -129,6 +129,13 @@ "ErrorMessage": "", "Enabled": false, "Expression": "true" + }, + { + "RuleName": "Block ZZ99", + "SuccessEvent": "Explicit Postal Block 99: Block ZZ99", + "ErrorMessage": "", + "Enabled": true, + "Expression": "item.PostCode.IsZZ99 == true" } ] }, diff --git a/commcheck-api/src/src/Api/CommsCheckAnswerResponseDto.cs b/commcheck-api/src/src/Api/CommsCheckAnswerResponseDto.cs index 17cd01f..8ff8f9c 100644 --- a/commcheck-api/src/src/Api/CommsCheckAnswerResponseDto.cs +++ b/commcheck-api/src/src/Api/CommsCheckAnswerResponseDto.cs @@ -21,3 +21,4 @@ public static CommsCheckAnswerResponseDto FromCommsCheckAnswer(CommsCheckAnswer ); } } + diff --git a/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs b/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs index 6dbee44..cd61660 100644 --- a/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs +++ b/commcheck-api/src/src/Api/CommsCheckQuestionRequestDto.cs @@ -1,7 +1,51 @@ 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 DateOfBirth, DateOnly DateOfSmsMostRecentUpdate, @@ -10,7 +54,8 @@ public readonly record struct CommsCheckQuestionRequestDto( DateOnly DateOfPostalMostRecentUpdate, DateOnly DateOfReasonForRemovalMostRecentUpdate, DeathStatus? DeathStatusValue, - ReasonForRemovals? RfR) + ReasonForRemovals? RfR, + PostalCode PostCode) { public static CommsCheckQuestionRequestDto DobOnly( @@ -24,5 +69,6 @@ public static CommsCheckQuestionRequestDto DobOnly( DateOnly.MinValue, DateOnly.MinValue, DeathStatus.None, - reasonForRemoval); + reasonForRemoval, + PostalCode.Empty); } diff --git a/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs b/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs index 6062f82..dfaf0fa 100644 --- a/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs +++ b/commcheck-api/src/src/CommsCheck/CommsCheckItem.cs @@ -9,6 +9,7 @@ public readonly record struct CommsCheckItem( DateOnly DateOfReasonForRemovalMostRecentUpdate, IReasonForRemoval ReasonForRemoval, IDeathStatus DeathStatus, + PostalCode PostCode, CommsCheckQuestionRequestDtoCopy CopyOfSource) { public int DaysOld => @@ -56,6 +57,7 @@ public CommsCheckItem FromDtoRelativeToToday(CommsCheckQuestionRequestDto dto) dto.DateOfReasonForRemovalMostRecentUpdate, IReasonForRemoval.FromEnum(dto.RfR), IDeathStatus.FromEnum(dto.DeathStatusValue), + dto.PostCode, CommsCheckQuestionRequestDtoCopy.FromDto(dto)); } } @@ -67,7 +69,8 @@ public readonly record struct CommsCheckQuestionRequestDtoCopy(DateOnly DateOfBi DateOnly DateOfPostalMostRecentUpdate, DateOnly DateOfReasonForRemovalMostRecentUpdate, DeathStatus? DeathStatusValue, - ReasonForRemovals? RfR + ReasonForRemovals? RfR, + PostalCode PostCode ) { public static CommsCheckQuestionRequestDtoCopy FromDto(CommsCheckQuestionRequestDto dto) => @@ -79,7 +82,8 @@ public static CommsCheckQuestionRequestDtoCopy FromDto(CommsCheckQuestionRequest dto.DateOfPostalMostRecentUpdate, dto.DateOfReasonForRemovalMostRecentUpdate, dto.DeathStatusValue, - dto.RfR); + dto.RfR, + dto.PostCode); public CommsCheckQuestionRequestDto ToDto() => new CommsCheckQuestionRequestDto( @@ -90,5 +94,6 @@ public CommsCheckQuestionRequestDto ToDto() => DateOfPostalMostRecentUpdate, DateOfReasonForRemovalMostRecentUpdate, DeathStatusValue, - RfR); + RfR, + PostCode); } \ No newline at end of file diff --git a/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/RulesEngineRulesLoader.cs b/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/RulesEngineRulesLoader.cs index f8f0670..6a0175a 100644 --- a/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/RulesEngineRulesLoader.cs +++ b/commcheck-api/src/src/CommsCheck/CommsCheckRulesEngine/RulesEngineRulesLoader.cs @@ -6,7 +6,6 @@ namespace CommsCheck; using System.Text; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; -using Newtonsoft.Json.Converters; using RulesEngine; using RulesEngine.Models; diff --git a/commcheck-api/src/src/Extensions/CommsCheckOptions.cs b/commcheck-api/src/src/Extensions/CommsCheckOptions.cs index 7994566..d158758 100644 --- a/commcheck-api/src/src/Extensions/CommsCheckOptions.cs +++ b/commcheck-api/src/src/Extensions/CommsCheckOptions.cs @@ -24,6 +24,7 @@ public CommsCheckOptions AddJsonConfig() options.SerializerOptions.WriteIndented = true; options.SerializerOptions.IncludeFields = true; options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.SerializerOptions.Converters.Add(new PostalCodeJsonConverter()); options.SerializerOptions.PropertyNameCaseInsensitive = true; }); @@ -31,6 +32,7 @@ public CommsCheckOptions AddJsonConfig() { options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + options.JsonSerializerOptions.Converters.Add(new PostalCodeJsonConverter()); }); return this; } diff --git a/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs b/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs index 49cbaef..95f18da 100644 --- a/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs +++ b/commcheck-api/src/src/Extensions/SwaggerGenExtensions.cs @@ -15,6 +15,12 @@ public static SwaggerGenOptions AddDateAndEnumFormatters( Format = "date" }); + options.MapType(() => new OpenApiSchema() + { + Type = "string" + }); + + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); options.IncludeXmlComments(xmlPath);