Compare commits

..

5 Commits

21 changed files with 250 additions and 74 deletions

View File

@@ -15,10 +15,10 @@ namespace EnvelopeGenerator.Application.Contracts
Task<bool> IsSigned(int envelopeId, string userReference); Task<bool> IsSigned(int envelopeId, string userReference);
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null); Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null);
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null); Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status); Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null);
} }
} }

View File

@@ -1,4 +1,7 @@
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory using DigitalData.UserManager.Application.DTOs.User;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
{ {
public record EnvelopeHistoryDto( public record EnvelopeHistoryDto(
long Id, long Id,
@@ -7,6 +10,8 @@
int Status, int Status,
DateTime AddedWhen, DateTime AddedWhen,
DateTime? ActionDate, DateTime? ActionDate,
UserCreateDto? Sender,
ReceiverDto? Receiver, ReceiverDto? Receiver,
ReferenceType ReferenceType,
string? Comment = null); string? Comment = null);
} }

View File

@@ -117,6 +117,9 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="and" xml:space="preserve">
<value>und</value>
</data>
<data name="Back" xml:space="preserve"> <data name="Back" xml:space="preserve">
<value>Zurück</value> <value>Zurück</value>
</data> </data>
@@ -144,6 +147,9 @@
<data name="Finalize" xml:space="preserve"> <data name="Finalize" xml:space="preserve">
<value>Abschließen</value> <value>Abschließen</value>
</data> </data>
<data name="Hello" xml:space="preserve">
<value>Hallo</value>
</data>
<data name="LocakedOpen" xml:space="preserve"> <data name="LocakedOpen" xml:space="preserve">
<value>Öffnen</value> <value>Öffnen</value>
</data> </data>
@@ -165,6 +171,12 @@
<data name="Reject" xml:space="preserve"> <data name="Reject" xml:space="preserve">
<value>Ablehnen</value> <value>Ablehnen</value>
</data> </data>
<data name="Rejection" xml:space="preserve">
<value>Ablehnung</value>
</data>
<data name="RejectionReasonQ" xml:space="preserve">
<value>Warum lehnen Sie den Vertrag ab?</value>
</data>
<data name="SigAgree" xml:space="preserve"> <data name="SigAgree" xml:space="preserve">
<value>Durch Klick auf Abschließen stimme ich zu, dass die abgebildete und übermittelte Signatur als elektronische Darstellung meiner Signatur in den Fällen gelten, in denen ich sie auf Dokumenten, einschließlich rechtsgültiger Verträge verwende.</value> <value>Durch Klick auf Abschließen stimme ich zu, dass die abgebildete und übermittelte Signatur als elektronische Darstellung meiner Signatur in den Fällen gelten, in denen ich sie auf Dokumenten, einschließlich rechtsgültiger Verträge verwende.</value>
</data> </data>

View File

@@ -117,6 +117,9 @@
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="and" xml:space="preserve">
<value>and</value>
</data>
<data name="Back" xml:space="preserve"> <data name="Back" xml:space="preserve">
<value>Back</value> <value>Back</value>
</data> </data>
@@ -144,6 +147,9 @@
<data name="Finalize" xml:space="preserve"> <data name="Finalize" xml:space="preserve">
<value>Finalize</value> <value>Finalize</value>
</data> </data>
<data name="Hello" xml:space="preserve">
<value>Hello</value>
</data>
<data name="LocakedOpen" xml:space="preserve"> <data name="LocakedOpen" xml:space="preserve">
<value>Open</value> <value>Open</value>
</data> </data>
@@ -165,6 +171,12 @@
<data name="Reject" xml:space="preserve"> <data name="Reject" xml:space="preserve">
<value>Reject</value> <value>Reject</value>
</data> </data>
<data name="Rejection" xml:space="preserve">
<value>Rejection</value>
</data>
<data name="RejectionReasonQ" xml:space="preserve">
<value>Why do you reject the contract?</value>
</data>
<data name="SigAgree" xml:space="preserve"> <data name="SigAgree" xml:space="preserve">
<value>By clicking on Finalize, I agree that the signature shown and submitted is an electronic representation of my signature in cases where I use it on documents, including legally binding contracts.</value> <value>By clicking on Finalize, I agree that the signature shown and submitted is an electronic representation of my signature in cases where I use it on documents, including legally binding contracts.</value>
</data> </data>

