From 84ed078eba66f7eb26179202a037dd8205fffce1 Mon Sep 17 00:00:00 2001 From: Nick Beckley Date: Thu, 10 Sep 2026 22:07:16 +0000 Subject: [PATCH] Allow merge activity logging for locations assets and characters --- PlotLine.Tests/Sql/LocationAndAssetMerge.sql | 16 ++++++++ PlotLine.Tests/Sql/ProjectActivityMerge.sql | 38 +++++++++++++++++++ PlotLine/Sql/194_ProjectActivityMergeType.sql | 24 ++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 PlotLine.Tests/Sql/ProjectActivityMerge.sql create mode 100644 PlotLine/Sql/194_ProjectActivityMergeType.sql diff --git a/PlotLine.Tests/Sql/LocationAndAssetMerge.sql b/PlotLine.Tests/Sql/LocationAndAssetMerge.sql index 2d613d1..9a5c4ac 100644 --- a/PlotLine.Tests/Sql/LocationAndAssetMerge.sql +++ b/PlotLine.Tests/Sql/LocationAndAssetMerge.sql @@ -21,6 +21,14 @@ BEGIN TRY INSERT dbo.LocationRelationships(FromLocationID, ToLocationID, LocationRelationshipTypeID) VALUES (@Source,@Target,@RelType),(@Source,@Child,@RelType),(@Target,@Child,@RelType); EXEC dbo.Location_Merge @Source, @Target, @UserID; + -- Exercise the post-merge activity write used by the service, not just the merge procedure. + EXEC dbo.ProjectAudit_Record @ProjectID=@ProjectID, @UserID=@UserID, + @ActivityType=N'Merged', @EntityType=N'Location', @EntityID=@Target, + @EntityName=N'Merge regression target', @Description=N'Merge regression activity'; + IF NOT EXISTS (SELECT 1 FROM dbo.ProjectActivity WHERE ProjectID=@ProjectID + AND EntityType=N'Location' AND EntityID=@Target AND ActivityType=N'Merged') + THROW 51001, 'Location merge activity was not recorded.', 1; + IF NOT EXISTS (SELECT 1 FROM dbo.Locations WHERE LocationID=@Source AND IsArchived=1) THROW 51001, 'Source location was not archived.', 1; IF NOT EXISTS (SELECT 1 FROM dbo.Locations WHERE LocationID=@Child AND ParentLocationID=@Target) THROW 51001, 'Child location was not moved.', 1; IF NOT EXISTS (SELECT 1 FROM dbo.Scenes WHERE SceneID=@SceneID AND PrimaryLocationID=@Target) THROW 51001, 'Primary scene location was not moved.', 1; @@ -45,6 +53,14 @@ BEGIN TRY DECLARE @CustodyID int=SCOPE_IDENTITY(), @DepType int=(SELECT TOP (1) AssetDependencyTypeID FROM dbo.AssetDependencyTypes); INSERT dbo.AssetDependencies(SourceAssetID,TargetAssetID,AssetDependencyTypeID) VALUES (@Source,@Target,@DepType),(@Source,@Other,@DepType),(@Target,@Other,@DepType); EXEC dbo.StoryAsset_Merge @Source,@Target,@UserID; + -- Exercise the post-merge activity write used by the service, not just the merge procedure. + EXEC dbo.ProjectAudit_Record @ProjectID=@ProjectID, @UserID=@UserID, + @ActivityType=N'Merged', @EntityType=N'Asset', @EntityID=@Target, + @EntityName=N'Merge regression target', @Description=N'Merge regression activity'; + IF NOT EXISTS (SELECT 1 FROM dbo.ProjectActivity WHERE ProjectID=@ProjectID + AND EntityType=N'Asset' AND EntityID=@Target AND ActivityType=N'Merged') + THROW 51001, 'Asset merge activity was not recorded.', 1; + IF NOT EXISTS (SELECT 1 FROM dbo.StoryAssets WHERE StoryAssetID=@Source AND IsArchived=1) THROW 51001, 'Source asset was not archived.', 1; IF (SELECT COUNT(*) FROM dbo.AssetAliases WHERE StoryAssetID=@Target) <> 3 THROW 51001, 'Asset names were lost or duplicated.', 1; IF (SELECT COUNT(*) FROM dbo.WordCompanionSceneAssets WHERE SceneID=@SceneID AND StoryAssetID=@Target) <> 1 THROW 51001, 'Duplicate asset scene link.', 1; diff --git a/PlotLine.Tests/Sql/ProjectActivityMerge.sql b/PlotLine.Tests/Sql/ProjectActivityMerge.sql new file mode 100644 index 0000000..b827180 --- /dev/null +++ b/PlotLine.Tests/Sql/ProjectActivityMerge.sql @@ -0,0 +1,38 @@ +-- Exercise the same audit procedure used by the merge services; leave no data behind. +SET XACT_ABORT ON; +BEGIN TRY + BEGIN TRANSACTION; + DECLARE @ProjectID int, @UserID int; + SELECT TOP (1) @ProjectID=ProjectID, @UserID=UserID FROM dbo.ProjectUserAccess WHERE IsActive=1; + IF @ProjectID IS NULL THROW 51001, 'Audit tests require a project with an active user.', 1; + EXEC dbo.ProjectAudit_Record @ProjectID=@ProjectID, @UserID=@UserID, + @ActivityType=N'Merged', @EntityType=N'Character', @EntityName=N'Merge audit regression'; + IF NOT EXISTS (SELECT 1 FROM dbo.ProjectActivity WHERE ProjectID=@ProjectID + AND ActivityType=N'Merged' AND EntityType=N'Character' AND EntityName=N'Merge audit regression') + THROW 51001, 'Character merge activity was not recorded.', 1; + -- Preserve all activity types that were allowed before the merge migration. + INSERT dbo.ProjectActivity(ProjectID,UserID,ActivityType,EntityType,EntityName) + SELECT @ProjectID,@UserID,ActivityType,N'Project',N'Merge audit regression' + FROM (VALUES (N'Created'),(N'Updated'),(N'Deleted'),(N'Archived'),(N'Restored'), + (N'Shared'),(N'CollaboratorRemoved'),(N'Exported')) types(ActivityType); + ROLLBACK TRANSACTION; + SELECT N'PASS: character merge and all existing activity types; fixtures rolled back' AS Result; +END TRY +BEGIN CATCH + IF XACT_STATE() <> 0 ROLLBACK TRANSACTION; + THROW; +END CATCH; +GO +BEGIN TRY + BEGIN TRANSACTION; + DECLARE @ProjectID int=(SELECT TOP (1) ProjectID FROM dbo.Projects); + EXEC dbo.ProjectAudit_Record @ProjectID=@ProjectID, @ActivityType=N'NotAnActivityType', + @EntityType=N'Project', @EntityName=N'Merge audit regression'; + THROW 51001, 'Unknown activity type was accepted.', 1; +END TRY +BEGIN CATCH + IF XACT_STATE() <> 0 ROLLBACK TRANSACTION; + IF ERROR_NUMBER() <> 547 OR ERROR_MESSAGE() NOT LIKE N'%CK_ProjectActivity_ActivityType%' THROW; + SELECT N'PASS: unknown activity types remain rejected; fixtures rolled back' AS Result; +END CATCH; +GO diff --git a/PlotLine/Sql/194_ProjectActivityMergeType.sql b/PlotLine/Sql/194_ProjectActivityMergeType.sql new file mode 100644 index 0000000..1a52ea5 --- /dev/null +++ b/PlotLine/Sql/194_ProjectActivityMergeType.sql @@ -0,0 +1,24 @@ +-- Character, location and asset merge services record a Merged activity after +-- moving references. Permit that activity without weakening the existing rules. +SET XACT_ABORT ON; +SET ANSI_NULLS ON; +SET QUOTED_IDENTIFIER ON; +GO +BEGIN TRY + BEGIN TRANSACTION; + IF EXISTS (SELECT 1 FROM sys.check_constraints + WHERE name = N'CK_ProjectActivity_ActivityType' + AND parent_object_id = OBJECT_ID(N'dbo.ProjectActivity')) + ALTER TABLE dbo.ProjectActivity DROP CONSTRAINT CK_ProjectActivity_ActivityType; + + ALTER TABLE dbo.ProjectActivity WITH CHECK + ADD CONSTRAINT CK_ProjectActivity_ActivityType CHECK + (ActivityType IN (N'Created', N'Updated', N'Deleted', N'Archived', N'Restored', + N'Shared', N'CollaboratorRemoved', N'Exported', N'Merged')); + COMMIT TRANSACTION; +END TRY +BEGIN CATCH + IF XACT_STATE() <> 0 ROLLBACK TRANSACTION; + THROW; +END CATCH; +GO