9cff87fe85
Remove project bookkeeping citations from shipped code comments across the solution: hyphenated task IDs (WP-14, StoreAndForward-025), milestone/task/ issue refs (M3, Task 4, Audit Log #23, #21), Bundle X task-bundle labels, and C/D/K/S/T phase labels. Comment text only — no code logic, string/log literals, or XML-doc structure changed. Genuine descriptions are preserved (only the citation is stripped), and technical lookalikes are retained (UTF-8, SHA-256, T00:00:00, M365, UTC-5, pre-C4/pre-C5 schema versions). Flagged by the new CommentChecker TaskReferenceInComment / TrackingReferenceInComment checks plus targeted grep passes; full solution builds clean, append-only guard tests pass.
82 lines
4.4 KiB
C#
82 lines
4.4 KiB
C#
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
#nullable disable
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Migrations
|
|
{
|
|
/// <summary>
|
|
/// SMS Notifications: makes a notification recipient's contact path optional and adds
|
|
/// the central SMS-provider (Twilio) configuration table.
|
|
///
|
|
/// 1. <c>NotificationRecipients.EmailAddress</c> becomes nullable — an SMS-only recipient
|
|
/// carries a <c>PhoneNumber</c> and no email. (ALTER COLUMN, naturally idempotent.)
|
|
/// 2. <c>NotificationRecipients.PhoneNumber nvarchar(32) NULL</c> — E.164 phone for SMS
|
|
/// recipients (guarded ADD).
|
|
/// 3. <c>SmsConfigurations</c> table — central-only provider config; <c>AuthToken</c> is
|
|
/// stored encrypted at rest (EncryptedStringConverter → <c>nvarchar(max)</c>, mirroring
|
|
/// <c>SmtpConfigurations.Credentials</c>) (guarded CREATE TABLE).
|
|
///
|
|
/// Every DDL statement is guarded so the migration is safe to re-run against a
|
|
/// partially-migrated database (the repo's idempotent-migration convention; see
|
|
/// AddListAttributeElementType).
|
|
/// </summary>
|
|
public partial class AddSmsNotifications : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
// ALTER COLUMN is naturally idempotent: re-running re-applies the same nullable shape.
|
|
migrationBuilder.Sql("ALTER TABLE [NotificationRecipients] ALTER COLUMN [EmailAddress] nvarchar(500) NULL;");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF NOT EXISTS (SELECT 1 FROM sys.columns WHERE Name='PhoneNumber' AND Object_ID=Object_ID('NotificationRecipients'))
|
|
ALTER TABLE [NotificationRecipients] ADD [PhoneNumber] nvarchar(32) NULL;");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF OBJECT_ID(N'dbo.SmsConfigurations', N'U') IS NULL
|
|
CREATE TABLE [SmsConfigurations] (
|
|
[Id] int NOT NULL IDENTITY(1, 1),
|
|
[AccountSid] nvarchar(100) NOT NULL,
|
|
[AuthToken] nvarchar(max) NULL,
|
|
[FromNumber] nvarchar(32) NOT NULL,
|
|
[MessagingServiceSid] nvarchar(100) NULL,
|
|
[ApiBaseUrl] nvarchar(500) NULL,
|
|
[ConnectionTimeoutSeconds] int NOT NULL,
|
|
[MaxRetries] int NOT NULL,
|
|
[RetryDelay] time NOT NULL,
|
|
CONSTRAINT [PK_SmsConfigurations] PRIMARY KEY ([Id])
|
|
);");
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
// ConfigurationDatabase-NNN: refuse to roll back if SMS-only recipients exist.
|
|
// Such a row carries a PhoneNumber and a (legitimately) NULL EmailAddress. The
|
|
// backfill below sets every NULL EmailAddress to '' so the column can revert to
|
|
// NOT NULL — but for an SMS-only recipient that silently destroys its contact
|
|
// info (PhoneNumber is also dropped) and leaves an invalid empty-string email.
|
|
// This guard MUST run before DROP COLUMN [PhoneNumber], while the column is still
|
|
// queryable, so the operator gets a clear error instead of silent data loss.
|
|
migrationBuilder.Sql(@"
|
|
IF EXISTS (SELECT 1 FROM [NotificationRecipients] WHERE [EmailAddress] IS NULL AND [PhoneNumber] IS NOT NULL)
|
|
THROW 60000, 'Cannot roll back AddSmsNotifications: SMS-only recipients (PhoneNumber set, EmailAddress NULL) exist. Reassign or delete them before rolling back -- otherwise their PhoneNumber would be dropped and EmailAddress backfilled to an invalid empty string.', 1;");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF OBJECT_ID(N'dbo.SmsConfigurations', N'U') IS NOT NULL
|
|
DROP TABLE [SmsConfigurations];");
|
|
|
|
migrationBuilder.Sql(@"
|
|
IF EXISTS (SELECT 1 FROM sys.columns WHERE Name='PhoneNumber' AND Object_ID=Object_ID('NotificationRecipients'))
|
|
ALTER TABLE [NotificationRecipients] DROP COLUMN [PhoneNumber];");
|
|
|
|
// Reversing to NOT NULL requires backfilling existing NULLs first, otherwise the
|
|
// ALTER fails. Mirrors EF's generated default ('') for the previously-required column.
|
|
// The guard above guarantees any remaining NULL here belongs to a pre-existing email
|
|
// recipient that never had an address, not an SMS-only recipient.
|
|
migrationBuilder.Sql("UPDATE [NotificationRecipients] SET [EmailAddress] = '' WHERE [EmailAddress] IS NULL;");
|
|
migrationBuilder.Sql("ALTER TABLE [NotificationRecipients] ALTER COLUMN [EmailAddress] nvarchar(500) NOT NULL;");
|
|
}
|
|
}
|
|
}
|