Compare commits

...

4 Commits

18 changed files with 291 additions and 92 deletions

View File

@@ -1,5 +1,6 @@
using DigitalData.Core.Contracts.Application;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts;
@@ -15,10 +16,14 @@ namespace EnvelopeGenerator.Application.Contracts
Task<bool> IsSigned(int envelopeId, string userReference);
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null);
Task<bool> IsRejected(int envelopeId, string? userReference = null);
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false);
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null);
Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId);
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null);
}
}

View File

@@ -34,6 +34,5 @@ namespace EnvelopeGenerator.Application.DTOs
bool IsAlreadySent,
string? StatusTranslated,
string? ContractTypeTranslated,
IEnumerable<EnvelopeDocumentDto>? Documents,
IEnumerable<EnvelopeHistoryDto>? History);
IEnumerable<EnvelopeDocumentDto>? Documents);
}

View File

@@ -1,4 +1,5 @@
using DigitalData.UserManager.Application.DTOs.User;
using DigitalData.Core.DTO;
using DigitalData.UserManager.Application.DTOs.User;
using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
@@ -13,5 +14,5 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
UserCreateDto? Sender,
ReceiverDto? Receiver,
ReferenceType ReferenceType,
string? Comment = null);
string? Comment = null) : BaseDTO<long>(Id);
}

View File

@@ -1,9 +1,11 @@
namespace EnvelopeGenerator.Application.DTOs
using DigitalData.Core.DTO;
namespace EnvelopeGenerator.Application.DTOs
{
public record ReceiverDto(
int Id,
string EmailAddress,
string Signature,
DateTime AddedWhen
);
) : BaseDTO<int>(Id);
}

View File

