diff --git a/src/Sql/dbo/Vault/Functions/CipherDetails.sql b/src/Sql/dbo/Vault/Functions/CipherDetails.sql index ed92c11cb6..7878cf4ce2 100644 --- a/src/Sql/dbo/Vault/Functions/CipherDetails.sql +++ b/src/Sql/dbo/Vault/Functions/CipherDetails.sql @@ -28,6 +28,12 @@ SELECT C.[DeletedDate], C.[Reprompt], C.[Key], - C.[ArchivedDate] + CASE + WHEN + @UserId IS NULL + OR C.[Archives] IS NULL + THEN NULL + ELSE TRY_CONVERT(DATETIME2(7), JSON_VALUE(C.[Archives], CONCAT('$."', @UserId, '"'))) + END [ArchivedDate] FROM - [dbo].[Cipher] C + [dbo].[Cipher] C; \ No newline at end of file diff --git a/src/Sql/dbo/Vault/Functions/UserCipherDetails.sql b/src/Sql/dbo/Vault/Functions/UserCipherDetails.sql index e7933572cd..09b8d32887 100644 --- a/src/Sql/dbo/Vault/Functions/UserCipherDetails.sql +++ b/src/Sql/dbo/Vault/Functions/UserCipherDetails.sql @@ -12,16 +12,29 @@ WITH [CTE] AS ( AND [Status] = 2 -- Confirmed ) SELECT - C.*, + C.Id, + C.UserId, + C.OrganizationId, + C.Type, + C.Data, + C.Attachments, + C.CreationDate, + C.RevisionDate, + C.Favorite, + C.FolderId, + C.DeletedDate, + C.ArchivedDate, + C.Reprompt, + C.[Key], CASE WHEN COALESCE(CU.[ReadOnly], CG.[ReadOnly], 0) = 0 THEN 1 ELSE 0 END [Edit], CASE - WHEN COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0 - THEN 1 - ELSE 0 + WHEN COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0 + THEN 1 + ELSE 0 END [ViewPassword], CASE WHEN COALESCE(CU.[Manage], CG.[Manage], 0) = 1 @@ -56,12 +69,25 @@ WHERE UNION ALL SELECT - *, + C.Id, + C.UserId, + C.OrganizationId, + C.Type, + C.Data, + C.Attachments, + C.CreationDate, + C.RevisionDate, + C.Favorite, + C.FolderId, + C.DeletedDate, + C.ArchivedDate, + C.Reprompt, + C.[Key], 1 [Edit], 1 [ViewPassword], 1 [Manage], 0 [OrganizationUseTotp] FROM - [dbo].[CipherDetails](@UserId) + [dbo].[CipherDetails](@UserId) AS C WHERE - [UserId] = @UserId + C.[UserId] = @UserId; \ No newline at end of file diff --git a/util/Migrator/DbScripts/2025-12-02_AddCipherArchives.sql b/util/Migrator/DbScripts/2025-12-02_AddCipherArchives.sql new file mode 100644 index 0000000000..421fcc4487 --- /dev/null +++ b/util/Migrator/DbScripts/2025-12-02_AddCipherArchives.sql @@ -0,0 +1,162 @@ +-- Add new JSON column for Archives (similar to Favorites/Folders pattern) +IF NOT EXISTS ( + SELECT 1 + FROM sys.columns + WHERE object_id = OBJECT_ID(N'[dbo].[Cipher]') + AND name = 'Archives' +) +BEGIN + ALTER TABLE [dbo].[Cipher] + ADD [Archives] NVARCHAR(MAX) NULL; +END; +GO + +-- Update CipherDetails function to use JSON column approach +IF OBJECT_ID('[dbo].[CipherDetails]') IS NOT NULL +BEGIN + DROP FUNCTION [dbo].[CipherDetails]; +END +GO + +CREATE FUNCTION [dbo].[CipherDetails](@UserId UNIQUEIDENTIFIER) +RETURNS TABLE +AS RETURN +SELECT + C.[Id], + C.[UserId], + C.[OrganizationId], + C.[Type], + C.[Data], + C.[Attachments], + C.[CreationDate], + C.[RevisionDate], + CASE + WHEN + @UserId IS NULL + OR C.[Favorites] IS NULL + OR JSON_VALUE(C.[Favorites], CONCAT('$."', @UserId, '"')) IS NULL + THEN 0 + ELSE 1 + END [Favorite], + CASE + WHEN + @UserId IS NULL + OR C.[Folders] IS NULL + THEN NULL + ELSE TRY_CONVERT(UNIQUEIDENTIFIER, JSON_VALUE(C.[Folders], CONCAT('$."', @UserId, '"'))) + END [FolderId], + C.[DeletedDate], + C.[Reprompt], + C.[Key], + CASE + WHEN + @UserId IS NULL + OR C.[Archives] IS NULL + THEN NULL + ELSE TRY_CONVERT(DATETIME2(7), JSON_VALUE(C.[Archives], CONCAT('$."', @UserId, '"'))) + END [ArchivedDate] +FROM + [dbo].[Cipher] C; +GO + +-- Update UserCipherDetails function +IF OBJECT_ID('[dbo].[UserCipherDetails]') IS NOT NULL +BEGIN + DROP FUNCTION [dbo].[UserCipherDetails]; +END +GO + +CREATE FUNCTION [dbo].[UserCipherDetails](@UserId UNIQUEIDENTIFIER) +RETURNS TABLE +AS RETURN +WITH [CTE] AS ( + SELECT + [Id], + [OrganizationId] + FROM + [OrganizationUser] + WHERE + [UserId] = @UserId + AND [Status] = 2 -- Confirmed +) +SELECT + C.Id, + C.UserId, + C.OrganizationId, + C.Type, + C.Data, + C.Attachments, + C.CreationDate, + C.RevisionDate, + C.Favorite, + C.FolderId, + C.DeletedDate, + C.ArchivedDate, + C.Reprompt, + C.[Key], + CASE + WHEN COALESCE(CU.[ReadOnly], CG.[ReadOnly], 0) = 0 + THEN 1 + ELSE 0 + END [Edit], + CASE + WHEN COALESCE(CU.[HidePasswords], CG.[HidePasswords], 0) = 0 + THEN 1 + ELSE 0 + END [ViewPassword], + CASE + WHEN COALESCE(CU.[Manage], CG.[Manage], 0) = 1 + THEN 1 + ELSE 0 + END [Manage], + CASE + WHEN O.[UseTotp] = 1 + THEN 1 + ELSE 0 + END [OrganizationUseTotp] +FROM + [dbo].[CipherDetails](@UserId) 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 + +UNION ALL + +SELECT + C.Id, + C.UserId, + C.OrganizationId, + C.Type, + C.Data, + C.Attachments, + C.CreationDate, + C.RevisionDate, + C.Favorite, + C.FolderId, + C.DeletedDate, + C.ArchivedDate, + C.Reprompt, + C.[Key], + 1 [Edit], + 1 [ViewPassword], + 1 [Manage], + 0 [OrganizationUseTotp] +FROM + [dbo].[CipherDetails](@UserId) AS C +WHERE + C.[UserId] = @UserId; +GO