Compare commits

..

1 Commits

Author SHA1 Message Date
1f745ae79c refactor(pdfburner): simplify form field handling and improve default field naming
- Replaced ImmutableDictionary-based FormFieldIndex with a simpler Dictionary
- Updated form field ordering to: NoName, signature, position, city, date
- Removed manual formFieldIndex counter, now using dictionary lookup by fieldName
- Introduced FieldNames class with NoName constant (guid-based) for unnamed fields
- Defaulted Annotation.fieldName to FieldNames.NoName instead of Nothing
2025-10-09 18:59:18 +02:00
53 changed files with 296 additions and 1266 deletions

View File

@@ -1,73 +0,0 @@
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; }
}

View File

@@ -82,7 +82,7 @@ public record EnvelopeDto
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool UseAccessCode { get; set; } = true; public bool? UseAccessCode { get; set; }
/// <summary> /// <summary>
/// ///

View File

@@ -35,7 +35,6 @@ 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>();
@@ -51,8 +50,6 @@ 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

View File

@@ -1,20 +1,12 @@
using EnvelopeGenerator.Application.Common.Dto; using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
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>
@@ -24,7 +16,7 @@ public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeRece
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public PsPdfKitAnnotation PsPdfKitAnnotation { get; init; } = null!; public required ExpandoObject Annotations { get; init; }
/// <summary> /// <summary>
/// ///
@@ -48,41 +40,17 @@ 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="psPdfKitAnnotation"></param> /// <param name="annotations"></param>
/// <returns>A new <see cref="DocSignedNotification"/> instance.</returns> /// <returns>A new <see cref="DocSignedNotification"/> instance.</returns>
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, PsPdfKitAnnotation psPdfKitAnnotation) public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, ExpandoObject annotations)
=> new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation }; => new(dto) { Annotations = annotations };
/// <summary> /// <summary>
/// /// Asynchronously converts a <see cref="Task{EnvelopeReceiverDto}"/> to a <see cref="DocSignedNotification"/>.
/// </summary> /// </summary>
/// <param name="dtoTask"></param> /// <param name="dtoTask">The task that returns the DTO to convert.</param>
/// <param name="psPdfKitAnnotation"></param> /// <param name="annotations"></param>
/// <returns></returns> /// <returns>A task that represents the asynchronous conversion operation.</returns>
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, PsPdfKitAnnotation psPdfKitAnnotation) public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, ExpandoObject annotations)
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation } : null; => await dtoTask is EnvelopeReceiverDto dto ? new(dto) { Annotations = annotations } : 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;
}
}
} }

View File

@@ -1,6 +1,7 @@
using DigitalData.Core.Abstraction.Application.Repository; using EnvelopeGenerator.Application.DocStatus.Commands;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Constants;
using MediatR; using MediatR;
using System.Text.Json;
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers; namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
@@ -9,18 +10,15 @@ namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
/// </summary> /// </summary>
public class AnnotationHandler : INotificationHandler<DocSignedNotification> public class AnnotationHandler : INotificationHandler<DocSignedNotification>
{ {
/// <summary> private readonly ISender _sender;
///
/// </summary>
private readonly IRepository<ElementAnnotation> _repo;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="repository"></param> /// <param name="sender"></param>
public AnnotationHandler(IRepository<ElementAnnotation> repository) public AnnotationHandler(ISender sender)
{ {
_repo = repository; _sender = sender;
} }
/// <summary> /// <summary>
@@ -29,6 +27,13 @@ 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 Task Handle(DocSignedNotification notification, CancellationToken cancel) public async 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);
}
} }

View File

@@ -1,39 +0,0 @@
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);
}
}

View File

@@ -2,6 +2,7 @@
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;

View File

@@ -1,5 +1,4 @@
using DigitalData.Core.Abstraction.Application.Repository; using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Domain.Entities;
using MediatR; using MediatR;
namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers; namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
@@ -9,13 +8,13 @@ namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Han
/// </summary> /// </summary>
public class RemoveAnnotationHandler : INotificationHandler<RemoveSignatureNotification> public class RemoveAnnotationHandler : INotificationHandler<RemoveSignatureNotification>
{ {
private readonly IRepository<ElementAnnotation> _repo; private readonly IRepository<Domain.Entities.DocumentStatus> _repo;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="repository"></param> /// <param name="repository"></param>
public RemoveAnnotationHandler(IRepository<ElementAnnotation> repository) public RemoveAnnotationHandler(IRepository<Domain.Entities.DocumentStatus> repository)
{ {
_repo = repository; _repo = repository;
} }
@@ -26,28 +25,8 @@ public class RemoveAnnotationHandler : INotificationHandler<RemoveSignatureNotif
/// <param name="notification"></param> /// <param name="notification"></param>
/// <param name="cancel"></param> /// <param name="cancel"></param>
/// <returns></returns> /// <returns></returns>
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel) public async Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
{ {
notification.ThrowIfHasNoFilter(); await _repo.DeleteAsync(s => s.Envelope!.Uuid == notification.EnvelopeUuid, cancel);
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);
} }
} }