@@ -102,9 +102,9 @@ namespace EnvelopeGenerator.Application
/// <returns>The receiver signature.</returns>
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
public static void LogEnvelopeError(this ILogger logger, string envelopeEeceiverId, Exception? exception = null, string? message = null, params object?[] args)
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
{
var sb = new StringBuilder().AppendLine(envelopeEeceiverId.DecodeEnvelopeReceiverId().ToTitle());
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
if (message is not null)
sb.AppendLine(message);

View File

@@ -135,6 +135,12 @@
<data name="DocProtected" xml:space="preserve">
<value>Dokument geschützt</value>
</data>
<data name="DocRejected" xml:space="preserve">
<value>Dokument abgelehnt</value>
</data>
<data name="DocSigned" xml:space="preserve">
<value>Dokument unterschrieben</value>
</data>
<data name="en-US" xml:space="preserve">
<value>Englisch</value>
</data>
@@ -174,8 +180,20 @@
<data name="Rejection" xml:space="preserve">
<value>Ablehnung</value>
</data>
<data name="RejectionInfo1" xml:space="preserve">
<value>Ihre Ablehnung wurde weitergeleitet!</value>
</data>
<data name="RejectionInfo1_ext" xml:space="preserve">
<value>Vorgang abgebrochen!</value>
</data>
<data name="RejectionInfo2" xml:space="preserve">
<value>Sie können bei Bedarf mit {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Sehr geehrte(r)%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; Kontakt aufnehmen.</value>
</data>
<data name="RejectionInfo2_ext" xml:space="preserve">
<value>Das Vorgang wurde von einer der beteiligten Parteien abgelehnt. Sie können bei Bedarf mit {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Sehr geehrte(r)%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; Kontakt aufnehmen.</value>
</data>
<data name="RejectionReasonQ" xml:space="preserve">
<value>Warum lehnen Sie den Vertrag ab?</value>
<value>Bitte geben Sie einen Grund an:</value>
</data>
<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>

View File

@@ -135,6 +135,12 @@
<data name="DocProtected" xml:space="preserve">
<value>Document protected</value>
</data>
<data name="DocRejected" xml:space="preserve">
<value>Document rejected</value>
</data>
<data name="DocSigned" xml:space="preserve">
<value>Document signed</value>
</data>
<data name="en-US" xml:space="preserve">
<value>English</value>
</data>
@@ -174,8 +180,20 @@
<data name="Rejection" xml:space="preserve">
<value>Rejection</value>
</data>
<data name="RejectionInfo1" xml:space="preserve">
<value>Your rejection has been forwarded!</value>
</data>
<data name="RejectionInfo1_ext" xml:space="preserve">
<value>Process canceled!</value>
</data>
<data name="RejectionInfo2" xml:space="preserve">
<value>You can contact {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Dear%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; if required.</value>
</data>
<data name="RejectionInfo2_ext" xml:space="preserve">
<value>The process has been rejected by one of the parties involved. You can contact {0}, &lt;a href="mailto:{1}?subject={2}&amp;body=Dear%20{0},%0A%0A%0A"&gt;{1}&lt;/a&gt; if required.</value>
</data>
<data name="RejectionReasonQ" xml:space="preserve">
<value>Why do you reject the contract?</value>
<value>Please give a reason:</value>
</data>
<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>

View File

@@ -8,6 +8,7 @@ using static EnvelopeGenerator.Common.Constants;
using EnvelopeGenerator.Application.Resources;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Application.DTOs;
namespace EnvelopeGenerator.Application.Services
{
@@ -50,20 +51,33 @@ namespace EnvelopeGenerator.Application.Services
status: (int)EnvelopeStatus.DocumentRejected) > 0;
}
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null)
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false)
{
var histDTOs = _mapper.MapOrThrow<IEnumerable<EnvelopeHistoryDto>>(
await _repository.ReadAsync(
envelopeId: envelopeId,
userReference: userReference,
status: status));
status: status,
withSender: withSender,
withReceiver: withReceiver));
return referenceType is null ? histDTOs : histDTOs.Where(h => h.ReferenceType == referenceType);
}
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, withReceiver:true);
public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null) =>
//TODO: use IQueryable in repository to incerease the performance
public async Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId)
{
var envelopes = await ReadRejectedAsync(envelopeId);
return envelopes is null
? Enumerable.Empty<ReceiverDto>()
: envelopes
.Where(eh => eh?.Receiver != null)
.Select(eh => eh.Receiver!);
}
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, Comment: comment))
.ThenAsync(
Success: id => Result.Success(id),

View File

@@ -11,6 +11,9 @@
</ItemGroup>
<ItemGroup>
<Reference Include="DigitalData.Core.Domain">
<HintPath>..\..\WebCoreModules\DigitalData.Core.Domain\bin\Debug\net7.0\DigitalData.Core.Domain.dll</HintPath>
</Reference>
<Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference>

View File

@@ -1,7 +1,6 @@
using DigitalData.Core.DTO;
using EnvelopeGenerator.Application;
using EnvelopeGenerator.Application.Contracts;
using DigitalData.Core.DTO;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Authorization;
@@ -134,7 +133,7 @@ namespace EnvelopeGenerator.Web.Controllers
if (envRcvRes.IsFailed)
{
_logger.LogNotice(envRcvRes.Notices);
return Unauthorized();
return Unauthorized("you are not authirized");
}
return await _histService.RecordAsync(envRcvRes.Data.EnvelopeId, userReference: mail, EnvelopeStatus.DocumentRejected, comment: reason).ThenAsync(

View File

@@ -1,5 +1,4 @@
using EnvelopeGenerator.Application.Contracts;
using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Authentication.Cookies;
@@ -71,7 +70,7 @@ namespace EnvelopeGenerator.Web.Controllers
}
catch(Exception ex)
{
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception:ex, message: _localizer[WebKey.UnexpectedError]);
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception:ex, message: _localizer[WebKey.UnexpectedError]);
return this.ViewInnerServiceError();
}
}
@@ -105,7 +104,7 @@ namespace EnvelopeGenerator.Web.Controllers
}
catch(Exception ex)
{
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex);
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError();
}
}
@@ -118,7 +117,7 @@ namespace EnvelopeGenerator.Web.Controllers
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId);
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
if(uuid is null || signature is null)
if (uuid is null || signature is null)
{
_logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer[WebKey.WrongEnvelopeReceiverId]);
return Unauthorized();
@@ -126,89 +125,100 @@ namespace EnvelopeGenerator.Web.Controllers
_logger.LogInformation($"Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]");
return await _envRcvService.VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: access_code).ThenAsync(
SuccessAsync: async isVerified =>
{
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId);
if (isVerified)
//check access code
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId);
var verification = await _envRcvService.VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: access_code);
if (verification.IsFailed)
{
_logger.LogNotice(verification.Notices);
Response.StatusCode = StatusCodes.Status401Unauthorized;
return View("EnvelopeLocked")
.WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language)
.WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value);
}
else if (verification.IsWrong())
{
database.Services.actionService.EnterIncorrectAccessCode(response.Envelope, response.Receiver); //for history
Response.StatusCode = StatusCodes.Status401Unauthorized;
return View("EnvelopeLocked")
.WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language)
.WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value);
}
else
{
ViewData["EnvelopeKey"] = envelopeReceiverId;
}
//show envelope
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
return await _envRcvService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature).ThenAsync<EnvelopeReceiverDto, IActionResult>(
SuccessAsync: async er =>
{
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
ViewData["EnvelopeKey"] = envelopeReceiverId;
//check rejection
var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id);
if(rejRcvrs.Any())
{
ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected
return View("EnvelopeRejected", er);
}
return await _envRcvService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature).ThenAsync<EnvelopeReceiverDto, IActionResult>(
SuccessAsync: async er =>
{
if(await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress))
return View("EnvelopeSigned");
//check if it has already signed
if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress))
return View("EnvelopeSigned");
if (response.Envelope.Documents.Count > 0)
{
var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeReceiverId);
byte[] bytes = await envelopeOldService.GetDocumentContents(document);
ViewData["DocumentBytes"] = bytes;
}
else
{
return this.ViewDocumentNotFound();
}
if (response.Envelope.Documents.Count > 0)
{
var document = await envelopeOldService.GetDocument(response.Envelope.Documents[0].Id, envelopeReceiverId);
byte[] bytes = await envelopeOldService.GetDocumentContents(document);
ViewData["DocumentBytes"] = bytes;
}
else
{
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document was found.");
return this.ViewDocumentNotFound();
}
var claims = new List<Claim> {
var claims = new List<Claim> {
new(ClaimTypes.NameIdentifier, uuid),
new(ClaimTypes.Hash, signature),
new(ClaimTypes.Name, er.Name ?? string.Empty),
new(ClaimTypes.Email, er.Receiver.EmailAddress),
new(EnvelopeClaimTypes.Title, er.Envelope.Title)
};
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties {
AllowRefresh = false,
IsPersistent = false
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties
{
AllowRefresh = false,
IsPersistent = false
};
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),
authProperties);
//add PSPDFKit licence key
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
ViewData["UserCulture"] = _cultures[UserLanguage];
//add PSPDFKit licence key
ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"];
ViewData["UserCulture"] = _cultures[UserLanguage];
return View("ShowEnvelope", er);
},
Fail: (messages, notices) =>
{
_logger.LogNotice(notices);
return this.ViewEnvelopeNotFound();
}
);
}
else
return View("ShowEnvelope", er);
},
Fail: (messages, notices) =>
{
database.Services.actionService.EnterIncorrectAccessCode(response.Envelope, response.Receiver); //for history
Response.StatusCode = StatusCodes.Status401Unauthorized;
return View("EnvelopeLocked")
.WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language)
.WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value);
_logger.LogNotice(notices);
return this.ViewEnvelopeNotFound();
}
},
Fail: (messages, notices) =>
{
_logger.LogNotice(notices);
Response.StatusCode = StatusCodes.Status401Unauthorized;
return View("EnvelopeLocked")
.WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language)
.WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value);
});
);
}
catch(Exception ex)
catch (Exception ex)
{
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex);
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError();
}
}
[Authorize]
[HttpGet("EnvelopeKey/{envelopeReceiverId}/Success")]
public async Task<IActionResult> EnvelopeSigned(string envelopeReceiverId)
{
@@ -237,11 +247,42 @@ namespace EnvelopeGenerator.Web.Controllers
}
catch (Exception ex)
{
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex);
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError();
}
}
[Authorize]
[HttpGet("EnvelopeKey/{envelopeReceiverId}/Rejected")]
public async Task<IActionResult> EnvelopeRejected(string envelopeReceiverId)
{
try
{
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId);
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId).ThenAsync(
SuccessAsync: async (er) =>
{
ViewData["UserCulture"] = _cultures[UserLanguage];
return await _historyService.IsRejected(envelopeId: er.EnvelopeId)
? View(er)
: Redirect($"/EnvelopeKey/{envelopeReceiverId}/Locked");
},
Fail: IActionResult (messages, notices) =>
{
_logger.LogNotice(notices);
return this.ViewEnvelopeNotFound();
});
}
catch (Exception ex)
{
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError();
}
}
[Authorize]
[HttpGet("IsAuthenticated")]
public IActionResult IsAuthenticated()

