Compare commits
129 Commits
3f116ce11a
...
feat/annot
| Author | SHA1 | Date | |
|---|---|---|---|
| e66c46767e | |||
| bc732d311c | |||
| c90d29d654 | |||
| 47a2e950ca | |||
| 6ef989213e | |||
| 2a27b6161b | |||
| efdc372b04 | |||
| 698b7ca1ac | |||
| bf6947a28c | |||
| e2e31e2e69 | |||
| 73f6221c3c | |||
| 10f730a833 | |||
| cf5a301942 | |||
| e364f1f592 | |||
| 8a488d4e71 | |||
| f0be1a5b03 | |||
| 773721b634 | |||
| 99e3e4c24d | |||
| b9c86ce3c6 | |||
| 637b45efe0 | |||
| 28b8c311f9 | |||
| 00c7fe5316 | |||
| e5a061d5b5 | |||
| 629b02863b | |||
| 3b24755c35 | |||
| 864e9e8164 | |||
| 7eff958d0a | |||
| c3deaae63b | |||
| bb0197e6ba | |||
| ec2935b524 | |||
| 4fd7982cba | |||
| ddcf5edc00 | |||
| 74d207caa3 | |||
| a367c12551 | |||
| 35a328f8dc | |||
| d259a15b4b | |||
| 23e0e5ddbe | |||
| 0bb85c28c1 | |||
| a11d9a0e0e | |||
| b9bb058137 | |||
| 0818d7d9eb | |||
| 9d200800c5 | |||
| 6feb601670 | |||
| 39c12ada45 | |||
| 985ad4dc29 | |||
| 038ac2aed0 | |||
| 5e74de0ce7 | |||
| 0ce7ae9494 | |||
| 7041a4694a | |||
| 75e47d10e3 | |||
| 7f9125b3aa | |||
| fee256a51a | |||
| 8ad7c37261 | |||
| ef28bbaaf1 | |||
| 258de6244c | |||
| a845b85a5c | |||
| 02a7b706cf | |||
| 7912469709 | |||
| 75d975223e | |||
| c456d67d03 | |||
| 241e59fc7e | |||
| f0d101bb23 | |||
| 8db5afae40 | |||
| b62cca5961 | |||
| 0e7b120ded | |||
| d8cbdb0c65 | |||
| 0107602a84 | |||
| 02ecd88758 | |||
| 17c7e46388 | |||
| f3af30c67d | |||
| 90e10d3d04 | |||
| af14ef7ce5 | |||
| 1edcfed318 | |||
| 2004c7ced2 | |||
| 40135fb8a2 | |||
| b57c0aa9c7 | |||
| 2c4c18935f | |||
| d8ed06fdb6 | |||
| 09bf8db884 | |||
| 911c812b19 | |||
| 8ae0f79365 | |||
| 0ca54fe1fe | |||
| a1d6b5347f | |||
| 6cc631111c | |||
| 9d6074874f | |||
| 26bdb0806d | |||
| 7919f02ffd | |||
| 04ae14c660 | |||
| cff79730b0 | |||
| 188cb67306 | |||
| abaa315b24 | |||
| 4f463c27e6 | |||
| d6f17ec4e8 | |||
| e3e2831da1 | |||
| 52306d481f | |||
| f046be240b | |||
| 16e5d5c692 | |||
| e64ad44b71 | |||
| e88bd55198 | |||
| 4abed0e1bc | |||
| 69821e64c6 | |||
| f13a2434f7 | |||
| ecc7552951 | |||
| d10f19d92a | |||
| 5e53f2b691 | |||
| f56928f44f | |||
| faa37e0dcd | |||
| e51470a449 | |||
| adce61fead | |||
| e052bf56f4 | |||
| 22a7619627 | |||
| 281cf47834 | |||
| a258dcdad0 | |||
| 79c26eb5b5 | |||
| ce7ca39c39 | |||
| 7b6f916486 | |||
| 57422a481c | |||
| e96523b786 | |||
| 3b7d0e1321 | |||
| 9adc1ea4e7 | |||
| 510f5e9ddd | |||
| 44b204ca68 | |||
| b72ac68daf | |||
| 7d85d59ace | |||
| 4fad41bd0b | |||
| 39936792aa | |||
| 74f444a8d6 | |||
| b67f26cc21 | |||
| a29f918125 |
73
EnvelopeGenerator.Application/Common/Dto/AnnotationDto.cs
Normal file
73
EnvelopeGenerator.Application/Common/Dto/AnnotationDto.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
namespace EnvelopeGenerator.Application.Common.Dto;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public record AnnotationCreateDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public int ElementId { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; init; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Value { get; init; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string Type { get; init; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public double? X { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public double? Y { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public double? Width { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public double? Height { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public record AnnotationDto : AnnotationCreateDto
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public DateTime AddedWhen { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ChangedWhen { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public string? ChangedWho { get; init; }
|
||||||
|
}
|
||||||
@@ -82,7 +82,7 @@ public record EnvelopeDto
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? UseAccessCode { get; set; }
|
public bool UseAccessCode { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class MappingProfile : Profile
|
|||||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||||
CreateMap<Domain.Entities.Receiver, ReceiverDto>();
|
CreateMap<Domain.Entities.Receiver, ReceiverDto>();
|
||||||
CreateMap<Domain.Entities.EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
|
CreateMap<Domain.Entities.EnvelopeReceiverReadOnly, EnvelopeReceiverReadOnlyDto>();
|
||||||
|
CreateMap<ElementAnnotation, AnnotationDto>();
|
||||||
|
|
||||||
// DTO to Entity mappings
|
// DTO to Entity mappings
|
||||||
CreateMap<ConfigDto, Config>();
|
CreateMap<ConfigDto, Config>();
|
||||||
@@ -50,6 +51,8 @@ public class MappingProfile : Profile
|
|||||||
CreateMap<ReceiverDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
CreateMap<ReceiverDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||||
|
CreateMap<AnnotationCreateDto, ElementAnnotation>()
|
||||||
|
.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
|
||||||
|
|
||||||
// Messaging mappings
|
// Messaging mappings
|
||||||
// for GTX messaging
|
// for GTX messaging
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
using EnvelopeGenerator.Application.Common.Dto;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Application.Common.Extensions;
|
using EnvelopeGenerator.Application.Common.Extensions;
|
||||||
|
using EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="Instant"></param>
|
||||||
|
/// <param name="Structured"></param>
|
||||||
|
public record PsPdfKitAnnotation(ExpandoObject Instant, IEnumerable<AnnotationCreateDto> Structured);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -16,7 +24,7 @@ public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeRece
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required ExpandoObject Annotations { get; init; }
|
public PsPdfKitAnnotation PsPdfKitAnnotation { get; init; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
@@ -40,17 +48,41 @@ public static class DocSignedNotificationExtensions
|
|||||||
/// Converts an <see cref="EnvelopeReceiverDto"/> to a <see cref="DocSignedNotification"/>.
|
/// Converts an <see cref="EnvelopeReceiverDto"/> to a <see cref="DocSignedNotification"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dto">The DTO to convert.</param>
|
/// <param name="dto">The DTO to convert.</param>
|
||||||
/// <param name="annotations"></param>
|
/// <param name="psPdfKitAnnotation"></param>
|
||||||
/// <returns>A new <see cref="DocSignedNotification"/> instance.</returns>
|
/// <returns>A new <see cref="DocSignedNotification"/> instance.</returns>
|
||||||
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, ExpandoObject annotations)
|
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, PsPdfKitAnnotation psPdfKitAnnotation)
|
||||||
=> new(dto) { Annotations = annotations };
|
=> new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asynchronously converts a <see cref="Task{EnvelopeReceiverDto}"/> to a <see cref="DocSignedNotification"/>.
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dtoTask">The task that returns the DTO to convert.</param>
|
/// <param name="dtoTask"></param>
|
||||||
/// <param name="annotations"></param>
|
/// <param name="psPdfKitAnnotation"></param>
|
||||||
/// <returns>A task that represents the asynchronous conversion operation.</returns>
|
/// <returns></returns>
|
||||||
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, ExpandoObject annotations)
|
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, PsPdfKitAnnotation psPdfKitAnnotation)
|
||||||
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { Annotations = annotations } : null;
|
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation } : null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="publisher"></param>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task PublishSafely(this IPublisher publisher, DocSignedNotification notification, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await publisher.Publish(notification, cancel);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
await publisher.Publish(new RemoveSignatureNotification()
|
||||||
|
{
|
||||||
|
EnvelopeId = notification.EnvelopeId,
|
||||||
|
ReceiverId = notification.ReceiverId
|
||||||
|
}, cancel);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using EnvelopeGenerator.Application.DocStatus.Commands;
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||||
|
|
||||||
@@ -10,15 +9,18 @@ namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
||||||
{
|
{
|
||||||
private readonly ISender _sender;
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
private readonly IRepository<ElementAnnotation> _repo;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="sender"></param>
|
/// <param name="repository"></param>
|
||||||
public AnnotationHandler(ISender sender)
|
public AnnotationHandler(IRepository<ElementAnnotation> repository)
|
||||||
{
|
{
|
||||||
_sender = sender;
|
_repo = repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -27,13 +29,6 @@ public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
|||||||
/// <param name="notification"></param>
|
/// <param name="notification"></param>
|
||||||
/// <param name="cancel"></param>
|
/// <param name="cancel"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
public Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||||
{
|
=> _repo.CreateAsync(notification.PsPdfKitAnnotation.Structured, cancel);
|
||||||
await _sender.Send(new SaveDocStatusCommand()
|
|
||||||
{
|
|
||||||
Envelope = new() { Id = notification.EnvelopeId },
|
|
||||||
Receiver = new() { Id = notification.ReceiverId},
|
|
||||||
Value = JsonSerializer.Serialize(notification.Annotations, Format.Json.ForAnnotations)
|
|
||||||
}, cancel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using EnvelopeGenerator.Application.DocStatus.Commands;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using MediatR;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class DocStatusHandler : INotificationHandler<DocSignedNotification>
|
||||||
|
{
|
||||||
|
private readonly ISender _sender;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
public DocStatusHandler(ISender sender)
|
||||||
|
{
|
||||||
|
_sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
await _sender.Send(new SaveDocStatusCommand()
|
||||||
|
{
|
||||||
|
Envelope = new() { Id = notification.EnvelopeId },
|
||||||
|
Receiver = new() { Id = notification.ReceiverId},
|
||||||
|
Value = JsonSerializer.Serialize(notification.PsPdfKitAnnotation.Instant, Format.Json.ForAnnotations)
|
||||||
|
}, cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using EnvelopeGenerator.Application.Histories.Commands;
|
using EnvelopeGenerator.Application.Histories.Commands;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class RemoveAnnotationHandler : INotificationHandler<RemoveSignatureNotification>
|
||||||
|
{
|
||||||
|
private readonly IRepository<ElementAnnotation> _repo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository"></param>
|
||||||
|
public RemoveAnnotationHandler(IRepository<ElementAnnotation> repository)
|
||||||
|
{
|
||||||
|
_repo = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
notification.ThrowIfHasNoFilter();
|
||||||
|
return _repo.DeleteAsync(annots =>
|
||||||
|
{
|
||||||
|
// envelope ID filter
|
||||||
|
if (notification.EnvelopeId is int envelopeId)
|
||||||
|
annots = annots.Where(annot => annot.Element!.Document.EnvelopeId == envelopeId);
|
||||||
|
|
||||||
|
// envelope UUID filter
|
||||||
|
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||||
|
annots = annots.Where(annot => annot.Element!.Document.Envelope!.Uuid == envelopeUuid);
|
||||||
|
|
||||||
|
// receiver ID
|
||||||
|
if (notification.ReceiverId is int receiverId)
|
||||||
|
annots = annots.Where(annot => annot.Element!.ReceiverId == receiverId);
|
||||||
|
|
||||||
|
// receiver signature
|
||||||
|
if (notification.ReceiverSignature is string receiverSignature)
|
||||||
|
annots = annots.Where(annot => annot.Element!.Receiver!.Signature == receiverSignature);
|
||||||
|
|
||||||
|
return annots;
|
||||||
|
}, cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using AngleSharp.Html;
|
||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class RemoveDocStatusHandler : INotificationHandler<RemoveSignatureNotification>
|
||||||
|
{
|
||||||
|
private readonly IRepository<Domain.Entities.DocumentStatus> _repo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository"></param>
|
||||||
|
public RemoveDocStatusHandler(IRepository<Domain.Entities.DocumentStatus> repository)
|
||||||
|
{
|
||||||
|
_repo = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
notification.ThrowIfHasNoFilter();
|
||||||
|
return _repo.DeleteAsync(statuses =>
|
||||||
|
{
|
||||||
|
// envelope ID filter
|
||||||
|
if (notification.EnvelopeId is int envelopeId)
|
||||||
|
statuses = statuses.Where(status => status.EnvelopeId == envelopeId);
|
||||||
|
|
||||||
|
// envelope UUID filter
|
||||||
|
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||||
|
statuses = statuses.Where(status => status.Envelope!.Uuid == envelopeUuid);
|
||||||
|
|
||||||
|
// receiver Id filter
|
||||||
|
if (notification.ReceiverId is int receiverId)
|
||||||
|
statuses = statuses.Where(status => status.ReceiverId == receiverId);
|
||||||
|
|
||||||
|
// receiver signature filter
|
||||||
|
if (notification.ReceiverSignature is string receiverSignature)
|
||||||
|
statuses = statuses.Where(status => status.Receiver!.Signature == receiverSignature);
|
||||||
|
|
||||||
|
return statuses;
|
||||||
|
}, cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using EnvelopeGenerator.Application.Common.Extensions;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class RemoveHistoryHandler : INotificationHandler<RemoveSignatureNotification>
|
||||||
|
{
|
||||||
|
private readonly IRepository<Domain.Entities.History> _repo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repository"></param>
|
||||||
|
public RemoveHistoryHandler(IRepository<Domain.Entities.History> repository)
|
||||||
|
{
|
||||||
|
_repo = repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="notification"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
notification.ThrowIfHasNoFilter();
|
||||||
|
return _repo.DeleteAsync(hists =>
|
||||||
|
{
|
||||||
|
hists = hists.Where(hist => hist.Status == EnvelopeStatus.DocumentSigned);
|
||||||
|
|
||||||
|
// envelope ID filter
|
||||||
|
if (notification.EnvelopeId is int envelopeId)
|
||||||
|
hists = hists.Where(hist => hist.EnvelopeId == envelopeId);
|
||||||
|
|
||||||
|
// envelope UUID filter
|
||||||
|
if (notification.EnvelopeUuid is string envelopeUuid)
|
||||||
|
hists = hists.Where(hist => hist.Envelope!.Uuid == envelopeUuid);
|
||||||
|
|
||||||
|
// receiver ID filter
|
||||||
|
if (notification.ReceiverId is int receiverId)
|
||||||
|
hists = hists.Where(hist => hist.Receiver!.Id == receiverId);
|
||||||
|
|
||||||
|
// receiver signature filter
|
||||||
|
if (notification.ReceiverSignature is string receiverSignature)
|
||||||
|
hists = hists.Where(hist => hist.Receiver!.Signature == receiverSignature);
|
||||||
|
|
||||||
|
return hists;
|
||||||
|
}, cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="EnvelopeId"></param>
|
||||||
|
/// <param name="ReceiverId"></param>
|
||||||
|
/// <param name="EnvelopeUuid"></param>
|
||||||
|
/// <param name="ReceiverSignature"></param>
|
||||||
|
public record RemoveSignatureNotification(
|
||||||
|
int? EnvelopeId = null,
|
||||||
|
int? ReceiverId = null,
|
||||||
|
string? EnvelopeUuid = null,
|
||||||
|
string? ReceiverSignature = null
|
||||||
|
) : INotification
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public bool HasFilter =>
|
||||||
|
EnvelopeId is not null
|
||||||
|
|| ReceiverId is not null
|
||||||
|
|| EnvelopeUuid is not null
|
||||||
|
|| ReceiverSignature is not null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="InvalidOperationException"></exception>
|
||||||
|
public void ThrowIfHasNoFilter()
|
||||||
|
{
|
||||||
|
if (!HasFilter)
|
||||||
|
throw new InvalidOperationException("At least one filter parameter must be provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
|
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.4.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Client" Version="2.1.0" />
|
<PackageReference Include="DigitalData.Core.Client" Version="2.1.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Histories.Queries;
|
||||||
|
|
||||||
|
//TODO: Add sender query
|
||||||
|
/// <summary>
|
||||||
|
/// Repräsentiert eine Abfrage für die Verlaufshistorie eines Umschlags.
|
||||||
|
/// </summary>
|
||||||
|
public record CountHistoryQuery : HistoryQueryBase, IRequest<int>;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public static class CountHistoryQueryExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender"></param>
|
||||||
|
/// <param name="uuid"></param>
|
||||||
|
/// <param name="statuses"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<bool> AnyHistoryAsync(this ISender sender, string uuid, IEnumerable<EnvelopeStatus> statuses, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var count = await sender.Send(new CountHistoryQuery
|
||||||
|
{
|
||||||
|
Envelope = new() { Uuid = uuid },
|
||||||
|
Statuses = new() { Include = statuses }
|
||||||
|
}, cancel);
|
||||||
|
return count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class CountHistoryQueryHandler : IRequestHandler<CountHistoryQuery, int>
|
||||||
|
{
|
||||||
|
private readonly IRepository<History> _repo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repo"></param>
|
||||||
|
public CountHistoryQueryHandler(IRepository<History> repo)
|
||||||
|
{
|
||||||
|
_repo = repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotFoundException"></exception>
|
||||||
|
public Task<int> Handle(CountHistoryQuery request, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var query = _repo.Query;
|
||||||
|
|
||||||
|
if (request.Envelope.Id is int envId)
|
||||||
|
query = query.Where(e => e.Id == envId);
|
||||||
|
else if (request.Envelope.Uuid is string uuid)
|
||||||
|
query = query.Where(e => e.Envelope!.Uuid == uuid);
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
else if (request.EnvelopeId is not null)
|
||||||
|
query = query.Where(h => h.EnvelopeId == request.EnvelopeId);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
else
|
||||||
|
throw new BadRequestException("Invalid request: An Envelope object or a valid EnvelopeId/UUID must be supplied.");
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
if (request.Status is not null)
|
||||||
|
query = query.Where(h => h.Status == request.Status);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
|
if (request.Statuses is not null)
|
||||||
|
{
|
||||||
|
var status = request.Statuses;
|
||||||
|
if (status.Min is not null)
|
||||||
|
query = query.Where(er => er.Envelope!.Status >= status.Min);
|
||||||
|
|
||||||
|
if (status.Max is not null)
|
||||||
|
query = query.Where(er => er.Envelope!.Status <= status.Max);
|
||||||
|
|
||||||
|
if (status.Include?.Count() > 0)
|
||||||
|
query = query.Where(er => status.Include.Contains(er.Envelope!.Status));
|
||||||
|
|
||||||
|
if (status.Ignore is not null)
|
||||||
|
query = query.Where(er => !status.Ignore.Contains(er.Envelope!.Status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return query.CountAsync(cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using EnvelopeGenerator.Application.Common.Query;
|
||||||
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.Histories.Queries;
|
||||||
|
|
||||||
|
//TODO: Add sender query
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public record HistoryQueryBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Die eindeutige Kennung des Umschlags.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("Use Envelope property")]
|
||||||
|
public int? EnvelopeId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.
|
||||||
|
/// </summary>
|
||||||
|
[Obsolete("Use statuses")]
|
||||||
|
public EnvelopeStatus? Status { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public EnvelopeStatusQuery Statuses { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public EnvelopeQueryBase Envelope { get; set; } = new EnvelopeQueryBase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public record EnvelopeStatusQuery
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Der minimale Statuswert, der berücksichtigt werden.
|
||||||
|
/// </summary>
|
||||||
|
public EnvelopeStatus? Min { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Der maximale Statuswert, der berücksichtigt werden.
|
||||||
|
/// </summary>
|
||||||
|
public EnvelopeStatus? Max { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eine Liste von Statuswerten, die einbezogen werden.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<EnvelopeStatus>? Include { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Eine Liste von Statuswerten, die ignoriert werden werden.
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<EnvelopeStatus>? Ignore { get; init; }
|
||||||
|
}
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
using EnvelopeGenerator.Application.Common.Dto.History;
|
using AutoMapper;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using DigitalData.Core.Exceptions;
|
||||||
|
using EnvelopeGenerator.Application.Common.Dto.History;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Histories.Queries;
|
namespace EnvelopeGenerator.Application.Histories.Queries;
|
||||||
|
|
||||||
@@ -9,21 +12,81 @@ namespace EnvelopeGenerator.Application.Histories.Queries;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Repräsentiert eine Abfrage für die Verlaufshistorie eines Umschlags.
|
/// Repräsentiert eine Abfrage für die Verlaufshistorie eines Umschlags.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public record ReadHistoryQuery : IRequest<IEnumerable<HistoryDto>>
|
public record ReadHistoryQuery : HistoryQueryBase, IRequest<IEnumerable<HistoryDto>>
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Die eindeutige Kennung des Umschlags.
|
|
||||||
/// </summary>
|
|
||||||
[Required]
|
|
||||||
public int EnvelopeId { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Der Include des Umschlags, der abgefragt werden soll. Kann optional angegeben werden, um die Ergebnisse zu filtern.
|
|
||||||
/// </summary>
|
|
||||||
public EnvelopeStatus? Status { get; init; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.
|
/// Abfrage zur Steuerung, ob nur der aktuelle Include oder der gesamte Datensatz zurückgegeben wird.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? OnlyLast { get; init; } = true;
|
public bool OnlyLast { get; init; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumerable<HistoryDto>>
|
||||||
|
{
|
||||||
|
private readonly IRepository<History> _repo;
|
||||||
|
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="repo"></param>
|
||||||
|
/// <param name="mapper"></param>
|
||||||
|
public ReadHistoryQueryHandler(IRepository<History> repo, IMapper mapper)
|
||||||
|
{
|
||||||
|
_repo = repo;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request"></param>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotFoundException"></exception>
|
||||||
|
public async Task<IEnumerable<HistoryDto>> Handle(ReadHistoryQuery request, CancellationToken cancel = default)
|
||||||
|
{
|
||||||
|
var query = _repo.Query;
|
||||||
|
|
||||||
|
if (request.Envelope.Id is int envId)
|
||||||
|
query = query.Where(e => e.Id == envId);
|
||||||
|
else if (request.Envelope.Uuid is string uuid)
|
||||||
|
query = query.Where(e => e.Envelope!.Uuid == uuid);
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
else if (request.EnvelopeId is not null)
|
||||||
|
query = query.Where(h => h.EnvelopeId == request.EnvelopeId);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
else
|
||||||
|
throw new BadRequestException("Invalid request: An Envelope object or a valid EnvelopeId/UUID must be supplied.");
|
||||||
|
|
||||||
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
if (request.Status is not null)
|
||||||
|
query = query.Where(h => h.Status == request.Status);
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
|
if (request.Statuses is not null)
|
||||||
|
{
|
||||||
|
var status = request.Statuses;
|
||||||
|
if (status.Min is not null)
|
||||||
|
query = query.Where(er => er.Envelope!.Status >= status.Min);
|
||||||
|
|
||||||
|
if (status.Max is not null)
|
||||||
|
query = query.Where(er => er.Envelope!.Status <= status.Max);
|
||||||
|
|
||||||
|
if (status.Include?.Count() > 0)
|
||||||
|
query = query.Where(er => status.Include.Contains(er.Envelope!.Status));
|
||||||
|
|
||||||
|
if (status.Ignore is not null)
|
||||||
|
query = query.Where(er => !status.Ignore.Contains(er.Envelope!.Status));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.OnlyLast)
|
||||||
|
query = query.OrderByDescending(x => x.AddedWhen);
|
||||||
|
|
||||||
|
var hists = await query.ToListAsync(cancel);
|
||||||
|
return _mapper.Map<List<HistoryDto>>(hists);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using DigitalData.Core.Abstraction.Application.Repository;
|
|
||||||
using DigitalData.Core.Exceptions;
|
|
||||||
using EnvelopeGenerator.Application.Common.Dto.History;
|
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
|
||||||
using MediatR;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Histories.Queries;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public class ReadHistoryQueryHandler : IRequestHandler<ReadHistoryQuery, IEnumerable<HistoryDto>>
|
|
||||||
{
|
|
||||||
private readonly IRepository<History> _repo;
|
|
||||||
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="repo"></param>
|
|
||||||
/// <param name="mapper"></param>
|
|
||||||
public ReadHistoryQueryHandler(IRepository<History> repo, IMapper mapper)
|
|
||||||
{
|
|
||||||
_repo = repo;
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request"></param>
|
|
||||||
/// <param name="cancel"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="NotFoundException"></exception>
|
|
||||||
public async Task<IEnumerable<HistoryDto>> Handle(ReadHistoryQuery request, CancellationToken cancel = default)
|
|
||||||
{
|
|
||||||
var query = _repo.ReadOnly().Where(h => h.EnvelopeId == request.EnvelopeId);
|
|
||||||
if (request.Status is not null)
|
|
||||||
query = query.Where(h => h.Status == request.Status);
|
|
||||||
|
|
||||||
var hists = await query.ToListAsync(cancel);
|
|
||||||
return _mapper.Map<List<HistoryDto>>(hists);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -70,11 +70,11 @@
|
|||||||
<Reference Include="DigitalData.Controls.DocumentViewer, Version=1.9.8.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Controls.DocumentViewer, Version=1.9.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Controls.DocumentViewer.1.9.8\lib\net462\DigitalData.Controls.DocumentViewer.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Controls.DocumentViewer.1.9.8\lib\net462\DigitalData.Controls.DocumentViewer.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.3.5.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.3.5\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="DigitalData.Core.Abstractions, Version=4.1.1.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Core.Abstractions.4.1.1\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Modules.Base.1.3.8\lib\net462\DigitalData.Modules.Base.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Modules.Base.1.3.8\lib\net462\DigitalData.Modules.Base.dll</HintPath>
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ Imports EnvelopeGenerator.CommonServices.Jobs
|
|||||||
Imports EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument
|
Imports EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument
|
||||||
Imports GdPicture14
|
Imports GdPicture14
|
||||||
Imports Newtonsoft.Json.Linq
|
Imports Newtonsoft.Json.Linq
|
||||||
Imports DigitalData.Core.Abstraction.Application
|
|
||||||
Imports EnvelopeGenerator.Infrastructure
|
Imports EnvelopeGenerator.Infrastructure
|
||||||
Imports Microsoft.EntityFrameworkCore
|
Imports Microsoft.EntityFrameworkCore
|
||||||
|
Imports System.Text
|
||||||
|
Imports DigitalData.Core.Abstractions
|
||||||
|
|
||||||
Public Class frmFinalizePDF
|
Public Class frmFinalizePDF
|
||||||
Private Const CONNECTIONSTRING = "Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=+bk8oAbbQP1AzoHtvZUbd+Mbok2f8Fl4miEx1qssJ5yEaEWoQJ9prg4L14fURpPnqi1WMNs9fE4=;"
|
Private Const CONNECTIONSTRING = "Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=+bk8oAbbQP1AzoHtvZUbd+Mbok2f8Fl4miEx1qssJ5yEaEWoQJ9prg4L14fURpPnqi1WMNs9fE4=;"
|
||||||
@@ -23,10 +24,15 @@ Public Class frmFinalizePDF
|
|||||||
|
|
||||||
Private Sub frmFinalizePDF_Load(sender As Object, e As EventArgs) Handles MyBase.Load
|
Private Sub frmFinalizePDF_Load(sender As Object, e As EventArgs) Handles MyBase.Load
|
||||||
LogConfig = New LogConfig(LogConfig.PathType.CustomPath, Application.StartupPath)
|
LogConfig = New LogConfig(LogConfig.PathType.CustomPath, Application.StartupPath)
|
||||||
Database = New MSSQLServer(LogConfig, MSSQLServer.DecryptConnectionString(CONNECTIONSTRING))
|
|
||||||
|
Dim dCnnStr As String = MSSQLServer.DecryptConnectionString(CONNECTIONSTRING)
|
||||||
|
|
||||||
|
Database = New MSSQLServer(LogConfig, dCnnStr)
|
||||||
|
|
||||||
#Disable Warning BC40000 ' Type or member is obsolete
|
#Disable Warning BC40000 ' Type or member is obsolete
|
||||||
Factory.Shared.AddEnvelopeGeneratorInfrastructureServices(
|
Factory.Shared _
|
||||||
|
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _
|
||||||
|
.AddEnvelopeGeneratorInfrastructureServices(
|
||||||
Sub(opt)
|
Sub(opt)
|
||||||
opt.AddDbTriggerParams(
|
opt.AddDbTriggerParams(
|
||||||
Sub(triggers)
|
Sub(triggers)
|
||||||
@@ -39,7 +45,7 @@ Public Class frmFinalizePDF
|
|||||||
End Sub)
|
End Sub)
|
||||||
opt.AddDbContext(
|
opt.AddDbContext(
|
||||||
Sub(options)
|
Sub(options)
|
||||||
options.UseSqlServer(CONNECTIONSTRING) _
|
options.UseSqlServer(dCnnStr) _
|
||||||
.EnableSensitiveDataLogging() _
|
.EnableSensitiveDataLogging() _
|
||||||
.EnableDetailedErrors()
|
.EnableDetailedErrors()
|
||||||
End Sub)
|
End Sub)
|
||||||
@@ -95,8 +101,9 @@ Public Class frmFinalizePDF
|
|||||||
Select(Function(r As DataRow) r.Item("VALUE").ToString()).
|
Select(Function(r As DataRow) r.Item("VALUE").ToString()).
|
||||||
ToList()
|
ToList()
|
||||||
|
|
||||||
Dim oBuffer As Byte() = ReadEnvelope(CInt(txtEnvelope.Text))
|
Dim envelopeId As Integer = CInt(txtEnvelope.Text)
|
||||||
Dim oNewBuffer = PDFBurner.BurnInstantJSONAnnotationsToPDF(oBuffer, oJsonList)
|
Dim oBuffer As Byte() = ReadEnvelope(envelopeId)
|
||||||
|
Dim oNewBuffer = PDFBurner.BurnAnnotsToPDF(oBuffer, oJsonList, envelopeId)
|
||||||
Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
|
Dim desktopPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
|
||||||
Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}R{txtReceiver.Text}.burned.pdf")
|
Dim oNewPath = Path.Combine(desktopPath, $"E{txtEnvelope.Text}R{txtReceiver.Text}.burned.pdf")
|
||||||
|
|
||||||
@@ -104,7 +111,15 @@ Public Class frmFinalizePDF
|
|||||||
|
|
||||||
Process.Start(oNewPath)
|
Process.Start(oNewPath)
|
||||||
Catch ex As Exception
|
Catch ex As Exception
|
||||||
MsgBox(ex.Message, MsgBoxStyle.Critical)
|
Dim exMsg As StringBuilder = New StringBuilder(ex.Message).AppendLine()
|
||||||
|
|
||||||
|
Dim innerEx = ex.InnerException
|
||||||
|
While (innerEx IsNot Nothing)
|
||||||
|
exMsg.AppendLine(innerEx.Message)
|
||||||
|
innerEx = innerEx.InnerException
|
||||||
|
End While
|
||||||
|
|
||||||
|
MsgBox(exMsg.ToString(), MsgBoxStyle.Critical)
|
||||||
End Try
|
End Try
|
||||||
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
||||||
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Controls.DocumentViewer" version="1.9.8" targetFramework="net462" />
|
<package id="DigitalData.Controls.DocumentViewer" version="1.9.8" targetFramework="net462" />
|
||||||
<package id="DigitalData.Core.Abstraction.Application" version="1.3.5" targetFramework="net462" />
|
<package id="DigitalData.Core.Abstraction.Application" version="1.4.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Core.Abstractions" version="4.1.1" targetFramework="net462" />
|
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Database" version="2.3.5.4" targetFramework="net462" />
|
<package id="DigitalData.Modules.Database" version="2.3.5.4" targetFramework="net462" />
|
||||||
|
|||||||
@@ -72,11 +72,12 @@
|
|||||||
<Reference Include="DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
<Reference Include="DevExpress.XtraEditors.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" />
|
||||||
<Reference Include="DevExpress.XtraGauges.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
<Reference Include="DevExpress.XtraGauges.v21.2.Core, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||||
<Reference Include="DevExpress.XtraReports.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
<Reference Include="DevExpress.XtraReports.v21.2, Version=21.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
|
||||||
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.3.5.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Core.Abstraction.Application, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.3.5\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="DigitalData.Core.Abstractions, Version=4.1.1.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Core.Abstractions.4.1.1\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\DigitalData.Modules.Base.1.3.8\lib\net462\DigitalData.Modules.Base.dll</HintPath>
|
<HintPath>..\packages\DigitalData.Modules.Base.1.3.8\lib\net462\DigitalData.Modules.Base.dll</HintPath>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Imports EnvelopeGenerator.Domain.Entities
|
|||||||
Imports DigitalData.Core.Abstraction.Application
|
Imports DigitalData.Core.Abstraction.Application
|
||||||
Imports EnvelopeGenerator.Infrastructure
|
Imports EnvelopeGenerator.Infrastructure
|
||||||
Imports Microsoft.EntityFrameworkCore
|
Imports Microsoft.EntityFrameworkCore
|
||||||
|
Imports DigitalData.Core.Abstractions
|
||||||
|
|
||||||
Namespace Jobs
|
Namespace Jobs
|
||||||
Public Class FinalizeDocumentJob
|
Public Class FinalizeDocumentJob
|
||||||
@@ -69,7 +70,9 @@ Namespace Jobs
|
|||||||
Database = New MSSQLServer(LogConfig, MSSQLServer.DecryptConnectionString(oConnectionString))
|
Database = New MSSQLServer(LogConfig, MSSQLServer.DecryptConnectionString(oConnectionString))
|
||||||
|
|
||||||
#Disable Warning BC40000 ' Type or member is obsolete
|
#Disable Warning BC40000 ' Type or member is obsolete
|
||||||
Factory.Shared.AddEnvelopeGeneratorInfrastructureServices(
|
Factory.Shared _
|
||||||
|
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _
|
||||||
|
.AddEnvelopeGeneratorInfrastructureServices(
|
||||||
Sub(opt)
|
Sub(opt)
|
||||||
opt.AddDbTriggerParams(
|
opt.AddDbTriggerParams(
|
||||||
Sub(triggers)
|
Sub(triggers)
|
||||||
@@ -403,7 +406,6 @@ Namespace Jobs
|
|||||||
ParentFolderUID = pEnvelopeData.EnvelopeUUID
|
ParentFolderUID = pEnvelopeData.EnvelopeUUID
|
||||||
End If
|
End If
|
||||||
|
|
||||||
|
|
||||||
Logger.Info("ParentFolderUID: [{0}]", ParentFolderUID)
|
Logger.Info("ParentFolderUID: [{0}]", ParentFolderUID)
|
||||||
Dim oInputDocumentBuffer As Byte()
|
Dim oInputDocumentBuffer As Byte()
|
||||||
If Not IsNothing(pEnvelopeData.DocAsByte) Then
|
If Not IsNothing(pEnvelopeData.DocAsByte) Then
|
||||||
@@ -416,7 +418,7 @@ Namespace Jobs
|
|||||||
End Try
|
End Try
|
||||||
End If
|
End If
|
||||||
|
|
||||||
Return PDFBurner.BurnInstantJSONAnnotationsToPDF(oInputDocumentBuffer, oAnnotations)
|
Return PDFBurner.BurnAnnotsToPDF(oInputDocumentBuffer, oAnnotations, pEnvelopeData.EnvelopeId)
|
||||||
End Function
|
End Function
|
||||||
|
|
||||||
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData
|
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
Imports System.Drawing
|
Imports System.Collections.Immutable
|
||||||
|
Imports System.Drawing
|
||||||
Imports System.IO
|
Imports System.IO
|
||||||
|
Imports DevExpress.DataProcessing
|
||||||
|
Imports DigitalData.Core.Abstraction.Application.Repository
|
||||||
|
Imports DigitalData.Core.Abstractions
|
||||||
Imports DigitalData.Modules.Base
|
Imports DigitalData.Modules.Base
|
||||||
Imports DigitalData.Modules.Logging
|
Imports DigitalData.Modules.Logging
|
||||||
Imports GdPicture14
|
|
||||||
Imports Newtonsoft.Json
|
|
||||||
Imports EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
Imports EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument.FinalizeDocumentExceptions
|
||||||
Imports DevExpress.DataProcessing
|
Imports EnvelopeGenerator.Domain.Entities
|
||||||
|
Imports EnvelopeGenerator.PdfEditor
|
||||||
|
Imports GdPicture14
|
||||||
|
Imports Microsoft.EntityFrameworkCore
|
||||||
|
Imports Newtonsoft.Json
|
||||||
|
|
||||||
Namespace Jobs.FinalizeDocument
|
Namespace Jobs.FinalizeDocument
|
||||||
Public Class PDFBurner
|
Public Class PDFBurner
|
||||||
@@ -14,9 +20,6 @@ Namespace Jobs.FinalizeDocument
|
|||||||
Private ReadOnly Manager As AnnotationManager
|
Private ReadOnly Manager As AnnotationManager
|
||||||
Private ReadOnly LicenseManager As LicenseManager
|
Private ReadOnly LicenseManager As LicenseManager
|
||||||
|
|
||||||
Private Const ANNOTATION_TYPE_IMAGE = "pspdfkit/image"
|
|
||||||
Private Const ANNOTATION_TYPE_INK = "pspdfkit/ink"
|
|
||||||
Private Const ANNOTATION_TYPE_WIDGET = "pspdfkit/widget"
|
|
||||||
Private Property _pdfBurnerParams As PDFBurnerParams
|
Private Property _pdfBurnerParams As PDFBurnerParams
|
||||||
|
|
||||||
Public Sub New(pLogConfig As LogConfig, pGDPictureLicenseKey As String, pdfBurnerParams As PDFBurnerParams)
|
Public Sub New(pLogConfig As LogConfig, pGDPictureLicenseKey As String, pdfBurnerParams As PDFBurnerParams)
|
||||||
@@ -30,7 +33,94 @@ Namespace Jobs.FinalizeDocument
|
|||||||
_pdfBurnerParams = pdfBurnerParams
|
_pdfBurnerParams = pdfBurnerParams
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Function BurnInstantJSONAnnotationsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String)) As Byte()
|
#Region "Burn PDF"
|
||||||
|
Public Function BurnAnnotsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String), envelopeId As Integer) As Byte()
|
||||||
|
'read the elements of envelope with their annotations
|
||||||
|
Using scope = Factory.Shared.ScopeFactory.CreateScope()
|
||||||
|
Dim sigRepo = scope.ServiceProvider.Repository(Of Signature)()
|
||||||
|
Dim elements = sigRepo _
|
||||||
|
.Where(Function(sig) sig.Document.EnvelopeId = envelopeId) _
|
||||||
|
.Include(Function(sig) sig.Annotations) _
|
||||||
|
.ToList()
|
||||||
|
|
||||||
|
Return If(elements.Any(),
|
||||||
|
BurnElementAnnotsToPDF(pSourceBuffer, elements),
|
||||||
|
BurnInstantJSONAnnotsToPDF(pSourceBuffer, pInstantJSONList))
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Public Function BurnElementAnnotsToPDF(pSourceBuffer As Byte(), elements As List(Of Signature)) As Byte()
|
||||||
|
' Add background
|
||||||
|
Using doc As Pdf(Of MemoryStream, MemoryStream) = Pdf.FromMemory(pSourceBuffer)
|
||||||
|
'TODO: take the length from the largest y
|
||||||
|
pSourceBuffer = doc.Background(elements, 1.9500000000000002 * 0.93, 2.52 * 0.67).ExportStream().ToArray()
|
||||||
|
|
||||||
|
Dim oResult As GdPictureStatus
|
||||||
|
Using oSourceStream As New MemoryStream(pSourceBuffer)
|
||||||
|
' Open PDF
|
||||||
|
oResult = Manager.InitFromStream(oSourceStream)
|
||||||
|
If oResult <> GdPictureStatus.OK Then
|
||||||
|
Throw New BurnAnnotationException($"Could not open document for burning: [{oResult}]")
|
||||||
|
End If
|
||||||
|
|
||||||
|
' Imported from background (add to configuration)
|
||||||
|
Dim margin As Double = 0.2
|
||||||
|
Dim inchFactor As Double = 72
|
||||||
|
|
||||||
|
' Y offset of form fields
|
||||||
|
Dim keys = {"position", "city", "date"} ' add to configuration
|
||||||
|
Dim unitYOffsets = 0.2
|
||||||
|
Dim yOffsetsOfFF = keys.
|
||||||
|
Select(Function(k, i) New With {Key .Key = k, Key .Value = unitYOffsets * i + 1}).
|
||||||
|
ToDictionary(Function(x) x.Key, Function(x) x.Value)
|
||||||
|
|
||||||
|
'Add annotations
|
||||||
|
For Each element In elements
|
||||||
|
|
||||||
|
Dim frameX = (element.Left - 0.7 - margin)
|
||||||
|
|
||||||
|
Dim frame = element.Annotations.FirstOrDefault(Function(a) a.Name = "frame")
|
||||||
|
Dim frameY = element.Top - 0.5 - margin
|
||||||
|
Dim frameYShift = frame.Y - frameY * inchFactor
|
||||||
|
Dim frameXShift = frame.X - frameX * inchFactor
|
||||||
|
|
||||||
|
For Each annot In element.Annotations
|
||||||
|
Dim yOffsetofFF As Double = If(yOffsetsOfFF.TryGetValue(annot.Name, yOffsetofFF), yOffsetofFF, 0)
|
||||||
|
Dim y = frameY + yOffsetofFF
|
||||||
|
|
||||||
|
If annot.Type = AnnotationType.FormField Then
|
||||||
|
AddFormFieldValue(annot.X / inchFactor, y, annot.Width / inchFactor, annot.Height / inchFactor, element.Page, annot.Value)
|
||||||
|
ElseIf annot.Type = AnnotationType.Image Then
|
||||||
|
AddImageAnnotation(
|
||||||
|
annot.X / inchFactor,
|
||||||
|
If(annot.Name = "signature", (annot.Y - frameYShift) / inchFactor, y),
|
||||||
|
annot.Width / inchFactor,
|
||||||
|
annot.Height / inchFactor,
|
||||||
|
element.Page,
|
||||||
|
annot.Value
|
||||||
|
)
|
||||||
|
ElseIf annot.Type = AnnotationType.Ink Then
|
||||||
|
AddInkAnnotation(element.Page, annot.Value)
|
||||||
|
End If
|
||||||
|
Next
|
||||||
|
Next
|
||||||
|
|
||||||
|
'Save PDF
|
||||||
|
Using oNewStream As New MemoryStream()
|
||||||
|
oResult = Manager.SaveDocumentToPDF(oNewStream)
|
||||||
|
If oResult <> GdPictureStatus.OK Then
|
||||||
|
Throw New BurnAnnotationException($"Could not save document to stream: [{oResult}]")
|
||||||
|
End If
|
||||||
|
|
||||||
|
Manager.Close()
|
||||||
|
|
||||||
|
Return oNewStream.ToArray()
|
||||||
|
End Using
|
||||||
|
End Using
|
||||||
|
End Using
|
||||||
|
End Function
|
||||||
|
|
||||||
|
Public Function BurnInstantJSONAnnotsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String)) As Byte()
|
||||||
Dim oResult As GdPictureStatus
|
Dim oResult As GdPictureStatus
|
||||||
Using oSourceStream As New MemoryStream(pSourceBuffer)
|
Using oSourceStream As New MemoryStream(pSourceBuffer)
|
||||||
' Open PDF
|
' Open PDF
|
||||||
@@ -67,47 +157,42 @@ Namespace Jobs.FinalizeDocument
|
|||||||
End Using
|
End Using
|
||||||
End Using
|
End Using
|
||||||
End Function
|
End Function
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "Add Value"
|
||||||
Private Sub AddInstantJSONAnnotationToPDF(pInstantJSON As String)
|
Private Sub AddInstantJSONAnnotationToPDF(pInstantJSON As String)
|
||||||
Dim oAnnotationData = JsonConvert.DeserializeObject(Of AnnotationData)(pInstantJSON)
|
Dim oAnnotationData = JsonConvert.DeserializeObject(Of AnnotationData)(pInstantJSON)
|
||||||
|
|
||||||
oAnnotationData.annotations.Reverse()
|
oAnnotationData.annotations.Reverse()
|
||||||
|
|
||||||
Dim yPosOfSigAnnot = oAnnotationData.annotations.ElementAt(2).bbox.ElementAt(1) - 71.84002685546875 + 7
|
For Each oAnnotation In oAnnotationData.annotations
|
||||||
Dim isSeal = True 'First element is signature seal
|
Logger.Debug("Adding AnnotationID: " + oAnnotation.id)
|
||||||
|
|
||||||
Dim formFieldIndex = 0
|
Select Case oAnnotation.type
|
||||||
For Each oAnnotation In oAnnotationData.annotations
|
Case AnnotationType.Image
|
||||||
Logger.Debug("Adding AnnotationID: " + oAnnotation.id)
|
AddImageAnnotation(oAnnotation, oAnnotationData.attachments)
|
||||||
|
Exit Select
|
||||||
|
Case AnnotationType.Ink
|
||||||
|
AddInkAnnotation(oAnnotation)
|
||||||
|
Exit Select
|
||||||
|
Case AnnotationType.Widget
|
||||||
|
'Add form field values
|
||||||
|
Dim formFieldValue = oAnnotationData.formFieldValues.FirstOrDefault(Function(fv) fv.name = oAnnotation.id)
|
||||||
|
If formFieldValue IsNot Nothing AndAlso Not _pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value) Then
|
||||||
|
AddFormFieldValue(oAnnotation, formFieldValue)
|
||||||
|
End If
|
||||||
|
Exit Select
|
||||||
|
End Select
|
||||||
|
Next
|
||||||
|
|
||||||
Select Case oAnnotation.type
|
|
||||||
Case ANNOTATION_TYPE_IMAGE
|
|
||||||
|
|
||||||
If (isSeal) Then
|
|
||||||
oAnnotation.bbox.Item(1) = yPosOfSigAnnot
|
|
||||||
End If
|
|
||||||
|
|
||||||
AddImageAnnotation(oAnnotation, oAnnotationData.attachments)
|
|
||||||
Exit Select
|
|
||||||
|
|
||||||
Case ANNOTATION_TYPE_INK
|
|
||||||
AddInkAnnotation(oAnnotation)
|
|
||||||
Exit Select
|
|
||||||
|
|
||||||
Case ANNOTATION_TYPE_WIDGET
|
|
||||||
'Add form field values
|
|
||||||
Dim formFieldValue = oAnnotationData.formFieldValues.FirstOrDefault(Function(fv) fv.name = oAnnotation.id)
|
|
||||||
If formFieldValue IsNot Nothing AndAlso Not _pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value) Then
|
|
||||||
AddFormFieldValue(oAnnotation, formFieldValue, formFieldIndex)
|
|
||||||
formFieldIndex += 1
|
|
||||||
End If
|
|
||||||
Exit Select
|
|
||||||
End Select
|
|
||||||
|
|
||||||
isSeal = False
|
|
||||||
Next
|
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Private Function AddImageAnnotation(pAnnotation As Annotation, pAttachments As Dictionary(Of String, Attachment)) As Void
|
Private Sub AddImageAnnotation(x As Double, y As Double, width As Double, height As Double, page As Integer, base64 As String)
|
||||||
|
Manager.SelectPage(page)
|
||||||
|
Manager.AddEmbeddedImageAnnotFromBase64(base64, x, y, width, height)
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private Sub AddImageAnnotation(pAnnotation As Annotation, pAttachments As Dictionary(Of String, Attachment))
|
||||||
Dim oAttachment = pAttachments.Where(Function(a) a.Key = pAnnotation.imageAttachmentId).
|
Dim oAttachment = pAttachments.Where(Function(a) a.Key = pAnnotation.imageAttachmentId).
|
||||||
SingleOrDefault()
|
SingleOrDefault()
|
||||||
|
|
||||||
@@ -121,9 +206,26 @@ Namespace Jobs.FinalizeDocument
|
|||||||
|
|
||||||
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
||||||
Manager.AddEmbeddedImageAnnotFromBase64(oAttachment.Value.binary, oX, oY, oWidth, oHeight)
|
Manager.AddEmbeddedImageAnnotFromBase64(oAttachment.Value.binary, oX, oY, oWidth, oHeight)
|
||||||
End Function
|
End Sub
|
||||||
|
|
||||||
Private Function AddInkAnnotation(pAnnotation As Annotation) As Void
|
Private Sub AddInkAnnotation(page As Integer, value As String)
|
||||||
|
|
||||||
|
Dim ink = JsonConvert.DeserializeObject(Of Ink)(value)
|
||||||
|
|
||||||
|
Dim oSegments = ink.lines.points
|
||||||
|
Dim oColor = ColorTranslator.FromHtml(ink.strokeColor)
|
||||||
|
Manager.SelectPage(page)
|
||||||
|
|
||||||
|
For Each oSegment As List(Of List(Of Single)) In oSegments
|
||||||
|
Dim oPoints = oSegment.
|
||||||
|
Select(AddressOf ToPointF).
|
||||||
|
ToArray()
|
||||||
|
|
||||||
|
Manager.AddFreeHandAnnot(oColor, oPoints)
|
||||||
|
Next
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private Sub AddInkAnnotation(pAnnotation As Annotation)
|
||||||
Dim oSegments = pAnnotation.lines.points
|
Dim oSegments = pAnnotation.lines.points
|
||||||
Dim oColor = ColorTranslator.FromHtml(pAnnotation.strokeColor)
|
Dim oColor = ColorTranslator.FromHtml(pAnnotation.strokeColor)
|
||||||
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
Manager.SelectPage(pAnnotation.pageIndex + 1)
|
||||||
@@ -135,14 +237,29 @@ Namespace Jobs.FinalizeDocument
|
|||||||
|
|
||||||
Manager.AddFreeHandAnnot(oColor, oPoints)
|
Manager.AddFreeHandAnnot(oColor, oPoints)
|
||||||
Next
|
Next
|
||||||
End Function
|
End Sub
|
||||||
|
|
||||||
|
Private Sub AddFormFieldValue(x As Double, y As Double, width As Double, height As Double, page As Integer, value As String)
|
||||||
|
Manager.SelectPage(page)
|
||||||
|
|
||||||
|
' Add the text annotation
|
||||||
|
Dim ant = Manager.AddTextAnnot(x, y, width, height, value)
|
||||||
|
|
||||||
|
' Set the font properties
|
||||||
|
ant.FontName = _pdfBurnerParams.FontName
|
||||||
|
ant.FontSize = _pdfBurnerParams.FontSize
|
||||||
|
ant.FontStyle = _pdfBurnerParams.FontStyle
|
||||||
|
Manager.SaveAnnotationsToPage()
|
||||||
|
End Sub
|
||||||
|
|
||||||
|
Private Sub AddFormFieldValue(pAnnotation As Annotation, formFieldValue As FormFieldValue)
|
||||||
|
Dim ffIndex As Integer = EGName.Index(pAnnotation.egName)
|
||||||
|
|
||||||
Private Function AddFormFieldValue(pAnnotation As Annotation, formFieldValue As FormFieldValue, index As Integer) As Void
|
|
||||||
' Convert pixels to Inches
|
' Convert pixels to Inches
|
||||||
Dim oBounds = pAnnotation.bbox.Select(AddressOf ToInches).ToList()
|
Dim oBounds = pAnnotation.bbox.Select(AddressOf ToInches).ToList()
|
||||||
|
|
||||||
Dim oX = oBounds.Item(0)
|
Dim oX = oBounds.Item(0)
|
||||||
Dim oY = oBounds.Item(1) + _pdfBurnerParams.YOffset * index + _pdfBurnerParams.TopMargin
|
Dim oY = oBounds.Item(1) + _pdfBurnerParams.YOffset * ffIndex + _pdfBurnerParams.TopMargin
|
||||||
Dim oWidth = oBounds.Item(2)
|
Dim oWidth = oBounds.Item(2)
|
||||||
Dim oHeight = oBounds.Item(3)
|
Dim oHeight = oBounds.Item(3)
|
||||||
|
|
||||||
@@ -155,8 +272,10 @@ Namespace Jobs.FinalizeDocument
|
|||||||
ant.FontSize = _pdfBurnerParams.FontSize
|
ant.FontSize = _pdfBurnerParams.FontSize
|
||||||
ant.FontStyle = _pdfBurnerParams.FontStyle
|
ant.FontStyle = _pdfBurnerParams.FontStyle
|
||||||
Manager.SaveAnnotationsToPage()
|
Manager.SaveAnnotationsToPage()
|
||||||
End Function
|
End Sub
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "Helpers"
|
||||||
Private Function ToPointF(pPoints As List(Of Single)) As PointF
|
Private Function ToPointF(pPoints As List(Of Single)) As PointF
|
||||||
Dim oPoints = pPoints.Select(AddressOf ToInches).ToList()
|
Dim oPoints = pPoints.Select(AddressOf ToInches).ToList()
|
||||||
Return New PointF(oPoints.Item(0), oPoints.Item(1))
|
Return New PointF(oPoints.Item(0), oPoints.Item(1))
|
||||||
@@ -169,22 +288,34 @@ Namespace Jobs.FinalizeDocument
|
|||||||
Private Function ToInches(pValue As Single) As Single
|
Private Function ToInches(pValue As Single) As Single
|
||||||
Return pValue / 72
|
Return pValue / 72
|
||||||
End Function
|
End Function
|
||||||
|
#End Region
|
||||||
|
|
||||||
|
#Region "Model"
|
||||||
|
Friend Class AnnotationType
|
||||||
|
Public Const Image As String = "pspdfkit/image"
|
||||||
|
Public Const Ink As String = "pspdfkit/ink"
|
||||||
|
Public Const Widget As String = "pspdfkit/widget"
|
||||||
|
Public Const FormField As String = "pspdfkit/form-field-value"
|
||||||
|
End Class
|
||||||
|
|
||||||
Friend Class AnnotationData
|
Friend Class AnnotationData
|
||||||
Public Property annotations As List(Of Annotation)
|
Public Property annotations As List(Of Annotation)
|
||||||
|
|
||||||
Public ReadOnly Property SignatureAnnotations As List(Of List(Of Annotation))
|
Public ReadOnly Property AnnotationsByReceiver As IEnumerable(Of List(Of Annotation))
|
||||||
Get
|
Get
|
||||||
Dim result As New List(Of List(Of Annotation))()
|
Return annotations _
|
||||||
|
.Where(Function(annot) annot.hasStructuredID).ToList() _
|
||||||
|
.GroupBy(Function(a) a.receiverId) _
|
||||||
|
.Select(Function(g) g.ToList())
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
If annotations IsNot Nothing AndAlso annotations.Count > 0 Then
|
Public ReadOnly Property UnstructuredAnnotations As IEnumerable(Of List(Of Annotation))
|
||||||
For i As Integer = 0 To annotations.Count - 1 Step 6
|
Get
|
||||||
Dim group As List(Of Annotation) = annotations.Skip(i).Take(6).ToList()
|
Return annotations _
|
||||||
result.Add(group)
|
.Where(Function(annot) Not annot.hasStructuredID).ToList() _
|
||||||
Next
|
.GroupBy(Function(a) a.receiverId) _
|
||||||
End If
|
.Select(Function(g) g.ToList())
|
||||||
|
|
||||||
Return result
|
|
||||||
End Get
|
End Get
|
||||||
End Property
|
End Property
|
||||||
|
|
||||||
@@ -193,16 +324,102 @@ Namespace Jobs.FinalizeDocument
|
|||||||
End Class
|
End Class
|
||||||
|
|
||||||
Friend Class Annotation
|
Friend Class Annotation
|
||||||
|
|
||||||
|
Private _id As String = Nothing
|
||||||
|
|
||||||
|
Public envelopeId As Integer = Nothing
|
||||||
|
|
||||||
|
Public receiverId As Integer = Nothing
|
||||||
|
|
||||||
|
Public index As Integer = Nothing
|
||||||
|
|
||||||
|
Public egName As String = PDFBurner.EGName.NoName
|
||||||
|
|
||||||
|
Public hasStructuredID As Boolean = False
|
||||||
|
|
||||||
|
Public ReadOnly Property isLabel As Boolean
|
||||||
|
Get
|
||||||
|
If String.IsNullOrEmpty(egName) Then
|
||||||
|
Return False
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim parts As String() = egName.Split("_"c)
|
||||||
|
Return parts.Length > 1 AndAlso parts(1) = "label"
|
||||||
|
End Get
|
||||||
|
End Property
|
||||||
|
|
||||||
Public Property id As String
|
Public Property id As String
|
||||||
|
Get
|
||||||
|
Return _id
|
||||||
|
End Get
|
||||||
|
Set(value As String)
|
||||||
|
_id = value
|
||||||
|
|
||||||
|
If String.IsNullOrWhiteSpace(_id) Then
|
||||||
|
Throw New BurnAnnotationException("The identifier of annotation is null or empty.")
|
||||||
|
End If
|
||||||
|
|
||||||
|
Dim parts As String() = value.Split("#"c)
|
||||||
|
|
||||||
|
If (parts.Length <> 4) Then
|
||||||
|
Return
|
||||||
|
'Throw New BurnAnnotationException($"The identifier of annotation has more or less than 4 sub-part. Id: {_id}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not Integer.TryParse(parts(0), envelopeId) Then
|
||||||
|
Throw New BurnAnnotationException($"The envelope ID of annotation is not integer. Id: {_id}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not Integer.TryParse(parts(1), receiverId) Then
|
||||||
|
Throw New BurnAnnotationException($"The receiver ID of annotation is not integer. Id: {_id}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
If Not Integer.TryParse(parts(2), index) Then
|
||||||
|
Throw New BurnAnnotationException($"The index of annotation is not integer. Id: {_id}")
|
||||||
|
End If
|
||||||
|
|
||||||
|
egName = parts(3)
|
||||||
|
|
||||||
|
hasStructuredID = True
|
||||||
|
End Set
|
||||||
|
End Property
|
||||||
|
|
||||||
Public Property bbox As List(Of Double)
|
Public Property bbox As List(Of Double)
|
||||||
|
|
||||||
Public Property type As String
|
Public Property type As String
|
||||||
|
|
||||||
Public Property isSignature As Boolean
|
Public Property isSignature As Boolean
|
||||||
|
|
||||||
Public Property imageAttachmentId As String
|
Public Property imageAttachmentId As String
|
||||||
|
|
||||||
Public Property lines As Lines
|
Public Property lines As Lines
|
||||||
|
|
||||||
Public Property pageIndex As Integer
|
Public Property pageIndex As Integer
|
||||||
|
|
||||||
Public Property strokeColor As String
|
Public Property strokeColor As String
|
||||||
End Class
|
End Class
|
||||||
|
|
||||||
|
Friend Class Ink
|
||||||
|
Public Property lines As Lines
|
||||||
|
|
||||||
|
Public Property strokeColor As String
|
||||||
|
End Class
|
||||||
|
|
||||||
|
Public Class EGName
|
||||||
|
Public Shared ReadOnly NoName As String = Guid.NewGuid().ToString()
|
||||||
|
|
||||||
|
Public Shared ReadOnly Seal As String = "signature"
|
||||||
|
|
||||||
|
Public Shared ReadOnly Index As ImmutableDictionary(Of String, Integer) =
|
||||||
|
New Dictionary(Of String, Integer) From {
|
||||||
|
{NoName, 0},
|
||||||
|
{Seal, 0},
|
||||||
|
{"position", 1},
|
||||||
|
{"city", 2},
|
||||||
|
{"date", 3}
|
||||||
|
}.ToImmutableDictionary()
|
||||||
|
End Class
|
||||||
|
|
||||||
Friend Class Lines
|
Friend Class Lines
|
||||||
Public Property points As List(Of List(Of List(Of Single)))
|
Public Property points As List(Of List(Of List(Of Single)))
|
||||||
End Class
|
End Class
|
||||||
@@ -216,5 +433,6 @@ Namespace Jobs.FinalizeDocument
|
|||||||
Public Property name As String
|
Public Property name As String
|
||||||
Public Property value As String
|
Public Property value As String
|
||||||
End Class
|
End Class
|
||||||
|
#End Region
|
||||||
End Class
|
End Class
|
||||||
End Namespace
|
End Namespace
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
<packages>
|
<packages>
|
||||||
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
<package id="AutoMapper" version="10.1.1" targetFramework="net462" />
|
||||||
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Core.Abstraction.Application" version="1.3.5" targetFramework="net462" />
|
<package id="DigitalData.Core.Abstraction.Application" version="1.4.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Core.Abstractions" version="4.1.1" targetFramework="net462" />
|
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
<package id="DigitalData.Modules.Base" version="1.3.8" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
<package id="DigitalData.Modules.Config" version="1.3.0" targetFramework="net462" />
|
||||||
<package id="DigitalData.Modules.Database" version="2.3.5.4" targetFramework="net462" />
|
<package id="DigitalData.Modules.Database" version="2.3.5.4" targetFramework="net462" />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using EnvelopeGenerator.Domain.Interfaces;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
@@ -14,7 +15,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
[Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")]
|
[Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")]
|
||||||
public class Document
|
public class Document : IHasEnvelope
|
||||||
{
|
{
|
||||||
public Document()
|
public Document()
|
||||||
{
|
{
|
||||||
@@ -30,27 +31,50 @@ public class Document
|
|||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Column("ENVELOPE_ID")]
|
[Column("ENVELOPE_ID")]
|
||||||
public int EnvelopeId { get; set; } = 0;
|
public int EnvelopeId { get; set; }
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
= 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
[Column("BYTE_DATA", TypeName = "varbinary(max)")]
|
[Column("BYTE_DATA", TypeName = "varbinary(max)")]
|
||||||
public byte[] ByteData { get; set; }
|
public byte[]
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
ByteData { get; set; }
|
||||||
|
|
||||||
public List<Signature> Elements { get; set; }
|
#region File
|
||||||
|
[Column("FILENAME", TypeName = "nvarchar(256)")]
|
||||||
|
public string Filename { get; set; }
|
||||||
|
|
||||||
// TODO: * Check the Form App and remove the default value
|
[Column("FILEPATH", TypeName = "nvarchar(256)")]
|
||||||
[NotMapped]
|
|
||||||
public string Filepath { get; set; }
|
public string Filepath { get; set; }
|
||||||
|
|
||||||
|
[Column("FILENAME_ORIGINAL", TypeName = "nvarchar(256)")]
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
FileNameOriginal { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public virtual List<Signature>
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Elements { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("EnvelopeId")]
|
||||||
|
public virtual Envelope
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Envelope { get; set; }
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
[NotMapped]
|
|
||||||
public string FileNameOriginal { get; set; }
|
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsTempFile { get; set; }
|
public bool IsTempFile { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
|
||||||
public string Filename { get; set; }
|
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public Bitmap Thumbnail { get; set; }
|
public Bitmap Thumbnail { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using DigitalData.Core.Abstractions.Interfaces;
|
||||||
using EnvelopeGenerator.Domain.Interfaces;
|
using EnvelopeGenerator.Domain.Interfaces;
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
@@ -14,7 +15,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
[Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")]
|
[Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")]
|
||||||
public class DocumentStatus : IHasEnvelope, IHasReceiver
|
public class DocumentStatus : IHasEnvelope, IHasReceiver, IEntity
|
||||||
{
|
{
|
||||||
public DocumentStatus()
|
public DocumentStatus()
|
||||||
{
|
{
|
||||||
|
|||||||
92
EnvelopeGenerator.Domain/Entities/ElementAnnotation.cs
Normal file
92
EnvelopeGenerator.Domain/Entities/ElementAnnotation.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
using System;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Domain.Entities
|
||||||
|
#if NET
|
||||||
|
;
|
||||||
|
#elif NETFRAMEWORK
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT_ANNOTATION")]
|
||||||
|
public class ElementAnnotation
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
[Column("GUID", TypeName = "bigint")]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("ELEMENT_ID", TypeName = "int")]
|
||||||
|
public int ElementId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("NAME", TypeName = "nvarchar(100)")]
|
||||||
|
[StringLength(100)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("VALUE", TypeName = "nvarchar(max)")]
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("TYPE", TypeName = "nvarchar(50)")]
|
||||||
|
public string Type { get; set; }
|
||||||
|
|
||||||
|
[Column("POSITION_X", TypeName = "float")]
|
||||||
|
public double
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
X { get; set; }
|
||||||
|
|
||||||
|
[Column("POSITION_Y", TypeName = "float")]
|
||||||
|
public double
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Y { get; set; }
|
||||||
|
|
||||||
|
[Column("WIDTH", TypeName = "float")]
|
||||||
|
public double
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Width { get; set; }
|
||||||
|
|
||||||
|
[Column("HEIGHT", TypeName = "float")]
|
||||||
|
public double
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Height { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime AddedWhen { get; set; }
|
||||||
|
|
||||||
|
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime? ChangedWhen { get; set; }
|
||||||
|
|
||||||
|
[Column("CHANGED_WHO", TypeName = "nvarchar(100)")]
|
||||||
|
[StringLength(100)]
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
ChangedWho { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("ElementId")]
|
||||||
|
public virtual Signature
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Element { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#if NETFRAMEWORK
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -3,6 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using EnvelopeGenerator.Domain.Interfaces;
|
using EnvelopeGenerator.Domain.Interfaces;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
|
using DigitalData.Core.Abstractions.Interfaces;
|
||||||
|
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
@@ -17,7 +18,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
[Table("TBSIG_ENVELOPE_HISTORY", Schema = "dbo")]
|
[Table("TBSIG_ENVELOPE_HISTORY", Schema = "dbo")]
|
||||||
public class History : IHasEnvelope, IHasReceiver
|
public class History : IHasEnvelope, IHasReceiver, IEntity
|
||||||
{
|
{
|
||||||
[Key]
|
[Key]
|
||||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Domain.Entities
|
namespace EnvelopeGenerator.Domain.Entities
|
||||||
@@ -14,7 +15,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
[Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT", Schema = "dbo")]
|
[Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT", Schema = "dbo")]
|
||||||
public class Signature : ISignature
|
public class Signature : ISignature, IHasReceiver
|
||||||
{
|
{
|
||||||
public Signature()
|
public Signature()
|
||||||
{
|
{
|
||||||
@@ -107,7 +108,17 @@ public class Signature : ISignature
|
|||||||
public virtual Document Document { get; set; }
|
public virtual Document Document { get; set; }
|
||||||
|
|
||||||
[ForeignKey("ReceiverId")]
|
[ForeignKey("ReceiverId")]
|
||||||
public virtual Receiver Receiver { get; set; }
|
public virtual Receiver
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Receiver { get; set; }
|
||||||
|
|
||||||
|
public virtual IEnumerable<ElementAnnotation>
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Annotations { get; set; }
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction.Attributes" Version="1.0.0" />
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher.Abstraction.Attributes" Version="1.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="UserManager.Domain" Version="3.2.3" />
|
<PackageReference Include="UserManager.Domain" Version="3.2.3" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.1.1" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -201,7 +201,7 @@
|
|||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity name="Microsoft.Identity.Client" publicKeyToken="0a613f4dd989e8ae" culture="neutral" />
|
<assemblyIdentity name="Microsoft.Identity.Client" publicKeyToken="0a613f4dd989e8ae" culture="neutral" />
|
||||||
<bindingRedirect oldVersion="0.0.0.0-4.55.0.0" newVersion="4.55.0.0" />
|
<bindingRedirect oldVersion="0.0.0.0-3.0.8.0" newVersion="3.0.8.0" />
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ namespace EnvelopeGenerator.Infrastructure
|
|||||||
services.AddDbRepository(opt =>
|
services.AddDbRepository(opt =>
|
||||||
{
|
{
|
||||||
// scan EnvelopeGenerator
|
// scan EnvelopeGenerator
|
||||||
opt.RegisterFromAssembly<EGDbContext>(typeof(Config).Assembly);
|
opt.RegisterFromAssembly<EGDbContext>(typeof(EnvelopeReceiver).Assembly);
|
||||||
|
|
||||||
// scan UserManager
|
// scan UserManager
|
||||||
opt.RegisterFromAssembly<EGDbContext>(typeof(User).Assembly);
|
opt.RegisterFromAssembly<EGDbContext>(typeof(User).Assembly);
|
||||||
#if NET
|
#if NET
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.Entities;
|
|||||||
using DigitalData.UserManager.Infrastructure;
|
using DigitalData.UserManager.Infrastructure;
|
||||||
using DigitalData.UserManager.Infrastructure.Contracts;
|
using DigitalData.UserManager.Infrastructure.Contracts;
|
||||||
using DigitalData.Core.Client;
|
using DigitalData.Core.Client;
|
||||||
using EnvelopeGenerator.Application.Common.Configurations;
|
|
||||||
#elif NETFRAMEWORK
|
#elif NETFRAMEWORK
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
#endif
|
#endif
|
||||||
@@ -40,7 +39,7 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
, IUserManagerDbContext, IMailDbContext
|
, IUserManagerDbContext, IMailDbContext
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
public DbSet<Domain.Entities.Config> Configs { get; set; }
|
public DbSet<Config> Configs { get; set; }
|
||||||
|
|
||||||
public DbSet<EnvelopeReceiver> EnvelopeReceivers { get; set; }
|
public DbSet<EnvelopeReceiver> EnvelopeReceivers { get; set; }
|
||||||
|
|
||||||
@@ -98,27 +97,6 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
{
|
{
|
||||||
_triggers = triggerParamOptions.Value;
|
_triggers = triggerParamOptions.Value;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
Configs = Set<Config>();
|
|
||||||
EnvelopeReceivers = Set<EnvelopeReceiver>();
|
|
||||||
Envelopes = Set<Envelope>();
|
|
||||||
DocumentReceiverElements = Set<Signature>();
|
|
||||||
DocumentStatus = Set<DocumentStatus>();
|
|
||||||
EnvelopeDocument = Set<Document>();
|
|
||||||
EnvelopeHistories = Set<History>();
|
|
||||||
EnvelopeTypes = Set<EnvelopeType>();
|
|
||||||
Receivers = Set<Receiver>();
|
|
||||||
|
|
||||||
GroupOfUsers = Set<GroupOfUser>();
|
|
||||||
Groups = Set<Group>();
|
|
||||||
ModuleOfUsers = Set<ModuleOfUser>();
|
|
||||||
Modules = Set<Module>();
|
|
||||||
Users = Set<User>();
|
|
||||||
UserReps = Set<UserRep>();
|
|
||||||
#if NET
|
|
||||||
EMailOuts = Set<EmailOut>();
|
|
||||||
#endif
|
|
||||||
EnvelopeReceiverReadOnlys = Set<EnvelopeReceiverReadOnly>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
@@ -147,7 +125,7 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
|
|
||||||
modelBuilder.Entity<Envelope>()
|
modelBuilder.Entity<Envelope>()
|
||||||
.HasMany(e => e.Documents)
|
.HasMany(e => e.Documents)
|
||||||
.WithOne()
|
.WithOne(d => d.Envelope)
|
||||||
.HasForeignKey(ed => ed.EnvelopeId);
|
.HasForeignKey(ed => ed.EnvelopeId);
|
||||||
|
|
||||||
modelBuilder.Entity<Envelope>()
|
modelBuilder.Entity<Envelope>()
|
||||||
@@ -215,6 +193,13 @@ public abstract class EGDbContextBase : DbContext
|
|||||||
.HasForeignKey(ds => ds.ReceiverId);
|
.HasForeignKey(ds => ds.ReceiverId);
|
||||||
#endregion DocumentStatus
|
#endregion DocumentStatus
|
||||||
|
|
||||||
|
#region Annotation
|
||||||
|
modelBuilder.Entity<Signature>()
|
||||||
|
.HasMany(signature => signature.Annotations)
|
||||||
|
.WithOne(annot => annot.Element)
|
||||||
|
.HasForeignKey(annot => annot.ElementId);
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Trigger
|
#region Trigger
|
||||||
// Configure entities to handle database triggers
|
// Configure entities to handle database triggers
|
||||||
void AddTrigger<T>() where T : class => _triggers
|
void AddTrigger<T>() where T : class => _triggers
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
|
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.4.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.4.3" />
|
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.4.5" />
|
||||||
<PackageReference Include="QuestPDF" Version="2025.7.1" />
|
<PackageReference Include="QuestPDF" Version="2025.7.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
using iText.Kernel.Pdf.Canvas;
|
using iText.Kernel.Pdf.Canvas;
|
||||||
using EnvelopeGenerator.Domain.Interfaces;
|
using EnvelopeGenerator.Domain.Interfaces;
|
||||||
using iText.Kernel.Colors;
|
using iText.Kernel.Colors;
|
||||||
using iText.Kernel.Geom;
|
using DigitalData.Core.Abstractions.Interfaces;
|
||||||
|
|
||||||
#if NETFRAMEWORK
|
#if NETFRAMEWORK
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
#endif
|
#endif
|
||||||
@@ -19,6 +19,15 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
{
|
{
|
||||||
return new Pdf<MemoryStream, MemoryStream>(new MemoryStream(documentBytes), new MemoryStream());
|
return new Pdf<MemoryStream, MemoryStream>(new MemoryStream(documentBytes), new MemoryStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pdf<MemoryStream, MemoryStream> FromMemory(MemoryStream stream, MemoryStream
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
outputStream = null)
|
||||||
|
{
|
||||||
|
return new Pdf<MemoryStream, MemoryStream>(stream, outputStream ?? new MemoryStream(), disposeInputStream: false, disposeOutputStream: outputStream is null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Pdf<TInputStream, TOutputStream> : IDisposable, IAsyncDisposable
|
public class Pdf<TInputStream, TOutputStream> : IDisposable, IAsyncDisposable
|
||||||
@@ -31,13 +40,18 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
private readonly PdfReader _reader;
|
private readonly PdfReader _reader;
|
||||||
private readonly PdfWriter _writer;
|
private readonly PdfWriter _writer;
|
||||||
|
|
||||||
public Pdf(TInputStream inputStream, TOutputStream outputStream)
|
private readonly bool _disposeInputStream;
|
||||||
|
private readonly bool _disposeOutputStream;
|
||||||
|
|
||||||
|
public Pdf(TInputStream inputStream, TOutputStream outputStream, bool disposeInputStream = true, bool disposeOutputStream = true)
|
||||||
{
|
{
|
||||||
_inputStream = inputStream;
|
_inputStream = inputStream;
|
||||||
_outputStream = outputStream;
|
_outputStream = outputStream;
|
||||||
_reader = new PdfReader(inputStream);
|
_reader = new PdfReader(inputStream);
|
||||||
_writer = new PdfWriter(outputStream);
|
_writer = new PdfWriter(outputStream);
|
||||||
_doc = new PdfDocument(_reader, _writer);
|
_doc = new PdfDocument(_reader, _writer);
|
||||||
|
_disposeInputStream = disposeInputStream;
|
||||||
|
_disposeOutputStream = disposeOutputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -88,7 +102,7 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
});
|
});
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public Pdf<TInputStream, TOutputStream> Background<TSignature>(IEnumerable<TSignature> signatures)
|
public Pdf<TInputStream, TOutputStream> Background<TSignature>(IEnumerable<TSignature> signatures, double widthPx = 1.9500000000000002, double heightPx = 2.52)
|
||||||
where TSignature : ISignature
|
where TSignature : ISignature
|
||||||
{
|
{
|
||||||
// once per page
|
// once per page
|
||||||
@@ -106,8 +120,8 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
double magin = .2;
|
double magin = .2;
|
||||||
double x = (signature.X - .7 - magin) * inchFactor;
|
double x = (signature.X - .7 - magin) * inchFactor;
|
||||||
double y = (signature.Y - .5 - magin) * inchFactor;
|
double y = (signature.Y - .5 - magin) * inchFactor;
|
||||||
double width = 1.9500000000000002 * inchFactor;
|
double width = widthPx * inchFactor;
|
||||||
double height = 2.52 * inchFactor;
|
double height = heightPx * inchFactor;
|
||||||
|
|
||||||
double bottomLineLength = 2.5;
|
double bottomLineLength = 2.5;
|
||||||
|
|
||||||
@@ -149,16 +163,16 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
{
|
{
|
||||||
// Managed resources
|
// Managed resources
|
||||||
_doc?.Close();
|
_doc?.Close();
|
||||||
_inputStream?.Dispose();
|
if (_disposeInputStream) _inputStream?.Dispose();
|
||||||
_outputStream?.Dispose();
|
if(_disposeOutputStream) _outputStream?.Dispose();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// When called by the finalizer, clean up only unmanaged resources
|
// When called by the finalizer, clean up only unmanaged resources
|
||||||
// Unmanaged resources such as PdfDocument, PdfReader, and PdfWriter are already IDisposable; we close them here
|
// Unmanaged resources such as PdfDocument, PdfReader, and PdfWriter are already IDisposable; we close them here
|
||||||
try { _doc?.Close(); } catch { }
|
try { _doc?.Close(); } catch { }
|
||||||
try { _inputStream?.Dispose(); } catch { }
|
try { if(_disposeInputStream) _inputStream?.Dispose(); } catch { }
|
||||||
try { _outputStream?.Dispose(); } catch { }
|
try { if (_disposeOutputStream) _outputStream?.Dispose(); } catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
@@ -170,15 +184,21 @@ namespace EnvelopeGenerator.PdfEditor
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_doc?.Close();
|
_doc?.Close();
|
||||||
if (_inputStream is IAsyncDisposable asyncInput)
|
if (_disposeInputStream)
|
||||||
await asyncInput.DisposeAsync();
|
{
|
||||||
else
|
if (_inputStream is IAsyncDisposable asyncInput)
|
||||||
_inputStream.Dispose();
|
await asyncInput.DisposeAsync();
|
||||||
|
else
|
||||||
|
_inputStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
if (_outputStream is IAsyncDisposable asyncOutput)
|
if (_disposeOutputStream)
|
||||||
await asyncOutput.DisposeAsync();
|
{
|
||||||
else
|
if (_outputStream is IAsyncDisposable asyncOutput)
|
||||||
_outputStream?.Dispose();
|
await asyncOutput.DisposeAsync();
|
||||||
|
else
|
||||||
|
_outputStream?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
||||||
<bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.0" />
|
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
<dependentAssembly>
|
<dependentAssembly>
|
||||||
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
|||||||
@@ -17,6 +17,21 @@
|
|||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
</NuGetPackageImportStamp>
|
</NuGetPackageImportStamp>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -54,6 +69,9 @@
|
|||||||
<Reference Include="BouncyCastle.Cryptography, Version=2.0.0.0, Culture=neutral, PublicKeyToken=072edcf4a5328938, processorArchitecture=MSIL">
|
<Reference Include="BouncyCastle.Cryptography, Version=2.0.0.0, Culture=neutral, PublicKeyToken=072edcf4a5328938, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\BouncyCastle.Cryptography.2.5.0\lib\net461\BouncyCastle.Cryptography.dll</HintPath>
|
<HintPath>..\packages\BouncyCastle.Cryptography.2.5.0\lib\net461\BouncyCastle.Cryptography.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="DigitalData.Modules.Base, Version=1.3.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\..\2_DLL Projekte\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
|
<HintPath>..\..\2_DLL Projekte\DDModules\Base\bin\Debug\DigitalData.Modules.Base.dll</HintPath>
|
||||||
@@ -160,8 +178,14 @@
|
|||||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.7.0.0\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
@@ -335,6 +359,18 @@
|
|||||||
<Name>EnvelopeGenerator.Domain</Name>
|
<Name>EnvelopeGenerator.Domain</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.6.2">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4.6.2 %28x86 and x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||||
<Import Project="..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets')" />
|
<Import Project="..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets" Condition="Exists('..\packages\GdPicture.runtimes.windows.14.3.3\build\net462\GdPicture.runtimes.windows.targets')" />
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||||
|
|||||||
16
EnvelopeGenerator.Service/UserConfig.xml
Normal file
16
EnvelopeGenerator.Service/UserConfig.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<Config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<ConnectionString>Server=sDD-VMP04-SQL17\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;TrustServerCertificate=True;</ConnectionString>
|
||||||
|
<Debug>true</Debug>
|
||||||
|
<IntervalInMin>1</IntervalInMin>
|
||||||
|
<IgnoredLabels>
|
||||||
|
<Label>Date</Label>
|
||||||
|
<Label>Datum</Label>
|
||||||
|
<Label>ZIP</Label>
|
||||||
|
<Label>PLZ</Label>
|
||||||
|
<Label>Place</Label>
|
||||||
|
<Label>Ort</Label>
|
||||||
|
<Label>Position</Label>
|
||||||
|
<Label>Stellung</Label>
|
||||||
|
</IgnoredLabels>
|
||||||
|
</Config>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net48" />
|
<package id="BouncyCastle.Cryptography" version="2.5.0" targetFramework="net48" />
|
||||||
|
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" />
|
||||||
<package id="DocumentFormat.OpenXml" version="3.2.0" targetFramework="net48" />
|
<package id="DocumentFormat.OpenXml" version="3.2.0" targetFramework="net48" />
|
||||||
<package id="DocumentFormat.OpenXml.Framework" version="3.2.0" targetFramework="net48" />
|
<package id="DocumentFormat.OpenXml.Framework" version="3.2.0" targetFramework="net48" />
|
||||||
<package id="EntityFramework" version="6.4.4" targetFramework="net48" />
|
<package id="EntityFramework" version="6.4.4" targetFramework="net48" />
|
||||||
@@ -11,7 +12,9 @@
|
|||||||
<package id="Microsoft.AspNet.WebApi.Client" version="6.0.0" targetFramework="net48" />
|
<package id="Microsoft.AspNet.WebApi.Client" version="6.0.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
|
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
|
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
|
||||||
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net462" />
|
<package id="Microsoft.Extensions.DependencyInjection" version="7.0.0" targetFramework="net462" />
|
||||||
|
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="7.0.0" targetFramework="net462" />
|
||||||
|
<package id="Microsoft.Extensions.Logging.Abstractions" version="7.0.0" targetFramework="net462" />
|
||||||
<package id="Microsoft.VisualBasic" version="10.3.0" targetFramework="net48" />
|
<package id="Microsoft.VisualBasic" version="10.3.0" targetFramework="net48" />
|
||||||
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
||||||
<package id="Newtonsoft.Json.Bson" version="1.0.2" targetFramework="net48" />
|
<package id="Newtonsoft.Json.Bson" version="1.0.2" targetFramework="net48" />
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Bogus" Version="35.6.3" />
|
<PackageReference Include="Bogus" Version="35.6.3" />
|
||||||
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
<PackageReference Include="coverlet.collector" Version="6.0.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
|
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.4.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.1.1" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.3.0" />
|
||||||
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using EnvelopeGenerator.Application.Common.Extensions;
|
|||||||
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
using EnvelopeGenerator.Application.Common.Interfaces.Services;
|
||||||
using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
|
||||||
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
|
||||||
|
using EnvelopeGenerator.Application.Histories.Queries;
|
||||||
using EnvelopeGenerator.Domain.Constants;
|
using EnvelopeGenerator.Domain.Constants;
|
||||||
using EnvelopeGenerator.Web.Extensions;
|
using EnvelopeGenerator.Web.Extensions;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
@@ -11,7 +12,6 @@ using Microsoft.AspNetCore.Authentication;
|
|||||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Dynamic;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers;
|
namespace EnvelopeGenerator.Web.Controllers;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ public class AnnotationController : ControllerBase
|
|||||||
|
|
||||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> CreateOrUpdate([FromBody] ExpandoObject annotations, CancellationToken cancel = default)
|
public async Task<IActionResult> CreateOrUpdate([FromBody] PsPdfKitAnnotation psPdfKitAnnotation, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
// get claims
|
// get claims
|
||||||
var signature = User.GetAuthReceiverSignature();
|
var signature = User.GetAuthReceiverSignature();
|
||||||
@@ -58,14 +58,16 @@ public class AnnotationController : ControllerBase
|
|||||||
|
|
||||||
// Again check if receiver has already signed
|
// Again check if receiver has already signed
|
||||||
if (await _mediator.IsSignedAsync(uuid, signature, cancel))
|
if (await _mediator.IsSignedAsync(uuid, signature, cancel))
|
||||||
return Problem(statusCode: 403);
|
return Problem(statusCode: 409);
|
||||||
|
else if (await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel))
|
||||||
|
return Problem(statusCode: 423);
|
||||||
|
|
||||||
var docSignedNotification = await _mediator
|
var docSignedNotification = await _mediator
|
||||||
.ReadEnvelopeReceiverAsync(uuid, signature, cancel)
|
.ReadEnvelopeReceiverAsync(uuid, signature, cancel)
|
||||||
.ToDocSignedNotification(annotations)
|
.ToDocSignedNotification(psPdfKitAnnotation)
|
||||||
?? throw new NotFoundException("Envelope receiver is not found.");
|
?? throw new NotFoundException("Envelope receiver is not found.");
|
||||||
|
|
||||||
await _mediator.Publish(docSignedNotification, cancel);
|
await _mediator.PublishSafely(docSignedNotification, cancel);
|
||||||
|
|
||||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,23 @@ public class EnvelopeController : ViewControllerBase
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region UseAccessCode
|
||||||
|
if (!er.Envelope!.UseAccessCode)
|
||||||
|
{
|
||||||
|
(string? uuid, string? signature) = decoded.ParseEnvelopeReceiverId();
|
||||||
|
var er_secret_res = await _envRcvService.ReadWithSecretByUuidSignatureAsync(uuid: uuid!, signature: signature!);
|
||||||
|
|
||||||
|
if (er_secret_res.IsFailed)
|
||||||
|
{
|
||||||
|
_logger.LogNotice(er_secret_res.Notices);
|
||||||
|
return this.ViewEnvelopeNotFound();
|
||||||
|
}
|
||||||
|
var er_secret = er_secret_res.Data;
|
||||||
|
await HttpContext.SignInEnvelopeAsync(er_secret, ReceiverRole.FullyAuth);
|
||||||
|
return await CreateShowEnvelopeView(er_secret);
|
||||||
|
}
|
||||||
|
#endregion UseAccessCode
|
||||||
|
|
||||||
#region Send Access Code
|
#region Send Access Code
|
||||||
bool accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress);
|
bool accessCodeAlreadyRequested = await _historyService.AccessCodeAlreadyRequested(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress);
|
||||||
if (!accessCodeAlreadyRequested)
|
if (!accessCodeAlreadyRequested)
|
||||||
@@ -121,7 +138,7 @@ public class EnvelopeController : ViewControllerBase
|
|||||||
|
|
||||||
[HttpPost("{envelopeReceiverId}")]
|
[HttpPost("{envelopeReceiverId}")]
|
||||||
[Obsolete("Use MediatR")]
|
[Obsolete("Use MediatR")]
|
||||||
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth)
|
public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -145,6 +162,15 @@ public class EnvelopeController : ViewControllerBase
|
|||||||
}
|
}
|
||||||
var er_secret = er_secret_res.Data;
|
var er_secret = er_secret_res.Data;
|
||||||
|
|
||||||
|
//check rejection
|
||||||
|
var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id);
|
||||||
|
if (rejRcvrs.Any())
|
||||||
|
{
|
||||||
|
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||||
|
ViewBag.IsExt = !rejRcvrs.Contains(er_secret.Receiver); //external if the current user is not rejected
|
||||||
|
return View("EnvelopeRejected", er_secret);
|
||||||
|
}
|
||||||
|
|
||||||
// show envelope if already logged in
|
// show envelope if already logged in
|
||||||
if (User.IsInRole(ReceiverRole.FullyAuth))
|
if (User.IsInRole(ReceiverRole.FullyAuth))
|
||||||
return await CreateShowEnvelopeView(er_secret);
|
return await CreateShowEnvelopeView(er_secret);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using EnvelopeGenerator.Application.Common.Extensions;
|
||||||
|
using EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Web.Controllers.Test;
|
||||||
|
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class TestAnnotationController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IMediator _mediator;
|
||||||
|
|
||||||
|
public TestAnnotationController(IMediator mediator)
|
||||||
|
{
|
||||||
|
_mediator = mediator;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{envelopeKey}")]
|
||||||
|
public async Task<IActionResult> Delete([FromRoute] string envelopeKey)
|
||||||
|
{
|
||||||
|
if (envelopeKey.GetEnvelopeUuid() is not string uuid)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
if (envelopeKey.GetReceiverSignature() is not string signature)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
await _mediator.Publish(new RemoveSignatureNotification()
|
||||||
|
{
|
||||||
|
EnvelopeUuid = uuid,
|
||||||
|
ReceiverSignature = signature
|
||||||
|
});
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<PackageId>EnvelopeGenerator.Web</PackageId>
|
<PackageId>EnvelopeGenerator.Web</PackageId>
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
<PackageTags>digital data envelope generator web</PackageTags>
|
<PackageTags>digital data envelope generator web</PackageTags>
|
||||||
<Description>EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description>
|
<Description>EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description>
|
||||||
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
|
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
|
||||||
<Version>3.4.1</Version>
|
<Version>3.7.0</Version>
|
||||||
<AssemblyVersion>3.4.1</AssemblyVersion>
|
<AssemblyVersion>3.7.0</AssemblyVersion>
|
||||||
<FileVersion>3.4.1</FileVersion>
|
<FileVersion>3.7.0</FileVersion>
|
||||||
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -2094,20 +2094,13 @@
|
|||||||
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" />
|
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
|
||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
|
||||||
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
||||||
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
|
||||||
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.20" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.15">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.20" />
|
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="7.0.20" />
|
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="7.0.20" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="NLog" Version="5.2.5" />
|
<PackageReference Include="NLog" Version="5.2.5" />
|
||||||
@@ -2126,6 +2119,56 @@
|
|||||||
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
|
||||||
|
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
||||||
|
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||||
|
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||||
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
|
||||||
|
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="7.0.20" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="NLog" Version="5.2.5" />
|
||||||
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.0" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.AspNetCore" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.Plugins" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.Serialization.Json" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
|
||||||
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.1" />
|
||||||
|
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
|
||||||
|
<PackageReference Include="System.DirectoryServices" Version="8.0.0" />
|
||||||
|
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.1" />
|
||||||
|
<PackageReference Include="System.DirectoryServices.Protocols" Version="8.0.1" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="8.0.16" />
|
||||||
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'net9.0'">
|
||||||
|
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
|
||||||
|
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
|
||||||
|
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
|
||||||
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
|
||||||
|
<PackageReference Include="HtmlSanitizer" Version="8.0.865" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="7.0.20" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="NLog" Version="5.2.5" />
|
||||||
|
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.0" />
|
||||||
|
<PackageReference Include="Quartz" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.AspNetCore" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.Plugins" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Quartz.Serialization.Json" Version="3.8.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.0.1" />
|
||||||
|
<PackageReference Include="System.Configuration.ConfigurationManager" Version="9.0.11" />
|
||||||
|
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
|
||||||
|
<PackageReference Include="System.DirectoryServices" Version="9.0.4" />
|
||||||
|
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="9.0.4" />
|
||||||
|
<PackageReference Include="System.DirectoryServices.Protocols" Version="9.0.4" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="9.0.5" />
|
||||||
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||||
|
|||||||
@@ -11,12 +11,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
|
|||||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
<ProjectGuid>5e0e17c0-ff5a-4246-bf87-1add85376a27</ProjectGuid>
|
<ProjectGuid>5e0e17c0-ff5a-4246-bf87-1add85376a27</ProjectGuid>
|
||||||
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\signFLOW\Web\net9\win64\$(Version)\EnvelopeGenerator.Web.zip</DesktopBuildPackageLocation>
|
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\signFLOW\Web\net8\$(Version)\EnvelopeGenerator.Web.zip</DesktopBuildPackageLocation>
|
||||||
<PackageAsSingleFile>true</PackageAsSingleFile>
|
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||||
<DeployIisAppPath>EnvelopeGenerator</DeployIisAppPath>
|
<DeployIisAppPath>EnvelopeGenerator</DeployIisAppPath>
|
||||||
<_TargetId>IISWebDeployPackage</_TargetId>
|
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
|
||||||
<SelfContained>true</SelfContained>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<h6>@($"{@envelope?.Message}")</h6>
|
<div class="markdown">@(envelope?.Message)</div>
|
||||||
}
|
}
|
||||||
<p>
|
<p>
|
||||||
<small class="text-body-secondary">
|
<small class="text-body-secondary">
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>
|
||||||
<script src="~/lib/sweetalert2/sweetalert2.min.js"></script>
|
<script src="~/lib/sweetalert2/sweetalert2.min.js"></script>
|
||||||
<script src="~/lib/alertifyjs/alertify.min.js"></script>
|
<script src="~/lib/alertifyjs/alertify.min.js"></script>
|
||||||
|
<script src="~/lib/marked/marked.umd.min.js"></script>
|
||||||
<script src="~/js/lazy.min.js" asp-append-version="true"></script>
|
<script src="~/js/lazy.min.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/ui.min.js" asp-append-version="true"></script>
|
<script src="~/js/ui.min.js" asp-append-version="true"></script>
|
||||||
<script src="~/js/annotation.js" asp-append-version="true"></script>
|
<script src="~/js/annotation.js" asp-append-version="true"></script>
|
||||||
@@ -95,5 +96,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<a href="/privacy-policy.@(_localizer.Culture()).html" target="_blank">@_localizer.Privacy()</a>
|
<a href="/privacy-policy.@(_localizer.Culture()).html" target="_blank">@_localizer.Privacy()</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
<script src="~/js/markdown.min.js" asp-append-version="true"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -41,6 +41,12 @@
|
|||||||
"wwwroot/js/util.js"
|
"wwwroot/js/util.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outputFileName": "wwwroot/js/markdown.min.js",
|
||||||
|
"inputFiles": [
|
||||||
|
"wwwroot/js/markdown.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outputFileName": "wwwroot/css/error-space.min.css",
|
"outputFileName": "wwwroot/css/error-space.min.css",
|
||||||
"inputFiles": [
|
"inputFiles": [
|
||||||
|
|||||||
@@ -1,23 +1,16 @@
|
|||||||
async function createAnnotations(document, envelopeId, receiverId) {
|
function generateId(envelopeId, receiverId, elementId, annotationType) {
|
||||||
|
return `${envelopeId}#${receiverId}#${elementId}#${annotationType}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createAnnotations(document, envelopeId, receiverId) {
|
||||||
const signatures = [];
|
const signatures = [];
|
||||||
|
|
||||||
for (let element of document.elements) {
|
|
||||||
const annotParams = await getAnnotationParams(element.left, element.top);
|
|
||||||
const page = element.page - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
let elementIndex = 0;
|
|
||||||
|
|
||||||
function generateId(annotationType) {
|
|
||||||
return `${envelopeId}_${receiverId}_${elementIndex++}_${annotationType}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let element of document.elements) {
|
for (let element of document.elements) {
|
||||||
const annotParams = await getAnnotationParams(element.left, element.top);
|
const annotParams = await getAnnotationParams(element.left, element.top);
|
||||||
const page = element.page - 1
|
const page = element.page - 1
|
||||||
|
|
||||||
//#region signatures
|
//#region signatures
|
||||||
const id = generateId('signature');
|
const id = generateId(envelopeId, receiverId, element.id, 'signature');
|
||||||
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id,
|
id: id,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -34,7 +27,7 @@
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region position
|
//#region position
|
||||||
const id_position = generateId('position');
|
const id_position = generateId(envelopeId, receiverId, element.id, 'position');
|
||||||
const annotation_position = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_position = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_position,
|
id: id_position,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -54,7 +47,7 @@
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region city
|
//#region city
|
||||||
const id_city = generateId('city');
|
const id_city = generateId(envelopeId, receiverId, element.id, 'city');
|
||||||
const annotation_city = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_city = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_city,
|
id: id_city,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -74,7 +67,7 @@
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region date
|
//#region date
|
||||||
const id_date = generateId('date');
|
const id_date = generateId(envelopeId, receiverId, element.id, 'date');
|
||||||
const annotation_date = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_date = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_date,
|
id: id_date,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -102,7 +95,7 @@
|
|||||||
this.markFieldAsCity(formFieldCity);
|
this.markFieldAsCity(formFieldCity);
|
||||||
|
|
||||||
//#region date label
|
//#region date label
|
||||||
const id_date_label = generateId('date_label');
|
const id_date_label = generateId(envelopeId, receiverId, element.id, 'date_label');
|
||||||
const annotation_date_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_date_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_date_label,
|
id: id_date_label,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -125,7 +118,7 @@
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region city label
|
//#region city label
|
||||||
const id_city_label = generateId('city_label');
|
const id_city_label = generateId(envelopeId, receiverId, element.id, 'city_label');
|
||||||
const annotation_city_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_city_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_city_label,
|
id: id_city_label,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -148,7 +141,7 @@
|
|||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region position label
|
//#region position label
|
||||||
const id_position_label = generateId('position_label');
|
const id_position_label = generateId(envelopeId, receiverId, element.id, 'position_label');
|
||||||
const annotation_position_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
const annotation_position_label = new PSPDFKit.Annotations.WidgetAnnotation({
|
||||||
id: id_position_label,
|
id: id_position_label,
|
||||||
pageIndex: page,
|
pageIndex: page,
|
||||||
@@ -224,8 +217,9 @@ function isSignature(annotation) {
|
|||||||
return !!annotation.isSignature || annotation.description == 'FRAME'
|
return !!annotation.isSignature || annotation.description == 'FRAME'
|
||||||
}
|
}
|
||||||
|
|
||||||
function createImageAnnotation(boundingBox, pageIndex, imageAttachmentId) {
|
function createImageAnnotation(boundingBox, pageIndex, imageAttachmentId, id) {
|
||||||
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
|
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
|
||||||
|
id: id,
|
||||||
pageIndex: pageIndex,
|
pageIndex: pageIndex,
|
||||||
isSignature: false,
|
isSignature: false,
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
@@ -314,3 +308,80 @@ function markFieldAsCity(formField) {
|
|||||||
function isCityField(formField) {
|
function isCityField(formField) {
|
||||||
return cityFieldNames.includes(formField.name)
|
return cityFieldNames.includes(formField.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fixBase64(escapedBase64) {
|
||||||
|
return escapedBase64
|
||||||
|
.replace(/\\u002B/g, "+")
|
||||||
|
.replace(/\\u002F/g, "/")
|
||||||
|
.replace(/\\u003D/g, "=");
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapSignature(iJSON) {
|
||||||
|
return [
|
||||||
|
// formFields
|
||||||
|
...iJSON.formFieldValues.filter(field => !field.name.includes("label")).map((field) => {
|
||||||
|
const nameParts = field.name.split('#');
|
||||||
|
const [x, y, width, height] = iJSON.annotations.find(iAnnot => iAnnot.id === field.name).bbox;
|
||||||
|
return {
|
||||||
|
elementId: Number(nameParts[2]),
|
||||||
|
name: nameParts[3],
|
||||||
|
value: field.value,
|
||||||
|
type: field.type,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
// frames
|
||||||
|
...iJSON.annotations.filter(annot => annot.description === 'FRAME').map((annot) => {
|
||||||
|
const preElement = findNearest(annot, e => e.bbox[0], e => e.bbox[1], iJSON.annotations.filter(
|
||||||
|
field => field.id.includes("signature") && field.pageIndex === annot.pageIndex
|
||||||
|
));
|
||||||
|
const idPartsOfPre = preElement.id.split('#');
|
||||||
|
const [x, y, width, height] = annot.bbox;
|
||||||
|
return {
|
||||||
|
elementId: Number(idPartsOfPre[2]),
|
||||||
|
name: 'frame',
|
||||||
|
value: fixBase64(iJSON.attachments[annot.imageAttachmentId]?.binary),
|
||||||
|
type: annot.type,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
// signatures
|
||||||
|
...iJSON.annotations.filter(annot => annot.isSignature).map(annot => {
|
||||||
|
const preElement = findNearest(annot, e => e.bbox[0], e => e.bbox[1], iJSON.annotations.filter(
|
||||||
|
field => field.id.includes("signature") && field.pageIndex === annot.pageIndex
|
||||||
|
));
|
||||||
|
const idPartsOfPre = preElement.id.split('#');
|
||||||
|
|
||||||
|
let value;
|
||||||
|
if (annot.imageAttachmentId)
|
||||||
|
value = iJSON.attachments[annot.imageAttachmentId]?.binary;
|
||||||
|
else if (annot.lines && annot.strokeColor)
|
||||||
|
value = JSON.stringify({
|
||||||
|
lines: annot.lines,
|
||||||
|
strokeColor: annot.strokeColor
|
||||||
|
});
|
||||||
|
else
|
||||||
|
throw new Error("Signature mapping failed: The data structure from the third-party library is incompatible or missing required fields.");
|
||||||
|
|
||||||
|
const [x, y, width, height] = annot.bbox;
|
||||||
|
return {
|
||||||
|
elementId: Number(idPartsOfPre[2]),
|
||||||
|
name: 'signature',
|
||||||
|
value,
|
||||||
|
type: annot.type,
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
};
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -87,7 +87,13 @@ class App {
|
|||||||
height: height,
|
height: height,
|
||||||
}),
|
}),
|
||||||
annotation.pageIndex,
|
annotation.pageIndex,
|
||||||
imageAttachmentId
|
imageAttachmentId,
|
||||||
|
generateId(
|
||||||
|
this.envelopeReceiver.envelopeId,
|
||||||
|
this.envelopeReceiver.receiverId,
|
||||||
|
this.fakeElementId--,
|
||||||
|
'signed'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
this.pdfKit.create(frameAnnotation)
|
this.pdfKit.create(frameAnnotation)
|
||||||
@@ -177,7 +183,8 @@ class App {
|
|||||||
|
|
||||||
async handleFinish(event) {
|
async handleFinish(event) {
|
||||||
const iJSON = await this.pdfKit.exportInstantJSON()
|
const iJSON = await this.pdfKit.exportInstantJSON()
|
||||||
const iFormFieldValues = await iJSON.formFieldValues;
|
|
||||||
|
const iFormFieldValues = iJSON.formFieldValues;
|
||||||
|
|
||||||
//check required
|
//check required
|
||||||
const iReqFields = iFormFieldValues.filter(f => isFieldRequired(f))
|
const iReqFields = iFormFieldValues.filter(f => isFieldRequired(f))
|
||||||
@@ -242,10 +249,13 @@ class App {
|
|||||||
|
|
||||||
// Export annotation data and save to database
|
// Export annotation data and save to database
|
||||||
try {
|
try {
|
||||||
const res = await signEnvelope(await iJSON);
|
const res = await signEnvelope({
|
||||||
|
instant: iJSON,
|
||||||
|
structured: mapSignature(iJSON)
|
||||||
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
if (res.status === 403) {
|
if (res.status === 409) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Warnung',
|
title: 'Warnung',
|
||||||
text: 'Umschlag ist nicht mehr verfügbar.',
|
text: 'Umschlag ist nicht mehr verfügbar.',
|
||||||
@@ -253,6 +263,17 @@ class App {
|
|||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
else if (res.status === 423) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Info',
|
||||||
|
text: 'Dokument wurde von einem Empfänger abgelehnt. Sie werden weitergeleitet...',
|
||||||
|
icon: 'info',
|
||||||
|
timer: 2000,
|
||||||
|
showConfirmButton: false
|
||||||
|
}).then(() => {
|
||||||
|
location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new Error()
|
throw new Error()
|
||||||
}
|
}
|
||||||
@@ -272,22 +293,17 @@ class App {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async validateAnnotations(totalSignatures) {
|
async validateAnnotations(totalSignatures) {
|
||||||
const annotations = await getAnnotations(this.pdfKit)
|
const annotations = await getAnnotations(this.pdfKit)
|
||||||
const filtered = annotations
|
const filtered = annotations
|
||||||
.map(a => a.toJS())
|
.map(a => a.toJS())
|
||||||
.filter(a => a.isSignature)
|
.filter(a => a.isSignature)
|
||||||
|
|
||||||
if (totalSignatures > filtered.length) {
|
return totalSignatures <= filtered.length
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleReset(event) {
|
async handleReset(event) {
|
||||||
const result = await Swal.fire({
|
const result = Swal.fire({
|
||||||
title: 'Sind sie sicher?',
|
title: 'Sind sie sicher?',
|
||||||
text: 'Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?',
|
text: 'Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?',
|
||||||
icon: 'question',
|
icon: 'question',
|
||||||
@@ -300,4 +316,6 @@ class App {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fakeElementId = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
4
EnvelopeGenerator.Web/wwwroot/js/app.min.js
vendored
4
EnvelopeGenerator.Web/wwwroot/js/app.min.js
vendored
@@ -1,3 +1,3 @@
|
|||||||
class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.pdfKit=null;this.currentDocument=t.envelope.documents[0];this.currentReceiver=t.receiver;this.signatureCount=t.envelope.documents[0].elements.length;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){this.pdfKit=await loadPSPDFKit(this.documentBytes,this.container,this.licenseKey,this.locale);addToolbarItems(this.pdfKit,this.handleClick.bind(this));this.pdfKit.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this));this.pdfKit.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this));this.pdfKit.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this));this.pdfKit.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()});try{let n=await createAnnotations(this.currentDocument,this.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId);await this.pdfKit.create(n)}catch(n){console.error("Error loading annotations:",n)}[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.pdfKit.createAttachment(s),c=createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h);this.pdfKit.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);Comp.SignatureProgress.SignedCount=0;t.isConfirmed&&Swal.fire({title:"Erfolg",text:"Dokument wurde zurückgesetzt",icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/Envelope/${this.envelopeKey}`);break;case"REJECT":Swal.fire({title:localized.rejection,html:`<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(`
|
class App{constructor(n,t,i,r,u,f){this.container=f??`#${this.constructor.name.toLowerCase()}`;this.envelopeKey=n;this.pdfKit=null;this.currentDocument=t.envelope.documents[0];this.currentReceiver=t.receiver;this.signatureCount=t.envelope.documents[0].elements.length;this.envelopeReceiver=t;this.documentBytes=i;this.licenseKey=r;this.locale=u}async init(){this.pdfKit=await loadPSPDFKit(this.documentBytes,this.container,this.licenseKey,this.locale);addToolbarItems(this.pdfKit,this.handleClick.bind(this));this.pdfKit.addEventListener("annotations.load",this.handleAnnotationsLoad.bind(this));this.pdfKit.addEventListener("annotations.change",this.handleAnnotationsChange.bind(this));this.pdfKit.addEventListener("annotations.create",this.handleAnnotationsCreate.bind(this));this.pdfKit.addEventListener("annotations.willChange",()=>{Comp.ActPanel.Toggle()});try{let n=await createAnnotations(this.currentDocument,this.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId);await this.pdfKit.create(n)}catch(n){console.error("Error loading annotations:",n)}[...document.getElementsByClassName("btn_refresh")].forEach(n=>n.addEventListener("click",()=>this.handleClick("RESET")));[...document.getElementsByClassName("btn_complete")].forEach(n=>n.addEventListener("click",()=>this.handleClick("FINISH")));[...document.getElementsByClassName("btn_reject")].forEach(n=>n.addEventListener("click",()=>this.handleClick("REJECT")))}handleAnnotationsLoad(n){n.toJS()}handleAnnotationsChange(){}async handleAnnotationsCreate(n){const t=n.toJS()[0],i=!!t.formFieldName,r=!!t.isSignature;if(i===!1&&r===!0){const r=t.boundingBox.left-20,u=t.boundingBox.top-20,n=150,i=75,f=new Date,e=await createAnnotationFrameBlob(this.envelopeReceiver.name,this.currentReceiver.signature,f,n,i),o=await fetch(e),s=await o.blob(),h=await this.pdfKit.createAttachment(s),c=createImageAnnotation(new PSPDFKit.Geometry.Rect({left:r,top:u,width:n,height:i}),t.pageIndex,h,generateId(this.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId,this.fakeElementId--,"signed"));this.pdfKit.create(c)}}async handleClick(n){let t=!1;switch(n){case"RESET":t=await this.handleReset(null);Comp.SignatureProgress.SignedCount=0;t.isConfirmed&&Swal.fire({title:"Erfolg",text:"Dokument wurde zurückgesetzt",icon:"info"});break;case"FINISH":t=await this.handleFinish(null);t==!0&&(window.location.href=`/Envelope/${this.envelopeKey}`);break;case"REJECT":Swal.fire({title:localized.rejection,html:`<div class="text-start fs-6 p-0 m-0">${localized.rejectionReasonQ}</div>`,icon:"question",input:"text",inputAttributes:{autocapitalize:"off"},showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.complete,cancelButtonText:localized.back,showLoaderOnConfirm:!0,preConfirm:async n=>{try{return await rejectEnvelope(n)}catch(t){Swal.showValidationMessage(`
|
||||||
Request failed: ${t}
|
Request failed: ${t}
|
||||||
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?reload():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify("Kopiert",{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify("Unerwarteter Fehler",{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}async handleFinish(){const n=await this.pdfKit.exportInstantJSON(),t=await n.formFieldValues,r=t.filter(n=>isFieldRequired(n)),u=r.some(n=>n.value===undefined||n.value===null||n.value==="");if(u)return Swal.fire({title:"Warnung",text:"Bitte füllen Sie alle Standortinformationen vollständig aus!",icon:"warning"}),!1;const f=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),e=t.filter(n=>isCityField(n));for(var i of e)if(!IS_MOBILE_DEVICE&&!f.test(i.value))return Swal.fire({title:"Warnung",text:`Bitte überprüfen Sie die eingegebene Ortsangabe "${i.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,icon:"warning"}),!1;const o=await this.validateAnnotations(this.signatureCount);return o===!1?(Swal.fire({title:"Warnung",text:"Es wurden nicht alle Signaturfelder ausgefüllt!",icon:"warning"}),!1):Swal.fire({title:localized.confirmation,html:`<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.pdfKit.save()}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}try{const t=await signEnvelope(await n);if(t.ok)return!0;if(t.status===403)return Swal.fire({title:"Warnung",text:"Umschlag ist nicht mehr verfügbar.",icon:"warning"}),!1;throw new Error;}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}}else return!1})}async validateAnnotations(n){const t=await getAnnotations(this.pdfKit),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n>i.length?!1:!0}async handleReset(){const n=await Swal.fire({title:"Sind sie sicher?",text:"Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?",icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await deleteAnnotations(this.pdfKit)}return n}}
|
`)}},allowOutsideClick:()=>!Swal.isLoading()}).then(n=>{if(n.isConfirmed){const t=n.value;t.ok?reload():Swal.showValidationMessage(`Request failed: ${t.message}`)}});break;case"COPY_URL":const n=window.location.href.replace(/\/readonly/gi,"");navigator.clipboard.writeText(n).then(function(){bsNotify("Kopiert",{alert_type:"success",delay:4,icon_name:"check_circle"})}).catch(function(){bsNotify("Unerwarteter Fehler",{alert_type:"danger",delay:4,icon_name:"error"})});break;case"SHARE":Comp.ShareBackdrop.show();break;case"LOGOUT":await logout()}}async handleFinish(){const n=await this.pdfKit.exportInstantJSON(),t=n.formFieldValues,r=t.filter(n=>isFieldRequired(n)),u=r.some(n=>n.value===undefined||n.value===null||n.value==="");if(u)return Swal.fire({title:"Warnung",text:"Bitte füllen Sie alle Standortinformationen vollständig aus!",icon:"warning"}),!1;const f=new RegExp("^[a-zA-Z\\u0080-\\u024F]+(?:([\\ \\-\\']|(\\.\\ ))[a-zA-Z\\u0080-\\u024F]+)*$"),e=t.filter(n=>isCityField(n));for(var i of e)if(!IS_MOBILE_DEVICE&&!f.test(i.value))return Swal.fire({title:"Warnung",text:`Bitte überprüfen Sie die eingegebene Ortsangabe "${i.value}" auf korrekte Formatierung. Beispiele für richtige Formate sind: München, Île-de-France, Sauðárkrókur, San Francisco, St. Catharines usw.`,icon:"warning"}),!1;const o=await this.validateAnnotations(this.signatureCount);return o===!1?(Swal.fire({title:"Warnung",text:"Es wurden nicht alle Signaturfelder ausgefüllt!",icon:"warning"}),!1):Swal.fire({title:localized.confirmation,html:`<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,icon:"question",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:localized.finalize,cancelButtonText:localized.back}).then(async t=>{if(t.isConfirmed){try{await this.pdfKit.save()}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}try{const t=await signEnvelope({instant:n,structured:mapSignature(n)});if(t.ok)return!0;if(t.status===409)return Swal.fire({title:"Warnung",text:"Umschlag ist nicht mehr verfügbar.",icon:"warning"}),!1;if(t.status===423)Swal.fire({title:"Info",text:"Dokument wurde von einem Empfänger abgelehnt. Sie werden weitergeleitet...",icon:"info",timer:2e3,showConfirmButton:!1}).then(()=>{location.reload()});else throw new Error;}catch(i){return Swal.fire({title:"Fehler",text:"Umschlag konnte nicht signiert werden!",icon:"error"}),!1}}else return!1})}async validateAnnotations(n){const t=await getAnnotations(this.pdfKit),i=t.map(n=>n.toJS()).filter(n=>n.isSignature);return n<=i.length}async handleReset(){const n=Swal.fire({title:"Sind sie sicher?",text:"Wollen Sie das Dokument und alle erstellten Signaturen zurücksetzen?",icon:"question",showCancelButton:!0});if(n.isConfirmed){const n=await deleteAnnotations(this.pdfKit)}return n}fakeElementId=0;}
|
||||||
11
EnvelopeGenerator.Web/wwwroot/js/markdown.js
Normal file
11
EnvelopeGenerator.Web/wwwroot/js/markdown.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
marked.use({
|
||||||
|
async: true,
|
||||||
|
breaks: true,
|
||||||
|
gfm: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
for (const el of document.querySelectorAll('.markdown')) {
|
||||||
|
el.innerHTML = await marked.parse(el.textContent.replace(/(\t| )/g, " "));
|
||||||
|
}
|
||||||
|
})();
|
||||||
1
EnvelopeGenerator.Web/wwwroot/js/markdown.min.js
vendored
Normal file
1
EnvelopeGenerator.Web/wwwroot/js/markdown.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
marked.use({"async":!0,breaks:!0,gfm:!0});(async()=>{for(const n of document.querySelectorAll(".markdown"))n.innerHTML=await marked.parse(n.textContent.replace(/(\t| )/g," "))})();
|
||||||
@@ -13,3 +13,14 @@ function detailedCurrentDate() {
|
|||||||
timeZoneName: 'shortOffset'
|
timeZoneName: 'shortOffset'
|
||||||
}).format();
|
}).format();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findNearest(origin, getX, getY, dests) {
|
||||||
|
const distanceToOrigin = (point) => Math.sqrt((getX(origin) - getX(point))**2 + (getY(origin) - getY(point))**2);
|
||||||
|
return dests.reduce(
|
||||||
|
(nearest, dest) => {
|
||||||
|
const dist = distanceToOrigin(dest);
|
||||||
|
return dist < nearest.dist ? {dist, dest} : nearest;
|
||||||
|
},
|
||||||
|
{dist: Infinity, dest: null}
|
||||||
|
).dest;
|
||||||
|
}
|
||||||
2
EnvelopeGenerator.Web/wwwroot/js/util.min.js
vendored
2
EnvelopeGenerator.Web/wwwroot/js/util.min.js
vendored
@@ -1 +1 @@
|
|||||||
function detailedCurrentDate(){return new Intl.DateTimeFormat("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}const B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer,getLocaleDateString=()=>(new Date).toLocaleDateString("de-DE");
|
function detailedCurrentDate(){return new Intl.DateTimeFormat("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:"shortOffset"}).format()}function findNearest(n,t,i,r){const u=r=>Math.sqrt((t(n)-t(r))**2+(i(n)-i(r))**2);return r.reduce((n,t)=>{const i=u(t);return i<n.dist?{dist:i,dest:t}:n},{dist:Infinity,dest:null}).dest}const B64ToBuff=n=>new Uint8Array(Array.from(atob(n),n=>n.charCodeAt(0))).buffer,getLocaleDateString=()=>(new Date).toLocaleDateString("de-DE");
|
||||||
8
EnvelopeGenerator.Web/wwwroot/lib/marked/marked.umd.min.js
vendored
Normal file
8
EnvelopeGenerator.Web/wwwroot/lib/marked/marked.umd.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -55,8 +55,8 @@ Global
|
|||||||
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.ActiveCfg = Debug|Any CPU
|
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.Build.0 = Debug|Any CPU
|
{5E0E17C0-FF5A-4246-BF87-1ADD85376A27}.Release|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
{83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Release|Any CPU
|
{83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.ActiveCfg = Debug|Any CPU
|
{83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.Build.0 = Debug|Any CPU
|
{83ED2617-B398-4859-8F59-B38F8807E83E}.Release|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{4F32A98D-E6F0-4A09-BD97-1CF26107E837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{4F32A98D-E6F0-4A09-BD97-1CF26107E837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
|||||||
Reference in New Issue
Block a user