diff --git a/EnvelopeGenerator.Application/Contracts/IConfigService.cs b/EnvelopeGenerator.Application/Contracts/IConfigService.cs index d53f0bdd..80702fac 100644 --- a/EnvelopeGenerator.Application/Contracts/IConfigService.cs +++ b/EnvelopeGenerator.Application/Contracts/IConfigService.cs @@ -5,7 +5,7 @@ using EnvelopeGenerator.Domain.Entities; namespace EnvelopeGenerator.Application.Contracts { - public interface IConfigService : IBasicCRUDService + public interface IConfigService : IReadService { Task> ReadFirstAsync(); diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeHistoryService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeHistoryService.cs index d6c5e671..b72bdec2 100644 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeHistoryService.cs +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeHistoryService.cs @@ -3,7 +3,6 @@ using DigitalData.Core.DTO; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Domain.Entities; -using EnvelopeGenerator.Infrastructure.Contracts; using static EnvelopeGenerator.Common.Constants; namespace EnvelopeGenerator.Application.Contracts diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeMailService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeMailService.cs index f4b00369..f57967f2 100644 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeMailService.cs @@ -1,6 +1,6 @@ using DigitalData.Core.DTO; using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts; -using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Common; namespace EnvelopeGenerator.Application.Contracts diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverService.cs index 6403d207..75a897a2 100644 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverService.cs +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeReceiverService.cs @@ -1,15 +1,18 @@ using DigitalData.Core.Abstractions.Application; using DigitalData.Core.DTO; -using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; +using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Domain.Entities; namespace EnvelopeGenerator.Application.Contracts { - public interface IEnvelopeReceiverService : IBasicCRUDService + public interface IEnvelopeReceiverService : IBasicCRUDService { Task>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false); + Task>> ReadSecretByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true); + Task>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true); Task> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true); @@ -25,5 +28,7 @@ namespace EnvelopeGenerator.Application.Contracts Task> IsExisting(string envelopeReceiverId); Task>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses); + + Task> ReadLastUsedReceiverNameByMail(string mail); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs b/EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs index 4a01e53d..a8cfbab1 100644 --- a/EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs +++ b/EnvelopeGenerator.Application/Contracts/IEnvelopeService.cs @@ -2,7 +2,6 @@ using DigitalData.Core.DTO; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; -using EnvelopeGenerator.Infrastructure.Contracts; namespace EnvelopeGenerator.Application.Contracts { @@ -11,5 +10,7 @@ namespace EnvelopeGenerator.Application.Contracts Task>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false); Task> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false); + + Task>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[]ignore_statuses); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Contracts/IUserReceiverService.cs b/EnvelopeGenerator.Application/Contracts/IUserReceiverService.cs index 17ae83c8..9c6f19fa 100644 --- a/EnvelopeGenerator.Application/Contracts/IUserReceiverService.cs +++ b/EnvelopeGenerator.Application/Contracts/IUserReceiverService.cs @@ -1,7 +1,6 @@ using DigitalData.Core.Abstractions.Application; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; -using EnvelopeGenerator.Infrastructure.Contracts; namespace EnvelopeGenerator.Application.Contracts { diff --git a/EnvelopeGenerator.Application/DTOs/ConfigDto.cs b/EnvelopeGenerator.Application/DTOs/ConfigDto.cs index 751ab329..f96f131d 100644 --- a/EnvelopeGenerator.Application/DTOs/ConfigDto.cs +++ b/EnvelopeGenerator.Application/DTOs/ConfigDto.cs @@ -1,4 +1,7 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; +using System.Text.Json.Serialization; + +namespace EnvelopeGenerator.Application.DTOs { public record ConfigDto( string DocumentPath, @@ -8,5 +11,10 @@ string ExportPath, string DocumentPathDmz, string ExportPathDmz, - string DocumentPathMoveAftsend); + string DocumentPathMoveAftsend) : IUnique + { + [JsonIgnore] + [Obsolete("Configuration does not have an ID; it represents a single table in the database.")] + public int Id => throw new InvalidOperationException("This configuration does not support an ID as it represents a single row in the database."); + }; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/DocumentReceiverElementDto.cs b/EnvelopeGenerator.Application/DTOs/DocumentReceiverElementDto.cs index 6e109e68..aff23a33 100644 --- a/EnvelopeGenerator.Application/DTOs/DocumentReceiverElementDto.cs +++ b/EnvelopeGenerator.Application/DTOs/DocumentReceiverElementDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record DocumentReceiverElementDto( int Id, @@ -18,5 +20,5 @@ DateTime? ChangedWhen, double Top, double Left - ); + ): IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs b/EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs index 4037c064..2decac1f 100644 --- a/EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs +++ b/EnvelopeGenerator.Application/DTOs/DocumentStatusDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record DocumentStatusDto( int Id, @@ -8,5 +10,5 @@ DateTime? StatusChangedWhen, string Value, DateTime AddedWhen, - DateTime? ChangedWhen); + DateTime? ChangedWhen) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs b/EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs index 5ec688ab..8eaa798f 100644 --- a/EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EmailTemplateDto.cs @@ -1,8 +1,10 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record EmailTemplateDto( int Id, string Name, string Body, - string Subject); + string Subject) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs index 44547d1e..34d38990 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeCertificateDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record EnvelopeCertificateDto( int Id, @@ -8,5 +10,5 @@ int CreatorId, string CreatorName, string CreatorEmail, - int EnvelopeStatus); + int EnvelopeStatus) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs index caa9c335..340b3a88 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeDocumentDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record EnvelopeDocumentDto ( @@ -6,5 +8,5 @@ int EnvelopeId, DateTime AddedWhen, IEnumerable? Elements - ); + ) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs index 0413453a..02db9593 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeDto.cs @@ -1,10 +1,11 @@ -using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes; +using DigitalData.Core.Abstractions; +using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes; using DigitalData.UserManager.Application.DTOs.User; using EnvelopeGenerator.Domain.Entities; namespace EnvelopeGenerator.Application.DTOs { - public record EnvelopeDto() + public record EnvelopeDto() : IUnique { public int Id { get; set; } diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeHistory/EnvelopeHistoryDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeHistory/EnvelopeHistoryDto.cs index 7967ac3c..0de3f3fb 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeHistory/EnvelopeHistoryDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeHistory/EnvelopeHistoryDto.cs @@ -1,4 +1,5 @@ -using DigitalData.Core.DTO; +using DigitalData.Core.Abstractions; +using DigitalData.Core.DTO; using DigitalData.UserManager.Application.DTOs.User; using EnvelopeGenerator.Application.DTOs.Receiver; using static EnvelopeGenerator.Common.Constants; @@ -10,10 +11,11 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory int EnvelopeId, string UserReference, int Status, + string? StatusName, DateTime AddedWhen, DateTime? ActionDate, UserCreateDto? Sender, ReceiverReadDto? Receiver, ReferenceType ReferenceType, - string? Comment = null) : BaseDTO(Id); + string? Comment = null) : BaseDTO(Id), IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs new file mode 100644 index 00000000..4dfdf6a8 --- /dev/null +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverBasicDto.cs @@ -0,0 +1,29 @@ +using DigitalData.Core.Abstractions; +using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes; + +namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver +{ + public record EnvelopeReceiverBasicDto() : IUnique<(int Envelope, int Receiver)> + { + public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId); + + public int EnvelopeId { get; init; } + + public int ReceiverId { get; init; } + + public int Sequence { get; init; } + + [TemplatePlaceholder("[NAME_RECEIVER]")] + public string? Name { get; init; } + + public string? JobTitle { get; init; } + + public string? CompanyName { get; init; } + + public string? PrivateMessage { get; init; } + + public DateTime AddedWhen { get; init; } + + public DateTime? ChangedWhen { get; init; } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverDto.cs new file mode 100644 index 00000000..49625eee --- /dev/null +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverDto.cs @@ -0,0 +1,11 @@ +using EnvelopeGenerator.Application.DTOs.Receiver; + +namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver +{ + public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto() + { + public EnvelopeDto? Envelope { get; set; } + + public ReceiverReadDto? Receiver { get; set; } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverSecretDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverSecretDto.cs new file mode 100644 index 00000000..511c6d42 --- /dev/null +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiver/EnvelopeReceiverSecretDto.cs @@ -0,0 +1,4 @@ +namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver +{ + public record EnvelopeReceiverSecretDto(string? AccessCode) : EnvelopeReceiverDto; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiverDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeReceiverDto.cs deleted file mode 100644 index e2fbcdca..00000000 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeReceiverDto.cs +++ /dev/null @@ -1,31 +0,0 @@ -using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes; -using EnvelopeGenerator.Application.DTOs.Receiver; - -namespace EnvelopeGenerator.Application.DTOs -{ - public record EnvelopeReceiverDto() - { - public int EnvelopeId { get; set; } - - public int ReceiverId { get; set; } - - public int Sequence { get; set; } - - [TemplatePlaceholder("[NAME_RECEIVER]")] - public string? Name { get; set; } - - public string? JobTitle { get; set; } - - public string? CompanyName { get; set; } - - public string? PrivateMessage { get; set; } - - public DateTime AddedWhen { get; set; } - - public DateTime? ChangedWhen { get; set; } - - public EnvelopeDto? Envelope { get; set; } - - public ReceiverReadDto? Receiver { get; set; } - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs b/EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs index 2342784d..f7f55ac3 100644 --- a/EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs +++ b/EnvelopeGenerator.Application/DTOs/EnvelopeTypeDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record EnvelopeTypeDto( int Id, @@ -15,5 +17,5 @@ bool? SendReminderEmails, int? FirstReminderDays, int? ReminderIntervalDays, - int? ContractType); + int? ContractType) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverReadDto.cs b/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverReadDto.cs index 4c5d5c69..ec6e5b76 100644 --- a/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverReadDto.cs +++ b/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverReadDto.cs @@ -1,4 +1,6 @@ using DigitalData.Core.DTO; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; +using System.Text.Json.Serialization; namespace EnvelopeGenerator.Application.DTOs.Receiver { @@ -6,6 +8,12 @@ namespace EnvelopeGenerator.Application.DTOs.Receiver int Id, string EmailAddress, string Signature, - DateTime AddedWhen - ) : BaseDTO(Id); + DateTime AddedWhen + ) : BaseDTO(Id) + { + [JsonIgnore] + public IEnumerable? EnvelopeReceivers { get; init; } + + public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name; + }; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverUpdateDto.cs b/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverUpdateDto.cs index a6818b3a..8f765667 100644 --- a/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverUpdateDto.cs +++ b/EnvelopeGenerator.Application/DTOs/Receiver/ReceiverUpdateDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs.Receiver +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs.Receiver { - public record ReceiverUpdateDto(); + public record ReceiverUpdateDto(int Id) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs b/EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs index 8c80ecd8..8630838a 100644 --- a/EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs +++ b/EnvelopeGenerator.Application/DTOs/UserReceiverDto.cs @@ -1,4 +1,6 @@ -namespace EnvelopeGenerator.Application.DTOs +using DigitalData.Core.Abstractions; + +namespace EnvelopeGenerator.Application.DTOs { public record UserReceiverDto( int Id, @@ -7,5 +9,5 @@ string Name, string CompanyName, string JobTitle, - DateTime AddedWhen); + DateTime AddedWhen) : IUnique; } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj index 1704c760..5ca8bdf4 100644 --- a/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj +++ b/EnvelopeGenerator.Application/EnvelopeGenerator.Application.csproj @@ -12,13 +12,13 @@ - - - - + + + + - - + + diff --git a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs index df3637da..820ddbc1 100644 --- a/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs +++ b/EnvelopeGenerator.Application/MappingProfiles/BasicDtoMappingProfile.cs @@ -1,6 +1,7 @@ using AutoMapper; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.DTOs.Receiver; using EnvelopeGenerator.Domain.Entities; @@ -21,6 +22,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); CreateMap(); CreateMap(); @@ -43,6 +45,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles CreateMap(); CreateMap(); CreateMap(); + CreateMap(); } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx index 1f243747..c7d98b63 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.de-DE.resx @@ -210,6 +210,9 @@ Ein unerwarteter Fehler ist aufgetreten. + + Herzlich willkommen im eSign-Portal + Ungültiger Zugangscode. diff --git a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx index 131a87c5..6cf39478 100644 --- a/EnvelopeGenerator.Application/Resources/Resource.en-US.resx +++ b/EnvelopeGenerator.Application/Resources/Resource.en-US.resx @@ -210,6 +210,9 @@ An unexpected error has occurred. + + Welcome to the eSign portal + Invalid access code. diff --git a/EnvelopeGenerator.Application/Services/ConfigService.cs b/EnvelopeGenerator.Application/Services/ConfigService.cs index 57317fc1..1d164d4f 100644 --- a/EnvelopeGenerator.Application/Services/ConfigService.cs +++ b/EnvelopeGenerator.Application/Services/ConfigService.cs @@ -3,15 +3,13 @@ using DigitalData.Core.Application; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; -using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.Extensions.Caching.Memory; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; namespace EnvelopeGenerator.Application.Services { - public class ConfigService : BasicCRUDService, IConfigService + public class ConfigService : ReadService, IConfigService { private static readonly Guid DefaultConfigCacheId = Guid.NewGuid(); @@ -28,7 +26,7 @@ namespace EnvelopeGenerator.Application.Services var config = await _repository.ReadFirstAsync(); return config is null ? Result.Fail().Notice(LogLevel.Error, Flag.DataIntegrityIssue, "There is no configuration in DB.") - : Result.Success(_mapper.MapOrThrow(config)); + : Result.Success(_mapper.Map(config)); } /// diff --git a/EnvelopeGenerator.Application/Services/DocumentReceiverElementService.cs b/EnvelopeGenerator.Application/Services/DocumentReceiverElementService.cs index 0c8e0c3d..24c25a25 100644 --- a/EnvelopeGenerator.Application/Services/DocumentReceiverElementService.cs +++ b/EnvelopeGenerator.Application/Services/DocumentReceiverElementService.cs @@ -2,10 +2,8 @@ using DigitalData.Core.Application; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; -using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using Microsoft.Extensions.Localization; namespace EnvelopeGenerator.Application.Services { diff --git a/EnvelopeGenerator.Application/Services/DocumentStatusService.cs b/EnvelopeGenerator.Application/Services/DocumentStatusService.cs index 019197ff..2a47922d 100644 --- a/EnvelopeGenerator.Application/Services/DocumentStatusService.cs +++ b/EnvelopeGenerator.Application/Services/DocumentStatusService.cs @@ -2,10 +2,8 @@ using DigitalData.Core.Application; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; -using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using Microsoft.Extensions.Localization; namespace EnvelopeGenerator.Application.Services { diff --git a/EnvelopeGenerator.Application/Services/EmailTemplateService.cs b/EnvelopeGenerator.Application/Services/EmailTemplateService.cs index d31e1430..2f9947f4 100644 --- a/EnvelopeGenerator.Application/Services/EmailTemplateService.cs +++ b/EnvelopeGenerator.Application/Services/EmailTemplateService.cs @@ -1,11 +1,9 @@ using AutoMapper; using DigitalData.Core.Application; -using Microsoft.Extensions.Localization; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using EnvelopeGenerator.Application.Resources; using static EnvelopeGenerator.Common.Constants; using DigitalData.Core.DTO; using Microsoft.Extensions.Logging; @@ -26,7 +24,7 @@ namespace EnvelopeGenerator.Application.Services ? Result.Fail() .Message(Key.InnerServiceError) .Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"EmailTemplateType '{type}' is not found in DB. Please, define required e-mail template.") - : Result.Success(_mapper.MapOrThrow(temp)); + : Result.Success(_mapper.Map(temp)); } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeHistoryService.cs b/EnvelopeGenerator.Application/Services/EnvelopeHistoryService.cs index d7a4a26a..db72280a 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeHistoryService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeHistoryService.cs @@ -1,11 +1,9 @@ using AutoMapper; using DigitalData.Core.Application; -using Microsoft.Extensions.Localization; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using static EnvelopeGenerator.Common.Constants; -using EnvelopeGenerator.Application.Resources; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.DTOs.EnvelopeHistory; using EnvelopeGenerator.Application.DTOs.Receiver; @@ -14,7 +12,7 @@ namespace EnvelopeGenerator.Application.Services { public class EnvelopeHistoryService : CRUDService, IEnvelopeHistoryService { - public EnvelopeHistoryService(IEnvelopeHistoryRepository repository, IStringLocalizer localizer, IMapper mapper) + public EnvelopeHistoryService(IEnvelopeHistoryRepository repository, IMapper mapper) : base(repository, mapper) { } @@ -53,7 +51,7 @@ namespace EnvelopeGenerator.Application.Services public async Task> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false) { - var histDTOs = _mapper.MapOrThrow>( + var histDTOs = _mapper.Map>( await _repository.ReadAsync( envelopeId: envelopeId, userReference: userReference, diff --git a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs index 59f83118..296ad932 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeMailService.cs @@ -5,7 +5,7 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut; using DigitalData.EmailProfilerDispatcher.Abstraction.Services; using DigitalData.UserManager.Application; using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Common; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; @@ -14,7 +14,7 @@ using static EnvelopeGenerator.Common.Constants; namespace EnvelopeGenerator.Application.Services { - public class EnvelopeMailService : EmailOutService, IEnvelopeMailService + public class EnvelopeMailService : EmailOutService, IEnvelopeMailService { private readonly IEmailTemplateService _tempService; private readonly IEnvelopeReceiverService _envRcvService; diff --git a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs index a244c19a..bd09cac4 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeReceiverService.cs @@ -2,7 +2,7 @@ using DigitalData.Core.Application; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; @@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging; namespace EnvelopeGenerator.Application.Services { - public class EnvelopeReceiverService : BasicCRUDService, IEnvelopeReceiverService + public class EnvelopeReceiverService : BasicCRUDService, IEnvelopeReceiverService { private readonly IStringLocalizer _localizer; @@ -24,13 +24,19 @@ namespace EnvelopeGenerator.Application.Services public async Task>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true) { var env_rcvs = await _repository.ReadBySignatureAsync(signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver); - return Result.Success(_mapper.MapOrThrow>(env_rcvs)); + return Result.Success(_mapper.Map>(env_rcvs)); } public async Task>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false) { var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver); - return Result.Success(_mapper.MapOrThrow>(env_rcvs)); + return Result.Success(_mapper.Map>(env_rcvs)); + } + + public async Task>> ReadSecretByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true) + { + var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver); + return Result.Success(_mapper.Map>(env_rcvs)); } public async Task> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true) @@ -40,7 +46,7 @@ namespace EnvelopeGenerator.Application.Services return Result.Fail() .Message(Key.EnvelopeReceiverNotFound); - return Result.Success(_mapper.MapOrThrow(env_rcv)); + return Result.Success(_mapper.Map(env_rcv)); } public async Task> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true) @@ -119,8 +125,14 @@ namespace EnvelopeGenerator.Application.Services public async Task>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses) { var er_list = await _repository.ReadByUsernameAsync(username: username, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses); - var dto_list = _mapper.MapOrThrow>(er_list); + var dto_list = _mapper.Map>(er_list); return Result.Success(dto_list); } + + public async Task> ReadLastUsedReceiverNameByMail(string mail) + { + var er = await _repository.ReadLastByReceiver(mail); + return er is null ? Result.Fail().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name); + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/EnvelopeService.cs b/EnvelopeGenerator.Application/Services/EnvelopeService.cs index 2c394713..fc84d2f6 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeService.cs @@ -3,27 +3,22 @@ using DigitalData.Core.Application; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; -using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging; namespace EnvelopeGenerator.Application.Services { public class EnvelopeService : BasicCRUDService, IEnvelopeService { - private readonly ILogger _logger; - public EnvelopeService(IEnvelopeRepository repository, IMapper mapper, ILogger logger) + public EnvelopeService(IEnvelopeRepository repository, IMapper mapper) : base(repository, mapper) { - _logger = logger; } public async Task>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false) { var envelopes = await _repository.ReadAllWithAsync(documents: documents, history: history, documentReceiverElement: documentReceiverElement); - var readDto = _mapper.MapOrThrow>(envelopes); + var readDto = _mapper.Map>(envelopes); return Result.Success(readDto); } @@ -34,7 +29,14 @@ namespace EnvelopeGenerator.Application.Services if (envelope is null) return Result.Fail(); - var readDto = _mapper.MapOrThrow(envelope); + var readDto = _mapper.Map(envelope); + return Result.Success(readDto); + } + + public async Task>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses) + { + var users = await _repository.ReadByUserAsync(userId: userId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses); + var readDto = _mapper.Map>(users); return Result.Success(readDto); } } diff --git a/EnvelopeGenerator.Application/Services/EnvelopeTypeService.cs b/EnvelopeGenerator.Application/Services/EnvelopeTypeService.cs index d8b00ebc..2bc3cc75 100644 --- a/EnvelopeGenerator.Application/Services/EnvelopeTypeService.cs +++ b/EnvelopeGenerator.Application/Services/EnvelopeTypeService.cs @@ -1,19 +1,30 @@ using AutoMapper; using DigitalData.Core.Application; -using Microsoft.Extensions.Localization; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using EnvelopeGenerator.Application.Resources; +using Microsoft.Extensions.Caching.Memory; +using DigitalData.Core.DTO; +using Microsoft.Extensions.Logging; namespace EnvelopeGenerator.Application.Services { public class EnvelopeTypeService : BasicCRUDService, IEnvelopeTypeService { - public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper) + private static readonly Guid CacheKey = Guid.NewGuid(); + + private readonly IMemoryCache _cache; + + public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper, IMemoryCache cache) : base(repository, mapper) { + _cache = cache; } + + public override async Task>> ReadAllAsync() + => await _cache.GetOrCreateAsync(CacheKey, async entry => await base.ReadAllAsync()) + ?? Result.Fail>().Notice(LogLevel.Error, Flag.NotFound, "No cached envelope types are available in the database. If you have added any envelope types after the server started, please restart the server."); + } } \ No newline at end of file diff --git a/EnvelopeGenerator.Application/Services/ReceiverService.cs b/EnvelopeGenerator.Application/Services/ReceiverService.cs index edbe3d62..422f5c0f 100644 --- a/EnvelopeGenerator.Application/Services/ReceiverService.cs +++ b/EnvelopeGenerator.Application/Services/ReceiverService.cs @@ -1,10 +1,8 @@ using AutoMapper; using DigitalData.Core.Application; -using Microsoft.Extensions.Localization; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using EnvelopeGenerator.Application.Resources; using EnvelopeGenerator.Application.DTOs.Receiver; using DigitalData.Core.DTO; @@ -12,7 +10,7 @@ namespace EnvelopeGenerator.Application.Services { public class ReceiverService : CRUDService, IReceiverService { - public ReceiverService(IReceiverRepository repository, IStringLocalizer localizer, IMapper mapper) + public ReceiverService(IReceiverRepository repository, IMapper mapper) : base(repository, mapper) { } @@ -24,7 +22,7 @@ namespace EnvelopeGenerator.Application.Services if (rcv is null) return Result.Fail(); - return Result.Success(_mapper.MapOrThrow(rcv)); + return Result.Success(_mapper.Map(rcv)); } public async Task DeleteByAsync(string? emailAddress = null, string? signature = null) diff --git a/EnvelopeGenerator.Application/Services/UserReceiverService.cs b/EnvelopeGenerator.Application/Services/UserReceiverService.cs index d241d5bf..08da1906 100644 --- a/EnvelopeGenerator.Application/Services/UserReceiverService.cs +++ b/EnvelopeGenerator.Application/Services/UserReceiverService.cs @@ -1,17 +1,15 @@ using AutoMapper; using DigitalData.Core.Application; -using Microsoft.Extensions.Localization; using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; -using EnvelopeGenerator.Application.Resources; namespace EnvelopeGenerator.Application.Services { public class UserReceiverService : BasicCRUDService, IUserReceiverService { - public UserReceiverService(IUserReceiverRepository repository, IStringLocalizer localizer, IMapper mapper) + public UserReceiverService(IUserReceiverRepository repository, IMapper mapper) : base(repository, mapper) { } diff --git a/EnvelopeGenerator.Common/Constants.vb b/EnvelopeGenerator.Common/Constants.vb index 2d7c26e5..16a19e08 100644 --- a/EnvelopeGenerator.Common/Constants.vb +++ b/EnvelopeGenerator.Common/Constants.vb @@ -26,6 +26,7 @@ MessageCompletionSent = 3005 End Enum + 'TODO: standardize in xwiki Public Enum ReferenceType Receiver Sender diff --git a/EnvelopeGenerator.Domain/Entities/Config.cs b/EnvelopeGenerator.Domain/Entities/Config.cs index 6c91262c..6621beb5 100644 --- a/EnvelopeGenerator.Domain/Entities/Config.cs +++ b/EnvelopeGenerator.Domain/Entities/Config.cs @@ -1,43 +1,41 @@ -using System.ComponentModel; +using DigitalData.Core.Abstractions; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_CONFIG", Schema = "dbo")] - public class Config + public class Config : IUnique { [Column("DOCUMENT_PATH", TypeName = "nvarchar(256)")] - public string DocumentPath { get; set; } + public string? DocumentPath { get; init; } [Column("SENDING_PROFILE", TypeName = "int")] [Required] - [DatabaseGenerated(DatabaseGeneratedOption.None)] // Assuming SENDING_PROFILE is manually entered or controlled by the application logic - [DefaultValue(0)] // This sets the default value for SENDING_PROFILE - public int SendingProfile { get; set; } + public required int SendingProfile { get; init; } [Column("SIGNATURE_HOST", TypeName = "nvarchar(128)")] - public string SignatureHost { get; set; } + public string? SignatureHost { get; init; } [Column("EXTERNAL_PROGRAM_NAME", TypeName = "nvarchar(30)")] - public string ExternalProgramName { get; set; } + public string? ExternalProgramName { get; init; } [Column("EXPORT_PATH", TypeName = "nvarchar(256)")] - public string ExportPath { get; set; } + public string? ExportPath { get; init; } [Column("DOCUMENT_PATH_DMZ", TypeName = "nvarchar(512)")] [Required] - [DefaultValue("")] // This sets the default value for DOCUMENT_PATH_DMZ - public string DocumentPathDmz { get; set; } + public string? DocumentPathDmz { get; init; } [Column("EXPORT_PATH_DMZ", TypeName = "nvarchar(512)")] [Required] - [DefaultValue("")] // This sets the default value for EXPORT_PATH_DMZ - public string ExportPathDmz { get; set; } + public required string ExportPathDmz { get; init; } [Column("DOCUMENT_PATH_MOVE_AFTSEND", TypeName = "nvarchar(512)")] [Required] - [DefaultValue("")] // This sets the default value for DOCUMENT_PATH_MOVE_AFTSEND - public string DocumentPathMoveAftsend { get; set; } + public required string DocumentPathMoveAftsend { get; init; } + + [Obsolete("Configuration does not have an ID; it represents a single table in the database.")] + public int Id => throw new InvalidOperationException("This configuration does not support an ID as it represents a single table in the database."); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/DocumentReceiverElement.cs b/EnvelopeGenerator.Domain/Entities/DocumentReceiverElement.cs index 381b268d..6d165028 100644 --- a/EnvelopeGenerator.Domain/Entities/DocumentReceiverElement.cs +++ b/EnvelopeGenerator.Domain/Entities/DocumentReceiverElement.cs @@ -1,11 +1,12 @@ -using System.ComponentModel; +using DigitalData.Core.Abstractions; +using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_DOCUMENT_RECEIVER_ELEMENT", Schema = "dbo")] - public class DocumentReceiverElement + public class DocumentReceiverElement : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] diff --git a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs index 7ee87a27..dd243b76 100644 --- a/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs +++ b/EnvelopeGenerator.Domain/Entities/DocumentStatus.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_DOCUMENT_STATUS", Schema = "dbo")] - public class DocumentStatus + public class DocumentStatus : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -27,7 +28,7 @@ namespace EnvelopeGenerator.Domain.Entities public DateTime? StatusChangedWhen { get; set; } [Column("VALUE", TypeName = "nvarchar(max)")] - public string Value { get; set; } + public string? Value { get; set; } [Required] [Column("ADDED_WHEN", TypeName = "datetime")] @@ -42,4 +43,4 @@ namespace EnvelopeGenerator.Domain.Entities [ForeignKey("ReceiverId")] public virtual Receiver? Receiver { get; set; } } -} +} \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/EmailTemplate.cs b/EnvelopeGenerator.Domain/Entities/EmailTemplate.cs index c82f3d4e..aef2df9d 100644 --- a/EnvelopeGenerator.Domain/Entities/EmailTemplate.cs +++ b/EnvelopeGenerator.Domain/Entities/EmailTemplate.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_EMAIL_TEMPLATE", Schema = "dbo")] - public class EmailTemplate + public class EmailTemplate : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -12,12 +13,12 @@ namespace EnvelopeGenerator.Domain.Entities public int Id { get; set; } [Column("NAME", TypeName = "nvarchar(64)")] - public string Name { get; set; } + public string? Name { get; set; } [Column("BODY", TypeName = "nvarchar(max)")] - public string Body { get; set; } + public string? Body { get; set; } [Column("SUBJECT", TypeName = "nvarchar(512)")] - public string Subject { get; set; } + public string? Subject { get; set; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/Envelope.cs b/EnvelopeGenerator.Domain/Entities/Envelope.cs index b1ab8438..62f8dfd2 100644 --- a/EnvelopeGenerator.Domain/Entities/Envelope.cs +++ b/EnvelopeGenerator.Domain/Entities/Envelope.cs @@ -1,12 +1,12 @@ -using EnvelopeGenerator.Common; -using EnvelopeGenerator.Common.My.Resources; +using DigitalData.Core.Abstractions; +using EnvelopeGenerator.Common; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE", Schema = "dbo")] - public class Envelope + public class Envelope : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -26,11 +26,11 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("ENVELOPE_UUID", TypeName = "nvarchar(36)")] - public string Uuid { get; set; } + public required string Uuid { get; init; } [Required] [Column("MESSAGE", TypeName = "nvarchar(max)")] - public string Message { get; set; } + public string? Message { get; set; } [Column("EXPIRES_WHEN", TypeName = "datetime")] public DateTime? ExpiresWhen { get; set; } @@ -46,13 +46,13 @@ namespace EnvelopeGenerator.Domain.Entities public DateTime? ChangedWhen { get; set; } [Column("TITLE", TypeName = "nvarchar(128)")] - public string Title { get; set; } + public string? Title { get; set; } [Column("CONTRACT_TYPE")] public int? ContractType { get; set; } [Column("LANGUAGE", TypeName = "nvarchar(5)")] - public string Language { get; set; } + public required string Language { get; set; } [Column("SEND_REMINDER_EMAILS")] public bool? SendReminderEmails { get; set; } diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeCertificate.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeCertificate.cs index c8bd8c6e..f6450954 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeCertificate.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeCertificate.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE_CERTIFICATE", Schema = "dbo")] - public class EnvelopeCertificate + public class EnvelopeCertificate : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -17,11 +18,11 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("ENVELOPE_UUID", TypeName = "nvarchar(36)")] - public string EnvelopeUuid { get; set; } + public required string EnvelopeUuid { get; set; } [Required] [Column("ENVELOPE_SUBJECT", TypeName = "nvarchar(512)")] - public string EnvelopeSubject { get; set; } + public required string EnvelopeSubject { get; set; } [Required] [Column("CREATOR_ID")] @@ -29,11 +30,11 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("CREATOR_NAME", TypeName = "nvarchar(128)")] - public string CreatorName { get; set; } + public required string CreatorName { get; set; } [Required] [Column("CREATOR_EMAIL", TypeName = "nvarchar(128)")] - public string CreatorEmail { get; set; } + public required string CreatorEmail { get; set; } [Required] [Column("ENVELOPE_STATUS")] diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeDocument.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeDocument.cs index b5e64977..f90ddce2 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeDocument.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeDocument.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE_DOCUMENT", Schema = "dbo")] - public class EnvelopeDocument + public class EnvelopeDocument : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -17,18 +18,18 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("FILENAME", TypeName = "nvarchar(256)")] - public string Filename { get; set; } + public required string Filename { get; set; } [Required] [Column("FILEPATH", TypeName = "nvarchar(256)")] - public string Filepath { get; set; } + public required string Filepath { get; set; } [Required] [Column("ADDED_WHEN", TypeName = "datetime")] - public DateTime AddedWhen { get; set; } + public required DateTime AddedWhen { get; set; } [Column("FILENAME_ORIGINAL", TypeName = "nvarchar(256)")] - public string FilenameOriginal { get; set; } + public required string FilenameOriginal { get; set; } public IEnumerable? Elements { get; set; } } diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeHistory.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeHistory.cs index 5c0f0cd1..ef9f33be 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeHistory.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeHistory.cs @@ -1,4 +1,5 @@ -using DigitalData.UserManager.Domain.Entities; +using DigitalData.Core.Abstractions; +using DigitalData.UserManager.Domain.Entities; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using static EnvelopeGenerator.Common.Constants; @@ -6,7 +7,7 @@ using static EnvelopeGenerator.Common.Constants; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE_HISTORY", Schema = "dbo")] - public class EnvelopeHistory + public class EnvelopeHistory : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -19,7 +20,7 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("USER_REFERENCE", TypeName = "nvarchar(128)")] - public string UserReference { get; set; } + public required string UserReference { get; init; } [Required] [Column("STATUS")] @@ -43,11 +44,17 @@ namespace EnvelopeGenerator.Domain.Entities public virtual Receiver? Receiver { get; set; } [NotMapped] - public ReferenceType ReferenceType => (Status / 3) switch + public ReferenceType ReferenceType => (Status / 1000) switch { 1 => ReferenceType.Sender, 2 or 3 => ReferenceType.Receiver, _ => ReferenceType.Unknown, }; + + [NotMapped] + public string? StatusName + => (Enum.IsDefined(typeof(EnvelopeStatus), Status)) + ? Enum.GetName(typeof(EnvelopeStatus), Status) + : null; } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeReceiver.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiver.cs index beef339d..e1374b3e 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeReceiver.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiver.cs @@ -1,45 +1,10 @@ -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")] - public class EnvelopeReceiver + public class EnvelopeReceiver : EnvelopeReceiverBase { - [Key] - [Column("ENVELOPE_ID")] - public int EnvelopeId { get; set; } - - [Key] - [Column("RECEIVER_ID")] - public int ReceiverId { get; set; } - - [Required] - [Column("SEQUENCE")] - public int Sequence { get; set; } - - [Column("NAME", TypeName = "nvarchar(128)")] - public string? Name { get; set; } - - [Column("JOB_TITLE", TypeName = "nvarchar(128)")] - public string? JobTitle { get; set; } - - [Column("COMPANY_NAME", TypeName = "nvarchar(128)")] - public string? CompanyName { get; set; } - - [Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")] - public string? PrivateMessage { get; set; } - - [Column("ACCESS_CODE", TypeName = "nvarchar(64)")] - public string? AccessCode { get; set; } - - [Required] - [Column("ADDED_WHEN", TypeName = "datetime")] - public DateTime AddedWhen { get; set; } - - [Column("CHANGED_WHEN", TypeName = "datetime")] - public DateTime? ChangedWhen { get; set; } - [ForeignKey("EnvelopeId")] public Envelope? Envelope { get; set; } diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs new file mode 100644 index 00000000..ef934a19 --- /dev/null +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs @@ -0,0 +1,46 @@ +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace EnvelopeGenerator.Domain.Entities +{ + [Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")] + public class EnvelopeReceiverBase : IUnique<(int Envelope, int Receiver)> + { + [Key] + [Column("ENVELOPE_ID")] + public int EnvelopeId { get; set; } + + [Key] + [Column("RECEIVER_ID")] + public int ReceiverId { get; set; } + + [Required] + [Column("SEQUENCE")] + public int Sequence { get; set; } + + [Column("NAME", TypeName = "nvarchar(128)")] + public string? Name { get; set; } + + [Column("JOB_TITLE", TypeName = "nvarchar(128)")] + public string? JobTitle { get; set; } + + [Column("COMPANY_NAME", TypeName = "nvarchar(128)")] + public string? CompanyName { get; set; } + + [Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")] + public string? PrivateMessage { get; set; } + + [Column("ACCESS_CODE", TypeName = "nvarchar(64)")] + public string? AccessCode { get; set; } + + [Required] + [Column("ADDED_WHEN", TypeName = "datetime")] + public DateTime AddedWhen { get; set; } + + [Column("CHANGED_WHEN", TypeName = "datetime")] + public DateTime? ChangedWhen { get; set; } + + public (int Envelope, int Receiver) Id => (Envelope: EnvelopeId, Receiver: ReceiverId); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/EnvelopeType.cs b/EnvelopeGenerator.Domain/Entities/EnvelopeType.cs index c1684672..bd837e81 100644 --- a/EnvelopeGenerator.Domain/Entities/EnvelopeType.cs +++ b/EnvelopeGenerator.Domain/Entities/EnvelopeType.cs @@ -1,12 +1,11 @@ -using System; +using DigitalData.Core.Abstractions; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using EnvelopeGenerator.Domain.Entities; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_ENVELOPE_TYPE", Schema = "dbo")] - public class EnvelopeType + public class EnvelopeType : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -15,10 +14,10 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("TITLE", TypeName = "nvarchar(128)")] - public string Title { get; set; } + public required string Title { get; set; } [Column("LANGUAGE", TypeName = "nvarchar(5)")] - public string Language { get; set; } + public string? Language { get; set; } [Column("EXPIRES_DAYS")] public int? ExpiresDays { get; set; } diff --git a/EnvelopeGenerator.Domain/Entities/Receiver.cs b/EnvelopeGenerator.Domain/Entities/Receiver.cs index bfb91c9c..ae39daf4 100644 --- a/EnvelopeGenerator.Domain/Entities/Receiver.cs +++ b/EnvelopeGenerator.Domain/Entities/Receiver.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_RECEIVER", Schema = "dbo")] - public class Receiver + public class Receiver : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -22,5 +23,7 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("ADDED_WHEN", TypeName = "datetime")] public DateTime AddedWhen { get; set; } + + public IEnumerable? EnvelopeReceivers { get; init; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/Entities/UserReceiver.cs b/EnvelopeGenerator.Domain/Entities/UserReceiver.cs index 9b221297..c2fc7c0c 100644 --- a/EnvelopeGenerator.Domain/Entities/UserReceiver.cs +++ b/EnvelopeGenerator.Domain/Entities/UserReceiver.cs @@ -1,10 +1,11 @@ -using System.ComponentModel.DataAnnotations; +using DigitalData.Core.Abstractions; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace EnvelopeGenerator.Domain.Entities { [Table("TBSIG_USER_RECEIVER", Schema = "dbo")] - public class UserReceiver + public class UserReceiver : IUnique { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] @@ -21,16 +22,16 @@ namespace EnvelopeGenerator.Domain.Entities [Required] [Column("NAME", TypeName = "nvarchar(128)")] - public string Name { get; set; } + public required string Name { get; set; } [Column("COMPANY_NAME", TypeName = "nvarchar(128)")] - public string CompanyName { get; set; } + public string? CompanyName { get; set; } [Column("JOB_TITLE", TypeName = "nvarchar(128)")] - public string JobTitle { get; set; } + public string? JobTitle { get; set; } [Required] [Column("ADDED_WHEN", TypeName = "datetime")] - public DateTime AddedWhen { get; set; } + public required DateTime AddedWhen { get; init; } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Domain/EnvelopeGenerator.Domain.csproj b/EnvelopeGenerator.Domain/EnvelopeGenerator.Domain.csproj index 40acf713..3480802f 100644 --- a/EnvelopeGenerator.Domain/EnvelopeGenerator.Domain.csproj +++ b/EnvelopeGenerator.Domain/EnvelopeGenerator.Domain.csproj @@ -7,6 +7,7 @@ + diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/app.config.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/app.config.ts index 869ce43e..c23f1870 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/app.config.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/app.config.ts @@ -1,4 +1,4 @@ -import { ApplicationConfig } from '@angular/core'; +import { ApplicationConfig, APP_INITIALIZER } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; import { provideClientHydration } from '@angular/platform-browser'; @@ -8,6 +8,7 @@ import { UrlService } from './services/url.service'; import { API_URL } from './tokens/index' import { HTTP_INTERCEPTORS, provideHttpClient, withFetch } from '@angular/common/http'; import { HttpRequestInterceptor } from './http.interceptor'; +import { ConfigurationService } from './services/configuration.service'; export const appConfig: ApplicationConfig = { providers: [ @@ -29,6 +30,12 @@ export const appConfig: ApplicationConfig = { provide: HTTP_INTERCEPTORS, useClass: HttpRequestInterceptor, multi: true + }, + { + provide: APP_INITIALIZER, + useFactory: (configService: ConfigurationService) => async () => await configService.ngOnInit(), + deps: [ConfigurationService], + multi: true } ] }; \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html deleted file mode 100644 index f2d68c2d..00000000 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.html +++ /dev/null @@ -1,48 +0,0 @@ - - - @for (colId of displayedColumns; track colId) { - - - - - } - - - - - - - - - - - - - - - -
{{schema[colId].header}} {{schema[colId].field(element)}}   - - -
-
-
{{"element.position"}}
-
{{"element.symbol"}}
-
{{"element.name"}}
-
{{"element.weight"}}
-
-
- {{"element.description"}} - -- Wikipedia -
-
-
\ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss deleted file mode 100644 index 19d1304d..00000000 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.scss +++ /dev/null @@ -1,31 +0,0 @@ -.example-element-row td { - border-bottom-width: 0; - } - - .example-element-detail { - overflow: hidden; - display: flex; - } - - .example-element-diagram { - min-width: 80px; - border: 2px solid black; - padding: 8px; - font-weight: lighter; - margin: 8px 0; - height: 104px; - } - - .example-element-symbol { - font-weight: bold; - font-size: 40px; - line-height: normal; - } - - .example-element-description { - padding: 16px; - } - - .example-element-description-attribution { - opacity: 0.5; - } \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts deleted file mode 100644 index 57c147a7..00000000 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { Component, Input, ViewChild } from '@angular/core'; -import { EnvelopeReceiverService } from '../../services/envelope-receiver.service'; -import { MatTable, MatTableModule } from '@angular/material/table'; -import { CommonModule } from '@angular/common' -import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { animate, state, style, transition, trigger } from '@angular/animations'; - -@Component({ - selector: 'app-envelope-table', - standalone: true, - imports: [MatTableModule, CommonModule, MatTableModule, MatButtonModule, MatIconModule], - templateUrl: './envelope-table.component.html', - animations: [ - trigger('detailExpand', [ - state('collapsed,void', style({ height: '0px', minHeight: '0' })), - state('expanded', style({ height: '*' })), - transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), - ]), - ], - styleUrl: './envelope-table.component.scss' -}) -export class EnvelopeTableComponent { - - @Input() data: Array = [] - - @Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] } - - @Input() displayedColumns: string[] = ['title', 'status', 'type', 'privateMessage', 'addedWhen']; - - @Input() schema: Record any; }> = { - 'title': { - header: 'Title', - field: (element: any) => element.envelope.title - }, - 'status': { - header: 'Status', - field: (element: any) => element.envelope.statusName - }, - 'type': { - header: 'Type', - field: (element: any) => element.envelope.contractType - }, - 'privateMessage': { - header: 'Private Message', - field: (element: any) => element.privateMessage - }, - 'addedWhen': { - header: 'Added When', - field: (element: any) => element.addedWhen - }, - } - - columnsToDisplayWithExpand = [...this.displayedColumns, 'expand']; - - expandedElement: any | null; - - @ViewChild(MatTable) table!: MatTable; - - constructor(private erService: EnvelopeReceiverService) { } - - async ngOnInit() { - if (this.data.length === 0) - this.data = await this.erService.getEnvelopeReceiverAsync(this.options); - } - - public updateTable() { - this.table.renderRows(); - } - - isExpandedRow(index: number, row: any): boolean { - return (row?.envelopeId === this.expandedElement?.envelopeId) && (row?.receiverId === this.expandedElement?.receiverId); - } -} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-input/receiver-input.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-input/receiver-input.component.ts index e01eb995..376cb002 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-input/receiver-input.component.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-input/receiver-input.component.ts @@ -37,19 +37,19 @@ export class ReceiverInputComponent implements OnInit, OnChanges { private setupFiltering(): void { this.filteredOptions = this.control.valueChanges.pipe( startWith(''), - map(value => this.filter(value || '', this.options)), + map(value => this.filter(value || '', this.options, this.index)), ); } control = new FormControl(''); filteredOptions!: Observable; - @Input() options: string[] = []; - @Input() filter: (value: string, options: string[]) => string[] = value => { + @Input() filter: (value: string, options: string[], index?: number) => string[] = value => { const filterValue = value.toLowerCase(); return this.options.filter(option => option.toLowerCase().includes(filterValue)); } + @Input() index?: number; public get text(): string { return this.control.value || ''; diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.html index a7b69ac5..744d5711 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.html +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.html @@ -1,7 +1,7 @@ - diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.html new file mode 100644 index 00000000..6bdca454 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.html @@ -0,0 +1,59 @@ +@if(isFilterable) { + + {{filter.label}} + + +} + +
Email +
+ @for (column of __columnsToDisplay; track column) { + + @if(isSortable) { + + } + @else { + + } + + + } + + + @if(isExpandable) { + + + + + + + + } + @if(isExpandable) { + + + + + } + @else { + + + } +
{{schema[column].header}} {{schema[column].header}} {{schema[column].field(element)}}   + + +
+ @if(__expandedElement === element){ + + } +
+
+@if(paginatorSizeOptions && paginatorSizeOptions.length > 0) { + +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.scss new file mode 100644 index 00000000..155617b3 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.scss @@ -0,0 +1,52 @@ +table { + width: 100%; +} + +tr.example-detail-row { + height: 0; +} + +tr.example-element-row:not(.example-expanded-row):hover { + background: whitesmoke; +} + +tr.example-element-row:not(.example-expanded-row):active { + background: #efefef; +} + +.example-element-row td { + border-bottom-width: 0; +} + +.example-element-detail { + overflow: hidden; + display: flex; +} + +.example-element-diagram { + min-width: 80px; + border: 2px solid black; + padding: 8px; + font-weight: lighter; + margin: 8px 0; + height: 104px; +} + +.example-element-symbol { + font-weight: bold; + font-size: 40px; + line-height: normal; +} + +.example-element-description { + padding: 16px; +} + +.example-element-description-attribution { + opacity: 0.5; +} + +.mat-mdc-form-field { + font-size: 14px; + width: 100%; +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.spec.ts new file mode 100644 index 00000000..0c704ba9 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DDTable } from './dd-table.component'; + +describe('TableExpandableRowsExampleComponent', () => { + let component: DDTable; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [DDTable] + }) + .compileComponents(); + + fixture = TestBed.createComponent(DDTable); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.ts new file mode 100644 index 00000000..4493ff6c --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/dd-table/dd-table.component.ts @@ -0,0 +1,103 @@ +import { AfterViewInit, Component, Input, ViewChild, inject } from '@angular/core'; +import { animate, state, style, transition, trigger } from '@angular/animations'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatTable, MatTableDataSource, MatTableModule } from '@angular/material/table'; +import { ConfigurationService } from '../../../services/configuration.service'; +import { MatInputModule } from '@angular/material/input'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatSort, MatSortModule } from '@angular/material/sort'; +import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; + +/** + * @title Table with expandable rows + */ +@Component({ + selector: 'dd-table', + styleUrl: 'dd-table.component.scss', + templateUrl: 'dd-table.component.html', + animations: [ + trigger('detailExpand', [ + state('collapsed,void', style({ height: '0px', minHeight: '0' })), + state('expanded', style({ height: '*' })), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ], + standalone: true, + imports: [ + MatTableModule, + MatButtonModule, + MatIconModule, + MatFormFieldModule, + MatInputModule, + MatTableModule, + MatSort, + MatSortModule, + MatPaginator, + MatPaginatorModule + ], +}) +export class DDTable implements AfterViewInit { + public readonly dataSource: any = new MatTableDataSource(); + @Input() public set columnsToDisplay(value: string[]) { + this.__columnsToDisplay = value; + this.__columnsToDisplayWithExpand = [...value, 'expand']; + } + @Input() public set data(value: any[]) { + this.dataSource.data = value; + } + @Input() schema: Record any; }> = {} + + @Input() paginatorSizeOptions?: number[]; + + @Input() filter: { label: string, placeholder: string } = { label: '', placeholder: '' } + + @Input() isFilterable: boolean = false; + + @Input() isExpandable: boolean = false; + + @Input() isSortable: boolean = false; + + @Input() onToggleExpandedRow: (element: any, event: Event) => Promise = async (element: any, event: Event) => { } + + public get data(): any[] { + return this.dataSource.data; + } + __columnsToDisplay: string[] = []; + __columnsToDisplayWithExpand: string[] = []; + __expandedElement!: any; + + config: ConfigurationService = inject(ConfigurationService); + + @ViewChild(MatSort) sort!: MatSort; + @ViewChild(MatPaginator) paginator!: MatPaginator; + @ViewChild(MatTable) table!: MatTable; + + ngAfterViewInit(): void { + if (this.isSortable) + this.dataSource.sort = this.sort; + if (this.paginatorSizeOptions && this.paginatorSizeOptions.length > 0) + this.dataSource.paginator = this.paginator; + } + + applyFilter(event: Event) { + const filterValue = (event.target as HTMLInputElement).value; + this.dataSource.filter = filterValue.trim().toLowerCase(); + } + + update() { + this.table.renderRows(); + } + + async toggleExpandedRow(element: any, event: Event): Promise { + // first determine the new expanded element, thus it would be possible to use up-to-date + const newExpandedElement = this.__expandedElement === element ? null : element; + + // before update the expanded element call the call-back method to show up-to-date component + await this.onToggleExpandedRow(newExpandedElement, event); + + // assign expanded element + this.__expandedElement = newExpandedElement; + event.stopPropagation(); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.html new file mode 100644 index 00000000..77a6daf9 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.html @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.scss new file mode 100644 index 00000000..1272cd53 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.scss @@ -0,0 +1,59 @@ +/* Structure */ +table { + width: 100%; +} + +.mat-mdc-form-field { + font-size: 14px; + width: 100%; + margin-top: 10px; +} + +/* For expanding table */ +table { + width: 100%; +} + +tr.example-detail-row { + height: 0; +} + +tr.example-element-row:not(.example-expanded-row):hover { + background: whitesmoke; +} + +tr.example-element-row:not(.example-expanded-row):active { + background: #efefef; +} + +.example-element-row td { + border-bottom-width: 0; +} + +.example-element-detail { + overflow: hidden; + display: flex; +} + +.example-element-diagram { + min-width: 80px; + border: 2px solid black; + padding: 8px; + font-weight: lighter; + margin: 8px 0; + height: 104px; +} + +.example-element-symbol { + font-weight: bold; + font-size: 40px; + line-height: normal; +} + +.example-element-description { + padding: 16px; +} + +.example-element-description-attribution { + opacity: 0.5; +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.spec.ts similarity index 100% rename from EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/envelope-table/envelope-table.component.spec.ts rename to EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.spec.ts diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.ts new file mode 100644 index 00000000..79adf50a --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/envelope-table/envelope-table.component.ts @@ -0,0 +1,82 @@ +import { AfterViewInit, Component, Input, ViewChild, inject, viewChild } from '@angular/core'; +import { EnvelopeService } from '../../../services/envelope.service'; +import { animate, state, style, transition, trigger } from '@angular/animations'; +import { ConfigurationService } from '../../../services/configuration.service'; +import { DDTable } from "../dd-table/dd-table.component"; +import { ClearableInputComponent } from '../../clearable-input/clearable-input.component' +import { MatTabsModule } from '@angular/material/tabs'; +import { ReceiverStatusTableComponent } from "../receiver-status-table/receiver-status-table.component"; +import { HistoryTableComponent } from "../history-table/history-table.component"; +import { EnvelopeReceiverService } from '../../../services/envelope-receiver.service'; +import { HistoryService } from '../../../services/history.service'; + +@Component({ + selector: 'envelope-table', + standalone: true, + imports: [DDTable, ClearableInputComponent, MatTabsModule, ReceiverStatusTableComponent, HistoryTableComponent], + templateUrl: './envelope-table.component.html', + animations: [ + trigger('detailExpand', [ + state('collapsed,void', style({ height: '0px', minHeight: '0' })), + state('expanded', style({ height: '*' })), + transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')), + ]), + ], + styleUrl: './envelope-table.component.scss' +}) +export class EnvelopeTableComponent implements AfterViewInit { + + @Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] } + + displayedColumns: string[] = ['title', 'status', 'type', 'addedWhen']; + + schema: Record any; }> = { + 'title': { + header: 'Title', + field: (element: any) => element.title + }, + 'status': { + header: 'Status', + field: (element: any) => element.statusName + }, + 'type': { + header: 'Type', + field: (element: any) => this.config.envelopeTypeTitles[element.contractType - 1] + }, + 'addedWhen': { + header: 'Added When', + field: (element: any) => element.addedWhen + } + } + + data: any[] = []; + + @ViewChild(ReceiverStatusTableComponent) rsTable!: ReceiverStatusTableComponent + + @ViewChild(HistoryTableComponent) histTable!: HistoryTableComponent + + onToggleExpandedRow: (envelope: any, event: Event) => Promise = async (envelope, event) => { + if (envelope === null || envelope === undefined) + return; + + var uuid: string = envelope.uuid; + this.rsTable.data = await this.erService.getSecretAsync(uuid); + + var id: number = envelope.id; + var refType: number = this.config.referenceType.receiver; + const histories = await this.histService.getHistoryAsync({ envelopeId: id, referenceType: refType, withReceiver: true }) + this.histTable.data = histories; + } + + private eService: EnvelopeService = inject(EnvelopeService); + + private config: ConfigurationService = inject(ConfigurationService); + + private readonly erService: EnvelopeReceiverService = inject(EnvelopeReceiverService); + + private readonly histService: HistoryService = inject(HistoryService); + + async ngAfterViewInit() { + this.data = await this.eService.getEnvelopeAsync(this.options); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.html new file mode 100644 index 00000000..73206709 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.scss similarity index 100% rename from EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.scss rename to EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.scss diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.spec.ts new file mode 100644 index 00000000..4156b756 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HistoryTableComponent } from './history-table.component'; + +describe('HistoryTableComponent', () => { + let component: HistoryTableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HistoryTableComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HistoryTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.ts new file mode 100644 index 00000000..1d2cd2fd --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/history-table/history-table.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; +import { DDTable } from '../dd-table/dd-table.component' + +@Component({ + selector: 'history-table', + standalone: true, + imports: [DDTable], + templateUrl: './history-table.component.html', + styleUrl: './history-table.component.scss' +}) +export class HistoryTableComponent { + data: any[] = []; + + schema: Record any; }> = { + "status": { + "header": "Status", + "field": hist => hist.statusName + }, + "user": { + "header": "Benutzer", + "field": hist => hist.userReference + }, + "date": { + "header": "Datum", + "field": hist => hist.actionDate + } + } + + columnsToDisplay: string[] = ["status", "user", "date"]; +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.html new file mode 100644 index 00000000..73206709 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.spec.ts new file mode 100644 index 00000000..98748987 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ReceiverStatusTableComponent } from './receiver-status-table.component'; + +describe('ReceiverStatusTableComponent', () => { + let component: ReceiverStatusTableComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ReceiverStatusTableComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ReceiverStatusTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.ts new file mode 100644 index 00000000..b4a17350 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-status-table/receiver-status-table.component.ts @@ -0,0 +1,30 @@ +import { Component } from '@angular/core'; +import { DDTable } from '../dd-table/dd-table.component' + +@Component({ + selector: 'receiver-status-table', + standalone: true, + imports: [DDTable], + templateUrl: './receiver-status-table.component.html', + styleUrl: './receiver-status-table.component.scss' +}) +export class ReceiverStatusTableComponent { + data: any[] = []; + + schema: Record any; }> = { + "name": { + "header": "Email Anrede", + "field": (er) => er.name + }, + "email": { + "header": "Email", + "field": (er) => er.receiver.emailAddress + }, + "access_code": { + "header": "Email", + "field": (er) => er.accessCode + }, + } + + columnsToDisplay: string[] = ["name", "email", "access_code"]; +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.html new file mode 100644 index 00000000..b439f39e --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + +
Email + + Anrede Email + + Zugriffscode {{element.accessCode}}
\ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.scss b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.spec.ts similarity index 100% rename from EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.spec.ts rename to EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.spec.ts diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.ts similarity index 56% rename from EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.ts rename to EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.ts index b45d343c..c1219a2b 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/receiver-table/receiver-table.component.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/components/tables/receiver-table/receiver-table.component.ts @@ -1,15 +1,15 @@ -import { Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; +import { Component, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { MatTableModule } from '@angular/material/table'; import { AsyncPipe } from '@angular/common'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatFormFieldModule } from '@angular/material/form-field'; -import { ReceiverService } from '../../services/receiver.service' -import { ReceiverInputComponent } from '../receiver-input/receiver-input.component'; +import { ReceiverService } from '../../../services/receiver.service' +import { ReceiverInputComponent } from '../../receiver-input/receiver-input.component'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; -import { ClearableInputComponent } from '../clearable-input/clearable-input.component' +import { ClearableInputComponent } from '../../clearable-input/clearable-input.component' import { v4 as uuidv4 } from 'uuid'; @Component({ @@ -34,24 +34,41 @@ export class ReceiverTableComponent implements OnInit { constructor(private receiverService: ReceiverService) { } async ngOnInit() { - this.receiver_mails = await this.receiverService.getReceiverAsync().then((receivers: any[]) => receivers.map(r => r.emailAddress)); + const receivers = await this.receiverService.getReceiverAsync(); + this.receiver_mails = receivers.map((r: any) => r.emailAddress); + this.last_used_name = receivers.reduce((acc: any, r: any) => { + acc[r.emailAddress] = r.lastUsedName; + return acc; + }, {} as { [key: string]: string | null }); } - receiver_filter: (value: string, options: string[]) => string[] = (value, options) => { + receiver_filter: (value: string, options: string[], index?: number) => string[] = (value, options, index) => { const filterValue = value.toLowerCase(); + // set the name if it is used before + const name = this.last_used_name[value]; + + if (name && index != null && index != undefined) { + this.receiverData.at(index)!.name = name + } + + // !!! do not allow email duplication !!! + var similarMails = this.receiver_mails.filter(m => m.toLocaleLowerCase() === value.toLocaleLowerCase() && m !== value) + if (similarMails.length > 0 && index != undefined) { + this.receiverInputs[index].text = similarMails[0]; + } + // if added into last row if (value.length > 0 && (this.receiverInputs.at(-1)?.lenght ?? 0) > 0) { this.receiverData.at(-1)!.accessCode = generateAccessCode(); this.receiverData.push({ email: "", name: "", accessCode: "" }); this.update(); } - else if (value.length == 0) { - for (var i = 0; i < this.receiverInputs.length - 1; i++) { - if (this.receiverInputs[i].lenght === 0) { - this.receiverData.splice(i, 1); - this.update(); - } + // delete the row with out mail + else if (value.length === 0 && this.receiverInputs.length - 1 !== index) { + if (this.receiverInputs.length > 1 && this.receiverInputs[index!]?.lenght === 0) { + this.receiverData.splice(index!, 1); + this.update(); } } @@ -59,6 +76,7 @@ export class ReceiverTableComponent implements OnInit { } receiver_mails: string[] = []; + last_used_name: { [key: string]: string | null } = {}; @ViewChildren(ReceiverInputComponent) receiverInputsQueryList!: QueryList; get receiverInputs(): ReceiverInputComponent[] { diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope-creation/envelope-creation.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope-creation/envelope-creation.component.ts index 9b617390..32b38270 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope-creation/envelope-creation.component.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope-creation/envelope-creation.component.ts @@ -5,7 +5,7 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatStepperModule } from '@angular/material/stepper'; import { MatButtonModule } from '@angular/material/button'; import { MatSelectModule } from '@angular/material/select'; -import { ReceiverTableComponent } from "../../components/receiver-table/receiver-table.component"; +import { ReceiverTableComponent } from "../../components/tables/receiver-table/receiver-table.component"; import { MatIconModule } from '@angular/material/icon'; @Component({ diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.html b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.html index b131b165..34ed812e 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.html +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.html @@ -1,10 +1,10 @@
- + - +
\ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.ts index ee5f93e6..fd2ff694 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/pages/envelope/envelope.component.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { EnvelopeTableComponent } from "../../components/envelope-table/envelope-table.component"; +import { EnvelopeTableComponent } from "../../components/tables/envelope-table/envelope-table.component"; import { MatTabsModule } from '@angular/material/tabs'; import { LocalizationService } from '../../services/localization.service'; import { Status } from '../../enums/envelope-const' diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.spec.ts new file mode 100644 index 00000000..ec51dfa5 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ConfigurationService } from './configuration.service'; + +describe('ConfigurationService', () => { + let service: ConfigurationService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ConfigurationService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.ts new file mode 100644 index 00000000..2b56191e --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/configuration.service.ts @@ -0,0 +1,47 @@ +import { Injectable, OnInit, inject } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, firstValueFrom } from 'rxjs'; +import { API_URL } from '../tokens/index'; + +@Injectable({ + providedIn: 'root' +}) +export class ConfigurationService implements OnInit { + + protected url: string; + + private _envelopeTypes! : any[]; + + private _envelopeTypeTitles! : any[]; + + private _referenceType!: any; + + constructor(private http: HttpClient) { + const api_url = inject(API_URL); + this.url = `${api_url}`; + } + + async ngOnInit(): Promise { + const envelopeTypes$: Observable = this.http.get(`${this.url}/EnvelopeType`) + envelopeTypes$.subscribe({next: res => { + this._envelopeTypes = res; + this._envelopeTypeTitles = res.map(e => e.title); + }}); + + this.http.get(`${this.url}/History/reference-type`).subscribe({ + next: res => this._referenceType = res + }) + } + + public get envelopeTypes() { + return this._envelopeTypes; + } + + public get envelopeTypeTitles() { + return this._envelopeTypeTitles; + } + + public get referenceType() { + return this._referenceType; + } +} diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope-receiver.service.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope-receiver.service.ts index 3a1a3766..c919798d 100644 --- a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope-receiver.service.ts +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope-receiver.service.ts @@ -27,8 +27,18 @@ export class EnvelopeReceiverService { return this.http.get(this.url, { params }); } - getEnvelopeReceiverAsync(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Promise { return firstValueFrom(this.getEnvelopeReceiver(options)); } + + getSecret(uuid: string): Observable { + let params = new HttpParams(); + params = params.set('uuid', uuid); + + return this.http.get(`${this.url}/secret`, { params }); + } + + getSecretAsync(uuid: string): Promise { + return firstValueFrom(this.getSecret(uuid)); + } } \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.spec.ts new file mode 100644 index 00000000..25fa59b3 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { EnvelopeService } from './envelope.service'; + +describe('EnvelopeService', () => { + let service: EnvelopeService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(EnvelopeService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.ts new file mode 100644 index 00000000..228f2677 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/envelope.service.ts @@ -0,0 +1,33 @@ +import { Injectable, inject } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, firstValueFrom } from 'rxjs'; +import { API_URL } from '../tokens/index'; + +@Injectable({ + providedIn: 'root' +}) +export class EnvelopeService { + protected url: string; + + constructor(private http: HttpClient) { + const api_url = inject(API_URL); + this.url = `${api_url}/envelope`; + } + + public getEnvelope(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Observable { + let params = new HttpParams(); + if (options) { + if (options.min_status) + params = params.set('min_status', options.min_status.toString()); + if (options.max_status) + params = params.set('max_status', options.max_status.toString()); + if (options.ignore_status) + params = params.set('ignore_status', options.ignore_status.join(',')); + } + return this.http.get(this.url, { params }); + } + + public async getEnvelopeAsync(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Promise { + return await firstValueFrom(this.getEnvelope(options)); + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.spec.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.spec.ts new file mode 100644 index 00000000..65de5db7 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { HistoryService } from './history.service'; + +describe('HistoryService', () => { + let service: HistoryService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(HistoryService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.ts b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.ts new file mode 100644 index 00000000..b458943f --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/src/app/services/history.service.ts @@ -0,0 +1,46 @@ +import { Injectable, inject } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { Observable, firstValueFrom } from 'rxjs'; +import { API_URL } from '../tokens/index'; + + +@Injectable({ + providedIn: 'root' +}) +export class HistoryService { + protected url: string; + + constructor(private http: HttpClient) { + const api_url = inject(API_URL); + this.url = `${api_url}/history`; + } + + public getHistory(options?: Options): Observable { + let params = new HttpParams(); + if (options) { + if (options.envelopeId) + params = params.set('envelopeId', options.envelopeId); + if (options.referenceType != null) + params = params.set('referenceType', options.referenceType); + if (options.userReference) + params = params.set('userReference', options.userReference); + if (options.withReceiver) + params = params.set('withReceiver', options.withReceiver); + if (options.withSender) + params = params.set('withSender', options.withSender); + } + return this.http.get(this.url, { params }); + } + + public async getHistoryAsync(options?: Options): Promise { + return firstValueFrom(this.getHistory(options)); + } +} + +class Options { + envelopeId?: number; + userReference?: string; + referenceType: number | null = null; + withSender?: boolean; + withReceiver?: boolean; +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/ControllerExtensions.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/ControllerExtensions.cs index a897824b..1121a9b8 100644 --- a/EnvelopeGenerator.GeneratorAPI/Controllers/ControllerExtensions.cs +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/ControllerExtensions.cs @@ -5,20 +5,20 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers { public static class ControllerExtensions { - public static int? GetId(this ControllerBase controller) - => int.TryParse(controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value, out int result) + public static int? GetId(this ClaimsPrincipal user) + => int.TryParse(user.FindFirst(ClaimTypes.NameIdentifier)?.Value, out int result) ? result : null; - public static string? GetUsername(this ControllerBase controller) - => controller.User.FindFirst(ClaimTypes.Name)?.Value; + public static string? GetUsername(this ClaimsPrincipal user) + => user.FindFirst(ClaimTypes.Name)?.Value; - public static string? GetName(this ControllerBase controller) - => controller.User.FindFirst(ClaimTypes.Surname)?.Value; + public static string? GetName(this ClaimsPrincipal user) + => user.FindFirst(ClaimTypes.Surname)?.Value; - public static string? GetPrename(this ControllerBase controller) - => controller.User.FindFirst(ClaimTypes.GivenName)?.Value; + public static string? GetPrename(this ClaimsPrincipal user) + => user.FindFirst(ClaimTypes.GivenName)?.Value; - public static string? GetEmail(this ControllerBase controller) - => controller.User.FindFirst(ClaimTypes.Email)?.Value; + public static string? GetEmail(this ClaimsPrincipal user) + => user.FindFirst(ClaimTypes.Email)?.Value; } } \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeController.cs new file mode 100644 index 00000000..a7306a36 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeController.cs @@ -0,0 +1,52 @@ +using DigitalData.Core.DTO; +using EnvelopeGenerator.Application.Contracts; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace EnvelopeGenerator.GeneratorAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [Authorize] + public class EnvelopeController : ControllerBase + { + private readonly ILogger _logger; + private readonly IEnvelopeService _envelopeService; + + public EnvelopeController(ILogger logger, IEnvelopeService envelopeService) + { + _logger = logger; + _envelopeService = envelopeService; + } + + [Authorize] + [HttpGet] + public async Task GetCurrentAsync( + [FromQuery] int? min_status = null, + [FromQuery] int? max_status = null, + [FromQuery] params int[] ignore_statuses) + { + try + { + if (User.GetId() is int intId) + return await _envelopeService.ReadByUserAsync(intId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses).ThenAsync( + Success: Ok, + Fail: IActionResult (msg, ntc) => + { + _logger.LogNotice(ntc); + return StatusCode(StatusCodes.Status500InternalServerError); + }); + else + { + _logger.LogError("Despite successful authorization, the 'api/envelope' route encountered an issue: the user ID is not recognized as an integer. This may be due to the removal of the ID during the creation of the claims list."); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + catch (Exception ex) + { + _logger.LogError(ex, "{Message}", ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs index bf8e2cb2..b5a9c989 100644 --- a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeReceiverController.cs @@ -1,11 +1,13 @@ using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; +using EnvelopeGenerator.Common.My.Resources; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace EnvelopeGenerator.GeneratorAPI.Controllers { [Route("api/[controller]")] + [Authorize] [ApiController] public class EnvelopeReceiverController : ControllerBase { @@ -17,19 +19,18 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers _logger = logger; _erService = envelopeReceiverService; } - - [Authorize] + [HttpGet] public async Task GetEnvelopeReceiver([FromQuery] int? min_status = null, [FromQuery] int? max_status = null, [FromQuery] int[]? ignore_status = null) { try { - var username = this.GetUsername(); + var username = User.GetUsername(); if (username is null) { _logger.LogError(@"Envelope Receiver dto cannot be sent because username claim is null. Potential authentication and authorization error. The value of other claims are [id: {id}], [username: {username}], [name: {name}], [prename: {prename}], [email: {email}].", - this.GetId(), this.GetUsername(), this.GetName(), this.GetPrename(), this.GetEmail()); + User.GetId(), User.GetUsername(), User.GetName(), User.GetPrename(), User.GetEmail()); return StatusCode(StatusCodes.Status500InternalServerError); } @@ -49,5 +50,49 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers return new StatusCodeResult(StatusCodes.Status500InternalServerError); } } + + [HttpGet("receiver-name/{mail}")] + public async Task GetReceiverName([FromRoute] string mail) + { + try + { + return await _erService.ReadLastUsedReceiverNameByMail(mail).ThenAsync( + Success: res => res is null ? Ok(string.Empty) : Ok(res), + Fail: IActionResult (msg, ntc) => + { + if (ntc.HasFlag(Flag.NotFound)) + return NotFound(); + + _logger.LogNotice(ntc); + return StatusCode(StatusCodes.Status500InternalServerError); + }); + } + catch(Exception ex) + { + _logger.LogError(ex, "{message}", ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + + [HttpGet("secret")] + [Authorize] + public async Task GetSecretAsync([FromQuery] string uuid) + { + try + { + return await _erService.ReadSecretByUuidAsync(uuid: uuid).ThenAsync( + Success: Ok, + Fail: IActionResult (msg, ntc) => + { + _logger.LogNotice(ntc); + return StatusCode(StatusCodes.Status500InternalServerError); + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "{message}", ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeTypeController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeTypeController.cs new file mode 100644 index 00000000..daacd703 --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/EnvelopeTypeController.cs @@ -0,0 +1,43 @@ +using DigitalData.Core.DTO; +using EnvelopeGenerator.Application.Contracts; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Net.Mail; +using System.Security.Cryptography.Xml; + +namespace EnvelopeGenerator.GeneratorAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class EnvelopeTypeController : ControllerBase + { + private readonly ILogger _logger; + private readonly IEnvelopeTypeService _service; + + public EnvelopeTypeController(ILogger logger, IEnvelopeTypeService service) + { + _logger = logger; + _service = service; + } + + [HttpGet] + public async Task GetAllAsync() + { + try + { + return await _service.ReadAllAsync().ThenAsync( + Success: Ok, + Fail: IActionResult (msg, ntc) => + { + _logger.LogNotice(ntc); + return ntc.HasFlag(Flag.NotFound) ? NotFound() : StatusCode(StatusCodes.Status500InternalServerError); + }); + } + catch (Exception ex) + { + _logger.LogError(ex, "{Message}", ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/HistoryController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/HistoryController.cs new file mode 100644 index 00000000..8b24cc9d --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/HistoryController.cs @@ -0,0 +1,73 @@ +using EnvelopeGenerator.Application.Contracts; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using System; +using static EnvelopeGenerator.Common.Constants; + +namespace EnvelopeGenerator.GeneratorAPI.Controllers +{ + [Route("api/[controller]")] + [ApiController] + [Authorize] + public class HistoryController : ControllerBase + { + private readonly ILogger _logger; + + private readonly IEnvelopeHistoryService _service; + + public HistoryController(ILogger logger, IEnvelopeHistoryService service) + { + _logger = logger; + _service = service; + } + + [HttpGet("reference-type")] + [Authorize] + public IActionResult GetReferenceTypes() + { + // Enum to Key-Value pair + var referenceTypes = Enum.GetValues(typeof(ReferenceType)) + .Cast() + .ToDictionary(rt => + { + var key = rt.ToString(); + var keyAsCamelCase = char.ToLower(key[0]) + key[1..]; + return keyAsCamelCase; + }, rt => (int)rt); + + return Ok(referenceTypes); + } + + [HttpGet] + [Authorize] + public async Task GetAllAsync([FromQuery] int? envelopeId = null, [FromQuery] string? userReference = null, [FromQuery] int? referenceType = null, [FromQuery] bool withSender = false, [FromQuery] bool withReceiver = false) + { + ReferenceType? refTypEnum = null; + + if (referenceType is int refTypInt) + if (Enum.IsDefined(typeof(ReferenceType), refTypInt)) + refTypEnum = (ReferenceType)refTypInt; + else + throw new ArgumentException($"The provided referenceType '{referenceType}' is not valid. It must correspond to a valid value in the {nameof(ReferenceType)} enum."); + + switch(referenceType) + { + case (int)ReferenceType.Receiver: + withReceiver = true; + break; + case (int)ReferenceType.Sender: + withSender = true; + break; + } + + var histories = await _service.ReadAsync( + envelopeId: envelopeId, + userReference: userReference, + referenceType: refTypEnum, + withSender: withSender, + withReceiver: withReceiver); + + return Ok(histories); + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.GeneratorAPI/Controllers/ReceiverController.cs b/EnvelopeGenerator.GeneratorAPI/Controllers/ReceiverController.cs index 9fbeea1c..4c057b92 100644 --- a/EnvelopeGenerator.GeneratorAPI/Controllers/ReceiverController.cs +++ b/EnvelopeGenerator.GeneratorAPI/Controllers/ReceiverController.cs @@ -17,8 +17,6 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers { } - - [HttpGet] public async Task Get([FromQuery] string? emailAddress = null, [FromQuery] string? signature = null) { diff --git a/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj b/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj index d42159a2..2684ed2c 100644 --- a/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj +++ b/EnvelopeGenerator.GeneratorAPI/EnvelopeGenerator.GeneratorAPI.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -7,8 +7,8 @@ - - + + diff --git a/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeReceiverRepository.cs b/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeReceiverRepository.cs index 219e64eb..e471ddf7 100644 --- a/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeReceiverRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeReceiverRepository.cs @@ -3,7 +3,7 @@ using EnvelopeGenerator.Domain.Entities; namespace EnvelopeGenerator.Infrastructure.Contracts { - public interface IEnvelopeReceiverRepository : ICRUDRepository + public interface IEnvelopeReceiverRepository : ICRUDRepository { Task> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false); @@ -20,5 +20,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts Task ReadAccessCodeByIdAsync(int envelopeId, int receiverId); Task> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses); + + Task ReadLastByReceiver(string email); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeRepository.cs b/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeRepository.cs index d2d1377f..5b78658e 100644 --- a/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Contracts/IEnvelopeRepository.cs @@ -8,5 +8,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts Task> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false); Task ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false); + + Task> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/EGDbContext.cs b/EnvelopeGenerator.Infrastructure/EGDbContext.cs index a367bf47..449bd55e 100644 --- a/EnvelopeGenerator.Infrastructure/EGDbContext.cs +++ b/EnvelopeGenerator.Infrastructure/EGDbContext.cs @@ -1,14 +1,77 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.Entities; +using DigitalData.UserManager.Domain.Entities; using DigitalData.UserManager.Infrastructure; +using DigitalData.UserManager.Infrastructure.Contracts; using EnvelopeGenerator.Domain.Entities; using Microsoft.EntityFrameworkCore; +using Group = DigitalData.UserManager.Domain.Entities.Group; +using Module = DigitalData.UserManager.Domain.Entities.Module; +using DigitalData.EmailProfilerDispatcher; namespace EnvelopeGenerator.Infrastructure { - public class EGDbContext : DbContext + //TODO: Adding EmailOut instead of EmailOut.Abst is not correct for the arch. Re-design EmailPut consedering this. IMailDbContext shoud move to Abstraction layer (hint: in this case using DBSet in abst. will be problem because entity framework will have to be added. + public class EGDbContext : DbContext, IUserManagerDbContext, IMailDbContext { + public DbSet UserReceivers { get; set; } + + public DbSet Configs { get; set; } + + public DbSet EnvelopeReceivers { get; set; } + + public DbSet Envelopes { get; set; } + + public DbSet DocumentReceiverElements { get; set; } + + public DbSet DocumentStatus { get; set; } + + public DbSet EmailTemplate { get; set; } + + public DbSet EnvelopeCertificates { get; set; } + + public DbSet EnvelopeDocument { get; set; } + + public DbSet EnvelopeHistories { get; set; } + + public DbSet EnvelopeTypes { get; set; } + + public DbSet Receivers { get; set; } + + public DbSet GroupOfUsers { get; set; } + + public DbSet Groups { get; set; } + + public DbSet ModuleOfUsers { get; set; } + + public DbSet Modules { get; set; } + + public DbSet Users { get; set; } + + public DbSet UserReps { get; set; } + + public DbSet EMailOuts { get; set; } + public EGDbContext(DbContextOptions options) : base(options) { + UserReceivers = Set(); + Configs = Set(); + EnvelopeReceivers = Set(); + Envelopes = Set(); + DocumentReceiverElements = Set(); + DocumentStatus = Set(); + EnvelopeCertificates = Set(); + EnvelopeDocument = Set(); + EnvelopeHistories = Set(); + EnvelopeTypes = Set(); + Receivers = Set(); + + GroupOfUsers = Set(); + Groups = Set(); + ModuleOfUsers = Set(); + Modules = Set(); + Users = Set(); + UserReps = Set(); + EMailOuts = Set(); } protected override void OnModelCreating(ModelBuilder modelBuilder) diff --git a/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj b/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj index f81afd68..f295ff69 100644 --- a/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj +++ b/EnvelopeGenerator.Infrastructure/EnvelopeGenerator.Infrastructure.csproj @@ -7,15 +7,16 @@ - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/EnvelopeGenerator.Infrastructure/Repositories/ConfigRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/ConfigRepository.cs index 6dc89ebb..bae012ae 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/ConfigRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/ConfigRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.EntityFrameworkCore; @@ -8,7 +7,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class ConfigRepository : CRUDRepository, IConfigRepository { - public ConfigRepository(EGDbContext dbContext) : base(dbContext) + public ConfigRepository(EGDbContext dbContext) : base(dbContext, dbContext.Configs) { } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/DocumentReceiverElementRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/DocumentReceiverElementRepository.cs index 0c7c5b55..a57bde74 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/DocumentReceiverElementRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/DocumentReceiverElementRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; @@ -7,7 +6,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class DocumentReceiverElementRepository : CRUDRepository, IDocumentReceiverElementRepository { - public DocumentReceiverElementRepository(EGDbContext dbContext) : base(dbContext) + public DocumentReceiverElementRepository(EGDbContext dbContext) : base(dbContext, dbContext.DocumentReceiverElements) { } } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/DocumentStatusRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/DocumentStatusRepository.cs index 0bb95c99..e27e56a6 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/DocumentStatusRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/DocumentStatusRepository.cs @@ -7,7 +7,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class DocumentStatusRepository : CRUDRepository, IDocumentStatusRepository { - public DocumentStatusRepository(EGDbContext dbContext) : base(dbContext) + public DocumentStatusRepository(EGDbContext dbContext) : base(dbContext, dbContext.DocumentStatus) { } } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EmailTemplateRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EmailTemplateRepository.cs index dc80e97b..47772341 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EmailTemplateRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EmailTemplateRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.EntityFrameworkCore; @@ -12,7 +11,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { private readonly IMemoryCache _cache; - public EmailTemplateRepository(EGDbContext dbContext, IMemoryCache cache) : base(dbContext) + public EmailTemplateRepository(EGDbContext dbContext, IMemoryCache cache) : base(dbContext, dbContext.EmailTemplate) { _cache = cache; } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeCertificateRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeCertificateRepository.cs index 5cc4195e..6bc3c4a9 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeCertificateRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeCertificateRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; @@ -7,7 +6,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class EnvelopeCertificateRepository : CRUDRepository, IEnvelopeCertificateRepository { - public EnvelopeCertificateRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeCertificateRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeCertificates) { } } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeDocumentRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeDocumentRepository.cs index 57fa4eee..25ff8949 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeDocumentRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeDocumentRepository.cs @@ -7,7 +7,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class EnvelopeDocumentRepository : CRUDRepository, IEnvelopeDocumentRepository { - public EnvelopeDocumentRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeDocumentRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeDocument) { } } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeHistoryRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeHistoryRepository.cs index 2c3c64c3..97dcfc37 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeHistoryRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeHistoryRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.EntityFrameworkCore; @@ -8,7 +7,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class EnvelopeHistoryRepository : CRUDRepository, IEnvelopeHistoryRepository { - public EnvelopeHistoryRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeHistoryRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeHistories) { } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeRepository.cs index 73ac63a0..40783bf2 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.EntityFrameworkCore; @@ -8,13 +7,13 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class EnvelopeRepository : CRUDRepository, IEnvelopeRepository { - public EnvelopeRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeRepository(EGDbContext dbContext) : base(dbContext, dbContext.Envelopes) { } public async Task> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false) { - var query = _dbSet.AsQueryable(); + var query = _dbSet.AsNoTracking(); if (documents) if (documentReceiverElement) @@ -30,7 +29,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories public async Task ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false) { - var query = _dbSet.Where(e => e.Uuid == uuid); + var query = _dbSet.AsNoTracking().Where(e => e.Uuid == uuid); if (withAll || withDocuments) if (withAll || withDocumentReceiverElement) @@ -46,5 +45,21 @@ namespace EnvelopeGenerator.Infrastructure.Repositories return await query.FirstOrDefaultAsync(); } + + public async Task> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses) + { + var query = _dbSet.AsNoTracking().Where(e => e.UserId == userId); + + if (min_status is not null) + query = query.Where(e => e.Status >= min_status); + + if (max_status is not null) + query = query.Where(e => e.Status <= max_status); + + foreach (var ignore_status in ignore_statuses) + query = query.Where(e => e.Status != ignore_status); + + return await query.ToListAsync(); + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeTypeRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeTypeRepository.cs index 9b7533e3..5bc9f6c5 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeTypeRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvelopeTypeRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; @@ -7,7 +6,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class EnvelopeTypeRepository : CRUDRepository, IEnvelopeTypeRepository { - public EnvelopeTypeRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeTypeRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeTypes) { } } diff --git a/EnvelopeGenerator.Infrastructure/Repositories/EnvlopeReceiverRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/EnvlopeReceiverRepository.cs index 10b7012b..7b72f29e 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/EnvlopeReceiverRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/EnvlopeReceiverRepository.cs @@ -1,14 +1,13 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; using Microsoft.EntityFrameworkCore; namespace EnvelopeGenerator.Infrastructure.Repositories { - public class EnvelopeReceiverRepository : CRUDRepository, IEnvelopeReceiverRepository + public class EnvelopeReceiverRepository : CRUDRepository, IEnvelopeReceiverRepository { - public EnvelopeReceiverRepository(EGDbContext dbContext) : base(dbContext) + public EnvelopeReceiverRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeReceivers) { } @@ -76,5 +75,10 @@ namespace EnvelopeGenerator.Infrastructure.Repositories return await query.Include(er => er.Envelope).Include(er => er.Receiver).ToListAsync(); } + + public async Task ReadLastByReceiver(string email) + { + return await _dbSet.Where(er => er.Receiver!.EmailAddress == email).OrderBy(er => er.EnvelopeId).LastOrDefaultAsync(); + } } } \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/Repositories/ReceiverRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/ReceiverRepository.cs index 53ffb2ba..bccb6c1b 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/ReceiverRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/ReceiverRepository.cs @@ -7,11 +7,11 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class ReceiverRepository : CRUDRepository, IReceiverRepository { - public ReceiverRepository(EGDbContext dbContext) : base(dbContext) + public ReceiverRepository(EGDbContext dbContext) : base(dbContext, dbContext.Receivers) { } - protected IQueryable ReadBy(string? emailAddress = null, string? signature = null) + protected IQueryable ReadBy(string? emailAddress = null, string? signature = null, bool withLastUsedName = true) { IQueryable query = _dbSet.AsNoTracking(); @@ -21,9 +21,17 @@ namespace EnvelopeGenerator.Infrastructure.Repositories if(signature is not null) query = query.Where(r => r.Signature == signature); + // envelope receivers are ignored (with '[JsonIgnore]' attribute). The reson to add them is to get the las used receiver name + if (withLastUsedName) + { + query = query.Include(r => r.EnvelopeReceivers!.OrderByDescending(er => er.EnvelopeId).Take(1)); + } + return query; } public async Task ReadByAsync(string? emailAddress = null, string? signature = null) => await ReadBy(emailAddress, signature).FirstOrDefaultAsync(); + + public async override Task> ReadAllAsync() => await ReadBy().ToListAsync(); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Infrastructure/Repositories/UserReceiverRepository.cs b/EnvelopeGenerator.Infrastructure/Repositories/UserReceiverRepository.cs index 2c5800ec..04bb30fa 100644 --- a/EnvelopeGenerator.Infrastructure/Repositories/UserReceiverRepository.cs +++ b/EnvelopeGenerator.Infrastructure/Repositories/UserReceiverRepository.cs @@ -1,5 +1,4 @@ using DigitalData.Core.Infrastructure; -using DigitalData.UserManager.Infrastructure.Repositories; using EnvelopeGenerator.Domain.Entities; using EnvelopeGenerator.Infrastructure.Contracts; @@ -7,7 +6,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories { public class UserReceiverRepository : CRUDRepository, IUserReceiverRepository { - public UserReceiverRepository(EGDbContext dbContext) : base(dbContext) + public UserReceiverRepository(EGDbContext dbContext) : base(dbContext, dbContext.UserReceivers) { } } diff --git a/EnvelopeGenerator.Web/Controllers/HomeController.cs b/EnvelopeGenerator.Web/Controllers/HomeController.cs index 98c5b69a..431901e7 100644 --- a/EnvelopeGenerator.Web/Controllers/HomeController.cs +++ b/EnvelopeGenerator.Web/Controllers/HomeController.cs @@ -10,11 +10,11 @@ using DigitalData.Core.API; using EnvelopeGenerator.Application; using Microsoft.Extensions.Localization; using DigitalData.Core.DTO; -using EnvelopeGenerator.Application.DTOs; using Microsoft.AspNetCore.Localization; using System.Text.Encodings.Web; using EnvelopeGenerator.Web.Models; using EnvelopeGenerator.Application.Resources; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; namespace EnvelopeGenerator.Web.Controllers { @@ -123,6 +123,8 @@ namespace EnvelopeGenerator.Web.Controllers { try { + ViewData["UserCulture"] = _cultures[UserLanguage]; + envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId); (string? uuid, string? signature) = envelopeReceiverId.DecodeEnvelopeReceiverId(); @@ -142,7 +144,6 @@ namespace EnvelopeGenerator.Web.Controllers _logger.LogNotice(verification.Notices); Response.StatusCode = StatusCodes.Status401Unauthorized; return View("EnvelopeLocked") - .WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language) .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); } @@ -156,7 +157,6 @@ namespace EnvelopeGenerator.Web.Controllers await _historyService.RecordAsync(er.EnvelopeId, er.Receiver!.EmailAddress, Constants.EnvelopeStatus.AccessCodeIncorrect); Response.StatusCode = StatusCodes.Status401Unauthorized; return View("EnvelopeLocked") - .WithData("UserLanguage", UserLanguage ?? _cultures.Default.Language) .WithData("ErrorMessage", _localizer[WebKey.WrongAccessCode].Value); } @@ -209,7 +209,6 @@ namespace EnvelopeGenerator.Web.Controllers //add PSPDFKit licence key ViewData["PSPDFKitLicenseKey"] = _configuration["PSPDFKitLicenseKey"]; - ViewData["UserCulture"] = _cultures[UserLanguage]; return View("ShowEnvelope", er); }, diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestConfigController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestConfigController.cs index ad7e0ec3..0117f542 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestConfigController.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestConfigController.cs @@ -1,10 +1,11 @@ using EnvelopeGenerator.Application.Contracts; using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Domain.Entities; +using DigitalData.Core.API; namespace EnvelopeGenerator.Web.Controllers.Test { - public class TestConfigController : TestControllerBase + public class TestConfigController : ReadControllerBase { public TestConfigController(ILogger logger, IConfigService service) : base(logger, service) { diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs b/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs index e39b0ed8..b92ae934 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestControllerBase.cs @@ -1,6 +1,7 @@ using DigitalData.Core.API; using DigitalData.Core.Abstractions.Application; using Microsoft.AspNetCore.Mvc; +using DigitalData.Core.Abstractions; namespace EnvelopeGenerator.Web.Controllers.Test { @@ -8,10 +9,10 @@ namespace EnvelopeGenerator.Web.Controllers.Test [Route("api/test/[controller]")] public class TestControllerBase : BasicCRUDControllerBase where TCRUDService : ICRUDService - where TDto : class where TEntity : class + where TDto : class, IUnique where TEntity : class, IUnique { public TestControllerBase(ILogger logger, TCRUDService service) : base(logger, service) { } } -} +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeMailController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeMailController.cs index 2840c53f..47f958b2 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeMailController.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeMailController.cs @@ -1,12 +1,12 @@ using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.DTOs; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; using Microsoft.AspNetCore.Mvc; using System.Net; namespace EnvelopeGenerator.Web.Controllers.Test { - [ApiController] + [ApiController] [Route("api/test/[controller]")] public class TestEnvelopeMailController : ControllerBase { diff --git a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeReceiverController.cs b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeReceiverController.cs index c4a09eb7..592688de 100644 --- a/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeReceiverController.cs +++ b/EnvelopeGenerator.Web/Controllers/Test/TestEnvelopeReceiverController.cs @@ -1,14 +1,14 @@ using DigitalData.Core.API; using DigitalData.Core.DTO; using EnvelopeGenerator.Application.Contracts; -using EnvelopeGenerator.Application.DTOs; using EnvelopeGenerator.Application; using EnvelopeGenerator.Domain.Entities; using Microsoft.AspNetCore.Mvc; +using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver; namespace EnvelopeGenerator.Web.Controllers.Test { - public class TestEnvelopeReceiverController : TestControllerBase + public class TestEnvelopeReceiverController : ReadControllerBase { public TestEnvelopeReceiverController(ILogger logger, IEnvelopeReceiverService service) : base(logger, service) { diff --git a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj index 8bed176f..79023085 100644 --- a/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj +++ b/EnvelopeGenerator.Web/EnvelopeGenerator.Web.csproj @@ -5,7 +5,7 @@ enable enable EnvelopeGenerator.Web - 1.0.0.3 + 2.0.0.0 Digital Data GmbH Digital Data GmbH EnvelopeGenerator.Web @@ -13,8 +13,8 @@ digital data envelope generator web 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. Assets\icon.ico - 1.0.0.3 - 1.0.0.3 + 2.0.0.0 + 2.0.0.0 @@ -38,9 +38,9 @@ - - - + + + @@ -64,7 +64,7 @@ - + @@ -98,13 +98,10 @@ Never - - Always - PreserveNewest - + Always diff --git a/EnvelopeGenerator.Web/Models/Logo.cs b/EnvelopeGenerator.Web/Models/Logo.cs new file mode 100644 index 00000000..7b92d8a3 --- /dev/null +++ b/EnvelopeGenerator.Web/Models/Logo.cs @@ -0,0 +1,11 @@ +namespace EnvelopeGenerator.Web.Models +{ + public class Logo + { + public string Src { get; init; } = string.Empty; + + public string LockedPageClass { get; init; } = string.Empty; + + public string ShowPageClass { get; init; } = string.Empty; + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Program.cs b/EnvelopeGenerator.Web/Program.cs index f5064f51..81459100 100644 --- a/EnvelopeGenerator.Web/Program.cs +++ b/EnvelopeGenerator.Web/Program.cs @@ -63,6 +63,15 @@ try q.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.IgnoreCycles; }); + builder.Services.Configure(options => + { + // This lambda determines whether user consent for non-essential + // cookies is needed for a given request. + options.CheckConsentNeeded = context => true; + + options.MinimumSameSitePolicy = SameSiteMode.None; + }); + if (config.GetValue("EnableSwagger") && builder.IsDevOrDiP()) { builder.Services.AddEndpointsApiExplorer(); @@ -150,6 +159,8 @@ try builder.ConfigureBySection(); + builder.ConfigureBySection(); + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -185,7 +196,7 @@ try app.UseStaticFiles(); - //app.UseCookiePolicy(); + app.UseCookiePolicy(); app.UseRouting(); diff --git a/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml b/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml index 43c8315f..4964fd97 100644 --- a/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml +++ b/EnvelopeGenerator.Web/Views/Home/EnvelopeLocked.cshtml @@ -1,13 +1,18 @@ @{ var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; + var logo = _logoOpt.Value; } @{ ViewData["Title"] = _localizer[WebKey.DocProtected]; var userCulture = ViewData["UserCulture"] as Culture; } -
+
-
+ +
@@ -19,8 +24,8 @@

@_localizer[WebKey.LockedBody]

-
-
+
+
@@ -63,7 +68,6 @@
- \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml b/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml index 6dfed5cf..3de3aef8 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml +++ b/EnvelopeGenerator.Web/Views/Shared/_CookieConsentPartial.cshtml @@ -1,27 +1,41 @@ -@{ - var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; -} -@using DigitalData.Core.DTO; -@using Microsoft.AspNetCore.Http.Features -@using Newtonsoft.Json.Serialization; -@using Newtonsoft.Json; -@inject CookieConsentSettings _cookieSettings +@using Microsoft.AspNetCore.Http.Features + @{ + var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string; var consentFeature = Context.Features.Get(); var showBanner = !consentFeature?.CanTrack ?? false; var cookieString = consentFeature?.CreateConsentCookie(); } + @if (showBanner) { - + + + } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml index a858721c..46271921 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml +++ b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml @@ -13,12 +13,20 @@ + + + + @if (ViewData["EnvelopeKey"] is string envelopeKey) { @@ -53,5 +61,6 @@ @Html.AntiForgeryToken() + \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml.css b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml.css index 5c43bd4f..7bef8b13 100644 --- a/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml.css +++ b/EnvelopeGenerator.Web/Views/Shared/_Layout.cshtml.css @@ -1,7 +1,4 @@ -/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification -for details on configuring this project to bundle and minify static web assets. */ - -a.navbar-brand { +a.navbar-brand { white-space: normal; text-align: center; word-break: break-all; @@ -37,12 +34,4 @@ a { button.accept-policy { font-size: 1rem; line-height: inherit; -} - -.footer { - position: absolute; - bottom: 0; - width: 100%; - white-space: nowrap; - line-height: 3.75rem; -} +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/Views/_ViewImports.cshtml b/EnvelopeGenerator.Web/Views/_ViewImports.cshtml index 25a878c5..1e3c2c8f 100644 --- a/EnvelopeGenerator.Web/Views/_ViewImports.cshtml +++ b/EnvelopeGenerator.Web/Views/_ViewImports.cshtml @@ -3,10 +3,12 @@ @using EnvelopeGenerator.Web.Sanitizers @using Microsoft.Extensions.Localization @using EnvelopeGenerator.Application.Resources +@using Microsoft.Extensions.Options @inject IStringLocalizer _localizer @inject System.Text.Encodings.Web.UrlEncoder _encoder @inject Ganss.Xss.HtmlSanitizer _sanitizer @inject HighlightHtmlSanitizer _hlSanitizer @inject Microsoft.AspNetCore.Http.IHttpContextAccessor _accessor @inject Cultures _cultures +@inject IOptions _logoOpt @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers \ No newline at end of file diff --git a/EnvelopeGenerator.Web/WebKey.cs b/EnvelopeGenerator.Web/WebKey.cs index f2b31630..c11c76a0 100644 --- a/EnvelopeGenerator.Web/WebKey.cs +++ b/EnvelopeGenerator.Web/WebKey.cs @@ -33,5 +33,6 @@ public static readonly string RejectionInfo1_ext = nameof(RejectionInfo1_ext); public static readonly string RejectionInfo2_ext = nameof(RejectionInfo2_ext); public static readonly string SigningProcessTitle = nameof(SigningProcessTitle); + public static readonly string WelcomeToTheESignPortal = nameof(WelcomeToTheESignPortal); } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/appsettings.json b/EnvelopeGenerator.Web/appsettings.json index 8d28c37e..e3c23d6a 100644 --- a/EnvelopeGenerator.Web/appsettings.json +++ b/EnvelopeGenerator.Web/appsettings.json @@ -20,9 +20,9 @@ "Content-Security-Policy": [ // The first format parameter {0} will be replaced by the nonce value. "default-src 'self'", "script-src 'self' 'nonce-{0}' 'unsafe-eval'", - "style-src 'self' 'unsafe-inline'", + "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com:*", "img-src 'self' data: https: blob:", - "font-src 'self'", + "font-src 'self' https://fonts.gstatic.com:*", "connect-src 'self' https://nominatim.openstreetmap.org:* http://localhost:* https://localhost:* ws://localhost:* wss://localhost:* blob:", "frame-src 'self'", "media-src 'self'", @@ -130,5 +130,10 @@ "Name": "City", "Platforms": [ "javascript" ] } - ] + ], + "Logo": { + "Src": "/img/digital_data.svg", + "ShowPageClass": "dd-show-logo", + "LockedPageClass": "dd-locked-logo" + } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/bundleconfig.json b/EnvelopeGenerator.Web/bundleconfig.json index f69c4c25..3584b22f 100644 --- a/EnvelopeGenerator.Web/bundleconfig.json +++ b/EnvelopeGenerator.Web/bundleconfig.json @@ -58,5 +58,23 @@ "inputFiles": [ "wwwroot/lib/bootstrap-cookie-consent-settings-main/bootstrap-cookie-consent-settings.js" ] + }, + { + "outputFileName": "wwwroot/css/cursor.min.css", + "inputFiles": [ + "wwwroot/css/cursor.css" + ] + }, + { + "outputFileName": "wwwroot/css/logo.min.css", + "inputFiles": [ + "wwwroot/css/logo.css" + ] + }, + { + "outputFileName": "wwwroot/css/privacy-policy.min.css", + "inputFiles": [ + "wwwroot/css/privacy-policy.css" + ] } ] diff --git a/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html b/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html deleted file mode 100644 index 73262fb6..00000000 --- a/EnvelopeGenerator.Web/wwwroot/cookies-policy.en.html +++ /dev/null @@ -1,68 +0,0 @@ -

Cookies Policy

-

Last updated: April 16, 2024

-

This Cookies Policy explains what Cookies are and how We use them. You should read this policy so You can understand what type of cookies We use, or the information We collect using Cookies and how that information is used. This Cookies Policy has been created with the help of the Cookies Policy Generator.

-

Cookies do not typically contain any information that personally identifies a user, but personal information that we store about You may be linked to the information stored in and obtained from Cookies. For further information on how We use, store and keep your personal data secure, see our Privacy Policy.

-

We do not store sensitive personal information, such as mailing addresses, account passwords, etc. in the Cookies We use.

-

Interpretation and Definitions

-

Interpretation

-

The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.

-

Definitions

-

For the purposes of this Cookies Policy:

-
    -
  • Company (referred to as either "the Company", "We", "Us" or "Our" in this Cookies Policy) refers to Digital Data GmbH, Ludwig Rinn Str. 16, D-35452 Heuchelheim.
  • -
  • Cookies means small files that are placed on Your computer, mobile device or any other device by a website, containing details of your browsing history on that website among its many uses.
  • -
  • Website refers to Digitaldata Unterschrift, accessible from unterschrift.digitaldata.works
  • -
  • You means the individual accessing or using the Website, or a company, or any legal entity on behalf of which such individual is accessing or using the Website, as applicable.
  • -
-

The use of the Cookies

-

Type of Cookies We Use

-

Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close your web browser.

-

We use both session and persistent Cookies for the purposes set out below:

-
    -
  • -

    Necessary / Essential Cookies

    -

    Type: Session Cookies

    -

    Administered by: Us

    -

    Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.

    -
  • -
  • -

    Functionality Cookies

    -

    Type: Persistent Cookies

    -

    Administered by: Us

    -

    Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.

    -
  • -
-

Your Choices Regarding Cookies

-

If You prefer to avoid the use of Cookies on the Website, first You must disable the use of Cookies in your browser and then delete the Cookies saved in your browser associated with this website. You may use this option for preventing the use of Cookies at any time.

-

If You do not accept Our Cookies, You may experience some inconvenience in your use of the Website and some features may not function properly.

-

If You'd like to delete Cookies or instruct your web browser to delete or refuse Cookies, please visit the help pages of your web browser.

- -

For any other web browser, please visit your web browser's official web pages.

-

More Information about Cookies

-

You can learn more about cookies here: All About Cookies by TermsFeed.

-

Contact Us

-

If you have any questions about this Cookies Policy, You can contact us:

-
    -
  • -

    By visiting this page on our website: unterschrift.digitaldata.works

    -
  • -
  • -

    By phone number: +49(0)-641-202360

    -
  • -
  • -

    By mail: Ludwig Rinn Str. 16, D-35452 Heuchelheim

    -
  • -
\ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/logo.css b/EnvelopeGenerator.Web/wwwroot/css/logo.css new file mode 100644 index 00000000..9527cdaa --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/css/logo.css @@ -0,0 +1,27 @@ +.dd-locked-logo { + width: 13rem; + padding-top: 1rem; +} + +.dd-show-logo { + width: 9rem; +} + +.cursor-locked-logo { + width: 9rem; + padding-top: 1rem; +} + +.cursor-show-logo { + width: 6rem; +} + +@media (max-width: 767px) { + .dd-show-logo { + width: 5rem; + } + + .cursor-show-logo { + width: 3rem; + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/logo.min.css b/EnvelopeGenerator.Web/wwwroot/css/logo.min.css new file mode 100644 index 00000000..bc86abec --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/css/logo.min.css @@ -0,0 +1 @@ +.dd-locked-logo{width:13rem;padding-top:1rem}.dd-show-logo{width:9rem}.cursor-locked-logo{width:9rem;padding-top:1rem}.cursor-show-logo{width:6rem}@media(max-width:767px){.dd-show-logo{width:5rem}.cursor-show-logo{width:3rem}} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.css b/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.css new file mode 100644 index 00000000..5dd01060 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.css @@ -0,0 +1,41 @@ +body { + font-family: Arial, sans-serif; + line-height: 1.6; + margin: 1.25rem; + background-color: #f4f4f4; +} + +header { + text-align: center; + margin: 0rem 10rem 3rem 10rem; + box-shadow: 0 .25rem .5rem rgba(0, 0, 0, 0.1); +} + +h1 { + color: #333; +} + +h2 { + color: #0056b3; +} + +section { + background-color: white; + padding: 1.25rem; + border-radius: 0.5rem; + box-shadow: 0 .25rem .5rem rgba(0, 0, 0, 0.1); + margin: 0rem 10rem 3rem 10rem +} + +ul { + list-style: disc inside; +} + +a { + color: #0056b3; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.min.css b/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.min.css new file mode 100644 index 00000000..4394da81 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/css/privacy-policy.min.css @@ -0,0 +1 @@ +body{font-family:Arial,sans-serif;line-height:1.6;margin:1.25rem;background-color:#f4f4f4}header{text-align:center;margin:0 10rem 3rem 10rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1)}h1{color:#333}h2{color:#0056b3}section{background-color:#fff;padding:1.25rem;border-radius:.5rem;box-shadow:0 .25rem .5rem rgba(0,0,0,.1);margin:0 10rem 3rem 10rem}ul{list-style:disc inside}a{color:#0056b3;text-decoration:none}a:hover{text-decoration:underline} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/site.css b/EnvelopeGenerator.Web/wwwroot/css/site.css index d5d5b332..d9dbe1a3 100644 --- a/EnvelopeGenerator.Web/wwwroot/css/site.css +++ b/EnvelopeGenerator.Web/wwwroot/css/site.css @@ -10,6 +10,10 @@ height: 80vh; } +.navbar-toggler { + border: 0; +} + .btn-group { margin-right: 10vw; margin-bottom: 10vh; @@ -66,8 +70,25 @@ body { background-color: #bbb; + + display: flex; + flex-direction: column; + height: 100vh; + margin: 0; } +main { + flex: 1; +} + +footer { + background: #333; + color: white; + text-align: center; + padding: 10px 0; +} + + .page { margin-top: 3rem; background: white; @@ -163,8 +184,43 @@ footer#page-footer { border-radius: 3.125rem; } +.navbar .container { + display: flex; + padding: 0; + margin: 0; +} + +.navbar-toggler { + padding: 0; + margin: 0; + width: 4rem; + left: 0; +} + .envelope-message { + position: absolute; + display: flex; + width: calc(100% - 8rem); + align-items: center; + justify-content: start; + margin-left: 4rem; +} + +.envelope-message .icon { + margin-right: 0.5rem; +} + +.envelope-message .message { font-family: 'Roboto', sans-serif; + font-size: 16px; + font-weight: 550; +} + +.logo { + width: 9rem; + position: absolute; + right: 0; + margin-right:2rem; } .none-display { @@ -224,18 +280,76 @@ footer#page-footer { z-index: 1050; } +#form-access-code { + margin-left: 5rem; +} + +.header-1 { + align-items: center; + justify-content: space-between; + margin-top:0; + padding-top: 0; +} + +.header-1 .text { + text-align: center; + margin-left: 1.5vw; + margin-top:0; + padding-top: 0; +} + /* styles for mobile responsiveness */ +@media (max-height: 850px) { + .navbar .container { + display: flex; + padding: 0; + margin: 0; + } + + .navbar-toggler { + padding: 0; + margin: 0; + width: 4rem; + left: 0; + } + + .envelope-message { + width: calc(100% - 4rem -9rem); + } + + .envelope-message .message { + font-size: 14px; + font-weight: 550; + } + + .logo { + width: 9rem; + position: absolute; + right: 0; + } + + .card-text, .card-text { + font-size: 0.6rem; /* Font size reduced */ + margin: 0rem; + padding: 0rem; + } + + .highlight { + font-weight: 700; + font-size: 0.5rem; + } + + .signature-process-title, .signature-process-name { + font-size: 0.7rem; + } +} + @media (max-width: 767px) { .navbar { flex-direction: column; align-items: flex-start; } - .navbar-toggler { - transform: scale(0.75); - padding: 0; - } - .navbar-brand { font-size: 0.5rem; text-align: center; @@ -243,14 +357,25 @@ footer#page-footer { text-overflow: ellipsis; } - .collapse .card-text, .collapsing .card-text { - font-size: 0.6rem; /* Font size reduced */ - margin: 0rem; - padding: 0rem; + .envelope-message { + width: calc(100% - 4rem - 4.5rem); + margin-left: 3rem; } - .sender-card .card-body { - padding: 0.5rem; + .envelope-message .message { + font-size: 12px; + font-weight: 550; + } + + .envelope-message .icon { + margin-right: 0.1rem; + font-size: 1rem + } + + .logo { + width: 5rem; + right: 0; + margin-right: 1rem; } .btn_group { @@ -266,10 +391,6 @@ footer#page-footer { display: none; } - img { - max-width: 4rem; - } - .page { margin-top: 1rem; max-width: 90%; @@ -280,28 +401,13 @@ footer#page-footer { max-width: 90%; } - .highlight { - font-weight: 700; - font-size: 0.5rem; - } - - .signature-process-title, .signature-process-name { - font-size: 0.7rem; + #form-access-code { + margin-left: 0; } } -@media (max-height: 850px) { - .collapse .card-text, .collapsing .card-text { - font-size: 0.5rem; /* Font size reduced */ - margin: 0rem; - padding: 0rem; - } - .highlight { - font-weight: 700; - font-size: 0.5rem; - } - - .signature-process-title, .signature-process-name { - font-size: 0.7rem; +@media (max-height: 600px) { + .collapse { + height: 4rem; } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/css/site.min.css b/EnvelopeGenerator.Web/wwwroot/css/site.min.css index d0b6755b..241a4f3d 100644 --- a/EnvelopeGenerator.Web/wwwroot/css/site.min.css +++ b/EnvelopeGenerator.Web/wwwroot/css/site.min.css @@ -1 +1 @@ -#app{background:#808080;width:100vw;height:80vh}.btn-group{margin-right:10vw;margin-bottom:10vh}.btn_refresh,.btn_reject,.btn_complete{height:2.5rem}.btn_complete .icon,.btn_reject .icon,.btn_refresh .icon{width:1.1rem}.btn_complete span,.btn_reject span,.btn_refresh span{vertical-align:middle}.button-finish{transition:background-color linear 300ms;background-color:#059669;color:#fff;border-left:0}.button-finish:hover,.button-finish:focus,.button-finish:active{background-color:#10b981;color:#fff}.button-reject{transition:background-color linear 300ms;background-color:#d97706;color:#fff;border-left:0}.button-reject:hover,.button-reject:focus,.button-reject:active{background-color:#f59e0b;color:#fff}.button-reset{transition:background-color linear 300ms;background-color:#2563eb;color:#fff;border-left:0}.button-reset:hover,.button-reset:focus,.button-reset:active{background-color:#3b82f6;color:#fff}body{background-color:#bbb}.page{margin-top:3rem;background:#fff;border-radius:.313rem;box-shadow:rgba(9,30,66,.25) 0 .25rem .5rem -.125rem,rgba(9,30,66,.08) 0 0 0 .063rem;max-width:40rem}.page section{max-width:30rem;margin:0 auto}.page header .icon{display:inline-block;border-radius:6.25rem;padding:.938rem;margin-bottom:2rem}.page header .icon.admin{background-color:#331904;color:#fecba1}.page header .icon.locked{background-color:#ffc107;color:#000}.page header .icon.signed{background-color:#146c43;color:#fff}.page header .icon.rejected{background-color:#e4d8d5;color:#fff}.page .form{max-width:30rem;margin:2rem auto;display:flex;gap:1rem}#form-access-code>.input,#form-admin-password>.input{flex-grow:1}#page-admin header .icon{background-color:#331904;color:#fecba1}.envelope{display:block;border:.063rem solid #eee;margin-bottom:1rem;padding:.5rem}footer#page-footer{color:#333;max-width:40rem;margin-top:1rem;font-size:.85rem}footer#page-footer a,footer#page-footer a:link,footer#page-footer a:hover,footer#page-footer a:visited,footer#page-footer a:focus{color:#444}.sender-card{background-color:transparent;border:0}.sender-card .row{height:7vh}.sender-card img{height:7vh;background-color:#d1cfcf;border-radius:3.125rem}.envelope-message{font-family:'Roboto',sans-serif}.none-display{display:none}.dropdown-flag img,.img-flag{width:30%;height:70%}.dropdown-flag{height:75%;width:75%}.increase-dropdown-height{min-height:25rem}.dropdown-flag .select2-container{width:100%!important;max-width:11.25rem}.lang-item{font-size:.85rem}#langDropdownMenuButton{min-width:4vw}.highlight{font-weight:700;font-size:.85rem}.signature-process-title,.signature-process-name{font-size:1.125rem}.mail-link{color:#000;text-decoration:none}.mail-link:hover{text-decoration:underline}#flex-action-panel{z-index:1050}@media(max-width:767px){.navbar{flex-direction:column;align-items:flex-start}.navbar-toggler{transform:scale(.75);padding:0}.navbar-brand{font-size:.5rem;text-align:center;overflow:hidden;text-overflow:ellipsis}.collapse .card-text,.collapsing .card-text{font-size:.6rem;margin:0;padding:0}.sender-card .card-body{padding:.5rem}.btn_group{position:fixed;flex-direction:row;bottom:.5rem;right:.5rem}.img-fluid{width:1.2rem;height:100%;display:none}img{max-width:4rem}.page{margin-top:1rem;max-width:90%;padding:.5rem}.page section{max-width:90%}.highlight{font-weight:700;font-size:.5rem}.signature-process-title,.signature-process-name{font-size:.7rem}}@media(max-height:850px){.collapse .card-text,.collapsing .card-text{font-size:.5rem;margin:0;padding:0}.highlight{font-weight:700;font-size:.5rem}.signature-process-title,.signature-process-name{font-size:.7rem}} \ No newline at end of file +#app{background:#808080;width:100vw;height:50vh}.navbar-toggler{border:0}.btn-group{margin-right:10vw;margin-bottom:10vh}.btn_refresh,.btn_reject,.btn_complete{height:2.5rem}.btn_complete .icon,.btn_reject .icon,.btn_refresh .icon{width:1.1rem}.btn_complete span,.btn_reject span,.btn_refresh span{vertical-align:middle}.button-finish{transition:background-color linear 300ms;background-color:#059669;color:#fff;border-left:0}.button-finish:hover,.button-finish:focus,.button-finish:active{background-color:#10b981;color:#fff}.button-reject{transition:background-color linear 300ms;background-color:#d97706;color:#fff;border-left:0}.button-reject:hover,.button-reject:focus,.button-reject:active{background-color:#f59e0b;color:#fff}.button-reset{transition:background-color linear 300ms;background-color:#2563eb;color:#fff;border-left:0}.button-reset:hover,.button-reset:focus,.button-reset:active{background-color:#3b82f6;color:#fff}body{background-color:#bbb;display:flex;flex-direction:column;height:100vh;margin:0}main{flex:1}footer{background:#333;color:#fff;text-align:center;padding:10px 0}.page{margin-top:3rem;background:#fff;border-radius:.313rem;box-shadow:rgba(9,30,66,.25) 0 .25rem .5rem -.125rem,rgba(9,30,66,.08) 0 0 0 .063rem;max-width:40rem}.page section{max-width:30rem;margin:0 auto}.page header .icon{display:inline-block;border-radius:6.25rem;padding:.938rem;margin-bottom:2rem}.page header .icon.admin{background-color:#331904;color:#fecba1}.page header .icon.locked{background-color:#ffc107;color:#000}.page header .icon.signed{background-color:#146c43;color:#fff}.page header .icon.rejected{background-color:#e4d8d5;color:#fff}.page .form{max-width:30rem;margin:2rem auto;display:flex;gap:1rem}#form-access-code>.input,#form-admin-password>.input{flex-grow:1}#page-admin header .icon{background-color:#331904;color:#fecba1}.envelope{display:block;border:.063rem solid #eee;margin-bottom:1rem;padding:.5rem}footer#page-footer{color:#333;max-width:40rem;margin-top:1rem;font-size:.85rem}footer#page-footer a,footer#page-footer a:link,footer#page-footer a:hover,footer#page-footer a:visited,footer#page-footer a:focus{color:#444}.sender-card{background-color:transparent;border:0}.sender-card .row{height:7vh}.sender-card img{height:7vh;background-color:#d1cfcf;border-radius:3.125rem}.navbar .container{display:flex;padding:0;margin:0}.navbar-toggler{padding:0;margin:0;width:4rem;left:0}.envelope-message{position:absolute;display:flex;width:calc(100% - 8rem);align-items:center;justify-content:start;margin-left:4rem}.envelope-message .icon{margin-right:.5rem}.envelope-message .message{font-family:'Roboto',sans-serif;font-size:16px;font-weight:550}.logo{width:9rem;position:absolute;right:0;margin-right:2rem}.none-display{display:none}.dropdown-flag img,.img-flag{width:30%;height:70%}.dropdown-flag{height:75%;width:75%}.increase-dropdown-height{min-height:25rem}.dropdown-flag .select2-container{width:100%!important;max-width:11.25rem}.lang-item{font-size:.85rem}#langDropdownMenuButton{min-width:4vw}.highlight{font-weight:700;font-size:.85rem}.signature-process-title,.signature-process-name{font-size:1.125rem}.mail-link{color:#000;text-decoration:none}.mail-link:hover{text-decoration:underline}#flex-action-panel{z-index:1050}#form-access-code{margin-left:5rem}.header-1{align-items:center;justify-content:space-between;margin-top:0;padding-top:0}.header-1 .text{text-align:center;margin-left:1.5vw;margin-top:0;padding-top:0}@media(max-height:850px){.navbar .container{display:flex;padding:0;margin:0}.navbar-toggler{padding:0;margin:0;width:4rem;left:0}.envelope-message{width:calc(100% - 4rem - 9rem)}.envelope-message .message{font-size:14px;font-weight:550}.logo{width:9rem;position:absolute;right:0}.card-text,.card-text{font-size:.6rem;margin:0;padding:0}.highlight{font-weight:700;font-size:.5rem}.signature-process-title,.signature-process-name{font-size:.7rem}}@media(max-width:767px){.navbar{flex-direction:column;align-items:flex-start}.navbar-brand{font-size:.5rem;text-align:center;overflow:hidden;text-overflow:ellipsis}.envelope-message{width:calc(100% - 4rem - 4.5rem);margin-left:3rem}.envelope-message .message{font-size:12px;font-weight:550}.envelope-message .icon{margin-right:.1rem;font-size:1rem}.logo{width:5rem;right:0;margin-right:1rem}.btn_group{position:fixed;flex-direction:row;bottom:.5rem;right:.5rem}.img-fluid{width:1.2rem;height:100%;display:none}.page{margin-top:1rem;max-width:90%;padding:.5rem}.page section{max-width:90%}#form-access-code{margin-left:0}}@media(max-height:600px){.collapse{height:4rem}} \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/img/cursor_logo.png b/EnvelopeGenerator.Web/wwwroot/img/cursor_logo.png new file mode 100644 index 00000000..baa0941f Binary files /dev/null and b/EnvelopeGenerator.Web/wwwroot/img/cursor_logo.png differ diff --git a/EnvelopeGenerator.Web/wwwroot/js/annotation.js b/EnvelopeGenerator.Web/wwwroot/js/annotation.js index 415277bb..b566c753 100644 --- a/EnvelopeGenerator.Web/wwwroot/js/annotation.js +++ b/EnvelopeGenerator.Web/wwwroot/js/annotation.js @@ -52,7 +52,7 @@ /** * Date, post code and place text form part */ - const date_place_top_shift = 16 + const date_place_top_shift = 9.5; //date const id_date = PSPDFKit.generateInstantId() const annotation_date = new PSPDFKit.Annotations.WidgetAnnotation({ @@ -64,8 +64,8 @@ boundingBox: new PSPDFKit.Geometry.Rect({ width: width * 1.55, height: height / 2, - top: top + height + 25 + date_place_top_shift, - left: left + width * 1.30, + top: top + height + 25 + date_place_top_shift + (height), + left: left }), fontSize: 8, backgroundColor: PSPDFKit.Color.TRANSPARENT, @@ -80,7 +80,7 @@ value: detailedCurrentDate(), readOnly: true }) - + //city var location = await getLocation(); const id_city = PSPDFKit.generateInstantId() @@ -93,12 +93,12 @@ boundingBox: new PSPDFKit.Geometry.Rect({ width: width * 1.2, height: height / 2, - top: top + height + 25 + date_place_top_shift, + top: top + height + 23 + date_place_top_shift + 2, left: left, }), fontSize: 8 }) - + const formFieldCity = new PSPDFKit.FormFields.TextFormField({ name: id_city, annotationIds: PSPDFKit.Immutable.List([annotation_city.id]), @@ -125,8 +125,8 @@ boundingBox: new PSPDFKit.Geometry.Rect({ width: width * 0.75, height: height / 2, - top: top + height + 25 + label_top_shift + date_place_top_shift, - left: left + width * 1.30 + top: top + height + 23 + label_top_shift + date_place_top_shift + (height) + 4, + left: left }), fontSize: 8, backgroundColor: PSPDFKit.Color.TRANSPARENT, @@ -166,7 +166,7 @@ annotationIds: PSPDFKit.Immutable.List([annotation_city_label.id]), value: "Ort", readOnly: true - }) + }) return [annotation, formField, annotation_date, formFieldDate, annotation_city, formFieldCity, annotation_date_label, formFieldDateLabel, annotation_city_label, formFieldCityLabel] } @@ -311,7 +311,7 @@ //required static #requiredFieldNames = new Array() - + static markFieldAsRequired(formField) { this.#requiredFieldNames.push(formField.name) } @@ -327,7 +327,7 @@ this.#cityFieldNames.push(formField.name) } - static isCityField(formField){ + static isCityField(formField) { return this.#cityFieldNames.includes(formField.name) } } \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/privacy-policy.de-DE.html b/EnvelopeGenerator.Web/wwwroot/privacy-policy.de-DE.html new file mode 100644 index 00000000..c94972a2 --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/privacy-policy.de-DE.html @@ -0,0 +1,123 @@ + + + + + + Datenschutzinformation für das Fernsignatursystem signFLOW + + + +
+

Datenschutzinformation für das Fernsignatursystem signFLOW

+

Stand: 19.09.2024

+
+ +
+

1. Allgemeine Informationen

+

In der heutigen schnelllebigen und zunehmend digitalen Welt, sind personenbezogene Daten eine wichtige Ressource. Ihre Daten sind wertvoll und müssen daher mit der durch diverse Gesetze und Vorschriften (DSGVO, TDDDG, ...) gebotenen Sorgfalt behandelt werden.

+

Als Anbieter von lokalen Lösungen (OnPremise) setzt der Hersteller des signFLOWs, die Digital Data GmbH, einen klaren Schwerpunkt auf Datenschutz und Datensicherheit. Für Sie bedeutet dies, dass nur die nötigsten Daten erhoben und gespeichert werden (Datensparsamkeit bzw. Datenminimierung). Außerdem kommen bei der Verarbeitung aktuelle und als sicher geltende Technologien zum Einsatz.

+

Kontaktdaten des Herstellers:

+
+ Digital Data GmbH
+ Ludwig-Rinn-Straße 16
+ 35452 Heuchelheim
+ https://digitaldata.works
+ info-flow@digitaldata.works
+ Telefon: 0049 641 202360
+
+

Kontakt zum Datenschutzbeauftragten: privacy-flow@digitaldata.works

+
+ +
+

2. Verantwortliche Stelle der Datenverarbeitung

+

Ihre Daten werden vertrauensvoll verarbeitet von:

+
+ Digital Data GmbH
+ Ludwig-Rinn-Straße 16
+ 35452 Heuchelheim
+ https://digitaldata.works
+ info-flow@digitaldata.works
+ Telefon: 0049 641 202360
+
+

Kontakt zu unserer Datenschutzbeauftragten: privacy-flow@digitaldata.works

+
+ +
+

3. Datenerhebung

+

3.1 Die folgenden Kategorien personenbezogener Daten werden verarbeitet

+
    +
  • Namen: Vor- und Zunamen sowie Ihre digitale Unterschrift
  • +
  • Kontaktdaten: Telefonnummer, Mobilfunknummer und E-Mail-Adresse
  • +
  • Technische Daten: IP-Adresse, Zeitpunkt des Zugriffs oder Zugriffsversuchs
  • +
+ +

3.2 Ursprung der personenbezogenen Daten

+

Sie haben die unter 3.1 stehenden Daten vorab an Ihren Geschäftspartner (die verantwortliche Stelle) übermittelt. Diese Übermittlung kann mündlich per Telefon, im persönlichen Kontakt, per E-Mail oder per Kontaktformular geschehen sein.

+

Ihre digitale Signatur übermitteln Sie eigenständig, bei der Unterzeichnung eines Dokuments.

+ +

3.3 Aufbewahrungsfristen / Speicherungsdauer

+
    +
  • Die automatische E-Mail Korrespondenz wird für 6 Jahre aufbewahrt.
  • +
  • Unterzeichnete Verträge werden für die Dauer ihrer Laufzeit + 10 Jahre aufbewahrt.
  • +
  • Der technische Vorgang wird in der signFLOW Softwarelösung je nach Dokumentart bzw. Vertragsart unbegrenzt aufbewahrt.
  • +
+

Ihre personenbezogenen Daten werden aber grundsätzlich anonymisiert, wenn:

+
    +
  • Der Vertrag ausgelaufen ist und die gesetzliche Aufbewahrungszeit vorbei ist.
  • +
  • Der Vertrag von Ihnen abgelehnt wurde bzw. nie unterschrieben wurde.
  • +
+

Die gesetzlichen Grundlagen dieser Aufbewahrungsfristen bieten unter anderen:

+
    +
  • Handelsgesetzbuch (HGB)
  • +
  • Abgabenordnung (AO)
  • +
  • Grundsätze zur ordnungsgemäßen Führung und Aufbewahrung von Büchern, Aufzeichnungen und Unterlagen in elektronischer Form sowie zum Datenzugriff (GoBD)
  • +
+ +

3.4 Verarbeitungszweck

+

Die unter 3.1 definierten personenbezogenen Daten werden verarbeitet, um den technisch notwendigen Prozess abzubilden bzw. anbieten zu können. Dies umfasst die Feststellung der Identität, Antragsprüfung, Abrechnung und Dokumentationspflichten.

+ +

3.5 Rechtmäßigkeit der Verarbeitung

+

Ihre Daten werden auf Grundlage einer sich anbahnenden oder bereits vorhandenen Geschäftsbeziehung erhoben.

+

Die rechtliche Grundlage für die Übermittlung an zuständige Stellen bildet §8 Abs. 2 VDG.

+ +

3.6 Berechtigte Interessen

+

Es besteht ein berechtigtes Interesse der verantwortlichen Stelle gemäß Art. 6 Abs. 1 lit. f DSGVO, insbesondere in der Informationssicherheit und zur Vermeidung von Schäden.

+ +

3.7 Erforderlichkeit der Daten

+

Die erhobenen Daten stellen das Minimum der nötigen Daten zwecks digitaler Unterschrift dar.

+ +

3.8 Weitergabe von Daten

+

Daten werden nur in Ausnahmefällen zwecks Supportleistungen an den Hersteller weitergegeben.

+
+ +
+

4. Verwendung von Cookies

+

Beim Besuch bestimmter Seiten kommen temporäre Cookies zum Einsatz, die für die technische Bereitstellung der Dienste notwendig sind.

+
+ +
+

5. Betroffenenrechte

+

Wenn Sie Fragen zu Ihren Daten haben oder eine Berichtigung, Löschung oder Einschränkung der Verarbeitung wünschen, senden Sie bitte Ihre Anfrage per Post oder E-Mail an die oben angegebene Adresse. Sie können auch gemäß Art. 21 DSGVO Widerspruch gegen die Verarbeitung einlegen.

+
+ +
+

6. Hinweisgebersystem

+

Wir haben ein unabhängiges, neutrales und vertrauliches Hinweisgebersystem eingerichtet, das es internen und externen Hinweisgebenden ermöglicht, anonym Meldungen abzugeben. Dieses Verfahren dient der Aufdeckung von schwerwiegenden Verstößen gegen geltendes Recht sowie anderen ernsthaften Angelegenheiten.

+ +

6.1 Zweck und Rechtsgrundlage der Datenverarbeitung

+

Der Zweck der Verarbeitung besteht in der Verwaltung des Hinweisgebersystems, welches rechtliche Verpflichtungen gemäß Art. 6 Abs. 1 lit. c DSGVO erfüllt.

+ +

6.2 Kategorien personenbezogener Daten

+

Es können allgemeine personenbezogene Daten, Daten zu strafrechtlichen Verurteilungen sowie besondere Kategorien personenbezogener Daten verarbeitet werden.

+ +

6.3 Verpflichtung zur Bereitstellung personenbezogener Daten

+

Die Bereitstellung personenbezogener Daten ist nicht zwingend erforderlich, da auch eine anonyme Meldung möglich ist.

+ +

6.4 Empfänger personenbezogener Daten

+

Die Meldungen werden bei der verarbeitenden Stelle erfasst und an zuständige Fachabteilungen weitergeleitet. Eine Weitergabe erfolgt nur bei rechtlicher Notwendigkeit oder mit Zustimmung der hinweisgebenden Person.

+ +

6.5 Speicherdauer

+

Personenbezogene Daten, die sich als nicht relevant erweisen, werden anonymisiert oder gelöscht. Archivierte Meldungen werden nach Abschluss des Verfahrens und Erfüllung der Dokumentationspflichten nach 3 Jahren gelöscht.

+
+ + \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/privacy-policy.en-US.html b/EnvelopeGenerator.Web/wwwroot/privacy-policy.en-US.html new file mode 100644 index 00000000..64bedaae --- /dev/null +++ b/EnvelopeGenerator.Web/wwwroot/privacy-policy.en-US.html @@ -0,0 +1,123 @@ + + + + + + Privacy Information for the Remote Signature System signFLOW + + + +
+

Privacy Information for the Remote Signature System signFLOW

+

Last updated: 19.09.2024

+
+ +
+

1. General Information

+

In today’s fast-paced and increasingly digital world, personal data is a valuable resource. Your data is important and must be handled with care as mandated by various laws and regulations (GDPR, TDDDG, ...).

+

As a provider of on-premise solutions, the manufacturer of signFLOW, Digital Data GmbH, places a clear emphasis on data protection and data security. For you, this means that only the necessary data is collected and stored (data minimization). Additionally, the processing is done using the latest and considered secure technologies.

+

Manufacturer's Contact Information:

+
+ Digital Data GmbH
+ Ludwig-Rinn-Straße 16
+ 35452 Heuchelheim
+ https://digitaldata.works
+ info-flow@digitaldata.works
+ Phone: 0049 641 202360
+
+

Contact for Data Protection: privacy-flow@digitaldata.works

+
+ +
+

2. Responsible Party for Data Processing

+

Your data will be processed confidentially by:

+
+ Digital Data GmbH
+ Ludwig-Rinn-Straße 16
+ 35452 Heuchelheim
+ https://digitaldata.works
+ info-flow@digitaldata.works
+ Phone: 0049 641 202360
+
+

Contact our Data Protection Officer: privacy-flow@digitaldata.works

+
+ +
+

3. Data Collection

+

3.1 The following categories of personal data are processed:

+
    +
  • Names: First and last names, and your digital signature
  • +
  • Contact details: Phone number, mobile phone number, and email address
  • +
  • Technical data: IP address, time of access, or attempted access
  • +
+ +

3.2 Source of personal data

+

You have previously provided the data listed in 3.1 to your business partner (the responsible party). This submission may have occurred orally by phone, in person, via email, or through a contact form.

+

You submit your digital signature independently when signing a document.

+ +

3.3 Retention periods / storage duration

+
    +
  • Automatic email correspondence is stored for 6 years.
  • +
  • Signed contracts are stored for the duration of their term plus 10 years.
  • +
  • The technical process is stored indefinitely in the signFLOW software solution depending on the type of document or contract.
  • +
+

Your personal data will generally be anonymized when:

+
    +
  • The contract has expired and the legal retention period has passed.
  • +
  • The contract was rejected by you or never signed.
  • +
+

The legal bases for these retention periods include:

+
    +
  • Commercial Code (HGB)
  • +
  • Tax Code (AO)
  • +
  • Principles for the proper management and storage of books, records, and documents in electronic form and access to data (GoBD)
  • +
+ +

3.4 Purpose of processing

+

The personal data defined in 3.1 is processed to enable the technically necessary process. This includes identity verification, application review, billing, and documentation obligations.

+ +

3.5 Lawfulness of processing

+

Your data is collected based on a developing or existing business relationship.

+

The legal basis for transferring data to responsible authorities is §8 para. 2 VDG.

+ +

3.6 Legitimate interests

+

There is a legitimate interest of the responsible party according to Art. 6 para. 1 lit. f GDPR, especially in information security and damage prevention.

+ +

3.7 Necessity of the data

+

The data collected represents the minimum necessary for the purpose of a digital signature.

+ +

3.8 Data sharing

+

Data is only shared with the manufacturer in exceptional cases for support services.

+
+ +
+

4. Use of Cookies

+

Temporary cookies are used when visiting certain pages, which are necessary for the technical provision of the services.

+
+ +
+

5. Rights of Data Subjects

+

If you have questions about your data or wish to request rectification, deletion, or restriction of processing, please send your inquiry by post or email to the address listed above. You can also object to the processing under Art. 21 GDPR.

+
+ +
+

6. Whistleblower System

+

We have established an independent, neutral, and confidential whistleblower system that allows internal and external whistleblowers to submit reports anonymously. This system serves to uncover serious violations of applicable law and other significant matters.

+ +

6.1 Purpose and legal basis of data processing

+

The purpose of the processing is to manage the whistleblower system, which fulfills legal obligations under Art. 6 para. 1 lit. c GDPR.

+ +

6.2 Categories of personal data

+

General personal data, data related to criminal convictions, and special categories of personal data may be processed.

+ +

6.3 Obligation to provide personal data

+

Providing personal data is not mandatory, as anonymous reporting is also possible.

+ +

6.4 Recipients of personal data

+

Reports are processed by the relevant department and forwarded to the appropriate divisions. Data is only shared when legally required or with the consent of the whistleblower.

+ +

6.5 Retention period

+

Personal data that proves irrelevant will be anonymized or deleted. Archived reports are deleted after 3 years following the conclusion of the process and documentation obligations.

+
+ + \ No newline at end of file diff --git a/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html b/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html deleted file mode 100644 index 4de34e9e..00000000 --- a/EnvelopeGenerator.Web/wwwroot/privacy-policy.en.html +++ /dev/null @@ -1,184 +0,0 @@ -

Privacy Policy

-

Last updated: April 16, 2024

-

This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.

-

We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the Privacy Policy Generator.

-

Interpretation and Definitions

-

Interpretation

-

The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.

-

Definitions

-

For the purposes of this Privacy Policy:

-
    -
  • -

    Account means a unique account created for You to access our Service or parts of our Service.

    -
  • -
  • -

    Affiliate means an entity that controls, is controlled by or is under common control with a party, where "control" means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority.

    -
  • -
  • -

    Company (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to Digital Data GmbH, Ludwig Rinn Str. 16, D-35452 Heuchelheim.

    -
  • -
  • -

    Cookies are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.

    -
  • -
  • -

    Country refers to: Hessen, Germany

    -
  • -
  • -

    Device means any device that can access the Service such as a computer, a cellphone or a digital tablet.

    -
  • -
  • -

    Personal Data is any information that relates to an identified or identifiable individual.

    -
  • -
  • -

    Service refers to the Website.

    -
  • -
  • -

    Service Provider means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.

    -
  • -
  • -

    Usage Data refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).

    -
  • -
  • -

    Website refers to Unterschrift, accessible from unterschrift.digitaldata.works

    -
  • -
  • -

    You means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.

    -
  • -
-

Collecting and Using Your Personal Data

-

Types of Data Collected

-

Personal Data

-

While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:

-
    -
  • -

    Email address

    -
  • -
  • -

    First name and last name

    -
  • -
  • -

    Usage Data

    -
  • -
-

Usage Data

-

Usage Data is collected automatically when using the Service.

-

Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.

-

When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.

-

We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.

-

Tracking Technologies and Cookies

-

We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:

-
    -
  • Cookies or Browser Cookies. A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.
  • -
  • Web Beacons. Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).
  • -
-

Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. You can learn more about cookies on TermsFeed website article.

-

We use both Session and Persistent Cookies for the purposes set out below:

-
    -
  • -

    Necessary / Essential Cookies

    -

    Type: Session Cookies

    -

    Administered by: Us

    -

    Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.

    -
  • -
  • -

    Cookies Policy / Notice Acceptance Cookies

    -

    Type: Persistent Cookies

    -

    Administered by: Us

    -

    Purpose: These Cookies identify if users have accepted the use of cookies on the Website.

    -
  • -
  • -

    Functionality Cookies

    -

    Type: Persistent Cookies

    -

    Administered by: Us

    -

    Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.

    -
  • -
-

For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.

-

Use of Your Personal Data

-

The Company may use Personal Data for the following purposes:

-
    -
  • -

    To provide and maintain our Service, including to monitor the usage of our Service.

    -
  • -
  • -

    To manage Your Account: to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.

    -
  • -
  • -

    For the performance of a contract: the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.

    -
  • -
  • -

    To contact You: To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.

    -
  • -
  • -

    To provide You with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.

    -
  • -
  • -

    To manage Your requests: To attend and manage Your requests to Us.

    -
  • -
  • -

    For business transfers: We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.

    -
  • -
  • -

    For other purposes: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.

    -
  • -
-

We may share Your personal information in the following situations:

-
    -
  • With Service Providers: We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You.
  • -
  • For business transfers: We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.
  • -
  • With Affiliates: We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.
  • -
  • With business partners: We may share Your information with Our business partners to offer You certain products, services or promotions.
  • -
  • With other users: when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside.
  • -
  • With Your consent: We may disclose Your personal information for any other purpose with Your consent.
  • -
-

Retention of Your Personal Data

-

The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.

-

The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.

-

Transfer of Your Personal Data

-

Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.

-

Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.

-

The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.

-

Delete Your Personal Data

-

You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You.

-

Our Service may give You the ability to delete certain information about You from within the Service.

-

You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us.

-

Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so.

-

Disclosure of Your Personal Data

-

Business Transactions

-

If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.

-

Law enforcement

-

Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).

-

Other legal requirements

-

The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:

-
    -
  • Comply with a legal obligation
  • -
  • Protect and defend the rights or property of the Company
  • -
  • Prevent or investigate possible wrongdoing in connection with the Service
  • -
  • Protect the personal safety of Users of the Service or the public
  • -
  • Protect against legal liability
  • -
-

Security of Your Personal Data

-

The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.

-

Children's Privacy

-

Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.

-

If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.

-

Links to Other Websites

-

Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.

-

We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.

-

Changes to this Privacy Policy

-

We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.

-

We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the "Last updated" date at the top of this Privacy Policy.

-

You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.

-

Contact Us

-

If you have any questions about this Privacy Policy, You can contact us:

-
    -
  • -

    By email: info-flow(at)digitaldata.works

    -
  • -
  • -

    By phone number: +49(0)-641-202360

    -
  • -
  • -

    By mail: Ludwig Rinn Str. 16, D-35452 Heuchelheim

    -
  • -
\ No newline at end of file