View File

@@ -0,0 +1,73 @@
@{
ViewData["Title"] = _localizer[WebKey.DocRejected];
}
@{
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
}
@using DigitalData.Core.DTO;
@using EnvelopeGenerator.Application.DTOs;
@using Newtonsoft.Json
@using Newtonsoft.Json.Serialization
@model EnvelopeReceiverDto;
<partial name="_CookieConsentPartial" />
@{
var userCulture = ViewData["UserCulture"] as Culture;
var envelope = Model.Envelope;
var document = Model.Envelope?.Documents?.FirstOrDefault();
var sender = Model.Envelope?.User;
var isExt = ViewBag.IsExt ?? false;
}
<div class="page container p-5">
<header class="text-center">
<div class="icon rejected">
<svg height="100" width="100" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 500 520" xml:space="preserve">
<polygon style="fill:#F4B2B0;" points="27.959,164.583 27.959,160.534 172.263,14.827 172.263,164.583 "/>
<g>
<path style="fill:#B3404A;" d="M459.181,264.152c-5.593-5.981-14.975-6.295-20.956-0.703c-5.981,5.593-6.295,14.976-0.703,20.956
c20.435,21.854,31.69,50.379,31.69,80.317c0,64.859-52.766,117.623-117.623,117.623c-64.859,0-117.623-52.766-117.623-117.623
s52.765-117.623,117.623-117.623c8.187,0,14.827-6.638,14.827-14.827c0-8.189-6.639-14.827-14.827-14.827
c-81.208,0-147.276,66.068-147.276,147.276c0,14.953,2.248,29.389,6.41,42.997H42.786v-167.54c0-8.189-6.638-14.827-14.827-14.827
s-14.827,6.638-14.827,14.827v182.366c0,8.189,6.638,14.827,14.827,14.827h195.559c25.359,44.53,73.265,74.626,128.072,74.626
c81.208,0,147.276-66.068,147.276-147.276C498.866,327.236,484.772,291.519,459.181,264.152z"/>
<path style="fill:#B3404A;" d="M394.597,0H172.263c-0.178,0-0.353,0.021-0.529,0.027c-0.172,0.006-0.344,0.013-0.516,0.025
c-0.636,0.044-1.268,0.117-1.889,0.242c-0.021,0.004-0.04,0.012-0.061,0.015c-0.608,0.126-1.202,0.299-1.787,0.5
c-0.159,0.053-0.314,0.111-0.471,0.171c-0.577,0.219-1.143,0.463-1.689,0.752c-0.024,0.013-0.049,0.022-0.073,0.034
c-0.565,0.304-1.103,0.657-1.626,1.033c-0.135,0.098-0.268,0.197-0.4,0.299c-0.519,0.4-1.023,0.824-1.49,1.296L17.428,150.099
c-0.348,0.351-0.676,0.719-0.984,1.1c-0.212,0.261-0.399,0.534-0.59,0.805c-0.086,0.123-0.182,0.239-0.264,0.363
c-0.219,0.331-0.415,0.673-0.603,1.017c-0.042,0.076-0.09,0.147-0.13,0.222c-0.187,0.353-0.35,0.713-0.506,1.078
c-0.033,0.077-0.073,0.151-0.105,0.23c-0.141,0.345-0.259,0.697-0.374,1.048c-0.034,0.107-0.077,0.211-0.11,0.317
c-0.096,0.325-0.172,0.654-0.246,0.984c-0.033,0.142-0.073,0.28-0.101,0.424c-0.059,0.304-0.096,0.609-0.136,0.915
c-0.022,0.173-0.055,0.344-0.073,0.519c-0.028,0.302-0.034,0.605-0.044,0.907c-0.006,0.168-0.025,0.334-0.025,0.501v4.051
c0,8.189,6.638,14.827,14.827,14.827h144.304c8.189,0,14.827-6.638,14.827-14.827V29.653h192.681v143.315
c0,8.189,6.639,14.827,14.827,14.827s14.827-6.638,14.827-14.827V14.827C409.423,6.638,402.786,0,394.597,0z M59.498,149.757
l91.096-91.982l6.842-6.908v98.89H59.498z"/>
</g>
<polygon style="fill:#F4B2B0;" points="425.039,404.045 384.233,363.241 425.039,322.435 392.394,289.792 351.59,330.597
310.786,289.792 278.14,322.435 318.946,363.241 278.14,404.045 310.786,436.689 351.59,395.885 392.394,436.689 "/>
<path style="fill:#B3404A;" d="M392.395,451.515c-3.932,0-7.702-1.563-10.484-4.343l-30.32-30.322l-30.32,30.322
c-5.791,5.788-15.176,5.79-20.969,0l-32.645-32.644c-2.78-2.78-4.343-6.552-4.343-10.484s1.563-7.704,4.343-10.484l30.32-30.32
l-30.32-30.32c-2.78-2.78-4.343-6.552-4.343-10.484c0-3.932,1.563-7.704,4.343-10.484l32.645-32.644
c5.793-5.79,15.178-5.788,20.969,0l30.32,30.322l30.32-30.322c2.781-2.78,6.552-4.343,10.484-4.343s7.704,1.563,10.484,4.343
l32.644,32.644c5.79,5.79,5.79,15.178,0,20.968l-30.32,30.32l30.32,30.32c5.79,5.79,5.79,15.178,0,20.968l-32.644,32.644
C400.099,449.954,396.327,451.515,392.395,451.515z M299.11,404.045l11.676,11.676l30.32-30.322c5.791-5.79,15.176-5.79,20.969,0
l30.32,30.322l11.676-11.676l-30.322-30.32c-5.79-5.79-5.79-15.178,0-20.969l30.322-30.32l-11.676-11.676l-30.32,30.322
c-5.791,5.79-15.176,5.79-20.969,0l-30.32-30.322l-11.676,11.676l30.32,30.32c5.79,5.79,5.79,15.178,0,20.969L299.11,404.045z"/>
</svg>
</div>
<h1>@_localizer[isExt ? WebKey.RejectionInfo1_ext : WebKey.RejectionInfo1].TrySanitize(_sanitizer)</h1>
</header>
<section class="text-center">
<div class="card-body p-0 m-0 ms-4">
<p class="card-text p-0 m-0">
<small class="text-body-secondary">
@Html.Raw(string.Format(_localizer[isExt ? WebKey.RejectionInfo2_ext : WebKey.RejectionInfo2],
$"{sender?.Prename} {sender?.Name}".TrySanitize(_sanitizer),
sender?.Email.TrySanitize(_sanitizer),
envelope?.Title.TrySanitize(_sanitizer)))
</small>
</p>
</div>
</section>
</div>
<footer class="container" id="page-footer">&copy; SignFlow 2023-2024 <a href="https://digitaldata.works">Digital Data GmbH</a></footer>