View File

@@ -50,17 +50,21 @@ namespace EnvelopeGenerator.Application.Services
status: (int)EnvelopeStatus.DocumentRejected) > 0; status: (int)EnvelopeStatus.DocumentRejected) > 0;
} }
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null) => _mapper.MapOrThrow<IEnumerable<EnvelopeHistoryDto>>( public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null)
await _repository.ReadAsync( {
envelopeId: envelopeId, var histDTOs = _mapper.MapOrThrow<IEnumerable<EnvelopeHistoryDto>>(
userReference: userReference, await _repository.ReadAsync(
status: status)); envelopeId: envelopeId,
userReference: userReference,
status: status));
return referenceType is null ? histDTOs : histDTOs.Where(h => h.ReferenceType == referenceType);
}
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) => public async Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) =>
await ReadAsync(envelopeId: envelopeId, userReference: userReference, status: (int)EnvelopeStatus.DocumentRejected); await ReadAsync(envelopeId: envelopeId, userReference: userReference, status: (int)EnvelopeStatus.DocumentRejected);
public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status) => public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null) =>
await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now)) await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now, Comment: comment))
.ThenAsync( .ThenAsync(
Success: id => Result.Success(id), Success: id => Result.Success(id),
Fail: (mssg, ntc) => Result.Fail<long>().Message(mssg).Notice(ntc) Fail: (mssg, ntc) => Result.Fail<long>().Message(mssg).Notice(ntc)

View File

@@ -26,6 +26,13 @@
MessageCompletionSent = 3005 MessageCompletionSent = 3005
End Enum End Enum
Public Enum ReferenceType
Receiver
Sender
System
Unknown
End Enum
Public Enum ElementStatus Public Enum ElementStatus
Created = 0 Created = 0
End Enum End Enum

View File

@@ -1,5 +1,7 @@
using System.ComponentModel.DataAnnotations; using DigitalData.UserManager.Domain.Entities;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Domain.Entities namespace EnvelopeGenerator.Domain.Entities
{ {
@@ -34,10 +36,18 @@ namespace EnvelopeGenerator.Domain.Entities
[Column("COMMENT", TypeName = "nvarchar(max)")] [Column("COMMENT", TypeName = "nvarchar(max)")]
public string? Comment { get; set; } public string? Comment { get; set; }
//[ForeignKey("UserReference")] [ForeignKey("UserReference")]
//public virtual DigitalData.UserManager.Domain.Entities.User? Sender { get; set; } public virtual User? Sender { get; set; }
[ForeignKey("UserReference")] [ForeignKey("UserReference")]
public virtual Receiver? Receiver { get; set; } public virtual Receiver? Receiver { get; set; }
[NotMapped]
public ReferenceType ReferenceType => (Status / 3) switch
{
1 => ReferenceType.Sender,
2 or 3 => ReferenceType.Receiver,
_ => ReferenceType.Unknown,
};
} }
} }

View File

@@ -7,6 +7,6 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
{ {
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null); Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null);
Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null, bool withReceiver = true); Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null, bool withSender = false, bool withReceiver = false);
} }
} }

View File

@@ -54,6 +54,12 @@ namespace DigitalData.UserManager.Infrastructure.Repositories
.HasForeignKey(eh => eh.UserReference) .HasForeignKey(eh => eh.UserReference)
.HasPrincipalKey(e => e.EmailAddress); .HasPrincipalKey(e => e.EmailAddress);
modelBuilder.Entity<EnvelopeHistory>()
.HasOne(eh => eh.Sender)
.WithMany()
.HasForeignKey(eh => eh.UserReference)
.HasPrincipalKey(e => e.Email);
// Configure entities to handle database triggers // Configure entities to handle database triggers
modelBuilder.Entity<Envelope>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS")); modelBuilder.Entity<Envelope>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));
modelBuilder.Entity<EnvelopeHistory>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS")); modelBuilder.Entity<EnvelopeHistory>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));

View File

