feat(application): add OAuth2RefreshToken/OAuth2Provider to DTOs; guard refresh token from being overwritten on seed; add OAuth2MappingProfile

This commit is contained in:
2026-08-17 15:05:28 +02:00
parent 6d6e876d94
commit ba8f701223
4 changed files with 53 additions and 1 deletions

View File

@@ -54,8 +54,22 @@ public record EmailAccountDto
public string? OAuth2ClientId { get; set; }
/// <summary>
/// OAuth2 refresh token (Google only). Obtained via OAuth Playground or authorization flow.
/// Leave empty for Microsoft.
/// </summary>
public string? OAuth2RefreshToken { get; set; }
/// <summary>
/// Tenant ID for Microsoft OAuth2 (GUID, full domain, or "common"). Not used for Google.
/// </summary>
public string? OAuth2TenantId { get; set; }
/// <summary>
/// Identifies which OAuth2 identity provider to use when <see cref="UseOAuth2"/> is true.
/// </summary>
public OAuth2Provider OAuth2Provider { get; set; } = OAuth2Provider.None;
/// <summary>
/// The protocol used to receive (sync) incoming emails.
/// </summary>

View File

@@ -57,8 +57,22 @@ public record EmailAccountModificationDto
public string? OAuth2ClientSecret { get; set; }
/// <summary>
/// OAuth2 refresh token (Google only). Obtained via OAuth Playground or authorization flow.
/// Leave empty for Microsoft.
/// </summary>
public string? OAuth2RefreshToken { get; set; }
/// <summary>
/// Tenant ID for Microsoft OAuth2 (GUID, full domain, or "common"). Not used for Google.
/// </summary>
public string? OAuth2TenantId { get; set; }
/// <summary>
/// Identifies which OAuth2 identity provider to use when <see cref="UseOAuth2"/> is true.
/// </summary>
public OAuth2Provider OAuth2Provider { get; set; } = OAuth2Provider.None;
/// <summary>
/// The protocol used to receive (sync) incoming emails.
/// </summary>

View File

@@ -32,7 +32,12 @@ public class EmailMappingProfile : Profile
// EmailAccountDto -> EmailAccount
CreateMap<EmailAccount, EmailAccountDto>();
CreateMap<EmailAccountModificationDto, EmailAccount>();
CreateMap<EmailAccountModificationDto, EmailAccount>()
// Do not overwrite OAuth2RefreshToken if the source value is null or empty.
// This prevents the seed process from erasing a token that was obtained via
// the OAuth2 authorization flow and saved to the database at runtime.
.ForMember(dest => dest.OAuth2RefreshToken,
opt => opt.Condition((src, dest, srcMember) => !string.IsNullOrEmpty(srcMember)));
// ReceivedEmailDto <-> ReceivedEmail
CreateMap<ReceivedEmailDto, ReceivedEmail>()

View File

@@ -0,0 +1,19 @@
#if NET
using AutoMapper;
using DigitalData.MessagingService.Domain.Entities;
namespace DigitalData.MessagingService.Application.Common.Mappings;
/// <summary>
/// AutoMapper profile for OAuth2 operations.
/// Registers EmailAccount self-mapping so UpdateSingleAsync can update an account
/// entity using another EmailAccount instance (e.g. after setting OAuth2RefreshToken).
/// </summary>
public class OAuth2MappingProfile : Profile
{
public OAuth2MappingProfile()
{
CreateMap<EmailAccount, EmailAccount>();
}
}
#endif