feat: add envelope delete command and API endpoint

This commit is contained in:
2026-09-25 11:31:40 +02:00
parent 435be882c9
commit 4449743105
9 changed files with 214 additions and 3 deletions

View File

@@ -0,0 +1,25 @@
using System.ComponentModel.DataAnnotations;
using EnvelopeGenerator.Domain.Constants;
using MediatR;
namespace EnvelopeGenerator.Application.Envelopes.Commands;
public record DeleteEnvelopeResultDto(int EnvelopeId, EnvelopeStatus AppliedStatus, bool IsNoOp);
public record DeleteEnvelopeCommand : IRequest<DeleteEnvelopeResultDto>
{
[Required]
public int EnvelopeId { get; init; }
[Required]
[MinLength(1)]
public string Reason { get; init; } = string.Empty;
internal int UserId { get; private set; }
public DeleteEnvelopeCommand WithAuth(int userId)
{
UserId = userId;
return this;
}
}

View File

@@ -0,0 +1,83 @@
using EnvelopeGenerator.Application.Common.Notifications.EnvelopeDeleted;
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Histories.Commands;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace EnvelopeGenerator.Application.Envelopes.Commands;
public class DeleteEnvelopeCommandHandler : IRequestHandler<DeleteEnvelopeCommand, DeleteEnvelopeResultDto>
{
private readonly IRepository<Envelope> _envelopeRepository;
private readonly IMediator _mediator;
public DeleteEnvelopeCommandHandler(
IRepository<Envelope> envelopeRepository,
IMediator mediator)
{
_envelopeRepository = envelopeRepository;
_mediator = mediator;
}
public async Task<DeleteEnvelopeResultDto> Handle(DeleteEnvelopeCommand request, CancellationToken cancel)
{
var reason = request.Reason?.Trim();
if (string.IsNullOrWhiteSpace(reason))
throw new BadRequestException("Please provide a reason.");
var envelope = await _envelopeRepository.Query
.Include(e => e.User)
.Include(e => e.EnvelopeReceivers)
.ThenInclude(er => er.Receiver)
.FirstOrDefaultAsync(e => e.Id == request.EnvelopeId, cancel)
?? throw new NotFoundException($"Envelope {request.EnvelopeId} not found.");
if (envelope.UserId != request.UserId)
throw new ForbiddenException();
if (envelope.Status is EnvelopeStatus.EnvelopeDeleted or EnvelopeStatus.EnvelopeWithdrawn)
return new DeleteEnvelopeResultDto(envelope.Id, envelope.Status, IsNoOp: true);
var targetStatus = envelope.Status > EnvelopeStatus.EnvelopeSaved
? EnvelopeStatus.EnvelopeWithdrawn
: EnvelopeStatus.EnvelopeDeleted;
envelope.Status = targetStatus;
envelope.Comment = reason;
envelope.ChangedWhen = DateTime.Now;
await _envelopeRepository.UpdateAsync(envelope, e => e.Id == envelope.Id, cancel);
var userReference = envelope.User?.Email;
if (string.IsNullOrWhiteSpace(userReference))
throw new BadRequestException("Envelope sender email is missing.");
await _mediator.Send(new CreateHistoryCommand
{
EnvelopeId = envelope.Id,
UserReference = userReference,
Status = targetStatus,
Comment = reason
}, cancel);
foreach (var envelopeReceiver in envelope.EnvelopeReceivers ?? Enumerable.Empty<EnvelopeReceiver>())
{
if (envelopeReceiver.Receiver is null)
continue;
await _mediator.Publish(new EnvelopeDeletedNotification
{
Envelope = envelope,
EnvelopeReceiver = envelopeReceiver,
Reason = reason,
SenderReference = userReference
}, cancel);
}
return new DeleteEnvelopeResultDto(envelope.Id, targetStatus, IsNoOp: false);
}
}