View File

@@ -1,5 +1,5 @@
@{
ViewData["Title"] = "Dokument unterschrieben";
ViewData["Title"] = _localizer[WebKey.DocSigned];
}
<div class="page container p-5">
<header class="text-center">

View File

@@ -8,7 +8,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"]</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/lib/sweetalert2/sweetalert2.min.css" />
@@ -17,6 +17,10 @@
<link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" />
</head>
<body>
@if (ViewData["EnvelopeKey"] is string envelopeKey)
{
<script>const ENV_KEY = "@envelopeKey.TrySanitize(_sanitizer)"</script>
}
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/popper/dist/umd/popper.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.min.js"></script>

View File

@@ -18,6 +18,8 @@
public static readonly string LockedFooterBody = nameof(LockedFooterBody);
public static readonly string WrongAccessCode = nameof(WrongAccessCode);
public static readonly string SignDoc = nameof(SignDoc);
public static readonly string DocRejected = nameof(DocRejected);
public static readonly string DocSigned = nameof(DocSigned);
public static readonly string DocProtected = nameof(DocProtected);
public static readonly string Complete = nameof(Complete);
public static readonly string EnvelopeInfo1 = nameof(EnvelopeInfo1);
@@ -26,5 +28,9 @@
public static readonly string Reject = nameof(Reject);
public static readonly string and = nameof(and);
public static readonly string Hello = nameof(Hello);
}
public static readonly string RejectionInfo1 = nameof(RejectionInfo1);
public static readonly string RejectionInfo2 = nameof(RejectionInfo2);
public static readonly string RejectionInfo1_ext = nameof(RejectionInfo1_ext);
public static readonly string RejectionInfo2_ext = nameof(RejectionInfo2_ext);
}
}

