Compare commits

...

19 Commits

Author SHA1 Message Date
Developer 02
8a4d3ff6f9 refactor(SaveDocStatusCommand): simplify repository filtering in SaveDocStatusCommandHandler
- Replaced explicit envelope and receiver expression filters with a single `.Where(request)` call.
- Removed redundant checks for null and empty values in handler.
- Updated using statements to include `EnvelopeGenerator.Application.Extensions`.
- Maintains the same functionality while reducing code complexity.
2025-08-26 22:34:54 +02:00
Developer 02
783d91a658 feat(QueryExtensions): add combined EnvelopeReceiver query support in QueryExtensions 2025-08-26 22:32:34 +02:00
Developer 02
ad032b2bdf fix(QueryExtensions): update to use base classes instead of interfaces 2025-08-26 22:23:26 +02:00
Developer 02
f2876d8995 move model intterfaces to interfaces dir 2025-08-26 22:09:45 +02:00
Developer 02
5468d7b2aa feat: add QueryExtensions for filtering by Envelope and Receiver
- Introduced extension methods on IQueryable<TEntity> to filter entities
  by Envelope (Id or Uuid) and Receiver (Id, EmailAddress, or Signature).
- Throws BadRequestException if no valid identifier is provided when notnull = true.
- Improves query handling consistency across application layer.
2025-08-26 22:05:33 +02:00
Developer 02
b005c194d3 create and implement IHasEnvelopeQuery and IHasReceiverQuery 2025-08-26 19:43:55 +02:00
Developer 02
dee6608390 add and implement IHasEnvelope and IHasReceiver 2025-08-26 19:20:44 +02:00
Developer 02
8b53eae6da init QueryExtensions 2025-08-26 18:51:57 +02:00
Developer 02
405b619bdc refactor(ReceiverAlreadySignedQuery): update to use common models 2025-08-26 17:29:07 +02:00
Developer 02
c5918b8e49 refactor(CreateHistoryCommand): update to use EnvelopeQuery- and ReceiverQueryBase 2025-08-26 17:16:30 +02:00
Developer 02
05cd8a05f4 refactor(MappingProfile): create to handle model mappings 2025-08-26 17:13:21 +02:00
Developer 02
2355a566e4 refactor(EnvelopeReceiverQueryBase): simplify EnvelopeReceiverQueryBase.Key handling
- Introduced private backing field `_key` for Key property
- Removed dynamic recomputation from Envelope and Receiver
- Ensured Key is only set once during initialization
- Improved null handling and exception safety
2025-08-26 16:49:22 +02:00
Developer 02
c887f857cd fix(EnvelopeReceiverQueryBase): make Envelope and Receiver properties not null and set default value 2025-08-26 16:39:12 +02:00
Developer 02
f114144d34 Fügen das Suffix „-base“ am Ende gängiger Modelle hinzu. 2025-08-26 16:36:52 +02:00
Developer 02
5c09601e3f refactor(ModifyDocStatusCommandBase): update to use EnvelopeReceiverQuery 2025-08-26 16:33:56 +02:00
Developer 02
18b05a3c63 refactor(ReceiverQuery): make properties virtual 2025-08-26 16:26:52 +02:00
Developer 02
ce35b0fea1 refactor(EnvelopeQuery): make properties virtual 2025-08-26 16:26:11 +02:00
Developer 02
7f18cd64c5 feat(EnvelopeReceiverQuery): create query with Key, Envelope and Receiver properties 2025-08-26 16:25:37 +02:00
Developer 02
0083c1b6c1 Create common Envelope and Receiver queries 2025-08-26 14:34:52 +02:00
14 changed files with 283 additions and 204 deletions

View File