View File

@@ -1,53 +0,0 @@
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);
}
}

View File

@@ -1,7 +1,9 @@
using DigitalData.Core.Abstraction.Application.Repository; using DigitalData.Core.Abstraction.Application.Repository;
using EnvelopeGenerator.Application.Common.Extensions; using EnvelopeGenerator.Application.Common.Extensions;
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.RemoveSignature.Handlers; namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature.Handlers;
@@ -27,30 +29,12 @@ public class RemoveHistoryHandler : INotificationHandler<RemoveSignatureNotifica
/// <param name="notification"></param> /// <param name="notification"></param>
/// <param name="cancel"></param> /// <param name="cancel"></param>
/// <returns></returns> /// <returns></returns>
public Task Handle(RemoveSignatureNotification notification, CancellationToken cancel) public async Task Handle(RemoveSignatureNotification notification, CancellationToken cancel)
{ {
notification.ThrowIfHasNoFilter(); await _repo.DeleteAsync(hists
return _repo.DeleteAsync(hists => => hists
{ .Where(hist => hist.Envelope!.Uuid == notification.EnvelopeUuid)
hists = hists.Where(hist => hist.Status == EnvelopeStatus.DocumentSigned); .Where(hist => hist.Status == EnvelopeStatus.DocumentSigned),
cancel);
// 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);
} }
} }

View File

@@ -5,33 +5,5 @@ namespace EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="EnvelopeId"></param>
/// <param name="ReceiverId"></param>
/// <param name="EnvelopeUuid"></param> /// <param name="EnvelopeUuid"></param>
/// <param name="ReceiverSignature"></param> public record RemoveSignatureNotification(string EnvelopeUuid) : INotification;
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.");
}
}

View File

@@ -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.4.0" /> <PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
<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" />

View File

@@ -1,101 +0,0 @@
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);
}
}

View File

@@ -1,60 +0,0 @@
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; }
}

View File

@@ -1,10 +1,7 @@
using AutoMapper; using EnvelopeGenerator.Application.Common.Dto.History;
using DigitalData.Core.Abstraction.Application.Repository; using EnvelopeGenerator.Domain.Constants;
using DigitalData.Core.Exceptions;
using EnvelopeGenerator.Application.Common.Dto.History;
using MediatR; using MediatR;
using EnvelopeGenerator.Domain.Entities; using System.ComponentModel.DataAnnotations;
using Microsoft.EntityFrameworkCore;
namespace EnvelopeGenerator.Application.Histories.Queries; namespace EnvelopeGenerator.Application.Histories.Queries;
@@ -12,81 +9,21 @@ 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 : HistoryQueryBase, IRequest<IEnumerable<HistoryDto>> public record ReadHistoryQuery : 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);
}
} }

View File

@@ -0,0 +1,47 @@
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);
}
}

View File

@@ -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.4.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="DigitalData.Core.Abstraction.Application, Version=1.3.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath> <HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.3.5\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
</Reference> </Reference>
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="DigitalData.Core.Abstractions, Version=4.1.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath> <HintPath>..\packages\DigitalData.Core.Abstractions.4.1.1\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>

View File

