diff --git a/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/RemoveEnvelopeReceiverCommand.cs b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/RemoveEnvelopeReceiverCommand.cs
new file mode 100644
index 00000000..b64e4e43
--- /dev/null
+++ b/EnvelopeGenerator.Application/EnvelopeReceivers/Commands/RemoveEnvelopeReceiverCommand.cs
@@ -0,0 +1,84 @@
+using DigitalData.Core.Abstraction.Application.Repository;
+using DigitalData.Core.Exceptions;
+using EnvelopeGenerator.Domain.Constants;
+using EnvelopeGenerator.Domain.Entities;
+using EnvelopeGenerator.Domain.Exceptions;
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+
+namespace EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
+
+///
+///
+///
+public record RemoveEnvelopeReceiverCommand : IRequest
+{
+ ///
+ ///
+ ///
+ public required int EnvelopeId { get; init; }
+
+ ///
+ ///
+ ///
+ public required int ReceiverId { get; init; }
+
+ internal int? UserId { get; private set; }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public RemoveEnvelopeReceiverCommand Authenticated(int userId)
+ {
+ UserId = userId;
+ return this;
+ }
+}
+
+///
+///
+///
+///
+public class RemoveEnvelopeReceiverCommandHandler(
+ IRepository Repo,
+ IRepository ElementRepo,
+ IRepository AnnotRepo) : IRequestHandler
+{
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task Handle(RemoveEnvelopeReceiverCommand request, CancellationToken cancel)
+ {
+ var er = await Repo.Query
+ .Where(er => er.EnvelopeId == request.EnvelopeId && er.ReceiverId == request.ReceiverId)
+ .Include(er => er.Envelope)
+ .SingleOrDefaultAsync(cancel)
+ ?? throw new NotFoundException();
+
+ if (er.Envelope is null)
+ throw new InvalidOperationException($"In {nameof(RemoveEnvelopeReceiverCommandHandler)} EnvelopeReceiver.Envelope is null." +
+ $"This should not happen." +
+ $"EnvelopeId: {request.EnvelopeId}, ReceiverId: {request.ReceiverId}");
+
+ if (request.UserId is int userId && er.Envelope.UserId != userId)
+ throw new AuthorizationException("Cannot remove receiver from envelope that you do not own.");
+
+ if (er.Envelope.Status > EnvelopeStatus.EnvelopeSaved)
+ throw new ForbiddenException("Cannot remove receiver from envelope that is already processed.");
+
+ // 1. Delete all ElementAnnotations for this EnvelopeReceiver
+ await AnnotRepo.DeleteAsync(ann => ann.Element.Document.EnvelopeId == request.EnvelopeId && ann.Element.ReceiverId == request.ReceiverId, cancel);
+
+ // 2. Delete all DocReceiverElements for this EnvelopeReceiver
+ await ElementRepo.DeleteAsync(el => el.Document.EnvelopeId == request.EnvelopeId && el.ReceiverId == request.ReceiverId, cancel);
+
+ // 3. Delete the EnvelopeReceiver
+ await Repo.DeleteAsync(er => er.EnvelopeId == request.EnvelopeId && er.ReceiverId == request.ReceiverId, cancel);
+ }
+}
\ No newline at end of file
diff --git a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs
index fe85f9ed..7e1c313f 100644
--- a/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs
+++ b/EnvelopeGenerator.Server/EnvelopeGenerator.Server/Controllers/EnvelopeReceiverController.cs
@@ -17,6 +17,7 @@ using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Application.EnvelopeReceivers.Commands.CreateEnvelopeReceiver;
using EnvelopeGenerator.Application.Common.Extensions;
using EnvelopeGenerator.Server.Options;
+using EnvelopeGenerator.Application.EnvelopeReceivers.Commands;
namespace EnvelopeGenerator.Server.Controllers;
@@ -26,34 +27,16 @@ namespace EnvelopeGenerator.Server.Controllers;
///
/// Dieser Controller bietet Endpunkte für das Abrufen und Verwalten von Umschlagempfängerdaten.
///
+///
+/// Konstruktor für den EnvelopeReceiverController.
+///
[Route("api/[controller]")]
[Authorize]
[ApiController]
-public class EnvelopeReceiverController : ControllerBase
+public class EnvelopeReceiverController(ILogger Logger, IMediator Mediator, IMapper Mapper, IEnvelopeExecutor EnvelopeExecutor, IEnvelopeReceiverExecutor ER_Executor, IDocumentExecutor DocExecutor, IOptions csOpt, IOptionsMonitor senderFeatAccessOpt) : ControllerBase
{
- private readonly ILogger _logger;
- private readonly IMediator _mediator;
- private readonly IMapper _mapper;
- private readonly IEnvelopeExecutor _envelopeExecutor;
- private readonly IEnvelopeReceiverExecutor _erExecutor;
- private readonly IDocumentExecutor _documentExecutor;
- private readonly string _cnnStr;
- private readonly IOptionsMonitor _senderFeatureAccessOptions;
-
- ///
- /// Konstruktor für den EnvelopeReceiverController.
- ///
- public EnvelopeReceiverController(ILogger logger, IMediator mediator, IMapper mapper, IEnvelopeExecutor envelopeExecutor, IEnvelopeReceiverExecutor erExecutor, IDocumentExecutor documentExecutor, IOptions csOpt, IOptionsMonitor senderFeatureAccessOptions)
- {
- _logger = logger;
- _mediator = mediator;
- _mapper = mapper;
- _envelopeExecutor = envelopeExecutor;
- _erExecutor = erExecutor;
- _documentExecutor = documentExecutor;
- _cnnStr = csOpt.Value.Value;
- _senderFeatureAccessOptions = senderFeatureAccessOptions;
- }
+ private readonly string _cnnStr = csOpt.Value.Value;
+ private readonly IOptionsMonitor SenderFeatAccessOpt = senderFeatAccessOpt;
///
/// Ruft eine Liste von Umschlagempfängern basierend auf den angegebenen Abfrageparametern ab.
@@ -73,7 +56,7 @@ public class EnvelopeReceiverController : ControllerBase
{
envelopeReceiver = envelopeReceiver with { Username = User.GetUsername() };
- var result = await _mediator.Send(envelopeReceiver);
+ var result = await Mediator.Send(envelopeReceiver);
return Ok(result);
}
@@ -88,7 +71,7 @@ public class EnvelopeReceiverController : ControllerBase
[HttpGet("{envelopeKey}")]
public async Task GetEnvelopeReceiverOfReceiver([FromRoute] string envelopeKey, CancellationToken cancel)
{
- var er = await _mediator.Send(new ReadEnvelopeReceiverQuery()
+ var er = await Mediator.Send(new ReadEnvelopeReceiverQuery()
{
Key = envelopeKey
}, cancel);
@@ -112,10 +95,16 @@ public class EnvelopeReceiverController : ControllerBase
[HttpGet("salute")]
public async Task GetReceiverName([FromQuery] ReadReceiverNameQuery receiver)
{
- var name = await _mediator.Send(receiver);
+ var name = await Mediator.Send(receiver);
return name is null ? NotFound() : Ok(name);
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
[Authorize(AuthenticationSchemes = AuthScheme.Sender)]
[HttpGet("receiver-envelope-url")]
public IActionResult GetReceiverEnvelopeUrl([FromQuery] string envelopeUuid, [FromQuery] string receiverSignature)
@@ -132,6 +121,10 @@ public class EnvelopeReceiverController : ControllerBase
return Ok(new { url = absoluteUrl });
}
+ ///
+ ///
+ ///
+ ///
[Authorize(AuthenticationSchemes = AuthScheme.Sender)]
[HttpGet("receiver-envelope-url/enabled")]
public IActionResult GetReceiverEnvelopeUrlFeatureEnabled()
@@ -145,7 +138,7 @@ public class EnvelopeReceiverController : ControllerBase
if (string.IsNullOrWhiteSpace(senderEmail))
return false;
- var allowedEmails = _senderFeatureAccessOptions.CurrentValue.AllowedReceiverEnvelopeUrlEmails;
+ var allowedEmails = SenderFeatAccessOpt.CurrentValue.AllowedReceiverEnvelopeUrlEmails;
return allowedEmails.Any(email => string.Equals(email?.Trim(), senderEmail, StringComparison.OrdinalIgnoreCase));
}
@@ -159,7 +152,7 @@ public class EnvelopeReceiverController : ControllerBase
[HttpGet("recent-suggestions")]
public async Task GetRecentSuggestions([FromQuery] ReadRecentReceiverSuggestionsQuery query, CancellationToken cancel)
{
- var result = await _mediator.Send(query.ForSender(User.GetUsername()), cancel);
+ var result = await Mediator.Send(query.ForSender(User.GetUsername()), cancel);
return Ok(result);
}
@@ -206,7 +199,7 @@ public class EnvelopeReceiverController : ControllerBase
public async Task CreateAsync([FromBody] CreateEnvelopeReceiverCommand request, CancellationToken cancel)
{
#region Create Envelope
- var envelope = await _envelopeExecutor.CreateEnvelopeAsync(User.GetId(), request.Title, request.Message, request.TFAEnabled, cancel);
+ var envelope = await EnvelopeExecutor.CreateEnvelopeAsync(User.GetId(), request.Title, request.Message, request.TFAEnabled, cancel);
#endregion
#region Add receivers
@@ -215,7 +208,7 @@ public class EnvelopeReceiverController : ControllerBase
foreach (var receiver in request.Receivers)
{
- var envelopeReceiver = await _erExecutor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel);
+ var envelopeReceiver = await ER_Executor.AddEnvelopeReceiverAsync(envelope.Uuid, receiver.EmailAddress, receiver.Salution, receiver.PhoneNumber, cancel);
if (envelopeReceiver is null)
unsentReceivers.Add(receiver);
@@ -223,13 +216,13 @@ public class EnvelopeReceiverController : ControllerBase
sentReceivers.Add(envelopeReceiver);
}
- var res = _mapper.Map(envelope);
+ var res = Mapper.Map(envelope);
res.UnsentReceivers = unsentReceivers;
- res.SentReceiver = _mapper.Map>(sentReceivers.Select(er => er.Receiver));
+ res.SentReceiver = Mapper.Map>(sentReceivers.Select(er => er.Receiver));
#endregion
#region Add document
- var document = await _documentExecutor.CreateDocumentAsync(request.Document.DataAsBase64, envelope.Uuid, cancel);
+ var document = await DocExecutor.CreateDocumentAsync(request.Document.DataAsBase64, envelope.Uuid, cancel);
if (document is null)
return StatusCode(StatusCodes.Status500InternalServerError, "Document creation is failed.");
@@ -266,7 +259,7 @@ public class EnvelopeReceiverController : ControllerBase
{
bool outSuccess = reader.GetBoolean(0);
if (!outSuccess)
- _logger.LogWarning(
+ Logger.LogWarning(
"PRSIG_API_ADD_DOC_RECEIVER_ELEM returned OUT_SUCCESS=false. DOC_ID={DocId}, RECEIVER_ID={ReceiverId}, Page={Page}",
document.Id, rcv.Id, sign.Page);
}
@@ -298,7 +291,7 @@ public class EnvelopeReceiverController : ControllerBase
{
bool outSuccess = reader.GetBoolean(0);
if (!outSuccess)
- _logger.LogWarning(
+ Logger.LogWarning(
"PRSIG_API_ADD_HISTORY_STATE returned OUT_SUCCESS=false. EnvelopeUuid={EnvelopeUuid}",
envelope.Uuid);
}
@@ -329,4 +322,18 @@ public class EnvelopeReceiverController : ControllerBase
}
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpDelete]
+ [Authorize(AuthenticationSchemes = AuthScheme.Sender)]
+ public async Task RemoveAsync([FromQuery] RemoveEnvelopeReceiverCommand request, CancellationToken cancel)
+ {
+ request = request.Authenticated(User.GetId());
+ await Mediator.Send(request, cancel);
+ return Ok();
+ }
}