@@ -12,7 +12,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
{ {
} }
private IQueryable<EnvelopeHistory> By(int? envelopeId = null, string? userReference = null, int? status = null, bool withReceiver = false) private IQueryable<EnvelopeHistory> By(int? envelopeId = null, string? userReference = null, int? status = null, bool withSender = false, bool withReceiver = false)
{ {
var query = _dbSet.AsQueryable(); var query = _dbSet.AsQueryable();
@@ -25,7 +25,10 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
if (status is not null) if (status is not null)
query = query.Where(eh => eh.Status == status); query = query.Where(eh => eh.Status == status);
if(withReceiver) if (withSender)
query = query.Include(eh => eh.Sender);
if (withReceiver)
query = query.Include(eh => eh.Receiver); query = query.Include(eh => eh.Receiver);
return query; return query;
@@ -36,10 +39,12 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
userReference: userReference, userReference: userReference,
status: status).CountAsync(); status: status).CountAsync();
public async Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null, bool withReceiver = true) => await By( public async Task<IEnumerable<EnvelopeHistory>> ReadAsync(int? envelopeId = null, string? userReference = null, int? status = null, bool withSender = false, bool withReceiver = false)
=> await By(
envelopeId: envelopeId, envelopeId: envelopeId,
userReference: userReference, userReference: userReference,
status: status, status: status,
withSender: withSender,
withReceiver: withReceiver).ToListAsync(); withReceiver: withReceiver).ToListAsync();
} }
} }

View File