@@ -5,10 +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 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=;"
@@ -24,15 +24,10 @@ 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 _ Factory.Shared.AddEnvelopeGeneratorInfrastructureServices(
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _
.AddEnvelopeGeneratorInfrastructureServices(
Sub(opt) Sub(opt)
opt.AddDbTriggerParams( opt.AddDbTriggerParams(
Sub(triggers) Sub(triggers)
@@ -45,7 +40,7 @@ Public Class frmFinalizePDF
End Sub) End Sub)
opt.AddDbContext( opt.AddDbContext(
Sub(options) Sub(options)
options.UseSqlServer(dCnnStr) _ options.UseSqlServer(CONNECTIONSTRING) _
.EnableSensitiveDataLogging() _ .EnableSensitiveDataLogging() _
.EnableDetailedErrors() .EnableDetailedErrors()
End Sub) End Sub)
@@ -101,9 +96,8 @@ Public Class frmFinalizePDF
Select(Function(r As DataRow) r.Item("VALUE").ToString()). Select(Function(r As DataRow) r.Item("VALUE").ToString()).
ToList() ToList()
Dim envelopeId As Integer = CInt(txtEnvelope.Text) Dim oBuffer As Byte() = ReadEnvelope(CInt(txtEnvelope.Text))
Dim oBuffer As Byte() = ReadEnvelope(envelopeId) Dim oNewBuffer = PDFBurner.BurnInstantJSONAnnotationsToPDF(oBuffer, oJsonList)
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")

View File

@@ -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.4.0" targetFramework="net462" /> <package id="DigitalData.Core.Abstraction.Application" version="1.3.5" targetFramework="net462" />
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" /> <package id="DigitalData.Core.Abstractions" version="4.1.1" 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" />

View File

@@ -72,12 +72,11 @@
<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.4.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="DigitalData.Core.Abstraction.Application, Version=1.3.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.4.0\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath> <HintPath>..\packages\DigitalData.Core.Abstraction.Application.1.3.5\lib\net462\DigitalData.Core.Abstraction.Application.dll</HintPath>
</Reference> </Reference>
<Reference Include="DigitalData.Core.Abstractions, Version=4.3.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="DigitalData.Core.Abstractions, Version=4.1.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\DigitalData.Core.Abstractions.4.3.0\lib\net462\DigitalData.Core.Abstractions.dll</HintPath> <HintPath>..\packages\DigitalData.Core.Abstractions.4.1.1\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>

View File

@@ -14,7 +14,6 @@ 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
@@ -70,9 +69,7 @@ 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 _ Factory.Shared.AddEnvelopeGeneratorInfrastructureServices(
.BehaveOnPostBuild(PostBuildBehavior.Ignore) _
.AddEnvelopeGeneratorInfrastructureServices(
Sub(opt) Sub(opt)
opt.AddDbTriggerParams( opt.AddDbTriggerParams(
Sub(triggers) Sub(triggers)
@@ -406,6 +403,7 @@ 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
@@ -418,7 +416,7 @@ Namespace Jobs
End Try End Try
End If End If
Return PDFBurner.BurnAnnotsToPDF(oInputDocumentBuffer, oAnnotations, pEnvelopeData.EnvelopeId) Return PDFBurner.BurnInstantJSONAnnotationsToPDF(oInputDocumentBuffer, oAnnotations)
End Function End Function
Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData Private Function GetEnvelopeData(pEnvelopeId As Integer) As EnvelopeData

View File

@@ -2,15 +2,10 @@
Imports System.Drawing Imports System.Drawing
Imports System.IO Imports System.IO
Imports DevExpress.DataProcessing 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 EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument.FinalizeDocumentExceptions Imports EnvelopeGenerator.CommonServices.Jobs.FinalizeDocument.FinalizeDocumentExceptions
Imports EnvelopeGenerator.Domain.Entities
Imports EnvelopeGenerator.PdfEditor
Imports GdPicture14 Imports GdPicture14
Imports Microsoft.EntityFrameworkCore
Imports Newtonsoft.Json Imports Newtonsoft.Json
Namespace Jobs.FinalizeDocument Namespace Jobs.FinalizeDocument
@@ -20,6 +15,9 @@ 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)
@@ -33,94 +31,7 @@ Namespace Jobs.FinalizeDocument
_pdfBurnerParams = pdfBurnerParams _pdfBurnerParams = pdfBurnerParams
End Sub End Sub
#Region "Burn PDF" Public Function BurnInstantJSONAnnotationsToPDF(pSourceBuffer As Byte(), pInstantJSONList As List(Of String)) As Byte()
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
@@ -157,25 +68,40 @@ Namespace Jobs.FinalizeDocument
End Using End Using
End Using End Using
End Function End Function
#End Region
#Region "Add Value" Public Shared ReadOnly FormFieldIndex As New Dictionary(Of String, Integer) From {
{FieldNames.NoName, 0},
{"signature", 1},
{"position", 2},
{"city", 3},
{"date", 4}
}
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
Dim isSeal = True 'First element is signature seal
For Each oAnnotation In oAnnotationData.annotations For Each oAnnotation In oAnnotationData.annotations
Logger.Debug("Adding AnnotationID: " + oAnnotation.id) Logger.Debug("Adding AnnotationID: " + oAnnotation.id)
Select Case oAnnotation.type Select Case oAnnotation.type
Case AnnotationType.Image Case ANNOTATION_TYPE_IMAGE
If (isSeal) Then
oAnnotation.bbox.Item(1) = yPosOfSigAnnot
End If
AddImageAnnotation(oAnnotation, oAnnotationData.attachments) AddImageAnnotation(oAnnotation, oAnnotationData.attachments)
Exit Select Exit Select
Case AnnotationType.Ink
Case ANNOTATION_TYPE_INK
AddInkAnnotation(oAnnotation) AddInkAnnotation(oAnnotation)
Exit Select Exit Select
Case AnnotationType.Widget
Case ANNOTATION_TYPE_WIDGET
'Add form field values 'Add form field values
Dim formFieldValue = oAnnotationData.formFieldValues.FirstOrDefault(Function(fv) fv.name = oAnnotation.id) Dim formFieldValue = oAnnotationData.formFieldValues.FirstOrDefault(Function(fv) fv.name = oAnnotation.id)
If formFieldValue IsNot Nothing AndAlso Not _pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value) Then If formFieldValue IsNot Nothing AndAlso Not _pdfBurnerParams.IgnoredLabels.Contains(formFieldValue.value) Then
@@ -183,16 +109,14 @@ Namespace Jobs.FinalizeDocument
End If End If
Exit Select Exit Select
End Select End Select
isSeal = False
Next Next
End Sub End Sub
Private Sub AddImageAnnotation(x As Double, y As Double, width As Double, height As Double, page As Integer, base64 As String) Private Function AddImageAnnotation(pAnnotation As Annotation, pAttachments As Dictionary(Of String, Attachment)) As Void
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()
@@ -206,26 +130,9 @@ 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 Sub End Function
Private Sub AddInkAnnotation(page As Integer, value As String) Private Function AddInkAnnotation(pAnnotation As Annotation) As Void
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)
@@ -237,29 +144,17 @@ Namespace Jobs.FinalizeDocument
Manager.AddFreeHandAnnot(oColor, oPoints) Manager.AddFreeHandAnnot(oColor, oPoints)
Next Next
End Sub End Function
Private Sub AddFormFieldValue(x As Double, y As Double, width As Double, height As Double, page As Integer, value As String) Private Function AddFormFieldValue(pAnnotation As Annotation, formFieldValue As FormFieldValue) As Void
Manager.SelectPage(page)
' Add the text annotation Dim index As Integer = FormFieldIndex(pAnnotation.fieldName)
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)
' 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 * ffIndex + _pdfBurnerParams.TopMargin Dim oY = oBounds.Item(1) + _pdfBurnerParams.YOffset * Index + _pdfBurnerParams.TopMargin
Dim oWidth = oBounds.Item(2) Dim oWidth = oBounds.Item(2)
Dim oHeight = oBounds.Item(3) Dim oHeight = oBounds.Item(3)
@@ -272,10 +167,8 @@ Namespace Jobs.FinalizeDocument
ant.FontSize = _pdfBurnerParams.FontSize ant.FontSize = _pdfBurnerParams.FontSize
ant.FontStyle = _pdfBurnerParams.FontStyle ant.FontStyle = _pdfBurnerParams.FontStyle
Manager.SaveAnnotationsToPage() Manager.SaveAnnotationsToPage()
End Sub End Function
#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))
@@ -288,15 +181,6 @@ 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)
@@ -333,17 +217,17 @@ Namespace Jobs.FinalizeDocument
Public index As Integer = Nothing Public index As Integer = Nothing
Public egName As String = PDFBurner.EGName.NoName Public fieldName As String = FieldNames.NoName
Public hasStructuredID As Boolean = False Public hasStructuredID As Boolean = False
Public ReadOnly Property isLabel As Boolean Public ReadOnly Property isLabel As Boolean
Get Get
If String.IsNullOrEmpty(egName) Then If String.IsNullOrEmpty(fieldName) Then
Return False Return False
End If End If
Dim parts As String() = egName.Split("_"c) Dim parts As String() = fieldName.Split("_"c)
Return parts.Length > 1 AndAlso parts(1) = "label" Return parts.Length > 1 AndAlso parts(1) = "label"
End Get End Get
End Property End Property
@@ -378,7 +262,7 @@ Namespace Jobs.FinalizeDocument
Throw New BurnAnnotationException($"The index of annotation is not integer. Id: {_id}") Throw New BurnAnnotationException($"The index of annotation is not integer. Id: {_id}")
End If End If
egName = parts(3) fieldName = parts(3)
hasStructuredID = True hasStructuredID = True
End Set End Set
@@ -399,25 +283,8 @@ Namespace Jobs.FinalizeDocument
Public Property strokeColor As String Public Property strokeColor As String
End Class End Class
Friend Class Ink Public Class FieldNames
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 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 End Class
Friend Class Lines Friend Class Lines
@@ -433,6 +300,5 @@ 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

