Compare commits
7 Commits
e17f7df930
...
a32f495038
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a32f495038 | ||
|
|
210466883c | ||
|
|
728385b70a | ||
|
|
792aa0b922 | ||
|
|
6847b74095 | ||
|
|
54e86b421c | ||
|
|
370666cb0e |
@@ -22,6 +22,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using EnvelopeGenerator.Domain.Entities;
|
||||
using EnvelopeGenerator.Infrastructure.Contracts;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Application.Services
|
||||
{
|
||||
|
||||
@@ -17,8 +17,9 @@ namespace EnvelopeGenerator.Domain.Entities
|
||||
[Required]
|
||||
public long EnvelopeId { get; init; }
|
||||
|
||||
[ForeignKey("EnvelopeId")]
|
||||
public Envelope? Envelope { get; init; }
|
||||
//TODO: remove NotMapped attribute when EnvelopeId data type is standardized
|
||||
[NotMapped]
|
||||
public Envelope? Envelope { get; set; }
|
||||
|
||||
[Column("RECEIVER_MAIL")]
|
||||
[Required]
|
||||
|
||||
9
EnvelopeGenerator.Extensions/EncodeType.cs
Normal file
9
EnvelopeGenerator.Extensions/EncodeType.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
public enum EncodeType
|
||||
{
|
||||
EnvelopeReceiver,
|
||||
ReadOnly,
|
||||
Undefined
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
|
||||
namespace EnvelopeGenerator.Application
|
||||
namespace EnvelopeGenerator.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides extension methods for decoding and extracting information from an envelope receiver ID.
|
||||
/// </summary>
|
||||
public static class EnvelopeGeneratorExtensions
|
||||
public static class EncodingExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates whether a given string is a correctly formatted Base-64 encoded string.
|
||||
@@ -67,6 +67,36 @@ namespace EnvelopeGenerator.Application
|
||||
return input.IndexOf('=') == -1; // No padding allowed except at the end
|
||||
}
|
||||
|
||||
public static bool TryDecode(this string encoded, out string[] decoded)
|
||||
{
|
||||
if (!encoded.IsBase64String())
|
||||
{
|
||||
decoded = Array.Empty<string>();
|
||||
return false;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(encoded);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
decoded = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static EncodeType GetEncodeType(this string[] decoded) => decoded.Length switch
|
||||
{
|
||||
2 => EncodeType.EnvelopeReceiver,
|
||||
3 => long.TryParse(decoded[1], out var _) ? EncodeType.ReadOnly : EncodeType.Undefined,
|
||||
_ => EncodeType.Undefined,
|
||||
};
|
||||
|
||||
public static (string? EnvelopeUuid, string? ReceiverSignature) ToEnvelopeReceiverId(this string[] decoded)
|
||||
=> decoded.GetEncodeType() == EncodeType.EnvelopeReceiver
|
||||
? (EnvelopeUuid: decoded[0], ReceiverSignature: decoded[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
|
||||
|
||||
public static long ToReadOnlyId(this string[] decoded)
|
||||
=> decoded.GetEncodeType() == EncodeType.ReadOnly
|
||||
? long.Parse(decoded[1])
|
||||
: throw new InvalidOperationException("Attempted to convert a decoded other than type EnvelopeReceiver to EnvelopeReceiver. ");
|
||||
|
||||
/// <summary>
|
||||
/// Decodes the envelope receiver ID and extracts the envelope UUID and receiver signature.
|
||||
/// </summary>
|
||||
@@ -79,7 +109,7 @@ namespace EnvelopeGenerator.Application
|
||||
return (null, null);
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverId);
|
||||
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
string decodedString = Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 1)
|
||||
@@ -88,6 +118,22 @@ namespace EnvelopeGenerator.Application
|
||||
return (string.Empty, string.Empty);
|
||||
}
|
||||
|
||||
public static long? DecodeEnvelopeReceiverReadOnlyId(this string envelopeReceiverReadOnlyId)
|
||||
{
|
||||
if (!envelopeReceiverReadOnlyId.IsBase64String())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
byte[] bytes = Convert.FromBase64String(envelopeReceiverReadOnlyId);
|
||||
string decodedString = System.Text.Encoding.UTF8.GetString(bytes);
|
||||
string[] parts = decodedString.Split(new string[] { "::" }, StringSplitOptions.None);
|
||||
|
||||
if (parts.Length > 2)
|
||||
return long.TryParse(parts[1], out long readOnlyId) ? readOnlyId : null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the envelope UUID from the decoded envelope receiver ID.
|
||||
/// </summary>
|
||||
@@ -111,7 +157,16 @@ namespace EnvelopeGenerator.Application
|
||||
return base64String;
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
public static string EncodeEnvelopeReceiverId(this long readOnlyId)
|
||||
{
|
||||
string combinedString = $"{Random.Shared.Next()}::{readOnlyId}::{Random.Shared.Next()}";
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(combinedString);
|
||||
string base64String = Convert.ToBase64String(bytes);
|
||||
|
||||
return base64String;
|
||||
}
|
||||
|
||||
public static void LogEnvelopeError(this ILogger logger, string envelopeReceiverId, Exception? exception = null, string? message = null, params object?[] args)
|
||||
{
|
||||
var sb = new StringBuilder().AppendLine(envelopeReceiverId.DecodeEnvelopeReceiverId().ToTitle());
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -135,11 +135,6 @@ namespace EnvelopeGenerator.Infrastructure
|
||||
.HasForeignKey(erro => erro.AddedWho)
|
||||
.HasPrincipalKey(r => r.EmailAddress);
|
||||
|
||||
modelBuilder.Entity<EnvelopeReceiverReadOnly>()
|
||||
.HasOne(erro => erro.Envelope)
|
||||
.WithMany()
|
||||
.HasForeignKey(erro => (int) erro.EnvelopeId);
|
||||
|
||||
// Configure entities to handle database triggers
|
||||
modelBuilder.Entity<Envelope>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));
|
||||
modelBuilder.Entity<EnvelopeHistory>().ToTable(tb => tb.HasTrigger("TBSIG_ENVELOPE_HISTORY_AFT_INS"));
|
||||
|
||||
@@ -7,15 +7,46 @@ namespace EnvelopeGenerator.Infrastructure.Repositories
|
||||
{
|
||||
public class EnvelopeReceiverReadOnlyRepository : CRUDRepository<EnvelopeReceiverReadOnly, long, EGDbContext>, IEnvelopeReceiverReadOnlyRepository
|
||||
{
|
||||
public EnvelopeReceiverReadOnlyRepository(EGDbContext dbContext) : base(dbContext, dbContext.EnvelopeReceiverReadOnlys)
|
||||
private readonly IEnvelopeRepository _envRepo;
|
||||
|
||||
public EnvelopeReceiverReadOnlyRepository(EGDbContext dbContext, IEnvelopeRepository envelopeRepository) : base(dbContext, dbContext.EnvelopeReceiverReadOnlys)
|
||||
{
|
||||
_envRepo = envelopeRepository;
|
||||
}
|
||||
|
||||
protected override IQueryable<EnvelopeReceiverReadOnly> ReadOnly()
|
||||
{
|
||||
return base.ReadOnly()
|
||||
.Include(erro => erro.Envelope)
|
||||
//TODO: add again when EnvelopeId data type is standardized
|
||||
//.Include(erro => erro.Envelope)
|
||||
.Include(erro => erro.Receiver);
|
||||
}
|
||||
|
||||
public async override Task<IEnumerable<EnvelopeReceiverReadOnly>> ReadAllAsync()
|
||||
{
|
||||
var erros = await base.ReadAllAsync();
|
||||
return await IncludeEnvelope(erros);
|
||||
}
|
||||
|
||||
//TODO: Use IQueryable.Include instead of this when ID type is clarified.
|
||||
[Obsolete("Use IQueryable.Include instead of this when ID type is clarified.")]
|
||||
private async Task<IEnumerable<EnvelopeReceiverReadOnly>> IncludeEnvelope(params EnvelopeReceiverReadOnly[] erros)
|
||||
{
|
||||
foreach (var erro in erros)
|
||||
erro.Envelope = await _envRepo.ReadByIdAsync((int) erro.EnvelopeId);
|
||||
|
||||
return erros;
|
||||
}
|
||||
|
||||
//TODO: Use IQueryable.Include instead of this when ID type is clarified.
|
||||
[Obsolete("Use IQueryable.Include instead of this when ID type is clarified.")]
|
||||
private async Task<T> IncludeEnvelope<T>(T erros)
|
||||
where T : IEnumerable<EnvelopeReceiverReadOnly>
|
||||
{
|
||||
foreach (var erro in erros)
|
||||
erro.Envelope = await _envRepo.ReadByIdAsync((int)erro.EnvelopeId);
|
||||
|
||||
return erros;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using EnvelopeGenerator.Web.Services;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using EnvelopeGenerator.Application;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers
|
||||
{
|
||||
|
||||
@@ -6,8 +6,8 @@ using EnvelopeGenerator.Web.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Text.Encodings.Web;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeHistory;
|
||||
using static EnvelopeGenerator.Common.Constants;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using DigitalData.Core.API;
|
||||
using EnvelopeGenerator.Application;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using DigitalData.Core.DTO;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
@@ -15,6 +15,8 @@ using System.Text.Encodings.Web;
|
||||
using EnvelopeGenerator.Web.Models;
|
||||
using EnvelopeGenerator.Application.Resources;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers
|
||||
{
|
||||
@@ -29,8 +31,9 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
private readonly UrlEncoder _urlEncoder;
|
||||
private readonly Cultures _cultures;
|
||||
private readonly IEnvelopeMailService _mailService;
|
||||
|
||||
public HomeController(EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, UrlEncoder urlEncoder, Cultures cultures, IEnvelopeMailService envelopeMailService)
|
||||
private readonly IEnvelopeReceiverReadOnlyService _readOnlyService;
|
||||
|
||||
public HomeController(EnvelopeOldService envelopeOldService, ILogger<HomeController> logger, IEnvelopeReceiverService envelopeReceiverService, IEnvelopeHistoryService historyService, IStringLocalizer<Resource> localizer, IConfiguration configuration, UrlEncoder urlEncoder, Cultures cultures, IEnvelopeMailService envelopeMailService, IEnvelopeReceiverReadOnlyService readOnlyService)
|
||||
{
|
||||
this.envelopeOldService = envelopeOldService;
|
||||
_envRcvService = envelopeReceiverService;
|
||||
@@ -41,14 +44,25 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
_cultures = cultures;
|
||||
_mailService = envelopeMailService;
|
||||
_logger = logger;
|
||||
}
|
||||
_readOnlyService = readOnlyService;
|
||||
}
|
||||
|
||||
[HttpGet("EnvelopeKey/{envelopeReceiverId}")]
|
||||
public async Task<IActionResult> SendAccessCode([FromRoute] string envelopeReceiverId)
|
||||
public async Task<IActionResult> MainAsync([FromRoute] string envelopeReceiverId)
|
||||
{
|
||||
try
|
||||
{
|
||||
envelopeReceiverId = _urlEncoder.Encode(envelopeReceiverId);
|
||||
|
||||
if (!envelopeReceiverId.TryDecode(out var decoded))
|
||||
{
|
||||
Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
return this.ViewDocumentNotFound();
|
||||
}
|
||||
|
||||
if(decoded.GetEncodeType() == EncodeType.ReadOnly)
|
||||
return Redirect($"{envelopeReceiverId}/ReadOnly");
|
||||
|
||||
ViewData["EnvelopeKey"] = envelopeReceiverId;
|
||||
|
||||
return await _envRcvService.ReadByEnvelopeReceiverIdAsync(envelopeReceiverId: envelopeReceiverId).ThenAsync<EnvelopeReceiverDto, IActionResult>(
|
||||
@@ -290,7 +304,21 @@ namespace EnvelopeGenerator.Web.Controllers
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("EnvelopeKey/{envelopeReceiverId}/ReadOnly")]
|
||||
public async Task<IActionResult> EnvelopeReceiverReadOnly(string readOnlyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Ok();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.ViewInnerServiceError();
|
||||
}
|
||||
}
|
||||
|
||||
[Authorize]
|
||||
[HttpGet("IsAuthenticated")]
|
||||
public IActionResult IsAuthenticated()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using EnvelopeGenerator.Application;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application.DTOs;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
|
||||
namespace EnvelopeGenerator.Web.Controllers.Test
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using DigitalData.Core.API;
|
||||
using DigitalData.Core.DTO;
|
||||
using EnvelopeGenerator.Application.Contracts;
|
||||
using EnvelopeGenerator.Application;
|
||||
using EnvelopeGenerator.Extensions;
|
||||
using EnvelopeGenerator.Domain.Entities;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using EnvelopeGenerator.Application.DTOs.EnvelopeReceiver;
|
||||
@@ -40,13 +40,27 @@ namespace EnvelopeGenerator.Web.Controllers.Test
|
||||
}
|
||||
|
||||
[HttpGet("decode")]
|
||||
public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId)
|
||||
public IActionResult DecodeEnvelopeReceiverId(string envelopeReceiverId, bool isReadOnly = false)
|
||||
{
|
||||
var decoded = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
return Ok(new { uuid = decoded.EnvelopeUuid, signature = decoded.ReceiverSignature });
|
||||
if (isReadOnly)
|
||||
{
|
||||
var readOnlyId = envelopeReceiverId.DecodeEnvelopeReceiverReadOnlyId();
|
||||
return Ok(new { readOnlyId });
|
||||
}
|
||||
else
|
||||
{
|
||||
var (EnvelopeUuid, ReceiverSignature) = envelopeReceiverId.DecodeEnvelopeReceiverId();
|
||||
return Ok(new { uuid = EnvelopeUuid, signature = ReceiverSignature });
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("encode")]
|
||||
public IActionResult EncodeEnvelopeReceiverId(string uuid, string signature) => Ok((uuid, signature).EncodeEnvelopeReceiverId());
|
||||
public IActionResult EncodeEnvelopeReceiverId(string? uuid = null, string? signature = null, long? readOnlyId = null)
|
||||
{
|
||||
if(readOnlyId is long readOnlyId_long)
|
||||
return Ok(readOnlyId_long.EncodeEnvelopeReceiverId());
|
||||
else
|
||||
return Ok((uuid ?? string.Empty, signature ?? string.Empty).EncodeEnvelopeReceiverId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Application\EnvelopeGenerator.Application.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Common\EnvelopeGenerator.Common.vbproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
|
||||
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.Applicati
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnvelopeGenerator.GeneratorAPI", "EnvelopeGenerator.GeneratorAPI\EnvelopeGenerator.GeneratorAPI.csproj", "{E5E12BA4-60C1-48BA-9053-0F8B62B38124}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EnvelopeGenerator.Extensions", "EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj", "{47F98812-4280-4D53-B04A-2AAEEA5EBC31}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -63,6 +65,10 @@ Global
|
||||
{E5E12BA4-60C1-48BA-9053-0F8B62B38124}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E5E12BA4-60C1-48BA-9053-0F8B62B38124}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E5E12BA4-60C1-48BA-9053-0F8B62B38124}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{47F98812-4280-4D53-B04A-2AAEEA5EBC31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{47F98812-4280-4D53-B04A-2AAEEA5EBC31}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{47F98812-4280-4D53-B04A-2AAEEA5EBC31}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{47F98812-4280-4D53-B04A-2AAEEA5EBC31}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user