Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: or-2515 request model and validation for wijzig lidmaatschap #980

Merged
merged 2 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.Examples;
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.Examples;

using RequestModels;
using Swashbuckle.AspNetCore.Filters;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.RequestModels;
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;

using Acties.VoegLidmaatschapToe;
using System.Runtime.Serialization;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.RequestModels;
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;

using FluentValidation;
using Infrastructure.Validation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap;
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe;

using Acties.VoegLidmaatschapToe;
using Asp.Versioning;
Expand Down Expand Up @@ -37,22 +37,23 @@ public VoegLidmaatschapToeController(IMessageBus messageBus, AppSettings appSett
}

/// <summary>
/// Voeg een Lidmaatschap toe.
/// Voeg een lidmaatschap toe.
/// </summary>
/// <remarks>
/// Na het uitvoeren van deze actie wordt een sequentie teruggegeven via de `VR-Sequence` header.
/// Deze waarde kan gebruikt worden in andere endpoints om op te volgen of de aanpassing
/// al is doorgestroomd naar deze endpoints.
/// Na het uitvoeren van deze actie wordt een sequentie teruggegeven via de `VR-Sequence` header.
/// Deze waarde kan gebruikt worden in andere endpoints om op te volgen of de aanpassing
/// al is doorgestroomd naar deze endpoints.
/// </remarks>
/// <param name="vCode">De VCode van de vereniging</param>
/// <param name="request">De toe te voegen Lidmaatschap</param>
/// <param name="vCode">De VCode van de vereniging.</param>
/// <param name="request">Het toe te voegen lidmaatschap.</param>
/// <param name="validator">De validator voor het toevoegen van een lidmaatschap.</param>
/// <param name="metadataProvider"></param>
/// <param name="ifMatch">If-Match header met ETag van de laatst gekende versie van de vereniging.</param>
/// <response code="202">Het lidmaatschap werd toegevoegd.</response>
/// <response code="400">Er was een probleem met de doorgestuurde waarden.</response>
/// <response code="412">De gevraagde vereniging heeft niet de verwachte sequentiewaarde.</response>
/// <response code="500">Er is een interne fout opgetreden.</response>
[HttpPost("{vCode}/Lidmaatschappen")]
[HttpPost("{vCode}/lidmaatschappen")]
[ConsumesJson]
[ProducesJson]
[SwaggerRequestExample(typeof(VoegLidmaatschapToeRequest), typeof(VoegLidmaatschapToeRequestExamples))]
Expand All @@ -64,7 +65,7 @@ public VoegLidmaatschapToeController(IMessageBus messageBus, AppSettings appSett
[SwaggerResponseHeader(StatusCodes.Status202Accepted, name: "ETag", type: "string",
description: "De versie van de geregistreerde vereniging.")]
[SwaggerResponseHeader(StatusCodes.Status202Accepted, name: "Location", type: "string",
description: "De Lidmaatschap van de toegevoegde Lidmaatschap.")]
description: "De locatie van het toegevoegde lidmaatschap.")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status412PreconditionFailed)]
Expand All @@ -73,12 +74,11 @@ public VoegLidmaatschapToeController(IMessageBus messageBus, AppSettings appSett
public async Task<IActionResult> Post(
[FromRoute] string vCode,
[FromBody] VoegLidmaatschapToeRequest request,
//[FromServices] IValidator<VoegLidmaatschapToeRequest> validator,
[FromServices] IValidator<VoegLidmaatschapToeRequest> validator,
[FromServices] ICommandMetadataProvider metadataProvider,
[FromHeader(Name = "If-Match")] string? ifMatch = null)
{
// TODO: validate
//await validator.NullValidateAndThrowAsync(request);
await validator.NullValidateAndThrowAsync(request);

var metaData = metadataProvider.GetMetadata(IfMatchParser.ParseIfMatch(ifMatch));
var envelope = new CommandEnvelope<VoegLidmaatschapToeCommand>(request.ToCommand(vCode), metaData);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.WijzigLidmaatschap.Examples;

using RequestModels;
using Swashbuckle.AspNetCore.Filters;

public class WijzigLidmaatschapRequestExamples : IExamplesProvider<WijzigLidmaatschapRequest>
{
public WijzigLidmaatschapRequest GetExamples()
=> new()
{
LidmaatschapId = 1,
Beschrijving = "De beschrijving van het lidmaatschap.",
Van = new DateOnly(2024, 10, 12),
Tot = new DateOnly(2024, 10, 10),
Identificatie = "0012",
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.WijzigLidmaatschap.RequestModels;

using System.Runtime.Serialization;

[DataContract]
public class WijzigLidmaatschapRequest
{
/// <summary>
/// De unieke identificator van het lidmaatschap
/// </summary>
[DataMember]
public int LidmaatschapId { get; set; }

/// <summary>
/// De datum waarop de relatie actief wordt
/// </summary>
[DataMember]
public DateOnly? Van { get; set; }

/// <summary>
/// De datum waarop de relatie niet meer actief wordt
/// </summary>
[DataMember]
public DateOnly? Tot { get; set; }

/// <summary>
/// De externe identificatie voor het lidmaatschap
/// </summary>
[DataMember]
public string Identificatie { get; set; }

/// <summary>
/// De externe beschrijving van het lidmaatschap
/// </summary>
[DataMember]
public string Beschrijving { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.WijzigLidmaatschap.RequestModels;

using FluentValidation;
using Infrastructure.Validation;

public class WijzigLidmaatschapRequestValidator : AbstractValidator<WijzigLidmaatschapRequest>
{
public WijzigLidmaatschapRequestValidator()
{
RuleFor(r => r.LidmaatschapId)
.GreaterThan(0)
.WithMessage(ValidationMessages.VeldIsVerplicht);

RuleFor(r => r.Tot)
.GreaterThanOrEqualTo(x => x.Van)
.When(x => x.Van.HasValue)
.WithMessage(ValidationMessages.DatumTotMoetLaterZijnDanDatumVan);

RuleFor(r => r.Identificatie).MustNotContainHtml();
RuleFor(r => r.Beschrijving).MustNotContainHtml();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
namespace AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.WijzigLidmaatschap;

using Asp.Versioning;
using Be.Vlaanderen.Basisregisters.Api;
using Be.Vlaanderen.Basisregisters.Api.Exceptions;
using Examples;
using FluentValidation;
using Hosts.Configuration.ConfigurationBindings;
using Infrastructure;
using Infrastructure.Extensions;
using Infrastructure.Middleware;
using Infrastructure.Swagger.Annotations;
using Infrastructure.Swagger.Examples;
using Microsoft.AspNetCore.Mvc;
using RequestModels;
using Swashbuckle.AspNetCore.Filters;
using Wolverine;
using ProblemDetails = Be.Vlaanderen.Basisregisters.BasicApiProblem.ProblemDetails;
using ValidationProblemDetails = Be.Vlaanderen.Basisregisters.BasicApiProblem.ValidationProblemDetails;

[ApiVersion("1.0")]
[AdvertiseApiVersions("1.0")]
[ApiRoute("verenigingen")]
[SwaggerGroup.DecentraalBeheer]

// TODO Remove visibility marker before actual deployment
[ApiExplorerSettings(IgnoreApi = true)]
public class WijzigLidmaatschapController : ApiController
{
private readonly IMessageBus _messageBus;
private readonly AppSettings _appSettings;

public WijzigLidmaatschapController(IMessageBus messageBus, AppSettings appSettings)
{
_messageBus = messageBus;
_appSettings = appSettings;
}

/// <summary>
/// Wijzig een lidmaatschap.
/// </summary>
/// <remarks>
/// Na het uitvoeren van deze actie wordt een sequentie teruggegeven via de `VR-Sequence` header.
/// Deze waarde kan gebruikt worden in andere endpoints om op te volgen of de aanpassing
/// al is doorgestroomd naar deze endpoints.
/// </remarks>
/// <param name="vCode">De VCode van de vereniging.</param>
/// <param name="request">Het te wijzigen lidmaatschap.</param>
/// <param name="validator">De validator voor het wijzigen van het lidmaatschap.</param>
/// <param name="metadataProvider"></param>
/// <param name="ifMatch">If-Match header met ETag van de laatst gekende versie van de vereniging.</param>
/// <response code="202">Het lidmaatschap werd gewijzigd.</response>
/// <response code="400">Er was een probleem met de doorgestuurde waarden.</response>
/// <response code="412">De gevraagde vereniging heeft niet de verwachte sequentiewaarde.</response>
/// <response code="500">Er is een interne fout opgetreden.</response>
[HttpPatch("{vCode}/lidmaatschappen")]
[ConsumesJson]
[ProducesJson]
[SwaggerRequestExample(typeof(WijzigLidmaatschapRequest), typeof(WijzigLidmaatschapRequestExamples))]
[SwaggerResponseExample(StatusCodes.Status500InternalServerError, typeof(InternalServerErrorResponseExamples))]
[SwaggerResponseExample(StatusCodes.Status400BadRequest, typeof(ProblemAndValidationProblemDetailsExamples))]
[SwaggerResponseExample(StatusCodes.Status412PreconditionFailed, typeof(PreconditionFailedProblemDetailsExamples))]
[SwaggerResponseHeader(StatusCodes.Status202Accepted, WellknownHeaderNames.Sequence, type: "string",
description: "Het sequence nummer van deze request.")]
[SwaggerResponseHeader(StatusCodes.Status202Accepted, name: "ETag", type: "string",
description: "De versie van de geregistreerde vereniging.")]
[SwaggerResponseHeader(StatusCodes.Status202Accepted, name: "Location", type: "string",
description: "De locatie van het gewijzigde lidmaatschap.")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status412PreconditionFailed)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status500InternalServerError)]
[ProducesResponseType(StatusCodes.Status202Accepted)]
public async Task<IActionResult> Post(
[FromRoute] string vCode,
[FromBody] WijzigLidmaatschapRequest request,
[FromServices] IValidator<WijzigLidmaatschapRequest> validator,
[FromServices] ICommandMetadataProvider metadataProvider,
[FromHeader(Name = "If-Match")] string? ifMatch = null)
{
await validator.NullValidateAndThrowAsync(request);

var metaData = metadataProvider.GetMetadata(IfMatchParser.ParseIfMatch(ifMatch));
// var envelope = new CommandEnvelope<WijzigLidmaatschapCommand>(request.ToCommand(vCode), metaData);
// var commandResult = await _messageBus.InvokeAsync<EntityCommandResult>(envelope);

// return this.AcceptedEntityCommand(_appSettings, WellKnownHeaderEntityNames.Lidmaatschappen, commandResult);

return new EmptyResult();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_Adding_Lidmaatschap.CommandHandling;
namespace AssociationRegistry.Test.Admin.Api.Commands.VerenigingOfAnyKind.When_Adding_Lidmaatschap.CommandHandling;

using Acties.VoegLidmaatschapToe;
using AssociationRegistry.Framework;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_Adding_Lidmaatschap.RequestMapping;
namespace AssociationRegistry.Test.Admin.Api.Commands.VerenigingOfAnyKind.When_Adding_Lidmaatschap.RequestMapping;

using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.RequestModels;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;
using AutoFixture;
using Common.AutoFixture;
using FluentAssertions;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_Adding_Lidmaatschap.RequestValidating;
namespace AssociationRegistry.Test.Admin.Api.Commands.VerenigingOfAnyKind.When_Adding_Lidmaatschap.RequestValidating;

using AssociationRegistry.Admin.Api;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.RequestModels;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;
using AutoFixture;
using Common.AutoFixture;
using FluentValidation.TestHelper;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace AssociationRegistry.Test.Admin.Api.Commands.FeitelijkeVereniging.When_Adding_Lidmaatschap.RequestValidating;
namespace AssociationRegistry.Test.Admin.Api.Commands.VerenigingOfAnyKind.When_Adding_Lidmaatschap.RequestValidating;

using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.RequestModels;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;
using AutoFixture;
using Common.AutoFixture;
using FluentValidation.TestHelper;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
namespace AssociationRegistry.Test.Admin.Api.Commands.VerenigingOfAnyKind.When_Wijzig_Lidmaatschap.RequestValidating;
janlesage marked this conversation as resolved.
Show resolved Hide resolved

using AssociationRegistry.Admin.Api;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.VoegLidmaatschapToe.RequestModels;
using AssociationRegistry.Admin.Api.Verenigingen.Lidmaatschap.WijzigLidmaatschap.RequestModels;
using AssociationRegistry.Resources;
using AssociationRegistry.Test.Common.AutoFixture;
using AutoFixture;
using FluentValidation.TestHelper;
using Microsoft.AspNetCore.Http;
using Xunit;
using Xunit.Categories;
using ValidatorTest = Framework.ValidatorTest;

[UnitTest]
public class A_Invalid_Request : ValidatorTest
{
private readonly Fixture _fixture;
private readonly WijzigLidmaatschapRequestValidator _validator;

public A_Invalid_Request()
{
_fixture = new Fixture().CustomizeAdminApi();
_validator = new WijzigLidmaatschapRequestValidator();
}

[Fact]
public void Has_validation_errors_for_lidmaatschapId_when_zero()
{
var request = _fixture.Create<WijzigLidmaatschapRequest>();
request.LidmaatschapId = 0;

var result = _validator.TestValidate(request);

result.ShouldHaveValidationErrorFor(x => x.LidmaatschapId)
.WithErrorMessage(ValidationMessages.VeldIsVerplicht);
}

[Fact]
public void Has_validation_errors_when_tot_after_van()
{
var request = _fixture.Create<WijzigLidmaatschapRequest>();
request.Van = DateOnly.FromDateTime(DateTime.Now);
request.Tot = DateOnly.FromDateTime(DateTime.Now.AddDays(-1));

var result = _validator.TestValidate(request);
result.ShouldHaveValidationErrorFor(x => x.Tot)
.WithErrorMessage(ValidationMessages.DatumTotMoetLaterZijnDanDatumVan);
}

[Fact]
public void Has_no_validation_errors_when_tot_not_after_van()
{
var request = _fixture.Create<WijzigLidmaatschapRequest>();
request.Van = DateOnly.FromDateTime(DateTime.Now);
request.Tot = DateOnly.FromDateTime(DateTime.Now.AddDays(1));

var result = _validator.TestValidate(request);
result.ShouldNotHaveAnyValidationErrors();
}

[Fact]
public void Has_validation_errors_when_html_detected_in_identificatie()
{
var request = _fixture.Create<WijzigLidmaatschapRequest>();
request.Identificatie = "<p>Something something</p>";

var result = _validator.TestValidate(request);
result.ShouldHaveValidationErrorFor(r => r.Identificatie)
.WithErrorCode(StatusCodes.Status400BadRequest.ToString())
.WithErrorMessage(ExceptionMessages.UnsupportedContent);
}

[Fact]
public void Has_validation_errors_when_html_detected_in_beschrijving()
{
var request = _fixture.Create<WijzigLidmaatschapRequest>();
request.Beschrijving = "<p>Something something</p>";

var result = _validator.TestValidate(request);
result.ShouldHaveValidationErrorFor(r => r.Beschrijving)
.WithErrorCode(StatusCodes.Status400BadRequest.ToString())
.WithErrorMessage(ExceptionMessages.UnsupportedContent);
}
}
Loading
Loading