From 84f17c4fe3f9334db4a7818100cd215aff3b38ef Mon Sep 17 00:00:00 2001 From: Koen Metsu Date: Mon, 10 Feb 2025 14:29:49 +0100 Subject: [PATCH 01/12] fix: or-2665 add first e2e test --- .../Constants/VersionHeader.cs | 7 + .../Vereniging/Verenigingstype.cs | 1 + .../Framework/AlbaHost/AdminApiEndpoints.cs | 11 + .../Returns_VZER_DetailResponse.cs | 212 ++++++++++++++++++ .../Returns_DetailResponse.cs | 6 +- 5 files changed, 234 insertions(+), 3 deletions(-) create mode 100644 src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs create mode 100644 test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs rename test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/{ => Without_Header}/Returns_DetailResponse.cs (98%) diff --git a/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs b/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs new file mode 100644 index 000000000..2a2c37bdd --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs @@ -0,0 +1,7 @@ +namespace AssociationRegistry.Admin.Api.Constants; + +public static class VersionHeader +{ + public const string HeaderName = "vr-api-version"; + public const string V2 = "v2"; +} diff --git a/src/AssociationRegistry/Vereniging/Verenigingstype.cs b/src/AssociationRegistry/Vereniging/Verenigingstype.cs index debd28cc9..ca3885387 100644 --- a/src/AssociationRegistry/Vereniging/Verenigingstype.cs +++ b/src/AssociationRegistry/Vereniging/Verenigingstype.cs @@ -3,6 +3,7 @@ public class Verenigingstype { public static readonly Verenigingstype FeitelijkeVereniging = new(code: "FV", naam: "Feitelijke vereniging"); + public static readonly Verenigingstype VZER = new(code: "VZER", naam: "Vereniging zonder eigen rechtspersoonlijkheid"); public static readonly Verenigingstype VZW = new(code: "VZW", naam: "Vereniging zonder winstoogmerk"); public static readonly Verenigingstype IVZW = new(code: "IVZW", naam: "Internationale vereniging zonder winstoogmerk"); public static readonly Verenigingstype PrivateStichting = new(code: "PS", naam: "Private stichting"); diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs index 0017219a2..0a2b505a5 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs @@ -1,11 +1,13 @@ namespace AssociationRegistry.Test.E2E.Framework.AlbaHost; using Admin.Api.Administratie.DubbelControle; +using Admin.Api.Constants; using Admin.Api.Verenigingen.Detail.ResponseModels; using Admin.Api.Verenigingen.Historiek.ResponseModels; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; using Admin.Api.Verenigingen.Search.ResponseModels; using Alba; +using System.Net.Http.Json; public static class AdminApiEndpoints { @@ -19,6 +21,15 @@ public static string GetDetailAsText(this IAlbaHost source, string vCode) public static DetailVerenigingResponse GetBeheerDetail(this IAlbaHost source, string vCode) => source.GetAsJson($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult()!; + public static DetailVerenigingResponse GetBeheerDetailWithHeader(this IAlbaHost source, string vCode) + { + var client = source.Server.CreateClient(); + client.DefaultRequestHeaders.Add(VersionHeader.HeaderName, VersionHeader.V2); + var response = client.GetAsync($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult(); + + return response.Content.ReadFromJsonAsync().GetAwaiter().GetResult(); + } + public static DubbelControleResponse[] PostDubbelControle(this IAlbaHost source, RegistreerFeitelijkeVerenigingRequest registreerFeitelijkeVerenigingRequest) => source.PostJson(registreerFeitelijkeVerenigingRequest, "/v1/admin/dubbelcontrole").Receive().GetAwaiter().GetResult(); diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs new file mode 100644 index 000000000..40367d78e --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs @@ -0,0 +1,212 @@ +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Detail.With_Header; + +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; +using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using Formats; +using JsonLdContext; +using Framework.AlbaHost; +using Framework.ApiSetup; +using Framework.Comparison; +using Framework.TestClasses; +using Vereniging; +using Vereniging.Bronnen; +using KellermanSoftware.CompareNetObjects; +using NodaTime; +using Xunit; +using Contactgegeven = Admin.Api.Verenigingen.Detail.ResponseModels.Contactgegeven; +using HoofdactiviteitVerenigingsloket = Vereniging.HoofdactiviteitVerenigingsloket; +using Locatie = Admin.Api.Verenigingen.Detail.ResponseModels.Locatie; +using VerenigingStatus = Admin.Schema.Constants.VerenigingStatus; +using Vertegenwoordiger = Admin.Api.Verenigingen.Detail.ResponseModels.Vertegenwoordiger; +using Werkingsgebied = Vereniging.Werkingsgebied; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_VZER_DetailResponse : + End2EndTest, + IAsyncLifetime +{ + public Returns_VZER_DetailResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) + { + } + + [Fact] + public void With_Context() + { + Response.Context.ShouldCompare("http://127.0.0.1:11003/v1/contexten/beheer/detail-vereniging-context.json"); + } + + [Fact] + public void With_Metadata_DatumLaatsteAanpassing() + { + Response.Metadata.DatumLaatsteAanpassing.ShouldCompare(Instant.FromDateTimeOffset(DateTimeOffset.Now).FormatAsBelgianDate(), + compareConfig: new ComparisonConfig + { MaxMillisecondsDateDifference = 5000 }); + } + + [Fact] + public async Task WithFeitelijkeVereniging() + => Response.Vereniging.ShouldCompare(new VerenigingDetail + { + Bron = Bron.Initiator, + type = JsonLdType.FeitelijkeVereniging.Type, + CorresponderendeVCodes = [], + Doelgroep = new DoelgroepResponse + { + type = JsonLdType.Doelgroep.Type, + id = JsonLdType.Doelgroep.CreateWithIdValues(TestContext.VCode), + Minimumleeftijd = 1, + Maximumleeftijd = 149, + }, + VCode = TestContext.VCode, + KorteBeschrijving = Request.KorteBeschrijving, + KorteNaam = Request.KorteNaam, + Verenigingstype = new VerenigingsType + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }, + Naam = Request.Naam, + Startdatum = Instant.FromDateTimeOffset(DateTimeOffset.UtcNow).FormatAsBelgianDate(), + Einddatum = null, + Status = VerenigingStatus.Actief, + IsUitgeschrevenUitPubliekeDatastroom = Request.IsUitgeschrevenUitPubliekeDatastroom, + Contactgegevens = MapLocaties(Request.Contactgegevens, TestContext.VCode), + HoofdactiviteitenVerenigingsloket = MapHoofdactiviteitenVerenigingsloket(Request.HoofdactiviteitenVerenigingsloket), + Werkingsgebieden = MapWerkingsgebieden(Request.Werkingsgebieden), + Locaties = MapLocaties(Request.Locaties, TestContext.VCode), + Vertegenwoordigers = MapVertegenwoordigers(Request.Vertegenwoordigers, TestContext.VCode), + Relaties = MapRelaties([], TestContext.VCode), + Lidmaatschappen = [], + Sleutels = MapSleutels(Request, TestContext.VCode), + IsDubbelVan = string.Empty, + }, compareConfig: AdminDetailComparisonConfig.Instance); + + private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) + => + [ + new Sleutel + { + Bron = Sleutelbron.VR.Waarde, + id = JsonLdType.Sleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.Sleutel.Type, + Waarde = vCode, + CodeerSysteem = CodeerSysteem.VR, + GestructureerdeIdentificator = new GestructureerdeIdentificator + { + id = JsonLdType.GestructureerdeSleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.GestructureerdeSleutel.Type, + Nummer = vCode, + }, + }, + ]; + + private static Relatie[] MapRelaties(Relatie[] relaties, string vCode) + { + return relaties.Select((x, i) => new Relatie + { + AndereVereniging = x.AndereVereniging, + Relatietype = x.Relatietype, + }).ToArray(); + } + + private static Vertegenwoordiger[] MapVertegenwoordigers(ToeTeVoegenVertegenwoordiger[] vertegenwoordigers, string vCode) + { + return vertegenwoordigers.Select((x, i) => new Vertegenwoordiger + { + id = JsonLdType.Vertegenwoordiger.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Vertegenwoordiger.Type, + VertegenwoordigerId = i + 1, + PrimairContactpersoon = x.IsPrimair, + Achternaam = x.Achternaam, + Email = x.Email, + Insz = x.Insz, + Voornaam = x.Voornaam, + Roepnaam = x.Roepnaam, + Rol = x.Rol, + Telefoon = x.Telefoon, + Mobiel = x.Mobiel, + SocialMedia = x.SocialMedia, + VertegenwoordigerContactgegevens = new VertegenwoordigerContactgegevens + { + id = JsonLdType.VertegenwoordigerContactgegeven.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.VertegenwoordigerContactgegeven.Type, + IsPrimair = x.IsPrimair, + Email = x.Email, + Telefoon = x.Telefoon, + Mobiel = x.Mobiel, + SocialMedia = x.SocialMedia, + }, + Bron = Bron.Initiator, + }).ToArray(); + } + + private static Contactgegeven[] MapLocaties(ToeTeVoegenContactgegeven[] toeTeVoegenContactgegevens, string vCode) + { + return toeTeVoegenContactgegevens.Select((x, i) => new Contactgegeven + { + id = JsonLdType.Contactgegeven.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Contactgegeven.Type, + ContactgegevenId = i + 1, + Contactgegeventype = x.Contactgegeventype, + Waarde = x.Waarde, + Beschrijving = x.Beschrijving!, + IsPrimair = x.IsPrimair, + Bron = Bron.Initiator, + }).ToArray(); + } + + private static Locatie[] MapLocaties(ToeTeVoegenLocatie[] toeTeVoegenLocaties, string vCode) + { + return toeTeVoegenLocaties.Select((x, i) => new Locatie + { + id = JsonLdType.Locatie.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Locatie.Type, + LocatieId = i + 1, + Locatietype = x.Locatietype, + Naam = x.Naam, + Bron = Bron.Initiator, + IsPrimair = x.IsPrimair, + }).ToArray(); + } + + private static Admin.Api.Verenigingen.Detail.ResponseModels.HoofdactiviteitVerenigingsloket[] MapHoofdactiviteitenVerenigingsloket( + string[] hoofdactiviteitenVerenigingsloket) + { + return hoofdactiviteitenVerenigingsloket.Select(x => + { + var hoofdactiviteitVerenigingsloket = HoofdactiviteitVerenigingsloket.Create(x); + + return new Admin.Api.Verenigingen.Detail.ResponseModels.HoofdactiviteitVerenigingsloket + { + Code = hoofdactiviteitVerenigingsloket.Code, + Naam = hoofdactiviteitVerenigingsloket.Naam, + id = JsonLdType.Hoofdactiviteit.CreateWithIdValues(hoofdactiviteitVerenigingsloket.Code), + type = JsonLdType.Hoofdactiviteit.Type, + }; + }).ToArray(); + } + + private static Admin.Api.Verenigingen.Detail.ResponseModels.Werkingsgebied[] MapWerkingsgebieden(string[] werkingsgebieden) + { + return werkingsgebieden.Select(x => + { + var werkingsgebied = Werkingsgebied.Create(x); + + return new Admin.Api.Verenigingen.Detail.ResponseModels.Werkingsgebied + { + Code = werkingsgebied.Code, + Naam = werkingsgebied.Naam, + id = JsonLdType.Werkingsgebied.CreateWithIdValues(werkingsgebied.Code), + type = JsonLdType.Werkingsgebied.Type, + }; + }).ToArray(); + } + + public override Func GetResponse + => setup => setup.AdminApiHost.GetBeheerDetailWithHeader(TestContext.VCode); +} diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Without_Header/Returns_DetailResponse.cs similarity index 98% rename from test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs rename to test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Without_Header/Returns_DetailResponse.cs index 86d1cb427..199d2d304 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/Without_Header/Returns_DetailResponse.cs @@ -1,7 +1,7 @@ -namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Detail; +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Detail.Without_Header; -using Admin.Api.Verenigingen.Common; -using Admin.Api.Verenigingen.Detail.ResponseModels; +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; using Formats; using JsonLdContext; From 2e8d2e548ae568e2bc714770ccd7932d72778af7 Mon Sep 17 00:00:00 2001 From: emalfroy Date: Mon, 10 Feb 2025 15:05:35 +0100 Subject: [PATCH 02/12] test: or-2665 add request header for vzer detail response e2e tests --- .../Framework/AlbaHost/AdminApiEndpoints.cs | 14 ++++++++++++-- .../With_Header/Returns_VZER_DetailResponse.cs | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs index 0a2b505a5..7cce1a396 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs @@ -21,12 +21,22 @@ public static string GetDetailAsText(this IAlbaHost source, string vCode) public static DetailVerenigingResponse GetBeheerDetail(this IAlbaHost source, string vCode) => source.GetAsJson($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult()!; - public static DetailVerenigingResponse GetBeheerDetailWithHeader(this IAlbaHost source, string vCode) + public static DetailVerenigingResponse GetBeheerDetailWithHeader( + this IAlbaHost source, + HttpClient authenticatedClient, + string vCode) { var client = source.Server.CreateClient(); + + foreach (var defaultRequestHeader in authenticatedClient.DefaultRequestHeaders) + { + client.DefaultRequestHeaders.Add(defaultRequestHeader.Key, defaultRequestHeader.Value); + } + client.DefaultRequestHeaders.Add(VersionHeader.HeaderName, VersionHeader.V2); - var response = client.GetAsync($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult(); + var response = client.GetAsync($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult(); + var k = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); return response.Content.ReadFromJsonAsync().GetAwaiter().GetResult(); } diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs index 40367d78e..aaf1724bb 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs @@ -208,5 +208,5 @@ private static Admin.Api.Verenigingen.Detail.ResponseModels.Werkingsgebied[] Map } public override Func GetResponse - => setup => setup.AdminApiHost.GetBeheerDetailWithHeader(TestContext.VCode); + => setup => setup.AdminApiHost.GetBeheerDetailWithHeader(setup.SuperAdminHttpClient, TestContext.VCode); } From 3775136b62453b75f3f1195a50db0c214275f16a Mon Sep 17 00:00:00 2001 From: Koen Metsu Date: Tue, 11 Feb 2025 11:55:31 +0100 Subject: [PATCH 03/12] fix: or-2665 store an init event so all projections get started (hack) --- .../Framework/ApiSetup/FullBlownApiSetup.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs index 0438589fc..9f0b6cc60 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs @@ -12,6 +12,7 @@ using Marten; using Marten.Events; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -80,11 +81,12 @@ public async Task InitializeAsync() AmazonSqs = AdminApiHost.Services.GetRequiredService(); ElasticClient = AdminApiHost.Services.GetRequiredService(); - - - await AdminApiHost.DocumentStore().Storage.ApplyAllConfiguredChangesToDatabaseAsync(); + var lightweightSession = AdminApiHost.DocumentStore().LightweightSession(); + lightweightSession.Events.Append("force-init", new object()); + await lightweightSession.SaveChangesAsync(); + await AdminApiHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(1)); } public IElasticClient ElasticClient { get; set; } From 4b163ff4b8be343c722a024acda5bc555ab94a49 Mon Sep 17 00:00:00 2001 From: Koen Metsu Date: Tue, 11 Feb 2025 14:57:33 +0100 Subject: [PATCH 04/12] fix: or-2665 use expectedSequence to make sure projections are ready --- .../Constants/VersionHeader.cs | 7 ---- .../Framework/AlbaHost/AdminApiEndpoints.cs | 25 ++++++++++---- ...treerFeitelijkeVerenigingRequestFactory.cs | 11 +++--- .../Scenarios/Requests/ITestRequestFactory.cs | 2 +- .../Returns_VZER_DetailResponse.cs | 17 +++++++++- .../RegistreerFeitelijkeVerenigingContext.cs | 34 ++++++++++++++++++- 6 files changed, 76 insertions(+), 20 deletions(-) delete mode 100644 src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs diff --git a/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs b/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs deleted file mode 100644 index 2a2c37bdd..000000000 --- a/src/AssociationRegistry.Admin.Api/Constants/VersionHeader.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace AssociationRegistry.Admin.Api.Constants; - -public static class VersionHeader -{ - public const string HeaderName = "vr-api-version"; - public const string V2 = "v2"; -} diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs index 7cce1a396..b12e3384d 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs @@ -2,11 +2,15 @@ namespace AssociationRegistry.Test.E2E.Framework.AlbaHost; using Admin.Api.Administratie.DubbelControle; using Admin.Api.Constants; +using Admin.Api.Infrastructure; using Admin.Api.Verenigingen.Detail.ResponseModels; using Admin.Api.Verenigingen.Historiek.ResponseModels; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; using Admin.Api.Verenigingen.Search.ResponseModels; using Alba; +using JasperFx.Core; +using Newtonsoft.Json; +using System.Net; using System.Net.Http.Json; public static class AdminApiEndpoints @@ -21,10 +25,11 @@ public static string GetDetailAsText(this IAlbaHost source, string vCode) public static DetailVerenigingResponse GetBeheerDetail(this IAlbaHost source, string vCode) => source.GetAsJson($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult()!; - public static DetailVerenigingResponse GetBeheerDetailWithHeader( + public static async Task GetBeheerDetailWithHeader( this IAlbaHost source, HttpClient authenticatedClient, - string vCode) + string vCode, + long? expectedSequence) { var client = source.Server.CreateClient(); @@ -33,11 +38,19 @@ public static DetailVerenigingResponse GetBeheerDetailWithHeader( client.DefaultRequestHeaders.Add(defaultRequestHeader.Key, defaultRequestHeader.Value); } - client.DefaultRequestHeaders.Add(VersionHeader.HeaderName, VersionHeader.V2); + client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); - var response = client.GetAsync($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult(); - var k = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); - return response.Content.ReadFromJsonAsync().GetAwaiter().GetResult(); + var response = await client.GetAsync($"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); + + while (response.StatusCode == HttpStatusCode.PreconditionFailed) + { + await Task.Delay(300); + response = await client.GetAsync($"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); + } + + var readAsStringAsync = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(readAsStringAsync); } public static DubbelControleResponse[] PostDubbelControle(this IAlbaHost source, RegistreerFeitelijkeVerenigingRequest registreerFeitelijkeVerenigingRequest) diff --git a/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/RegistreerFeitelijkeVerenigingRequestFactory.cs b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/RegistreerFeitelijkeVerenigingRequestFactory.cs index fcc35d1ef..b591e24d8 100644 --- a/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/RegistreerFeitelijkeVerenigingRequestFactory.cs +++ b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/FeitelijkeVereniging/RegistreerFeitelijkeVerenigingRequestFactory.cs @@ -129,7 +129,7 @@ public async Task> ExecuteR Werkingsgebieden = ["BE25", "BE25535002"], }; - var vCode = (await apiSetup.AdminApiHost.Scenario(s => + var response = (await apiSetup.AdminApiHost.Scenario(s => { s.Post .Json(request, JsonStyle.Mvc) @@ -144,10 +144,13 @@ public async Task> ExecuteR s.Header(WellknownHeaderNames.Sequence).ShouldHaveValues(); s.Header(WellknownHeaderNames.Sequence).SingleValueShouldMatch(_isPositiveInteger); - })).Context.Response.Headers.Location.First().Split('/').Last(); + })).Context.Response; - await apiSetup.AdminApiHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(60)); + var vCode = response.Headers.Location.First().Split('/').Last(); + long sequence = Convert.ToInt64(response.Headers[WellknownHeaderNames.Sequence].First()); - return new RequestResult(VCode.Create(vCode), request); + await apiSetup.AdminProjectionDaemon.WaitForNonStaleData(TimeSpan.FromSeconds(60)); + + return new RequestResult(VCode.Create(vCode), request, sequence); } } diff --git a/test/AssociationRegistry.Test.E2E/Scenarios/Requests/ITestRequestFactory.cs b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/ITestRequestFactory.cs index e9fe8eb75..36d4eac83 100644 --- a/test/AssociationRegistry.Test.E2E/Scenarios/Requests/ITestRequestFactory.cs +++ b/test/AssociationRegistry.Test.E2E/Scenarios/Requests/ITestRequestFactory.cs @@ -8,4 +8,4 @@ public interface ITestRequestFactory Task> ExecuteRequest(IApiSetup apiSetup); } -public record RequestResult(VCode VCode, TRequest Request); +public record RequestResult(VCode VCode, TRequest Request, long? Sequence = null); diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs index aaf1724bb..2684be2fe 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Detail/With_Header/Returns_VZER_DetailResponse.cs @@ -1,5 +1,6 @@ namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Detail.With_Header; +using Admin.Api; using AssociationRegistry.Admin.Api.Verenigingen.Common; using AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; @@ -12,7 +13,10 @@ namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Behe using Vereniging; using Vereniging.Bronnen; using KellermanSoftware.CompareNetObjects; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using NodaTime; +using Serilog; using Xunit; using Contactgegeven = Admin.Api.Verenigingen.Detail.ResponseModels.Contactgegeven; using HoofdactiviteitVerenigingsloket = Vereniging.HoofdactiviteitVerenigingsloket; @@ -208,5 +212,16 @@ private static Admin.Api.Verenigingen.Detail.ResponseModels.Werkingsgebied[] Map } public override Func GetResponse - => setup => setup.AdminApiHost.GetBeheerDetailWithHeader(setup.SuperAdminHttpClient, TestContext.VCode); + { + get { return setup => + { + var logger = setup.AdminApiHost.Services.GetRequiredService>(); + + logger.LogInformation("EXECUTING GET REQUEST"); + + return setup.AdminApiHost.GetBeheerDetailWithHeader(setup.SuperAdminHttpClient, TestContext.RequestResult.VCode, + TestContext.RequestResult.Sequence) + .GetAwaiter().GetResult(); + }; } + } } diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/RegistreerFeitelijkeVerenigingContext.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/RegistreerFeitelijkeVerenigingContext.cs index 907410ae5..4cadb385e 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/RegistreerFeitelijkeVerenigingContext.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/RegistreerFeitelijkeVerenigingContext.cs @@ -1,10 +1,15 @@ namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging; +using Admin.Api; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; using Framework.ApiSetup; using Framework.TestClasses; +using JasperFx.Core; using Marten.Events; +using Marten.Events.Daemon; +using Marten.Events.Daemon.Coordination; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Nest; using Scenarios.Givens; using Scenarios.Requests.FeitelijkeVereniging; @@ -13,6 +18,7 @@ namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging; public class RegistreerFeitelijkeVerenigingTestContext: TestContextBase { private EmptyScenario _emptyScenario; + private readonly ILogger _logger; public VCode VCode => RequestResult.VCode; public RegistreerFeitelijkeVerenigingTestContext(FullBlownApiSetup apiSetup) @@ -37,13 +43,39 @@ public override async Task InitializeAsync() public override async Task Init() { + var logger = ApiSetup.AdminApiHost.Services.GetRequiredService>(); + _emptyScenario = new EmptyScenario(); var requestFactory = new RegistreerFeitelijkeVerenigingRequestFactory(); + var daemon = ApiSetup.AdminProjectionDaemon; + + logger.LogInformation("Starting up shards (running: {IsRunning})", daemon.IsRunning); + + await ApiSetup.ExecuteGiven(_emptyScenario); + + logger.LogInformation("Executing registreer feitelijke vereniging request"); + RequestResult = await requestFactory.ExecuteRequest(ApiSetup); - await ApiSetup.AdminProjectionHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(10)); + + + await daemon.WaitForNonStaleData(TimeSpan.FromSeconds(10)); + + var agents = daemon.CurrentAgents().Select(x => new + { + x.Name.Identity, x.Position, x.Status + }); + + logger.LogInformation("Daemon agents {@Says}", agents.Select(x => $" {x.Identity}: {x.Position} ({x.Status})|")); + + logger.LogInformation("Waiting for non stale data...(running: {IsRunning})", daemon.IsRunning); + + logger.LogInformation("Refreshing indices"); + await ApiSetup.AdminApiHost.Services.GetRequiredService().Indices.RefreshAsync(Indices.All); + + logger.LogInformation("Initialisation complete"); } } From 4654f7be5ec0ec0d544fa0518a9115732343956b Mon Sep 17 00:00:00 2001 From: Koen Metsu Date: Tue, 11 Feb 2025 15:01:01 +0100 Subject: [PATCH 05/12] fix: or-2665 update marten, add healtchecks, move version header --- paket.dependencies | 2 +- paket.lock | 210 ++++++++++++------ .../Infrastructure/WellknownHeaderNames.cs | 6 + .../Metrics/ProjectionStateListener.cs | 56 ----- .../ConfigureMartenExtensions.cs | 5 +- .../Program.cs | 29 ++- .../paket.references | 3 +- .../paket.references | 5 +- .../Framework/ApiSetup/FullBlownApiSetup.cs | 26 ++- .../Framework/ApiSetup/IApiSetup.cs | 4 + .../appsettings.e2e.adminapi.json | 6 + .../appsettings.e2e.adminproj.json | 5 + .../appsettings.e2e.json | 10 +- 13 files changed, 223 insertions(+), 144 deletions(-) diff --git a/paket.dependencies b/paket.dependencies index 54d8743de..1286ee665 100644 --- a/paket.dependencies +++ b/paket.dependencies @@ -35,6 +35,7 @@ nuget IdentityModel.AspNetCore.OAuth2Introspection nuget CompareNETObjects nuget Marten +nuget Marten.AspNetCore 7.37.1 nuget Marten.Commandline nuget Microsoft.AspNetCore.App.Ref @@ -116,4 +117,3 @@ nuget NEST 7.17.4 nuget Npgsql - diff --git a/paket.lock b/paket.lock index 488192c0c..864cf1b5c 100644 --- a/paket.lock +++ b/paket.lock @@ -219,7 +219,7 @@ NUGET System.Buffers (>= 4.5.1) System.Diagnostics.DiagnosticSource (>= 5.0) Fare (2.2.1) - FastExpressionCompiler (4.2) + FastExpressionCompiler (5.0.2) FluentAssertions (6.12) System.Configuration.ConfigurationManager (>= 4.4) FluentAssertions.Json (6.1) @@ -236,6 +236,7 @@ NUGET Microsoft.Extensions.FileProviders.Abstractions (>= 8.0) Parlot (>= 0.0.25) TimeZoneConverter (>= 6.1) + FSharp.Core (9.0.101) Google.Protobuf (3.26.1) Grpc.Core.Api (2.62) Grpc.Net.Client (2.62) @@ -247,21 +248,21 @@ NUGET IdentityModel (7.0) IdentityModel.AspNetCore.OAuth2Introspection (6.2) IdentityModel (>= 6.0) - JasperFx.CodeGeneration (3.5.3) - FastExpressionCompiler (>= 4.1) - JasperFx.Core (>= 1.5) - JasperFx.CodeGeneration.Commands (3.5.3) - JasperFx.CodeGeneration (>= 3.5.3) - JasperFx.RuntimeCompiler (>= 3.5.3) - Oakton (>= 6.1) - JasperFx.Core (1.8) + JasperFx.CodeGeneration (3.7.2) + FastExpressionCompiler (>= 4.2.2) + JasperFx.Core (>= 1.9) + JasperFx.CodeGeneration.Commands (3.7.2) + JasperFx.CodeGeneration (>= 3.7.2) + JasperFx.RuntimeCompiler (>= 3.7.2) + Oakton (>= 6.3) + JasperFx.Core (1.12) Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0) - JasperFx.RuntimeCompiler (3.5.3) - JasperFx.CodeGeneration (>= 3.5.3) - Microsoft.CodeAnalysis (>= 4.8) - Microsoft.CodeAnalysis.CSharp (>= 4.8) - Microsoft.CodeAnalysis.Scripting (>= 4.8) - Microsoft.Extensions.Logging.Abstractions (>= 6.0 < 9.0) + JasperFx.RuntimeCompiler (3.7.2) + JasperFx.CodeGeneration (>= 3.7.2) + Microsoft.CodeAnalysis (>= 4.11) + Microsoft.CodeAnalysis.CSharp (>= 4.11) + Microsoft.CodeAnalysis.Scripting (>= 4.11) + Microsoft.Extensions.Logging.Abstractions (>= 6.0 < 10.0) Lamar (13.0.4) JasperFx.CodeGeneration (>= 3.4) JasperFx.Core (>= 1.5.1) @@ -275,25 +276,29 @@ NUGET Microsoft.Extensions.Logging (>= 8.0) Microsoft.Extensions.Options (>= 8.0) librdkafka.redist (2.4) - Marten (7.23.1) - JasperFx.CodeGeneration (>= 3.5.3) - JasperFx.Core (>= 1.7.2) - JasperFx.RuntimeCompiler (>= 3.5.3) + Marten (7.37.1) + FSharp.Core (>= 9.0.100) + JasperFx.CodeGeneration (>= 3.7.2) + JasperFx.Core (>= 1.12) + JasperFx.RuntimeCompiler (>= 3.7.2) Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0) Microsoft.Extensions.Hosting.Abstractions (>= 8.0) Microsoft.Extensions.Logging.Abstractions (>= 8.0) Newtonsoft.Json (>= 13.0.3) Npgsql.Json.NET (>= 8.0) OpenTelemetry.Api (>= 1.8) - Polly.Core (>= 8.3.1) - System.Text.Json (>= 8.0) + Polly.Core (>= 8.5) + System.Text.Json (>= 8.0.5) System.Threading.Tasks.Dataflow (>= 8.0) - Weasel.Postgresql (>= 7.4.1) - Marten.CommandLine (7.23.1) - JasperFx.CodeGeneration.Commands (>= 3.5.3) - Marten (>= 7.23.1) - Oakton (>= 6.1) - Weasel.CommandLine (>= 7.4.1) + Weasel.Postgresql (>= 7.13.5) + Marten.AspNetCore (7.37.1) + Marten (>= 7.37.1) + Microsoft.Extensions.Diagnostics.HealthChecks (>= 8.0) + Marten.CommandLine (7.37.1) + JasperFx.CodeGeneration.Commands (>= 3.7.1) + Marten (>= 7.37.1) + Oakton (>= 6.3) + Weasel.CommandLine (>= 7.13.2) Microsoft.AspNetCore.App.Ref (8.0.6) Microsoft.AspNetCore.Authentication.JwtBearer (8.0.7) Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 7.1.2) @@ -354,43 +359,94 @@ NUGET Microsoft.Net.Http.Headers (>= 8.0.5) System.IO.Pipelines (>= 8.0) Microsoft.Bcl.AsyncInterfaces (8.0) - Microsoft.CodeAnalysis (4.9.2) - Microsoft.CodeAnalysis.CSharp.Workspaces (4.9.2) - Microsoft.CodeAnalysis.VisualBasic.Workspaces (4.9.2) - Microsoft.CodeAnalysis.Analyzers (3.3.4) - Microsoft.CodeAnalysis.Common (4.9.2) + Microsoft.CodeAnalysis (4.12) + Humanizer.Core (>= 2.14.1) + Microsoft.Bcl.AsyncInterfaces (>= 8.0) Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.CSharp.Workspaces (4.12) + Microsoft.CodeAnalysis.VisualBasic.Workspaces (4.12) + System.Buffers (>= 4.5.1) System.Collections.Immutable (>= 8.0) + System.Composition (>= 8.0) + System.IO.Pipelines (>= 8.0) + System.Memory (>= 4.5.5) + System.Numerics.Vectors (>= 4.5) System.Reflection.Metadata (>= 8.0) System.Runtime.CompilerServices.Unsafe (>= 6.0) - Microsoft.CodeAnalysis.CSharp (4.9.2) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.CSharp.Scripting (4.9.2) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.CSharp (4.9.2) - Microsoft.CodeAnalysis.Scripting.Common (4.9.2) + System.Text.Encoding.CodePages (>= 7.0) + System.Threading.Channels (>= 7.0) + System.Threading.Tasks.Extensions (>= 4.5.4) + Microsoft.CodeAnalysis.Analyzers (3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + System.Collections.Immutable (>= 8.0) + System.Reflection.Metadata (>= 8.0) + Microsoft.CodeAnalysis.CSharp (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + System.Collections.Immutable (>= 8.0) + System.Reflection.Metadata (>= 8.0) + Microsoft.CodeAnalysis.CSharp.Scripting (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + Microsoft.CodeAnalysis.CSharp (4.12) + Microsoft.CodeAnalysis.Scripting.Common (4.12) Microsoft.CSharp (>= 4.7) - Microsoft.CodeAnalysis.CSharp.Workspaces (4.9.2) + System.Collections.Immutable (>= 8.0) + System.Reflection.Metadata (>= 8.0) + Microsoft.CodeAnalysis.CSharp.Workspaces (4.12) Humanizer.Core (>= 2.14.1) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.CSharp (4.9.2) - Microsoft.CodeAnalysis.Workspaces.Common (4.9.2) - Microsoft.CodeAnalysis.Scripting (4.9.2) - Microsoft.CodeAnalysis.CSharp.Scripting (4.9.2) - Microsoft.CodeAnalysis.Scripting.Common (4.9.2) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.VisualBasic (4.9.2) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.VisualBasic.Workspaces (4.9.2) - Microsoft.CodeAnalysis.Common (4.9.2) - Microsoft.CodeAnalysis.VisualBasic (4.9.2) - Microsoft.CodeAnalysis.Workspaces.Common (4.9.2) - Microsoft.CodeAnalysis.Workspaces.Common (4.9.2) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + Microsoft.CodeAnalysis.CSharp (4.12) + Microsoft.CodeAnalysis.Workspaces.Common (4.12) + System.Collections.Immutable (>= 8.0) + System.Composition (>= 8.0) + System.IO.Pipelines (>= 8.0) + System.Reflection.Metadata (>= 8.0) + System.Threading.Channels (>= 7.0) + Microsoft.CodeAnalysis.Scripting (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.CSharp.Scripting (4.12) + Microsoft.CSharp (>= 4.7) + System.Buffers (>= 4.5.1) + System.Collections.Immutable (>= 8.0) + System.Memory (>= 4.5.5) + System.Numerics.Vectors (>= 4.5) + System.Reflection.Metadata (>= 8.0) + System.Runtime.CompilerServices.Unsafe (>= 6.0) + System.Text.Encoding.CodePages (>= 7.0) + System.Threading.Tasks.Extensions (>= 4.5.4) + Microsoft.CodeAnalysis.Scripting.Common (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + System.Collections.Immutable (>= 8.0) + System.Reflection.Metadata (>= 8.0) + Microsoft.CodeAnalysis.VisualBasic (4.12) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + System.Collections.Immutable (>= 8.0) + System.Reflection.Metadata (>= 8.0) + Microsoft.CodeAnalysis.VisualBasic.Workspaces (4.12) + Humanizer.Core (>= 2.14.1) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + Microsoft.CodeAnalysis.VisualBasic (4.12) + Microsoft.CodeAnalysis.Workspaces.Common (4.12) + System.Collections.Immutable (>= 8.0) + System.Composition (>= 8.0) + System.IO.Pipelines (>= 8.0) + System.Reflection.Metadata (>= 8.0) + System.Threading.Channels (>= 7.0) + Microsoft.CodeAnalysis.Workspaces.Common (4.12) Humanizer.Core (>= 2.14.1) - Microsoft.CodeAnalysis.Common (4.9.2) + Microsoft.CodeAnalysis.Analyzers (>= 3.3.4) + Microsoft.CodeAnalysis.Common (4.12) + System.Collections.Immutable (>= 8.0) System.Composition (>= 8.0) System.IO.Pipelines (>= 8.0) - System.Threading.Channels (>= 8.0) + System.Reflection.Metadata (>= 8.0) + System.Threading.Channels (>= 7.0) Microsoft.CodeCoverage (17.10) Microsoft.CSharp (4.7) Microsoft.Data.SqlClient (5.2) @@ -628,6 +684,10 @@ NUGET Elasticsearch.Net (>= 7.17.4) NETStandard.Library (2.0.3) Microsoft.NETCore.Platforms (>= 1.1) + NetTopologySuite (2.5) + System.Memory (>= 4.5.4) + NetTopologySuite.IO.PostGis (2.1) + NetTopologySuite (>= 2.0 < 3.0.0-A) Newtonsoft.Json (13.0.3) Newtonsoft.Json.Bson (1.0.2) Newtonsoft.Json (>= 12.0.1) @@ -648,11 +708,15 @@ NUGET NodaTime.Serialization.JsonNet (3.1) Newtonsoft.Json (>= 13.0.3) NodaTime (>= 3.0 < 4.0) - Npgsql (8.0.3) + Npgsql (8.0.6) Microsoft.Extensions.Logging.Abstractions (>= 8.0) Npgsql.Json.NET (8.0.3) Newtonsoft.Json (>= 13.0.3) Npgsql (>= 8.0.3) + Npgsql.NetTopologySuite (8.0.6) + NetTopologySuite (>= 2.5) + NetTopologySuite.IO.PostGis (>= 2.1) + Npgsql (>= 8.0.6) Npgsql.OpenTelemetry (8.0.3) Npgsql (>= 8.0.3) OpenTelemetry.Api (>= 1.6) @@ -667,9 +731,9 @@ NUGET NSwag.CodeGeneration (>= 14.0.7) NSwag.Core (14.0.7) NJsonSchema (>= 11.0) - Oakton (6.1) - JasperFx.Core (>= 1.5.1) - Microsoft.Extensions.Hosting (>= 6.0 < 9.0) + Oakton (6.3) + JasperFx.Core (>= 1.9) + Microsoft.Extensions.Hosting (>= 6.0 < 10.0) Spectre.Console (>= 0.47) OpenTelemetry (1.9) Microsoft.Extensions.Diagnostics.Abstractions (>= 8.0) @@ -713,7 +777,7 @@ NUGET Parlot (0.0.27) Polly (8.4) Polly.Core (>= 8.4) - Polly.Core (8.4) + Polly.Core (8.5.2) Result.Net (1.4) runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) runtime.debian.9-x64.runtime.native.System.Security.Cryptography.OpenSsl (4.3.3) @@ -919,7 +983,7 @@ NUGET System.Threading.Tasks (>= 4.3) System.IO.FileSystem.Primitives (4.3) System.Runtime (>= 4.3) - System.IO.Pipelines (8.0) + System.IO.Pipelines (9.0.1) System.Linq (4.3) System.Collections (>= 4.3) System.Diagnostics.Debug (>= 4.3) @@ -1135,9 +1199,10 @@ NUGET Microsoft.NETCore.Targets (>= 1.1) System.Runtime (>= 4.3) System.Text.Encoding (>= 4.3) - System.Text.Encodings.Web (8.0) - System.Text.Json (8.0.4) - System.Text.Encodings.Web (>= 8.0) + System.Text.Encodings.Web (9.0.1) + System.Text.Json (9.0.1) + System.IO.Pipelines (>= 9.0.1) + System.Text.Encodings.Web (>= 9.0.1) System.Text.RegularExpressions (4.3.1) System.Runtime (>= 4.3.1) System.Threading (4.3) @@ -1167,14 +1232,15 @@ NUGET System.Threading.Tasks (>= 4.3) System.Threading.Tasks.Extensions (>= 4.3) TimeZoneConverter (6.1) - Weasel.CommandLine (7.6) - Oakton (>= 6.1) - Weasel.Core (>= 7.6) - Weasel.Core (7.6) - JasperFx.Core (>= 1.5.1) - Weasel.Postgresql (7.6) - Npgsql (>= 8.0.3) - Weasel.Core (>= 7.6) + Weasel.CommandLine (7.13.5) + Oakton (>= 6.3) + Weasel.Core (>= 7.13.5) + Weasel.Core (7.13.5) + JasperFx.Core (>= 1.9) + Weasel.Postgresql (7.13.5) + Npgsql (>= 8.0.6) + Npgsql.NetTopologySuite (>= 8.0.6) + Weasel.Core (>= 7.13.5) WolverineFx (2.9) FastExpressionCompiler (>= 4.1) JasperFx.CodeGeneration.Commands (>= 3.5.2) diff --git a/src/AssociationRegistry.Admin.Api/Infrastructure/WellknownHeaderNames.cs b/src/AssociationRegistry.Admin.Api/Infrastructure/WellknownHeaderNames.cs index f4d12cfec..3e043a0f3 100644 --- a/src/AssociationRegistry.Admin.Api/Infrastructure/WellknownHeaderNames.cs +++ b/src/AssociationRegistry.Admin.Api/Infrastructure/WellknownHeaderNames.cs @@ -7,4 +7,10 @@ public class WellknownHeaderNames public const string Initiator = "VR-Initiator"; public const string IfMatch = "If-Match"; public const string CorrelationId = "X-Correlation-Id"; + public const string Version = "VR-Api-Version"; +} + +public class WellknownVersions +{ + public const string V2 = "v2"; } diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Metrics/ProjectionStateListener.cs b/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Metrics/ProjectionStateListener.cs index e3248b8a7..af3eac981 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Metrics/ProjectionStateListener.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Metrics/ProjectionStateListener.cs @@ -1,66 +1,10 @@ namespace AssociationRegistry.Admin.ProjectionHost.Infrastructure.Metrics; -using Marten; -using Marten.Events; using Marten.Events.Daemon; -using Marten.Events.Daemon.Internals; -using Marten.Internal.Operations; -using Marten.Services; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; -using Projections.Detail; -using Projections.Historiek; -using Projections.Locaties; using System.Reflection; -public class ProjectionStateListener : DocumentSessionListenerBase -{ - private readonly AdminInstrumentation _adminInstrumentation; - - public ProjectionStateListener(AdminInstrumentation adminInstrumentation) - { - _adminInstrumentation = adminInstrumentation; - } - - public override Task AfterCommitAsync(IDocumentSession session, IChangeSet commit, CancellationToken token) - { - if (commit is not IUnitOfWork uow) return Task.CompletedTask; - var operations = uow.OperationsFor(); - - foreach (var operation in operations) - { - var range = GetEventRange(operation); - - if (range is null) continue; - - if (range.ShardName.ProjectionName == "BeheerVerenigingZoekenDocument") - _adminInstrumentation.VerenigingZoekenEventValue = range.SequenceCeiling; - - if (range.ShardName.ProjectionName == typeof(BeheerVerenigingDetailProjection).FullName) - _adminInstrumentation.VerenigingDetailEventValue = range.SequenceCeiling; - - if (range.ShardName.ProjectionName == typeof(LocatieLookupProjection).FullName) - _adminInstrumentation.LocatieLookupEventValue = range.SequenceCeiling; - - if (range.ShardName.ProjectionName == typeof(BeheerVerenigingHistoriekProjection).FullName) - _adminInstrumentation.VerenigingHistoriekEventValue = range.SequenceCeiling; - } - - return Task.CompletedTask; - } - - private static EventRange? GetEventRange(IStorageOperation opperation) - { - return opperation.GetType().Name switch - { - "InsertProjectionProgress" => opperation.GetType().GetField(name: "_progress", BindingFlags.NonPublic | BindingFlags.Instance) - .GetValue(opperation) as EventRange, - "UpdateProjectionProgress" => opperation.GetType().GetProperty("Range").GetValue(opperation) as EventRange, - _ => null, - }; - } -} - public class AllFieldsContractResolver : DefaultContractResolver { protected override IList CreateProperties(Type type, MemberSerialization memberSerialization) diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Program/WebApplicationBuilder/ConfigureMartenExtensions.cs b/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Program/WebApplicationBuilder/ConfigureMartenExtensions.cs index bda3a73e2..225be51cb 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Program/WebApplicationBuilder/ConfigureMartenExtensions.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Infrastructure/Program/WebApplicationBuilder/ConfigureMartenExtensions.cs @@ -32,7 +32,8 @@ public static class ConfigureMartenExtensions { public static IServiceCollection ConfigureProjectionsWithMarten( this IServiceCollection source, - ConfigurationManager configurationManager) + ConfigurationManager configurationManager, + bool isDevelopment) { source .AddTransient(); @@ -40,7 +41,7 @@ public static IServiceCollection ConfigureProjectionsWithMarten( var martenConfiguration = AddMarten(source, configurationManager); if (configurationManager["ProjectionDaemonDisabled"]?.ToLowerInvariant() != "true") - martenConfiguration.AddAsyncDaemon(DaemonMode.HotCold); + martenConfiguration.AddAsyncDaemon(isDevelopment ? DaemonMode.Solo : DaemonMode.HotCold); return source; } diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Program.cs b/src/AssociationRegistry.Admin.ProjectionHost/Program.cs index a014b5e1d..c339863ab 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Program.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Program.cs @@ -10,6 +10,7 @@ namespace AssociationRegistry.Admin.ProjectionHost; using Infrastructure.Program.WebApplication; using Infrastructure.Program.WebApplicationBuilder; using JasperFx.CodeGeneration; +using Marten.Events.Daemon; using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Mvc.NewtonsoftJson; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -65,13 +66,15 @@ public static async Task Main(string[] args) builder.Services .ConfigureRequestLocalization() - .ConfigureProjectionsWithMarten(builder.Configuration) + .ConfigureProjectionsWithMarten(builder.Configuration, builder.Environment.IsDevelopment()) .ConfigureSwagger() .ConfigureElasticSearch(elasticSearchOptions) .AddMvc() .AddDataAnnotationsLocalization(); - builder.Services.AddHealthChecks(); + builder.Services + .AddHealthChecks() + .AddMartenAsyncDaemonHealthCheck(); builder.Services.TryAddEnumerable(ServiceDescriptor.Transient()); @@ -88,6 +91,7 @@ public static async Task Main(string[] args) // app.SetUpSwagger(); ConfigureHealtChecks(app); + ConfigureLifetimeHooks(app); await app.RunOaktonCommands(args); } @@ -161,6 +165,27 @@ private static void ConfigureHealtChecks(WebApplication app) app.UseHealthChecks(path: "/health", healthCheckOptions); } + + private static void ConfigureLifetimeHooks(WebApplication app) + { + app.Lifetime.ApplicationStarted.Register(() => Log.Information("Admin Projections Application started")); + + app.Lifetime.ApplicationStopping.Register( + () => + { + Log.Information("Admin Projections Application stopping"); + Log.CloseAndFlush(); + }); + + Console.CancelKeyPress += (_, eventArgs) => + { + app.Lifetime.StopApplication(); + + // Don't terminate the process immediately, wait for the Main thread to exit gracefully. + eventArgs.Cancel = true; + }; + } + } public static class ResponseExtensions diff --git a/src/AssociationRegistry.Admin.ProjectionHost/paket.references b/src/AssociationRegistry.Admin.ProjectionHost/paket.references index 7f55f0441..d725b3eb7 100755 --- a/src/AssociationRegistry.Admin.ProjectionHost/paket.references +++ b/src/AssociationRegistry.Admin.ProjectionHost/paket.references @@ -16,4 +16,5 @@ Destructurama.JsonNet FluentValidation Polly Marten.CommandLine -WolverineFx \ No newline at end of file +Marten.AspNetCore +WolverineFx diff --git a/src/AssociationRegistry.PowerBi.ExportHost/paket.references b/src/AssociationRegistry.PowerBi.ExportHost/paket.references index eda7eaf34..58c986bbf 100644 --- a/src/AssociationRegistry.PowerBi.ExportHost/paket.references +++ b/src/AssociationRegistry.PowerBi.ExportHost/paket.references @@ -1,9 +1,7 @@ CSVHelper Marten NodaTime - AWSSDK.S3 - Serilog Serilog.Enrichers.Environment Serilog.Enrichers.Thread @@ -12,7 +10,6 @@ Serilog.Formatting.Compact Serilog.Settings.Configuration Serilog.Sinks.File Serilog.Sinks.Console - OpenTelemetry OpenTelemetry.Api OpenTelemetry.Exporter.Console @@ -22,8 +19,8 @@ OpenTelemetry.Extensions.Hosting OpenTelemetry.Instrumentation.Http OpenTelemetry.Instrumentation.Runtime NpgSql.OpenTelemetry - Destructurama.JsonNet Microsoft.Extensions.Hosting Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Http +Marten.AspNetCore \ No newline at end of file diff --git a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs index 9f0b6cc60..6efefe705 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/FullBlownApiSetup.cs @@ -11,6 +11,8 @@ using IdentityModel.AspNetCore.OAuth2Introspection; using Marten; using Marten.Events; +using Marten.Events.Daemon; +using Marten.Events.Daemon.Coordination; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.Configuration; @@ -83,12 +85,28 @@ public async Task InitializeAsync() ElasticClient = AdminApiHost.Services.GetRequiredService(); await AdminApiHost.DocumentStore().Storage.ApplyAllConfiguredChangesToDatabaseAsync(); - var lightweightSession = AdminApiHost.DocumentStore().LightweightSession(); - lightweightSession.Events.Append("force-init", new object()); - await lightweightSession.SaveChangesAsync(); - await AdminApiHost.WaitForNonStaleProjectionDataAsync(TimeSpan.FromSeconds(1)); + AdminProjectionDaemon = AdminProjectionHost.Services.GetRequiredService().DaemonForMainDatabase(); + + var agents = AdminProjectionDaemon.CurrentAgents().Select(x => new + { + x.Name.Identity, x.Position, x.Status + }); + + + while (!agents.Any()) + { + Logger.LogInformation("Daemon Startup {@Says}", agents.Select(x => $" {x.Identity}: {x.Position} ({x.Status})|")); + await Task.Delay(500); + agents = AdminProjectionDaemon.CurrentAgents().Select(x => new + { + x.Name.Identity, x.Position, x.Status + }); + + } + Logger.LogInformation("Daemon Startup {@Says}", agents.Select(x => $" {x.Identity}: {x.Position} ({x.Status})|")); } + public IProjectionDaemon AdminProjectionDaemon { get; private set; } public IElasticClient ElasticClient { get; set; } public HttpClient SuperAdminHttpClient { get; private set; } diff --git a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/IApiSetup.cs b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/IApiSetup.cs index efdeb8a08..b9729cc78 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/IApiSetup.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/ApiSetup/IApiSetup.cs @@ -1,6 +1,7 @@ namespace AssociationRegistry.Test.E2E.Framework.ApiSetup; using Alba; +using Marten.Events.Daemon; using TestClasses; public interface IApiSetup @@ -11,5 +12,8 @@ public interface IApiSetup public IAlbaHost AdminProjectionHost { get; } public IAlbaHost PublicProjectionHost { get; } public IAlbaHost PublicApiHost { get; } + + public IProjectionDaemon AdminProjectionDaemon { get; } + Task ExecuteGiven(IScenario scenario); } diff --git a/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminapi.json b/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminapi.json index 2665c0737..2c1f3414e 100644 --- a/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminapi.json +++ b/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminapi.json @@ -54,6 +54,12 @@ "Timeout": 30 } }, + + "Serilog": { + "Properties": { + "Application": "AssociationRegistry - Admin Api" + } + }, "BaseUrl": "http://127.0.0.1:11004", "TemporaryMagdaVertegenwoordigers": "{\"TemporaryVertegenwoordigers\": [{\"Insz\": \"1234567890\",\"Voornaam\": \"Ikkeltje\",\"Achternaam\": \"Persoon\"},{\"Insz\": \"0987654321\",\"Voornaam\": \"Kramikkeltje\",\"Achternaam\": \"Persoon\"}]}" } diff --git a/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminproj.json b/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminproj.json index dce0f4be7..779e56bba 100644 --- a/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminproj.json +++ b/test/AssociationRegistry.Test.E2E/appsettings.e2e.adminproj.json @@ -17,5 +17,10 @@ "GrarSyncOptions": { "GrarSyncSqsQueueName": "verenigingsregister-grarsync-e2e", "GrarSyncSqsDeadLetterQueueName": "verenigingsregister-grarsync-e2e-dlq", + }, + "Serilog": { + "Properties": { + "Application": "AssociationRegistry - Admin Projections" + } } } diff --git a/test/AssociationRegistry.Test.E2E/appsettings.e2e.json b/test/AssociationRegistry.Test.E2E/appsettings.e2e.json index 347c3c9cd..5c9894a01 100644 --- a/test/AssociationRegistry.Test.E2E/appsettings.e2e.json +++ b/test/AssociationRegistry.Test.E2E/appsettings.e2e.json @@ -3,7 +3,7 @@ "Host": "127.0.0.1", "database": "fullblowne2e", "username": "root", - "password": "root", + "password": "root" }, "BeheerProjectionHostBaseUrl": "http://127.0.0.1:11006/", "PublicApiBaseUrl": "http://127.0.0.1:11003/", @@ -12,5 +12,11 @@ "KboSyncQueueName": "does-not-exist", "SuperAdminClientIds": [ "superAdminClient" - ] + ], + + "Serilog": { + "Properties": { + "Application": "AssociationRegistry - Unknown" + } + } } From b52f8d36554e36ec08aa1ef741402518c71c6fdd Mon Sep 17 00:00:00 2001 From: emalfroy Date: Tue, 11 Feb 2025 15:53:09 +0100 Subject: [PATCH 06/12] feat: or-2665 return vzer for beheer detail when using v2 api --- .../Detail/BeheerVerenigingDetailMapper.cs | 25 ++++++++++++++----- .../Detail/DetailVerenigingenController.cs | 5 +++- .../Vereniging/Verenigingstype.cs | 3 +++ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs index e9d5afd86..b5102348a 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs @@ -3,6 +3,7 @@ using AssociationRegistry.Admin.Schema.Detail; using AssociationRegistry.Formats; using AssociationRegistry.Hosts.Configuration.ConfigurationBindings; +using Infrastructure; using ResponseModels; using Adres = ResponseModels.Adres; using AdresId = ResponseModels.AdresId; @@ -30,11 +31,11 @@ public BeheerVerenigingDetailMapper(AppSettings appSettings, INamenVoorLidmaatsc _namenVoorLidmaatschapMapper = namenVoorLidmaatschapMapper; } - public DetailVerenigingResponse Map(BeheerVerenigingDetailDocument vereniging) + public DetailVerenigingResponse Map(BeheerVerenigingDetailDocument vereniging, string? version) => new() { Context = $"{_appSettings.PublicApiBaseUrl}/v1/contexten/beheer/detail-vereniging-context.json", - Vereniging = Map(vereniging, _namenVoorLidmaatschapMapper, _appSettings.BaseUrl), + Vereniging = Map(vereniging, _namenVoorLidmaatschapMapper, _appSettings.BaseUrl, version), Metadata = MapMetadata(vereniging), }; @@ -47,14 +48,15 @@ private static Metadata MapMetadata(BeheerVerenigingDetailDocument vereniging) private static VerenigingDetail Map( BeheerVerenigingDetailDocument vereniging, INamenVoorLidmaatschapMapper namenVoorLidmaatschapMapper, - string baseUrl) + string baseUrl, + string? version) { return new VerenigingDetail { type = vereniging.JsonLdMetadataType, VCode = vereniging.VCode, CorresponderendeVCodes = vereniging.CorresponderendeVCodes, - Verenigingstype = Map(vereniging.Verenigingstype), + Verenigingstype = Map(vereniging.Verenigingstype, version), Naam = vereniging.Naam, Roepnaam = vereniging.Roepnaam, KorteNaam = vereniging.KorteNaam, @@ -120,12 +122,23 @@ private static GerelateerdeVereniging Map( : string.Empty, }; - private static VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) - => new() + private static VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType, string? version) + { + if (Vereniging.Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code) && version == WellknownVersions.V2) + { + return new VerenigingsType + { + Code = Vereniging.Verenigingstype.VZER.Code, + Naam = Vereniging.Verenigingstype.VZER.Naam, + }; + } + + return new VerenigingsType { Code = verenigingsType.Code, Naam = verenigingsType.Naam, }; + } private static Sleutel Map(Schema.Detail.Sleutel sleutel) => new() diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs index b02289542..19699d84d 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs @@ -39,6 +39,7 @@ public DetailVerenigingenController(AppSettings appSettings) /// /// De vCode van de vereniging /// Sequentiewaarde verkregen bij creatie of aanpassing vereniging. + /// De versie van dit endpoint. /// /// Het detail van een vereniging /// Er was een probleem met de doorgestuurde waarden. @@ -65,6 +66,7 @@ public async Task Detail( [FromServices] IResponseWriter responseWriter, [FromRoute] string vCode, [FromQuery] long? expectedSequence, + [FromHeader(Name = WellknownHeaderNames.Version)] string? version, CancellationToken cancellationToken) { await sequenceGuarder.ThrowIfSequenceNotReached(expectedSequence); @@ -85,7 +87,8 @@ public async Task Detail( await getNamesForVCodesQuery.ExecuteAsync(new GetNamesForVCodesFilter(andereVerenigingen), cancellationToken); var mapper = new BeheerVerenigingDetailMapper(_appSettings, new VerplichteNamenVoorLidmaatschapMapper(namesForLidmaatschappen)); - var mappedDetail = mapper.Map(vereniging); + + var mappedDetail = mapper.Map(vereniging, version); return Ok(mappedDetail); } diff --git a/src/AssociationRegistry/Vereniging/Verenigingstype.cs b/src/AssociationRegistry/Vereniging/Verenigingstype.cs index ca3885387..cd56f76b5 100644 --- a/src/AssociationRegistry/Vereniging/Verenigingstype.cs +++ b/src/AssociationRegistry/Vereniging/Verenigingstype.cs @@ -29,4 +29,7 @@ public Verenigingstype(string code, string naam) public static Verenigingstype Parse(string code) => All.Single(t => t.Code == code); + + public static bool IsVerenigingZonderEigenRechtspersoonlijkheid(string code) + => code == FeitelijkeVereniging.Code || code == VZER.Code; } From 945cadba97d5ef8cad067edf39bec5c24427b054 Mon Sep 17 00:00:00 2001 From: emalfroy Date: Tue, 11 Feb 2025 16:05:10 +0100 Subject: [PATCH 07/12] refactor: or-2665 move verenigingsType to another class --- .../Detail/BeheerVerenigingDetailMapper.cs | 35 ++++--------- .../Detail/DetailVerenigingenController.cs | 5 +- .../Detail/VerenigingsTypeMapper.cs | 52 +++++++++++++++++++ 3 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs index b5102348a..2c3cded8e 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs @@ -15,7 +15,6 @@ using Locatie = ResponseModels.Locatie; using Relatie = ResponseModels.Relatie; using Sleutel = ResponseModels.Sleutel; -using VerenigingsType = ResponseModels.VerenigingsType; using Vertegenwoordiger = ResponseModels.Vertegenwoordiger; using VertegenwoordigerContactgegevens = ResponseModels.VertegenwoordigerContactgegevens; using Werkingsgebied = ResponseModels.Werkingsgebied; @@ -24,18 +23,21 @@ public class BeheerVerenigingDetailMapper { private readonly AppSettings _appSettings; private readonly INamenVoorLidmaatschapMapper _namenVoorLidmaatschapMapper; + private readonly string? _version; + private readonly IVerenigingsTypeMapper _verenigingsTypeMapper; - public BeheerVerenigingDetailMapper(AppSettings appSettings, INamenVoorLidmaatschapMapper namenVoorLidmaatschapMapper) + public BeheerVerenigingDetailMapper(AppSettings appSettings, INamenVoorLidmaatschapMapper namenVoorLidmaatschapMapper, string? version) { _appSettings = appSettings; _namenVoorLidmaatschapMapper = namenVoorLidmaatschapMapper; + _verenigingsTypeMapper = version == WellknownVersions.V2 ? new VerenigingsTypeMapperV2() : new VerenigingsTypeMapper(); } - public DetailVerenigingResponse Map(BeheerVerenigingDetailDocument vereniging, string? version) + public DetailVerenigingResponse Map(BeheerVerenigingDetailDocument vereniging) => new() { Context = $"{_appSettings.PublicApiBaseUrl}/v1/contexten/beheer/detail-vereniging-context.json", - Vereniging = Map(vereniging, _namenVoorLidmaatschapMapper, _appSettings.BaseUrl, version), + Vereniging = Map(vereniging, _namenVoorLidmaatschapMapper, _appSettings.BaseUrl), Metadata = MapMetadata(vereniging), }; @@ -45,18 +47,17 @@ private static Metadata MapMetadata(BeheerVerenigingDetailDocument vereniging) DatumLaatsteAanpassing = vereniging.DatumLaatsteAanpassing, }; - private static VerenigingDetail Map( + private VerenigingDetail Map( BeheerVerenigingDetailDocument vereniging, INamenVoorLidmaatschapMapper namenVoorLidmaatschapMapper, - string baseUrl, - string? version) + string baseUrl) { return new VerenigingDetail { type = vereniging.JsonLdMetadataType, VCode = vereniging.VCode, CorresponderendeVCodes = vereniging.CorresponderendeVCodes, - Verenigingstype = Map(vereniging.Verenigingstype, version), + Verenigingstype = _verenigingsTypeMapper.Map(vereniging.Verenigingstype), Naam = vereniging.Naam, Roepnaam = vereniging.Roepnaam, KorteNaam = vereniging.KorteNaam, @@ -122,24 +123,6 @@ private static GerelateerdeVereniging Map( : string.Empty, }; - private static VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType, string? version) - { - if (Vereniging.Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code) && version == WellknownVersions.V2) - { - return new VerenigingsType - { - Code = Vereniging.Verenigingstype.VZER.Code, - Naam = Vereniging.Verenigingstype.VZER.Naam, - }; - } - - return new VerenigingsType - { - Code = verenigingsType.Code, - Naam = verenigingsType.Naam, - }; - } - private static Sleutel Map(Schema.Detail.Sleutel sleutel) => new() { diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs index 19699d84d..a08fb6c6d 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/DetailVerenigingenController.cs @@ -86,9 +86,8 @@ public async Task Detail( var namesForLidmaatschappen = await getNamesForVCodesQuery.ExecuteAsync(new GetNamesForVCodesFilter(andereVerenigingen), cancellationToken); - var mapper = new BeheerVerenigingDetailMapper(_appSettings, new VerplichteNamenVoorLidmaatschapMapper(namesForLidmaatschappen)); - - var mappedDetail = mapper.Map(vereniging, version); + var mapper = new BeheerVerenigingDetailMapper(_appSettings, new VerplichteNamenVoorLidmaatschapMapper(namesForLidmaatschappen), version); + var mappedDetail = mapper.Map(vereniging); return Ok(mappedDetail); } diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs new file mode 100644 index 000000000..c6323daa8 --- /dev/null +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs @@ -0,0 +1,52 @@ +namespace AssociationRegistry.Admin.Api.Verenigingen.Detail; + +using ResponseModels; +using Vereniging; + +public interface IVerenigingsTypeMapper +{ + VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType); +} + +public class VerenigingsTypeMapper : IVerenigingsTypeMapper +{ + public VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) + { + // TODO: uncomment when implementing VZER + // if (Vereniging.Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) + // { + // return new VerenigingsType + // { + // Code = Vereniging.Verenigingstype.FeitelijkeVereniging.Code, + // Naam = Vereniging.Verenigingstype.FeitelijkeVereniging.Naam, + // }; + // } + + return new VerenigingsType + { + Code = verenigingsType.Code, + Naam = verenigingsType.Naam, + }; + } +} + +public class VerenigingsTypeMapperV2 : IVerenigingsTypeMapper +{ + public VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) + { + if (Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) + { + return new VerenigingsType + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }; + } + + return new VerenigingsType + { + Code = verenigingsType.Code, + Naam = verenigingsType.Naam, + }; + } +} From 7d404120d40de4cf4a5b2ac7c53d959c505baeb1 Mon Sep 17 00:00:00 2001 From: emalfroy Date: Tue, 11 Feb 2025 16:06:29 +0100 Subject: [PATCH 08/12] test: or-2665 set version null for tests --- .../Controllers/DetailVerenigingenControllerTests.cs | 1 + .../When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs | 2 +- .../When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/AssociationRegistry.Test.Admin.Api/Controllers/DetailVerenigingenControllerTests.cs b/test/AssociationRegistry.Test.Admin.Api/Controllers/DetailVerenigingenControllerTests.cs index c4d917a79..177e26dc0 100644 --- a/test/AssociationRegistry.Test.Admin.Api/Controllers/DetailVerenigingenControllerTests.cs +++ b/test/AssociationRegistry.Test.Admin.Api/Controllers/DetailVerenigingenControllerTests.cs @@ -43,6 +43,7 @@ await sut.Detail( Mock.Of(), detail.VCode, null, + null, CancellationToken.None); getNamesQuery.Verify(x => x.ExecuteAsync( diff --git a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs index ff3f816ef..cec27725e 100644 --- a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs +++ b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs @@ -21,7 +21,7 @@ public void Then_Adres_Is_Null() beheerVerenigingDetailDocument.Locaties.First().Adres = null; var beheerVerenigingDetailResponse = new BeheerVerenigingDetailMapper(new AppSettings(), - Mock.Of()) + Mock.Of(), null) .Map(beheerVerenigingDetailDocument); beheerVerenigingDetailResponse.Vereniging.Locaties.First().Adres.Should().BeNull(); diff --git a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs index 52ab4bbf0..5e6779b64 100644 --- a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs +++ b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs @@ -21,7 +21,7 @@ public void Then_AdresId_Is_Null() beheerVerenigingDetailDocument.Locaties.First().AdresId = null; var beheerVerenigingDetailResponse = new BeheerVerenigingDetailMapper(new AppSettings(), - Mock.Of()) + Mock.Of(), null) .Map(beheerVerenigingDetailDocument); beheerVerenigingDetailResponse.Vereniging.Locaties.First().AdresId.Should().BeNull(); From d857c39236cb3d3e99ed3a9ff4a8750327052e81 Mon Sep 17 00:00:00 2001 From: emalfroy Date: Tue, 11 Feb 2025 16:28:16 +0100 Subject: [PATCH 09/12] refactor: or-2665 make VerenigingsTypeMapper generic --- .../Detail/BeheerVerenigingDetailMapper.cs | 3 ++- .../Detail/ResponseModels/VerenigingsType.cs | 7 +++--- .../Detail/VerenigingsTypeMapper.cs | 22 ++++++++++++------- .../Detail/VerenigingsType.cs | 11 ++++++++-- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs index 2c3cded8e..8e805a0fb 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs @@ -15,6 +15,7 @@ using Locatie = ResponseModels.Locatie; using Relatie = ResponseModels.Relatie; using Sleutel = ResponseModels.Sleutel; +using VerenigingsType = ResponseModels.VerenigingsType; using Vertegenwoordiger = ResponseModels.Vertegenwoordiger; using VertegenwoordigerContactgegevens = ResponseModels.VertegenwoordigerContactgegevens; using Werkingsgebied = ResponseModels.Werkingsgebied; @@ -57,7 +58,7 @@ private VerenigingDetail Map( type = vereniging.JsonLdMetadataType, VCode = vereniging.VCode, CorresponderendeVCodes = vereniging.CorresponderendeVCodes, - Verenigingstype = _verenigingsTypeMapper.Map(vereniging.Verenigingstype), + Verenigingstype = _verenigingsTypeMapper.Map(vereniging.Verenigingstype), Naam = vereniging.Naam, Roepnaam = vereniging.Roepnaam, KorteNaam = vereniging.KorteNaam, diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs index 1ecbf9d46..d9237304b 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs @@ -1,22 +1,23 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; +using Schema.Detail; using System.Runtime.Serialization; /// /// Het type van een vereniging /// [DataContract] -public class VerenigingsType +public class VerenigingsType : IVerenigingsType { /// /// De code van het type vereniging /// [DataMember(Name = "Code")] - public string Code { get; set; } = null!; + public string Code { get; init; } = null!; /// /// De beschrijving van het type vereniging /// [DataMember(Name = "Naam")] - public string Naam { get; set; } = null!; + public string Naam { get; init; } = null!; } diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs index c6323daa8..d45a07dd9 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs @@ -1,16 +1,20 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Detail; -using ResponseModels; +using Schema.Detail; using Vereniging; public interface IVerenigingsTypeMapper { - VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType); + TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new(); } public class VerenigingsTypeMapper : IVerenigingsTypeMapper { - public VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) + public TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new() { // TODO: uncomment when implementing VZER // if (Vereniging.Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) @@ -22,28 +26,30 @@ public VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) // }; // } - return new VerenigingsType + return new TDestination() { Code = verenigingsType.Code, - Naam = verenigingsType.Naam, + Naam = verenigingsType.Naam }; } } public class VerenigingsTypeMapperV2 : IVerenigingsTypeMapper { - public VerenigingsType Map(Schema.Detail.VerenigingsType verenigingsType) + public TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new() { if (Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) { - return new VerenigingsType + return new TDestination { Code = Verenigingstype.VZER.Code, Naam = Verenigingstype.VZER.Naam, }; } - return new VerenigingsType + return new TDestination() { Code = verenigingsType.Code, Naam = verenigingsType.Naam, diff --git a/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs b/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs index 6a3067529..7f3105bb6 100644 --- a/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs @@ -1,7 +1,14 @@ namespace AssociationRegistry.Admin.Schema.Detail; -public record VerenigingsType +public record VerenigingsType : IVerenigingsType { public string Code { get; init; } = null!; public string Naam { get; init; } = null!; -} \ No newline at end of file +} + + +public interface IVerenigingsType +{ + string Code { get; init; } + string Naam { get; init; } +} From 7fd139d1d524856158e3a1d4fbbd4ae23a3de29f Mon Sep 17 00:00:00 2001 From: emalfroy Date: Tue, 11 Feb 2025 17:02:51 +0100 Subject: [PATCH 10/12] =?UTF-8?q?feat:=20or-2665=20return=20vzer=20in=20be?= =?UTF-8?q?heer=20zoek=20for=20api=20version=20v2=C3=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Search/ResponseModels/VerenigingsType.cs | 7 +- .../Search/SearchVerenigingenController.cs | 15 +- .../SearchVerenigingenResponseMapper.cs | 18 +-- .../Search/VerenigingZoekDocument.cs | 4 +- .../Framework/AlbaHost/AdminApiEndpoints.cs | 27 ++++ .../Scenarios/Givens/EmptyScenario.cs | 2 +- .../With_Header/Returns_VZER_ZoekResponse.cs | 140 ++++++++++++++++++ .../Returns_ZoekResponse.cs | 4 +- 8 files changed, 192 insertions(+), 25 deletions(-) create mode 100644 test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs rename test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/{ => Without_Header}/Returns_ZoekResponse.cs (98%) diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs index a3753efbc..71fcf9d56 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs @@ -1,19 +1,20 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Search.ResponseModels; +using Schema.Detail; using System.Runtime.Serialization; [DataContract] -public class VerenigingsType +public class VerenigingsType : IVerenigingsType { /// /// De code van het type vereniging /// [DataMember] - public string Code { get; set; } = null!; + public string Code { get; init; } = null!; /// /// De beschrijving van het type vereniging /// [DataMember] - public string Naam { get; set; } = null!; + public string Naam { get; init; } = null!; } diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenController.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenController.cs index 448b41f2f..e7e1740eb 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenController.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenController.cs @@ -10,6 +10,7 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Search; using Examples; using Exceptions; using FluentValidation; +using Hosts.Configuration.ConfigurationBindings; using Microsoft.AspNetCore.Mvc; using Nest; using RequestModels; @@ -25,13 +26,6 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Search; [SwaggerGroup.Opvragen] public class SearchVerenigingenController : ApiController { - private readonly SearchVerenigingenResponseMapper _responseMapper; - - public SearchVerenigingenController(SearchVerenigingenResponseMapper responseMapper) - { - _responseMapper = responseMapper; - } - /// /// Zoek verenigingen op. /// @@ -94,6 +88,8 @@ public SearchVerenigingenController(SearchVerenigingenResponseMapper responseMap /// /// /// + /// + /// De versie van dit endpoint. /// /// Indien de zoekopdracht succesvol was. /// Er was een probleem met de doorgestuurde waarden. @@ -113,6 +109,8 @@ public async Task Zoeken( [FromServices] IBeheerVerenigingenZoekQuery query, [FromServices] IValidator validator, [FromServices] ILogger logger, + [FromServices] AppSettings appSettings, + [FromHeader(Name = WellknownHeaderNames.Version)] string? version, CancellationToken cancellationToken) { await validator.ValidateAndThrowAsync(paginationQueryParams, cancellationToken); @@ -130,7 +128,8 @@ public async Task Zoeken( throw searchResponse.OriginalException; } - var response = _responseMapper.ToSearchVereningenResponse(logger, searchResponse, paginationQueryParams, q); + var responseMapper = new SearchVerenigingenResponseMapper(appSettings, version); + var response = responseMapper.ToSearchVereningenResponse(logger, searchResponse, paginationQueryParams, q); return Ok(response); } diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenResponseMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenResponseMapper.cs index 0f54924b6..6602691b3 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenResponseMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/SearchVerenigingenResponseMapper.cs @@ -2,6 +2,8 @@ using AssociationRegistry.Admin.Schema.Search; using AssociationRegistry.Hosts.Configuration.ConfigurationBindings; +using Detail; +using Infrastructure; using Nest; using RequestModels; using ResponseModels; @@ -9,10 +11,13 @@ public class SearchVerenigingenResponseMapper { private readonly AppSettings _appSettings; + private readonly IVerenigingsTypeMapper _verenigingsTypeMapper; - public SearchVerenigingenResponseMapper(AppSettings appSettings) + public SearchVerenigingenResponseMapper(AppSettings appSettings,string version) { _appSettings = appSettings; + _verenigingsTypeMapper = version == WellknownVersions.V2 ? new VerenigingsTypeMapperV2() : new VerenigingsTypeMapper(); + } public SearchVerenigingenResponse ToSearchVereningenResponse( @@ -29,7 +34,7 @@ public SearchVerenigingenResponse ToSearchVereningenResponse( Metadata = GetMetadata(searchResponse, paginationRequest), }; - private static Vereniging Map( + private Vereniging Map( ILogger logger, VerenigingZoekDocument verenigingZoekDocument, AppSettings appSettings) @@ -41,7 +46,7 @@ private static Vereniging Map( type = verenigingZoekDocument.JsonLdMetadataType, VCode = verenigingZoekDocument.VCode, CorresponderendeVCodes = verenigingZoekDocument.CorresponderendeVCodes, - Verenigingstype = Map(verenigingZoekDocument.Verenigingstype), + Verenigingstype = _verenigingsTypeMapper.Map(verenigingZoekDocument.Verenigingstype), Naam = verenigingZoekDocument.Naam, Roepnaam = verenigingZoekDocument.Roepnaam, KorteNaam = verenigingZoekDocument.KorteNaam, @@ -118,13 +123,6 @@ private static Werkingsgebied Map(VerenigingZoekDocument.Werkingsgebied wg) Naam = wg.Naam, }; - private static VerenigingsType Map(VerenigingZoekDocument.VerenigingsType verenigingDocumentType) - => new() - { - Code = verenigingDocumentType.Code, - Naam = verenigingDocumentType.Naam, - }; - private static Metadata GetMetadata(ISearchResponse searchResponse, PaginationQueryParams paginationRequest) => new() { diff --git a/src/AssociationRegistry.Admin.Schema/Search/VerenigingZoekDocument.cs b/src/AssociationRegistry.Admin.Schema/Search/VerenigingZoekDocument.cs index 8da2fbc41..874fcb369 100644 --- a/src/AssociationRegistry.Admin.Schema/Search/VerenigingZoekDocument.cs +++ b/src/AssociationRegistry.Admin.Schema/Search/VerenigingZoekDocument.cs @@ -1,5 +1,7 @@ namespace AssociationRegistry.Admin.Schema.Search; +using Detail; + public class VerenigingZoekDocument { public string JsonLdMetadataType { get; set; } @@ -67,7 +69,7 @@ public class Werkingsgebied public string Naam { get; init; } = null!; } - public class VerenigingsType + public class VerenigingsType : IVerenigingsType { public string Code { get; init; } = null!; public string Naam { get; init; } = null!; diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs index b12e3384d..0661f13ff 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs @@ -59,4 +59,31 @@ public static DubbelControleResponse[] PostDubbelControle(this IAlbaHost source, public static SearchVerenigingenResponse GetBeheerZoeken(this IAlbaHost source, string query) => source.GetAsJson($"/v1/verenigingen/zoeken?q={query}").GetAwaiter().GetResult()!; + + public static async Task GetBeheerZoekenV2( + this IAlbaHost source, + HttpClient authenticatedClient, + string query) + { + var client = source.Server.CreateClient(); + + foreach (var defaultRequestHeader in authenticatedClient.DefaultRequestHeaders) + { + client.DefaultRequestHeaders.Add(defaultRequestHeader.Key, defaultRequestHeader.Value); + } + + client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); + + var response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + + while (response.StatusCode == HttpStatusCode.PreconditionFailed) + { + await Task.Delay(300); + response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + } + + var readAsStringAsync = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(readAsStringAsync); + } } diff --git a/test/AssociationRegistry.Test.E2E/Scenarios/Givens/EmptyScenario.cs b/test/AssociationRegistry.Test.E2E/Scenarios/Givens/EmptyScenario.cs index 6b91e851d..28671dfba 100644 --- a/test/AssociationRegistry.Test.E2E/Scenarios/Givens/EmptyScenario.cs +++ b/test/AssociationRegistry.Test.E2E/Scenarios/Givens/EmptyScenario.cs @@ -14,7 +14,7 @@ namespace AssociationRegistry.Test.E2E.Scenarios.Givens; using Microsoft.Extensions.DependencyInjection; using System.Net; using Adres = Admin.Api.Verenigingen.Common.Adres; -using IEvent = AssociationRegistry.Events.IEvent; +using IEvent = Events.IEvent; public class EmptyScenario : Framework.TestClasses.IScenario { diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs new file mode 100644 index 000000000..4584caf37 --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs @@ -0,0 +1,140 @@ +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Zoeken.With_Header; + +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using Admin.Api.Verenigingen.Search.ResponseModels; +using Formats; +using JsonLdContext; +using Framework.AlbaHost; +using Framework.ApiSetup; +using Framework.Comparison; +using Framework.TestClasses; +using Vereniging; +using KellermanSoftware.CompareNetObjects; +using NodaTime; +using Xunit; +using HoofdactiviteitVerenigingsloket = Admin.Api.Verenigingen.Search.ResponseModels.HoofdactiviteitVerenigingsloket; +using Locatie = Admin.Api.Verenigingen.Search.ResponseModels.Locatie; +using Vereniging = Admin.Api.Verenigingen.Search.ResponseModels.Vereniging; +using VerenigingStatus = Admin.Schema.Constants.VerenigingStatus; +using Werkingsgebied = Admin.Api.Verenigingen.Search.ResponseModels.Werkingsgebied; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_VZER_ZoekResponse : End2EndTest +{ + private readonly RegistreerFeitelijkeVerenigingTestContext _testContext; + + public Returns_VZER_ZoekResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) + { + _testContext = testContext; + } + + [Fact] + public void With_Context() + { + Response.Context.ShouldCompare("http://127.0.0.1:11003/v1/contexten/beheer/zoek-verenigingen-context.json"); + } + + [Fact] + public async Task WithFeitelijkeVereniging() + => Response.Verenigingen.Single().ShouldCompare(new Vereniging + { + type = JsonLdType.FeitelijkeVereniging.Type, + Doelgroep = new DoelgroepResponse + { + type = JsonLdType.Doelgroep.Type, + id = JsonLdType.Doelgroep.CreateWithIdValues(_testContext.VCode), + Minimumleeftijd = 1, + Maximumleeftijd = 149, + }, + VCode = _testContext.VCode, + KorteNaam = Request.KorteNaam, + Verenigingstype = new VerenigingsType + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }, + Naam = Request.Naam, + Startdatum = Instant.FromDateTimeOffset(DateTimeOffset.UtcNow).FormatAsBelgianDate(), + Einddatum = null, + Status = VerenigingStatus.Actief, + HoofdactiviteitenVerenigingsloket = MapHoofdactiviteitenVerenigingsloket(Request.HoofdactiviteitenVerenigingsloket), + Werkingsgebieden = MapWerkingsgebieden(Request.Werkingsgebieden), + Locaties = MapLocaties(Request.Locaties, _testContext.VCode), + Sleutels = MapSleutels(Request, _testContext.VCode), + Lidmaatschappen = [], + Links = new VerenigingLinks() + { + Detail = new Uri($"{_testContext.AdminApiAppSettings.BaseUrl}/v1/verenigingen/{_testContext.VCode}"), + }, + }, compareConfig: PubliekZoekenComparisonConfig.Instance); + + private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) + => + [ + new Sleutel + { + Bron = Sleutelbron.VR.Waarde, + id = JsonLdType.Sleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.Sleutel.Type, + Waarde = vCode, + CodeerSysteem = CodeerSysteem.VR, + GestructureerdeIdentificator = new GestructureerdeIdentificator + { + id = JsonLdType.GestructureerdeSleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.GestructureerdeSleutel.Type, + Nummer = vCode, + }, + }, + ]; + + private static Locatie[] MapLocaties(ToeTeVoegenLocatie[] toeTeVoegenLocaties, string vCode) + { + return toeTeVoegenLocaties.Select((x, i) => new Locatie + { + id = JsonLdType.Locatie.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Locatie.Type, + Locatietype = x.Locatietype, + Naam = x.Naam, + IsPrimair = x.IsPrimair, + }).ToArray(); + } + + private static HoofdactiviteitVerenigingsloket[] MapHoofdactiviteitenVerenigingsloket( + string[] hoofdactiviteitenVerenigingsloket) + { + return hoofdactiviteitenVerenigingsloket.Select(x => + { + var hoofdactiviteitVerenigingsloket = AssociationRegistry.Vereniging.HoofdactiviteitVerenigingsloket.Create(x); + + return new HoofdactiviteitVerenigingsloket + { + Code = hoofdactiviteitVerenigingsloket.Code, + Naam = hoofdactiviteitVerenigingsloket.Naam, + id = JsonLdType.Hoofdactiviteit.CreateWithIdValues(hoofdactiviteitVerenigingsloket.Code), + type = JsonLdType.Hoofdactiviteit.Type, + }; + }).ToArray(); + } + + private static Werkingsgebied[] MapWerkingsgebieden( + string[] werkingsgebieden) + { + return werkingsgebieden.Select(x => + { + var werkingsgebied = AssociationRegistry.Vereniging.Werkingsgebied.Create(x); + + return new Werkingsgebied + { + Code = werkingsgebied.Code, + Naam = werkingsgebied.Naam, + id = JsonLdType.Werkingsgebied.CreateWithIdValues(werkingsgebied.Code), + type = JsonLdType.Werkingsgebied.Type, + }; + }).ToArray(); + } + + public override Func GetResponse + => setup => setup.AdminApiHost.GetBeheerZoekenV2(setup.SuperAdminHttpClient,$"vCode:{_testContext.VCode}").GetAwaiter().GetResult(); +} diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Returns_ZoekResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Without_Header/Returns_ZoekResponse.cs similarity index 98% rename from test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Returns_ZoekResponse.cs rename to test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Without_Header/Returns_ZoekResponse.cs index 04e166aa1..7e8cdd6a0 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Returns_ZoekResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Beheer/Zoeken/Without_Header/Returns_ZoekResponse.cs @@ -1,6 +1,6 @@ -namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Zoeken; +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Beheer.Zoeken.Without_Header; -using Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Common; using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; using Admin.Api.Verenigingen.Search.ResponseModels; using Formats; From f4ef887207405d7322c784ad619b63372e6e086e Mon Sep 17 00:00:00 2001 From: emalfroy Date: Wed, 12 Feb 2025 10:56:09 +0100 Subject: [PATCH 11/12] feat: or-2665 return vzer in publiek zoek for api version v2 --- .../Detail/BeheerVerenigingDetailMapper.cs | 2 +- .../Detail/ResponseModels/VerenigingsType.cs | 1 + .../Detail/VerenigingsTypeMapper.cs | 2 +- .../Search/ResponseModels/VerenigingsType.cs | 2 +- .../PowerBiExport/PowerBiExportProjection.cs | 3 +- .../{Detail => }/VerenigingsType.cs | 2 +- .../Infrastructure/WellknownHeaderNames.cs | 11 ++ src/AssociationRegistry.Public.Api/Program.cs | 1 - .../Search/ResponseModels/VerenigingsType.cs | 7 +- .../Search/SearchVerenigingenController.cs | 16 +-- .../SearchVerenigingenResponseMapper.cs | 18 +-- .../VerenigingsTypeMapper.cs | 58 ++++++++ .../Search/VerenigingZoekDocument.cs | 2 +- .../VerenigingsType.cs | 14 ++ .../Given_RechtsvormWerdGewijzigdInKbo.cs | 1 + .../Framework/AlbaHost/PublicApiEndpoints.cs | 29 ++++ .../With_Header/Returns_ZoekResponse.cs | 136 ++++++++++++++++++ .../Returns_ZoekResponse.cs | 20 +-- 18 files changed, 285 insertions(+), 40 deletions(-) rename src/AssociationRegistry.Admin.Schema/{Detail => }/VerenigingsType.cs (82%) create mode 100644 src/AssociationRegistry.Public.Api/Infrastructure/WellknownHeaderNames.cs create mode 100644 src/AssociationRegistry.Public.Api/VerenigingsTypeMapper.cs create mode 100644 src/AssociationRegistry.Public.Schema/VerenigingsType.cs create mode 100644 test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs rename test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/{ => Without_Header}/Returns_ZoekResponse.cs (90%) diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs index 8e805a0fb..005ca472f 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/BeheerVerenigingDetailMapper.cs @@ -58,7 +58,7 @@ private VerenigingDetail Map( type = vereniging.JsonLdMetadataType, VCode = vereniging.VCode, CorresponderendeVCodes = vereniging.CorresponderendeVCodes, - Verenigingstype = _verenigingsTypeMapper.Map(vereniging.Verenigingstype), + Verenigingstype = _verenigingsTypeMapper.Map(vereniging.Verenigingstype), Naam = vereniging.Naam, Roepnaam = vereniging.Roepnaam, KorteNaam = vereniging.KorteNaam, diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs index d9237304b..bf0be1d30 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/ResponseModels/VerenigingsType.cs @@ -1,5 +1,6 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; +using Schema; using Schema.Detail; using System.Runtime.Serialization; diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs index d45a07dd9..87e74bcc7 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Detail/VerenigingsTypeMapper.cs @@ -1,6 +1,6 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Detail; -using Schema.Detail; +using Schema; using Vereniging; public interface IVerenigingsTypeMapper diff --git a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs index 71fcf9d56..98c7c0dd8 100644 --- a/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Api/DecentraalBeheer/Verenigingen/Search/ResponseModels/VerenigingsType.cs @@ -1,6 +1,6 @@ namespace AssociationRegistry.Admin.Api.Verenigingen.Search.ResponseModels; -using Schema.Detail; +using Schema; using System.Runtime.Serialization; [DataContract] diff --git a/src/AssociationRegistry.Admin.ProjectionHost/Projections/PowerBiExport/PowerBiExportProjection.cs b/src/AssociationRegistry.Admin.ProjectionHost/Projections/PowerBiExport/PowerBiExportProjection.cs index 978dc36b3..c077c5a41 100644 --- a/src/AssociationRegistry.Admin.ProjectionHost/Projections/PowerBiExport/PowerBiExportProjection.cs +++ b/src/AssociationRegistry.Admin.ProjectionHost/Projections/PowerBiExport/PowerBiExportProjection.cs @@ -8,8 +8,7 @@ namespace AssociationRegistry.Admin.ProjectionHost.Projections.PowerBiExport; using JsonLdContext; using Marten.Events; using Marten.Events.Aggregation; -using Schema.Constants; -using Schema.Detail; +using Schema; using Schema.PowerBiExport; using Vereniging; using Contactgegeven = Schema.Detail.Contactgegeven; diff --git a/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs b/src/AssociationRegistry.Admin.Schema/VerenigingsType.cs similarity index 82% rename from src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs rename to src/AssociationRegistry.Admin.Schema/VerenigingsType.cs index 7f3105bb6..6c7ae4c1b 100644 --- a/src/AssociationRegistry.Admin.Schema/Detail/VerenigingsType.cs +++ b/src/AssociationRegistry.Admin.Schema/VerenigingsType.cs @@ -1,4 +1,4 @@ -namespace AssociationRegistry.Admin.Schema.Detail; +namespace AssociationRegistry.Admin.Schema; public record VerenigingsType : IVerenigingsType { diff --git a/src/AssociationRegistry.Public.Api/Infrastructure/WellknownHeaderNames.cs b/src/AssociationRegistry.Public.Api/Infrastructure/WellknownHeaderNames.cs new file mode 100644 index 000000000..1d2effedc --- /dev/null +++ b/src/AssociationRegistry.Public.Api/Infrastructure/WellknownHeaderNames.cs @@ -0,0 +1,11 @@ +namespace AssociationRegistry.Public.Api.Infrastructure; + +public class WellknownHeaderNames +{ + public const string Version = "VR-Api-Version"; +} + +public class WellknownVersions +{ + public const string V2 = "v2"; +} diff --git a/src/AssociationRegistry.Public.Api/Program.cs b/src/AssociationRegistry.Public.Api/Program.cs index 203cd4105..a209d13c4 100755 --- a/src/AssociationRegistry.Public.Api/Program.cs +++ b/src/AssociationRegistry.Public.Api/Program.cs @@ -246,7 +246,6 @@ private static void ConfigureServices(WebApplicationBuilder builder) .AddSingleton(appSettings) .AddMarten(postgreSqlOptionsSection, builder.Configuration) .AddElasticSearch(elasticSearchOptionsSection) - .AddSingleton() .AddTransient() .AddTransient() .AddTransient() diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Search/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Search/ResponseModels/VerenigingsType.cs index 002b81dcd..cc26cae3b 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Search/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Search/ResponseModels/VerenigingsType.cs @@ -1,19 +1,20 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Search.ResponseModels; +using Schema; using System.Runtime.Serialization; [DataContract] -public class VerenigingsType +public class VerenigingsType : IVerenigingsType { /// /// De code van het type vereniging /// [DataMember] - public string Code { get; set; } = null!; + public string Code { get; init; } = null!; /// /// De beschrijving van het type vereniging /// [DataMember] - public string Naam { get; set; } = null!; + public string Naam { get; init; } = null!; } diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenController.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenController.cs index 2ef119684..487b76fd6 100755 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenController.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenController.cs @@ -7,6 +7,8 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Search; using Detail; using Exceptions; using FluentValidation; +using Infrastructure; +using Infrastructure.ConfigurationBindings; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; @@ -34,13 +36,6 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Search; [ApiExplorerSettings(GroupName = "Opvragen van verenigingen")] public class SearchVerenigingenController : ApiController { - private readonly SearchVerenigingenResponseMapper _responseMapper; - - public SearchVerenigingenController(SearchVerenigingenResponseMapper responseMapper) - { - _responseMapper = responseMapper; - } - /// /// Zoek verenigingen op. /// @@ -107,6 +102,7 @@ public SearchVerenigingenController(SearchVerenigingenResponseMapper responseMap /// /// De paginatie parameters /// + /// De versie van dit endpoint. /// /// Indien de zoekopdracht succesvol was. /// Er is een interne fout opgetreden. @@ -127,6 +123,8 @@ public async Task Zoeken( [FromServices] IPubliekVerenigingenZoekQuery query, [FromServices] IValidator validator, [FromServices] ILogger logger, + [FromServices] AppSettings appsettings, + [FromHeader(Name = WellknownHeaderNames.Version)] string? version, CancellationToken cancellationToken) { await validator.ValidateAndThrowAsync(paginationQueryParams, cancellationToken); @@ -149,7 +147,9 @@ await query.ExecuteAsync(new PubliekVerenigingenZoekFilter(q, sort, hoofdActivit throw searchResponse.OriginalException; } - var response = _responseMapper.ToSearchVereningenResponse(logger, searchResponse, paginationQueryParams, q, hoofdActiviteitenArray); + var responseMapper = new SearchVerenigingenResponseMapper(appsettings, logger, version); + + var response = responseMapper.ToSearchVereningenResponse(logger, searchResponse, paginationQueryParams, q, hoofdActiviteitenArray); return Ok(response); } diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenResponseMapper.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenResponseMapper.cs index f2053676a..e0db37eb2 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenResponseMapper.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Search/SearchVerenigingenResponseMapper.cs @@ -1,6 +1,7 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Search; using Constants; +using Infrastructure; using Infrastructure.ConfigurationBindings; using Nest; using RequestModels; @@ -14,12 +15,14 @@ public class SearchVerenigingenResponseMapper { private readonly AppSettings _appSettings; - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly IVerenigingsTypeMapper _verenigingsTypeMapper; - public SearchVerenigingenResponseMapper(AppSettings appSettings, ILogger logger) + public SearchVerenigingenResponseMapper(AppSettings appSettings, ILogger logger, string? version) { _appSettings = appSettings; _logger = logger; + _verenigingsTypeMapper = version == WellknownVersions.V2 ? new VerenigingsTypeMapperV2() : new VerenigingsTypeMapper(); } public SearchVerenigingenResponse ToSearchVereningenResponse( @@ -44,7 +47,7 @@ private Facets MapFacets(ISearchResponse searchResponse, HoofdactiviteitenVerenigingsloket = GetHoofdActiviteitFacets(_appSettings, searchResponse, originalQuery, hoofdactiviteiten), }; - private static Vereniging Map( + private Vereniging Map( ILogger logger, VerenigingZoekDocument verenigingZoekDocument, AppSettings appSettings) @@ -61,7 +64,7 @@ private static Vereniging Map( { type = verenigingZoekDocument.JsonLdMetadataType, VCode = verenigingZoekDocument.VCode, - Verenigingstype = Map(verenigingZoekDocument.Verenigingstype), + Verenigingstype = _verenigingsTypeMapper.Map(verenigingZoekDocument.Verenigingstype), Naam = verenigingZoekDocument.Naam, Roepnaam = verenigingZoekDocument.Roepnaam, KorteNaam = verenigingZoekDocument.KorteNaam, @@ -127,13 +130,6 @@ private static Werkingsgebied Map(VerenigingZoekDocument.Werkingsgebied w) Naam = w.Naam, }; - private static VerenigingsType Map(VerenigingZoekDocument.VerenigingsType verenigingDocumentType) - => new() - { - Code = verenigingDocumentType.Code, - Naam = verenigingDocumentType.Naam, - }; - private static Metadata GetMetadata(ISearchResponse searchResponse, PaginationQueryParams paginationRequest) => new() { diff --git a/src/AssociationRegistry.Public.Api/VerenigingsTypeMapper.cs b/src/AssociationRegistry.Public.Api/VerenigingsTypeMapper.cs new file mode 100644 index 000000000..8ca189341 --- /dev/null +++ b/src/AssociationRegistry.Public.Api/VerenigingsTypeMapper.cs @@ -0,0 +1,58 @@ +namespace AssociationRegistry.Public.Api; + +using AssociationRegistry.Vereniging; +using Schema; + +public interface IVerenigingsTypeMapper +{ + TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new(); +} + +public class VerenigingsTypeMapper : IVerenigingsTypeMapper +{ + public TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new() + { + // TODO: uncomment when implementing VZER + // if (Vereniging.Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) + // { + // return new VerenigingsType + // { + // Code = Vereniging.Verenigingstype.FeitelijkeVereniging.Code, + // Naam = Vereniging.Verenigingstype.FeitelijkeVereniging.Naam, + // }; + // } + + return new TDestination() + { + Code = verenigingsType.Code, + Naam = verenigingsType.Naam + }; + } +} + +public class VerenigingsTypeMapperV2 : IVerenigingsTypeMapper +{ + public TDestination Map(TSource verenigingsType) + where TDestination : IVerenigingsType, new() + where TSource : IVerenigingsType, new() + { + if (Verenigingstype.IsVerenigingZonderEigenRechtspersoonlijkheid(verenigingsType.Code)) + { + return new TDestination + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }; + } + + return new TDestination() + { + Code = verenigingsType.Code, + Naam = verenigingsType.Naam, + }; + } +} diff --git a/src/AssociationRegistry.Public.Schema/Search/VerenigingZoekDocument.cs b/src/AssociationRegistry.Public.Schema/Search/VerenigingZoekDocument.cs index b01f74173..bd454b6a6 100644 --- a/src/AssociationRegistry.Public.Schema/Search/VerenigingZoekDocument.cs +++ b/src/AssociationRegistry.Public.Schema/Search/VerenigingZoekDocument.cs @@ -66,7 +66,7 @@ public class Werkingsgebied public string Naam { get; init; } = null!; } - public class VerenigingsType + public class VerenigingsType : IVerenigingsType { public string Code { get; init; } = null!; public string Naam { get; init; } = null!; diff --git a/src/AssociationRegistry.Public.Schema/VerenigingsType.cs b/src/AssociationRegistry.Public.Schema/VerenigingsType.cs new file mode 100644 index 000000000..eb0b16b92 --- /dev/null +++ b/src/AssociationRegistry.Public.Schema/VerenigingsType.cs @@ -0,0 +1,14 @@ +namespace AssociationRegistry.Public.Schema; + +public record VerenigingsType : IVerenigingsType +{ + public string Code { get; init; } = null!; + public string Naam { get; init; } = null!; +} + + +public interface IVerenigingsType +{ + string Code { get; init; } + string Naam { get; init; } +} diff --git a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/Projector/Given_RechtsvormWerdGewijzigdInKbo.cs b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/Projector/Given_RechtsvormWerdGewijzigdInKbo.cs index b89c5524a..484897def 100644 --- a/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/Projector/Given_RechtsvormWerdGewijzigdInKbo.cs +++ b/test/AssociationRegistry.Test.Admin.Api/Projections/V1/When_Retrieving_Detail/Projector/Given_RechtsvormWerdGewijzigdInKbo.cs @@ -1,5 +1,6 @@ namespace AssociationRegistry.Test.Admin.Api.Projections.V1.When_Retrieving_Detail.Projector; +using AssociationRegistry.Admin.Api.Verenigingen.Detail.ResponseModels; using AssociationRegistry.Admin.ProjectionHost.Projections.Detail; using AssociationRegistry.Admin.Schema.Detail; using Events; diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs index 3a791ddb4..efcb2ae01 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs @@ -1,7 +1,9 @@ namespace AssociationRegistry.Test.E2E.Framework.AlbaHost; using Alba; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Public.Api.Infrastructure; using Public.Api.Verenigingen.Detail.ResponseModels; using Public.Api.Verenigingen.Search.ResponseModels; using Public.Api.Werkingsgebieden.ResponseModels; @@ -23,6 +25,33 @@ public static HttpStatusCode GetPubliekDetailStatusCode(this IAlbaHost source, s public static SearchVerenigingenResponse GetPubliekZoeken(this IAlbaHost source, string query) => source.GetAsJson($"/v1/verenigingen/zoeken?q={query}").GetAwaiter().GetResult()!; + public static async Task GetPubliekZoekenV2( + this IAlbaHost source, + HttpClient authenticatedClient, + string query) + { + var client = source.Server.CreateClient(); + + foreach (var defaultRequestHeader in authenticatedClient.DefaultRequestHeaders) + { + client.DefaultRequestHeaders.Add(defaultRequestHeader.Key, defaultRequestHeader.Value); + } + + client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); + + var response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + + while (response.StatusCode == HttpStatusCode.PreconditionFailed) + { + await Task.Delay(300); + response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + } + + var readAsStringAsync = await response.Content.ReadAsStringAsync(); + + return JsonConvert.DeserializeObject(readAsStringAsync); + } + public static WerkingsgebiedenResponse GetWerkingsgebieden(this IAlbaHost source) => source.GetAsJson($"/v1/werkingsgebieden").GetAwaiter().GetResult()!; diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs new file mode 100644 index 000000000..324fc9739 --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs @@ -0,0 +1,136 @@ +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Zoeken.With_Header; + +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using AssociationRegistry.JsonLdContext; +using AssociationRegistry.Public.Api.Verenigingen.Search.ResponseModels; +using AssociationRegistry.Test.E2E.Framework.AlbaHost; +using AssociationRegistry.Test.E2E.Framework.ApiSetup; +using AssociationRegistry.Test.E2E.Framework.Comparison; +using AssociationRegistry.Test.E2E.Framework.TestClasses; +using AssociationRegistry.Vereniging; +using KellermanSoftware.CompareNetObjects; +using Xunit; +using HoofdactiviteitVerenigingsloket = Public.Api.Verenigingen.Search.ResponseModels.HoofdactiviteitVerenigingsloket; +using Locatie = Public.Api.Verenigingen.Search.ResponseModels.Locatie; +using Vereniging = Public.Api.Verenigingen.Search.ResponseModels.Vereniging; +using Werkingsgebied = Public.Api.Verenigingen.Search.ResponseModels.Werkingsgebied; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_SearchVerenigingenResponse : End2EndTest +{ + private readonly RegistreerFeitelijkeVerenigingTestContext _testContext; + + public Returns_SearchVerenigingenResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) + { + _testContext = testContext; + } + + [Fact] + public void With_Context() + { + Response.Context.ShouldCompare("http://127.0.0.1:11003/v1/contexten/publiek/zoek-verenigingen-context.json"); + } + + [Fact] + public async Task WithFeitelijkeVereniging() + => Response.Verenigingen.Single().ShouldCompare(new Vereniging + { + type = JsonLdType.FeitelijkeVereniging.Type, + Doelgroep = new DoelgroepResponse + { + type = JsonLdType.Doelgroep.Type, + id = JsonLdType.Doelgroep.CreateWithIdValues(_testContext.VCode), + Minimumleeftijd = 1, + Maximumleeftijd = 149, + }, + VCode = _testContext.VCode, + KorteBeschrijving = Request.KorteBeschrijving, + KorteNaam = Request.KorteNaam, + Verenigingstype = new VerenigingsType + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }, + Naam = Request.Naam, + HoofdactiviteitenVerenigingsloket = MapHoofdactiviteitenVerenigingsloket(Request.HoofdactiviteitenVerenigingsloket), + Werkingsgebieden = MapWerkingsgebieden(Request.Werkingsgebieden), + Locaties = MapLocaties(Request.Locaties, _testContext.VCode), + Relaties = [], + Lidmaatschappen = [], + Sleutels = MapSleutels(Request, _testContext.VCode), + Links = new VerenigingLinks() + { + Detail = new Uri($"{_testContext.PublicApiAppSettings.BaseUrl}/v1/verenigingen/{_testContext.VCode}"), + }, + }, compareConfig: PubliekZoekenComparisonConfig.Instance); + + private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) + => + [ + new Sleutel + { + Bron = Sleutelbron.VR.Waarde, + id = JsonLdType.Sleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.Sleutel.Type, + Waarde = vCode, + CodeerSysteem = CodeerSysteem.VR, + GestructureerdeIdentificator = new GestructureerdeIdentificator + { + id = JsonLdType.GestructureerdeSleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.GestructureerdeSleutel.Type, + Nummer = vCode, + }, + }, + ]; + + private static Locatie[] MapLocaties(ToeTeVoegenLocatie[] toeTeVoegenLocaties, string vCode) + { + return toeTeVoegenLocaties.Select((x, i) => new Locatie + { + id = JsonLdType.Locatie.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Locatie.Type, + Locatietype = x.Locatietype, + Naam = x.Naam, + IsPrimair = x.IsPrimair, + }).ToArray(); + } + + private static HoofdactiviteitVerenigingsloket[] MapHoofdactiviteitenVerenigingsloket( + string[] hoofdactiviteitenVerenigingsloket) + { + return hoofdactiviteitenVerenigingsloket.Select(x => + { + var hoofdactiviteitVerenigingsloket = AssociationRegistry.Vereniging.HoofdactiviteitVerenigingsloket.Create(x); + + return new HoofdactiviteitVerenigingsloket + { + Code = hoofdactiviteitVerenigingsloket.Code, + Naam = hoofdactiviteitVerenigingsloket.Naam, + id = JsonLdType.Hoofdactiviteit.CreateWithIdValues(hoofdactiviteitVerenigingsloket.Code), + type = JsonLdType.Hoofdactiviteit.Type, + }; + }).ToArray(); + } + + private static Werkingsgebied[] MapWerkingsgebieden( + string[] werkingsgebieden) + { + return werkingsgebieden.Select(x => + { + var werkingsgebied = AssociationRegistry.Vereniging.Werkingsgebied.Create(x); + + return new Werkingsgebied + { + Code = werkingsgebied.Code, + Naam = werkingsgebied.Naam, + id = JsonLdType.Werkingsgebied.CreateWithIdValues(werkingsgebied.Code), + type = JsonLdType.Werkingsgebied.Type, + }; + }).ToArray(); + } + + public override Func GetResponse + => setup => setup.PublicApiHost.GetPubliekZoekenV2(setup.SuperAdminHttpClient,$"vCode:{_testContext.VCode}").GetAwaiter().GetResult(); +} diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Returns_ZoekResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Without_Header/Returns_ZoekResponse.cs similarity index 90% rename from test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Returns_ZoekResponse.cs rename to test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Without_Header/Returns_ZoekResponse.cs index c58361b6a..59d0867ce 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Returns_ZoekResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/Without_Header/Returns_ZoekResponse.cs @@ -1,14 +1,14 @@ -namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Zoeken; +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Zoeken.Without_Header; -using Admin.Api.Verenigingen.Common; -using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; -using JsonLdContext; -using Public.Api.Verenigingen.Search.ResponseModels; -using Framework.AlbaHost; -using Framework.ApiSetup; -using Framework.Comparison; -using Framework.TestClasses; -using Vereniging; +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using AssociationRegistry.JsonLdContext; +using AssociationRegistry.Public.Api.Verenigingen.Search.ResponseModels; +using AssociationRegistry.Test.E2E.Framework.AlbaHost; +using AssociationRegistry.Test.E2E.Framework.ApiSetup; +using AssociationRegistry.Test.E2E.Framework.Comparison; +using AssociationRegistry.Test.E2E.Framework.TestClasses; +using AssociationRegistry.Vereniging; using KellermanSoftware.CompareNetObjects; using Xunit; using HoofdactiviteitVerenigingsloket = Public.Api.Verenigingen.Search.ResponseModels.HoofdactiviteitVerenigingsloket; From 83db12a538cbdd5fc3f40dcbb410429c737fd6bf Mon Sep 17 00:00:00 2001 From: emalfroy Date: Wed, 12 Feb 2025 11:20:00 +0100 Subject: [PATCH 12/12] feat: or-2665 return vzer in publiek detail for api version v2 --- .../Detail/DetailVerenigingenController.cs | 16 +- .../Detail/PubliekVerenigingDetailMapper.cs | 22 ++- .../Detail/ResponseModels/VerenigingsType.cs | 7 +- .../Detail/VerenigingDetailDocument.cs | 6 +- .../Framework/AlbaHost/AdminApiEndpoints.cs | 35 +--- .../Framework/AlbaHost/PublicApiEndpoints.cs | 24 ++- .../Returns_VZER_DetailResponse.cs | 174 ++++++++++++++++++ .../Returns_DetailResponse.cs | 20 +- ...sponse.cs => Returns_VZER_ZoekResponse.cs} | 6 +- .../Given_A_Null_Adres.cs | 3 +- .../Given_A_Null_AdresId.cs | 3 +- 11 files changed, 251 insertions(+), 65 deletions(-) create mode 100644 test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/With_Header/Returns_VZER_DetailResponse.cs rename test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/{ => Without_Header}/Returns_DetailResponse.cs (93%) rename test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/{Returns_ZoekResponse.cs => Returns_VZER_ZoekResponse.cs} (92%) diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs index 05b60eb46..f84c05dd9 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/DetailVerenigingenController.cs @@ -4,6 +4,7 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Detail; using Be.Vlaanderen.Basisregisters.Api; using Be.Vlaanderen.Basisregisters.Api.Exceptions; using Constants; +using Infrastructure; using Infrastructure.ConfigurationBindings; using Infrastructure.Extensions; using Marten; @@ -21,17 +22,11 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Detail; [ApiExplorerSettings(GroupName = "Opvragen van verenigingen")] public class DetailVerenigingenController : ApiController { - private readonly AppSettings _appsettings; - - public DetailVerenigingenController(AppSettings appsettings) - { - _appsettings = appsettings; - } - /// /// Vraag het detail van een vereniging op. /// /// De unieke identificatie code van deze vereniging + /// De versie van dit endpoint. /// Het detail van een vereniging /// De gevraagde vereniging is niet gevonden /// Er is een interne fout opgetreden. @@ -44,7 +39,9 @@ public DetailVerenigingenController(AppSettings appsettings) public async Task Detail( [FromServices] IDocumentStore store, [FromServices] IGetNamesForVCodesQuery getNamesForVCodesQuery, + [FromServices] AppSettings appSettings, [FromRoute] string vCode, + [FromHeader(Name = WellknownHeaderNames.Version)] string? version, CancellationToken cancellationToken) { await using var session = store.LightweightSession(); @@ -59,8 +56,9 @@ public async Task Detail( var namesForLidmaatschappen = await getNamesForVCodesQuery.ExecuteAsync(new GetNamesForVCodesFilter(andereVerenigingen), cancellationToken); - return Ok(PubliekVerenigingDetailMapper.Map(vereniging, _appsettings, - new VerplichteNamenVoorLidmaatschapMapper(namesForLidmaatschappen))); + var responseMapper = new PubliekVerenigingDetailMapper(appSettings, version); + + return Ok(responseMapper.Map(vereniging, new VerplichteNamenVoorLidmaatschapMapper(namesForLidmaatschappen))); } private static async Task GetDetail(IQuerySession session, string vCode) diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs index dc7c128a8..2927fe4bc 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/PubliekVerenigingDetailMapper.cs @@ -1,24 +1,34 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Detail; using Formats; +using Infrastructure; using Infrastructure.ConfigurationBindings; using ResponseModels; using Schema.Detail; -public static class PubliekVerenigingDetailMapper +public class PubliekVerenigingDetailMapper { - public static PubliekVerenigingDetailResponse Map( + private readonly AppSettings _appSettings; + private readonly IVerenigingsTypeMapper _verenigingsTypeMapper; + + public PubliekVerenigingDetailMapper(AppSettings appSettings, string version) + { + _appSettings = appSettings; + _verenigingsTypeMapper = version == WellknownVersions.V2 ? new VerenigingsTypeMapperV2() : new VerenigingsTypeMapper(); + + } + + public PubliekVerenigingDetailResponse Map( PubliekVerenigingDetailDocument document, - AppSettings appSettings, INamenVoorLidmaatschapMapper lidmaatschapMapper) => new() { - Context = $"{appSettings.BaseUrl}/v1/contexten/publiek/detail-vereniging-context.json", + Context = $"{_appSettings.BaseUrl}/v1/contexten/publiek/detail-vereniging-context.json", Vereniging = new Vereniging { type = document.JsonLdMetadataType, VCode = document.VCode, - Verenigingstype = Map(document.Verenigingstype), + Verenigingstype = _verenigingsTypeMapper.Map(document.Verenigingstype), Naam = document.Naam, Roepnaam = document.Roepnaam, KorteNaam = document.KorteNaam, @@ -37,7 +47,7 @@ public static PubliekVerenigingDetailResponse Map( HoofdactiviteitenVerenigingsloket = document.HoofdactiviteitenVerenigingsloket.Select(Map).ToArray(), Werkingsgebieden = document.Werkingsgebieden.Select(Map).ToArray(), Sleutels = document.Sleutels.Select(Map).ToArray(), - Relaties = document.Relaties.Select(r => Map(appSettings, r)).ToArray(), + Relaties = document.Relaties.Select(r => Map(_appSettings, r)).ToArray(), Lidmaatschappen = document.Lidmaatschappen.Select(l => Map(l, lidmaatschapMapper)).ToArray(), }, Metadata = new Metadata { DatumLaatsteAanpassing = document.DatumLaatsteAanpassing }, diff --git a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/VerenigingsType.cs b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/VerenigingsType.cs index 5f33cb49b..4a6c8fa8f 100644 --- a/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/VerenigingsType.cs +++ b/src/AssociationRegistry.Public.Api/Verenigingen/Detail/ResponseModels/VerenigingsType.cs @@ -1,19 +1,20 @@ namespace AssociationRegistry.Public.Api.Verenigingen.Detail.ResponseModels; +using Schema; using System.Runtime.Serialization; [DataContract] -public class VerenigingsType +public class VerenigingsType : IVerenigingsType { /// /// Code van het type vereniging /// [DataMember(Name = "Code")] - public string Code { get; set; } = null!; + public string Code { get; init; } = null!; /// /// Beschrijving van het type vereniging /// [DataMember(Name = "Naam")] - public string Naam { get; set; } = null!; + public string Naam { get; init; } = null!; } diff --git a/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs b/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs index 9984466e7..362ed7483 100644 --- a/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs +++ b/src/AssociationRegistry.Public.Schema/Detail/VerenigingDetailDocument.cs @@ -36,10 +36,10 @@ public class PubliekVerenigingDetailDocument : IVCode, ISoftDeleted, ICanBeUitge public bool? IsUitgeschrevenUitPubliekeDatastroom { get; set; } [Identity] public string VCode { get; set; } = null!; - public class VerenigingsType + public class VerenigingsType : IVerenigingsType { - public string Code { get; set; } = null!; - public string Naam { get; set; } = null!; + public string Code { get; init; } = null!; + public string Naam { get; init; } = null!; } public class Contactgegeven diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs index 0661f13ff..7dd1ceda3 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/AdminApiEndpoints.cs @@ -30,28 +30,7 @@ public static async Task GetBeheerDetailWithHeader( HttpClient authenticatedClient, string vCode, long? expectedSequence) - { - var client = source.Server.CreateClient(); - - foreach (var defaultRequestHeader in authenticatedClient.DefaultRequestHeaders) - { - client.DefaultRequestHeaders.Add(defaultRequestHeader.Key, defaultRequestHeader.Value); - } - - client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); - - var response = await client.GetAsync($"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); - - while (response.StatusCode == HttpStatusCode.PreconditionFailed) - { - await Task.Delay(300); - response = await client.GetAsync($"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); - } - - var readAsStringAsync = await response.Content.ReadAsStringAsync(); - - return JsonConvert.DeserializeObject(readAsStringAsync); - } + => await GetResponseFromRequestWithHeader(source, authenticatedClient, $"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); public static DubbelControleResponse[] PostDubbelControle(this IAlbaHost source, RegistreerFeitelijkeVerenigingRequest registreerFeitelijkeVerenigingRequest) => source.PostJson(registreerFeitelijkeVerenigingRequest, @@ -64,6 +43,12 @@ public static async Task GetBeheerZoekenV2( this IAlbaHost source, HttpClient authenticatedClient, string query) + => await GetResponseFromRequestWithHeader(source, authenticatedClient, $"/v1/verenigingen/zoeken?q={query}"); + + private static async Task GetResponseFromRequestWithHeader( + IAlbaHost source, + HttpClient authenticatedClient, + string requestUri) { var client = source.Server.CreateClient(); @@ -74,16 +59,16 @@ public static async Task GetBeheerZoekenV2( client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); - var response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + var response = await client.GetAsync(requestUri); while (response.StatusCode == HttpStatusCode.PreconditionFailed) { await Task.Delay(300); - response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + response = await client.GetAsync(requestUri); } var readAsStringAsync = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(readAsStringAsync); + return JsonConvert.DeserializeObject(readAsStringAsync); } } diff --git a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs index efcb2ae01..e840805f1 100644 --- a/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs +++ b/test/AssociationRegistry.Test.E2E/Framework/AlbaHost/PublicApiEndpoints.cs @@ -14,6 +14,13 @@ public static class PublicApiEndpoints public static PubliekVerenigingDetailResponse GetPubliekDetail(this IAlbaHost source, string vCode) => source.GetAsJson($"/v1/verenigingen/{vCode}").GetAwaiter().GetResult()!; + public static async Task GetPubliekDetailWithHeader( + this IAlbaHost source, + HttpClient authenticatedClient, + string vCode, + long? expectedSequence) + => await GetResponseFromRequestWithHeader(source, authenticatedClient, $"/v1/verenigingen/{vCode}?expectedSequence={expectedSequence}"); + public static HttpStatusCode GetPubliekDetailStatusCode(this IAlbaHost source, string vCode) { var client = source.Server.CreateClient(); @@ -25,10 +32,16 @@ public static HttpStatusCode GetPubliekDetailStatusCode(this IAlbaHost source, s public static SearchVerenigingenResponse GetPubliekZoeken(this IAlbaHost source, string query) => source.GetAsJson($"/v1/verenigingen/zoeken?q={query}").GetAwaiter().GetResult()!; - public static async Task GetPubliekZoekenV2( + public static async Task GetPubliekZoekenWithHeader( this IAlbaHost source, HttpClient authenticatedClient, string query) + => await GetResponseFromRequestWithHeader(source, authenticatedClient, $"/v1/verenigingen/zoeken?q={query}"); + + private static async Task GetResponseFromRequestWithHeader( + IAlbaHost source, + HttpClient authenticatedClient, + string requestUri) { var client = source.Server.CreateClient(); @@ -39,17 +52,17 @@ public static async Task GetPubliekZoekenV2( client.DefaultRequestHeaders.Add(WellknownHeaderNames.Version, WellknownVersions.V2); - var response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + var response = await client.GetAsync(requestUri); while (response.StatusCode == HttpStatusCode.PreconditionFailed) { await Task.Delay(300); - response = await client.GetAsync($"/v1/verenigingen/zoeken?q={query}"); + response = await client.GetAsync(requestUri); } var readAsStringAsync = await response.Content.ReadAsStringAsync(); - return JsonConvert.DeserializeObject(readAsStringAsync); + return JsonConvert.DeserializeObject(readAsStringAsync); } public static WerkingsgebiedenResponse GetWerkingsgebieden(this IAlbaHost source) @@ -73,6 +86,7 @@ private static JObject[] ParseResponse(string responseContent) var verenigingen = new List(); var reader = new StringReader(responseContent); + while (reader.Peek() != -1) { var line = reader.ReadLine(); @@ -88,6 +102,7 @@ private static HttpResponseMessage GetS3Response(Uri? locationHeader) handler.ServerCertificateCustomValidationCallback = (_, _, _, _) => true; using var s3HttpClient = new HttpClient(handler); + return s3HttpClient.GetAsync(locationHeader).GetAwaiter().GetResult(); } @@ -95,6 +110,7 @@ private static HttpResponseMessage GetS3Response(Uri? locationHeader) { var client = source.Server.CreateClient(); var response = client.GetAsync($"/v1/verenigingen/detail/all").GetAwaiter().GetResult(); + return response.Headers.Location; } } diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/With_Header/Returns_VZER_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/With_Header/Returns_VZER_DetailResponse.cs new file mode 100644 index 000000000..b05568021 --- /dev/null +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/With_Header/Returns_VZER_DetailResponse.cs @@ -0,0 +1,174 @@ +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Detail.With_Header; + +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using Formats; +using JsonLdContext; +using AssociationRegistry.Public.Api.Verenigingen.Detail.ResponseModels; +using Framework.AlbaHost; +using Framework.ApiSetup; +using Framework.Comparison; +using Framework.TestClasses; +using Vereniging; +using KellermanSoftware.CompareNetObjects; +using NodaTime; +using Xunit; +using Contactgegeven = Public.Api.Verenigingen.Detail.ResponseModels.Contactgegeven; +using DoelgroepResponse = Public.Api.Verenigingen.Detail.ResponseModels.DoelgroepResponse; +using GestructureerdeIdentificator = Public.Api.Verenigingen.Detail.ResponseModels.GestructureerdeIdentificator; +using HoofdactiviteitVerenigingsloket = Public.Api.Verenigingen.Detail.ResponseModels.HoofdactiviteitVerenigingsloket; +using Locatie = Public.Api.Verenigingen.Detail.ResponseModels.Locatie; +using Relatie = Public.Api.Verenigingen.Detail.ResponseModels.Relatie; +using Sleutel = Public.Api.Verenigingen.Detail.ResponseModels.Sleutel; +using Vereniging = Public.Api.Verenigingen.Detail.ResponseModels.Vereniging; +using VerenigingStatus = Admin.Schema.Constants.VerenigingStatus; +using VerenigingsType = Public.Api.Verenigingen.Detail.ResponseModels.VerenigingsType; +using Werkingsgebied = Public.Api.Verenigingen.Detail.ResponseModels.Werkingsgebied; + +[Collection(FullBlownApiCollection.Name)] +public class Returns_VZER_DetailResponse : End2EndTest +{ + private readonly RegistreerFeitelijkeVerenigingTestContext _testContext; + + public Returns_VZER_DetailResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) + { + _testContext = testContext; + } + + [Fact] + public void With_Context() + { + Response.Context.ShouldCompare("http://127.0.0.1:11003/v1/contexten/publiek/detail-vereniging-context.json"); + } + + [Fact] + public void With_Metadata_DatumLaatsteAanpassing() + { + Response.Metadata.DatumLaatsteAanpassing.ShouldCompare(Instant.FromDateTimeOffset(DateTimeOffset.Now).FormatAsBelgianDate(), + compareConfig: new ComparisonConfig + { MaxMillisecondsDateDifference = 5000 }); + } + + [Fact] + public async Task WithFeitelijkeVereniging() + => Response.Vereniging.ShouldCompare(new Vereniging + { + type = JsonLdType.FeitelijkeVereniging.Type, + Doelgroep = new DoelgroepResponse + { + type = JsonLdType.Doelgroep.Type, + id = JsonLdType.Doelgroep.CreateWithIdValues(_testContext.VCode), + Minimumleeftijd = 1, + Maximumleeftijd = 149, + }, + VCode = _testContext.VCode, + KorteBeschrijving = Request.KorteBeschrijving, + KorteNaam = Request.KorteNaam, + Verenigingstype = new VerenigingsType + { + Code = Verenigingstype.VZER.Code, + Naam = Verenigingstype.VZER.Naam, + }, + Naam = Request.Naam, + Startdatum = DateOnly.FromDateTime(DateTime.Now), + Status = VerenigingStatus.Actief, + Contactgegevens = MapContactgegevens(Request.Contactgegevens, _testContext.VCode), + HoofdactiviteitenVerenigingsloket = MapHoofdactiviteitenVerenigingsloket(Request.HoofdactiviteitenVerenigingsloket), + Werkingsgebieden = MapWerkingsgebieden(Request.Werkingsgebieden), + Locaties = MapLocaties(Request.Locaties, _testContext.VCode), + Relaties = MapRelaties([], _testContext.VCode), + Sleutels = MapSleutels(Request, _testContext.VCode), + }, compareConfig: AdminDetailComparisonConfig.Instance); + + private static Sleutel[] MapSleutels(RegistreerFeitelijkeVerenigingRequest request, string vCode) + => + [ + new Sleutel + { + Bron = Sleutelbron.VR.Waarde, + id = JsonLdType.Sleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.Sleutel.Type, + Waarde = vCode, + CodeerSysteem = CodeerSysteem.VR, + GestructureerdeIdentificator = new GestructureerdeIdentificator + { + id = JsonLdType.GestructureerdeSleutel.CreateWithIdValues(vCode, Sleutelbron.VR.Waarde), + type = JsonLdType.GestructureerdeSleutel.Type, + Nummer = vCode, + }, + }, + ]; + + private static Relatie[] MapRelaties(Relatie[] relaties, string vCode) + { + return relaties.Select((x, i) => new Relatie + { + AndereVereniging = x.AndereVereniging, + Relatietype = x.Relatietype, + }).ToArray(); + } + + private static Contactgegeven[] MapContactgegevens(ToeTeVoegenContactgegeven[] toeTeVoegenContactgegevens, string vCode) + { + return toeTeVoegenContactgegevens.Select((x, i) => new Contactgegeven + { + id = JsonLdType.Contactgegeven.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Contactgegeven.Type, + Contactgegeventype = x.Contactgegeventype, + Waarde = x.Waarde, + Beschrijving = x.Beschrijving!, + IsPrimair = x.IsPrimair, + }).ToArray(); + } + + private static Locatie[] MapLocaties(ToeTeVoegenLocatie[] toeTeVoegenLocaties, string vCode) + { + return toeTeVoegenLocaties.Select((x, i) => new Locatie + { + id = JsonLdType.Locatie.CreateWithIdValues( + vCode, $"{i + 1}"), + type = JsonLdType.Locatie.Type, + Locatietype = x.Locatietype, + Naam = x.Naam, + IsPrimair = x.IsPrimair, + }).ToArray(); + } + + private static HoofdactiviteitVerenigingsloket[] MapHoofdactiviteitenVerenigingsloket( + string[] hoofdactiviteitenVerenigingsloket) + { + return hoofdactiviteitenVerenigingsloket.Select(x => + { + var hoofdactiviteitVerenigingsloket = AssociationRegistry.Vereniging.HoofdactiviteitVerenigingsloket.Create(x); + + return new HoofdactiviteitVerenigingsloket + { + Code = hoofdactiviteitVerenigingsloket.Code, + Naam = hoofdactiviteitVerenigingsloket.Naam, + id = JsonLdType.Hoofdactiviteit.CreateWithIdValues(hoofdactiviteitVerenigingsloket.Code), + type = JsonLdType.Hoofdactiviteit.Type, + }; + }).ToArray(); + } + + private static Werkingsgebied[] MapWerkingsgebieden( + string[] werkingsgebieden) + { + return werkingsgebieden.Select(x => + { + var werkingsgebied = AssociationRegistry.Vereniging.Werkingsgebied.Create(x); + + return new Werkingsgebied + { + Code = werkingsgebied.Code, + Naam = werkingsgebied.Naam, + id = JsonLdType.Werkingsgebied.CreateWithIdValues(werkingsgebied.Code), + type = JsonLdType.Werkingsgebied.Type, + }; + }).ToArray(); + } + + public override Func GetResponse + => setup => setup.PublicApiHost.GetPubliekDetailWithHeader(setup.SuperAdminHttpClient, _testContext.VCode, _testContext.RequestResult.Sequence).GetAwaiter().GetResult(); +} diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Without_Header/Returns_DetailResponse.cs similarity index 93% rename from test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs rename to test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Without_Header/Returns_DetailResponse.cs index 1b7b47078..e111b0bf0 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Returns_DetailResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Detail/Without_Header/Returns_DetailResponse.cs @@ -1,15 +1,15 @@ -namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Detail; +namespace AssociationRegistry.Test.E2E.When_Registreer_FeitelijkeVereniging.Publiek.Detail.Without_Header; -using Admin.Api.Verenigingen.Common; -using Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; -using Formats; -using JsonLdContext; +using AssociationRegistry.Admin.Api.Verenigingen.Common; +using AssociationRegistry.Admin.Api.Verenigingen.Registreer.FeitelijkeVereniging.RequetsModels; +using AssociationRegistry.Formats; +using AssociationRegistry.JsonLdContext; using AssociationRegistry.Public.Api.Verenigingen.Detail.ResponseModels; -using Framework.AlbaHost; -using Framework.ApiSetup; -using Framework.Comparison; -using Framework.TestClasses; -using Vereniging; +using AssociationRegistry.Test.E2E.Framework.AlbaHost; +using AssociationRegistry.Test.E2E.Framework.ApiSetup; +using AssociationRegistry.Test.E2E.Framework.Comparison; +using AssociationRegistry.Test.E2E.Framework.TestClasses; +using AssociationRegistry.Vereniging; using KellermanSoftware.CompareNetObjects; using NodaTime; using Xunit; diff --git a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs similarity index 92% rename from test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs rename to test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs index 324fc9739..0590a3364 100644 --- a/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_ZoekResponse.cs +++ b/test/AssociationRegistry.Test.E2E/When_Registreer_FeitelijkeVereniging/Publiek/Zoeken/With_Header/Returns_VZER_ZoekResponse.cs @@ -17,11 +17,11 @@ using Werkingsgebied = Public.Api.Verenigingen.Search.ResponseModels.Werkingsgebied; [Collection(FullBlownApiCollection.Name)] -public class Returns_SearchVerenigingenResponse : End2EndTest +public class Returns_VZER_ZoekResponse : End2EndTest { private readonly RegistreerFeitelijkeVerenigingTestContext _testContext; - public Returns_SearchVerenigingenResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) + public Returns_VZER_ZoekResponse(RegistreerFeitelijkeVerenigingTestContext testContext) : base(testContext) { _testContext = testContext; } @@ -132,5 +132,5 @@ private static Werkingsgebied[] MapWerkingsgebieden( } public override Func GetResponse - => setup => setup.PublicApiHost.GetPubliekZoekenV2(setup.SuperAdminHttpClient,$"vCode:{_testContext.VCode}").GetAwaiter().GetResult(); + => setup => setup.PublicApiHost.GetPubliekZoekenWithHeader(setup.SuperAdminHttpClient,$"vCode:{_testContext.VCode}").GetAwaiter().GetResult(); } diff --git a/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs b/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs index 3de010f5a..970cac6e9 100644 --- a/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs +++ b/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_Adres.cs @@ -19,7 +19,8 @@ public void Then_Adres_Is_Null() var fixture = new Fixture().CustomizePublicApi(); var publiekVerenigingDetailDocument = fixture.Create(); publiekVerenigingDetailDocument.Locaties.First().Adres = null; - var publiekVerenigingDetailResponse = PubliekVerenigingDetailMapper.Map(publiekVerenigingDetailDocument, new AppSettings(), Mock.Of()); + var responseMapper = new PubliekVerenigingDetailMapper(new AppSettings(), null); + var publiekVerenigingDetailResponse = responseMapper.Map(publiekVerenigingDetailDocument, Mock.Of()); publiekVerenigingDetailResponse.Vereniging.Locaties.First().Adres.Should().BeNull(); } } diff --git a/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs b/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs index b8a71b393..9a2131df8 100644 --- a/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs +++ b/test/AssociationRegistry.Test.Public.Api/Mapping/When_Mapping_A_Location_To_Adres/Given_A_Null_AdresId.cs @@ -19,7 +19,8 @@ public void Then_AdresId_Is_Null() var fixture = new Fixture().CustomizePublicApi(); var publiekVerenigingDetailDocument = fixture.Create(); publiekVerenigingDetailDocument.Locaties.First().AdresId = null; - var publiekVerenigingDetailResponse = PubliekVerenigingDetailMapper.Map(publiekVerenigingDetailDocument, new AppSettings(), Mock.Of()); + var responseMapper = new PubliekVerenigingDetailMapper(new AppSettings(), null); + var publiekVerenigingDetailResponse = responseMapper.Map(publiekVerenigingDetailDocument, Mock.Of()); publiekVerenigingDetailResponse.Vereniging.Locaties.First().AdresId.Should().BeNull(); } }