Compare commits

...

16 Commits

Author SHA1 Message Date
OlgunR
45377ea61c Merge branch 'master' of https://vcs.digitaldata.works/AppStd/EnvelopeGenerator 2026-03-13 10:44:39 +01:00
OlgunR
b5748550d1 Fix typo in document confirmation message
Corrected "red" to "read" in the DocumentSuccessfullyConfirmed resource string to ensure proper messaging.
2026-03-13 10:44:00 +01:00
64c018b92e Add DbSets for ElementAnnotation and DocumentStatus
Added DocumentReceiverElementAnnotations (ElementAnnotation) and DocumentStatus DbSet properties to EGDbContextBase to support database operations for these entities.
2026-03-12 16:11:50 +01:00
176672d7eb Add interface import and update email sending condition
Added import for EnvelopeGenerator.Domain.Interfaces. Updated logic to send final emails to receivers only if the envelope requires "Read and Sign," adding an extra check to the email dispatch condition.
2026-03-11 17:45:27 +01:00
05d54e87c3 Bump version to 3.12.3 in project file
Updated EnvelopeGenerator.Web.csproj to increment <Version>, <AssemblyVersion>, and <FileVersion> from 3.12.2 to 3.12.3, preparing for a new release. No other changes included.
2026-03-11 14:19:15 +01:00
06c2a07fbc Replace DateTime.UtcNow with DateTime.Now for timestamps
Switched all audit and creation timestamps from UTC to local time
by replacing DateTime.UtcNow with DateTime.Now across the codebase.
This affects audit fields, object creation, and default values for
date/time properties.
2026-03-11 14:11:23 +01:00
7cb1546934 Add Reject endpoint to AnnotationController
Introduced a new Reject endpoint for users with the ReceiverFull role to reject annotations, with optional reason support. Marked the endpoint as obsolete for future exception handling updates. Also standardized the Unauthorized response to remove the custom error message.
2026-03-11 12:09:23 +01:00
60db762bcc Bump project version to 3.12.2
Updated EnvelopeGenerator.Web.csproj to increment <Version>, <AssemblyVersion>, and <FileVersion> from 3.12.1 to 3.12.2, reflecting the new release. No other changes were made.
2026-03-11 12:08:48 +01:00
5e840db04c Refactor envelope rejection logic in EnvelopeController
Clarified and streamlined the handling of rejected envelopes:
- Moved retrieval of rejecting receivers for clarity.
- Signed out users when any rejecting receivers are present.
- Improved determination of "external" users.
- Updated condition for showing the EnvelopeRejected view.
- Temporarily hardcoded ViewBag.IsExt with a TODO for future fix.
- Removed redundant code for better maintainability.
2026-03-11 12:05:20 +01:00
e724a74f9c Bump version to 3.12.1 in project file
Updated <Version>, <AssemblyVersion>, and <FileVersion> in EnvelopeGenerator.Web.csproj from 3.12.0 to 3.12.1 to reflect a new patch release. No other changes were made.
2026-03-11 11:19:17 +01:00
48b7afcdc1 Restrict rejection check to ReadAndSign envelopes
Previously, rejection logic was applied to all envelopes. Now, the check for rejected receivers and the "EnvelopeRejected" view are only executed if the envelope is of the "ReadAndSign" type, preventing unnecessary rejection handling for other envelope types.
2026-03-11 11:16:08 +01:00
717da90c01 Add .NET 7.0 support and update project dependencies
Added net7.0 to TargetFrameworks in EnvelopeGenerator.Web.csproj and introduced a conditional ItemGroup with required package references for .NET 7.0 compatibility. Also removed clipboard2.svg from the list of included static files.
2026-03-11 11:07:33 +01:00
8054bb377d Refine rejection check for read-and-sign envelopes
Only return 423 Locked if envelope is read-and-sign and has a rejection history. Also add missing using for Domain.Interfaces in AnnotationController.
2026-03-11 09:43:35 +01:00
200258ff73 Update EnvelopeDto.ReadOnly to use IsReadAndConfirm()
Refactored the ReadOnly property in EnvelopeDto to use the IsReadAndConfirm() extension method instead of directly checking EnvelopeTypeId. Marked the property as [Obsolete] and advised using EnvelopeExtensions.IsReadAndConfirm.
2026-03-11 09:43:22 +01:00
fa73d939b5 Only check rejection for read-and-sign envelopes
Previously, rejection checks were performed for all envelopes. Now, the code checks for rejecting receivers only if the envelope is of the "read-and-sign" type, avoiding unnecessary queries and logic for other envelope types.
2026-03-11 09:29:24 +01:00
ca9e25abcb Add IsReadAndSign extension method to IEnvelope
Introduced the IsReadAndSign method to IEnvelope extensions, which returns true when EnvelopeTypeId is not 2. This allows clear differentiation between "Read and Sign" and "Read and Confirm" envelope types.
2026-03-11 09:28:40 +01:00
13 changed files with 72 additions and 24 deletions

