Compare commits

...

7 Commits

Author SHA1 Message Date
Developer 02
a32f495038 refactor(HomeController): EnvelopeReceiverReadOnly-Endpunkt initialisiert.
- injiziert EnvelopeReceiverReadOnlyService
2024-10-01 18:14:59 +02:00
Developer 02
210466883c refactor(SendAccessCode): Prüfung hinzugefügt, ob die envelope-id schreibgeschützt ist. Wenn ja, Umleitung zu /ReadOnly
- Umbenannt in MainAsync
2024-10-01 17:51:31 +02:00
Developer 02
728385b70a feat(extensions): created extensions project.
- Moved encoding extensions from application to extensions project to increase the abstraction
2024-10-01 17:25:50 +02:00
Developer 02
792aa0b922 feat(decode): Methoden zur Konvertierung des dekodierten Arrays in eine Umschlag-Empfänger-ID und eine Nur-Lese-ID mit Ausnahmewirkung hinzugefügt. 2024-10-01 16:44:46 +02:00
Developer 02
6847b74095 feat(EncodeType): Enum zur Klassifizierung von Kodierungstypen erstellt.
- Erweiterungsmethoden hinzugefügt, um zu versuchen, String mit out-keyworld zu dekodieren.

- Erweiterungsmethode hinzugefügt, um den Typ des Kodierungstyps des dekodierten String-Arrays zu finden.
2024-10-01 16:04:44 +02:00
Developer 02
54e86b421c feat(EnvelopeReceiverReadOnly): Erweiterungsmethode zum Kodieren und Dekodieren von Envelope-Receiver ReadOnly Id hinzugefügt 2024-10-01 15:26:06 +02:00
Developer 02
370666cb0e refactor: EnvelopeReceiverReadOnlyRepository so angepasst, dass die Einbindung von Envelope bis zur Klärung des ID-Typs verschoben wird
- Konstruktor von EnvelopeReceiverReadOnlyRepository angepasst, um IEnvelopeRepository zu akzeptieren.
 - Die Zeile Include(erro => erro.Envelope) in der Methode ReadOnly auskommentiert, bis der EnvelopeId-Typ standardisiert ist.
 - Methoden IncludeEnvelope hinzugefügt, um Envelope manuell für jedes EnvelopeReceiverReadOnly einzubinden.
 - Markierte manuelle Einbindungs-Methoden als veraltet, um durch IQueryable.Include ersetzt zu werden, sobald der EnvelopeId-Typ geklärt ist.
2024-10-01 12:54:27 +02:00
16 changed files with 184 additions and 27 deletions

View File

@@ -22,6 +22,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EnvelopeGenerator.Extensions\EnvelopeGenerator.Extensions.csproj" />
<ProjectReference Include="..\EnvelopeGenerator.Infrastructure\EnvelopeGenerator.Infrastructure.csproj" />
</ItemGroup>

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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]

View File

@@ -0,0 +1,9 @@
namespace EnvelopeGenerator.Extensions
{
public enum EncodeType
{
EnvelopeReceiver,
ReadOnly,
Undefined
}
}

View File

@@ -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());

View File

@@ -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>

View File

@@ -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"));

View File

@@ -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;
}
}
}

View File

@@ -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
{

View File

@@ -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
{

View File

@@ -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()

View File

@@ -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
{

View File

@@ -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());
}
}
}

View File

@@ -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>

View File

@@ -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