View File

@@ -103,6 +103,11 @@ body {
color: #fff;
}
.page header .icon.rejected {
background-color: #e4d8d5;
color: #fff;
}
.page .form {
max-width: 30rem;
margin: 2rem auto;

View File

@@ -9,11 +9,19 @@ class API {
return `/api/envelope/reject`;
}
static get REJECT_REDIR_URL(){
return `/envelopekey/${API.ENV_KEY}/rejected`;
}
static __XSRF_TOKEN
static get XSRF_TOKEN() {
API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value;
return API.__XSRF_TOKEN;
}
static get ENV_KEY(){
return ENV_KEY ?? document.querySelector('meta[name="env-key"]').getAttribute('content');
}
}
const submitForm = async form => await fetch(form.action, {
@@ -38,4 +46,8 @@ const createRequest = async (method, url, body, contentType) => {
const createPost = (url, body, contentType) => createRequest('POST', url, body, contentType);
const rejectEnvelope = (reason) => createPost(API.REJECT_URL, reason, Content.JSON);
const rejectEnvelope = (reason) => createPost(API.REJECT_URL, reason, Content.JSON);
const redirect = (url) => window.location.href = url;
const redirRejected = () => redirect(API.REJECT_REDIR_URL);

View File

@@ -28,10 +28,9 @@ $('.btn_reject').click(_ =>
if (!result.isConfirmed)
return;
const res = result.value;
console.log(res)
if (res.ok) {
alert('rejected')
redirRejected()
}
else
alert('fail')
Swal.showValidationMessage(`Request failed: ${res.message}`);
}));