View File

@@ -75,10 +75,12 @@ public record EnvelopeDto : IEnvelope
/// </summary>
public int? EnvelopeTypeId { get; set; }
// TODO: use ReadAndConfirm property name
/// <summary>
///
/// </summary>
public bool ReadOnly => EnvelopeTypeId == 2;
[Obsolete("Use EnvelopeExtensions.IsReadAndConfirm extension metot instead.")]
public bool ReadOnly => this.IsReadAndConfirm();
/// <summary>
///

View File

@@ -13,12 +13,12 @@ public static class AutoMapperAuditingExtensions
/// </summary>
public static IMappingExpression<TSource, TDestination> MapAddedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
where TDestination : IHasAddedWhen
=> expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
=> expression.ForMember(dest => dest.AddedWhen, opt => opt.MapFrom(_ => DateTime.Now));
/// <summary>
/// Maps <see cref="IHasChangedWhen.ChangedWhen"/> to the current UTC time.
/// </summary>
public static IMappingExpression<TSource, TDestination> MapChangedWhen<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
where TDestination : IHasChangedWhen
=> expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.UtcNow));
=> expression.ForMember(dest => dest.ChangedWhen, opt => opt.MapFrom(_ => DateTime.Now));
}

View File

@@ -113,7 +113,7 @@ public abstract class SendMailHandler<TNotification> : INotificationHandler<TNot
EmailAddress = notification.EmailAddress,
EmailBody = temp.Body,
EmailSubj = temp.Subject,
AddedWhen = DateTime.UtcNow,
AddedWhen = DateTime.Now,
AddedWho = DispatcherParams.AddedWho,
SendingProfile = DispatcherParams.SendingProfile,
ReminderTypeId = DispatcherParams.ReminderTypeId,

View File

@@ -27,7 +27,7 @@ public class MappingProfile : Profile
CreateMap<UpdateDocStatusCommand, DocumentStatus>()
.ForMember(dest => dest.Envelope, opt => opt.Ignore())
.ForMember(dest => dest.Receiver, opt => opt.Ignore())
.ForMember(dest => dest.StatusChangedWhen, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.StatusChangedWhen, opt => opt.MapFrom(src => DateTime.Now))
.MapChangedWhen();
}
}

View File

@@ -34,7 +34,7 @@ public record CreateHistoryCommand : EnvelopeReceiverQueryBase, IRequest<History
/// <summary>
///
/// </summary>
public DateTime AddedWhen { get; } = DateTime.UtcNow;
public DateTime AddedWhen { get; } = DateTime.Now;
/// <summary>
///

View File

@@ -448,7 +448,7 @@
<value>Document has been reset.</value>
</data>
<data name="DocumentSuccessfullyConfirmed" xml:space="preserve">
<value>Document successfully red and confirmed!</value>
<value>Document successfully read and confirmed!</value>
</data>
<data name="DocumentConfirmedConfirmationMessage" xml:space="preserve">
<value>You have read and confirmed the document. You will receive a written confirmation afterwards.</value>

View File

@@ -15,6 +15,7 @@ Imports DigitalData.Core.Abstraction.Application
Imports EnvelopeGenerator.Infrastructure
Imports Microsoft.EntityFrameworkCore
Imports DigitalData.Core.Abstractions
Imports EnvelopeGenerator.Domain.Interfaces
Namespace Jobs
Public Class FinalizeDocumentJob
@@ -350,7 +351,7 @@ Namespace Jobs
Logger.Warn($"No SendFinalEmailToCreator - oMailToCreator [{oMailToCreator}] <> [{FinalEmailType.No}] ")
End If
If oMailToReceivers <> FinalEmailType.No Then
If oMailToReceivers <> FinalEmailType.No And pEnvelope.IsReadAndSign() Then
Logger.Debug("Sending emails to receivers..")
SendFinalEmailToReceivers(pEnvelope) ', pAttachment
Else

