Compare commits
7 Commits
7919f02ffd
...
911c812b19
| Author | SHA1 | Date | |
|---|---|---|---|
| 911c812b19 | |||
| 8ae0f79365 | |||
| 0ca54fe1fe | |||
| a1d6b5347f | |||
| 6cc631111c | |||
| 9d6074874f | |||
| 26bdb0806d |
@@ -1,136 +0,0 @@
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Query;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Dynamic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Annotations.Commands;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record CreateAnnotationCommand : EnvelopeReceiverQueryBase, IRequest<IEnumerable<Signature>>
|
||||
{
|
||||
private static readonly JsonSerializerOptions SerializerOptions = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
PropertyNamingPolicy = null
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string PSPDFKitInstantJSON
|
||||
{
|
||||
set => PSPDFKitInstant = JsonSerializer.Deserialize<dynamic>(value, SerializerOptions) ?? new ExpandoObject();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ExpandoObject PSPDFKitInstant { get; set; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class CreateAnnotationCommandExtensions
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="envelopeKey"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public static Task<IEnumerable<Signature>> CreateAnnotation(this ISender sender, string envelopeKey, CancellationToken cancel = default)
|
||||
=> sender.Send(new CreateAnnotationCommand() { Key = envelopeKey }, cancel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class CreateAnnotationCommandHandler : IRequestHandler<CreateAnnotationCommand, IEnumerable<Signature>>
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private readonly IRepository<Signature> _signRepo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private readonly IRepository<Annotation> _annotRepo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="signRepo"></param>
|
||||
/// <param name="annotRepo"></param>
|
||||
public CreateAnnotationCommandHandler(IRepository<Signature> signRepo, IRepository<Annotation> annotRepo)
|
||||
{
|
||||
_signRepo = signRepo;
|
||||
_annotRepo = annotRepo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IEnumerable<Signature>> Handle(CreateAnnotationCommand request, CancellationToken cancel)
|
||||
{
|
||||
var query = _signRepo.Query;
|
||||
|
||||
#region Envelope Query
|
||||
if (request.Envelope.Id is int envelopeId)
|
||||
query = query.Where(annot => annot.Document.EnvelopeId == envelopeId);
|
||||
|
||||
if (request.Envelope.Uuid is string envelopeUuid)
|
||||
query = query.Where(annot => annot.Document.Envelope!.Uuid == envelopeUuid);
|
||||
#endregion
|
||||
|
||||
// Receiver Query
|
||||
query = query.Where(request.Receiver);
|
||||
|
||||
var elements = await query.ToListAsync(cancel);
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
var annots = ParsePSPDFKitInstant(request.PSPDFKitInstant, element.Id)
|
||||
.Select(annot => new Annotation()
|
||||
{
|
||||
ElementId = element.Id,
|
||||
Name = annot.Key,
|
||||
Value = annot.Value,
|
||||
AddedWhen = DateTime.UtcNow
|
||||
});
|
||||
|
||||
element.Annotations = await _annotRepo.CreateAsync(annots, cancel);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="instant"></param>
|
||||
/// <param name="elementId"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<string, string> ParsePSPDFKitInstant(ExpandoObject instant, int elementId)
|
||||
{
|
||||
Dictionary<string, string> annots = new();
|
||||
|
||||
// parse json here
|
||||
|
||||
return annots;
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,8 @@
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record AnnotationDto
|
||||
public record AnnotationCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
@@ -25,6 +20,22 @@ public record AnnotationDto
|
||||
/// </summary>
|
||||
public string Value { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string Type { get; init; } = null!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public record AnnotationDto : AnnotationCreateDto
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
@@ -51,6 +51,8 @@ public class MappingProfile : Profile
|
||||
CreateMap<ReceiverDto, Domain.Entities.Receiver>().ForMember(rcv => rcv.EnvelopeReceivers, rcvReadDto => rcvReadDto.Ignore());
|
||||
CreateMap<EnvelopeReceiverReadOnlyCreateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
CreateMap<EnvelopeReceiverReadOnlyUpdateDto, Domain.Entities.EnvelopeReceiverReadOnly>();
|
||||
CreateMap<AnnotationCreateDto, Annotation>()
|
||||
.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
|
||||
|
||||
// Messaging mappings
|
||||
// for GTX messaging
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Dto;
|
||||
using EnvelopeGenerator.Application.Common.Dto.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
using System.Dynamic;
|
||||
|
||||
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>
|
||||
@@ -16,7 +23,7 @@ public record DocSignedNotification(EnvelopeReceiverDto Original) : EnvelopeRece
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public required ExpandoObject Annotations { get; init; }
|
||||
public PsPdfKitAnnotation PsPdfKitAnnotation { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -40,17 +47,17 @@ public static class DocSignedNotificationExtensions
|
||||
/// Converts an <see cref="EnvelopeReceiverDto"/> to a <see cref="DocSignedNotification"/>.
|
||||
/// </summary>
|
||||
/// <param name="dto">The DTO to convert.</param>
|
||||
/// <param name="annotations"></param>
|
||||
/// <param name="psPdfKitAnnotation"></param>
|
||||
/// <returns>A new <see cref="DocSignedNotification"/> instance.</returns>
|
||||
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, ExpandoObject annotations)
|
||||
=> new(dto) { Annotations = annotations };
|
||||
public static DocSignedNotification ToDocSignedNotification(this EnvelopeReceiverDto dto, PsPdfKitAnnotation psPdfKitAnnotation)
|
||||
=> new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation };
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously converts a <see cref="Task{EnvelopeReceiverDto}"/> to a <see cref="DocSignedNotification"/>.
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="dtoTask">The task that returns the DTO to convert.</param>
|
||||
/// <param name="annotations"></param>
|
||||
/// <returns>A task that represents the asynchronous conversion operation.</returns>
|
||||
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, ExpandoObject annotations)
|
||||
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { Annotations = annotations } : null;
|
||||
/// <param name="dtoTask"></param>
|
||||
/// <param name="psPdfKitAnnotation"></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<DocSignedNotification?> ToDocSignedNotification(this Task<EnvelopeReceiverDto?> dtoTask, PsPdfKitAnnotation psPdfKitAnnotation)
|
||||
=> await dtoTask is EnvelopeReceiverDto dto ? new(dto) { PsPdfKitAnnotation = psPdfKitAnnotation } : null;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using EnvelopeGenerator.Application.Annotations.Commands;
|
||||
using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using MediatR;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
@@ -11,15 +12,15 @@ public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private readonly ISender _sender;
|
||||
private readonly IRepository<Annotation> _repo;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
public AnnotationHandler(ISender sender)
|
||||
/// <param name="repository"></param>
|
||||
public AnnotationHandler(IRepository<Annotation> repository)
|
||||
{
|
||||
_sender = sender;
|
||||
_repo = repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,11 +29,6 @@ public class AnnotationHandler : INotificationHandler<DocSignedNotification>
|
||||
/// <param name="notification"></param>
|
||||
/// <param name="cancel"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public Task Handle(DocSignedNotification notification, CancellationToken cancel) => _sender.Send(new CreateAnnotationCommand()
|
||||
{
|
||||
Envelope = new() { Id = notification.EnvelopeId },
|
||||
Receiver = new() { Id = notification.ReceiverId },
|
||||
PSPDFKitInstant = notification.Annotations
|
||||
}, cancel);
|
||||
}
|
||||
public Task Handle(DocSignedNotification notification, CancellationToken cancel)
|
||||
=> _repo.CreateAsync(notification.PsPdfKitAnnotation.Structured, cancel);
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public class DocStatusHandler : INotificationHandler<DocSignedNotification>
|
||||
{
|
||||
Envelope = new() { Id = notification.EnvelopeId },
|
||||
Receiver = new() { Id = notification.ReceiverId},
|
||||
Value = JsonSerializer.Serialize(notification.Annotations, Format.Json.ForAnnotations)
|
||||
Value = JsonSerializer.Serialize(notification.PsPdfKitAnnotation.Instant, Format.Json.ForAnnotations)
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
using EnvelopeGenerator.Application.Histories.Commands;
|
||||
using EnvelopeGenerator.Domain.Constants;
|
||||
using MediatR;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Common.Notifications.DocSigned.Handlers;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public class Annotation
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
[Column("GUID", TypeName = "int")]
|
||||
[Column("GUID", TypeName = "bigint")]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
|
||||
@@ -44,7 +44,7 @@ public class AnnotationController : ControllerBase
|
||||
|
||||
[Authorize(Roles = ReceiverRole.FullyAuth)]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateOrUpdate([FromBody] ExpandoObject annotations, CancellationToken cancel = default)
|
||||
public async Task<IActionResult> CreateOrUpdate([FromBody] PsPdfKitAnnotation psPdfKitAnnotation, CancellationToken cancel = default)
|
||||
{
|
||||
// get claims
|
||||
var signature = User.GetAuthReceiverSignature();
|
||||
@@ -62,7 +62,7 @@ public class AnnotationController : ControllerBase
|
||||
|
||||
var docSignedNotification = await _mediator
|
||||
.ReadEnvelopeReceiverAsync(uuid, signature, cancel)
|
||||
.ToDocSignedNotification(annotations)
|
||||
.ToDocSignedNotification(psPdfKitAnnotation)
|
||||
?? throw new NotFoundException("Envelope receiver is not found.");
|
||||
|
||||
await _mediator.Publish(docSignedNotification, cancel);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using EnvelopeGenerator.Application.Annotations.Commands;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Extensions;
|
||||
using EnvelopeGenerator.Application.Common.Notifications.RemoveSignature;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -28,11 +27,4 @@ public class TestAnnotationController : ControllerBase
|
||||
await _mediator.Publish(new RemoveSignatureNotification(uuid));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
[HttpPost("{envelopeKey}")]
|
||||
public async Task<IActionResult> Create([FromRoute] string envelopeKey, CancellationToken cancel)
|
||||
{
|
||||
var annot = await _mediator.CreateAnnotation(envelopeKey, cancel);
|
||||
return Ok(annot);
|
||||
}
|
||||
}
|
||||
@@ -317,34 +317,52 @@ function fixBase64(escapedBase64) {
|
||||
}
|
||||
|
||||
function mapSignature(iJSON) {
|
||||
return {
|
||||
formFields: iJSON.formFieldValues.filter(field => !field.name.includes("label")).map((field) => {
|
||||
return [
|
||||
// formFields
|
||||
...iJSON.formFieldValues.filter(field => !field.name.includes("label")).map((field) => {
|
||||
const nameParts = field.name.split('#');
|
||||
field.elementId = Number(nameParts[2]);
|
||||
field.name = nameParts[3];
|
||||
return field;
|
||||
return {
|
||||
elementId: Number(nameParts[2]),
|
||||
name: nameParts[3],
|
||||
value: field.value,
|
||||
type: field.type
|
||||
};
|
||||
}),
|
||||
frames: iJSON.annotations.filter(annot => annot.description === 'FRAME').map((annot) => {
|
||||
|
||||
// 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")));
|
||||
const idPartsOfPre = preElement.id.split('#');
|
||||
annot.elementId = Number(idPartsOfPre[2]);
|
||||
annot.name = 'frame';
|
||||
annot.value = fixBase64(iJSON.attachments[annot.imageAttachmentId]?.binary);
|
||||
return annot;
|
||||
return {
|
||||
elementId: Number(idPartsOfPre[2]),
|
||||
name: 'frame',
|
||||
value: fixBase64(iJSON.attachments[annot.imageAttachmentId]?.binary),
|
||||
type: annot.type
|
||||
};
|
||||
}),
|
||||
signatures: iJSON.annotations.filter(annot => annot.isSignature).map(annot => {
|
||||
|
||||
// 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")));
|
||||
const idPartsOfPre = preElement.id.split('#');
|
||||
|
||||
let value;
|
||||
if (annot.imageAttachmentId)
|
||||
annot.value = iJSON.attachments[annot.imageAttachmentId]?.binary;
|
||||
value = iJSON.attachments[annot.imageAttachmentId]?.binary;
|
||||
else if (annot.lines && annot.strokeColor)
|
||||
annot.value = JSON.stringify({
|
||||
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.");
|
||||
|
||||
annot.name = 'signature';
|
||||
return annot;
|
||||
return {
|
||||
elementId: Number(idPartsOfPre[2]),
|
||||
name: 'signature',
|
||||
value,
|
||||
type: annot.type
|
||||
};
|
||||
})
|
||||
};
|
||||
];
|
||||
}
|
||||
Reference in New Issue
Block a user