diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 682457d..7bcceca 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,14 +3,14 @@ "isRoot": true, "tools": { "swashbuckle.aspnetcore.cli": { - "version": "9.0.1", + "version": "10.0.1", "commands": [ "swagger" ], "rollForward": false }, "csharpier": { - "version": "1.0.2", + "version": "1.2.1", "commands": [ "csharpier" ], diff --git a/Directory.Build.props b/Directory.Build.props index 0230962..6b89139 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj index c6c95d2..d25956e 100644 --- a/src/Api/Api.csproj +++ b/src/Api/Api.csproj @@ -13,19 +13,19 @@ - - - - - - - - + + + + + + + + - - - + + + diff --git a/src/Api/Authentication/PhaJwtAuthenticationHandler.cs b/src/Api/Authentication/PhaJwtAuthenticationHandler.cs index f1831c8..803d65a 100644 --- a/src/Api/Authentication/PhaJwtAuthenticationHandler.cs +++ b/src/Api/Authentication/PhaJwtAuthenticationHandler.cs @@ -28,12 +28,10 @@ IOptions aclOptions if (client == null) return Task.CompletedTask; - claimsIdentity.AddClaims( - [ - .. client.Bcps.Select(ClaimTypes.CreateBcpClaim), - .. client.ChedTypes.Select(ClaimTypes.CreateChedTypeClaim), - ] - ); + claimsIdentity.AddClaims([ + .. client.Bcps.Select(ClaimTypes.CreateBcpClaim), + .. client.ChedTypes.Select(ClaimTypes.CreateChedTypeClaim), + ]); context.Principal = new ClaimsPrincipal(claimsIdentity); diff --git a/src/Api/OpenApi/DescriptionSchemaFilter.cs b/src/Api/OpenApi/DescriptionSchemaFilter.cs index 2487cbe..3246f8d 100644 --- a/src/Api/OpenApi/DescriptionSchemaFilter.cs +++ b/src/Api/OpenApi/DescriptionSchemaFilter.cs @@ -1,6 +1,6 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Defra.PhaImportNotifications.Api.OpenApi; @@ -8,7 +8,7 @@ namespace Defra.PhaImportNotifications.Api.OpenApi; [ExcludeFromCodeCoverage] public class DescriptionSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { if (context.ParameterInfo != null) { diff --git a/src/Api/OpenApi/ExampleValueSchemaFilter.cs b/src/Api/OpenApi/ExampleValueSchemaFilter.cs index 057bd92..6a1c874 100644 --- a/src/Api/OpenApi/ExampleValueSchemaFilter.cs +++ b/src/Api/OpenApi/ExampleValueSchemaFilter.cs @@ -1,14 +1,16 @@ +using System.Text.Json.Nodes; using Defra.PhaImportNotifications.Contracts; -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Defra.PhaImportNotifications.Api.OpenApi; public class ExampleValueSchemaFilter : ISchemaFilter { - public void Apply(OpenApiSchema schema, SchemaFilterContext context) + public void Apply(IOpenApiSchema schema, SchemaFilterContext context) { + var open = schema as OpenApiSchema; + var exampleValueAttributes = context.MemberInfo?.GetCustomAttributes(false).OfType().ToList() ?? []; @@ -20,9 +22,12 @@ public void Apply(OpenApiSchema schema, SchemaFilterContext context) + " underlying systems evolve. Consuming clients should cater for this possibility."; var values = exampleValueAttributes.Select(a => a.Value).Where(v => !string.IsNullOrWhiteSpace(v)); + + open!.Enum ??= new List(); + foreach (var value in values) { - schema.Enum.Add(new OpenApiString(value)); + open.Enum.Add(value); } } } diff --git a/src/Api/OpenApi/TagsDocumentFilter.cs b/src/Api/OpenApi/TagsDocumentFilter.cs index d29ad02..5f77138 100644 --- a/src/Api/OpenApi/TagsDocumentFilter.cs +++ b/src/Api/OpenApi/TagsDocumentFilter.cs @@ -1,5 +1,5 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; +using System.Text.Json.Nodes; +using Microsoft.OpenApi; using Swashbuckle.AspNetCore.SwaggerGen; namespace Defra.PhaImportNotifications.Api.OpenApi; @@ -10,22 +10,23 @@ public class TagsDocumentFilter : IDocumentFilter public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { - swaggerDoc.Extensions["tags"] = new OpenApiArray + var tag = swaggerDoc.Tags?.FirstOrDefault(t => t.Name == ImportNotificationsTag); + if (tag is not null) { - new OpenApiObject - { - ["name"] = new OpenApiString(ImportNotificationsTag), - ["description"] = new OpenApiString("Get updated import notifications for a PHA"), - }, - }; + tag.Description = "Get updated import notifications for a PHA"; + } - swaggerDoc.Extensions["x-tagGroups"] = new OpenApiArray - { - new OpenApiObject + swaggerDoc.Extensions ??= new Dictionary(); + + swaggerDoc.Extensions["x-tagGroups"] = new JsonNodeExtension( + new JsonArray { - ["name"] = new OpenApiString("Endpoints"), - ["tags"] = new OpenApiArray { new OpenApiString(ImportNotificationsTag) }, - }, - }; + new JsonObject + { + ["name"] = "Endpoints", + ["tags"] = new JsonArray { ImportNotificationsTag }, + }, + } + ); } } diff --git a/src/Api/Program.cs b/src/Api/Program.cs index 87d54f1..9c01283 100644 --- a/src/Api/Program.cs +++ b/src/Api/Program.cs @@ -16,7 +16,7 @@ using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; +using Microsoft.OpenApi; using Serilog; using Swashbuckle.AspNetCore.SwaggerGen; @@ -114,18 +114,10 @@ static void ConfigureWebApplication(WebApplicationBuilder builder, string[] args }, } ); - c.AddSecurityRequirement( - new OpenApiSecurityRequirement - { - { - new OpenApiSecurityScheme - { - Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oAuth" }, - }, - [] - }, - } - ); + c.AddSecurityRequirement(document => new OpenApiSecurityRequirement + { + [new OpenApiSecuritySchemeReference("oAuth", document)] = [], + }); c.IncludeXmlComments(Assembly.GetExecutingAssembly()); c.IncludeXmlComments(typeof(ImportPreNotification).Assembly); c.DocumentFilter(); diff --git a/src/Contracts/CommodityComplements.g.cs b/src/Contracts/CommodityComplements.g.cs index e31d4b1..5e0b167 100644 --- a/src/Contracts/CommodityComplements.g.cs +++ b/src/Contracts/CommodityComplements.g.cs @@ -1,79 +1,79 @@ -#nullable enable -using System.Text.Json.Serialization; -using System.ComponentModel; - -namespace Defra.PhaImportNotifications.Contracts; -public partial record CommodityComplements -{ - [JsonPropertyName("uniqueComplementId")] - [Description("UUID used to match commodityComplement to its complementParameter set. CHEDPP only")] - public string? UniqueComplementId { get; init; } - - [JsonPropertyName("commodityDescription")] - [Description("Description of the commodity")] - public string? CommodityDescription { get; init; } - - [JsonPropertyName("commodityId")] - [Description("The unique commodity ID")] - public string? CommodityId { get; init; } - - [JsonPropertyName("complementId")] - [Description("Identifier of complement chosen from speciesFamily,speciesClass and speciesType'. This is also used to link to the complementParameterSet")] - public int? ComplementId { get; init; } - - [JsonPropertyName("complementName")] - [Description("Represents the lowest granularity - either type, class, family or species name - for the commodity selected. This is also used to drive behaviour for EU Import journeys")] - public string? ComplementName { get; init; } - - [JsonPropertyName("eppoCode")] - [Description("EPPO Code related to plant commodities and wood packaging")] - public string? EppoCode { get; init; } - - [JsonPropertyName("isWoodPackaging")] - [Description("(Deprecated in IMTA-11832) Is this commodity wood packaging?")] - public bool? IsWoodPackaging { get; init; } - - [JsonPropertyName("speciesId")] - [Description("The species ID of the commodity that is imported. Not every commodity has a species ID. This is also used to link to the complementParameterSet. The species ID can change over time")] - public string? SpeciesId { get; init; } - - [JsonPropertyName("speciesName")] - [Description("Species name")] - public string? SpeciesName { get; init; } - - [JsonPropertyName("speciesNomination")] - [Description("Species nomination")] - public string? SpeciesNomination { get; init; } - - [JsonPropertyName("speciesTypeName")] - [Description("Species type name")] - public string? SpeciesTypeName { get; init; } - - [JsonPropertyName("speciesType")] - [Description("Species type identifier of commodity")] - public string? SpeciesType { get; init; } - - [JsonPropertyName("speciesClassName")] - [Description("Species class name")] - public string? SpeciesClassName { get; init; } - - [JsonPropertyName("speciesClass")] - [Description("Species class identifier of commodity")] - public string? SpeciesClass { get; init; } - - [JsonPropertyName("speciesFamilyName")] - [Description("Species family name of commodity")] - public string? SpeciesFamilyName { get; init; } - - [JsonPropertyName("speciesFamily")] - [Description("Species family identifier of commodity")] - public string? SpeciesFamily { get; init; } - - [JsonPropertyName("speciesCommonName")] - [Description("Species common name of commodity for IMP notification simple commodity selection")] - public string? SpeciesCommonName { get; init; } - - [JsonPropertyName("isCdsMatched")] - [Description("Has commodity been matched with corresponding CDS declaration")] - public bool? IsCdsMatched { get; init; } -} +#nullable enable +using System.Text.Json.Serialization; +using System.ComponentModel; + +namespace Defra.PhaImportNotifications.Contracts; +public partial record CommodityComplements +{ + [JsonPropertyName("uniqueComplementId")] + [Description("UUID used to match commodityComplement to its complementParameter set. CHEDPP only")] + public string? UniqueComplementId { get; init; } + + [JsonPropertyName("commodityDescription")] + [Description("Description of the commodity")] + public string? CommodityDescription { get; init; } + + [JsonPropertyName("commodityId")] + [Description("The unique commodity ID")] + public string? CommodityId { get; init; } + + [JsonPropertyName("complementId")] + [Description("Identifier of complement chosen from speciesFamily,speciesClass and speciesType'. This is also used to link to the complementParameterSet")] + public int? ComplementId { get; init; } + + [JsonPropertyName("complementName")] + [Description("Represents the lowest granularity - either type, class, family or species name - for the commodity selected. This is also used to drive behaviour for EU Import journeys")] + public string? ComplementName { get; init; } + + [JsonPropertyName("eppoCode")] + [Description("EPPO Code related to plant commodities and wood packaging")] + public string? EppoCode { get; init; } + + [JsonPropertyName("isWoodPackaging")] + [Description("(Deprecated in IMTA-11832) Is this commodity wood packaging?")] + public bool? IsWoodPackaging { get; init; } + + [JsonPropertyName("speciesId")] + [Description("The species ID of the commodity that is imported. Not every commodity has a species ID. This is also used to link to the complementParameterSet. The species ID can change over time")] + public string? SpeciesId { get; init; } + + [JsonPropertyName("speciesName")] + [Description("Species name")] + public string? SpeciesName { get; init; } + + [JsonPropertyName("speciesNomination")] + [Description("Species nomination")] + public string? SpeciesNomination { get; init; } + + [JsonPropertyName("speciesTypeName")] + [Description("Species type name")] + public string? SpeciesTypeName { get; init; } + + [JsonPropertyName("speciesType")] + [Description("Species type identifier of commodity")] + public string? SpeciesType { get; init; } + + [JsonPropertyName("speciesClassName")] + [Description("Species class name")] + public string? SpeciesClassName { get; init; } + + [JsonPropertyName("speciesClass")] + [Description("Species class identifier of commodity")] + public string? SpeciesClass { get; init; } + + [JsonPropertyName("speciesFamilyName")] + [Description("Species family name of commodity")] + public string? SpeciesFamilyName { get; init; } + + [JsonPropertyName("speciesFamily")] + [Description("Species family identifier of commodity")] + public string? SpeciesFamily { get; init; } + + [JsonPropertyName("speciesCommonName")] + [Description("Species common name of commodity for IMP notification simple commodity selection")] + public string? SpeciesCommonName { get; init; } + + [JsonPropertyName("isCdsMatched")] + [Description("Has commodity been matched with corresponding CDS declaration")] + public bool? IsCdsMatched { get; init; } +} diff --git a/src/Contracts/ComplementParameterSets.g.cs b/src/Contracts/ComplementParameterSets.g.cs index 91c4198..bfefa86 100644 --- a/src/Contracts/ComplementParameterSets.g.cs +++ b/src/Contracts/ComplementParameterSets.g.cs @@ -1,29 +1,29 @@ -#nullable enable -using System.Text.Json.Serialization; -using System.ComponentModel; - -namespace Defra.PhaImportNotifications.Contracts; -public partial record ComplementParameterSets -{ - [JsonPropertyName("uniqueComplementId")] - [Description("UUID used to match commodityComplement to its complementParameter set. CHEDPP only")] - public string? UniqueComplementId { get; init; } - - [JsonPropertyName("complementId")] - public int? ComplementId { get; init; } - - [JsonPropertyName("speciesId")] - public string? SpeciesId { get; init; } - - [JsonPropertyName("keyDataPair")] - public List? KeyDataPair { get; init; } - - [JsonPropertyName("catchCertificates")] - [JsonIgnore] - [Description("Catch certificate details")] - public List? CatchCertificates { get; init; } - - [JsonPropertyName("identifiers")] - [Description("Data used to identify the complements inside an IMP consignment")] - public List? Identifiers { get; init; } -} +#nullable enable +using System.Text.Json.Serialization; +using System.ComponentModel; + +namespace Defra.PhaImportNotifications.Contracts; +public partial record ComplementParameterSets +{ + [JsonPropertyName("uniqueComplementId")] + [Description("UUID used to match commodityComplement to its complementParameter set. CHEDPP only")] + public string? UniqueComplementId { get; init; } + + [JsonPropertyName("complementId")] + public int? ComplementId { get; init; } + + [JsonPropertyName("speciesId")] + public string? SpeciesId { get; init; } + + [JsonPropertyName("keyDataPair")] + public List? KeyDataPair { get; init; } + + [JsonPropertyName("catchCertificates")] + [JsonIgnore] + [Description("Catch certificate details")] + public List? CatchCertificates { get; init; } + + [JsonPropertyName("identifiers")] + [Description("Data used to identify the complements inside an IMP consignment")] + public List? Identifiers { get; init; } +} diff --git a/src/Contracts/ExternalError.g.cs b/src/Contracts/ExternalError.g.cs index 6bdba91..ef9591f 100644 --- a/src/Contracts/ExternalError.g.cs +++ b/src/Contracts/ExternalError.g.cs @@ -1,22 +1,22 @@ -#nullable enable -using System.Text.Json.Serialization; -using System.ComponentModel; - -namespace Defra.PhaImportNotifications.Contracts; -public partial record ExternalError -{ - [JsonPropertyName("externalCorrelationId")] - public string? ExternalCorrelationId { get; init; } - - [JsonPropertyName("sourceCorrelationId")] - public string? SourceCorrelationId { get; init; } - - [JsonPropertyName("externalVersion")] - public int? ExternalVersion { get; init; } - - [JsonPropertyName("messageSentAt")] - public required DateTime MessageSentAt { get; init; } - - [JsonPropertyName("errors")] - public List? Errors { get; init; } -} +#nullable enable +using System.Text.Json.Serialization; +using System.ComponentModel; + +namespace Defra.PhaImportNotifications.Contracts; +public partial record ExternalError +{ + [JsonPropertyName("externalCorrelationId")] + public string? ExternalCorrelationId { get; init; } + + [JsonPropertyName("sourceCorrelationId")] + public string? SourceCorrelationId { get; init; } + + [JsonPropertyName("externalVersion")] + public int? ExternalVersion { get; init; } + + [JsonPropertyName("messageSentAt")] + public required DateTime MessageSentAt { get; init; } + + [JsonPropertyName("errors")] + public List? Errors { get; init; } +} diff --git a/src/Contracts/ImportPreNotificationUpdateResponse.g.cs b/src/Contracts/ImportPreNotificationUpdateResponse.g.cs index 016b88b..1e9d415 100644 --- a/src/Contracts/ImportPreNotificationUpdateResponse.g.cs +++ b/src/Contracts/ImportPreNotificationUpdateResponse.g.cs @@ -1,13 +1,13 @@ -#nullable enable -using System.Text.Json.Serialization; -using System.ComponentModel; - -namespace Defra.PhaImportNotifications.Contracts; -public partial record ImportPreNotificationUpdateResponse -{ - [JsonPropertyName("referenceNumber")] - public required string ReferenceNumber { get; init; } - - [JsonPropertyName("updated")] - public required DateTime Updated { get; init; } -} +#nullable enable +using System.Text.Json.Serialization; +using System.ComponentModel; + +namespace Defra.PhaImportNotifications.Contracts; +public partial record ImportPreNotificationUpdateResponse +{ + [JsonPropertyName("referenceNumber")] + public required string ReferenceNumber { get; init; } + + [JsonPropertyName("updated")] + public required DateTime Updated { get; init; } +} diff --git a/src/Contracts/ImportPreNotificationUpdatesResponse.g.cs b/src/Contracts/ImportPreNotificationUpdatesResponse.g.cs index 3991b81..b3d8d98 100644 --- a/src/Contracts/ImportPreNotificationUpdatesResponse.g.cs +++ b/src/Contracts/ImportPreNotificationUpdatesResponse.g.cs @@ -1,19 +1,19 @@ -#nullable enable -using System.Text.Json.Serialization; -using System.ComponentModel; - -namespace Defra.PhaImportNotifications.Contracts; -public partial record ImportPreNotificationUpdatesResponse -{ - [JsonPropertyName("importPreNotificationUpdates")] - public required List ImportPreNotificationUpdates { get; init; } - - [JsonPropertyName("total")] - public required int Total { get; init; } - - [JsonPropertyName("page")] - public required int Page { get; init; } - - [JsonPropertyName("pageSize")] - public required int PageSize { get; init; } -} +#nullable enable +using System.Text.Json.Serialization; +using System.ComponentModel; + +namespace Defra.PhaImportNotifications.Contracts; +public partial record ImportPreNotificationUpdatesResponse +{ + [JsonPropertyName("importPreNotificationUpdates")] + public required List ImportPreNotificationUpdates { get; init; } + + [JsonPropertyName("total")] + public required int Total { get; init; } + + [JsonPropertyName("page")] + public required int Page { get; init; } + + [JsonPropertyName("pageSize")] + public required int PageSize { get; init; } +} diff --git a/tests/Api.Integration/OpenApi/OpenApiTests.Redoc_VerifyAsExpected.verified.txt b/tests/Api.Integration/OpenApi/OpenApiTests.Redoc_VerifyAsExpected.verified.txt index dadfa17..5104874 100644 --- a/tests/Api.Integration/OpenApi/OpenApiTests.Redoc_VerifyAsExpected.verified.txt +++ b/tests/Api.Integration/OpenApi/OpenApiTests.Redoc_VerifyAsExpected.verified.txt @@ -12,6 +12,11 @@ StatusCode: OK, ReasonPhrase: OK, Headers: [ + { + x-redoc-version: [ + 2.5.2 + ] + }, { Cache-Control: [ max-age=604800, private diff --git a/tests/PhaImportNotifcations.Tests.csproj b/tests/PhaImportNotifcations.Tests.csproj index fe4da1c..5b16ac8 100644 --- a/tests/PhaImportNotifcations.Tests.csproj +++ b/tests/PhaImportNotifcations.Tests.csproj @@ -8,21 +8,21 @@ - + - - - - - - + + + + + + + - - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tools/SchemaToCSharp/SchemaToCSharp.csproj b/tools/SchemaToCSharp/SchemaToCSharp.csproj index d7efe54..6c87b67 100644 --- a/tools/SchemaToCSharp/SchemaToCSharp.csproj +++ b/tools/SchemaToCSharp/SchemaToCSharp.csproj @@ -6,8 +6,8 @@ enable - - - + + +