@@ -1,47 +1,13 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
/// <summary>
///
/// </summary>
public record ModifyDocStatusCommandBase
public record ModifyDocStatusCommandBase : EnvelopeReceiverQueryBase
{
/// <summary>
///
/// </summary>
public string? Key
{
get => Envelope?.Uuid is string uuid && Receiver?.Signature is string signature
? (uuid, signature).EncodeEnvelopeReceiverId()
: null;
init
{
if (value is null)
return;
(string? EnvelopeUuid, string? ReceiverSignature) = value.DecodeEnvelopeReceiverId();
if (string.IsNullOrEmpty(EnvelopeUuid) || string.IsNullOrEmpty(ReceiverSignature))
{
throw new BadRequestException("Der EnvelopeReceiverKey muss ein gültiger Base64-kodierter String sein, der die EnvelopeUuid und die ReceiverSignature enthält.");
}
Envelope.Uuid = EnvelopeUuid;
Receiver.Signature = ReceiverSignature;
}
}
/// <summary>
/// Der Umschlag, der mit dem Empfänger verknüpft ist.
/// </summary>
public EnvelopeQuery Envelope { get; set; } = new();
/// <summary>
/// Der Empfänger, der mit dem Umschlag verknüpft ist.
/// </summary>
public ReceiverQuery Receiver { get; set; } = new();
/// <summary>
/// Gets the current status code.
/// </summary>
@@ -70,44 +36,4 @@ public record ModifyDocStatusCommandBase
Receiver = Receiver,
Value = Value
};
}
#region Queries
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
/// </summary>
public record EnvelopeQuery
{
/// <summary>
/// Die eindeutige Kennung des Umschlags.
/// </summary>
public int? Id { get; init; }
/// <summary>
/// Die universell eindeutige Kennung des Umschlags.
/// </summary>
public string? Uuid { get; set; }
}
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public record ReceiverQuery
{
/// <summary>
/// ID des Empfängers
/// </summary>
public int? Id { get; init; }
/// <summary>
/// E-Mail Adresse des Empfängers
/// </summary>
public string? EmailAddress { get; init; }
/// <summary>
/// Eindeutige Signatur des Empfängers
/// </summary>
public string? Signature { get; set; }
}
#endregion
}

View File

@@ -1,9 +1,8 @@
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System.Linq.Expressions;
using EnvelopeGenerator.Application.Extensions;
namespace EnvelopeGenerator.Application.DocStatus.Commands;
@@ -60,30 +59,13 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
/// <returns></returns>
public async Task<int?> Handle(SaveDocStatusCommand request, CancellationToken cancel)
{
// envelope filter
Expression<Func<DocumentStatus, bool>>? eExp =
request.Envelope.Id is not null
? ds => ds.EnvelopeId == request.Envelope.Id
: !string.IsNullOrWhiteSpace(request.Envelope.Uuid)
? ds => ds.Envelope.Uuid == request.Envelope.Uuid
: throw new BadRequestException();
// receiver filter
Expression<Func<DocumentStatus, bool>>? rExp =
request.Receiver.Id is not null
? ds => ds.ReceiverId == request.Receiver.Id
: request.Receiver.EmailAddress is not null
? ds => ds.Receiver.EmailAddress == request.Receiver.EmailAddress
: !string.IsNullOrWhiteSpace(request.Receiver.Signature) ? ds => ds.Receiver.Signature == request.Receiver.Signature
: throw new BadRequestException();
// ceck if exists
bool isExists = await _repo.ReadOnly().Where(eExp).Where(rExp).AnyAsync(cancel);
bool isExists = await _repo.ReadOnly().Where(request).AnyAsync(cancel);
if (isExists)
{
var uReq = request.To<UpdateDocStatusCommand>();
await _repo.UpdateAsync(uReq, q => q.Where(eExp).Where(rExp), cancel);
await _repo.UpdateAsync(uReq, q => q.Where(request), cancel);
}
else
{
@@ -91,7 +73,7 @@ public class SaveDocStatusCommandHandler : IRequestHandler<SaveDocStatusCommand,
await _repo.CreateAsync(cReq, cancel);
}
var docStatus = await _repo.ReadOnly().Where(eExp).Where(rExp).SingleOrDefaultAsync(cancel);
var docStatus = await _repo.ReadOnly().Where(request).SingleOrDefaultAsync(cancel);
return docStatus?.Id;
}
}

