Merge branch 'master' of http://git.dd:3000/AppStd/EnvelopeGenerator
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -362,3 +362,4 @@ MigrationBackup/
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
/EnvelopeGenerator.Web/.config/dotnet-tools.json
|
||||
/EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/.vscode
|
||||
|
||||
@@ -6,10 +6,13 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IConfigService : IBasicCRUDService<IConfigRepository, ConfigDto, Config, int>
|
||||
public interface IConfigService : IBasicCRUDService<ConfigDto, Config, int>
|
||||
{
|
||||
Task<DataResult<ConfigDto>> ReadFirstAsync();
|
||||
|
||||
async Task<DataResult<ConfigDto>> ReadDefaultAsync() => await ReadFirstAsync();
|
||||
}
|
||||
Task<ConfigDto> ReadDefaultAsync();
|
||||
|
||||
Task<string> ReadDefaultSignatureHost();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IDocumentReceiverElementService : IBasicCRUDService<IDocumentReceiverElementRepository, DocumentReceiverElementDto, DocumentReceiverElement, int>
|
||||
public interface IDocumentReceiverElementService : IBasicCRUDService<DocumentReceiverElementDto, DocumentReceiverElement, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IDocumentStatusService : IBasicCRUDService<IDocumentStatusRepository, DocumentStatusDto, DocumentStatus, int>
|
||||
public interface IDocumentStatusService : IBasicCRUDService<DocumentStatusDto, DocumentStatus, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEmailTemplateService : IBasicCRUDService<IEmailTemplateRepository, EmailTemplateDto, EmailTemplate, int>
|
||||
public interface IEmailTemplateService : IBasicCRUDService<EmailTemplateDto, EmailTemplate, int>
|
||||
{
|
||||
Task<DataResult<EmailTemplateDto>> ReadByNameAsync(EmailTemplateType type);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeCertificateService : IBasicCRUDService<IEnvelopeCertificateRepository, EnvelopeCertificateDto, EnvelopeCertificate, int>
|
||||
public interface IEnvelopeCertificateService : IBasicCRUDService<EnvelopeCertificateDto, EnvelopeCertificate, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeDocumentService : IBasicCRUDService<IEnvelopeDocumentRepository, EnvelopeDocumentDto, EnvelopeDocument, int>
|
||||
public interface IEnvelopeDocumentService : IBasicCRUDService<EnvelopeDocumentDto, EnvelopeDocument, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using DigitalData.Core.Contracts.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
@@ -7,7 +8,7 @@ using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeHistoryService : ICRUDService<IEnvelopeHistoryRepository, EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistoryDto, EnvelopeHistory, long>
|
||||
public interface IEnvelopeHistoryService : ICRUDService<EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistoryDto, EnvelopeHistory, long>
|
||||
{
|
||||
Task<int> CountAsync(int? envelopeId = null, string? userReference = null, int? status = null);
|
||||
|
||||
@@ -15,6 +16,14 @@ namespace EnvelopeGenerator.Application.Contracts
|
||||
|
||||
Task<bool> IsSigned(int envelopeId, string userReference);
|
||||
|
||||
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status);
|
||||
Task<bool> IsRejected(int envelopeId, string? userReference = null);
|
||||
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false);
|
||||
|
||||
Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null);
|
||||
|
||||
Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId);
|
||||
|
||||
Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null);
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,10 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeReceiverService : IBasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, int>
|
||||
public interface IEnvelopeReceiverService : IBasicCRUDService<EnvelopeReceiverDto, EnvelopeReceiver, object>
|
||||
{
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
|
||||
@@ -17,10 +16,14 @@ namespace EnvelopeGenerator.Application.Contracts
|
||||
|
||||
Task<DataResult<EnvelopeReceiverDto>> ReadByEnvelopeReceiverIdAsync(string envelopeReceiverId, bool withEnvelope = true, bool withReceiver = true);
|
||||
|
||||
Task<DataResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode);
|
||||
Task<DataResult<string>> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
|
||||
|
||||
Task<DataResult<bool>> VerifyAccessCodeAsync(string uuid, string signature, string accessCode);
|
||||
|
||||
Task<DataResult<bool>> VerifyAccessCodeAsync(string envelopeReceiverId, string accessCode);
|
||||
|
||||
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
|
||||
|
||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeService : IBasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>
|
||||
public interface IEnvelopeService : IBasicCRUDService<EnvelopeDto, Envelope, int>
|
||||
{
|
||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IEnvelopeTypeService : IBasicCRUDService<IEnvelopeTypeRepository, EnvelopeTypeDto, EnvelopeType, int>
|
||||
public interface IEnvelopeTypeService : IBasicCRUDService<EnvelopeTypeDto, EnvelopeType, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IReceiverService : IBasicCRUDService<IReceiverRepository, ReceiverDto, Receiver, int>
|
||||
public interface IReceiverService : IBasicCRUDService<ReceiverDto, Receiver, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Contracts
|
||||
{
|
||||
public interface IUserReceiverService : IBasicCRUDService<IUserReceiverRepository, UserReceiverDto, UserReceiver, int>
|
||||
public interface IUserReceiverService : IBasicCRUDService<UserReceiverDto, UserReceiver, int>
|
||||
{
|
||||
}
|
||||
}
|
||||
57
EnvelopeGenerator.Application/DIExtensions.cs
Normal file
57
EnvelopeGenerator.Application/DIExtensions.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using DigitalData.UserManager.Application.MappingProfiles;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.MappingProfiles;
|
||||
using EnvelopeGenerator.Application.Services;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using EnvelopeGenerator.Infrastructure.Repositories;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EnvelopeGenerator.Application
|
||||
{
|
||||
public static class DIExtensions
|
||||
{
|
||||
public static IServiceCollection AddEnvelopeGenerator(this IServiceCollection services)
|
||||
{
|
||||
//Inject CRUD Service and repositoriesad
|
||||
services.AddScoped<IConfigRepository, ConfigRepository>();
|
||||
services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
||||
services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
||||
services.AddScoped<IConfigRepository, ConfigRepository>();
|
||||
services.AddScoped<IDocumentReceiverElementRepository, DocumentReceiverElementRepository>();
|
||||
services.AddScoped<IDocumentStatusRepository, DocumentStatusRepository>();
|
||||
services.AddScoped<IEmailTemplateRepository, EmailTemplateRepository>();
|
||||
services.AddScoped<IEnvelopeRepository, EnvelopeRepository>();
|
||||
services.AddScoped<IEnvelopeCertificateRepository, EnvelopeCertificateRepository>();
|
||||
services.AddScoped<IEnvelopeDocumentRepository, EnvelopeDocumentRepository>();
|
||||
services.AddScoped<IEnvelopeHistoryRepository, EnvelopeHistoryRepository>();
|
||||
services.AddScoped<IEnvelopeReceiverRepository, EnvelopeReceiverRepository>();
|
||||
services.AddScoped<IEnvelopeTypeRepository, EnvelopeTypeRepository>();
|
||||
services.AddScoped<IReceiverRepository, ReceiverRepository>();
|
||||
services.AddScoped<IUserReceiverRepository, UserReceiverRepository>();
|
||||
services.AddScoped<IConfigService, ConfigService>();
|
||||
services.AddScoped<IDocumentReceiverElementService, DocumentReceiverElementService>();
|
||||
services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
|
||||
services.AddScoped<IEnvelopeHistoryService, EnvelopeHistoryService>();
|
||||
services.AddScoped<IDocumentStatusService, DocumentStatusService>();
|
||||
services.AddScoped<IEmailTemplateService, EmailTemplateService>();
|
||||
services.AddScoped<IEnvelopeService, EnvelopeService>();
|
||||
services.AddScoped<IEnvelopeCertificateService, EnvelopeCertificateService>();
|
||||
services.AddScoped<IEnvelopeDocumentService, EnvelopeDocumentService>();
|
||||
services.AddScoped<IEnvelopeReceiverService, EnvelopeReceiverService>();
|
||||
services.AddScoped<IEnvelopeTypeService, EnvelopeTypeService>();
|
||||
services.AddScoped<IReceiverService, ReceiverService>();
|
||||
services.AddScoped<IUserReceiverService, UserReceiverService>();
|
||||
|
||||
//Auto mapping profiles
|
||||
services.AddAutoMapper(typeof(BasicDtoMappingProfile).Assembly);
|
||||
services.AddAutoMapper(typeof(UserMappingProfile).Assembly);
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +1,66 @@
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using DigitalData.EmailProfilerDispatcher.Domain.Attributes;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeDto(
|
||||
int Id,
|
||||
int UserId,
|
||||
int Status,
|
||||
string Uuid,
|
||||
string Message,
|
||||
DateTime? ExpiresWhen,
|
||||
DateTime? ExpiresWarningWhen,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ChangedWhen,
|
||||
string Title,
|
||||
int? ContractType,
|
||||
string Language,
|
||||
bool? SendReminderEmails,
|
||||
int? FirstReminderDays,
|
||||
int? ReminderIntervalDays,
|
||||
int? EnvelopeTypeId,
|
||||
int? CertificationType,
|
||||
bool? UseAccessCode,
|
||||
int? FinalEmailToCreator,
|
||||
int? FinalEmailToReceivers,
|
||||
int? ExpiresWhenDays,
|
||||
int? ExpiresWarningWhenDays,
|
||||
bool DmzMoved,
|
||||
User? User,
|
||||
EnvelopeType? EnvelopeType,
|
||||
string? EnvelopeTypeTitle,
|
||||
bool IsAlreadySent,
|
||||
string? StatusTranslated,
|
||||
string? ContractTypeTranslated,
|
||||
IEnumerable<EnvelopeDocumentDto>? Documents,
|
||||
IEnumerable<EnvelopeHistoryDto>? History);
|
||||
public record EnvelopeDto()
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public string Uuid { get; set; }
|
||||
|
||||
[TemplatePlaceholder("[MESSAGE]")]
|
||||
public string Message { get; set; }
|
||||
public DateTime? ExpiresWhen { get; set; }
|
||||
public DateTime? ExpiresWarningWhen { get; set; }
|
||||
public DateTime AddedWhen { get; set; }
|
||||
public DateTime? ChangedWhen { get; set; }
|
||||
|
||||
[TemplatePlaceholder("[DOCUMENT_TITLE]")]
|
||||
public string Title { get; set; }
|
||||
|
||||
public int? ContractType { get; set; }
|
||||
|
||||
public string Language { get; set; }
|
||||
|
||||
public bool? SendReminderEmails { get; set; }
|
||||
|
||||
public int? FirstReminderDays { get; set; }
|
||||
|
||||
public int? ReminderIntervalDays { get; set; }
|
||||
|
||||
public int? EnvelopeTypeId { get; set; }
|
||||
|
||||
public int? CertificationType { get; set; }
|
||||
|
||||
public bool? UseAccessCode { get; set; }
|
||||
|
||||
public int? FinalEmailToCreator { get; set; }
|
||||
|
||||
public int? FinalEmailToReceivers { get; set; }
|
||||
|
||||
public int? ExpiresWhenDays { get; set; }
|
||||
|
||||
public int? ExpiresWarningWhenDays { get; set; }
|
||||
|
||||
public bool DmzMoved { get; set; }
|
||||
public UserReadDto? User { get; set; }
|
||||
public EnvelopeType? EnvelopeType { get; set; }
|
||||
|
||||
public string? EnvelopeTypeTitle { get; set; }
|
||||
|
||||
public bool IsAlreadySent { get; set; }
|
||||
|
||||
public string? StatusTranslated { get; set; }
|
||||
|
||||
public string? ContractTypeTranslated { get; set; }
|
||||
public IEnumerable<EnvelopeDocumentDto>? Documents { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -4,5 +4,6 @@
|
||||
int EnvelopeId,
|
||||
string UserReference,
|
||||
int Status,
|
||||
DateTime? ActionDate);
|
||||
DateTime? ActionDate,
|
||||
string? Comment = null);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
|
||||
{
|
||||
public record EnvelopeHistoryDto(
|
||||
long Id,
|
||||
@@ -6,5 +10,9 @@
|
||||
string UserReference,
|
||||
int Status,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ActionDate);
|
||||
DateTime? ActionDate,
|
||||
UserCreateDto? Sender,
|
||||
ReceiverDto? Receiver,
|
||||
ReferenceType ReferenceType,
|
||||
string? Comment = null) : BaseDTO<long>(Id);
|
||||
}
|
||||
@@ -1,15 +1,32 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
using DigitalData.EmailProfilerDispatcher.Domain.Attributes;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record EnvelopeReceiverDto(
|
||||
int EnvelopeId,
|
||||
int ReceiverId,
|
||||
int Sequence,
|
||||
string? Name,
|
||||
string? JobTitle,
|
||||
string? CompanyName,
|
||||
string? PrivateMessage,
|
||||
DateTime AddedWhen,
|
||||
DateTime? ChangedWhen,
|
||||
EnvelopeDto? Envelope,
|
||||
ReceiverDto? Receiver);
|
||||
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 ReceiverDto? Receiver { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
using DigitalData.Core.DTO;
|
||||
|
||||
namespace EnvelopeGenerator.Application.DTOs
|
||||
{
|
||||
public record ReceiverDto(
|
||||
int Id,
|
||||
string EmailAddress,
|
||||
string Signature,
|
||||
DateTime AddedWhen
|
||||
);
|
||||
) : BaseDTO<int>(Id);
|
||||
}
|
||||
13
EnvelopeGenerator.Application/DispatcherConfig.cs
Normal file
13
EnvelopeGenerator.Application/DispatcherConfig.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace EnvelopeGenerator.Application
|
||||
{
|
||||
public class DispatcherConfig
|
||||
{
|
||||
public int SendingProfile { get; init; } = 1;
|
||||
|
||||
public string AddedWho { get; init; } = "DDEnvelopGenerator";
|
||||
|
||||
public int ReminderTypeId { get; init; } = 202377;
|
||||
|
||||
public string EmailAttmt1 { get; init; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -102,9 +102,18 @@ namespace EnvelopeGenerator.Application
|
||||
/// <returns>The receiver signature.</returns>
|
||||
public static string? GetReceiverSignature(this string envelopeReceiverId) => envelopeReceiverId.DecodeEnvelopeReceiverId().ReceiverSignature;
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeEeceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
public static string EncodeEnvelopeReceiverId(this (string envelopeUuid, string receiverSignature) input)
|
||||
{
|
||||
string combinedString = $"{input.envelopeUuid}::{input.receiverSignature}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
return base64String;
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder().AppendLine(envelopeEeceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
|
||||
if (message is not null)
|
||||
sb.AppendLine(message);
|
||||
|
||||
@@ -117,15 +117,30 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>und</value>
|
||||
</data>
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Zurück</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
</data>
|
||||
<data name="Confirmation" xml:space="preserve">
|
||||
<value>Bestätigung</value>
|
||||
</data>
|
||||
<data name="de-DE" xml:space="preserve">
|
||||
<value>Deutch</value>
|
||||
</data>
|
||||
<data name="DocProtected" xml:space="preserve">
|
||||
<value>Dokument geschützt</value>
|
||||
</data>
|
||||
<data name="DocRejected" xml:space="preserve">
|
||||
<value>Dokument abgelehnt</value>
|
||||
</data>
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Dokument unterschrieben</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>Englisch</value>
|
||||
</data>
|
||||
@@ -135,6 +150,12 @@
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Erstellt am {0} von {1}. Sie können den Absender über <a href="mailto:{2}?subject={3}&body=Sehr%20geehrter%20{4}%20{5},%0A%0A%0A">{6}</a> kontaktieren.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Abschließen</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Hallo</value>
|
||||
</data>
|
||||
<data name="LocakedOpen" xml:space="preserve">
|
||||
<value>Öffnen</value>
|
||||
</data>
|
||||
@@ -153,6 +174,30 @@
|
||||
<data name="LockedTitle" xml:space="preserve">
|
||||
<value>Dokument erfordert einen Zugriffscode</value>
|
||||
</data>
|
||||
<data name="Reject" xml:space="preserve">
|
||||
<value>Ablehnen</value>
|
||||
</data>
|
||||
<data name="Rejection" xml:space="preserve">
|
||||
<value>Ablehnung</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1" xml:space="preserve">
|
||||
<value>Dieser Unterzeichnungsvorgang wurde abgelehnt!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1_ext" xml:space="preserve">
|
||||
<value>Vorgang abgebrochen!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2" xml:space="preserve">
|
||||
<value>Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen.</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2_ext" xml:space="preserve">
|
||||
<value>Das Vorgang wurde von einer der beteiligten Parteien abgelehnt. Sie können bei Bedarf mit {0}, <a href="mailto:{1}?subject={2}&body=Sehr geehrte(r)%20{0},%0A%0A%0A">{1}</a> Kontakt aufnehmen.</value>
|
||||
</data>
|
||||
<data name="RejectionReasonQ" xml:space="preserve">
|
||||
<value>Bitte geben Sie einen Grund an:</value>
|
||||
</data>
|
||||
<data name="SigAgree" xml:space="preserve">
|
||||
<value>Durch Klick auf Abschließen stimme ich zu, dass die abgebildete und übermittelte Signatur als elektronische Darstellung meiner Signatur in den Fällen gelten, in denen ich sie auf Dokumenten, einschließlich rechtsgültiger Verträge verwende.</value>
|
||||
</data>
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Dokument unterschreiben</value>
|
||||
</data>
|
||||
|
||||
@@ -117,15 +117,30 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="and" xml:space="preserve">
|
||||
<value>and</value>
|
||||
</data>
|
||||
<data name="Back" xml:space="preserve">
|
||||
<value>Back</value>
|
||||
</data>
|
||||
<data name="Complete" xml:space="preserve">
|
||||
<value>Complete</value>
|
||||
</data>
|
||||
<data name="Confirmation" xml:space="preserve">
|
||||
<value>Confirmation</value>
|
||||
</data>
|
||||
<data name="de-DE" xml:space="preserve">
|
||||
<value>German</value>
|
||||
</data>
|
||||
<data name="DocProtected" xml:space="preserve">
|
||||
<value>Document protected</value>
|
||||
</data>
|
||||
<data name="DocRejected" xml:space="preserve">
|
||||
<value>Document rejected</value>
|
||||
</data>
|
||||
<data name="DocSigned" xml:space="preserve">
|
||||
<value>Document signed</value>
|
||||
</data>
|
||||
<data name="en-US" xml:space="preserve">
|
||||
<value>English</value>
|
||||
</data>
|
||||
@@ -135,6 +150,12 @@
|
||||
<data name="EnvelopeInfo2" xml:space="preserve">
|
||||
<value>Created on {0} by {1}. You can contact the sender via <a href="mailto:{2}?subject={3}&body=Dear%20{4}%20{5},%0A%0A%0A">{6}</a>.</value>
|
||||
</data>
|
||||
<data name="Finalize" xml:space="preserve">
|
||||
<value>Finalize</value>
|
||||
</data>
|
||||
<data name="Hello" xml:space="preserve">
|
||||
<value>Hello</value>
|
||||
</data>
|
||||
<data name="LocakedOpen" xml:space="preserve">
|
||||
<value>Open</value>
|
||||
</data>
|
||||
@@ -153,6 +174,30 @@
|
||||
<data name="LockedTitle" xml:space="preserve">
|
||||
<value>Document requires an access code</value>
|
||||
</data>
|
||||
<data name="Reject" xml:space="preserve">
|
||||
<value>Reject</value>
|
||||
</data>
|
||||
<data name="Rejection" xml:space="preserve">
|
||||
<value>Rejection</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1" xml:space="preserve">
|
||||
<value>This signing process was rejected!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo1_ext" xml:space="preserve">
|
||||
<value>Process canceled!</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2" xml:space="preserve">
|
||||
<value>You can contact {0}, <a href="mailto:{1}?subject={2}&body=Dear%20{0},%0A%0A%0A">{1}</a> if required.</value>
|
||||
</data>
|
||||
<data name="RejectionInfo2_ext" xml:space="preserve">
|
||||
<value>The process has been rejected by one of the parties involved. You can contact {0}, <a href="mailto:{1}?subject={2}&body=Dear%20{0},%0A%0A%0A">{1}</a> if required.</value>
|
||||
</data>
|
||||
<data name="RejectionReasonQ" xml:space="preserve">
|
||||
<value>Please give a reason:</value>
|
||||
</data>
|
||||
<data name="SigAgree" xml:space="preserve">
|
||||
<value>By clicking on Finalize, I agree that the signature shown and submitted is an electronic representation of my signature in cases where I use it on documents, including legally binding contracts.</value>
|
||||
</data>
|
||||
<data name="SignDoc" xml:space="preserve">
|
||||
<value>Sign document</value>
|
||||
</data>
|
||||
|
||||
@@ -6,22 +6,57 @@ 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<IConfigRepository, ConfigDto, Config, int>, IConfigService
|
||||
{
|
||||
public ConfigService(IConfigRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, localizer, mapper)
|
||||
private static readonly Guid DefaultConfigCacheId = Guid.NewGuid();
|
||||
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ILogger<ConfigService> _logger;
|
||||
public ConfigService(IConfigRepository repository, IMapper mapper, IMemoryCache memoryCache, ILogger<ConfigService> logger) : base(repository, mapper)
|
||||
{
|
||||
_cache = memoryCache;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<DataResult<ConfigDto>> ReadFirstAsync()
|
||||
{
|
||||
var config = await _repository.ReadFirstAsync();
|
||||
return config is null ? Result.Fail<ConfigDto>().Message("There is no configuration in DB.") : Result.Success(_mapper.MapOrThrow<ConfigDto>(config));
|
||||
return config is null
|
||||
? Result.Fail<ConfigDto>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, "There is no configuration in DB.")
|
||||
: Result.Success(_mapper.MapOrThrow<ConfigDto>(config));
|
||||
}
|
||||
|
||||
public async Task<DataResult<ConfigDto>> ReadDefaultAsync() => await ReadFirstAsync();
|
||||
/// <summary>
|
||||
/// Reads the default configuration asynchronously.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The configuration is cached in memory upon the first retrieval. If the configuration is updated,
|
||||
/// the application needs to be restarted for the changes to take effect as the memory cache will not be updated automatically.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// A task that represents the asynchronous read operation. The task result contains the default configuration as a <see cref="ConfigDto"/>.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown when the default configuration cannot be found.
|
||||
/// </exception>
|
||||
public async Task<ConfigDto> ReadDefaultAsync()
|
||||
{
|
||||
var config = await _cache.GetOrCreateAsync(DefaultConfigCacheId, _ => ReadFirstAsync().ThenAsync(
|
||||
Success: config => config,
|
||||
Fail: (mssg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
throw new InvalidOperationException("Default configuration cannot find.");
|
||||
}));
|
||||
|
||||
return config!;
|
||||
}
|
||||
|
||||
public async Task<string> ReadDefaultSignatureHost() => (await ReadDefaultAsync()).SignatureHost;
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class DocumentReceiverElementService : BasicCRUDService<IDocumentReceiverElementRepository, DocumentReceiverElementDto, DocumentReceiverElement, int>, IDocumentReceiverElementService
|
||||
{
|
||||
public DocumentReceiverElementService(IDocumentReceiverElementRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
public DocumentReceiverElementService(IDocumentReceiverElementRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class DocumentStatusService : BasicCRUDService<IDocumentStatusRepository, DocumentStatusDto, DocumentStatus, int>, IDocumentStatusService
|
||||
{
|
||||
public DocumentStatusService(IDocumentStatusRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
public DocumentStatusService(IDocumentStatusRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EmailTemplateService : BasicCRUDService<IEmailTemplateRepository, EmailTemplateDto, EmailTemplate, int>, IEmailTemplateService
|
||||
{
|
||||
public EmailTemplateService(IEmailTemplateRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
public EmailTemplateService(IEmailTemplateRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeCertificateService : BasicCRUDService<IEnvelopeCertificateRepository, EnvelopeCertificateDto, EnvelopeCertificate, int>, IEnvelopeCertificateService
|
||||
{
|
||||
public EnvelopeCertificateService(IEnvelopeCertificateRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
public EnvelopeCertificateService(IEnvelopeCertificateRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeDocumentService : BasicCRUDService<IEnvelopeDocumentRepository, EnvelopeDocumentDto, EnvelopeDocument, int>, IEnvelopeDocumentService
|
||||
{
|
||||
public EnvelopeDocumentService(IEnvelopeDocumentRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper) : base(repository, localizer, mapper)
|
||||
public EnvelopeDocumentService(IEnvelopeDocumentRepository repository, IMapper mapper) : base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ using static EnvelopeGenerator.Common.Constants;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeHistoryService : CRUDService<IEnvelopeHistoryRepository, EnvelopeHistoryCreateDto, EnvelopeHistoryDto, EnvelopeHistoryDto, EnvelopeHistory, long>, IEnvelopeHistoryService
|
||||
{
|
||||
public EnvelopeHistoryService(IEnvelopeHistoryRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,8 +36,49 @@ namespace EnvelopeGenerator.Application.Services
|
||||
userReference: userReference,
|
||||
status: (int) EnvelopeStatus.DocumentSigned) > 0;
|
||||
|
||||
public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status) =>
|
||||
await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now))
|
||||
/// <summary>
|
||||
/// Checks if the specified envelope has been rejected.
|
||||
/// <para><b>Note:</b> <i>If any document within the envelope is rejected, the entire envelope will be considered rejected.</i></para>
|
||||
/// </summary>
|
||||
/// <param name="envelopeId">The ID of the envelope to check.</param>
|
||||
/// <param name="userReference">Optional user reference associated with the envelope.</param>
|
||||
/// <returns>A task that represents the asynchronous operation. The task result contains a boolean value indicating whether the envelope is rejected.</returns>
|
||||
public async Task<bool> IsRejected(int envelopeId, string? userReference = null)
|
||||
{
|
||||
return await _repository.CountAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: (int)EnvelopeStatus.DocumentRejected) > 0;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadAsync(int? envelopeId = null, string? userReference = null, ReferenceType? referenceType = null, int? status = null, bool withSender = false, bool withReceiver = false)
|
||||
{
|
||||
var histDTOs = _mapper.MapOrThrow<IEnumerable<EnvelopeHistoryDto>>(
|
||||
await _repository.ReadAsync(
|
||||
envelopeId: envelopeId,
|
||||
userReference: userReference,
|
||||
status: status,
|
||||
withSender: withSender,
|
||||
withReceiver: withReceiver));
|
||||
return referenceType is null ? histDTOs : histDTOs.Where(h => h.ReferenceType == referenceType);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<EnvelopeHistoryDto>> ReadRejectedAsync(int envelopeId, string? userReference = null) =>
|
||||
await ReadAsync(envelopeId: envelopeId, userReference: userReference, status: (int)EnvelopeStatus.DocumentRejected, withReceiver:true);
|
||||
|
||||
//TODO: use IQueryable in repository to incerease the performance
|
||||
public async Task<IEnumerable<ReceiverDto>> ReadRejectingReceivers(int envelopeId)
|
||||
{
|
||||
var envelopes = await ReadRejectedAsync(envelopeId);
|
||||
return envelopes is null
|
||||
? Enumerable.Empty<ReceiverDto>()
|
||||
: envelopes
|
||||
.Where(eh => eh?.Receiver != null)
|
||||
.Select(eh => eh.Receiver!);
|
||||
}
|
||||
|
||||
public async Task<DataResult<long>> RecordAsync(int envelopeId, string userReference, EnvelopeStatus status, string? comment = null) =>
|
||||
await CreateAsync(new (EnvelopeId: envelopeId, UserReference: userReference, Status: (int)status, ActionDate: DateTime.Now, Comment: comment))
|
||||
.ThenAsync(
|
||||
Success: id => Result.Success(id),
|
||||
Fail: (mssg, ntc) => Result.Fail<long>().Message(mssg).Notice(ntc)
|
||||
|
||||
@@ -7,30 +7,93 @@ using DigitalData.UserManager.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Common;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeMailService : EmailOutService<Resource>, IEnvelopeMailService
|
||||
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
|
||||
{
|
||||
private readonly IEmailTemplateService _tempService;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly IEmailTemplateService _tempService;
|
||||
private readonly IEnvelopeReceiverService _envRcvService;
|
||||
private readonly DispatcherConfig _dConfig;
|
||||
private readonly IConfigService _configService;
|
||||
|
||||
public EnvelopeMailService(IEmailOutRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, IEmailTemplateService tempService, IMemoryCache cache) : base(repository, localizer, mapper)
|
||||
public EnvelopeMailService(IEmailOutRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, IEmailTemplateService tempService, IEnvelopeReceiverService envelopeReceiverService, IOptions<DispatcherConfig> dispatcherConfigOptions, IConfigService configService) : base(repository, mapper)
|
||||
{
|
||||
_tempService = tempService;
|
||||
_cache = cache;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
_dConfig = dispatcherConfigOptions.Value;
|
||||
_configService = configService;
|
||||
}
|
||||
|
||||
public Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto envelopeReceiverDto)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
//TODO: create ioptions and implement TemplatePlaceHolderAttribute instead of this method
|
||||
private async Task<Dictionary<string, string>> CreatePlaceholders(string? accessCode = null, EnvelopeReceiverDto? envelopeReceiverDto = null)
|
||||
{
|
||||
Dictionary<string, string> placeholders = new() {
|
||||
{ "[NAME_PORTAL]", "signFlow" },
|
||||
{ "[SIGNATURE_TYPE]" , "signieren"},
|
||||
{ "[REASON]", string.Empty } };
|
||||
|
||||
public Task<DataResult<int>> SendAsync(EnvelopeReceiverDto envelopeReceiverDto, Constants.EmailTemplateType tempType)
|
||||
if (accessCode is not null)
|
||||
placeholders["[DOCUMENT_ACCESS_CODE]"] = accessCode;
|
||||
|
||||
if(envelopeReceiverDto is not null && envelopeReceiverDto.Envelope is not null && envelopeReceiverDto.Receiver is not null)
|
||||
{
|
||||
var erId = (envelopeReceiverDto.Envelope.Uuid, envelopeReceiverDto.Receiver.Signature).EncodeEnvelopeReceiverId();
|
||||
var sigHost = await _configService.ReadDefaultSignatureHost();
|
||||
var linkToDoc = $"{sigHost}/envelope/{erId}";
|
||||
placeholders["[LINK_TO_DOCUMENT]"] = linkToDoc;
|
||||
placeholders["[LINK_TO_DOCUMENT_TEXT]"] = linkToDoc[..Math.Min(40, linkToDoc.Length)];
|
||||
}
|
||||
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
public async Task<DataResult<int>> SendAccessCodeAsync(EnvelopeReceiverDto dto) => await SendAsync(dto: dto, tempType: Constants.EmailTemplateType.DocumentAccessCodeReceived);
|
||||
|
||||
public async Task<DataResult<int>> SendAsync(EnvelopeReceiverDto dto, Constants.EmailTemplateType tempType)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
var tempSerResult = await _tempService.ReadByNameAsync(tempType);
|
||||
if (tempSerResult.IsFailed)
|
||||
return tempSerResult.ToFail<int>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"The email cannot send because '{tempType}' template cannot found.");
|
||||
var temp = tempSerResult.Data;
|
||||
|
||||
var mail = new EmailOutCreateDto()
|
||||
{
|
||||
EmailAddress = dto.Receiver!.EmailAddress,
|
||||
EmailSubj = temp.Subject,
|
||||
EmailBody = temp.Body,
|
||||
//email_type = envelope_status,
|
||||
//message = envelope_message,
|
||||
ReferenceId = dto.EnvelopeId, //REFERENCE_ID = ENVELOPE_ID
|
||||
ReferenceString = dto!.Envelope!.Uuid, //REFERENCE_STRING = ENVELOPE_UUID
|
||||
//receiver_name = receiver.name,
|
||||
//receiver_access_code = receiver.access_code,
|
||||
//sender_adress = envelope.user.email,
|
||||
//sender_name = envelope.user.full_name,
|
||||
//envelope_title = envelope.title,
|
||||
ReminderTypeId = _dConfig.ReminderTypeId,
|
||||
SendingProfile = _dConfig.SendingProfile,
|
||||
EntityId = null,
|
||||
WfId = (int) EnvelopeStatus.MessageAccessCodeSent,
|
||||
WfReference = null,
|
||||
AddedWho = _dConfig.AddedWho,
|
||||
EmailAttmt1 = _dConfig.EmailAttmt1
|
||||
};
|
||||
|
||||
//get acccess code
|
||||
var acResult = await _envRcvService.ReadAccessCodeByIdAsync(envelopeId: dto.EnvelopeId, receiverId: dto.ReceiverId);
|
||||
if (acResult.IsFailed)
|
||||
return acResult.ToFail<int>().Notice(LogLevel.Error, "Therefore, access code cannot be sent");
|
||||
var accessCode = acResult.Data;
|
||||
|
||||
var placeholders = await CreatePlaceholders(accessCode: accessCode, envelopeReceiverDto: dto);
|
||||
|
||||
return await CreateWithTemplateAsync(createDto: mail,placeholders: placeholders,
|
||||
dto, dto.Envelope.User!, dto.Envelope);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,14 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeReceiverService : BasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, int>, IEnvelopeReceiverService
|
||||
public class EnvelopeReceiverService : BasicCRUDService<IEnvelopeReceiverRepository, EnvelopeReceiverDto, EnvelopeReceiver, object>, IEnvelopeReceiverService
|
||||
{
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
public EnvelopeReceiverService(IEnvelopeReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true)
|
||||
@@ -103,6 +106,21 @@ namespace EnvelopeGenerator.Application.Services
|
||||
|
||||
int count = await _repository.CountAsync(uuid:uuid, signature:signature);
|
||||
return Result.Success(count > 0);
|
||||
}
|
||||
|
||||
public async Task<DataResult<string>> ReadAccessCodeByIdAsync(int envelopeId, int receiverId)
|
||||
{
|
||||
var code = await _repository.ReadAccessCodeByIdAsync(envelopeId: envelopeId, receiverId: receiverId);
|
||||
return code is null ?
|
||||
Result.Fail<string>().Notice(LogLevel.Error, Flag.DataIntegrityIssue, $"Access code is null. Envelope ID is {envelopeId} and receiver ID {receiverId}")
|
||||
: Result.Success(code);
|
||||
}
|
||||
|
||||
public async Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username)
|
||||
{
|
||||
var er_list = await _repository.ReadByUsernameAsync(username: username);
|
||||
var dto_list = _mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(er_list);
|
||||
return Result.Success(dto_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
public class EnvelopeService : BasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>, IEnvelopeService
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
public EnvelopeService(IEnvelopeRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper, ILogger<EnvelopeService> logger)
|
||||
: base(repository, localizer, mapper)
|
||||
public EnvelopeService(IEnvelopeRepository repository, IMapper mapper, ILogger<EnvelopeService> logger)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class EnvelopeTypeService : BasicCRUDService<IEnvelopeTypeRepository, EnvelopeTypeDto, EnvelopeType, int>, IEnvelopeTypeService
|
||||
{
|
||||
public EnvelopeTypeService(IEnvelopeTypeRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,14 @@ using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
public class ReceiverService : BasicCRUDService<IReceiverRepository, ReceiverDto, Receiver, int>, IReceiverService
|
||||
{
|
||||
public ReceiverService(IReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace EnvelopeGenerator.Application.Services
|
||||
public class UserReceiverService : BasicCRUDService<IUserReceiverRepository, UserReceiverDto, UserReceiver, int>, IUserReceiverService
|
||||
{
|
||||
public UserReceiverService(IUserReceiverRepository repository, IStringLocalizer<Resource> localizer, IMapper mapper)
|
||||
: base(repository, localizer, mapper)
|
||||
: base(repository, mapper)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
DocumentOpened = 2004
|
||||
DocumentSigned = 2005
|
||||
SignatureConfirmed = 2006
|
||||
DocumentRejected = 2007
|
||||
MessageInvitationSent = 3001 ' Wird von Trigger verwendet
|
||||
MessageAccessCodeSent = 3002
|
||||
MessageConfirmationSent = 3003
|
||||
@@ -25,6 +26,13 @@
|
||||
MessageCompletionSent = 3005
|
||||
End Enum
|
||||
|
||||
Public Enum ReferenceType
|
||||
Receiver
|
||||
Sender
|
||||
System
|
||||
Unknown
|
||||
End Enum
|
||||
|
||||
Public Enum ElementStatus
|
||||
Created = 0
|
||||
End Enum
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using DigitalData.UserManager.Domain.Entities;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
|
||||
namespace EnvelopeGenerator.Domain.Entities
|
||||
{
|
||||
@@ -30,5 +32,22 @@ namespace EnvelopeGenerator.Domain.Entities
|
||||
|
||||
[Column("ACTION_DATE", TypeName = "datetime")]
|
||||
public DateTime? ActionDate { get; set; }
|
||||
|
||||
[Column("COMMENT", TypeName = "nvarchar(max)")]
|
||||
public string? Comment { get; set; }
|
||||
|
||||
[ForeignKey("UserReference")]
|
||||
public virtual User? Sender { get; set; }
|
||||
|
||||
[ForeignKey("UserReference")]
|
||||
public virtual Receiver? Receiver { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public ReferenceType ReferenceType => (Status / 3) switch
|
||||
{
|
||||
1 => ReferenceType.Sender,
|
||||
2 or 3 => ReferenceType.Receiver,
|
||||
_ => ReferenceType.Unknown,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
42
EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/.gitignore
vendored
Normal file
42
EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||
|
||||
# Compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
/bazel-out
|
||||
|
||||
# Node
|
||||
/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# IDEs and editors
|
||||
.idea/
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
|
||||
# Visual Studio Code
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
|
||||
# Miscellaneous
|
||||
/.angular/cache
|
||||
.sass-cache/
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# System files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,27 @@
|
||||
# EnvelopeGeneratorUi
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 17.3.8.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
||||
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"envelope-generator-ui": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:application",
|
||||
"options": {
|
||||
"outputPath": "dist/envelope-generator-ui",
|
||||
"index": "src/index.html",
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": [
|
||||
"zone.js"
|
||||
],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": [],
|
||||
"server": "src/main.server.ts",
|
||||
"prerender": true,
|
||||
"ssr": {
|
||||
"entry": "server.ts"
|
||||
}
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "500kb",
|
||||
"maximumError": "1mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "2kb",
|
||||
"maximumError": "4kb"
|
||||
}
|
||||
],
|
||||
"outputHashing": "all"
|
||||
},
|
||||
"development": {
|
||||
"optimization": false,
|
||||
"extractLicenses": false,
|
||||
"sourceMap": true
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "production"
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "envelope-generator-ui:build:production"
|
||||
},
|
||||
"development": {
|
||||
"buildTarget": "envelope-generator-ui:build:development"
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"options": {
|
||||
"proxyConfig": "src/proxy.conf.json"
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"buildTarget": "envelope-generator-ui:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"polyfills": [
|
||||
"zone.js",
|
||||
"zone.js/testing"
|
||||
],
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.scss",
|
||||
"node_modules/bootstrap/dist/css/bootstrap.min.css",
|
||||
"src/styles.css"
|
||||
],
|
||||
"scripts": [
|
||||
"node_modules/jquery/dist/jquery.min.js",
|
||||
"node_modules/popper.js/dist/umd/popper.min.js",
|
||||
"node_modules/bootstrap/dist/js/bootstrap.min.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13451
EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/package-lock.json
generated
Normal file
13451
EnvelopeGenerator.GeneratorAPI/ClientApp/envelope-generator-ui/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "envelope-generator-ui",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"watch": "ng build --watch --configuration development",
|
||||
"test": "ng test",
|
||||
"serve:ssr:envelope-generator-ui": "node dist/envelope-generator-ui/server/server.mjs"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^17.3.0",
|
||||
"@angular/cdk": "^17.3.10",
|
||||
"@angular/common": "^17.3.0",
|
||||
"@angular/compiler": "^17.3.0",
|
||||
"@angular/core": "^17.3.0",
|
||||
"@angular/forms": "^17.3.0",
|
||||
"@angular/material": "^17.3.10",
|
||||
"@angular/platform-browser": "^17.3.0",
|
||||
"@angular/platform-browser-dynamic": "^17.3.0",
|
||||
"@angular/platform-server": "^17.3.0",
|
||||
"@angular/router": "^17.3.0",
|
||||
"@angular/ssr": "^17.3.8",
|
||||
"@generic-ui/fabric": "^0.21.0",
|
||||
"@generic-ui/hermes": "^0.21.0",
|
||||
"@generic-ui/ngx-grid": "^0.21.0",
|
||||
"@ng-bootstrap/ng-bootstrap": "^16.0.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"express": "^4.18.2",
|
||||
"rxjs": "~7.8.0",
|
||||
"tslib": "^2.3.0",
|
||||
"zone.js": "~0.14.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "^17.3.8",
|
||||
"@angular/cli": "^17.3.8",
|
||||
"@angular/compiler-cli": "^17.3.0",
|
||||
"@angular/localize": "^17.3.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jasmine": "~5.1.0",
|
||||
"@types/node": "^18.18.0",
|
||||
"jasmine-core": "~5.1.0",
|
||||
"karma": "~6.4.0",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"karma-jasmine": "~5.1.0",
|
||||
"karma-jasmine-html-reporter": "~2.1.0",
|
||||
"typescript": "~5.4.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import express from 'express';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import bootstrap from './src/main.server';
|
||||
|
||||
// The Express app is exported so that it can be used by serverless Functions.
|
||||
export function app(): express.Express {
|
||||
const server = express();
|
||||
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
|
||||
const browserDistFolder = resolve(serverDistFolder, '../browser');
|
||||
const indexHtml = join(serverDistFolder, 'index.server.html');
|
||||
|
||||
const commonEngine = new CommonEngine();
|
||||
|
||||
server.set('view engine', 'html');
|
||||
server.set('views', browserDistFolder);
|
||||
|
||||
// Example Express Rest API endpoints
|
||||
// server.get('/api/**', (req, res) => { });
|
||||
// Serve static files from /browser
|
||||
server.get('*.*', express.static(browserDistFolder, {
|
||||
maxAge: '1y'
|
||||
}));
|
||||
|
||||
// All regular routes use the Angular engine
|
||||
server.get('*', (req, res, next) => {
|
||||
const { protocol, originalUrl, baseUrl, headers } = req;
|
||||
|
||||
commonEngine
|
||||
.render({
|
||||
bootstrap,
|
||||
documentFilePath: indexHtml,
|
||||
url: `${protocol}://${headers.host}${originalUrl}`,
|
||||
publicPath: browserDistFolder,
|
||||
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
|
||||
})
|
||||
.then((html) => res.send(html))
|
||||
.catch((err) => next(err));
|
||||
});
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
function run(): void {
|
||||
const port = process.env['PORT'] || 4000;
|
||||
|
||||
// Start up the Node server
|
||||
const server = app();
|
||||
server.listen(port, () => {
|
||||
console.log(`Node Express server listening on http://localhost:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
run();
|
||||
@@ -0,0 +1,4 @@
|
||||
<app-navbar></app-navbar>
|
||||
<main>
|
||||
<router-outlet />
|
||||
</main>
|
||||
@@ -0,0 +1,11 @@
|
||||
main {
|
||||
width: 100%;
|
||||
min-height: calc(100% - 4rem);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
router-outlet{
|
||||
display: none;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [AppComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have the 'envelope-generator-ui' title`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('envelope-generator-ui');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement as HTMLElement;
|
||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, envelope-generator-ui');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { NavbarComponent } from "./components/navbar/navbar.component";
|
||||
import { LoginComponent } from "./components/login/login.component";
|
||||
import { HomeComponent } from "./components/home/home.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
standalone: true,
|
||||
templateUrl: './app.component.html',
|
||||
styleUrl: './app.component.scss',
|
||||
imports: [RouterOutlet, NavbarComponent, LoginComponent, HomeComponent]
|
||||
})
|
||||
export class AppComponent {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
|
||||
import { provideServerRendering } from '@angular/platform-server';
|
||||
import { appConfig } from './app.config';
|
||||
|
||||
const serverConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideServerRendering()
|
||||
]
|
||||
};
|
||||
|
||||
export const config = mergeApplicationConfig(appConfig, serverConfig);
|
||||
@@ -0,0 +1,28 @@
|
||||
import { ApplicationConfig } from '@angular/core';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { routes } from './app.routes';
|
||||
import { provideClientHydration } from '@angular/platform-browser';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { APP_BASE_HREF } from '@angular/common';
|
||||
import { UrlService } from './services/url.service';
|
||||
import { API_URL } from './tokens/index'
|
||||
import { provideHttpClient, withFetch } from '@angular/common/http';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideRouter(routes),
|
||||
provideClientHydration(),
|
||||
provideAnimationsAsync(),
|
||||
provideHttpClient(withFetch()),
|
||||
{
|
||||
provide: APP_BASE_HREF,
|
||||
useFactory: (urlService: UrlService) => urlService.getBaseHref(),
|
||||
deps: [UrlService]
|
||||
},
|
||||
{
|
||||
provide: API_URL,
|
||||
useFactory: (urlService: UrlService) => urlService.getApiUrl(),
|
||||
deps: [UrlService]
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import {EnvelopeTableComponent} from '../app/components/envelope-table/envelope-table.component'
|
||||
import {HomeComponent} from '../app/components/home/home.component'
|
||||
export const routes: Routes = [
|
||||
{ path: '', component: HomeComponent },
|
||||
{ path: 'login', component: HomeComponent },
|
||||
{ path: 'envelope', component: EnvelopeTableComponent }
|
||||
];
|
||||
@@ -0,0 +1 @@
|
||||
<p>envelope-table works!</p>
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EnvelopeTableComponent } from './envelope-table.component';
|
||||
|
||||
describe('EnvelopeTableComponent', () => {
|
||||
let component: EnvelopeTableComponent;
|
||||
let fixture: ComponentFixture<EnvelopeTableComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [EnvelopeTableComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(EnvelopeTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { EnvelopeReceiverService } from '../../services/envelope-receiver.service';
|
||||
import { error } from 'console';
|
||||
|
||||
@Component({
|
||||
selector: 'app-envelope-table',
|
||||
standalone: true,
|
||||
imports: [],
|
||||
templateUrl: './envelope-table.component.html',
|
||||
styleUrl: './envelope-table.component.scss'
|
||||
})
|
||||
export class EnvelopeTableComponent {
|
||||
|
||||
constructor(private erService : EnvelopeReceiverService){
|
||||
erService.getEnvelopeReceiver().subscribe({
|
||||
next: (res) => {
|
||||
console.log(res)
|
||||
},
|
||||
error: (error) => {
|
||||
console.log(error)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<div class="main">
|
||||
<div class="content">
|
||||
<div class="left-side">
|
||||
<app-login></app-login>
|
||||
</div>
|
||||
<div class="divider" role="separator" aria-label="Divider"></div>
|
||||
<div class="right-side">
|
||||
<div class="pill-group">
|
||||
@for (item of [
|
||||
{ title: 'Explore Digital Data', link: 'https://digitaldata.works/' },
|
||||
{ title: 'Learn signFlow', link: '/' },
|
||||
{ title: 'API Docs', link: '/' },
|
||||
]; track item.title) {
|
||||
<a class="pill" [href]="item.link" target="_blank" rel="noopener">
|
||||
<span>{{ item.title }}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="14" viewBox="0 -960 960 960" width="14"
|
||||
fill="currentColor">
|
||||
<path
|
||||
d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" />
|
||||
</svg>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
<div class="social-links">
|
||||
<a href="/" aria-label="Github" target="_blank" rel="noopener">
|
||||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Github">
|
||||
<path
|
||||
d="M12.3047 0C5.50634 0 0 5.50942 0 12.3047C0 17.7423 3.52529 22.3535 8.41332 23.9787C9.02856 24.0946 9.25414 23.7142 9.25414 23.3871C9.25414 23.0949 9.24389 22.3207 9.23876 21.2953C5.81601 22.0377 5.09414 19.6444 5.09414 19.6444C4.53427 18.2243 3.72524 17.8449 3.72524 17.8449C2.61064 17.082 3.81137 17.0973 3.81137 17.0973C5.04697 17.1835 5.69604 18.3647 5.69604 18.3647C6.79321 20.2463 8.57636 19.7029 9.27978 19.3881C9.39052 18.5924 9.70736 18.0499 10.0591 17.7423C7.32641 17.4347 4.45429 16.3765 4.45429 11.6618C4.45429 10.3185 4.9311 9.22133 5.72065 8.36C5.58222 8.04931 5.16694 6.79833 5.82831 5.10337C5.82831 5.10337 6.85883 4.77319 9.2121 6.36459C10.1965 6.09082 11.2424 5.95546 12.2883 5.94931C13.3342 5.95546 14.3801 6.09082 15.3644 6.36459C17.7023 4.77319 18.7328 5.10337 18.7328 5.10337C19.3942 6.79833 18.9789 8.04931 18.8559 8.36C19.6403 9.22133 20.1171 10.3185 20.1171 11.6618C20.1171 16.3888 17.2409 17.4296 14.5031 17.7321C14.9338 18.1012 15.3337 18.8559 15.3337 20.0084C15.3337 21.6552 15.3183 22.978 15.3183 23.3779C15.3183 23.7009 15.5336 24.0854 16.1642 23.9623C21.0871 22.3484 24.6094 17.7341 24.6094 12.3047C24.6094 5.50942 19.0999 0 12.3047 0Z" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href="/" aria-label="Twitter" target="_blank" rel="noopener">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Twitter">
|
||||
<path
|
||||
d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
|
||||
</svg>
|
||||
</a>
|
||||
<a href="/" aria-label="Youtube" target="_blank" rel="noopener">
|
||||
<svg width="29" height="20" viewBox="0 0 29 20" fill="none" xmlns="http://www.w3.org/2000/svg"
|
||||
alt="Youtube">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd"
|
||||
d="M27.4896 1.52422C27.9301 1.96749 28.2463 2.51866 28.4068 3.12258C29.0004 5.35161 29.0004 10 29.0004 10C29.0004 10 29.0004 14.6484 28.4068 16.8774C28.2463 17.4813 27.9301 18.0325 27.4896 18.4758C27.0492 18.9191 26.5 19.2389 25.8972 19.4032C23.6778 20 14.8068 20 14.8068 20C14.8068 20 5.93586 20 3.71651 19.4032C3.11363 19.2389 2.56449 18.9191 2.12405 18.4758C1.68361 18.0325 1.36732 17.4813 1.20683 16.8774C0.613281 14.6484 0.613281 10 0.613281 10C0.613281 10 0.613281 5.35161 1.20683 3.12258C1.36732 2.51866 1.68361 1.96749 2.12405 1.52422C2.56449 1.08095 3.11363 0.76113 3.71651 0.596774C5.93586 0 14.8068 0 14.8068 0C14.8068 0 23.6778 0 25.8972 0.596774C26.5 0.76113 27.0492 1.08095 27.4896 1.52422ZM19.3229 10L11.9036 5.77905V14.221L19.3229 10Z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,173 @@
|
||||
:host {
|
||||
--bright-blue: oklch(51.01% 0.274 263.83);
|
||||
--electric-violet: oklch(53.18% 0.28 296.97);
|
||||
--french-violet: oklch(47.66% 0.246 305.88);
|
||||
--vivid-pink: oklch(69.02% 0.277 332.77);
|
||||
--hot-red: oklch(61.42% 0.238 15.34);
|
||||
--orange-red: oklch(63.32% 0.24 31.68);
|
||||
|
||||
--gray-900: oklch(19.37% 0.006 300.98);
|
||||
--gray-700: oklch(36.98% 0.014 302.71);
|
||||
--gray-400: oklch(70.9% 0.015 304.04);
|
||||
|
||||
--red-to-pink-to-purple-vertical-gradient: linear-gradient(180deg,
|
||||
var(--orange-red) 0%,
|
||||
var(--vivid-pink) 50%,
|
||||
var(--electric-violet) 100%);
|
||||
|
||||
--red-to-pink-to-purple-horizontal-gradient: linear-gradient(90deg,
|
||||
var(--orange-red) 0%,
|
||||
var(--vivid-pink) 50%,
|
||||
var(--electric-violet) 100%);
|
||||
|
||||
--pill-accent: var(--bright-blue);
|
||||
|
||||
font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol";
|
||||
box-sizing: border-box;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.125rem;
|
||||
color: var(--gray-900);
|
||||
font-weight: 500;
|
||||
line-height: 100%;
|
||||
letter-spacing: -0.125rem;
|
||||
margin: 0;
|
||||
font-family: "Inter Tight", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
|
||||
"Segoe UI Symbol";
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
color: var(--gray-700);
|
||||
}
|
||||
|
||||
.main {
|
||||
width: 100%;
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
box-sizing: inherit;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.angular-logo {
|
||||
max-width: 9.2rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
width: 100%;
|
||||
max-width: 700px;
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
margin-top: 1.75rem;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 1px;
|
||||
background: var(--red-to-pink-to-purple-vertical-gradient);
|
||||
margin-inline: 0.5rem;
|
||||
}
|
||||
|
||||
.pill-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
flex-wrap: wrap;
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.pill {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
--pill-accent: var(--bright-blue);
|
||||
background: color-mix(in srgb, var(--pill-accent) 5%, transparent);
|
||||
color: var(--pill-accent);
|
||||
padding-inline: 0.75rem;
|
||||
padding-block: 0.375rem;
|
||||
border-radius: 2.75rem;
|
||||
border: 0;
|
||||
transition: background 0.3s ease;
|
||||
font-family: var(--inter-font);
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
line-height: 1.4rem;
|
||||
letter-spacing: -0.00875rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pill:hover {
|
||||
background: color-mix(in srgb, var(--pill-accent) 15%, transparent);
|
||||
}
|
||||
|
||||
.pill-group .pill:nth-child(6n + 1) {
|
||||
--pill-accent: var(--bright-blue);
|
||||
}
|
||||
|
||||
.pill-group .pill:nth-child(6n + 2) {
|
||||
--pill-accent: var(--french-violet);
|
||||
}
|
||||
|
||||
.pill-group .pill:nth-child(6n + 3),
|
||||
.pill-group .pill:nth-child(6n + 4),
|
||||
.pill-group .pill:nth-child(6n + 5) {
|
||||
--pill-accent: var(--hot-red);
|
||||
}
|
||||
|
||||
.pill-group svg {
|
||||
margin-inline-start: 0.25rem;
|
||||
}
|
||||
|
||||
.social-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.73rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.social-links path {
|
||||
transition: fill 0.3s ease;
|
||||
fill: var(--gray-400);
|
||||
}
|
||||
|
||||
.social-links a:hover svg path {
|
||||
fill: var(--gray-900);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 650px) {
|
||||
.content {
|
||||
flex-direction: column;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.divider {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
background: var(--red-to-pink-to-purple-horizontal-gradient);
|
||||
margin-block: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sidenav-container {
|
||||
height: calc(100% - 64px); /* Toolbar yüksekliği */
|
||||
}
|
||||
|
||||
.sidenav {
|
||||
margin-top: 64px; /* Toolbar yüksekliği */
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
let fixture: ComponentFixture<HomeComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [HomeComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(HomeComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { LoginComponent } from "../login/login.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
standalone: true,
|
||||
templateUrl: './home.component.html',
|
||||
styleUrl: './home.component.scss',
|
||||
imports: [LoginComponent]
|
||||
})
|
||||
export class HomeComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<!-- src/app/components/login/login.component.html -->
|
||||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
|
||||
<div class="mb-3">
|
||||
<mat-form-field>
|
||||
<mat-label>Username</mat-label>
|
||||
<input matInput formControlName="username">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<mat-form-field>
|
||||
<mat-label>Enter your password</mat-label>
|
||||
<input matInput [type]="hide ? 'password' : 'text'" formControlName="password">
|
||||
<button type="button" mat-icon-button matSuffix (click)="togglePWVisibility($event)" [attr.aria-label]="'Hide password'"
|
||||
[attr.aria-pressed]="hide">
|
||||
<mat-icon>{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button mat-flat-button color="primary" type="submit">Log In</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
mat-form-field{
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { LoginComponent } from './login.component';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
let component: LoginComponent;
|
||||
let fixture: ComponentFixture<LoginComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [LoginComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(LoginComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { AuthService } from '../../services/auth.service'
|
||||
import { Router } from '@angular/router';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-login',
|
||||
standalone: true,
|
||||
imports: [MatFormFieldModule, MatInputModule, MatButtonModule, MatIconModule, ReactiveFormsModule],
|
||||
templateUrl: './login.component.html',
|
||||
styleUrl: './login.component.scss'
|
||||
})
|
||||
export class LoginComponent {
|
||||
hide = true;
|
||||
loginForm: FormGroup;
|
||||
|
||||
constructor(private fb: FormBuilder, private authService: AuthService, private router: Router) {
|
||||
this.loginForm = this.fb.group({
|
||||
username: ['', Validators.required],
|
||||
password: ['', Validators.required]
|
||||
});
|
||||
}
|
||||
|
||||
togglePWVisibility(event: MouseEvent) {
|
||||
this.hide = !this.hide;
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
if (this.loginForm.valid) {
|
||||
this.authService.login(this.loginForm.value).subscribe({
|
||||
next: () => {
|
||||
this.router.navigate(['/envelope']);
|
||||
},
|
||||
error: error => {
|
||||
console.error('Login failed', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<mat-toolbar color="primary" class="toolbar">
|
||||
<button mat-icon-button>
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
<span>signFlow</span>
|
||||
</mat-toolbar>
|
||||
@@ -0,0 +1,3 @@
|
||||
mat-toolbar{
|
||||
height: 4rem
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { NavbarComponent } from './navbar.component';
|
||||
|
||||
describe('NavbarComponent', () => {
|
||||
let component: NavbarComponent;
|
||||
let fixture: ComponentFixture<NavbarComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [NavbarComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(NavbarComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatListModule } from '@angular/material/list';
|
||||
|
||||
@Component({
|
||||
selector: 'app-navbar',
|
||||
standalone: true,
|
||||
imports: [
|
||||
MatToolbarModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatSidenavModule,
|
||||
MatListModule
|
||||
],
|
||||
templateUrl: './navbar.component.html',
|
||||
styleUrl: './navbar.component.scss'
|
||||
})
|
||||
export class NavbarComponent {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { CanActivateFn } from '@angular/router';
|
||||
|
||||
import { authGuard } from './auth.guard';
|
||||
|
||||
describe('authGuard', () => {
|
||||
const executeGuard: CanActivateFn = (...guardParameters) =>
|
||||
TestBed.runInInjectionContext(() => authGuard(...guardParameters));
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(executeGuard).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
// src/app/guards/auth.guard.ts
|
||||
import { inject } from '@angular/core';
|
||||
import { CanActivateFn, Router } from '@angular/router';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
export const authGuard: CanActivateFn = (route, state) => {
|
||||
const authService = inject(AuthService);
|
||||
const router = inject(Router);
|
||||
return authService.isAuthenticated().pipe(
|
||||
map(isAuthenticated => {
|
||||
if (!isAuthenticated) {
|
||||
router.navigate(['/']);
|
||||
}
|
||||
return isAuthenticated;
|
||||
})
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(AuthService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { API_URL } from '../tokens/index';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
private url: string;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
const api_url = inject(API_URL);
|
||||
this.url = `${api_url}/auth`;
|
||||
}
|
||||
|
||||
login(credentials: { username: string; password: string }): Observable<any> {
|
||||
return this.http.post(`${this.url}/login`, credentials);
|
||||
}
|
||||
|
||||
logout(): Observable<any> {
|
||||
return this.http.post(`${this.url}/logout`, {});
|
||||
}
|
||||
|
||||
isAuthenticated(): Observable<boolean> {
|
||||
return this.http.get<boolean>(`${this.url}/check`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { EnvelopeReceiverService } from './envelope-receiver.service';
|
||||
|
||||
describe('EnvelopeReceiverService', () => {
|
||||
let service: EnvelopeReceiverService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(EnvelopeReceiverService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable, catchError } from 'rxjs';
|
||||
import { API_URL } from '../tokens/index';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class EnvelopeReceiverService {
|
||||
private url: string;
|
||||
|
||||
constructor(private http: HttpClient) {
|
||||
const api_url = inject(API_URL);
|
||||
this.url = `${api_url}/envelopereceiver`;
|
||||
}
|
||||
|
||||
getEnvelopeReceiver(): Observable<any> {
|
||||
const headers = new HttpHeaders({
|
||||
'Content-Type': 'application/json',
|
||||
});
|
||||
|
||||
return this.http.get<any>(this.url, { withCredentials: true , headers });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { UrlService } from './url.service';
|
||||
|
||||
describe('UrlService', () => {
|
||||
let service: UrlService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(UrlService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Injectable, Inject, inject } from '@angular/core';
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Meta } from '@angular/platform-browser';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UrlService {
|
||||
document: Document;
|
||||
meta: Meta;
|
||||
|
||||
constructor() {
|
||||
this.document = inject(DOCUMENT)
|
||||
this.meta = inject(Meta)
|
||||
}
|
||||
|
||||
getBaseHref(): string {
|
||||
const baseElement = this.document.querySelector('base');
|
||||
return baseElement?.getAttribute('href') || '/';
|
||||
}
|
||||
|
||||
getApiUrl(): string | null {
|
||||
const apiMetaTag = this.meta.getTag('name="api-url"');
|
||||
return apiMetaTag ? apiMetaTag.content : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
export const API_URL = new InjectionToken<string>('API_URL');
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,16 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>signFlow</title>
|
||||
<base href="/">
|
||||
<meta name="api-url" content="/api">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
</head>
|
||||
<body class="mat-typography">
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { AppComponent } from './app/app.component';
|
||||
import { config } from './app/app.config.server';
|
||||
|
||||
const bootstrap = () => bootstrapApplication(AppComponent, config);
|
||||
|
||||
export default bootstrap;
|
||||
@@ -0,0 +1,8 @@
|
||||
/// <reference types="@angular/localize" />
|
||||
|
||||
import { bootstrapApplication } from '@angular/platform-browser';
|
||||
import { appConfig } from './app/app.config';
|
||||
import { AppComponent } from './app/app.component';
|
||||
|
||||
bootstrapApplication(AppComponent, appConfig)
|
||||
.catch((err) => console.error(err));
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"/api": {
|
||||
"target": "https://localhost:7174",
|
||||
"secure": false,
|
||||
"changeOrigin": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
|
||||
html, body { height: 100%; }
|
||||
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
|
||||
|
||||
/* Importing Bootstrap SCSS file. */
|
||||
@import 'bootstrap/scss/bootstrap';
|
||||
@@ -0,0 +1,19 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/app",
|
||||
"types": [
|
||||
"node",
|
||||
"@angular/localize"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/main.ts",
|
||||
"src/main.server.ts",
|
||||
"server.ts"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/out-tsc",
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"experimentalDecorators": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"useDefineForClassFields": false,
|
||||
"lib": [
|
||||
"ES2022",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableI18nLegacyMessageIdFormat": false,
|
||||
"strictInjectionParameters": true,
|
||||
"strictInputAccessModifiers": true,
|
||||
"strictTemplates": true,
|
||||
"js/ts.implicitProjectConfig.experimentalDecorators": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"@angular/localize"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
112
EnvelopeGenerator.GeneratorAPI/Controllers/AuthController.cs
Normal file
112
EnvelopeGenerator.GeneratorAPI/Controllers/AuthController.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
using DigitalData.Core.Contracts.Application;
|
||||
using DigitalData.Core.DTO;
|
||||
using DigitalData.UserManager.Application.Contracts;
|
||||
using DigitalData.UserManager.Application.DTOs.User;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using System.Security.Claims;
|
||||
using DigitalData.UserManager.Application.DTOs.Auth;
|
||||
using DigitalData.UserManager.Application;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IDirectorySearchService _dirSearchService;
|
||||
private readonly IStringLocalizer<Resource> _localizer;
|
||||
|
||||
public AuthController(ILogger<AuthController> logger, IUserService userService, IDirectorySearchService dirSearchService, IStringLocalizer<Resource> localizer)
|
||||
{
|
||||
_logger = logger;
|
||||
_userService = userService;
|
||||
_dirSearchService = dirSearchService;
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
//TODO: When a user group is created for signFlow, add a process to check if the user is in this group (like "PM_USER")
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] LogInDto login)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isValid = _dirSearchService.ValidateCredentials(login.Username, login.Password);
|
||||
|
||||
if (!isValid)
|
||||
return Unauthorized();
|
||||
|
||||
//find the user
|
||||
var uRes = await _userService.ReadByUsernameAsync(login.Username);
|
||||
if (!uRes.IsSuccess || uRes.Data is null)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
UserReadDto user = uRes.Data;
|
||||
|
||||
// Create claims
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new (ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new (ClaimTypes.Name, user.Username),
|
||||
new (ClaimTypes.Surname, user.Name!),
|
||||
new (ClaimTypes.GivenName, user.Prename!),
|
||||
new (ClaimTypes.Email, user.Email!),
|
||||
};
|
||||
|
||||
// Create claimsIdentity
|
||||
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
// Create authProperties
|
||||
var authProperties = new AuthenticationProperties
|
||||
{
|
||||
IsPersistent = true,
|
||||
AllowRefresh = true,
|
||||
ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
|
||||
};
|
||||
|
||||
// Sign in
|
||||
await HttpContext.SignInAsync(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme,
|
||||
new ClaimsPrincipal(claimsIdentity),
|
||||
authProperties);
|
||||
|
||||
_dirSearchService.SetSearchRootCache(user.Username, login.Password);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error occurred.\n{ErrorMessage}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("logout")]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
try
|
||||
{
|
||||
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Unexpected error occurred.\n{ErrorMessage}", ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("check")]
|
||||
public IActionResult IsAuthenticated() => Ok(User.Identity?.IsAuthenticated ?? false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
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)
|
||||
? result : null;
|
||||
|
||||
public static string? GetUsername(this ControllerBase controller)
|
||||
=> controller.User.FindFirst(ClaimTypes.Name)?.Value;
|
||||
|
||||
public static string? GetName(this ControllerBase controller)
|
||||
=> controller.User.FindFirst(ClaimTypes.Surname)?.Value;
|
||||
|
||||
public static string? GetPrename(this ControllerBase controller)
|
||||
=> controller.User.FindFirst(ClaimTypes.GivenName)?.Value;
|
||||
|
||||
public static string? GetEmail(this ControllerBase controller)
|
||||
=> controller.User.FindFirst(ClaimTypes.Email)?.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EnvelopeReceiverController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<EnvelopeReceiverController> _logger;
|
||||
private readonly IEnvelopeReceiverService _erService;
|
||||
|
||||
public EnvelopeReceiverController(ILogger<EnvelopeReceiverController> logger, IEnvelopeReceiverService envelopeReceiverService)
|
||||
{
|
||||
_logger = logger;
|
||||
_erService = envelopeReceiverService;
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetEnvelopeReceiver()
|
||||
{
|
||||
try
|
||||
{
|
||||
var username = this.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());
|
||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
|
||||
return await _erService.ReadByUsernameAsync(username).ThenAsync(
|
||||
Success: Ok,
|
||||
Fail: IActionResult (msg, ntc) =>
|
||||
{
|
||||
_logger.LogNotice(ntc);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, msg);
|
||||
});
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An unexpected error occurred. {message}", ex.Message);
|
||||
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.15" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="System.DirectoryServices" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="7.0.1" />
|
||||
<PackageReference Include="System.DirectoryServices.Protocols" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="ClientApp\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Domain\EnvelopeGenerator.Domain.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="DigitalData.Core.API">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.API.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Application">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.Application\bin\Debug\net7.0\DigitalData.Core.Application.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Contracts">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.Contracts.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.DTO">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.API\bin\Debug\net7.0\DigitalData.Core.DTO.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.Core.Infrastructure">
|
||||
<HintPath>..\..\WebCoreModules\DigitalData.Core.Infrastructure\bin\Debug\net7.0\DigitalData.Core.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="DigitalData.UserManager.Application">
|
||||
<HintPath>..\..\WebUserManager\DigitalData.UserManager.Application\bin\Debug\net7.0\DigitalData.UserManager.Application.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-35PBLQEP.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\chunk-IUSOII6E.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\favicon.ico">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\index.html">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\login\index.html">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\main-ZN7C4PGY.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\polyfills-N6LQB2YD.js">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="ClientApp\envelope-generator-ui\dist\envelope-generator-ui\browser\styles-S5ZWIC2V.css">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
96
EnvelopeGenerator.GeneratorAPI/Program.cs
Normal file
96
EnvelopeGenerator.GeneratorAPI/Program.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.Application;
|
||||
using DigitalData.UserManager.Application;
|
||||
using DigitalData.UserManager.Infrastructure.Repositories;
|
||||
using EnvelopeGenerator.Application;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
var config = builder.Configuration;
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
//CORS Policy
|
||||
var allowedOrigins = config.GetSection("AllowedOrigins").Get<string[]>() ??
|
||||
throw new InvalidOperationException("AllowedOrigins section is missing in the configuration.");
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowSpecificOriginsPolicy", builder =>
|
||||
{
|
||||
builder.WithOrigins(allowedOrigins)
|
||||
.SetIsOriginAllowedToAllowWildcardSubdomains()
|
||||
.AllowCredentials()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader();
|
||||
});
|
||||
});
|
||||
|
||||
// Swagger
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
// DbContext
|
||||
var connStr = config.GetConnectionString("Default") ?? throw new InvalidOperationException("There is no default connection string in appsettings.json.");
|
||||
builder.Services.AddDbContext<EGDbContext>(options => options.UseSqlServer(connStr));
|
||||
|
||||
// Authentication
|
||||
if (builder.Environment.IsDevelopment())
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.LoginPath = "/api/auth/login";
|
||||
options.LogoutPath = "/api/auth/logout";
|
||||
});
|
||||
else
|
||||
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true; // Makes the cookie inaccessible to client-side scripts for security
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; // Ensures cookies are sent over HTTPS only
|
||||
options.Cookie.SameSite = SameSiteMode.Strict; // Protects against CSRF attacks by restricting how cookies are sent with requests from external sites
|
||||
options.LoginPath = "/api/auth/login";
|
||||
options.LogoutPath = "/api/auth/logout";
|
||||
});
|
||||
|
||||
// User manager
|
||||
builder.Services.AddUserManager<EGDbContext>();
|
||||
|
||||
// LDAP
|
||||
builder.ConfigureBySection<DirectorySearchOptions>();
|
||||
builder.Services.AddDirectorySearchService();
|
||||
|
||||
// Localizer
|
||||
builder.Services.AddCookieBasedLocalizer() ;
|
||||
|
||||
// Envelope generator serives
|
||||
builder.Services.AddEnvelopeGenerator();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
}
|
||||
|
||||
// Set CORS policy
|
||||
app.UseCors("AllowSpecificOriginsPolicy");
|
||||
|
||||
// Localizer
|
||||
app.UseCookieBasedLocalizer("de-DE", "en-US");
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseDefaultFiles();
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:4176",
|
||||
"sslPort": 44300
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5131",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7174;http://localhost:5131",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"angular": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "",
|
||||
"applicationUrl": "https://localhost:7174;http://localhost:5131",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
22
EnvelopeGenerator.GeneratorAPI/appsettings.json
Normal file
22
EnvelopeGenerator.GeneratorAPI/appsettings.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"AllowedOrigins": [ "http://localhost:4200" ],
|
||||
"ConnectionStrings": {
|
||||
"Default": "Server=SDD-VMP04-SQL17\\DD_DEVELOP01;Database=DD_ECM;User Id=sa;Password=dd;Encrypt=false;TrustServerCertificate=True;"
|
||||
},
|
||||
"DirectorySearchOptions": {
|
||||
"ServerName": "DD-VMP01-DC01",
|
||||
"Root": "DC=dd-gan,DC=local,DC=digitaldata,DC=works",
|
||||
"UserCacheExpirationDays": 1,
|
||||
"CustomSearchFilters": {
|
||||
"User": "(&(objectClass=user)(sAMAccountName=*))",
|
||||
"Group": "(&(objectClass=group)(samAccountName=*))"
|
||||
}
|
||||
}
|
||||
}
|
||||
7
EnvelopeGenerator.GeneratorAPI/wwwroot/chunk-KPVI7RD6.js
Normal file
7
EnvelopeGenerator.GeneratorAPI/wwwroot/chunk-KPVI7RD6.js
Normal file
File diff suppressed because one or more lines are too long
1
EnvelopeGenerator.GeneratorAPI/wwwroot/chunk-NALQ2D3H.js
Normal file
1
EnvelopeGenerator.GeneratorAPI/wwwroot/chunk-NALQ2D3H.js
Normal file
File diff suppressed because one or more lines are too long
BIN
EnvelopeGenerator.GeneratorAPI/wwwroot/favicon.ico
Normal file
BIN
EnvelopeGenerator.GeneratorAPI/wwwroot/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
179
EnvelopeGenerator.GeneratorAPI/wwwroot/index.html
Normal file
179
EnvelopeGenerator.GeneratorAPI/wwwroot/index.html
Normal file
File diff suppressed because one or more lines are too long
166
EnvelopeGenerator.GeneratorAPI/wwwroot/main-U7N36S7P.js
Normal file
166
EnvelopeGenerator.GeneratorAPI/wwwroot/main-U7N36S7P.js
Normal file
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user