diff --git a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs index 3c45afe530..ebe39852f4 100644 --- a/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs +++ b/src/Infrastructure.EntityFramework/Vault/Repositories/CipherRepository.cs @@ -704,6 +704,9 @@ public class CipherRepository : Repository suts, + List efUserRepos, + List efOrgRepos, + List efCollectionRepos) + { + foreach (var sut in suts) + { + var i = suts.IndexOf(sut); + + var postEfOrg = await efOrgRepos[i].CreateAsync(org); + efOrgRepos[i].ClearChangeTracking(); + var postEfUser = await efUserRepos[i].CreateAsync(user); + efUserRepos[i].ClearChangeTracking(); + + collection.OrganizationId = postEfOrg.Id; + var postEfCollection = await efCollectionRepos[i].CreateAsync(collection); + efCollectionRepos[i].ClearChangeTracking(); + + cipher.UserId = postEfUser.Id; + cipher.OrganizationId = null; + cipher.Folders = $"{{\"{postEfUser.Id}\":\"some-folder-id\"}}"; + cipher.Favorites = $"{{\"{postEfUser.Id}\":true}}"; + cipher.Reprompt = Core.Vault.Enums.CipherRepromptType.Password; + + var createdCipher = await sut.CreateAsync(cipher); + sut.ClearChangeTracking(); + + var updatedCipher = await sut.GetByIdAsync(createdCipher.Id); + updatedCipher.UserId = postEfUser.Id; + updatedCipher.OrganizationId = postEfOrg.Id; + updatedCipher.Folders = $"{{\"{postEfUser.Id}\":\"new-folder-id\"}}"; + updatedCipher.Favorites = $"{{\"{postEfUser.Id}\":true}}"; + updatedCipher.Reprompt = Core.Vault.Enums.CipherRepromptType.Password; + + await sut.ReplaceAsync(updatedCipher, new List { postEfCollection.Id }); + sut.ClearChangeTracking(); + + + var savedCipher = await sut.GetByIdAsync(createdCipher.Id); + Assert.NotNull(savedCipher); + Assert.Null(savedCipher.UserId); + Assert.Equal(postEfOrg.Id, savedCipher.OrganizationId); + Assert.Equal($"{{\"{postEfUser.Id}\":\"new-folder-id\"}}", savedCipher.Folders); + Assert.Equal($"{{\"{postEfUser.Id}\":true}}", savedCipher.Favorites); + Assert.Equal(Core.Vault.Enums.CipherRepromptType.Password, savedCipher.Reprompt); + } + } } diff --git a/util/Migrator/DbScripts/2025-11-17_00_ShareFavoriteFolderReprompt.sql b/util/Migrator/DbScripts/2025-11-17_00_ShareFavoriteFolderReprompt.sql new file mode 100644 index 0000000000..6d4ea668a3 --- /dev/null +++ b/util/Migrator/DbScripts/2025-11-17_00_ShareFavoriteFolderReprompt.sql @@ -0,0 +1,62 @@ +CREATE OR ALTER PROCEDURE [dbo].[Cipher_UpdateWithCollections] + @Id UNIQUEIDENTIFIER, + @UserId UNIQUEIDENTIFIER, + @OrganizationId UNIQUEIDENTIFIER, + @Type TINYINT, + @Data NVARCHAR(MAX), + @Favorites NVARCHAR(MAX), + @Folders NVARCHAR(MAX), + @Attachments NVARCHAR(MAX), + @CreationDate DATETIME2(7), + @RevisionDate DATETIME2(7), + @DeletedDate DATETIME2(7), + @Reprompt TINYINT, + @Key VARCHAR(MAX) = NULL, + @CollectionIds AS [dbo].[GuidIdArray] READONLY, + @ArchivedDate DATETIME2(7) = NULL +AS +BEGIN + SET NOCOUNT ON + + BEGIN TRANSACTION Cipher_UpdateWithCollections + + DECLARE @UpdateCollectionsSuccess INT + EXEC @UpdateCollectionsSuccess = [dbo].[Cipher_UpdateCollections] @Id, @UserId, @OrganizationId, @CollectionIds + + IF @UpdateCollectionsSuccess < 0 + BEGIN + COMMIT TRANSACTION Cipher_UpdateWithCollections + SELECT -1 -- -1 = Failure + RETURN + END + + UPDATE + [dbo].[Cipher] + SET + [UserId] = NULL, + [OrganizationId] = @OrganizationId, + [Data] = @Data, + [Attachments] = @Attachments, + [RevisionDate] = @RevisionDate, + [DeletedDate] = @DeletedDate, + [Key] = @Key, + [ArchivedDate] = @ArchivedDate, + [Folders] = @Folders, + [Favorites] = @Favorites, + [Reprompt] = @Reprompt + -- No need to update CreationDate or Type since that data will not change + WHERE + [Id] = @Id + + COMMIT TRANSACTION Cipher_UpdateWithCollections + + IF @Attachments IS NOT NULL + BEGIN + EXEC [dbo].[Organization_UpdateStorage] @OrganizationId + EXEC [dbo].[User_UpdateStorage] @UserId + END + + EXEC [dbo].[User_BumpAccountRevisionDateByCipherId] @Id, @OrganizationId + + SELECT 0 -- 0 = Success +END