View File

@@ -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.4.0" targetFramework="net462" /> <package id="DigitalData.Core.Abstraction.Application" version="1.3.5" targetFramework="net462" />
<package id="DigitalData.Core.Abstractions" version="4.3.0" targetFramework="net462" /> <package id="DigitalData.Core.Abstractions" version="4.1.1" 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" />

View File

@@ -1,5 +1,4 @@
using EnvelopeGenerator.Domain.Interfaces; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
#if NETFRAMEWORK #if NETFRAMEWORK
using System.Drawing; using System.Drawing;
@@ -15,7 +14,7 @@ namespace EnvelopeGenerator.Domain.Entities
#endif #endif
[Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")] [Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")]
public class Document : IHasEnvelope public class Document
{ {
public Document() public Document()
{ {
@@ -31,50 +30,27 @@ public class Document : IHasEnvelope
[Required] [Required]
[Column("ENVELOPE_ID")] [Column("ENVELOPE_ID")]
public int EnvelopeId { get; set; } public int EnvelopeId { get; set; } = 0;
#if NETFRAMEWORK
= 0;
#endif
[Column("BYTE_DATA", TypeName = "varbinary(max)")] [Column("BYTE_DATA", TypeName = "varbinary(max)")]
public byte[] public byte[] ByteData { get; set; }
#if NET
?
#endif
ByteData { get; set; }
#region File public List<Signature> Elements { get; set; }
[Column("FILENAME", TypeName = "nvarchar(256)")]
public string Filename { get; set; }
[Column("FILEPATH", TypeName = "nvarchar(256)")] // TODO: * Check the Form App and remove the default value
[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; }

View File

@@ -1,92 +0,0 @@
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

View File

@@ -4,7 +4,6 @@ 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
@@ -15,7 +14,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, IHasReceiver public class Signature : ISignature
{ {
public Signature() public Signature()
{ {
@@ -108,17 +107,7 @@ public class Signature : ISignature, IHasReceiver
public virtual Document Document { get; set; } public virtual Document Document { get; set; }
[ForeignKey("ReceiverId")] [ForeignKey("ReceiverId")]
public virtual Receiver public virtual Receiver Receiver { get; set; }
#if NET
?
#endif
Receiver { get; set; }
public virtual IEnumerable<ElementAnnotation>
#if NET
?
#endif
Annotations { get; set; }
#if NETFRAMEWORK #if NETFRAMEWORK
[NotMapped] [NotMapped]

View File

@@ -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.3.0" /> <PackageReference Include="DigitalData.Core.Abstractions" Version="4.1.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -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-3.0.8.0" newVersion="3.0.8.0" /> <bindingRedirect oldVersion="0.0.0.0-4.55.0.0" newVersion="4.55.0.0" />
</dependentAssembly> </dependentAssembly>
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />

View File

@@ -11,6 +11,7 @@ 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
@@ -39,7 +40,7 @@ public abstract class EGDbContextBase : DbContext
, IUserManagerDbContext, IMailDbContext , IUserManagerDbContext, IMailDbContext
#endif #endif
{ {
public DbSet<Config> Configs { get; set; } public DbSet<Domain.Entities.Config> Configs { get; set; }
public DbSet<EnvelopeReceiver> EnvelopeReceivers { get; set; } public DbSet<EnvelopeReceiver> EnvelopeReceivers { get; set; }
@@ -97,6 +98,27 @@ 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)
@@ -125,7 +147,7 @@ public abstract class EGDbContextBase : DbContext
modelBuilder.Entity<Envelope>() modelBuilder.Entity<Envelope>()
.HasMany(e => e.Documents) .HasMany(e => e.Documents)
.WithOne(d => d.Envelope) .WithOne()
.HasForeignKey(ed => ed.EnvelopeId); .HasForeignKey(ed => ed.EnvelopeId);
modelBuilder.Entity<Envelope>() modelBuilder.Entity<Envelope>()
@@ -193,13 +215,6 @@ 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

View File

@@ -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.4.0" /> <PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
<PackageReference Include="DigitalData.Core.Infrastructure" Version="2.4.5" /> <PackageReference Include="DigitalData.Core.Infrastructure" Version="2.4.3" />
<PackageReference Include="QuestPDF" Version="2025.7.1" /> <PackageReference Include="QuestPDF" Version="2025.7.1" />
</ItemGroup> </ItemGroup>

View File

@@ -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 DigitalData.Core.Abstractions.Interfaces; using iText.Kernel.Geom;
#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,15 +19,6 @@ 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
@@ -40,18 +31,13 @@ namespace EnvelopeGenerator.PdfEditor
private readonly PdfReader _reader; private readonly PdfReader _reader;
private readonly PdfWriter _writer; private readonly PdfWriter _writer;
private readonly bool _disposeInputStream; public Pdf(TInputStream inputStream, TOutputStream outputStream)
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>
@@ -102,7 +88,7 @@ namespace EnvelopeGenerator.PdfEditor
}); });
#endregion #endregion
public Pdf<TInputStream, TOutputStream> Background<TSignature>(IEnumerable<TSignature> signatures, double widthPx = 1.9500000000000002, double heightPx = 2.52) public Pdf<TInputStream, TOutputStream> Background<TSignature>(IEnumerable<TSignature> signatures)
where TSignature : ISignature where TSignature : ISignature
{ {
// once per page // once per page
@@ -120,8 +106,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 = widthPx * inchFactor; double width = 1.9500000000000002 * inchFactor;
double height = heightPx * inchFactor; double height = 2.52 * inchFactor;
double bottomLineLength = 2.5; double bottomLineLength = 2.5;
@@ -163,16 +149,16 @@ namespace EnvelopeGenerator.PdfEditor
{ {
// Managed resources // Managed resources
_doc?.Close(); _doc?.Close();
if (_disposeInputStream) _inputStream?.Dispose(); _inputStream?.Dispose();
if(_disposeOutputStream) _outputStream?.Dispose(); _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 { if(_disposeInputStream) _inputStream?.Dispose(); } catch { } try { _inputStream?.Dispose(); } catch { }
try { if (_disposeOutputStream) _outputStream?.Dispose(); } catch { } try { _outputStream?.Dispose(); } catch { }
} }
_disposed = true; _disposed = true;
@@ -184,21 +170,15 @@ namespace EnvelopeGenerator.PdfEditor
return; return;
_doc?.Close(); _doc?.Close();
if (_disposeInputStream) if (_inputStream is IAsyncDisposable asyncInput)
{ await asyncInput.DisposeAsync();
if (_inputStream is IAsyncDisposable asyncInput) else
await asyncInput.DisposeAsync(); _inputStream.Dispose();
else
_inputStream.Dispose();
}
if (_disposeOutputStream) if (_outputStream is IAsyncDisposable asyncOutput)
{ await asyncOutput.DisposeAsync();
if (_outputStream is IAsyncDisposable asyncOutput) else
await asyncOutput.DisposeAsync(); _outputStream?.Dispose();
else
_outputStream?.Dispose();
}
_disposed = true; _disposed = true;
GC.SuppressFinalize(this); GC.SuppressFinalize(this);

View File

@@ -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-7.0.0.0" newVersion="7.0.0.0" /> <bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.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" />

View File

@@ -17,21 +17,6 @@
<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>
@@ -69,9 +54,6 @@
<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>
@@ -178,14 +160,8 @@
<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.DependencyInjection, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL"> <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.7.0.0\lib\net462\Microsoft.Extensions.DependencyInjection.dll</HintPath> <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.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>
@@ -359,18 +335,6 @@
<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">

View File

@@ -1,16 +0,0 @@
<?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>

View File

@@ -1,7 +1,6 @@
<?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" />
@@ -12,9 +11,7 @@
<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.DependencyInjection" version="7.0.0" targetFramework="net462" /> <package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" 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" />

View File

@@ -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.4.0" /> <PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.3.5" />
<PackageReference Include="DigitalData.Core.Abstractions" Version="4.3.0" /> <PackageReference Include="DigitalData.Core.Abstractions" Version="4.1.1" />
<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" />

View File

@@ -4,7 +4,6 @@ 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;
@@ -12,6 +11,7 @@ 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] PsPdfKitAnnotation psPdfKitAnnotation, CancellationToken cancel = default) public async Task<IActionResult> CreateOrUpdate([FromBody] ExpandoObject annotations, CancellationToken cancel = default)
{ {
// get claims // get claims
var signature = User.GetAuthReceiverSignature(); var signature = User.GetAuthReceiverSignature();
@@ -58,22 +58,20 @@ 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: 409); return Problem(statusCode: 403);
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(psPdfKitAnnotation) .ToDocSignedNotification(annotations)
?? throw new NotFoundException("Envelope receiver is not found."); ?? throw new NotFoundException("Envelope receiver is not found.");
await _mediator.PublishSafely(docSignedNotification, cancel); await _mediator.Publish(docSignedNotification, cancel);
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return Ok(); return Ok();
} }
[Authorize(Roles = ReceiverRole.FullyAuth)] [Authorize(Roles = ReceiverRole.FullyAuth)]
[HttpPost("reject")] [HttpPost("reject")]
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")] [Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]

View File

@@ -95,23 +95,6 @@ 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)
@@ -138,7 +121,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, CancellationToken cancel) public async Task<IActionResult> LogInEnvelope([FromRoute] string envelopeReceiverId, [FromForm] Auth auth)
{ {
try try
{ {
@@ -162,15 +145,6 @@ 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);
@@ -216,7 +190,7 @@ public class EnvelopeController : ViewControllerBase
return this.ViewInnerServiceError(); return this.ViewInnerServiceError();
} }
} }
private async Task<IActionResult> CreateEnvelopeLockedView(EnvelopeReceiverDto er, CancellationToken cancel) private async Task<IActionResult> CreateEnvelopeLockedView(EnvelopeReceiverDto er, CancellationToken cancel)
{ {
var uuidClaim = User.GetAuthEnvelopeUuid(); var uuidClaim = User.GetAuthEnvelopeUuid();

View File

@@ -9,7 +9,7 @@ namespace EnvelopeGenerator.Web.Controllers.Test;
[ApiController] [ApiController]
public class TestAnnotationController : ControllerBase public class TestAnnotationController : ControllerBase
{ {
private readonly IMediator _mediator; private IMediator _mediator;
public TestAnnotationController(IMediator mediator) public TestAnnotationController(IMediator mediator)
{ {
@@ -19,17 +19,12 @@ public class TestAnnotationController : ControllerBase
[HttpDelete("{envelopeKey}")] [HttpDelete("{envelopeKey}")]
public async Task<IActionResult> Delete([FromRoute] string envelopeKey) public async Task<IActionResult> Delete([FromRoute] string envelopeKey)
{ {
if (envelopeKey.GetEnvelopeUuid() is not string uuid) var uuid = envelopeKey.GetEnvelopeUuid();
if (uuid == null)
return BadRequest(); return BadRequest();
if (envelopeKey.GetReceiverSignature() is not string signature) await _mediator.Publish(new RemoveSignatureNotification(uuid));
return BadRequest();
await _mediator.Publish(new RemoveSignatureNotification()
{
EnvelopeUuid = uuid,
ReceiverSignature = signature
});
return Ok(); return Ok();
} }
} }

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks> <TargetFramework>net7.0</TargetFramework>
<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.7.0</Version> <Version>3.4.1</Version>
<AssemblyVersion>3.7.0</AssemblyVersion> <AssemblyVersion>3.4.1</AssemblyVersion>
<FileVersion>3.7.0</FileVersion> <FileVersion>3.4.1</FileVersion>
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright> <Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
</PropertyGroup> </PropertyGroup>
@@ -2094,13 +2094,20 @@
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" /> <None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'"> <ItemGroup>
<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" />
@@ -2119,56 +2126,6 @@
<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" />

View File

@@ -11,10 +11,12 @@ 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\net8\$(Version)\EnvelopeGenerator.Web.zip</DesktopBuildPackageLocation> <DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\signFLOW\Web\net9\win64\$(Version)\EnvelopeGenerator.Web.zip</DesktopBuildPackageLocation>
<PackageAsSingleFile>true</PackageAsSingleFile> <PackageAsSingleFile>true</PackageAsSingleFile>
<DeployIisAppPath>EnvelopeGenerator</DeployIisAppPath> <DeployIisAppPath>EnvelopeGenerator</DeployIisAppPath>
<_TargetId>IISWebDeployPackage</_TargetId> <_TargetId>IISWebDeployPackage</_TargetId>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View File

@@ -79,7 +79,7 @@
} }
else else
{ {
<div class="markdown">@(envelope?.Message)</div> <h6>@($"{@envelope?.Message}")</h6>
} }
<p> <p>
<small class="text-body-secondary"> <small class="text-body-secondary">

View File

@@ -49,7 +49,6 @@
<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>
@@ -96,6 +95,5 @@
</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>

View File

@@ -41,12 +41,6 @@
"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": [

View File

@@ -1,5 +1,7 @@
function generateId(envelopeId, receiverId, elementId, annotationType) { let __elementIndex = 0;
return `${envelopeId}#${receiverId}#${elementId}#${annotationType}`;
function generateId(envelopeId, receiverId, annotationType) {
return `${envelopeId}#${receiverId}#${__elementIndex++}#${annotationType}`;
} }
async function createAnnotations(document, envelopeId, receiverId) { async function createAnnotations(document, envelopeId, receiverId) {
@@ -10,7 +12,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
const page = element.page - 1 const page = element.page - 1
//#region signatures //#region signatures
const id = generateId(envelopeId, receiverId, element.id, 'signature'); const id = generateId(envelopeId, receiverId, 'signature');
const annotation = new PSPDFKit.Annotations.WidgetAnnotation({ const annotation = new PSPDFKit.Annotations.WidgetAnnotation({
id: id, id: id,
pageIndex: page, pageIndex: page,
@@ -27,7 +29,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
//#endregion //#endregion
//#region position //#region position
const id_position = generateId(envelopeId, receiverId, element.id, 'position'); const id_position = generateId(envelopeId, receiverId, '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,
@@ -47,7 +49,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
//#endregion //#endregion
//#region city //#region city
const id_city = generateId(envelopeId, receiverId, element.id, 'city'); const id_city = generateId(envelopeId, receiverId, '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,
@@ -67,7 +69,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
//#endregion //#endregion
//#region date //#region date
const id_date = generateId(envelopeId, receiverId, element.id, 'date'); const id_date = generateId(envelopeId, receiverId, '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,
@@ -95,7 +97,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
this.markFieldAsCity(formFieldCity); this.markFieldAsCity(formFieldCity);
//#region date label //#region date label
const id_date_label = generateId(envelopeId, receiverId, element.id, 'date_label'); const id_date_label = generateId(envelopeId, receiverId, '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,
@@ -118,7 +120,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
//#endregion //#endregion
//#region city label //#region city label
const id_city_label = generateId(envelopeId, receiverId, element.id, 'city_label'); const id_city_label = generateId(envelopeId, receiverId, '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,
@@ -141,7 +143,7 @@ async function createAnnotations(document, envelopeId, receiverId) {
//#endregion //#endregion
//#region position label //#region position label
const id_position_label = generateId(envelopeId, receiverId, element.id, 'position_label'); const id_position_label = generateId(envelopeId, receiverId, '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,
@@ -217,9 +219,9 @@ function isSignature(annotation) {
return !!annotation.isSignature || annotation.description == 'FRAME' return !!annotation.isSignature || annotation.description == 'FRAME'
} }
function createImageAnnotation(boundingBox, pageIndex, imageAttachmentId, id) { function createImageAnnotation(boundingBox, pageIndex, imageAttachmentId, envelopeId, receiverId, annotationType) {
const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({ const frameAnnotation = new PSPDFKit.Annotations.ImageAnnotation({
id: id, id: generateId(envelopeId, receiverId, annotationType),
pageIndex: pageIndex, pageIndex: pageIndex,
isSignature: false, isSignature: false,
readOnly: true, readOnly: true,
@@ -307,81 +309,4 @@ 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
};
})
];
} }

View File

@@ -88,12 +88,9 @@ class App {
}), }),
annotation.pageIndex, annotation.pageIndex,
imageAttachmentId, imageAttachmentId,
generateId( this.envelopeReceiver.envelopeId,
this.envelopeReceiver.envelopeId, this.envelopeReceiver.receiverId,
this.envelopeReceiver.receiverId, 'signature'
this.fakeElementId--,
'signed'
)
) )
this.pdfKit.create(frameAnnotation) this.pdfKit.create(frameAnnotation)
@@ -183,8 +180,7 @@ 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))
@@ -249,13 +245,10 @@ class App {
// Export annotation data and save to database // Export annotation data and save to database
try { try {
const res = await signEnvelope({ const res = await signEnvelope(await iJSON);
instant: iJSON,
structured: mapSignature(iJSON)
});
if (!res.ok) { if (!res.ok) {
if (res.status === 409) { if (res.status === 403) {
Swal.fire({ Swal.fire({
title: 'Warnung', title: 'Warnung',
text: 'Umschlag ist nicht mehr verfügbar.', text: 'Umschlag ist nicht mehr verfügbar.',
@@ -263,17 +256,6 @@ 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()
} }
@@ -299,11 +281,15 @@ class App {
.map(a => a.toJS()) .map(a => a.toJS())
.filter(a => a.isSignature) .filter(a => a.isSignature)
return totalSignatures <= filtered.length if (totalSignatures > filtered.length) {
return false
} else {
return true
}
} }
async handleReset(event) { async handleReset(event) {
const result = Swal.fire({ const result = await 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',
@@ -316,6 +302,4 @@ class App {
return result return result
} }
fakeElementId = 0;
} }

View File

@@ -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,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(` 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.envelopeReceiver.envelopeId,this.envelopeReceiver.receiverId,"signature");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=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;} `)}},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}}

View File

@@ -1,11 +0,0 @@
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, "&emsp;"));
}
})();

View File

@@ -1 +0,0 @@
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,"&emsp;"))})();

View File

@@ -12,15 +12,4 @@ function detailedCurrentDate() {
second: '2-digit', second: '2-digit',
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;
} }

View File

@@ -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()}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"); 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");

File diff suppressed because one or more lines are too long

View File

@@ -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 = Debug|Any CPU {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Debug|Any CPU {83ED2617-B398-4859-8F59-B38F8807E83E}.Debug|Any CPU.Build.0 = Release|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