View File

@@ -11,5 +11,10 @@
{
return envelope.EnvelopeTypeId == 2;
}
public static bool IsReadAndSign(this IEnvelope envelope)
{
return envelope.EnvelopeTypeId != 2;
}
}
}

View File

@@ -47,6 +47,8 @@ public abstract class EGDbContextBase : DbContext
public DbSet<Signature> DocumentReceiverElements { get; set; }
public DbSet<ElementAnnotation> DocumentReceiverElementAnnotations { get; set; }
public DbSet<DocumentStatus> DocumentStatus { get; set; }
public DbSet<EmailTemplate> EmailTemplate { get; set; }

View File

@@ -215,7 +215,7 @@ public static class Extensions
Title = faker.Lorem.Paragraph(faker.Random.Number(1, 2)),
Message = faker.Lorem.Paragraph(faker.Random.Number(2, 5)),
TfaEnabled = tfaEnabled,
AddedWhen = DateTime.UtcNow,
AddedWhen = DateTime.Now,
CertificationType = (int)CertificationType.AdvancedElectronicSignature,
UseAccessCode = false,
ContractType = (int)ContractType.Contract,
@@ -273,9 +273,9 @@ public static class Extensions
EnvelopeId = envelopeId,
ReceiverId = receiverId,
Status = ReceiverStatus.Unsigned,
AddedWhen = DateTime.UtcNow,
AddedWhen = DateTime.Now,
AccessCode = faker.Random.Number(1000, 9999).ToString(),
ChangedWhen = DateTime.UtcNow,
ChangedWhen = DateTime.Now,
CompanyName = faker.Company.CompanyName(),
JobTitle = faker.Name.JobTitle(),
Name = faker.Name.FullName(),

View File

@@ -6,6 +6,7 @@ using EnvelopeGenerator.Application.Common.Notifications.DocSigned;
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
using EnvelopeGenerator.Application.Histories.Queries;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Interfaces;
using EnvelopeGenerator.Web.Extensions;
using MediatR;
using Microsoft.AspNetCore.Authentication;
@@ -65,7 +66,7 @@ public class AnnotationController : ControllerBase
// Again check if receiver has already signed
if (await _mediator.IsSignedAsync(uuid, signature, cancel))
return Problem(statusCode: 409);
else if (await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel))
else if (er.Envelope.IsReadAndSign() && await _mediator.AnyHistoryAsync(uuid, new[] { EnvelopeStatus.EnvelopeRejected, EnvelopeStatus.DocumentRejected }, cancel))
return Problem(statusCode: 423);
var docSignedNotification = await _mediator
@@ -80,6 +81,7 @@ public class AnnotationController : ControllerBase
return Ok();
}
//TODO: add logic to check if it is already rejected or signed
[Authorize(Roles = Role.ReceiverFull)]
[HttpPost("reject")]
[Obsolete("Use DigitalData.Core.Exceptions and .Middleware")]
@@ -100,7 +102,7 @@ public class AnnotationController : ControllerBase
if (envRcvRes.IsFailed)
{
_logger.LogNotice(envRcvRes.Notices);
return Unauthorized("you are not authirized");
return Unauthorized();
}
var histRes = await _histService.RecordAsync(envRcvRes.Data.EnvelopeId, userReference: mail, EnvelopeStatus.DocumentRejected, comment: reason);

View File