@@ -6,39 +6,17 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
public static class ControllerBaseExtensions public static class ControllerBaseExtensions
{ {
public static (string EnvelopeUuid, string ReceiverSignature)? GetAuthenticatedEnvelopeDetails(this ControllerBase controller) public static string? GetClaimValue(this ControllerBase controller, string claimType) => controller.User.FindFirstValue(claimType);
{
if(controller?.User?.Identity?.IsAuthenticated ?? false)
{
var envelopeUuid = controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
var receiverSignature = controller.User.FindFirst(ClaimTypes.Hash)?.Value;
if (!string.IsNullOrEmpty(envelopeUuid) && !string.IsNullOrEmpty(receiverSignature))
return (EnvelopeUuid: envelopeUuid, ReceiverSignature: receiverSignature);
}
return null;
}
public static string? GetAuthenticatedEnvelopeUuid(this ControllerBase controller) public static string? GetAuthEnvelopeUuid(this ControllerBase controller) => controller.User.FindFirstValue(ClaimTypes.NameIdentifier);
{
if (controller?.User?.Identity?.IsAuthenticated ?? false)
{
var envelopeUuid = controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (!string.IsNullOrEmpty(envelopeUuid))
return envelopeUuid;
}
return null;
}
public static string? GetAuthenticatedReceiverSignature(this ControllerBase controller) public static string? GetAuthReceiverSignature(this ControllerBase controller) => controller.User.FindFirstValue(ClaimTypes.Hash);
{
if (controller?.User?.Identity?.IsAuthenticated ?? false) public static string? GetAuthReceiverName(this ControllerBase controller) => controller.User.FindFirstValue(ClaimTypes.Name);
{
var receiverSignature = controller.User.FindFirst(ClaimTypes.Hash)?.Value; public static string? GetAuthReceiverMail(this ControllerBase controller) => controller.User.FindFirstValue(ClaimTypes.Email);
if (!string.IsNullOrEmpty(receiverSignature))
return receiverSignature; public static string? GetAuthEnvelopeTitle(this ControllerBase controller) => controller.User.FindFirstValue(EnvelopeClaimTypes.Title);
}
return null;
}
//TODO: integrate localizer for ready-to-use views //TODO: integrate localizer for ready-to-use views
public static ViewResult ViewError(this Controller controller, ErrorViewModel errorViewModel) => controller.View("_Error", errorViewModel); public static ViewResult ViewError(this Controller controller, ErrorViewModel errorViewModel) => controller.View("_Error", errorViewModel);

View File

@@ -52,7 +52,7 @@ namespace EnvelopeGenerator.Web.Controllers
{ {
try try
{ {
var authSignature = this.GetAuthenticatedReceiverSignature(); var authSignature = this.GetAuthReceiverSignature();
if (authSignature != envelopeKey.GetReceiverSignature()) if (authSignature != envelopeKey.GetReceiverSignature())
return Forbid(); return Forbid();

View File

@@ -1,24 +1,43 @@
using EnvelopeGenerator.Application; using DigitalData.Core.DTO;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Application.Contracts;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Common; using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services; using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Web.Controllers namespace EnvelopeGenerator.Web.Controllers
{ {
[Authorize] [Authorize]
[ApiController]
[Route("api/[controller]")]
public class EnvelopeController : BaseController public class EnvelopeController : BaseController
{ {
private readonly EnvelopeOldService envelopeService; private readonly EnvelopeOldService envelopeService;
private readonly ActionService? actionService; private readonly ActionService? actionService;
private readonly UrlEncoder _urlEncoder; private readonly UrlEncoder _urlEncoder;
private readonly IEnvelopeHistoryService _histService;
private readonly IReceiverService _receiverService;
private readonly IEnvelopeReceiverService _envRcvService;
public EnvelopeController(DatabaseService database, EnvelopeOldService envelope, ILogger<EnvelopeController> logger, UrlEncoder urlEncoder) : base(database, logger)
public EnvelopeController(DatabaseService database,
EnvelopeOldService envelope,
ILogger<EnvelopeController> logger, UrlEncoder urlEncoder,
IEnvelopeHistoryService envelopeHistoryService,
IReceiverService receiverService,
IEnvelopeReceiverService envelopeReceiverService) : base(database, logger)
{ {
envelopeService = envelope; envelopeService = envelope;
actionService = database?.Services?.actionService; actionService = database?.Services?.actionService;
_urlEncoder = urlEncoder; _urlEncoder = urlEncoder;
_histService = envelopeHistoryService;
_receiverService = receiverService;
_envRcvService = envelopeReceiverService;
} }
[NonAction] [NonAction]
@@ -49,17 +68,17 @@ namespace EnvelopeGenerator.Web.Controllers
} }
[Authorize] [Authorize]
[HttpPost("api/envelope/{envelopeKey}")] [HttpPost("{envelopeKey}")]
public async Task<IActionResult> Update(string envelopeKey, int index) public async Task<IActionResult> Update(string envelopeKey, int index)
{ {
try try
{ {
envelopeKey = _urlEncoder.Encode(envelopeKey); envelopeKey = _urlEncoder.Encode(envelopeKey);
var authSignature = this.GetAuthenticatedReceiverSignature(); var authSignature = this.GetAuthReceiverSignature();
if (authSignature != envelopeKey.GetReceiverSignature()) if (authSignature != envelopeKey.GetReceiverSignature())
return Forbid(); return Unauthorized();
// Validate Envelope Key and load envelope // Validate Envelope Key and load envelope
envelopeService.EnsureValidEnvelopeKey(envelopeKey); envelopeService.EnsureValidEnvelopeKey(envelopeKey);
@@ -75,7 +94,7 @@ namespace EnvelopeGenerator.Web.Controllers
string? annotationData = await envelopeService.EnsureValidAnnotationData(Request); string? annotationData = await envelopeService.EnsureValidAnnotationData(Request);
envelopeService.InsertDocumentStatus(new DocumentStatus() envelopeService.InsertDocumentStatus(new Common.DocumentStatus()
{ {
EnvelopeId = response.Envelope.Id, EnvelopeId = response.Envelope.Id,
ReceiverId = response.Receiver.Id, ReceiverId = response.Receiver.Id,
@@ -93,5 +112,45 @@ namespace EnvelopeGenerator.Web.Controllers
return StatusCode(StatusCodes.Status500InternalServerError); return StatusCode(StatusCodes.Status500InternalServerError);
} }
} }
[Authorize]
[HttpPost("reject")]
public async Task<IActionResult> Reject([FromBody] string? reason = null)
{
try
{
var signature = this.GetAuthReceiverSignature();
var uuid = this.GetAuthEnvelopeUuid();
var mail = this.GetAuthReceiverMail();
if(uuid is null || signature is null || mail is null)
{
_logger.LogEnvelopeError(uuid: uuid, signature: signature,
message: @$"Unauthorized POST request in api\envelope\reject. One of claims, Envelope, signature or mail ({mail}) is null.");
return Unauthorized();
}
var envRcvRes = await _envRcvService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature);
if (envRcvRes.IsFailed)
{
_logger.LogNotice(envRcvRes.Notices);
return Unauthorized();
}
return await _histService.RecordAsync(envRcvRes.Data.EnvelopeId, userReference: mail, EnvelopeStatus.DocumentRejected, comment: reason).ThenAsync(
Success: id => NoContent(),
Fail: IActionResult (mssg, ntc) =>
{
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: "Unexpected error happend in api/envelope/reject");
_logger.LogNotice(ntc);
return this.ViewInnerServiceError();
});
}
catch (Exception e)
{
_logger.LogError(e, "{Message}", e.Message);
return StatusCode(StatusCodes.Status500InternalServerError);
}
}
} }
} }

View File

@@ -95,12 +95,12 @@ try
builder.Services.AddScoped<IConfigService, ConfigService>(); builder.Services.AddScoped<IConfigService, ConfigService>();
builder.Services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>(); builder.Services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>(); builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
builder.Services.AddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
builder.Services.AddScoped<IDocumentStatusService, DocumentStatusService>(); builder.Services.AddScoped<IDocumentStatusService, DocumentStatusService>();
builder.Services.AddScoped<IEmailTemplateService, EmailTemplateService>(); builder.Services.AddScoped<IEmailTemplateService, EmailTemplateService>();
builder.Services.AddScoped<IEnvelopeService, EnvelopeService>(); builder.Services.AddScoped<IEnvelopeService, EnvelopeService>();
builder.Services.AddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>(); builder.Services.AddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>(); builder.Services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
builder.Services.AddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
builder.Services.AddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>(); builder.Services.AddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
builder.Services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>(); builder.Services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
builder.Services.AddScoped<IReceiverService, ReceiverService>(); builder.Services.AddScoped<IReceiverService, ReceiverService>();

View File

@@ -17,7 +17,7 @@
var sender = Model.Envelope?.User; var sender = Model.Envelope?.User;
var pages = document?.Elements?.Select(e => e.Page) ?? Array.Empty<int>(); var pages = document?.Elements?.Select(e => e.Page) ?? Array.Empty<int>();
var stPageIndexes = string.Join(pages.Count() > 1 ? ", " : "", pages.Take(pages.Count() - 1)) var stPageIndexes = string.Join(pages.Count() > 1 ? ", " : "", pages.Take(pages.Count() - 1))
+ (pages.Count() > 1 ? " und " : "") + pages.LastOrDefault(); + (pages.Count() > 1 ? $" {_localizer[WebKey.and].TrySanitize(_sanitizer)} " : "") + pages.LastOrDefault();
} }
<div class="d-flex flex-column min-vh-100"> <div class="d-flex flex-column min-vh-100">
<nav class="navbar navbar-light bg-light"> <nav class="navbar navbar-light bg-light">
@@ -25,7 +25,7 @@
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
<div class="navbar-brand me-auto ms-5 envelope-message">@($"Hallo {Model.Name.TrySanitize(_sanitizer)}, {@envelope?.Message.TrySanitize(_sanitizer)}")</div> <div class="navbar-brand me-auto ms-5 envelope-message">@($"{_localizer[WebKey.Hello]} {Model.Name}, {@envelope?.Message}".TrySanitize(_sanitizer))</div>
<div class="col-1 p-0 m-0 me-3 d-flex"> <div class="col-1 p-0 m-0 me-3 d-flex">
<img src="~/img/digital_data.svg" alt="..."> <img src="~/img/digital_data.svg" alt="...">
</div> </div>
@@ -46,7 +46,7 @@
envelope?.Title.TryEncode(_encoder), envelope?.Title.TryEncode(_encoder),
sender?.Prename.TryEncode(_encoder), sender?.Prename.TryEncode(_encoder),
sender?.Name.TryEncode(_encoder), sender?.Name.TryEncode(_encoder),
sender?.Email.TryEncode(_encoder)))</small></p> sender?.Email.TryEncode(_encoder)).TrySanitize(_sanitizer))</small></p>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,6 @@
@using DigitalData.Core.API @using DigitalData.Core.API
@using Newtonsoft.Json @using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@{ @{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
} }
@@ -27,19 +28,23 @@
<script src="~/lib/pspdfkit/pspdfkit.js" asp-append-version="true"></script> <script src="~/lib/pspdfkit/pspdfkit.js" asp-append-version="true"></script>
<script src="~/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js" asp-append-version="true"></script> <script src="~/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js" asp-append-version="true"></script>
<script src="~/js/util.js" asp-append-version="true"></script> <script src="~/js/util.js" asp-append-version="true"></script>
<script src="~/js/api.js" asp-append-version="true"></script> <script src="~/js/api-service.js" asp-append-version="true"></script>
@await RenderSectionAsync("Scripts", required: false) @await RenderSectionAsync("Scripts", required: false)
@{ @{
var lStrsJson = JsonConvert.SerializeObject(_localizer.ToDictionary()).TrySanitize(_sanitizer); var settings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
var lStrsJson = JsonConvert.SerializeObject(_localizer.ToDictionary(), settings).TrySanitize(_sanitizer);
} }
<script nonce="@nonce"> <script nonce="@nonce">
var localized = @Html.Raw(lStrsJson) var localized = @Html.Raw(lStrsJson)
</script> </script>
<main role="main"> <main role="main">
<partial name="_CookieConsentPartial" /> <partial name="_CookieConsentPartial" />
@RenderBody() @RenderBody()
</main> </main>
<script src="~/js/event-binder.js" asp-append-version="true"></script>
@Html.AntiForgeryToken() @Html.AntiForgeryToken()
</body> </body>
</html> </html>

