SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO IF OBJECT_ID(N'dbo.SubscriptionLevel', N'U') IS NULL BEGIN CREATE TABLE dbo.SubscriptionLevel ( SubscriptionLevelID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_SubscriptionLevel PRIMARY KEY, Name nvarchar(100) NOT NULL, DisplayName nvarchar(100) NOT NULL, Description nvarchar(500) NULL, MaxBooks int NOT NULL, MaxChaptersPerBook int NOT NULL, MaxScenesPerBook int NOT NULL, MaxCharactersPerProject int NOT NULL, MaxStorageMB int NOT NULL, MaxCollaborators int NOT NULL, IsActive bit NOT NULL CONSTRAINT DF_SubscriptionLevel_IsActive DEFAULT 1, SortOrder int NOT NULL, CreatedDateUTC datetime2 NOT NULL CONSTRAINT DF_SubscriptionLevel_CreatedDateUTC DEFAULT SYSUTCDATETIME(), ModifiedDateUTC datetime2 NOT NULL CONSTRAINT DF_SubscriptionLevel_ModifiedDateUTC DEFAULT SYSUTCDATETIME() ); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_SubscriptionLevel_Name' AND object_id = OBJECT_ID(N'dbo.SubscriptionLevel')) CREATE UNIQUE INDEX UX_SubscriptionLevel_Name ON dbo.SubscriptionLevel(Name); GO IF OBJECT_ID(N'dbo.UserSubscription', N'U') IS NULL BEGIN CREATE TABLE dbo.UserSubscription ( UserSubscriptionID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_UserSubscription PRIMARY KEY, UserID int NOT NULL, SubscriptionLevelID int NOT NULL, StartDateUTC datetime2 NOT NULL CONSTRAINT DF_UserSubscription_StartDateUTC DEFAULT SYSUTCDATETIME(), EndDateUTC datetime2 NULL, IsActive bit NOT NULL CONSTRAINT DF_UserSubscription_IsActive DEFAULT 1, IsTrial bit NOT NULL CONSTRAINT DF_UserSubscription_IsTrial DEFAULT 0, TrialExpiryDateUTC datetime2 NULL, CreatedDateUTC datetime2 NOT NULL CONSTRAINT DF_UserSubscription_CreatedDateUTC DEFAULT SYSUTCDATETIME(), ModifiedDateUTC datetime2 NOT NULL CONSTRAINT DF_UserSubscription_ModifiedDateUTC DEFAULT SYSUTCDATETIME(), CONSTRAINT FK_UserSubscription_AppUser FOREIGN KEY (UserID) REFERENCES dbo.AppUser(UserID), CONSTRAINT FK_UserSubscription_SubscriptionLevel FOREIGN KEY (SubscriptionLevelID) REFERENCES dbo.SubscriptionLevel(SubscriptionLevelID) ); END; GO IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'UX_UserSubscription_User_Active' AND object_id = OBJECT_ID(N'dbo.UserSubscription')) CREATE UNIQUE INDEX UX_UserSubscription_User_Active ON dbo.UserSubscription(UserID) WHERE IsActive = 1; GO MERGE dbo.SubscriptionLevel AS target USING (VALUES (N'DraftDesk', N'Draft Desk', N'Trial and evaluation.', 2, 75, 300, 75, 100, 0, 1, 10), (N'WritingRoom', N'Writing Room', N'Standard subscription for most authors.', 10, 150, 1000, 250, 1024, 1, 1, 20), (N'StoryForge', N'Story Forge', N'Professional authors and co-authors.', 30, 200, 2000, 500, 5120, 3, 1, 30), (N'AuthorStudio', N'Author Studio', N'Advanced users and writing teams.', 999999, 999999, 999999, 999999, 20480, 10, 1, 40) ) AS source ( Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook, MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive, SortOrder ) ON target.Name = source.Name WHEN MATCHED THEN UPDATE SET DisplayName = source.DisplayName, Description = source.Description, MaxBooks = source.MaxBooks, MaxChaptersPerBook = source.MaxChaptersPerBook, MaxScenesPerBook = source.MaxScenesPerBook, MaxCharactersPerProject = source.MaxCharactersPerProject, MaxStorageMB = source.MaxStorageMB, MaxCollaborators = source.MaxCollaborators, IsActive = source.IsActive, SortOrder = source.SortOrder, ModifiedDateUTC = SYSUTCDATETIME() WHEN NOT MATCHED THEN INSERT ( Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook, MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive, SortOrder ) VALUES ( source.Name, source.DisplayName, source.Description, source.MaxBooks, source.MaxChaptersPerBook, source.MaxScenesPerBook, source.MaxCharactersPerProject, source.MaxStorageMB, source.MaxCollaborators, source.IsActive, source.SortOrder ); GO DECLARE @AuthorStudioID int; SELECT @AuthorStudioID = SubscriptionLevelID FROM dbo.SubscriptionLevel WHERE Name = N'AuthorStudio'; IF @AuthorStudioID IS NOT NULL BEGIN INSERT INTO dbo.UserSubscription (UserID, SubscriptionLevelID, StartDateUTC, IsActive, IsTrial) SELECT u.UserID, @AuthorStudioID, SYSUTCDATETIME(), 1, 0 FROM dbo.AppUser u WHERE NOT EXISTS ( SELECT 1 FROM dbo.UserSubscription us WHERE us.UserID = u.UserID AND us.IsActive = 1 ); END; GO CREATE OR ALTER PROCEDURE dbo.SubscriptionLevel_ListActive AS BEGIN SET NOCOUNT ON; SELECT SubscriptionLevelID, Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook, MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive, SortOrder, CreatedDateUTC, ModifiedDateUTC FROM dbo.SubscriptionLevel WHERE IsActive = 1 ORDER BY SortOrder, DisplayName; END; GO CREATE OR ALTER PROCEDURE dbo.SubscriptionLevel_Get @SubscriptionLevelID int AS BEGIN SET NOCOUNT ON; SELECT SubscriptionLevelID, Name, DisplayName, Description, MaxBooks, MaxChaptersPerBook, MaxScenesPerBook, MaxCharactersPerProject, MaxStorageMB, MaxCollaborators, IsActive, SortOrder, CreatedDateUTC, ModifiedDateUTC FROM dbo.SubscriptionLevel WHERE SubscriptionLevelID = @SubscriptionLevelID; END; GO CREATE OR ALTER PROCEDURE dbo.UserSubscription_GetCurrent @UserID int AS BEGIN SET NOCOUNT ON; SELECT us.UserSubscriptionID, us.UserID, us.SubscriptionLevelID, us.StartDateUTC, us.EndDateUTC, us.IsActive, us.IsTrial, us.TrialExpiryDateUTC, us.CreatedDateUTC, us.ModifiedDateUTC, sl.Name, sl.DisplayName, sl.Description, sl.MaxBooks, sl.MaxChaptersPerBook, sl.MaxScenesPerBook, sl.MaxCharactersPerProject, sl.MaxStorageMB, sl.MaxCollaborators, sl.IsActive AS SubscriptionLevelIsActive, sl.SortOrder FROM dbo.UserSubscription us INNER JOIN dbo.SubscriptionLevel sl ON sl.SubscriptionLevelID = us.SubscriptionLevelID WHERE us.UserID = @UserID AND us.IsActive = 1 AND (us.EndDateUTC IS NULL OR us.EndDateUTC > SYSUTCDATETIME()); END; GO CREATE OR ALTER PROCEDURE dbo.UserSubscription_AssignDefaultDraftDesk @UserID int AS BEGIN SET NOCOUNT ON; DECLARE @DraftDeskID int; SELECT @DraftDeskID = SubscriptionLevelID FROM dbo.SubscriptionLevel WHERE Name = N'DraftDesk'; IF @DraftDeskID IS NULL RETURN; IF NOT EXISTS ( SELECT 1 FROM dbo.UserSubscription WHERE UserID = @UserID AND IsActive = 1 ) BEGIN INSERT INTO dbo.UserSubscription (UserID, SubscriptionLevelID, StartDateUTC, IsActive, IsTrial) VALUES (@UserID, @DraftDeskID, SYSUTCDATETIME(), 1, 0); END; END; GO CREATE OR ALTER PROCEDURE dbo.User_Create @Email nvarchar(256), @DisplayName nvarchar(200), @PasswordHash nvarchar(max), @EmailConfirmed bit = 0 AS BEGIN SET NOCOUNT ON; INSERT INTO dbo.AppUser (Email, DisplayName, PasswordHash, EmailConfirmed) VALUES (@Email, @DisplayName, @PasswordHash, @EmailConfirmed); DECLARE @UserID int = SCOPE_IDENTITY(); EXEC dbo.UserSubscription_AssignDefaultDraftDesk @UserID = @UserID; EXEC dbo.User_GetById @UserID = @UserID; END; GO