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.Contracts.Application;
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Domain.Entities;
using EnvelopeGenerator.Infrastructure.Contracts; using EnvelopeGenerator.Infrastructure.Contracts;
@@ -15,10 +16,14 @@ 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, 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<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId);
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null); 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, bool IsAlreadySent,
string? StatusTranslated, string? StatusTranslated,
string? ContractTypeTranslated, string? ContractTypeTranslated,
IEnumerable<EnvelopeDocumentDto>? Documents, IEnumerable<EnvelopeDocumentDto>? Documents);
IEnumerable<EnvelopeHistoryDto>? History);
} }

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; using static EnvelopeGenerator.Common.Constants;
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
@@ -13,5 +14,5 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
UserCreateDto? Sender, UserCreateDto? Sender,
ReceiverDto? Receiver, ReceiverDto? Receiver,
ReferenceType ReferenceType, 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( public record ReceiverDto(
int Id, int Id,
string EmailAddress, string EmailAddress,
string Signature, string Signature,
DateTime AddedWhen DateTime AddedWhen
); ) : BaseDTO<int>(Id);
} }

View File

@@ -102,9 +102,9 @@ namespace EnvelopeGenerator.Application
/// <returns>The receiver signature.</returns> /// <returns>The receiver signature.</returns>
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature; 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) if (message is not null)
sb.AppendLine(message); sb.AppendLine(message);

View File

@@ -135,6 +135,12 @@
<data name="DocProtected" xml:space="preserve"> <data name="DocProtected" xml:space="preserve">
<value>Dokument geschützt</value> <value>Dokument geschützt</value>
</data> </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"> <data name="en-US" xml:space="preserve">
<value>Englisch</value> <value>Englisch</value>
</data> </data>
@@ -174,8 +180,20 @@
<data name="Rejection" xml:space="preserve"> <data name="Rejection" xml:space="preserve">
<value>Ablehnung</value> <value>Ablehnung</value>
</data> </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"> <data name="RejectionReasonQ" xml:space="preserve">
<value>Warum lehnen Sie den Vertrag ab?</value> <value>Bitte geben Sie einen Grund an:</value>
</data> </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>

View File

@@ -135,6 +135,12 @@
<data name="DocProtected" xml:space="preserve"> <data name="DocProtected" xml:space="preserve">
<value>Document protected</value> <value>Document protected</value>
</data> </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"> <data name="en-US" xml:space="preserve">
<value>English</value> <value>English</value>
</data> </data>
@@ -174,8 +180,20 @@
<data name="Rejection" xml:space="preserve"> <data name="Rejection" xml:space="preserve">
<value>Rejection</value> <value>Rejection</value>
</data> </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"> <data name="RejectionReasonQ" xml:space="preserve">
<value>Why do you reject the contract?</value> <value>Please give a reason:</value>
</data> </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>

View File