View File

@@ -24,5 +24,7 @@
public static readonly string EnvelopeInfo2 = nameof(EnvelopeInfo2); public static readonly string EnvelopeInfo2 = nameof(EnvelopeInfo2);
public static readonly string SigAgree = nameof(SigAgree); public static readonly string SigAgree = nameof(SigAgree);
public static readonly string Reject = nameof(Reject); public static readonly string Reject = nameof(Reject);
public static readonly string and = nameof(and);
public static readonly string Hello = nameof(Hello);
} }
} }

View File

@@ -0,0 +1,41 @@
class Content {
static get JSON () {
return 'application/json';
}
}
class API {
static get REJECT_URL () {
return `/api/envelope/reject`;
}
static __XSRF_TOKEN
static get XSRF_TOKEN() {
API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value;
return API.__XSRF_TOKEN;
}
}
const submitForm = async form => await fetch(form.action, {
method: form.method,
body: new FormData(form),
headers: {
"X-Requested-With": "XMLHttpRequest"
}
})
const createRequest = async (method, url, body, contentType) => {
return fetch(url, {
credentials: 'include',
method: method,
headers: {
'Content-Type': contentType,
'X-XSRF-TOKEN': API.XSRF_TOKEN
},
body: JSON.stringify(body)
})
}
const createPost = (url, body, contentType) => createRequest('POST', url, body, contentType);
const rejectEnvelope = (reason) => createPost(API.REJECT_URL, reason, Content.JSON);