@@ -7,6 +7,7 @@ using EnvelopeGenerator.Application.Common.Interfaces.Services;
using EnvelopeGenerator.Application.EnvelopeReceivers.Queries;
using EnvelopeGenerator.Application.Resources;
using EnvelopeGenerator.Domain.Constants;
using EnvelopeGenerator.Domain.Interfaces;
using EnvelopeGenerator.PdfEditor;
using EnvelopeGenerator.Web.Extensions;
using EnvelopeGenerator.Web.Models;
@@ -78,13 +79,18 @@ public class EnvelopeController : ViewControllerBase
return this.ViewEnvelopeNotFound();
#region Rejected or Signed
//check rejection
var rejRcvrs = await _historyService.ReadRejectingReceivers(er.Envelope!.Id);
if (rejRcvrs.Any())
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
ViewBag.IsExt = !rejRcvrs.Contains(er.Receiver); //external if the current user is not rejected
return View("EnvelopeRejected", er);
var isExt = !rejRcvrs.Where(rcv => rcv.Id == er.Receiver!.Id).Any(); //external if the current user is not rejected
if (er.Envelope.IsReadAndSign() || !isExt)
{
//TODO: Normally assigned to the isExt variable. However, since the relevant keys are not defined in the resx files, it was assigned false. Fix this.
ViewBag.IsExt = true;
return View("EnvelopeRejected", er);
}
}
//check if it has already signed
@@ -162,13 +168,19 @@ public class EnvelopeController : ViewControllerBase
}
var er_secret = er_secret_res.Data;
//check rejection
var rejRcvrs = await _historyService.ReadRejectingReceivers(er_secret.Envelope!.Id);
if (rejRcvrs.Any())
{
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
ViewBag.IsExt = !rejRcvrs.Contains(er_secret.Receiver); //external if the current user is not rejected
return View("EnvelopeRejected", er_secret);
var isExt = !rejRcvrs.Where(rcv => rcv.Id == er_secret.Receiver!.Id).Any(); //external if the current user is not rejected
//check rejection if the envelope is read-and-sign or non-external (internal)
if (er_secret.Envelope.IsReadAndSign() || !isExt)
{
//TODO: Normally assigned to the isExt variable. However, since the relevant keys are not defined in the resx files, it was assigned false. Fix this.
ViewBag.IsExt = true;
return View("EnvelopeRejected", er_secret);
}
}
// show envelope if already logged in

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net7.0;net8.0;net9.0</TargetFrameworks>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PackageId>EnvelopeGenerator.Web</PackageId>
@@ -12,9 +12,9 @@
<PackageTags>digital data envelope generator web</PackageTags>
<Description>EnvelopeGenerator.Web is an ASP.NET MVC application developed to manage signing processes. It uses Entity Framework Core (EF Core) for database operations. The user interface for signing processes is developed with Razor View Engine (.cshtml files) and JavaScript under wwwroot, integrated with PSPDFKit. This integration allows users to view and sign documents seamlessly.</Description>
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
<Version>3.12.0</Version> <!-- NuGet package version -->
<AssemblyVersion>3.12.0.0</AssemblyVersion> <!-- Assembly version for API compatibility -->
<FileVersion>3.12.0.0</FileVersion> <!-- Windows file version -->
<Version>3.12.3</Version> <!-- NuGet package version -->
<AssemblyVersion>3.12.3.0</AssemblyVersion> <!-- Assembly version for API compatibility -->
<FileVersion>3.12.3.0</FileVersion> <!-- Windows file version -->
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
</PropertyGroup>
@@ -626,7 +626,6 @@
<None Include="wwwroot\lib\bootstrap-icons\icons\clipboard2-pulse.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clipboard2-x-fill.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clipboard2-x.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clipboard2.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clock-fill.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clock-history.svg" />
<None Include="wwwroot\lib\bootstrap-icons\icons\clock.svg" />
@@ -2093,6 +2092,31 @@
<None Include="wwwroot\lib\bootstrap-icons\icons\zoom-out.svg" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net7.0'">
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.11" />
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.0" />
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="3.1.1" />
<PackageReference Include="HtmlSanitizer" Version="9.0.892" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.20" />
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="7.0.20" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.3.4" />
<PackageReference Include="Quartz" Version="3.7.0" />
<PackageReference Include="Quartz.AspNetCore" Version="3.7.0" />
<PackageReference Include="Quartz.Plugins" Version="3.7.0" />
<PackageReference Include="Quartz.Serialization.Json" Version="3.7.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="7.0.0" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="7.0.0" />
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="7.0.1" />
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="BuildBundlerMinifier2022" Version="2.9.9" />
<PackageReference Include="DigitalData.Core.API" Version="2.2.1" />