using Microsoft.EntityFrameworkCore; namespace Backend.Data; public static class OperationalTablesBootstrapper { public static Task EnsureAsync(AwardsDbContext db) => db.Database.ExecuteSqlRawAsync( """ ALTER TABLE "UserSessions" ADD COLUMN IF NOT EXISTS "CreatedFromIp" character varying(80) NOT NULL DEFAULT ''; ALTER TABLE "UserSessions" ADD COLUMN IF NOT EXISTS "UserAgent" character varying(400) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "RiskRulesJson" text NOT NULL DEFAULT '[]'; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "WorkflowRulesJson" text NOT NULL DEFAULT '[]'; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "NominationLinkBlacklistJson" text NOT NULL DEFAULT '[]'; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ClipSubmissionsEnabled" boolean NOT NULL DEFAULT false; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ClipReviewEnabled" boolean NOT NULL DEFAULT true; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ClipSubmissionDisabledMessage" character varying(240) NOT NULL DEFAULT 'Clip-Einreichungen sind aktuell geschlossen.'; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ShowactApplicationsEnabled" boolean NOT NULL DEFAULT false; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ShowactApplicationDisabledMessage" character varying(240) NOT NULL DEFAULT 'Showact-Bewerbungen sind aktuell geschlossen.'; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "SponsorsVisible" boolean NOT NULL DEFAULT true; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "TwitchAuthManagedByDatabase" boolean NOT NULL DEFAULT false; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "TwitchClientId" character varying(120) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "TwitchClientSecret" character varying(180) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "TwitchRedirectUri" character varying(400) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "TwitchScope" character varying(300) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ImprintContent" text NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ContactContent" text NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "SponsorsContent" text NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ShowactsUrl" character varying(400) NOT NULL DEFAULT ''; ALTER TABLE "SiteSettings" ADD COLUMN IF NOT EXISTS "ShowactsContent" text NOT NULL DEFAULT ''; CREATE TABLE IF NOT EXISTS "RiskFlags" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "SeasonId" integer NULL, "TwitchUserId" character varying(120) NULL, "Source" character varying(80) NOT NULL, "Type" character varying(80) NOT NULL, "Severity" character varying(20) NOT NULL, "Status" character varying(20) NOT NULL, "Summary" character varying(240) NOT NULL, "CreatedFromIp" character varying(80) NOT NULL, "UserAgent" character varying(400) NOT NULL, "MetadataJson" text NOT NULL, "ReviewNote" character varying(500) NULL, "ReviewedByTwitchId" character varying(120) NULL, "CreatedAt" timestamp with time zone NOT NULL, "ReviewedAt" timestamp with time zone NULL ); ALTER TABLE "RiskFlags" ADD COLUMN IF NOT EXISTS "ReviewNote" character varying(500) NULL; CREATE INDEX IF NOT EXISTS "IX_RiskFlags_Status_CreatedAt" ON "RiskFlags" ("Status", "CreatedAt" DESC); CREATE INDEX IF NOT EXISTS "IX_RiskFlags_SeasonId" ON "RiskFlags" ("SeasonId"); CREATE TABLE IF NOT EXISTS "AdminAuditEntries" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "AdminTwitchUserId" character varying(120) NOT NULL, "ActionType" character varying(80) NOT NULL, "EntityType" character varying(80) NOT NULL, "EntityId" character varying(120) NOT NULL, "Summary" character varying(240) NOT NULL, "MetadataJson" text NOT NULL, "CreatedFromIp" character varying(80) NOT NULL DEFAULT '', "UserAgent" character varying(400) NOT NULL DEFAULT '', "CreatedAt" timestamp with time zone NOT NULL ); ALTER TABLE "AdminAuditEntries" ADD COLUMN IF NOT EXISTS "CreatedFromIp" character varying(80) NOT NULL DEFAULT ''; ALTER TABLE "AdminAuditEntries" ADD COLUMN IF NOT EXISTS "UserAgent" character varying(400) NOT NULL DEFAULT ''; CREATE INDEX IF NOT EXISTS "IX_AdminAuditEntries_CreatedAt" ON "AdminAuditEntries" ("CreatedAt" DESC); CREATE TABLE IF NOT EXISTS "ClipSubmissions" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "SeasonId" integer NOT NULL, "CategoryId" integer NULL, "SubmittedByTwitchId" character varying(120) NOT NULL, "ClipUrl" character varying(500) NOT NULL, "Title" character varying(200) NOT NULL, "Creator" character varying(120) NOT NULL, "Platform" character varying(40) NOT NULL, "Status" character varying(20) NOT NULL, "CreatedFromIp" character varying(80) NOT NULL, "CreatedAt" timestamp with time zone NOT NULL ); ALTER TABLE "ClipSubmissions" ADD COLUMN IF NOT EXISTS "CandidateId" integer NULL; ALTER TABLE "ClipSubmissions" ADD COLUMN IF NOT EXISTS "ReviewNote" character varying(500) NULL; ALTER TABLE "ClipSubmissions" ADD COLUMN IF NOT EXISTS "ReviewedByTwitchId" character varying(120) NULL; ALTER TABLE "ClipSubmissions" ADD COLUMN IF NOT EXISTS "ReviewedAt" timestamp with time zone NULL; CREATE INDEX IF NOT EXISTS "IX_ClipSubmissions_SeasonId_Status" ON "ClipSubmissions" ("SeasonId", "Status"); CREATE INDEX IF NOT EXISTS "IX_ClipSubmissions_CandidateId" ON "ClipSubmissions" ("CandidateId"); CREATE TABLE IF NOT EXISTS "ShowactApplications" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "SeasonId" integer NOT NULL, "ArtistName" character varying(120) NOT NULL, "ContactEmail" character varying(180) NOT NULL, "ContactDiscord" character varying(120) NOT NULL, "PlatformUrl" character varying(500) NOT NULL, "PerformanceType" character varying(80) NOT NULL, "Description" character varying(1000) NOT NULL, "TechnicalNotes" character varying(1000) NOT NULL, "ReferenceUrl" character varying(500) NOT NULL, "Status" character varying(20) NOT NULL, "ReviewNote" character varying(500) NULL, "ReviewedByTwitchId" character varying(120) NULL, "CreatedFromIp" character varying(80) NOT NULL, "UserAgent" character varying(400) NOT NULL, "CreatedAt" timestamp with time zone NOT NULL, "ReviewedAt" timestamp with time zone NULL ); CREATE INDEX IF NOT EXISTS "IX_ShowactApplications_SeasonId_Status" ON "ShowactApplications" ("SeasonId", "Status"); CREATE TABLE IF NOT EXISTS "Sponsors" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "SeasonId" integer NOT NULL, "Name" character varying(120) NOT NULL, "WebsiteUrl" character varying(500) NOT NULL, "LogoUrl" character varying(500) NOT NULL, "Description" character varying(500) NOT NULL, "Tier" character varying(80) NOT NULL, "SortOrder" integer NOT NULL, "IsVisible" boolean NOT NULL, "CreatedAt" timestamp with time zone NOT NULL, "UpdatedAt" timestamp with time zone NULL ); CREATE INDEX IF NOT EXISTS "IX_Sponsors_SeasonId_IsVisible_SortOrder" ON "Sponsors" ("SeasonId", "IsVisible", "SortOrder"); DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'FK_ShowactApplications_Seasons_SeasonId' ) THEN ALTER TABLE "ShowactApplications" ADD CONSTRAINT "FK_ShowactApplications_Seasons_SeasonId" FOREIGN KEY ("SeasonId") REFERENCES "Seasons" ("Id") ON DELETE CASCADE; END IF; END $$; DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'FK_Sponsors_Seasons_SeasonId' ) THEN ALTER TABLE "Sponsors" ADD CONSTRAINT "FK_Sponsors_Seasons_SeasonId" FOREIGN KEY ("SeasonId") REFERENCES "Seasons" ("Id") ON DELETE CASCADE; END IF; END $$; DO $$ BEGIN IF NOT EXISTS ( SELECT 1 FROM pg_constraint WHERE conname = 'FK_ClipSubmissions_Candidates_CandidateId' ) THEN ALTER TABLE "ClipSubmissions" ADD CONSTRAINT "FK_ClipSubmissions_Candidates_CandidateId" FOREIGN KEY ("CandidateId") REFERENCES "Candidates" ("Id") ON DELETE SET NULL; END IF; END $$; ALTER TABLE "Nominations" ADD COLUMN IF NOT EXISTS "StreamUrl" character varying(300) NULL; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "AcceptanceStatus" character varying(30) NOT NULL DEFAULT 'open'; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "AcceptanceNote" character varying(500) NULL; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "ClipCompilationUrl" character varying(500) NULL; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "ClipCompilationTitle" character varying(200) NULL; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "ClipCompilationPlatform" character varying(40) NULL; ALTER TABLE "Candidates" ADD COLUMN IF NOT EXISTS "ClipEmbedStatus" character varying(30) NOT NULL DEFAULT 'unchecked'; ALTER TABLE "Nominations" ADD COLUMN IF NOT EXISTS "Status" character varying(20) NOT NULL DEFAULT 'pending'; ALTER TABLE "Nominations" ADD COLUMN IF NOT EXISTS "ReviewNote" character varying(500) NULL; ALTER TABLE "Nominations" ADD COLUMN IF NOT EXISTS "ReviewedByTwitchId" character varying(120) NULL; ALTER TABLE "Nominations" ADD COLUMN IF NOT EXISTS "ReviewedAt" timestamp with time zone NULL; CREATE INDEX IF NOT EXISTS "IX_Nominations_SeasonId_Status" ON "Nominations" ("SeasonId", "Status"); CREATE TABLE IF NOT EXISTS "TeamMembers" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "Login" character varying(80) NOT NULL, "DisplayName" character varying(120) NOT NULL, "Role" character varying(40) NOT NULL, "PasswordHash" character varying(120) NOT NULL, "PasswordSalt" character varying(80) NOT NULL, "BoundTwitchUserId" character varying(120) NULL, "BoundTwitchDisplayName" character varying(120) NULL, "MustChangePassword" boolean NOT NULL, "IsActive" boolean NOT NULL, "CreatedByTwitchId" character varying(120) NOT NULL, "UpdatedByTwitchId" character varying(120) NULL, "CreatedAt" timestamp with time zone NOT NULL, "UpdatedAt" timestamp with time zone NULL, "LastLoginAt" timestamp with time zone NULL, "TwitchBoundAt" timestamp with time zone NULL, "PasswordResetAt" timestamp with time zone NULL ); ALTER TABLE "TeamMembers" ADD COLUMN IF NOT EXISTS "BoundTwitchUserId" character varying(120) NULL; ALTER TABLE "TeamMembers" ADD COLUMN IF NOT EXISTS "BoundTwitchDisplayName" character varying(120) NULL; ALTER TABLE "TeamMembers" ADD COLUMN IF NOT EXISTS "TwitchBoundAt" timestamp with time zone NULL; CREATE UNIQUE INDEX IF NOT EXISTS "IX_TeamMembers_Login" ON "TeamMembers" ("Login"); CREATE UNIQUE INDEX IF NOT EXISTS "IX_TeamMembers_BoundTwitchUserId" ON "TeamMembers" ("BoundTwitchUserId") WHERE "BoundTwitchUserId" IS NOT NULL; CREATE TABLE IF NOT EXISTS "TeamRolePermissions" ( "Id" integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "Role" character varying(40) NOT NULL, "PermissionsJson" text NOT NULL, "UpdatedByTwitchId" character varying(120) NOT NULL, "UpdatedAt" timestamp with time zone NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS "IX_TeamRolePermissions_Role" ON "TeamRolePermissions" ("Role"); """); }