From 4ab608a636670cbdd6d54352cf10224b27f3f91d Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Thu, 11 Jul 2024 08:00:28 +1000 Subject: [PATCH] [AC-2733] Remove AccessAll - misc sprocs (#4477) Remove AccessAll logic from miscellaneous sprocs and corresponding EF queries --- .../OrganizationUserRepository.cs | 5 +- .../CipherReadCanEditByIdUserIdQuery.cs | 16 +- .../Cipher/Cipher_ReadCanEditByIdUserId.sql | 16 +- .../Cipher/Cipher_UpdateCollections.sql | 12 +- .../Folder/Folder_DeleteById.sql | 15 +- ...llectionUser_ReadByOrganizationUserIds.sql | 4 +- ...serUserDetails_ReadWithCollectionsById.sql | 2 +- ...ganizationUser_ReadWithCollectionsById.sql | 2 +- ...024-07-10_00_MiscSprocsRemoveAccessAll.sql | 274 ++++++++++++++++++ 9 files changed, 306 insertions(+), 40 deletions(-) create mode 100644 util/Migrator/DbScripts/2024-07-10_00_MiscSprocsRemoveAccessAll.sql diff --git a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs index 7e1301e2a1..0252e78ae5 100644 --- a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs +++ b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs @@ -161,8 +161,7 @@ public class OrganizationUserRepository : Repository new CollectionAccessSelection { @@ -257,7 +256,7 @@ public class OrganizationUserRepository : Repository new CollectionAccessSelection { diff --git a/src/Infrastructure.EntityFramework/Vault/Repositories/Queries/CipherReadCanEditByIdUserIdQuery.cs b/src/Infrastructure.EntityFramework/Vault/Repositories/Queries/CipherReadCanEditByIdUserIdQuery.cs index 3f0a17180b..76133ed310 100644 --- a/src/Infrastructure.EntityFramework/Vault/Repositories/Queries/CipherReadCanEditByIdUserIdQuery.cs +++ b/src/Infrastructure.EntityFramework/Vault/Repositories/Queries/CipherReadCanEditByIdUserIdQuery.cs @@ -31,8 +31,8 @@ public class CipherReadCanEditByIdUserIdQuery : IQuery from ou in ou_g.DefaultIfEmpty() join cc in dbContext.CollectionCiphers - on new { c.UserId, ou.AccessAll, CipherId = c.Id } equals - new { UserId = (Guid?)null, AccessAll = false, cc.CipherId } into cc_g + on new { c.UserId, CipherId = c.Id } equals + new { UserId = (Guid?)null, cc.CipherId } into cc_g from cc in cc_g.DefaultIfEmpty() join cu in dbContext.CollectionUsers @@ -41,8 +41,8 @@ public class CipherReadCanEditByIdUserIdQuery : IQuery from cu in cu_g.DefaultIfEmpty() join gu in dbContext.GroupUsers - on new { c.UserId, CollectionId = (Guid?)cu.CollectionId, ou.AccessAll, OrganizationUserId = ou.Id } equals - new { UserId = (Guid?)null, CollectionId = (Guid?)null, AccessAll = false, gu.OrganizationUserId } into gu_g + on new { c.UserId, CollectionId = (Guid?)cu.CollectionId, OrganizationUserId = ou.Id } equals + new { UserId = (Guid?)null, CollectionId = (Guid?)null, gu.OrganizationUserId } into gu_g from gu in gu_g.DefaultIfEmpty() join g in dbContext.Groups @@ -50,8 +50,8 @@ public class CipherReadCanEditByIdUserIdQuery : IQuery from g in g_g.DefaultIfEmpty() join cg in dbContext.CollectionGroups - on new { g.AccessAll, cc.CollectionId, gu.GroupId } equals - new { AccessAll = false, cg.CollectionId, cg.GroupId } into cg_g + on new { cc.CollectionId, gu.GroupId } equals + new { cg.CollectionId, cg.GroupId } into cg_g from cg in cg_g.DefaultIfEmpty() where @@ -60,10 +60,10 @@ public class CipherReadCanEditByIdUserIdQuery : IQuery c.UserId == _userId || ( !c.UserId.HasValue && ou.Status == OrganizationUserStatusType.Confirmed && o.Enabled && - (ou.AccessAll || cu.CollectionId != null || g.AccessAll || cg.CollectionId != null) + (cu.CollectionId != null || cg.CollectionId != null) ) ) && - (c.UserId.HasValue || ou.AccessAll || !cu.ReadOnly || g.AccessAll || !cg.ReadOnly) + (c.UserId.HasValue || !cu.ReadOnly || !cg.ReadOnly) select c; return query; } diff --git a/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_ReadCanEditByIdUserId.sql b/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_ReadCanEditByIdUserId.sql index 0c1ad526f4..3eb7f73ccb 100644 --- a/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_ReadCanEditByIdUserId.sql +++ b/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_ReadCanEditByIdUserId.sql @@ -9,8 +9,8 @@ BEGIN ;WITH [CTE] AS ( SELECT - CASE - WHEN C.[UserId] IS NOT NULL OR OU.[AccessAll] = 1 OR CU.[ReadOnly] = 0 OR G.[AccessAll] = 1 OR CG.[ReadOnly] = 0 THEN 1 + CASE + WHEN C.[UserId] IS NOT NULL OR CU.[ReadOnly] = 0 OR CG.[ReadOnly] = 0 THEN 1 ELSE 0 END [Edit] FROM @@ -20,15 +20,15 @@ BEGIN LEFT JOIN [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId LEFT JOIN - [dbo].[CollectionCipher] CC ON C.[UserId] IS NULL AND OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] + [dbo].[CollectionCipher] CC ON C.[UserId] IS NULL AND CC.[CipherId] = C.[Id] LEFT JOIN [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] LEFT JOIN - [dbo].[GroupUser] GU ON C.[UserId] IS NULL AND CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] + [dbo].[GroupUser] GU ON C.[UserId] IS NULL AND CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] LEFT JOIN [dbo].[Group] G ON G.[Id] = GU.[GroupId] LEFT JOIN - [dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] WHERE C.Id = @Id AND ( @@ -38,9 +38,7 @@ BEGIN AND OU.[Status] = 2 -- 2 = Confirmed AND O.[Enabled] = 1 AND ( - OU.[AccessAll] = 1 - OR CU.[CollectionId] IS NOT NULL - OR G.[AccessAll] = 1 + CU.[CollectionId] IS NOT NULL OR CG.[CollectionId] IS NOT NULL ) ) @@ -57,4 +55,4 @@ BEGIN [Edit] = 1 SELECT @CanEdit -END \ No newline at end of file +END diff --git a/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_UpdateCollections.sql b/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_UpdateCollections.sql index 6b5e93dc61..a14ef46de6 100644 --- a/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_UpdateCollections.sql +++ b/src/Sql/Vault/dbo/Stored Procedures/Cipher/Cipher_UpdateCollections.sql @@ -38,21 +38,19 @@ BEGIN INNER JOIN [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId LEFT JOIN - [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = OU.[Id] + [dbo].[CollectionUser] CU ON CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = OU.[Id] LEFT JOIN - [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] + [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] LEFT JOIN [dbo].[Group] G ON G.[Id] = GU.[GroupId] LEFT JOIN - [dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId] + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId] WHERE O.[Id] = @OrganizationId AND O.[Enabled] = 1 AND OU.[Status] = 2 -- Confirmed AND ( - OU.[AccessAll] = 1 - OR CU.[ReadOnly] = 0 - OR G.[AccessAll] = 1 + CU.[ReadOnly] = 0 OR CG.[ReadOnly] = 0 ) END @@ -77,4 +75,4 @@ BEGIN [Id] IN (SELECT [Id] FROM #AvailableCollections) RETURN(0) -END \ No newline at end of file +END diff --git a/src/Sql/Vault/dbo/Stored Procedures/Folder/Folder_DeleteById.sql b/src/Sql/Vault/dbo/Stored Procedures/Folder/Folder_DeleteById.sql index 2c005a4038..d82e92986c 100644 --- a/src/Sql/Vault/dbo/Stored Procedures/Folder/Folder_DeleteById.sql +++ b/src/Sql/Vault/dbo/Stored Procedures/Folder/Folder_DeleteById.sql @@ -10,8 +10,7 @@ BEGIN ;WITH [CTE] AS ( SELECT [Id], - [OrganizationId], - [AccessAll] + [OrganizationId] FROM [OrganizationUser] WHERE @@ -29,20 +28,18 @@ BEGIN INNER JOIN [dbo].[Organization] O ON O.[Id] = OU.[OrganizationId] AND O.[Id] = C.[OrganizationId] AND O.[Enabled] = 1 LEFT JOIN - [dbo].[CollectionCipher] CC ON OU.[AccessAll] = 0 AND CC.[CipherId] = C.[Id] + [dbo].[CollectionCipher] CC ON CC.[CipherId] = C.[Id] LEFT JOIN [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] LEFT JOIN - [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND OU.[AccessAll] = 0 AND GU.[OrganizationUserId] = OU.[Id] + [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] LEFT JOIN [dbo].[Group] G ON G.[Id] = GU.[GroupId] LEFT JOIN - [dbo].[CollectionGroup] CG ON G.[AccessAll] = 0 AND CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] WHERE ( - OU.[AccessAll] = 1 - OR CU.[CollectionId] IS NOT NULL - OR G.[AccessAll] = 1 + CU.[CollectionId] IS NOT NULL OR CG.[CollectionId] IS NOT NULL ) AND JSON_VALUE(C.[Folders], @UserIdPath) = @Id @@ -64,4 +61,4 @@ BEGIN [Id] = @Id EXEC [dbo].[User_BumpAccountRevisionDate] @UserId -END \ No newline at end of file +END diff --git a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserIds.sql b/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserIds.sql index 6982371ee4..c78d7390a7 100644 --- a/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserIds.sql +++ b/src/Sql/dbo/Stored Procedures/CollectionUser_ReadByOrganizationUserIds.sql @@ -9,7 +9,7 @@ BEGIN FROM [dbo].[OrganizationUser] OU INNER JOIN - [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = OU.[Id] + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = OU.[Id] INNER JOIN @OrganizationUserIds OUI ON OUI.[Id] = OU.[Id] -END \ No newline at end of file +END diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUserUserDetails_ReadWithCollectionsById.sql b/src/Sql/dbo/Stored Procedures/OrganizationUserUserDetails_ReadWithCollectionsById.sql index b5550a40dd..b76e4b8775 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUserUserDetails_ReadWithCollectionsById.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUserUserDetails_ReadWithCollectionsById.sql @@ -14,7 +14,7 @@ BEGIN FROM [dbo].[OrganizationUser] OU INNER JOIN - [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = [OU].[Id] + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = [OU].[Id] WHERE [OrganizationUserId] = @Id END diff --git a/src/Sql/dbo/Stored Procedures/OrganizationUser_ReadWithCollectionsById.sql b/src/Sql/dbo/Stored Procedures/OrganizationUser_ReadWithCollectionsById.sql index 56fb360a7c..28b3100cf8 100644 --- a/src/Sql/dbo/Stored Procedures/OrganizationUser_ReadWithCollectionsById.sql +++ b/src/Sql/dbo/Stored Procedures/OrganizationUser_ReadWithCollectionsById.sql @@ -14,7 +14,7 @@ BEGIN FROM [dbo].[OrganizationUser] OU INNER JOIN - [dbo].[CollectionUser] CU ON OU.[AccessAll] = 0 AND CU.[OrganizationUserId] = [OU].[Id] + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = [OU].[Id] WHERE [OrganizationUserId] = @Id END diff --git a/util/Migrator/DbScripts/2024-07-10_00_MiscSprocsRemoveAccessAll.sql b/util/Migrator/DbScripts/2024-07-10_00_MiscSprocsRemoveAccessAll.sql new file mode 100644 index 0000000000..f96a6a4140 --- /dev/null +++ b/util/Migrator/DbScripts/2024-07-10_00_MiscSprocsRemoveAccessAll.sql @@ -0,0 +1,274 @@ +-- Remove AccessAll logic from miscellaneous sprocs + +-- CollectionUser_ReadByOrganizationUserIds +CREATE OR ALTER PROCEDURE [dbo].[CollectionUser_ReadByOrganizationUserIds] + @OrganizationUserIds [dbo].[GuidIdArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + SELECT + CU.* + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = OU.[Id] + INNER JOIN + @OrganizationUserIds OUI ON OUI.[Id] = OU.[Id] +END +GO + +-- OrganizationUser_ReadWithCollectionsById +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUser_ReadWithCollectionsById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + EXEC [OrganizationUser_ReadById] @Id + + SELECT + CU.[CollectionId] Id, + CU.[ReadOnly], + CU.[HidePasswords], + CU.[Manage] + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = [OU].[Id] + WHERE + [OrganizationUserId] = @Id +END +GO + +-- OrganizationUserUserDetails_ReadWithCollectionsById +CREATE OR ALTER PROCEDURE [dbo].[OrganizationUserUserDetails_ReadWithCollectionsById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + EXEC [OrganizationUserUserDetails_ReadById] @Id + + SELECT + CU.[CollectionId] Id, + CU.[ReadOnly], + CU.[HidePasswords], + CU.[Manage] + FROM + [dbo].[OrganizationUser] OU + INNER JOIN + [dbo].[CollectionUser] CU ON CU.[OrganizationUserId] = [OU].[Id] + WHERE + [OrganizationUserId] = @Id +END +GO + +-- Cipher_ReadCanEditByIdUserId +CREATE OR ALTER PROCEDURE [dbo].[Cipher_ReadCanEditByIdUserId] + @Id UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + DECLARE @CanEdit BIT + + ;WITH [CTE] AS ( + SELECT + CASE + WHEN C.[UserId] IS NOT NULL OR CU.[ReadOnly] = 0 OR CG.[ReadOnly] = 0 THEN 1 + ELSE 0 + END [Edit] + FROM + [dbo].[Cipher] C + LEFT JOIN + [dbo].[Organization] O ON C.[UserId] IS NULL AND O.[Id] = C.[OrganizationId] + LEFT JOIN + [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId + LEFT JOIN + [dbo].[CollectionCipher] CC ON C.[UserId] IS NULL AND CC.[CipherId] = C.[Id] + LEFT JOIN + [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[GroupUser] GU ON C.[UserId] IS NULL AND CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[Group] G ON G.[Id] = GU.[GroupId] + LEFT JOIN + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] + WHERE + C.Id = @Id + AND ( + C.[UserId] = @UserId + OR ( + C.[UserId] IS NULL + AND OU.[Status] = 2 -- 2 = Confirmed + AND O.[Enabled] = 1 + AND ( + CU.[CollectionId] IS NOT NULL + OR CG.[CollectionId] IS NOT NULL + ) + ) + ) + ) + SELECT + @CanEdit = CASE + WHEN COUNT(1) > 0 THEN 1 + ELSE 0 + END + FROM + [CTE] + WHERE + [Edit] = 1 + + SELECT @CanEdit +END +GO + +-- Cipher_UpdateCollections +CREATE OR ALTER PROCEDURE [dbo].[Cipher_UpdateCollections] + @Id UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @CollectionIds AS [dbo].[GuidIdArray] READONLY +AS +BEGIN + SET NOCOUNT ON + + IF @OrganizationId IS NULL OR (SELECT COUNT(1) FROM @CollectionIds) < 1 + BEGIN + RETURN(-1) + END + + CREATE TABLE #AvailableCollections ( + [Id] UNIQUEIDENTIFIER + ) + + IF @UserId IS NULL + BEGIN + INSERT INTO #AvailableCollections + SELECT + [Id] + FROM + [dbo].[Collection] + WHERE + [OrganizationId] = @OrganizationId + END + ELSE + BEGIN + INSERT INTO #AvailableCollections + SELECT + C.[Id] + FROM + [dbo].[Collection] C + INNER JOIN + [Organization] O ON O.[Id] = C.[OrganizationId] + INNER JOIN + [dbo].[OrganizationUser] OU ON OU.[OrganizationId] = O.[Id] AND OU.[UserId] = @UserId + LEFT JOIN + [dbo].[CollectionUser] CU ON CU.[CollectionId] = C.[Id] AND CU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[Group] G ON G.[Id] = GU.[GroupId] + LEFT JOIN + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = C.[Id] AND CG.[GroupId] = GU.[GroupId] + WHERE + O.[Id] = @OrganizationId + AND O.[Enabled] = 1 + AND OU.[Status] = 2 -- Confirmed + AND ( + CU.[ReadOnly] = 0 + OR CG.[ReadOnly] = 0 + ) + END + + IF (SELECT COUNT(1) FROM #AvailableCollections) < 1 + BEGIN + -- No writable collections available to share with in this organization. + RETURN(-1) + END + + INSERT INTO [dbo].[CollectionCipher] + ( + [CollectionId], + [CipherId] + ) + SELECT + [Id], + @Id + FROM + @CollectionIds + WHERE + [Id] IN (SELECT [Id] FROM #AvailableCollections) + + RETURN(0) +END +GO + +-- Folder_DeleteById +CREATE OR ALTER PROCEDURE [dbo].[Folder_DeleteById] + @Id UNIQUEIDENTIFIER +AS +BEGIN + SET NOCOUNT ON + + DECLARE @UserId UNIQUEIDENTIFIER = (SELECT TOP 1 [UserId] FROM [dbo].[Folder] WHERE [Id] = @Id) + DECLARE @UserIdPath VARCHAR(50) = CONCAT('$."', @UserId, '"') + + ;WITH [CTE] AS ( + SELECT + [Id], + [OrganizationId] + FROM + [OrganizationUser] + WHERE + [UserId] = @UserId + AND [Status] = 2 -- Confirmed + ) + UPDATE + C + SET + C.[Folders] = JSON_MODIFY(C.[Folders], @UserIdPath, NULL) + FROM + [dbo].[Cipher] C + INNER JOIN + [CTE] OU ON C.[UserId] IS NULL AND C.[OrganizationId] IN (SELECT [OrganizationId] FROM [CTE]) + INNER JOIN + [dbo].[Organization] O ON O.[Id] = OU.[OrganizationId] AND O.[Id] = C.[OrganizationId] AND O.[Enabled] = 1 + LEFT JOIN + [dbo].[CollectionCipher] CC ON CC.[CipherId] = C.[Id] + LEFT JOIN + [dbo].[CollectionUser] CU ON CU.[CollectionId] = CC.[CollectionId] AND CU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[GroupUser] GU ON CU.[CollectionId] IS NULL AND GU.[OrganizationUserId] = OU.[Id] + LEFT JOIN + [dbo].[Group] G ON G.[Id] = GU.[GroupId] + LEFT JOIN + [dbo].[CollectionGroup] CG ON CG.[CollectionId] = CC.[CollectionId] AND CG.[GroupId] = GU.[GroupId] + WHERE + ( + CU.[CollectionId] IS NOT NULL + OR CG.[CollectionId] IS NOT NULL + ) + AND JSON_VALUE(C.[Folders], @UserIdPath) = @Id + + UPDATE + C + SET + C.[Folders] = JSON_MODIFY(C.[Folders], @UserIdPath, NULL) + FROM + [dbo].[Cipher] C + WHERE + [UserId] = @UserId + AND JSON_VALUE([Folders], @UserIdPath) = @Id + + DELETE + FROM + [dbo].[Folder] + WHERE + [Id] = @Id + + EXEC [dbo].[User_BumpAccountRevisionDate] @UserId +END +GO