@@ -8,6 +8,7 @@ using static EnvelopeGenerator.Common.Constants;
using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Application.Resources;
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
using EnvelopeGenerator.Application.DTOs;
namespace EnvelopeGenerator.Application.Services namespace EnvelopeGenerator.Application.Services
{ {
@@ -50,18 +51,31 @@ 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, 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>>( var histDTOs = _mapper.MapOrThrow<IEnumerable<EnvelopeHistoryDto>>(
await _repository.ReadAsync( await _repository.ReadAsync(
envelopeId: envelopeId, envelopeId: envelopeId,
userReference: userReference, userReference: userReference,
status: status)); status: status,
withSender: withSender,
withReceiver: withReceiver));
return referenceType is null ? histDTOs : histDTOs.Where(h => h.ReferenceType == referenceType); 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, withReceiver:true);
//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) => 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)) await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now, Comment: comment))

View File

@@ -11,6 +11,9 @@
</ItemGroup> </ItemGroup>
<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"> <Reference Include="DigitalData.UserManager.Domain">
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath> <HintPath>..\..\WebUserManager\DigitalData.UserManager.Domain\bin\Debug\net7.0\DigitalData.UserManager.Domain.dll</HintPath>
</Reference> </Reference>

View File

@@ -1,7 +1,6 @@
using DigitalData.Core.DTO; using DigitalData.Core.DTO;
using EnvelopeGenerator.Application; using EnvelopeGenerator.Application;
using EnvelopeGenerator.Application.Contracts; 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;
@@ -134,7 +133,7 @@ namespace EnvelopeGenerator.Web.Controllers
if (envRcvRes.IsFailed) if (envRcvRes.IsFailed)
{ {
_logger.LogNotice(envRcvRes.Notices); _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( 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.Contracts;
using EnvelopeGenerator.Application.Services;
using EnvelopeGenerator.Common; using EnvelopeGenerator.Common;
using EnvelopeGenerator.Web.Services; using EnvelopeGenerator.Web.Services;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
@@ -71,7 +70,7 @@ namespace EnvelopeGenerator.Web.Controllers
} }
catch(Exception ex) 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(); return this.ViewInnerServiceError();
} }
} }
@@ -105,7 +104,7 @@ namespace EnvelopeGenerator.Web.Controllers
} }
catch(Exception ex) catch(Exception ex)
{ {
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex); _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError(); return this.ViewInnerServiceError();
} }
} }
@@ -118,7 +117,7 @@ namespace EnvelopeGenerator.Web.Controllers
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId);
(string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId(); (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]); _logger.LogEnvelopeError(uuid: uuid, signature: signature, message: _localizer[WebKey.WrongEnvelopeReceiverId]);
return Unauthorized(); return Unauthorized();
@@ -126,19 +125,45 @@ namespace EnvelopeGenerator.Web.Controllers
_logger.LogInformation($"Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]"); _logger.LogInformation($"Envelope UUID: [{uuid}]\nReceiver Signature: [{signature}]");
return await _envRcvService.VerifyAccessCodeAsync(uuid: uuid, signature: signature, accessCode: access_code).ThenAsync( //check access code
SuccessAsync: async isVerified =>
{
EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId); EnvelopeResponse response = await envelopeOldService.LoadEnvelope(envelopeReceiverId);
if (isVerified) 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
{ {
database.Services.actionService.EnterCorrectAccessCode(response.Envelope, response.Receiver); //for history
ViewData["EnvelopeKey"] = envelopeReceiverId; 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>( return await _envRcvService.ReadByUuidSignatureAsync(uuid: uuid, signature: signature).ThenAsync<EnvelopeReceiverDto, IActionResult>(
SuccessAsync: async er => SuccessAsync: async er =>
{ {
if(await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress)) //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);
}
//check if it has already signed
if (await _historyService.IsSigned(envelopeId: er.Envelope!.Id, userReference: er.Receiver!.EmailAddress))
return View("EnvelopeSigned"); return View("EnvelopeSigned");
if (response.Envelope.Documents.Count > 0) if (response.Envelope.Documents.Count > 0)
@@ -149,6 +174,7 @@ namespace EnvelopeGenerator.Web.Controllers
} }
else else
{ {
_logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, message: "No document was found.");
return this.ViewDocumentNotFound(); return this.ViewDocumentNotFound();
} }
@@ -161,7 +187,8 @@ namespace EnvelopeGenerator.Web.Controllers
}; };
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties { var authProperties = new AuthenticationProperties
{
AllowRefresh = false, AllowRefresh = false,
IsPersistent = false IsPersistent = false
}; };
@@ -184,31 +211,14 @@ namespace EnvelopeGenerator.Web.Controllers
} }
); );
} }
else catch (Exception ex)
{ {
database.Services.actionService.EnterIncorrectAccessCode(response.Envelope, response.Receiver); //for history _logger.LogEnvelopeError(envelopeReceiverId: envelopeReceiverId, exception: ex);
Response.StatusCode = StatusCodes.Status401Unauthorized;
return View("EnvelopeLocked")
.WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language)
.WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value);
}
},
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)
{
_logger.LogEnvelopeError(envelopeEeceiverId: envelopeReceiverId, exception: ex);
return this.ViewInnerServiceError(); return this.ViewInnerServiceError();
} }
} }
[Authorize]
[HttpGet("EnvelopeKey/{envelopeReceiverId}/Success")] [HttpGet("EnvelopeKey/{envelopeReceiverId}/Success")]
public async Task<IActionResult> EnvelopeSigned(string envelopeReceiverId) public async Task<IActionResult> EnvelopeSigned(string envelopeReceiverId)
{ {
@@ -237,7 +247,38 @@ namespace EnvelopeGenerator.Web.Controllers
} }
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}/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(); return this.ViewInnerServiceError();
} }
} }

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"> <div class="page container p-5">
<header class="text-center"> <header class="text-center">

View File

@@ -17,6 +17,10 @@
<link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" /> <link rel="stylesheet" href="~/lib/flag-icons-main/css/flag-icons.min.css" asp-append-version="true" />
</head> </head>
<body> <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/jquery/dist/jquery.min.js"></script>
<script src="~/lib/popper/dist/umd/popper.min.js"></script> <script src="~/lib/popper/dist/umd/popper.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.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 LockedFooterBody = nameof(LockedFooterBody);
public static readonly string WrongAccessCode = nameof(WrongAccessCode); public static readonly string WrongAccessCode = nameof(WrongAccessCode);
public static readonly string SignDoc = nameof(SignDoc); 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 DocProtected = nameof(DocProtected);
public static readonly string Complete = nameof(Complete); public static readonly string Complete = nameof(Complete);
public static readonly string EnvelopeInfo1 = nameof(EnvelopeInfo1); public static readonly string EnvelopeInfo1 = nameof(EnvelopeInfo1);
@@ -26,5 +28,9 @@
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 and = nameof(and);
public static readonly string Hello = nameof(Hello); 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; color: #fff;
} }
.page header .icon.rejected {
background-color: #e4d8d5;
color: #fff;
}
.page .form { .page .form {
max-width: 30rem; max-width: 30rem;
margin: 2rem auto; margin: 2rem auto;

View File

@@ -9,11 +9,19 @@ class API {
return `/api/envelope/reject`; return `/api/envelope/reject`;
} }
static get REJECT_REDIR_URL(){
return `/envelopekey/${API.ENV_KEY}/rejected`;
}
static __XSRF_TOKEN static __XSRF_TOKEN
static get XSRF_TOKEN() { static get XSRF_TOKEN() {
API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value; API.__XSRF_TOKEN ??= document.getElementsByName('__RequestVerificationToken')[0].value;
return API.__XSRF_TOKEN; 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, { const submitForm = async form => await fetch(form.action, {
@@ -39,3 +47,7 @@ const createRequest = async (method, url, body, contentType) => {
const createPost = (url, body, contentType) => createRequest('POST', 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) if (!result.isConfirmed)
return; return;
const res = result.value; const res = result.value;
console.log(res)
if (res.ok) { if (res.ok) {
alert('rejected') redirRejected()
} }
else else
alert('fail') Swal.showValidationMessage(`Request failed: ${res.message}`);
})); }));