View File

@@ -16,7 +16,5 @@ public class MappingProfile : Profile
{
CreateMap<CreateDocStatusCommand, DocumentStatus>();
CreateMap<UpdateDocStatusCommand, DocumentStatus>();
CreateMap<EnvelopeQuery, Envelope>();
CreateMap<ReceiverQuery, Receiver>();
}
}

View File

@@ -1,5 +1,6 @@
using DigitalData.Core.Abstraction.Application.Repository;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Extensions;
@@ -11,58 +12,7 @@ namespace EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
/// <summary>
///
/// </summary>
public record ReceiverAlreadySignedQuery : IRequest<bool>
{
/// <summary>
///
/// </summary>
public string Key
{
get => (Envelope.Uuid, Receiver.Signature).EncodeEnvelopeReceiverId();
init
{
(string? EnvelopeUuid, string? ReceiverSignature) = value.DecodeEnvelopeReceiverId();
if (string.IsNullOrEmpty(EnvelopeUuid) || string.IsNullOrEmpty(ReceiverSignature))
{
throw new BadRequestException("Der EnvelopeReceiverKey muss ein gültiger Base64-kodierter String sein, der die EnvelopeUuid und die ReceiverSignature enthält.");
}
}
}
/// <summary>
///
/// </summary>
public EnvelopeQuery Envelope { get; set; } = new EnvelopeQuery();
/// <summary>
///
/// </summary>
public ReceiverQuery Receiver { get; set; } = new ReceiverQuery();
}
#region Queries
/// <summary>
///
/// </summary>
public record EnvelopeQuery()
{
/// <summary>
///
/// </summary>
public string Uuid { get; set; } = null!;
};
/// <summary>
///
/// </summary>
public record ReceiverQuery()
{
/// <summary>
///
/// </summary>
public string Signature { get; set; } = null!;
};
#endregion
public record ReceiverAlreadySignedQuery : EnvelopeReceiverQueryBase, IRequest<bool>;
/// <summary>
///

View File

@@ -0,0 +1,77 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain.Interfaces;
namespace EnvelopeGenerator.Application.Extensions;
/// <summary>
///
/// </summary>
public static class QueryExtensions
{
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, EnvelopeQueryBase query, bool notnull = true)
where TEntity : IHasEnvelope
{
if (query.Id is not null)
root = root.Where(e => e.Envelope!.Id == query.Id);
else if (query.Uuid is not null)
root = root.Where(e => e.Envelope!.Uuid == query.Uuid);
else if (notnull)
throw new BadRequestException(
"Either Envelope Id or Envelope Uuid must be provided in the query."
);
return root;
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
/// <exception cref="BadRequestException"></exception>
public static IQueryable<TEntity> Where<TEntity>(this IQueryable<TEntity> root, ReceiverQueryBase query, bool notnull = true)
where TEntity : IHasReceiver
{
if (query.Id is not null)
root = root.Where(e => e.Receiver!.Id == query.Id);
else if (query.EmailAddress is not null)
root = root.Where(e => e.Receiver!.EmailAddress == query.EmailAddress);
else if (query.Signature is not null)
root = root.Where(e => e.Receiver!.Signature == query.Signature);
else if (notnull)
throw new BadRequestException(
"Receiver must have at least one identifier (Id, EmailAddress, or Signature)."
);
return root;
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TEnvelopeQuery"></typeparam>
/// <typeparam name="TReceiverQuery"></typeparam>
/// <param name="root"></param>
/// <param name="query"></param>
/// <param name="notnull"></param>
/// <returns></returns>
public static IQueryable<TEntity> Where<TEntity, TEnvelopeQuery, TReceiverQuery>(this IQueryable<TEntity> root, EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery> query, bool notnull = true)
where TEntity : IHasEnvelope, IHasReceiver
where TEnvelopeQuery : EnvelopeQueryBase, new()
where TReceiverQuery : ReceiverQueryBase, new()
=> root.Where(query.Envelope, notnull).Where(query.Receiver, notnull);
}

View File

@@ -1,4 +1,5 @@
using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Model;
using EnvelopeGenerator.Domain;
using EnvelopeGenerator.Domain.Entities;
using MediatR;
@@ -44,54 +45,14 @@ public record CreateHistoryCommand : IRequest<long?>
/// <summary>
///
/// </summary>
public EnvelopeQuery? Envelope { get; init; }
public EnvelopeQueryBase? Envelope { get; init; }
/// <summary>
/// /
/// </summary>
public ReceiverQuery? Receiver { get; init; }
public ReceiverQueryBase? Receiver { get; init; }
}
#region Queries
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
/// </summary>
public record EnvelopeQuery
{
/// <summary>
/// Die eindeutige Kennung des Umschlags.
/// </summary>
public int? Id { get; init; }
/// <summary>
/// Die universell eindeutige Kennung des Umschlags.
/// </summary>
public string? Uuid { get; set; }
}
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public record ReceiverQuery
{
/// <summary>
/// ID des Empfängers
/// </summary>
public int? Id { get; init; }
/// <summary>
/// E-Mail Adresse des Empfängers
/// </summary>
public string? EmailAddress { get; init; }
/// <summary>
/// Eindeutige Signatur des Empfängers
/// </summary>
public string? Signature { get; set; }
}
#endregion
/// <summary>
///
/// </summary>