View File

@@ -1,7 +0,0 @@
const submitForm = async form => await fetch(form.action, {
method: form.method,
body: new FormData(form),
headers: {
"X-Requested-With": "XMLHttpRequest"
}
})

View File

@@ -180,14 +180,14 @@ class App {
} }
return Swal.fire({ return Swal.fire({
title: localized.Confirmation, title: localized.confirmation,
html: `<div class="text-start fs-6 p-0 m-0">${localized.SigAgree}</div>`, html: `<div class="text-start fs-6 p-0 m-0">${localized.sigAgree}</div>`,
icon: "question", icon: "question",
showCancelButton: true, showCancelButton: true,
confirmButtonColor: "#3085d6", confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33", cancelButtonColor: "#d33",
confirmButtonText: localized.Finalize, confirmButtonText: localized.finalize,
cancelButtonText: localized.Back cancelButtonText: localized.back
}).then(async (result) => { }).then(async (result) => {
if (result.isConfirmed) { if (result.isConfirmed) {
//--- //---

View File

@@ -0,0 +1,37 @@
$('.btn_reject').click(_ =>
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: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: localized.complete,
cancelButtonText: localized.back,
showLoaderOnConfirm: true,
preConfirm: async (reason) => {
try {
var res = await rejectEnvelope(reason);
return res;
} catch (error) {
Swal.showValidationMessage(`
Request failed: ${error}
`);
}
},
allowOutsideClick: () => !Swal.isLoading()
}).then((result) => {
if (!result.isConfirmed)
return;
const res = result.value;
console.log(res)
if (res.ok) {
alert('rejected')
}
else
alert('fail')
}));