feat(sms): make FromNumber optional — support Twilio Messaging-Service-only configs (UI-Med-2)
Code-review finding UI-Med-2: the design doc + delivery adapter treat FromNumber and MessagingServiceSid as either-or, but the entity ctor, EF schema, UI and CLI all hard- required FromNumber — so a Messaging-Service-only Twilio config (a normal production setup) could not be created. Bring the implementation into line with the spec: - Commons: SmsConfiguration.FromNumber -> string? (ctor fromNumber optional); UpdateSmsConfigCommand.FromNumber -> string?. - ConfigurationDatabase: FromNumber.IsRequired(false) + migration SmsFromNumberOptional (ALTER COLUMN nullable, idempotent; Down backfills '' — harmless, MsgSid keeps it deliverable) + regenerated model snapshot. - Transport: SmsConfigDto.FromNumber -> string? (round-trips a Messaging-Service-only config). - CentralUI: form validation requires AccountSid + at-least-one-of(FromNumber, MsgSid); nullable create/edit paths; From-number help text. - CLI: --from-number no longer Required; BuildUpdateSmsConfigCommand validates the either-or. - Adapter: From branch null-forgiving (guarded by the existing incomplete-config check). Tests: ManagementActor MsgSid-only persists null FromNumber; CLI MsgSid-only builds + neither-throws + contract (--from-number not Required); CentralUI MsgSid-only save.
This commit is contained in:
@@ -208,11 +208,37 @@ public class NotificationSmsCommandTests
|
||||
public void SmsUpdate_OptionalFlags_AreNotRequired()
|
||||
{
|
||||
var update = SmsUpdate();
|
||||
Assert.False(update.Options.Single(o => o.Name == "--from-number").Required);
|
||||
Assert.False(update.Options.Single(o => o.Name == "--messaging-service-sid").Required);
|
||||
Assert.False(update.Options.Single(o => o.Name == "--api-base-url").Required);
|
||||
Assert.False(update.Options.Single(o => o.Name == "--auth-token").Required);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SmsUpdate_MessagingServiceSidOnly_NoFromNumber_Builds()
|
||||
{
|
||||
// Twilio Messaging-Service-only config: From number omitted, Messaging Service SID
|
||||
// supplied. The either-or validation accepts it and FromNumber maps to null.
|
||||
var parse = Parse(SmsUpdate(),
|
||||
"--id", "3", "--account-sid", "ACmsg", "--messaging-service-sid", "MGonly");
|
||||
|
||||
Assert.Empty(parse.Errors);
|
||||
var cmd = NotificationCommands.BuildUpdateSmsConfigCommand(parse);
|
||||
|
||||
Assert.Null(cmd.FromNumber);
|
||||
Assert.Equal("MGonly", cmd.MessagingServiceSid);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SmsUpdate_NeitherFromNorMessagingService_Throws()
|
||||
{
|
||||
// Neither sender identity supplied => the build rejects it so an SMS config is
|
||||
// never left with no way to send (mirrors the UI + delivery-adapter validation).
|
||||
var parse = Parse(SmsUpdate(), "--id", "4", "--account-sid", "ACnone");
|
||||
|
||||
Assert.Throws<ArgumentException>(() => NotificationCommands.BuildUpdateSmsConfigCommand(parse));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SmsCommands_ResolveViaRegistry()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user