View File

@@ -0,0 +1,17 @@
namespace EnvelopeGenerator.Application.Model;
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
/// </summary>
public record EnvelopeQueryBase
{
/// <summary>
/// Die eindeutige Kennung des Umschlags.
/// </summary>
public virtual int? Id { get; init; }
/// <summary>
/// Die universell eindeutige Kennung des Umschlags.
/// </summary>
public virtual string? Uuid { get; set; }
}

View File

@@ -0,0 +1,62 @@
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Extensions;
namespace EnvelopeGenerator.Application.Model;
/// <summary>
///
/// </summary>
public record EnvelopeReceiverQueryBase : EnvelopeReceiverQueryBase<EnvelopeQueryBase, ReceiverQueryBase>;
/// <summary>
///
/// </summary>
/// <typeparam name="TEnvelopeQuery"></typeparam>
/// <typeparam name="TReceiverQuery"></typeparam>
public record EnvelopeReceiverQueryBase<TEnvelopeQuery, TReceiverQuery>
where TEnvelopeQuery : EnvelopeQueryBase, new()
where TReceiverQuery : ReceiverQueryBase, new()
{
private string? _key;
/// <summary>
///
/// </summary>
public virtual string? Key
{
get => _key;
set
{
if (value is null)
{
_key = null;
return;
}
(string? EnvelopeUuid, string? ReceiverSignature) = value.DecodeEnvelopeReceiverId();
if (string.IsNullOrEmpty(EnvelopeUuid) || string.IsNullOrEmpty(ReceiverSignature))
throw new BadRequestException("Der EnvelopeReceiverKey muss ein gültiger Base64-kodierter String sein, der die EnvelopeUuid und die ReceiverSignature enthält.");
Envelope = new TEnvelopeQuery()
{
Uuid = EnvelopeUuid
};
Receiver = new TReceiverQuery()
{
Signature = ReceiverSignature
};
_key = value;
}
}
/// <summary>
/// Repräsentiert eine Abfrage für Umschläge.
/// </summary>
public virtual TEnvelopeQuery Envelope { get; set; } = new();
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public virtual TReceiverQuery Receiver { get; set; } = new();
}

View File

