Compare commits
41 Commits
customer/C
...
b66c2f67da
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b66c2f67da | ||
|
|
d084a4cd81 | ||
|
|
5d2bf56493 | ||
|
|
cd88f5c833 | ||
|
|
ab41e25071 | ||
|
|
eb775da7d4 | ||
|
|
7bc2695da4 | ||
|
|
75fff426bc | ||
|
|
4172df4d78 | ||
|
|
01856b61ef | ||
|
|
2e32559132 | ||
|
|
9adb49df78 | ||
|
|
18e21b0a8e | ||
|
|
e1d7d0e141 | ||
|
|
cfa40e640b | ||
|
|
cb0a45bc17 | ||
|
|
c7b6e5bf24 | ||
|
|
a9ca1b71eb | ||
|
|
97f07bc72d | ||
|
|
8753875d93 | ||
|
|
3692aa80a4 | ||
|
|
b8b09ded5d | ||
|
|
5b8d8b9e55 | ||
|
|
e3fbf4fc77 | ||
|
|
8d680992b7 | ||
|
|
01247f73f4 | ||
|
|
6a7a3dcb90 | ||
|
|
2fbfbb4eb6 | ||
|
|
f88b5d2733 | ||
|
|
363358aaa1 | ||
|
|
7444eeba2a | ||
|
|
e9d686a4c1 | ||
|
|
939ba1bb47 | ||
|
|
d5de868eb9 | ||
|
|
6e3bb6c3a0 | ||
|
|
d347ec420c | ||
|
|
a011b677ea | ||
|
|
8831436809 | ||
|
|
1ededc1f64 | ||
|
|
183c94fd0a | ||
|
|
a0a5568d93 |
@@ -1,6 +1,6 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
|
using DigitalData.EmailProfilerDispatcher.Abstraction.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Common;
|
using EnvelopeGenerator.Common;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Contracts
|
namespace EnvelopeGenerator.Application.Contracts
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using DigitalData.Core.Abstractions.Application;
|
using DigitalData.Core.Abstractions.Application;
|
||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Contracts
|
namespace EnvelopeGenerator.Application.Contracts
|
||||||
@@ -10,6 +11,8 @@ namespace EnvelopeGenerator.Application.Contracts
|
|||||||
|
|
||||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
|
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUuidAsync(string uuid, bool withEnvelope = true, bool withReceiver = false);
|
||||||
|
|
||||||
|
Task<DataResult<IEnumerable<EnvelopeReceiverSecretDto>>> ReadSecretByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true);
|
||||||
|
|
||||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true);
|
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadBySignatureAsync(string signature, bool withEnvelope = false, bool withReceiver = true);
|
||||||
|
|
||||||
Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true);
|
Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true);
|
||||||
@@ -25,5 +28,7 @@ namespace EnvelopeGenerator.Application.Contracts
|
|||||||
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
|
Task<DataResult<bool>> IsExisting(string envelopeReceiverId);
|
||||||
|
|
||||||
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
Task<DataResult<IEnumerable<EnvelopeReceiverDto>>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||||
|
|
||||||
|
Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Contracts
|
namespace EnvelopeGenerator.Application.Contracts
|
||||||
{
|
{
|
||||||
@@ -11,5 +10,7 @@ namespace EnvelopeGenerator.Application.Contracts
|
|||||||
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
||||||
|
|
||||||
Task<DataResult<EnvelopeDto>> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
|
Task<DataResult<EnvelopeDto>> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
|
||||||
|
|
||||||
|
Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[]ignore_statuses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ namespace EnvelopeGenerator.Application.DTOs.EnvelopeHistory
|
|||||||
int EnvelopeId,
|
int EnvelopeId,
|
||||||
string UserReference,
|
string UserReference,
|
||||||
int Status,
|
int Status,
|
||||||
|
string? StatusName,
|
||||||
DateTime AddedWhen,
|
DateTime AddedWhen,
|
||||||
DateTime? ActionDate,
|
DateTime? ActionDate,
|
||||||
UserCreateDto? Sender,
|
UserCreateDto? Sender,
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||||
|
{
|
||||||
|
public record EnvelopeReceiverBasicDto()
|
||||||
|
{
|
||||||
|
public int EnvelopeId { get; init; }
|
||||||
|
|
||||||
|
public int ReceiverId { get; init; }
|
||||||
|
|
||||||
|
public int Sequence { get; init; }
|
||||||
|
|
||||||
|
[TemplatePlaceholder("[NAME_RECEIVER]")]
|
||||||
|
public string? Name { get; init; }
|
||||||
|
|
||||||
|
public string? JobTitle { get; init; }
|
||||||
|
|
||||||
|
public string? CompanyName { get; init; }
|
||||||
|
|
||||||
|
public string? PrivateMessage { get; init; }
|
||||||
|
|
||||||
|
public DateTime AddedWhen { get; init; }
|
||||||
|
|
||||||
|
public DateTime? ChangedWhen { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||||
|
{
|
||||||
|
public record EnvelopeReceiverDto() : EnvelopeReceiverBasicDto()
|
||||||
|
{
|
||||||
|
public EnvelopeDto? Envelope { get; set; }
|
||||||
|
|
||||||
|
public ReceiverReadDto? Receiver { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
namespace EnvelopeGenerator.Application.DTOs.EnvelopeReceiver
|
||||||
|
{
|
||||||
|
public record EnvelopeReceiverSecretDto(string? AccessCode) : EnvelopeReceiverDto;
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Attributes;
|
|
||||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.DTOs
|
|
||||||
{
|
|
||||||
public record EnvelopeReceiverDto()
|
|
||||||
{
|
|
||||||
public int EnvelopeId { get; set; }
|
|
||||||
|
|
||||||
public int ReceiverId { get; set; }
|
|
||||||
|
|
||||||
public int Sequence { get; set; }
|
|
||||||
|
|
||||||
[TemplatePlaceholder("[NAME_RECEIVER]")]
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public string? JobTitle { get; set; }
|
|
||||||
|
|
||||||
public string? CompanyName { get; set; }
|
|
||||||
|
|
||||||
public string? PrivateMessage { get; set; }
|
|
||||||
|
|
||||||
public DateTime AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
|
|
||||||
public EnvelopeDto? Envelope { get; set; }
|
|
||||||
|
|
||||||
public ReceiverReadDto? Receiver { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.DTOs.Receiver
|
namespace EnvelopeGenerator.Application.DTOs.Receiver
|
||||||
{
|
{
|
||||||
@@ -6,6 +8,12 @@ namespace EnvelopeGenerator.Application.DTOs.Receiver
|
|||||||
int Id,
|
int Id,
|
||||||
string EmailAddress,
|
string EmailAddress,
|
||||||
string Signature,
|
string Signature,
|
||||||
DateTime AddedWhen
|
DateTime AddedWhen
|
||||||
) : BaseDTO<int>(Id);
|
) : BaseDTO<int>(Id)
|
||||||
|
{
|
||||||
|
[JsonIgnore]
|
||||||
|
public IEnumerable<EnvelopeReceiverBasicDto>? EnvelopeReceivers { get; init; }
|
||||||
|
|
||||||
|
public string? LastUsedName => EnvelopeReceivers?.LastOrDefault()?.Name;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstractions" Version="1.0.1.1" />
|
<PackageReference Include="DigitalData.Core.Abstractions" Version="1.0.1.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="1.0.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="1.0.0" />
|
||||||
<PackageReference Include="DigitalData.Core.DTO" Version="1.0.0" />
|
<PackageReference Include="DigitalData.Core.DTO" Version="1.0.0.1" />
|
||||||
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="1.0.0" />
|
<PackageReference Include="DigitalData.EmailProfilerDispatcher" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.18" />
|
||||||
<PackageReference Include="UserManager.Application" Version="1.0.0" />
|
<PackageReference Include="UserManager.Application" Version="1.0.0" />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs;
|
||||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Application.DTOs.Receiver;
|
using EnvelopeGenerator.Application.DTOs.Receiver;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles
|
|||||||
CreateMap<EnvelopeHistory, EnvelopeHistoryDto>();
|
CreateMap<EnvelopeHistory, EnvelopeHistoryDto>();
|
||||||
CreateMap<EnvelopeHistory, EnvelopeHistoryCreateDto>();
|
CreateMap<EnvelopeHistory, EnvelopeHistoryCreateDto>();
|
||||||
CreateMap<EnvelopeReceiver, EnvelopeReceiverDto>();
|
CreateMap<EnvelopeReceiver, EnvelopeReceiverDto>();
|
||||||
|
CreateMap<EnvelopeReceiver, EnvelopeReceiverSecretDto>();
|
||||||
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
CreateMap<EnvelopeType, EnvelopeTypeDto>();
|
||||||
CreateMap<Receiver, ReceiverReadDto>();
|
CreateMap<Receiver, ReceiverReadDto>();
|
||||||
CreateMap<Receiver, ReceiverCreateDto>();
|
CreateMap<Receiver, ReceiverCreateDto>();
|
||||||
@@ -43,6 +45,7 @@ namespace EnvelopeGenerator.Application.MappingProfiles
|
|||||||
CreateMap<ReceiverCreateDto, Receiver>();
|
CreateMap<ReceiverCreateDto, Receiver>();
|
||||||
CreateMap<ReceiverUpdateDto, Receiver>();
|
CreateMap<ReceiverUpdateDto, Receiver>();
|
||||||
CreateMap<UserReceiverDto, UserReceiver>();
|
CreateMap<UserReceiverDto, UserReceiver>();
|
||||||
|
CreateMap<EnvelopeReceiverBase, EnvelopeReceiverBasicDto>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ using DigitalData.EmailProfilerDispatcher.Abstraction.DTOs.EmailOut;
|
|||||||
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
|
using DigitalData.EmailProfilerDispatcher.Abstraction.Services;
|
||||||
using DigitalData.UserManager.Application;
|
using DigitalData.UserManager.Application;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Common;
|
using EnvelopeGenerator.Common;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@@ -14,7 +14,7 @@ using static EnvelopeGenerator.Common.Constants;
|
|||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Services
|
namespace EnvelopeGenerator.Application.Services
|
||||||
{
|
{
|
||||||
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
|
public class EnvelopeMailService : EmailOutService, IEnvelopeMailService
|
||||||
{
|
{
|
||||||
private readonly IEmailTemplateService _tempService;
|
private readonly IEmailTemplateService _tempService;
|
||||||
private readonly IEnvelopeReceiverService _envRcvService;
|
private readonly IEnvelopeReceiverService _envRcvService;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
using DigitalData.Core.Application;
|
using DigitalData.Core.Application;
|
||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using EnvelopeGenerator.Application.Resources;
|
using EnvelopeGenerator.Application.Resources;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||||
@@ -33,6 +33,12 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
return Result.Success(_mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
|
return Result.Success(_mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(env_rcvs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<DataResult<IEnumerable<EnvelopeReceiverSecretDto>>> ReadSecretByUuidAsync(string uuid, bool withEnvelope = false, bool withReceiver = true)
|
||||||
|
{
|
||||||
|
var env_rcvs = await _repository.ReadByUuidAsync(uuid: uuid, withEnvelope: withEnvelope, withReceiver: withReceiver);
|
||||||
|
return Result.Success(_mapper.MapOrThrow<IEnumerable<EnvelopeReceiverSecretDto>>(env_rcvs));
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
|
public async Task<DataResult<EnvelopeReceiverDto>> ReadByUuidSignatureAsync(string uuid, string signature, bool withEnvelope = true, bool withReceiver = true)
|
||||||
{
|
{
|
||||||
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver);
|
var env_rcv = await _repository.ReadByUuidSignatureAsync(uuid: uuid, signature: signature, withEnvelope: withEnvelope, withReceiver: withReceiver);
|
||||||
@@ -122,5 +128,11 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
var dto_list = _mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(er_list);
|
var dto_list = _mapper.MapOrThrow<IEnumerable<EnvelopeReceiverDto>>(er_list);
|
||||||
return Result.Success(dto_list);
|
return Result.Success(dto_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<DataResult<string?>> ReadLastUsedReceiverNameByMail(string mail)
|
||||||
|
{
|
||||||
|
var er = await _repository.ReadLastByReceiver(mail);
|
||||||
|
return er is null ? Result.Fail<string?>().Notice(LogLevel.None, Flag.NotFound) : Result.Success(er.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,21 +3,16 @@ using DigitalData.Core.Application;
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs;
|
||||||
using EnvelopeGenerator.Application.Resources;
|
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||||
using Microsoft.Extensions.Localization;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Services
|
namespace EnvelopeGenerator.Application.Services
|
||||||
{
|
{
|
||||||
public class EnvelopeService : BasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>, IEnvelopeService
|
public class EnvelopeService : BasicCRUDService<IEnvelopeRepository, EnvelopeDto, Envelope, int>, IEnvelopeService
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
public EnvelopeService(IEnvelopeRepository repository, IMapper mapper)
|
||||||
public EnvelopeService(IEnvelopeRepository repository, IMapper mapper, ILogger<EnvelopeService> logger)
|
|
||||||
: base(repository, mapper)
|
: base(repository, mapper)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false)
|
public async Task<DataResult<IEnumerable<EnvelopeDto>>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false)
|
||||||
@@ -37,5 +32,12 @@ namespace EnvelopeGenerator.Application.Services
|
|||||||
var readDto = _mapper.MapOrThrow<EnvelopeDto>(envelope);
|
var readDto = _mapper.MapOrThrow<EnvelopeDto>(envelope);
|
||||||
return Result.Success(readDto);
|
return Result.Success(readDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<DataResult<IEnumerable<EnvelopeDto>>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses)
|
||||||
|
{
|
||||||
|
var users = await _repository.ReadByUserAsync(userId: userId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses);
|
||||||
|
var readDto = _mapper.MapOrThrow<IEnumerable<EnvelopeDto>>(users);
|
||||||
|
return Result.Success(readDto);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,31 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using DigitalData.Core.Application;
|
using DigitalData.Core.Application;
|
||||||
using Microsoft.Extensions.Localization;
|
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||||
using EnvelopeGenerator.Application.Resources;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using DigitalData.Core.DTO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Application.Services
|
namespace EnvelopeGenerator.Application.Services
|
||||||
{
|
{
|
||||||
public class EnvelopeTypeService : BasicCRUDService<IEnvelopeTypeRepository, EnvelopeTypeDto, EnvelopeType, int>, IEnvelopeTypeService
|
public class EnvelopeTypeService : BasicCRUDService<IEnvelopeTypeRepository, EnvelopeTypeDto, EnvelopeType, int>, IEnvelopeTypeService
|
||||||
{
|
{
|
||||||
public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper)
|
private static readonly Guid CacheKey = Guid.NewGuid();
|
||||||
|
|
||||||
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
|
public EnvelopeTypeService(IEnvelopeTypeRepository repository, IMapper mapper, IMemoryCache cache)
|
||||||
: base(repository, mapper)
|
: base(repository, mapper)
|
||||||
{
|
{
|
||||||
|
_cache = cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override async Task<DataResult<IEnumerable<EnvelopeTypeDto>>> ReadAllAsync()
|
||||||
|
=> await _cache.GetOrCreateAsync(CacheKey, async entry => await base.ReadAllAsync())
|
||||||
|
?? Result.Fail<IEnumerable<EnvelopeTypeDto>>().Notice(LogLevel.Error, Flag.NotFound, "No cached envelope types are available in the database. If you have added any envelope types after the server started, please restart the server.");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
MessageCompletionSent = 3005
|
MessageCompletionSent = 3005
|
||||||
End Enum
|
End Enum
|
||||||
|
|
||||||
|
'TODO: standardize in xwiki
|
||||||
Public Enum ReferenceType
|
Public Enum ReferenceType
|
||||||
Receiver
|
Receiver
|
||||||
Sender
|
Sender
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Column("USER_REFERENCE", TypeName = "nvarchar(128)")]
|
[Column("USER_REFERENCE", TypeName = "nvarchar(128)")]
|
||||||
public string UserReference { get; set; }
|
public required string UserReference { get; init; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Column("STATUS")]
|
[Column("STATUS")]
|
||||||
@@ -43,11 +43,17 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
public virtual Receiver? Receiver { get; set; }
|
public virtual Receiver? Receiver { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public ReferenceType ReferenceType => (Status / 3) switch
|
public ReferenceType ReferenceType => (Status / 1000) switch
|
||||||
{
|
{
|
||||||
1 => ReferenceType.Sender,
|
1 => ReferenceType.Sender,
|
||||||
2 or 3 => ReferenceType.Receiver,
|
2 or 3 => ReferenceType.Receiver,
|
||||||
_ => ReferenceType.Unknown,
|
_ => ReferenceType.Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string? StatusName
|
||||||
|
=> (Enum.IsDefined(typeof(EnvelopeStatus), Status))
|
||||||
|
? Enum.GetName(typeof(EnvelopeStatus), Status)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,45 +1,10 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Domain.Entities
|
namespace EnvelopeGenerator.Domain.Entities
|
||||||
{
|
{
|
||||||
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
|
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
|
||||||
public class EnvelopeReceiver
|
public class EnvelopeReceiver : EnvelopeReceiverBase
|
||||||
{
|
{
|
||||||
[Key]
|
|
||||||
[Column("ENVELOPE_ID")]
|
|
||||||
public int EnvelopeId { get; set; }
|
|
||||||
|
|
||||||
[Key]
|
|
||||||
[Column("RECEIVER_ID")]
|
|
||||||
public int ReceiverId { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[Column("SEQUENCE")]
|
|
||||||
public int Sequence { get; set; }
|
|
||||||
|
|
||||||
[Column("NAME", TypeName = "nvarchar(128)")]
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
[Column("JOB_TITLE", TypeName = "nvarchar(128)")]
|
|
||||||
public string? JobTitle { get; set; }
|
|
||||||
|
|
||||||
[Column("COMPANY_NAME", TypeName = "nvarchar(128)")]
|
|
||||||
public string? CompanyName { get; set; }
|
|
||||||
|
|
||||||
[Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")]
|
|
||||||
public string? PrivateMessage { get; set; }
|
|
||||||
|
|
||||||
[Column("ACCESS_CODE", TypeName = "nvarchar(64)")]
|
|
||||||
public string? AccessCode { get; set; }
|
|
||||||
|
|
||||||
[Required]
|
|
||||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
|
||||||
public DateTime AddedWhen { get; set; }
|
|
||||||
|
|
||||||
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
|
|
||||||
[ForeignKey("EnvelopeId")]
|
[ForeignKey("EnvelopeId")]
|
||||||
public Envelope? Envelope { get; set; }
|
public Envelope? Envelope { get; set; }
|
||||||
|
|
||||||
|
|||||||
43
EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs
Normal file
43
EnvelopeGenerator.Domain/Entities/EnvelopeReceiverBase.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.Domain.Entities
|
||||||
|
{
|
||||||
|
[Table("TBSIG_ENVELOPE_RECEIVER", Schema = "dbo")]
|
||||||
|
public class EnvelopeReceiverBase
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Column("ENVELOPE_ID")]
|
||||||
|
public int EnvelopeId { get; set; }
|
||||||
|
|
||||||
|
[Key]
|
||||||
|
[Column("RECEIVER_ID")]
|
||||||
|
public int ReceiverId { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("SEQUENCE")]
|
||||||
|
public int Sequence { get; set; }
|
||||||
|
|
||||||
|
[Column("NAME", TypeName = "nvarchar(128)")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[Column("JOB_TITLE", TypeName = "nvarchar(128)")]
|
||||||
|
public string? JobTitle { get; set; }
|
||||||
|
|
||||||
|
[Column("COMPANY_NAME", TypeName = "nvarchar(128)")]
|
||||||
|
public string? CompanyName { get; set; }
|
||||||
|
|
||||||
|
[Column("PRIVATE_MESSAGE", TypeName = "nvarchar(max)")]
|
||||||
|
public string? PrivateMessage { get; set; }
|
||||||
|
|
||||||
|
[Column("ACCESS_CODE", TypeName = "nvarchar(64)")]
|
||||||
|
public string? AccessCode { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime AddedWhen { get; set; }
|
||||||
|
|
||||||
|
[Column("CHANGED_WHEN", TypeName = "datetime")]
|
||||||
|
public DateTime? ChangedWhen { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,5 +22,7 @@ namespace EnvelopeGenerator.Domain.Entities
|
|||||||
[Required]
|
[Required]
|
||||||
[Column("ADDED_WHEN", TypeName = "datetime")]
|
[Column("ADDED_WHEN", TypeName = "datetime")]
|
||||||
public DateTime AddedWhen { get; set; }
|
public DateTime AddedWhen { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<EnvelopeReceiver>? EnvelopeReceivers { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ApplicationConfig } from '@angular/core';
|
import { ApplicationConfig, APP_INITIALIZER } from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
import { provideClientHydration } from '@angular/platform-browser';
|
import { provideClientHydration } from '@angular/platform-browser';
|
||||||
@@ -8,6 +8,7 @@ import { UrlService } from './services/url.service';
|
|||||||
import { API_URL } from './tokens/index'
|
import { API_URL } from './tokens/index'
|
||||||
import { HTTP_INTERCEPTORS, provideHttpClient, withFetch } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS, provideHttpClient, withFetch } from '@angular/common/http';
|
||||||
import { HttpRequestInterceptor } from './http.interceptor';
|
import { HttpRequestInterceptor } from './http.interceptor';
|
||||||
|
import { ConfigurationService } from './services/configuration.service';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
@@ -29,6 +30,12 @@ export const appConfig: ApplicationConfig = {
|
|||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
useClass: HttpRequestInterceptor,
|
useClass: HttpRequestInterceptor,
|
||||||
multi: true
|
multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: APP_INITIALIZER,
|
||||||
|
useFactory: (configService: ConfigurationService) => async () => await configService.ngOnInit(),
|
||||||
|
deps: [ConfigurationService],
|
||||||
|
multi: true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
<table #table mat-table [dataSource]="data" class="mat-elevation-z8">
|
|
||||||
|
|
||||||
@for (colId of displayedColumns; track colId) {
|
|
||||||
<ng-container matColumnDef="{{colId}}">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> {{schema[colId].header}} </th>
|
|
||||||
<td mat-cell *matCellDef="let element"> {{schema[colId].field(element)}} </td>
|
|
||||||
</ng-container>
|
|
||||||
}
|
|
||||||
|
|
||||||
<ng-container matColumnDef="expand">
|
|
||||||
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
|
||||||
<td mat-cell *matCellDef="let element">
|
|
||||||
<button mat-icon-button aria-label="expand row"
|
|
||||||
(click)="(expandedElement = expandedElement === element ? null : element); $event.stopPropagation()">
|
|
||||||
@if (expandedElement === element) {
|
|
||||||
<mat-icon>keyboard_arrow_up</mat-icon>
|
|
||||||
} @else {
|
|
||||||
<mat-icon>keyboard_arrow_down</mat-icon>
|
|
||||||
}
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
|
||||||
<ng-container matColumnDef="expandedDetail">
|
|
||||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplayWithExpand.length">
|
|
||||||
<div class="example-element-detail" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
|
|
||||||
<div class="example-element-diagram">
|
|
||||||
<div class="example-element-position"> {{"element.position"}} </div>
|
|
||||||
<div class="example-element-symbol"> {{"element.symbol"}} </div>
|
|
||||||
<div class="example-element-name"> {{"element.name"}} </div>
|
|
||||||
<div class="example-element-weight"> {{"element.weight"}} </div>
|
|
||||||
</div>
|
|
||||||
<div class="example-element-description">
|
|
||||||
{{"element.description"}}
|
|
||||||
<span class="example-element-description-attribution"> -- Wikipedia </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplayWithExpand"></tr>
|
|
||||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplayWithExpand;" class="example-element-row"
|
|
||||||
[class.example-expanded-row]="expandedElement === element"
|
|
||||||
(click)="expandedElement = expandedElement === element ? null : element">
|
|
||||||
</tr>
|
|
||||||
<!--<tr mat-row *matRowDef="let row; columns: ['expandedDetail']; when: isExpandedRow" class="example-detail-row"></tr>-->
|
|
||||||
</table>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
.example-element-row td {
|
|
||||||
border-bottom-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-element-detail {
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-element-diagram {
|
|
||||||
min-width: 80px;
|
|
||||||
border: 2px solid black;
|
|
||||||
padding: 8px;
|
|
||||||
font-weight: lighter;
|
|
||||||
margin: 8px 0;
|
|
||||||
height: 104px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-element-symbol {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 40px;
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-element-description {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.example-element-description-attribution {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import { Component, Input, ViewChild } from '@angular/core';
|
|
||||||
import { EnvelopeReceiverService } from '../../services/envelope-receiver.service';
|
|
||||||
import { MatTable, MatTableModule } from '@angular/material/table';
|
|
||||||
import { CommonModule } from '@angular/common'
|
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-envelope-table',
|
|
||||||
standalone: true,
|
|
||||||
imports: [MatTableModule, CommonModule, MatTableModule, MatButtonModule, MatIconModule],
|
|
||||||
templateUrl: './envelope-table.component.html',
|
|
||||||
animations: [
|
|
||||||
trigger('detailExpand', [
|
|
||||||
state('collapsed,void', style({ height: '0px', minHeight: '0' })),
|
|
||||||
state('expanded', style({ height: '*' })),
|
|
||||||
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
|
||||||
]),
|
|
||||||
],
|
|
||||||
styleUrl: './envelope-table.component.scss'
|
|
||||||
})
|
|
||||||
export class EnvelopeTableComponent {
|
|
||||||
|
|
||||||
@Input() data: Array<any> = []
|
|
||||||
|
|
||||||
@Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] }
|
|
||||||
|
|
||||||
@Input() displayedColumns: string[] = ['title', 'status', 'type', 'privateMessage', 'addedWhen'];
|
|
||||||
|
|
||||||
@Input() schema: Record<string, { header: string; field: (element: any) => any; }> = {
|
|
||||||
'title': {
|
|
||||||
header: 'Title',
|
|
||||||
field: (element: any) => element.envelope.title
|
|
||||||
},
|
|
||||||
'status': {
|
|
||||||
header: 'Status',
|
|
||||||
field: (element: any) => element.envelope.statusName
|
|
||||||
},
|
|
||||||
'type': {
|
|
||||||
header: 'Type',
|
|
||||||
field: (element: any) => element.envelope.contractType
|
|
||||||
},
|
|
||||||
'privateMessage': {
|
|
||||||
header: 'Private Message',
|
|
||||||
field: (element: any) => element.privateMessage
|
|
||||||
},
|
|
||||||
'addedWhen': {
|
|
||||||
header: 'Added When',
|
|
||||||
field: (element: any) => element.addedWhen
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
columnsToDisplayWithExpand = [...this.displayedColumns, 'expand'];
|
|
||||||
|
|
||||||
expandedElement: any | null;
|
|
||||||
|
|
||||||
@ViewChild(MatTable) table!: MatTable<any>;
|
|
||||||
|
|
||||||
constructor(private erService: EnvelopeReceiverService) { }
|
|
||||||
|
|
||||||
async ngOnInit() {
|
|
||||||
if (this.data.length === 0)
|
|
||||||
this.data = await this.erService.getEnvelopeReceiverAsync(this.options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateTable() {
|
|
||||||
this.table.renderRows();
|
|
||||||
}
|
|
||||||
|
|
||||||
isExpandedRow(index: number, row: any): boolean {
|
|
||||||
return (row?.envelopeId === this.expandedElement?.envelopeId) && (row?.receiverId === this.expandedElement?.receiverId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -37,19 +37,19 @@ export class ReceiverInputComponent implements OnInit, OnChanges {
|
|||||||
private setupFiltering(): void {
|
private setupFiltering(): void {
|
||||||
this.filteredOptions = this.control.valueChanges.pipe(
|
this.filteredOptions = this.control.valueChanges.pipe(
|
||||||
startWith(''),
|
startWith(''),
|
||||||
map(value => this.filter(value || '', this.options)),
|
map(value => this.filter(value || '', this.options, this.index)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
control = new FormControl('');
|
control = new FormControl('');
|
||||||
filteredOptions!: Observable<string[]>;
|
filteredOptions!: Observable<string[]>;
|
||||||
|
|
||||||
|
|
||||||
@Input() options: string[] = [];
|
@Input() options: string[] = [];
|
||||||
@Input() filter: (value: string, options: string[]) => string[] = value => {
|
@Input() filter: (value: string, options: string[], index?: number) => string[] = value => {
|
||||||
const filterValue = value.toLowerCase();
|
const filterValue = value.toLowerCase();
|
||||||
return this.options.filter(option => option.toLowerCase().includes(filterValue));
|
return this.options.filter(option => option.toLowerCase().includes(filterValue));
|
||||||
}
|
}
|
||||||
|
@Input() index?: number;
|
||||||
|
|
||||||
public get text(): string {
|
public get text(): string {
|
||||||
return this.control.value || '';
|
return this.control.value || '';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<table mat-table [dataSource]="receiverData" class="mat-elevation-z8">
|
<table mat-table [dataSource]="receiverData" class="mat-elevation-z8">
|
||||||
<ng-container matColumnDef="email">
|
<ng-container matColumnDef="email">
|
||||||
<th mat-header-cell *matHeaderCellDef> Email </th>
|
<th mat-header-cell *matHeaderCellDef> Email </th>
|
||||||
<td mat-cell *matCellDef="let element">
|
<td mat-cell *matCellDef="let element; let i = index">
|
||||||
<receiver-input [options]="receiver_mails" [filter]="receiver_filter"></receiver-input>
|
<receiver-input [options]="receiver_mails" [filter]="receiver_filter"></receiver-input>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
@if(isFilterable) {
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-label>{{filter.label}}</mat-label>
|
||||||
|
<input matInput (keyup)="applyFilter($event)" [placeholder]="filter.placeholder" #input>
|
||||||
|
</mat-form-field>
|
||||||
|
}
|
||||||
|
|
||||||
|
<table mat-table [dataSource]="dataSource" multiTemplateDataRows class="mat-elevation-z8" matSort>
|
||||||
|
@for (column of __columnsToDisplay; track column) {
|
||||||
|
<ng-container matColumnDef="{{column}}">
|
||||||
|
@if(isSortable) {
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header> {{schema[column].header}} </th>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{schema[column].header}} </th>
|
||||||
|
}
|
||||||
|
<td mat-cell *matCellDef="let element"> {{schema[column].field(element)}} </td>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
|
||||||
|
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
||||||
|
@if(isExpandable) {
|
||||||
|
<ng-container matColumnDef="expand">
|
||||||
|
<th mat-header-cell *matHeaderCellDef aria-label="row actions"> </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-icon-button aria-label="expand row" (click)="toggleExpandedRow(element, $event)">
|
||||||
|
@if (__expandedElement === element) {
|
||||||
|
<mat-icon>keyboard_arrow_up</mat-icon>
|
||||||
|
} @else {
|
||||||
|
<mat-icon>keyboard_arrow_down</mat-icon>
|
||||||
|
}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="expandedDetail">
|
||||||
|
<td mat-cell *matCellDef="let element" [attr.colspan]="__columnsToDisplayWithExpand.length">
|
||||||
|
<div class="example-element-detail" [@detailExpand]="element == __expandedElement ? 'expanded' : 'collapsed'">
|
||||||
|
@if(__expandedElement === element){
|
||||||
|
<ng-content select="[expanded]" detailed></ng-content>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
}
|
||||||
|
@if(isExpandable) {
|
||||||
|
<tr mat-header-row *matHeaderRowDef="__columnsToDisplayWithExpand"></tr>
|
||||||
|
<tr mat-row *matRowDef="let element; columns: __columnsToDisplayWithExpand;" class="example-element-row"
|
||||||
|
[class.example-expanded-row]="__expandedElement === element" (click)="toggleExpandedRow(element, $event)">
|
||||||
|
</tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
<tr mat-header-row *matHeaderRowDef="__columnsToDisplay"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: __columnsToDisplay;"></tr>
|
||||||
|
}
|
||||||
|
</table>
|
||||||
|
@if(paginatorSizeOptions && paginatorSizeOptions.length > 0) {
|
||||||
|
<mat-paginator [pageSizeOptions]="paginatorSizeOptions" aria-label="Select page of users"></mat-paginator>
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-detail-row {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):hover {
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):active {
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-row td {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-detail {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-diagram {
|
||||||
|
min-width: 80px;
|
||||||
|
border: 2px solid black;
|
||||||
|
padding: 8px;
|
||||||
|
font-weight: lighter;
|
||||||
|
margin: 8px 0;
|
||||||
|
height: 104px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-symbol {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description-attribution {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-form-field {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DDTable } from './dd-table.component';
|
||||||
|
|
||||||
|
describe('TableExpandableRowsExampleComponent', () => {
|
||||||
|
let component: DDTable;
|
||||||
|
let fixture: ComponentFixture<DDTable>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [DDTable]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DDTable);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import { AfterViewInit, Component, Input, ViewChild, inject } from '@angular/core';
|
||||||
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatTable, MatTableDataSource, MatTableModule } from '@angular/material/table';
|
||||||
|
import { ConfigurationService } from '../../../services/configuration.service';
|
||||||
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
|
import { MatSort, MatSortModule } from '@angular/material/sort';
|
||||||
|
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @title Table with expandable rows
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'dd-table',
|
||||||
|
styleUrl: 'dd-table.component.scss',
|
||||||
|
templateUrl: 'dd-table.component.html',
|
||||||
|
animations: [
|
||||||
|
trigger('detailExpand', [
|
||||||
|
state('collapsed,void', style({ height: '0px', minHeight: '0' })),
|
||||||
|
state('expanded', style({ height: '*' })),
|
||||||
|
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
MatTableModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatFormFieldModule,
|
||||||
|
MatInputModule,
|
||||||
|
MatTableModule,
|
||||||
|
MatSort,
|
||||||
|
MatSortModule,
|
||||||
|
MatPaginator,
|
||||||
|
MatPaginatorModule
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class DDTable implements AfterViewInit {
|
||||||
|
public readonly dataSource: any = new MatTableDataSource();
|
||||||
|
@Input() public set columnsToDisplay(value: string[]) {
|
||||||
|
this.__columnsToDisplay = value;
|
||||||
|
this.__columnsToDisplayWithExpand = [...value, 'expand'];
|
||||||
|
}
|
||||||
|
@Input() public set data(value: any[]) {
|
||||||
|
this.dataSource.data = value;
|
||||||
|
}
|
||||||
|
@Input() schema: Record<string, { header: string; field: (element: any) => any; }> = {}
|
||||||
|
|
||||||
|
@Input() paginatorSizeOptions?: number[];
|
||||||
|
|
||||||
|
@Input() filter: { label: string, placeholder: string } = { label: '', placeholder: '' }
|
||||||
|
|
||||||
|
@Input() isFilterable: boolean = false;
|
||||||
|
|
||||||
|
@Input() isExpandable: boolean = false;
|
||||||
|
|
||||||
|
@Input() isSortable: boolean = false;
|
||||||
|
|
||||||
|
@Input() onToggleExpandedRow: (element: any, event: Event) => Promise<void> = async (element: any, event: Event) => { }
|
||||||
|
|
||||||
|
public get data(): any[] {
|
||||||
|
return this.dataSource.data;
|
||||||
|
}
|
||||||
|
__columnsToDisplay: string[] = [];
|
||||||
|
__columnsToDisplayWithExpand: string[] = [];
|
||||||
|
__expandedElement!: any;
|
||||||
|
|
||||||
|
config: ConfigurationService = inject(ConfigurationService);
|
||||||
|
|
||||||
|
@ViewChild(MatSort) sort!: MatSort;
|
||||||
|
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||||
|
@ViewChild(MatTable) table!: MatTable<any>;
|
||||||
|
|
||||||
|
ngAfterViewInit(): void {
|
||||||
|
if (this.isSortable)
|
||||||
|
this.dataSource.sort = this.sort;
|
||||||
|
if (this.paginatorSizeOptions && this.paginatorSizeOptions.length > 0)
|
||||||
|
this.dataSource.paginator = this.paginator;
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter(event: Event) {
|
||||||
|
const filterValue = (event.target as HTMLInputElement).value;
|
||||||
|
this.dataSource.filter = filterValue.trim().toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.table.renderRows();
|
||||||
|
}
|
||||||
|
|
||||||
|
async toggleExpandedRow(element: any, event: Event): Promise<void> {
|
||||||
|
// first determine the new expanded element, thus it would be possible to use up-to-date
|
||||||
|
const newExpandedElement = this.__expandedElement === element ? null : element;
|
||||||
|
|
||||||
|
// before update the expanded element call the call-back method to show up-to-date component
|
||||||
|
await this.onToggleExpandedRow(newExpandedElement, event);
|
||||||
|
|
||||||
|
// assign expanded element
|
||||||
|
this.__expandedElement = newExpandedElement;
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<dd-table [data]="data" [columnsToDisplay]="displayedColumns" [schema]="schema"
|
||||||
|
[paginatorSizeOptions]="[5, 10, 25, 100]" [filter]="{label: 'Filter', placeholder: ''}"
|
||||||
|
[onToggleExpandedRow]="onToggleExpandedRow" [isSortable]="true" [isExpandable]="true" [isFilterable]="true">
|
||||||
|
<mat-tab-group expanded>
|
||||||
|
<mat-tab label="Emfänger">
|
||||||
|
<receiver-status-table></receiver-status-table>
|
||||||
|
</mat-tab>
|
||||||
|
<mat-tab label="History">
|
||||||
|
<history-table></history-table>
|
||||||
|
</mat-tab>
|
||||||
|
</mat-tab-group>
|
||||||
|
</dd-table>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* Structure */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-mdc-form-field {
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For expanding table */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-detail-row {
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):hover {
|
||||||
|
background: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.example-element-row:not(.example-expanded-row):active {
|
||||||
|
background: #efefef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-row td {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-detail {
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-diagram {
|
||||||
|
min-width: 80px;
|
||||||
|
border: 2px solid black;
|
||||||
|
padding: 8px;
|
||||||
|
font-weight: lighter;
|
||||||
|
margin: 8px 0;
|
||||||
|
height: 104px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-symbol {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 40px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.example-element-description-attribution {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import { AfterViewInit, Component, Input, ViewChild, inject, viewChild } from '@angular/core';
|
||||||
|
import { EnvelopeService } from '../../../services/envelope.service';
|
||||||
|
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||||
|
import { ConfigurationService } from '../../../services/configuration.service';
|
||||||
|
import { DDTable } from "../dd-table/dd-table.component";
|
||||||
|
import { ClearableInputComponent } from '../../clearable-input/clearable-input.component'
|
||||||
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
|
import { ReceiverStatusTableComponent } from "../receiver-status-table/receiver-status-table.component";
|
||||||
|
import { HistoryTableComponent } from "../history-table/history-table.component";
|
||||||
|
import { EnvelopeReceiverService } from '../../../services/envelope-receiver.service';
|
||||||
|
import { HistoryService } from '../../../services/history.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'envelope-table',
|
||||||
|
standalone: true,
|
||||||
|
imports: [DDTable, ClearableInputComponent, MatTabsModule, ReceiverStatusTableComponent, HistoryTableComponent],
|
||||||
|
templateUrl: './envelope-table.component.html',
|
||||||
|
animations: [
|
||||||
|
trigger('detailExpand', [
|
||||||
|
state('collapsed,void', style({ height: '0px', minHeight: '0' })),
|
||||||
|
state('expanded', style({ height: '*' })),
|
||||||
|
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
|
||||||
|
]),
|
||||||
|
],
|
||||||
|
styleUrl: './envelope-table.component.scss'
|
||||||
|
})
|
||||||
|
export class EnvelopeTableComponent implements AfterViewInit {
|
||||||
|
|
||||||
|
@Input() options?: { min_status?: number; max_status?: number; ignore_status?: number[] }
|
||||||
|
|
||||||
|
displayedColumns: string[] = ['title', 'status', 'type', 'addedWhen'];
|
||||||
|
|
||||||
|
schema: Record<string, { header: string; field: (element: any) => any; }> = {
|
||||||
|
'title': {
|
||||||
|
header: 'Title',
|
||||||
|
field: (element: any) => element.title
|
||||||
|
},
|
||||||
|
'status': {
|
||||||
|
header: 'Status',
|
||||||
|
field: (element: any) => element.statusName
|
||||||
|
},
|
||||||
|
'type': {
|
||||||
|
header: 'Type',
|
||||||
|
field: (element: any) => this.config.envelopeTypeTitles[element.contractType - 1]
|
||||||
|
},
|
||||||
|
'addedWhen': {
|
||||||
|
header: 'Added When',
|
||||||
|
field: (element: any) => element.addedWhen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data: any[] = [];
|
||||||
|
|
||||||
|
@ViewChild(ReceiverStatusTableComponent) rsTable!: ReceiverStatusTableComponent
|
||||||
|
|
||||||
|
@ViewChild(HistoryTableComponent) histTable!: HistoryTableComponent
|
||||||
|
|
||||||
|
onToggleExpandedRow: (envelope: any, event: Event) => Promise<void> = async (envelope, event) => {
|
||||||
|
if (envelope === null || envelope === undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var uuid: string = envelope.uuid;
|
||||||
|
this.rsTable.data = await this.erService.getSecretAsync(uuid);
|
||||||
|
|
||||||
|
var id: number = envelope.id;
|
||||||
|
var refType: number = this.config.referenceType.receiver;
|
||||||
|
const histories = await this.histService.getHistoryAsync({ envelopeId: id, referenceType: refType, withReceiver: true })
|
||||||
|
this.histTable.data = histories;
|
||||||
|
}
|
||||||
|
|
||||||
|
private eService: EnvelopeService = inject(EnvelopeService);
|
||||||
|
|
||||||
|
private config: ConfigurationService = inject(ConfigurationService);
|
||||||
|
|
||||||
|
private readonly erService: EnvelopeReceiverService = inject(EnvelopeReceiverService);
|
||||||
|
|
||||||
|
private readonly histService: HistoryService = inject(HistoryService);
|
||||||
|
|
||||||
|
async ngAfterViewInit() {
|
||||||
|
this.data = await this.eService.getEnvelopeAsync(this.options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<dd-table [data]="data" [columnsToDisplay]="columnsToDisplay" [schema]="schema" [isSortable]="true"></dd-table>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HistoryTableComponent } from './history-table.component';
|
||||||
|
|
||||||
|
describe('HistoryTableComponent', () => {
|
||||||
|
let component: HistoryTableComponent;
|
||||||
|
let fixture: ComponentFixture<HistoryTableComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [HistoryTableComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(HistoryTableComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { DDTable } from '../dd-table/dd-table.component'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'history-table',
|
||||||
|
standalone: true,
|
||||||
|
imports: [DDTable],
|
||||||
|
templateUrl: './history-table.component.html',
|
||||||
|
styleUrl: './history-table.component.scss'
|
||||||
|
})
|
||||||
|
export class HistoryTableComponent {
|
||||||
|
data: any[] = [];
|
||||||
|
|
||||||
|
schema: Record<string, { header: string; field: (element: any) => any; }> = {
|
||||||
|
"status": {
|
||||||
|
"header": "Status",
|
||||||
|
"field": hist => hist.statusName
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"header": "Benutzer",
|
||||||
|
"field": hist => hist.userReference
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"header": "Datum",
|
||||||
|
"field": hist => hist.actionDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
columnsToDisplay: string[] = ["status", "user", "date"];
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<dd-table [data]="data" [columnsToDisplay]="columnsToDisplay" [schema]="schema" [isSortable]="true"></dd-table>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ReceiverStatusTableComponent } from './receiver-status-table.component';
|
||||||
|
|
||||||
|
describe('ReceiverStatusTableComponent', () => {
|
||||||
|
let component: ReceiverStatusTableComponent;
|
||||||
|
let fixture: ComponentFixture<ReceiverStatusTableComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [ReceiverStatusTableComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ReceiverStatusTableComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { DDTable } from '../dd-table/dd-table.component'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'receiver-status-table',
|
||||||
|
standalone: true,
|
||||||
|
imports: [DDTable],
|
||||||
|
templateUrl: './receiver-status-table.component.html',
|
||||||
|
styleUrl: './receiver-status-table.component.scss'
|
||||||
|
})
|
||||||
|
export class ReceiverStatusTableComponent {
|
||||||
|
data: any[] = [];
|
||||||
|
|
||||||
|
schema: Record<string, { header: string; field: (element: any) => any; }> = {
|
||||||
|
"name": {
|
||||||
|
"header": "Email Anrede",
|
||||||
|
"field": (er) => er.name
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"header": "Email",
|
||||||
|
"field": (er) => er.receiver.emailAddress
|
||||||
|
},
|
||||||
|
"access_code": {
|
||||||
|
"header": "Email",
|
||||||
|
"field": (er) => er.accessCode
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
columnsToDisplay: string[] = ["name", "email", "access_code"];
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<table mat-table [dataSource]="receiverData" class="mat-elevation-z8">
|
||||||
|
<ng-container matColumnDef="email">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Email </th>
|
||||||
|
<td mat-cell *matCellDef="let element; let i = index">
|
||||||
|
<receiver-input [options]="receiver_mails" [filter]="receiver_filter" [index]="i"></receiver-input>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Anrede Email </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<clearable-input [label]="'Anrede Email'" [value]="element.name"></clearable-input>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="accessCode">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> Zugriffscode </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.accessCode}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import { Component, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
|
import { Component, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||||
import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { AsyncPipe } from '@angular/common';
|
import { AsyncPipe } from '@angular/common';
|
||||||
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
import { MatAutocompleteModule } from '@angular/material/autocomplete';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { ReceiverService } from '../../services/receiver.service'
|
import { ReceiverService } from '../../../services/receiver.service'
|
||||||
import { ReceiverInputComponent } from '../receiver-input/receiver-input.component';
|
import { ReceiverInputComponent } from '../../receiver-input/receiver-input.component';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { ClearableInputComponent } from '../clearable-input/clearable-input.component'
|
import { ClearableInputComponent } from '../../clearable-input/clearable-input.component'
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -34,24 +34,41 @@ export class ReceiverTableComponent implements OnInit {
|
|||||||
constructor(private receiverService: ReceiverService) { }
|
constructor(private receiverService: ReceiverService) { }
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.receiver_mails = await this.receiverService.getReceiverAsync().then((receivers: any[]) => receivers.map(r => r.emailAddress));
|
const receivers = await this.receiverService.getReceiverAsync();
|
||||||
|
this.receiver_mails = receivers.map((r: any) => r.emailAddress);
|
||||||
|
this.last_used_name = receivers.reduce((acc: any, r: any) => {
|
||||||
|
acc[r.emailAddress] = r.lastUsedName;
|
||||||
|
return acc;
|
||||||
|
}, {} as { [key: string]: string | null });
|
||||||
}
|
}
|
||||||
|
|
||||||
receiver_filter: (value: string, options: string[]) => string[] = (value, options) => {
|
receiver_filter: (value: string, options: string[], index?: number) => string[] = (value, options, index) => {
|
||||||
const filterValue = value.toLowerCase();
|
const filterValue = value.toLowerCase();
|
||||||
|
|
||||||
|
// set the name if it is used before
|
||||||
|
const name = this.last_used_name[value];
|
||||||
|
|
||||||
|
if (name && index != null && index != undefined) {
|
||||||
|
this.receiverData.at(index)!.name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// !!! do not allow email duplication !!!
|
||||||
|
var similarMails = this.receiver_mails.filter(m => m.toLocaleLowerCase() === value.toLocaleLowerCase() && m !== value)
|
||||||
|
if (similarMails.length > 0 && index != undefined) {
|
||||||
|
this.receiverInputs[index].text = similarMails[0];
|
||||||
|
}
|
||||||
|
|
||||||
// if added into last row
|
// if added into last row
|
||||||
if (value.length > 0 && (this.receiverInputs.at(-1)?.lenght ?? 0) > 0) {
|
if (value.length > 0 && (this.receiverInputs.at(-1)?.lenght ?? 0) > 0) {
|
||||||
this.receiverData.at(-1)!.accessCode = generateAccessCode();
|
this.receiverData.at(-1)!.accessCode = generateAccessCode();
|
||||||
this.receiverData.push({ email: "", name: "", accessCode: "" });
|
this.receiverData.push({ email: "", name: "", accessCode: "" });
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
else if (value.length == 0) {
|
// delete the row with out mail
|
||||||
for (var i = 0; i < this.receiverInputs.length - 1; i++) {
|
else if (value.length === 0 && this.receiverInputs.length - 1 !== index) {
|
||||||
if (this.receiverInputs[i].lenght === 0) {
|
if (this.receiverInputs.length > 1 && this.receiverInputs[index!]?.lenght === 0) {
|
||||||
this.receiverData.splice(i, 1);
|
this.receiverData.splice(index!, 1);
|
||||||
this.update();
|
this.update();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,6 +76,7 @@ export class ReceiverTableComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
receiver_mails: string[] = [];
|
receiver_mails: string[] = [];
|
||||||
|
last_used_name: { [key: string]: string | null } = {};
|
||||||
|
|
||||||
@ViewChildren(ReceiverInputComponent) receiverInputsQueryList!: QueryList<ReceiverInputComponent>;
|
@ViewChildren(ReceiverInputComponent) receiverInputsQueryList!: QueryList<ReceiverInputComponent>;
|
||||||
get receiverInputs(): ReceiverInputComponent[] {
|
get receiverInputs(): ReceiverInputComponent[] {
|
||||||
@@ -5,7 +5,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatStepperModule } from '@angular/material/stepper';
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { ReceiverTableComponent } from "../../components/receiver-table/receiver-table.component";
|
import { ReceiverTableComponent } from "../../components/tables/receiver-table/receiver-table.component";
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<div id="table">
|
<div id="table">
|
||||||
<mat-tab-group>
|
<mat-tab-group>
|
||||||
<mat-tab label="Offene Umschläge">
|
<mat-tab label="Offene Umschläge">
|
||||||
<app-envelope-table [options]="{max_status: Status.EnvelopePartlySigned}"></app-envelope-table>
|
<envelope-table [options]="{max_status: Status.EnvelopePartlySigned}"></envelope-table>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
<mat-tab label="Abgeschlossene Umschläge">
|
<mat-tab label="Abgeschlossene Umschläge">
|
||||||
<app-envelope-table [options]="{min_status: Status.EnvelopeCompletelySigned, ignore_status: [Status.EnvelopeDeleted]}"></app-envelope-table>
|
<envelope-table [options]="{min_status: Status.EnvelopeCompletelySigned, ignore_status: [Status.EnvelopeDeleted]}"></envelope-table>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { EnvelopeTableComponent } from "../../components/envelope-table/envelope-table.component";
|
import { EnvelopeTableComponent } from "../../components/tables/envelope-table/envelope-table.component";
|
||||||
import { MatTabsModule } from '@angular/material/tabs';
|
import { MatTabsModule } from '@angular/material/tabs';
|
||||||
import { LocalizationService } from '../../services/localization.service';
|
import { LocalizationService } from '../../services/localization.service';
|
||||||
import { Status } from '../../enums/envelope-const'
|
import { Status } from '../../enums/envelope-const'
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ConfigurationService } from './configuration.service';
|
||||||
|
|
||||||
|
describe('ConfigurationService', () => {
|
||||||
|
let service: ConfigurationService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(ConfigurationService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Injectable, OnInit, inject } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable, firstValueFrom } from 'rxjs';
|
||||||
|
import { API_URL } from '../tokens/index';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class ConfigurationService implements OnInit {
|
||||||
|
|
||||||
|
protected url: string;
|
||||||
|
|
||||||
|
private _envelopeTypes! : any[];
|
||||||
|
|
||||||
|
private _envelopeTypeTitles! : any[];
|
||||||
|
|
||||||
|
private _referenceType!: any;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
const api_url = inject(API_URL);
|
||||||
|
this.url = `${api_url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit(): Promise<void> {
|
||||||
|
const envelopeTypes$: Observable<any[]> = this.http.get<any[]>(`${this.url}/EnvelopeType`)
|
||||||
|
envelopeTypes$.subscribe({next: res => {
|
||||||
|
this._envelopeTypes = res;
|
||||||
|
this._envelopeTypeTitles = res.map(e => e.title);
|
||||||
|
}});
|
||||||
|
|
||||||
|
this.http.get<any>(`${this.url}/History/reference-type`).subscribe({
|
||||||
|
next: res => this._referenceType = res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public get envelopeTypes() {
|
||||||
|
return this._envelopeTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get envelopeTypeTitles() {
|
||||||
|
return this._envelopeTypeTitles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get referenceType() {
|
||||||
|
return this._referenceType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,8 +27,18 @@ export class EnvelopeReceiverService {
|
|||||||
return this.http.get<any>(this.url, { params });
|
return this.http.get<any>(this.url, { params });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getEnvelopeReceiverAsync(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Promise<any> {
|
getEnvelopeReceiverAsync(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Promise<any> {
|
||||||
return firstValueFrom(this.getEnvelopeReceiver(options));
|
return firstValueFrom(this.getEnvelopeReceiver(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSecret(uuid: string): Observable<any> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
params = params.set('uuid', uuid);
|
||||||
|
|
||||||
|
return this.http.get<any>(`${this.url}/secret`, { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
getSecretAsync(uuid: string): Promise<any> {
|
||||||
|
return firstValueFrom(this.getSecret(uuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { EnvelopeService } from './envelope.service';
|
||||||
|
|
||||||
|
describe('EnvelopeService', () => {
|
||||||
|
let service: EnvelopeService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(EnvelopeService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable, firstValueFrom } from 'rxjs';
|
||||||
|
import { API_URL } from '../tokens/index';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class EnvelopeService {
|
||||||
|
protected url: string;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
const api_url = inject(API_URL);
|
||||||
|
this.url = `${api_url}/envelope`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getEnvelope(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Observable<any> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
if (options) {
|
||||||
|
if (options.min_status)
|
||||||
|
params = params.set('min_status', options.min_status.toString());
|
||||||
|
if (options.max_status)
|
||||||
|
params = params.set('max_status', options.max_status.toString());
|
||||||
|
if (options.ignore_status)
|
||||||
|
params = params.set('ignore_status', options.ignore_status.join(','));
|
||||||
|
}
|
||||||
|
return this.http.get(this.url, { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getEnvelopeAsync(options?: { min_status?: number; max_status?: number; ignore_status?: number[] }): Promise<any> {
|
||||||
|
return await firstValueFrom(this.getEnvelope(options));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { HistoryService } from './history.service';
|
||||||
|
|
||||||
|
describe('HistoryService', () => {
|
||||||
|
let service: HistoryService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(HistoryService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { Injectable, inject } from '@angular/core';
|
||||||
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
|
import { Observable, firstValueFrom } from 'rxjs';
|
||||||
|
import { API_URL } from '../tokens/index';
|
||||||
|
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class HistoryService {
|
||||||
|
protected url: string;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient) {
|
||||||
|
const api_url = inject(API_URL);
|
||||||
|
this.url = `${api_url}/history`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getHistory(options?: Options): Observable<any> {
|
||||||
|
let params = new HttpParams();
|
||||||
|
if (options) {
|
||||||
|
if (options.envelopeId)
|
||||||
|
params = params.set('envelopeId', options.envelopeId);
|
||||||
|
if (options.referenceType != null)
|
||||||
|
params = params.set('referenceType', options.referenceType);
|
||||||
|
if (options.userReference)
|
||||||
|
params = params.set('userReference', options.userReference);
|
||||||
|
if (options.withReceiver)
|
||||||
|
params = params.set('withReceiver', options.withReceiver);
|
||||||
|
if (options.withSender)
|
||||||
|
params = params.set('withSender', options.withSender);
|
||||||
|
}
|
||||||
|
return this.http.get(this.url, { params });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getHistoryAsync(options?: Options): Promise<any> {
|
||||||
|
return firstValueFrom(this.getHistory(options));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Options {
|
||||||
|
envelopeId?: number;
|
||||||
|
userReference?: string;
|
||||||
|
referenceType: number | null = null;
|
||||||
|
withSender?: boolean;
|
||||||
|
withReceiver?: boolean;
|
||||||
|
}
|
||||||
@@ -5,20 +5,20 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
|||||||
{
|
{
|
||||||
public static class ControllerExtensions
|
public static class ControllerExtensions
|
||||||
{
|
{
|
||||||
public static int? GetId(this ControllerBase controller)
|
public static int? GetId(this ClaimsPrincipal user)
|
||||||
=> int.TryParse(controller.User.FindFirst(ClaimTypes.NameIdentifier)?.Value, out int result)
|
=> int.TryParse(user.FindFirst(ClaimTypes.NameIdentifier)?.Value, out int result)
|
||||||
? result : null;
|
? result : null;
|
||||||
|
|
||||||
public static string? GetUsername(this ControllerBase controller)
|
public static string? GetUsername(this ClaimsPrincipal user)
|
||||||
=> controller.User.FindFirst(ClaimTypes.Name)?.Value;
|
=> user.FindFirst(ClaimTypes.Name)?.Value;
|
||||||
|
|
||||||
public static string? GetName(this ControllerBase controller)
|
public static string? GetName(this ClaimsPrincipal user)
|
||||||
=> controller.User.FindFirst(ClaimTypes.Surname)?.Value;
|
=> user.FindFirst(ClaimTypes.Surname)?.Value;
|
||||||
|
|
||||||
public static string? GetPrename(this ControllerBase controller)
|
public static string? GetPrename(this ClaimsPrincipal user)
|
||||||
=> controller.User.FindFirst(ClaimTypes.GivenName)?.Value;
|
=> user.FindFirst(ClaimTypes.GivenName)?.Value;
|
||||||
|
|
||||||
public static string? GetEmail(this ControllerBase controller)
|
public static string? GetEmail(this ClaimsPrincipal user)
|
||||||
=> controller.User.FindFirst(ClaimTypes.Email)?.Value;
|
=> user.FindFirst(ClaimTypes.Email)?.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using DigitalData.Core.DTO;
|
||||||
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class EnvelopeController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<EnvelopeController> _logger;
|
||||||
|
private readonly IEnvelopeService _envelopeService;
|
||||||
|
|
||||||
|
public EnvelopeController(ILogger<EnvelopeController> logger, IEnvelopeService envelopeService)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_envelopeService = envelopeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Authorize]
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetCurrentAsync(
|
||||||
|
[FromQuery] int? min_status = null,
|
||||||
|
[FromQuery] int? max_status = null,
|
||||||
|
[FromQuery] params int[] ignore_statuses)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (User.GetId() is int intId)
|
||||||
|
return await _envelopeService.ReadByUserAsync(intId, min_status: min_status, max_status: max_status, ignore_statuses: ignore_statuses).ThenAsync(
|
||||||
|
Success: Ok,
|
||||||
|
Fail: IActionResult (msg, ntc) =>
|
||||||
|
{
|
||||||
|
_logger.LogNotice(ntc);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
});
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogError("Despite successful authorization, the 'api/envelope' route encountered an issue: the user ID is not recognized as an integer. This may be due to the removal of the ID during the creation of the claims list.");
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "{Message}", ex.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
|
using EnvelopeGenerator.Common.My.Resources;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||||
{
|
{
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
|
[Authorize]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class EnvelopeReceiverController : ControllerBase
|
public class EnvelopeReceiverController : ControllerBase
|
||||||
{
|
{
|
||||||
@@ -17,19 +19,18 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
_erService = envelopeReceiverService;
|
_erService = envelopeReceiverService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize]
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> GetEnvelopeReceiver([FromQuery] int? min_status = null, [FromQuery] int? max_status = null, [FromQuery] int[]? ignore_status = null)
|
public async Task<IActionResult> GetEnvelopeReceiver([FromQuery] int? min_status = null, [FromQuery] int? max_status = null, [FromQuery] int[]? ignore_status = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var username = this.GetUsername();
|
var username = User.GetUsername();
|
||||||
|
|
||||||
if (username is null)
|
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}].",
|
_logger.LogError(@"Envelope Receiver dto cannot be sent because username claim is null. Potential authentication and authorization error. The value of other claims are [id: {id}], [username: {username}], [name: {name}], [prename: {prename}], [email: {email}].",
|
||||||
this.GetId(), this.GetUsername(), this.GetName(), this.GetPrename(), this.GetEmail());
|
User.GetId(), User.GetUsername(), User.GetName(), User.GetPrename(), User.GetEmail());
|
||||||
return StatusCode(StatusCodes.Status500InternalServerError);
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,5 +50,49 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
|||||||
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
|
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("receiver-name/{mail}")]
|
||||||
|
public async Task<IActionResult> GetReceiverName([FromRoute] string mail)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _erService.ReadLastUsedReceiverNameByMail(mail).ThenAsync(
|
||||||
|
Success: res => res is null ? Ok(string.Empty) : Ok(res),
|
||||||
|
Fail: IActionResult (msg, ntc) =>
|
||||||
|
{
|
||||||
|
if (ntc.HasFlag(Flag.NotFound))
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
_logger.LogNotice(ntc);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "{message}", ex.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("secret")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> GetSecretAsync([FromQuery] string uuid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _erService.ReadSecretByUuidAsync(uuid: uuid).ThenAsync(
|
||||||
|
Success: Ok,
|
||||||
|
Fail: IActionResult (msg, ntc) =>
|
||||||
|
{
|
||||||
|
_logger.LogNotice(ntc);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "{message}", ex.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using DigitalData.Core.DTO;
|
||||||
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Security.Cryptography.Xml;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
public class EnvelopeTypeController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<EnvelopeTypeController> _logger;
|
||||||
|
private readonly IEnvelopeTypeService _service;
|
||||||
|
|
||||||
|
public EnvelopeTypeController(ILogger<EnvelopeTypeController> logger, IEnvelopeTypeService service)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAllAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await _service.ReadAllAsync().ThenAsync(
|
||||||
|
Success: Ok,
|
||||||
|
Fail: IActionResult (msg, ntc) =>
|
||||||
|
{
|
||||||
|
_logger.LogNotice(ntc);
|
||||||
|
return ntc.HasFlag(Flag.NotFound) ? NotFound() : StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "{Message}", ex.Message);
|
||||||
|
return StatusCode(StatusCodes.Status500InternalServerError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System;
|
||||||
|
using static EnvelopeGenerator.Common.Constants;
|
||||||
|
|
||||||
|
namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[ApiController]
|
||||||
|
[Authorize]
|
||||||
|
public class HistoryController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<HistoryController> _logger;
|
||||||
|
|
||||||
|
private readonly IEnvelopeHistoryService _service;
|
||||||
|
|
||||||
|
public HistoryController(ILogger<HistoryController> logger, IEnvelopeHistoryService service)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_service = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("reference-type")]
|
||||||
|
[Authorize]
|
||||||
|
public IActionResult GetReferenceTypes()
|
||||||
|
{
|
||||||
|
// Enum to Key-Value pair
|
||||||
|
var referenceTypes = Enum.GetValues(typeof(ReferenceType))
|
||||||
|
.Cast<ReferenceType>()
|
||||||
|
.ToDictionary(rt =>
|
||||||
|
{
|
||||||
|
var key = rt.ToString();
|
||||||
|
var keyAsCamelCase = char.ToLower(key[0]) + key[1..];
|
||||||
|
return keyAsCamelCase;
|
||||||
|
}, rt => (int)rt);
|
||||||
|
|
||||||
|
return Ok(referenceTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> GetAllAsync([FromQuery] int? envelopeId = null, [FromQuery] string? userReference = null, [FromQuery] int? referenceType = null, [FromQuery] bool withSender = false, [FromQuery] bool withReceiver = false)
|
||||||
|
{
|
||||||
|
ReferenceType? refTypEnum = null;
|
||||||
|
|
||||||
|
if (referenceType is int refTypInt)
|
||||||
|
if (Enum.IsDefined(typeof(ReferenceType), refTypInt))
|
||||||
|
refTypEnum = (ReferenceType)refTypInt;
|
||||||
|
else
|
||||||
|
throw new ArgumentException($"The provided referenceType '{referenceType}' is not valid. It must correspond to a valid value in the {nameof(ReferenceType)} enum.");
|
||||||
|
|
||||||
|
switch(referenceType)
|
||||||
|
{
|
||||||
|
case (int)ReferenceType.Receiver:
|
||||||
|
withReceiver = true;
|
||||||
|
break;
|
||||||
|
case (int)ReferenceType.Sender:
|
||||||
|
withSender = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var histories = await _service.ReadAsync(
|
||||||
|
envelopeId: envelopeId,
|
||||||
|
userReference: userReference,
|
||||||
|
referenceType: refTypEnum,
|
||||||
|
withSender: withSender,
|
||||||
|
withReceiver: withReceiver);
|
||||||
|
|
||||||
|
return Ok(histories);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,8 +17,6 @@ namespace EnvelopeGenerator.GeneratorAPI.Controllers
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<IActionResult> Get([FromQuery] string? emailAddress = null, [FromQuery] string? signature = null)
|
public async Task<IActionResult> Get([FromQuery] string? emailAddress = null, [FromQuery] string? signature = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,5 +20,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
|
|||||||
Task<string?> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
|
Task<string?> ReadAccessCodeByIdAsync(int envelopeId, int receiverId);
|
||||||
|
|
||||||
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
Task<IEnumerable<EnvelopeReceiver>> ReadByUsernameAsync(string username, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||||
|
|
||||||
|
Task<EnvelopeReceiver?> ReadLastByReceiver(string email);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,5 +8,7 @@ namespace EnvelopeGenerator.Infrastructure.Contracts
|
|||||||
Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false);
|
||||||
|
|
||||||
Task<Envelope?> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
|
Task<Envelope?> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false);
|
||||||
|
|
||||||
|
Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using DigitalData.Core.Infrastructure;
|
using DigitalData.Core.Infrastructure;
|
||||||
using DigitalData.UserManager.Infrastructure.Repositories;
|
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -14,7 +13,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
|
|
||||||
public async Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false)
|
public async Task<IEnumerable<Envelope>> ReadAllWithAsync(bool documents = false, bool history = false, bool documentReceiverElement = false)
|
||||||
{
|
{
|
||||||
var query = _dbSet.AsQueryable();
|
var query = _dbSet.AsNoTracking();
|
||||||
|
|
||||||
if (documents)
|
if (documents)
|
||||||
if (documentReceiverElement)
|
if (documentReceiverElement)
|
||||||
@@ -30,7 +29,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
|
|
||||||
public async Task<Envelope?> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false)
|
public async Task<Envelope?> ReadByUuidAsync(string uuid, bool withDocuments = false, bool withHistory = false, bool withDocumentReceiverElement = false, bool withUser = false, bool withAll = false)
|
||||||
{
|
{
|
||||||
var query = _dbSet.Where(e => e.Uuid == uuid);
|
var query = _dbSet.AsNoTracking().Where(e => e.Uuid == uuid);
|
||||||
|
|
||||||
if (withAll || withDocuments)
|
if (withAll || withDocuments)
|
||||||
if (withAll || withDocumentReceiverElement)
|
if (withAll || withDocumentReceiverElement)
|
||||||
@@ -46,5 +45,21 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
|
|
||||||
return await query.FirstOrDefaultAsync();
|
return await query.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Envelope>> ReadByUserAsync(int userId, int? min_status = null, int? max_status = null, params int[] ignore_statuses)
|
||||||
|
{
|
||||||
|
var query = _dbSet.AsNoTracking().Where(e => e.UserId == userId);
|
||||||
|
|
||||||
|
if (min_status is not null)
|
||||||
|
query = query.Where(e => e.Status >= min_status);
|
||||||
|
|
||||||
|
if (max_status is not null)
|
||||||
|
query = query.Where(e => e.Status <= max_status);
|
||||||
|
|
||||||
|
foreach (var ignore_status in ignore_statuses)
|
||||||
|
query = query.Where(e => e.Status != ignore_status);
|
||||||
|
|
||||||
|
return await query.ToListAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using DigitalData.Core.Infrastructure;
|
using DigitalData.Core.Infrastructure;
|
||||||
using DigitalData.UserManager.Infrastructure.Repositories;
|
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -76,5 +75,10 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
|
|
||||||
return await query.Include(er => er.Envelope).Include(er => er.Receiver).ToListAsync();
|
return await query.Include(er => er.Envelope).Include(er => er.Receiver).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<EnvelopeReceiver?> ReadLastByReceiver(string email)
|
||||||
|
{
|
||||||
|
return await _dbSet.Where(er => er.Receiver!.EmailAddress == email).OrderBy(er => er.EnvelopeId).LastOrDefaultAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IQueryable<Receiver> ReadBy(string? emailAddress = null, string? signature = null)
|
protected IQueryable<Receiver> ReadBy(string? emailAddress = null, string? signature = null, bool withLastUsedName = true)
|
||||||
{
|
{
|
||||||
IQueryable<Receiver> query = _dbSet.AsNoTracking();
|
IQueryable<Receiver> query = _dbSet.AsNoTracking();
|
||||||
|
|
||||||
@@ -21,9 +21,17 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
|||||||
if(signature is not null)
|
if(signature is not null)
|
||||||
query = query.Where(r => r.Signature == signature);
|
query = query.Where(r => r.Signature == signature);
|
||||||
|
|
||||||
|
// envelope receivers are ignored (with '[JsonIgnore]' attribute). The reson to add them is to get the las used receiver name
|
||||||
|
if (withLastUsedName)
|
||||||
|
{
|
||||||
|
query = query.Include(r => r.EnvelopeReceivers!.OrderByDescending(er => er.EnvelopeId).Take(1));
|
||||||
|
}
|
||||||
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Receiver?> ReadByAsync(string? emailAddress = null, string? signature = null) => await ReadBy(emailAddress, signature).FirstOrDefaultAsync();
|
public async Task<Receiver?> ReadByAsync(string? emailAddress = null, string? signature = null) => await ReadBy(emailAddress, signature).FirstOrDefaultAsync();
|
||||||
|
|
||||||
|
public async override Task<IEnumerable<Receiver>> ReadAllAsync() => await ReadBy().ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,11 +10,11 @@ using DigitalData.Core.API;
|
|||||||
using EnvelopeGenerator.Application;
|
using EnvelopeGenerator.Application;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
|
||||||
using Microsoft.AspNetCore.Localization;
|
using Microsoft.AspNetCore.Localization;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
using EnvelopeGenerator.Web.Models;
|
using EnvelopeGenerator.Web.Models;
|
||||||
using EnvelopeGenerator.Application.Resources;
|
using EnvelopeGenerator.Application.Resources;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers
|
namespace EnvelopeGenerator.Web.Controllers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers.Test
|
namespace EnvelopeGenerator.Web.Controllers.Test
|
||||||
{
|
{
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/test/[controller]")]
|
[Route("api/test/[controller]")]
|
||||||
public class TestEnvelopeMailController : ControllerBase
|
public class TestEnvelopeMailController : ControllerBase
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
using DigitalData.Core.API;
|
using DigitalData.Core.API;
|
||||||
using DigitalData.Core.DTO;
|
using DigitalData.Core.DTO;
|
||||||
using EnvelopeGenerator.Application.Contracts;
|
using EnvelopeGenerator.Application.Contracts;
|
||||||
using EnvelopeGenerator.Application.DTOs;
|
|
||||||
using EnvelopeGenerator.Application;
|
using EnvelopeGenerator.Application;
|
||||||
using EnvelopeGenerator.Domain.Entities;
|
using EnvelopeGenerator.Domain.Entities;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||||
|
|
||||||
namespace EnvelopeGenerator.Web.Controllers.Test
|
namespace EnvelopeGenerator.Web.Controllers.Test
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
@{
|
@{
|
||||||
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
||||||
}
|
}
|
||||||
@using DigitalData.Core.DTO;
|
@ using DigitalData.Core.DTO;
|
||||||
@using EnvelopeGenerator.Application.DTOs;
|
@ using EnvelopeGenerator.Application.DTOs;
|
||||||
@using Newtonsoft.Json
|
@ using Newtonsoft.Json
|
||||||
@using Newtonsoft.Json.Serialization
|
@ using Newtonsoft.Json.Serialization
|
||||||
@model EnvelopeReceiverDto;
|
@model EnvelopeReceiverDto;
|
||||||
<partial name="_CookieConsentPartial" />
|
<partial name="_CookieConsentPartial" />
|
||||||
@{
|
@{
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
@{
|
@{
|
||||||
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
var nonce = _accessor.HttpContext?.Items["csp-nonce"] as string;
|
||||||
}
|
}
|
||||||
@using DigitalData.Core.DTO;
|
@ using DigitalData.Core.DTO;
|
||||||
@using EnvelopeGenerator.Application.DTOs;
|
@ using EnvelopeGenerator.Application.DTOs;
|
||||||
@using Newtonsoft.Json
|
@ using Newtonsoft.Json
|
||||||
@using Newtonsoft.Json.Serialization
|
@ using Newtonsoft.Json.Serialization
|
||||||
@model EnvelopeReceiverDto;
|
@model EnvelopeReceiverDto;
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = _localizer[WebKey.SignDoc];
|
ViewData["Title"] = _localizer[WebKey.SignDoc];
|
||||||
|
|||||||
Reference in New Issue
Block a user