fix(transport): carry Transport + OAuth2 authority/scope on SmtpConfigDto (OAuth2 fields were silently dropped)
This commit is contained in:
@@ -266,6 +266,12 @@ public sealed class ArtifactDiff
|
||||
AddIfDifferent(changes, "MaxConcurrentConnections", existing.MaxConcurrentConnections, incoming.MaxConcurrentConnections);
|
||||
AddIfDifferent(changes, "MaxRetries", existing.MaxRetries, incoming.MaxRetries);
|
||||
AddIfDifferent(changes, "RetryDelay", existing.RetryDelay.ToString(), incoming.RetryDelay.ToString());
|
||||
// Non-sensitive delivery metadata: diffed by value (unlike the credential,
|
||||
// which is presence-only below). Both sides null on pre-EWS bundles, so a
|
||||
// legacy configuration still classifies Identical.
|
||||
AddIfDifferent(changes, "OAuth2Authority", existing.OAuth2Authority, incoming.OAuth2Authority);
|
||||
AddIfDifferent(changes, "OAuth2Scope", existing.OAuth2Scope, incoming.OAuth2Scope);
|
||||
AddIfDifferent(changes, "Transport", existing.Transport, incoming.Transport);
|
||||
|
||||
var existingHasSecret = !string.IsNullOrEmpty(existing.Credentials);
|
||||
var incomingHasSecret = incoming.Secrets is not null && incoming.Secrets.Values.ContainsKey("Credentials");
|
||||
|
||||
@@ -3437,6 +3437,11 @@ public sealed class BundleImporter : IBundleImporter
|
||||
target.MaxConcurrentConnections = dto.MaxConcurrentConnections;
|
||||
target.MaxRetries = dto.MaxRetries;
|
||||
target.RetryDelay = dto.RetryDelay;
|
||||
// Non-sensitive delivery metadata; null on a bundle written before these
|
||||
// were carried, which is the entity's "provider defaults / Smtp" state.
|
||||
target.OAuth2Authority = dto.OAuth2Authority;
|
||||
target.OAuth2Scope = dto.OAuth2Scope;
|
||||
target.Transport = dto.Transport;
|
||||
target.Credentials = dto.Secrets?.Values.TryGetValue("Credentials", out var cred) == true ? cred : null;
|
||||
}
|
||||
|
||||
|
||||
@@ -285,6 +285,12 @@ public sealed record NotificationRecipientDto(
|
||||
// WhenWritingNull policy keeps it out of email-only bundles' JSON.
|
||||
string? PhoneNumber = null);
|
||||
|
||||
/// <summary>
|
||||
/// An email delivery configuration (the <c>SmtpConfiguration</c> entity). Every
|
||||
/// non-sensitive field is carried directly and only the credential (SMTP password
|
||||
/// or OAuth2 client secret) rides inside <see cref="Secrets"/>, so a future
|
||||
/// "share without secrets" export can drop it as a unit.
|
||||
/// </summary>
|
||||
public sealed record SmtpConfigDto(
|
||||
string Host,
|
||||
int Port,
|
||||
@@ -295,7 +301,17 @@ public sealed record SmtpConfigDto(
|
||||
int MaxConcurrentConnections,
|
||||
int MaxRetries,
|
||||
TimeSpan RetryDelay,
|
||||
SecretsBlock? Secrets);
|
||||
SecretsBlock? Secrets,
|
||||
// OAuth2 token-endpoint authority and scope: endpoint URLs, not secrets, so
|
||||
// they belong on the public DTO rather than in the SecretsBlock. Trailing +
|
||||
// nullable so a bundle written before these were carried deserializes them as
|
||||
// null (= provider defaults); WhenWritingNull keeps them out of the JSON of
|
||||
// configurations that don't set them.
|
||||
string? OAuth2Authority = null,
|
||||
string? OAuth2Scope = null,
|
||||
// Delivery transport ("Smtp" or "Ews"); null means Smtp. Trailing + nullable
|
||||
// for the same additive-evolution reason — no bundleFormatVersion bump.
|
||||
string? Transport = null);
|
||||
|
||||
/// <summary>
|
||||
/// An SMS provider configuration (the <c>SmsConfiguration</c> entity). Mirrors
|
||||
|
||||
@@ -186,7 +186,12 @@ public sealed class EntitySerializer
|
||||
MaxConcurrentConnections: smtp.MaxConcurrentConnections,
|
||||
MaxRetries: smtp.MaxRetries,
|
||||
RetryDelay: smtp.RetryDelay,
|
||||
Secrets: secrets);
|
||||
Secrets: secrets,
|
||||
// Non-sensitive delivery metadata: the OAuth2 endpoint pair and
|
||||
// the Smtp/Ews transport selector travel as plain DTO fields.
|
||||
OAuth2Authority: smtp.OAuth2Authority,
|
||||
OAuth2Scope: smtp.OAuth2Scope,
|
||||
Transport: smtp.Transport);
|
||||
}).ToList(),
|
||||
// Inbound API keys are not transported between environments:
|
||||
// the bundle carries API methods only. ApiMethod.ApprovedApiKeyIds is also
|
||||
@@ -486,6 +491,11 @@ public sealed class EntitySerializer
|
||||
MaxConcurrentConnections = dto.MaxConcurrentConnections,
|
||||
MaxRetries = dto.MaxRetries,
|
||||
RetryDelay = dto.RetryDelay,
|
||||
// Null on a bundle written before these fields were carried, which
|
||||
// is exactly the entity's "use the provider defaults / Smtp" state.
|
||||
OAuth2Authority = dto.OAuth2Authority,
|
||||
OAuth2Scope = dto.OAuth2Scope,
|
||||
Transport = dto.Transport,
|
||||
})
|
||||
.ToList();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user