@@ -0,0 +1,20 @@
using AutoMapper;
using EnvelopeGenerator.Domain.Entities;
namespace EnvelopeGenerator.Application.Model;
/// <summary>
///
/// </summary>
public class MappingProfile : Profile
{
/// <summary>
///
/// </summary>
public MappingProfile()
{
CreateMap<EnvelopeQueryBase, Envelope>();
CreateMap<ReceiverQueryBase, Receiver>();
CreateMap<EnvelopeReceiverQueryBase, EnvelopeReceiver>();
}
}

View File

@@ -0,0 +1,23 @@
namespace EnvelopeGenerator.Application.Model;
/// <summary>
/// Stellt eine Abfrage dar, um die Details eines Empfängers zu lesen.
/// um spezifische Informationen über einen Empfänger abzurufen.
/// </summary>
public record ReceiverQueryBase
{
/// <summary>
/// ID des Empfängers
/// </summary>
public virtual int? Id { get; init; }
/// <summary>
/// E-Mail Adresse des Empfängers
/// </summary>
public virtual string? EmailAddress { get; init; }
/// <summary>
/// Eindeutige Signatur des Empfängers
/// </summary>
public virtual string? Signature { get; set; }
}

View File

@@ -1,5 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using EnvelopeGenerator.Domain.Interfaces;
#if NETFRAMEWORK
using System;
#endif
@@ -12,7 +14,7 @@ namespace EnvelopeGenerator.Domain.Entities
#endif
[Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")]
public class DocumentStatus
public class DocumentStatus : IHasEnvelope, IHasReceiver
{
public DocumentStatus()
{
@@ -43,10 +45,18 @@ public class DocumentStatus
public string Value { get; set; }
[ForeignKey("EnvelopeId")]
public virtual Envelope Envelope { get; set; }
public virtual Envelope
#if NET
?
#endif
Envelope { get; set; }
[ForeignKey("ReceiverId")]
public virtual Receiver Receiver { get; set; }
public virtual Receiver
#if NET
?
#endif
Receiver { get; set; }
}
#if NETFRAMEWORK

View File

@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Drawing;
using EnvelopeGenerator.Domain.Interfaces;
#if NETFRAMEWORK
using System;
#endif
@@ -13,7 +14,7 @@ namespace EnvelopeGenerator.Domain.Entities
#endif
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
public class EnvelopeReceiver
public class EnvelopeReceiver : IHasEnvelope, IHasReceiver
{
public EnvelopeReceiver()
{
@@ -70,10 +71,18 @@ public class EnvelopeReceiver
public bool HasPhoneNumber => !string.IsNullOrWhiteSpace(PhoneNumber);
[ForeignKey("EnvelopeId")]
public Envelope Envelope { get; set; }
public Envelope
#if NET
?
#endif
Envelope { get; set; }
[ForeignKey("ReceiverId")]
public Receiver Receiver { get; set; }
public Receiver
#if NET
?
#endif
Receiver { get; set; }
#region Model of old serice
[NotMapped]
@@ -86,8 +95,8 @@ public class EnvelopeReceiver
public bool HasEmailAndName =>
!string.IsNullOrWhiteSpace(Receiver.EmailAddress) &&
!string.IsNullOrWhiteSpace(Name);
#endregion
}
#endregion
}
#if NETFRAMEWORK
}

View File

@@ -0,0 +1,22 @@
namespace EnvelopeGenerator.Domain.Interfaces
#if NET
;
#elif NETFRAMEWORK
{
#endif
public interface IHasEnvelope
{
#if NET
public
#endif
Entities.Envelope
#if NET
?
#endif
Envelope { get; set; }
}
#if NETFRAMEWORK
}
#endif

View File

@@ -0,0 +1,22 @@
namespace EnvelopeGenerator.Domain.Interfaces
#if NET
;
#elif NETFRAMEWORK
{
#endif
public interface IHasReceiver
{
#if NET
public
#endif
Entities.Receiver
#if NET
?
#endif
Receiver { get; set; }
}
#if NETFRAMEWORK
}
#endif