SET ANSI_NULLS ON; GO SET QUOTED_IDENTIFIER ON; GO CREATE OR ALTER PROCEDURE dbo.Project_ListOwnedForAccountDeletion @UserID int AS BEGIN SET NOCOUNT ON; SELECT p.ProjectID, p.ProjectName, p.Description, p.CreatedDate, p.UpdatedDate, p.IsArchived, p.ArchivedDate, p.ArchivedReason, pua.AccessRole FROM dbo.Projects p INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE pua.UserID = @UserID AND pua.AccessRole = N'Owner' AND pua.IsActive = 1 ORDER BY p.ProjectID; END; GO CREATE OR ALTER PROCEDURE dbo.ProjectHardDelete_ListFilePathsForAccountDeletion @ProjectID int, @UserID int AS BEGIN SET NOCOUNT ON; IF NOT EXISTS ( SELECT 1 FROM dbo.Projects p INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE p.ProjectID = @ProjectID AND pua.UserID = @UserID AND pua.AccessRole = N'Owner' AND pua.IsActive = 1 ) RETURN; SELECT DISTINCT StoragePath FROM dbo.UserFile WHERE ProjectID = @ProjectID AND NULLIF(LTRIM(RTRIM(StoragePath)), N'') IS NOT NULL UNION SELECT DISTINCT sa.FilePath FROM dbo.SceneAttachments sa INNER JOIN dbo.Scenes s ON s.SceneID = sa.SceneID INNER JOIN dbo.Chapters c ON c.ChapterID = s.ChapterID INNER JOIN dbo.Books b ON b.BookID = c.BookID WHERE b.ProjectID = @ProjectID AND NULLIF(LTRIM(RTRIM(sa.FilePath)), N'') IS NOT NULL; END; GO CREATE OR ALTER PROCEDURE dbo.ProjectHardDelete_ForAccountDeletion @ProjectID int, @UserID int AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; IF NOT EXISTS ( SELECT 1 FROM dbo.Projects p INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE p.ProjectID = @ProjectID AND pua.UserID = @UserID AND pua.AccessRole = N'Owner' AND pua.IsActive = 1 ) THROW 52101, 'Project was not found for this account owner.', 1; BEGIN TRY BEGIN TRANSACTION; UPDATE dbo.Projects SET IsArchived = 1, ArchivedDate = COALESCE(ArchivedDate, SYSUTCDATETIME()), ArchivedReason = COALESCE(ArchivedReason, N'Account deletion') WHERE ProjectID = @ProjectID; EXEC dbo.ProjectHardDelete_ForOwner @ProjectID = @ProjectID, @UserID = @UserID; COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH END; GO CREATE OR ALTER PROCEDURE dbo.UserHardDelete_ListFilePaths @UserID int AS BEGIN SET NOCOUNT ON; IF NOT EXISTS (SELECT 1 FROM dbo.AppUser WHERE UserID = @UserID) RETURN; SELECT DISTINCT StoragePath FROM dbo.UserFile WHERE UserID = @UserID AND NULLIF(LTRIM(RTRIM(StoragePath)), N'') IS NOT NULL; END; GO CREATE OR ALTER PROCEDURE dbo.UserHardDelete_ForAccountDeletion @UserID int AS BEGIN SET NOCOUNT ON; SET XACT_ABORT ON; DECLARE @Email nvarchar(256); SELECT @Email = Email FROM dbo.AppUser WHERE UserID = @UserID; IF @Email IS NULL BEGIN SELECT CAST(0 AS bit); RETURN; END; IF EXISTS ( SELECT 1 FROM dbo.Projects p INNER JOIN dbo.ProjectUserAccess pua ON pua.ProjectID = p.ProjectID WHERE pua.UserID = @UserID AND pua.AccessRole = N'Owner' AND pua.IsActive = 1 ) THROW 52102, 'All owned projects must be deleted before deleting the account.', 1; BEGIN TRY BEGIN TRANSACTION; DELETE FROM dbo.EmailQueue WHERE ToEmail = @Email; DELETE FROM dbo.ProjectInvitation WHERE InvitedByUserID = @UserID OR AcceptedByUserID = @UserID OR EmailAddress = @Email; DELETE FROM dbo.ProjectActivity WHERE UserID = @UserID; UPDATE dbo.ProjectUserAccess SET InvitedByUserID = NULL WHERE InvitedByUserID = @UserID; DELETE FROM dbo.ProjectUserAccess WHERE UserID = @UserID; DELETE FROM dbo.UserFile WHERE UserID = @UserID; DELETE FROM dbo.UserSubscription WHERE UserID = @UserID; DELETE FROM dbo.UserTwoFactor WHERE UserID = @UserID; DELETE FROM dbo.UserEmailVerificationToken WHERE UserID = @UserID; DELETE FROM dbo.UserPasswordResetToken WHERE UserID = @UserID; DELETE FROM dbo.UserLoginAudit WHERE UserID = @UserID OR EmailAttempted = @Email; DELETE FROM dbo.AppUser WHERE UserID = @UserID; DECLARE @Deleted bit = CASE WHEN @@ROWCOUNT = 1 THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END; COMMIT TRANSACTION; SELECT @Deleted; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; THROW; END CATCH END; GO