mirror of
https://github.com/bitwarden/server
synced 2025-12-16 00:03:54 +00:00
[PM-24954] [PM-24955] Remove BulkResourceCreationService Feature Flag (#6428)
* chore: remove ff implementation and superflous tests, refs PM-24954 * chore: remove UpdateForKeyRotation vNext, refs PM-24954 * chore: remove CreateAsync vNext for ImportCiphersCommand, refs PM-24954 * chore: remove UpdateCiphersAsync vNext from CipherService, refs PM-24954 * chore: formatting, refs PM-24954 * chore: fix CipherRepositoryTests by removing vNext references, refs PM-24954 * chore: remove bulk cipher copy ff key, refs PM-24954
This commit is contained in:
@@ -141,7 +141,6 @@ public static class FeatureFlagKeys
|
|||||||
public const string SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions";
|
public const string SeparateCustomRolePermissions = "pm-19917-separate-custom-role-permissions";
|
||||||
public const string CreateDefaultLocation = "pm-19467-create-default-location";
|
public const string CreateDefaultLocation = "pm-19467-create-default-location";
|
||||||
public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache";
|
public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache";
|
||||||
public const string CipherRepositoryBulkResourceCreation = "pm-24951-cipher-repository-bulk-resource-creation-service";
|
|
||||||
|
|
||||||
/* Auth Team */
|
/* Auth Team */
|
||||||
public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence";
|
public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence";
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
|||||||
private readonly IdentityErrorDescriber _identityErrorDescriber;
|
private readonly IdentityErrorDescriber _identityErrorDescriber;
|
||||||
private readonly IWebAuthnCredentialRepository _credentialRepository;
|
private readonly IWebAuthnCredentialRepository _credentialRepository;
|
||||||
private readonly IPasswordHasher<User> _passwordHasher;
|
private readonly IPasswordHasher<User> _passwordHasher;
|
||||||
private readonly IFeatureService _featureService;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiates a new <see cref="RotateUserAccountKeysCommand"/>
|
/// Instantiates a new <see cref="RotateUserAccountKeysCommand"/>
|
||||||
@@ -61,7 +60,6 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
|||||||
_identityErrorDescriber = errors;
|
_identityErrorDescriber = errors;
|
||||||
_credentialRepository = credentialRepository;
|
_credentialRepository = credentialRepository;
|
||||||
_passwordHasher = passwordHasher;
|
_passwordHasher = passwordHasher;
|
||||||
_featureService = featureService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -103,15 +101,7 @@ public class RotateUserAccountKeysCommand : IRotateUserAccountKeysCommand
|
|||||||
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
|
List<UpdateEncryptedDataForKeyRotation> saveEncryptedDataActions = new();
|
||||||
if (model.Ciphers.Any())
|
if (model.Ciphers.Any())
|
||||||
{
|
{
|
||||||
var useBulkResourceCreationService = _featureService.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation);
|
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation(user.Id, model.Ciphers));
|
||||||
if (useBulkResourceCreationService)
|
|
||||||
{
|
|
||||||
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation_vNext(user.Id, model.Ciphers));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
saveEncryptedDataActions.Add(_cipherRepository.UpdateForKeyRotation(user.Id, model.Ciphers));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model.Folders.Any())
|
if (model.Folders.Any())
|
||||||
|
|||||||
@@ -108,15 +108,7 @@ public class ImportCiphersCommand : IImportCiphersCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create it all
|
// Create it all
|
||||||
var useBulkResourceCreationService = _featureService.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation);
|
await _cipherRepository.CreateAsync(importingUserId, ciphers, newFolders);
|
||||||
if (useBulkResourceCreationService)
|
|
||||||
{
|
|
||||||
await _cipherRepository.CreateAsync_vNext(importingUserId, ciphers, newFolders);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _cipherRepository.CreateAsync(importingUserId, ciphers, newFolders);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push
|
// push
|
||||||
await _pushService.PushSyncVaultAsync(importingUserId);
|
await _pushService.PushSyncVaultAsync(importingUserId);
|
||||||
@@ -191,15 +183,7 @@ public class ImportCiphersCommand : IImportCiphersCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create it all
|
// Create it all
|
||||||
var useBulkResourceCreationService = _featureService.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation);
|
await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers, newCollectionUsers);
|
||||||
if (useBulkResourceCreationService)
|
|
||||||
{
|
|
||||||
await _cipherRepository.CreateAsync_vNext(ciphers, newCollections, collectionCiphers, newCollectionUsers);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _cipherRepository.CreateAsync(ciphers, newCollections, collectionCiphers, newCollectionUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push
|
// push
|
||||||
await _pushService.PushSyncVaultAsync(importingUserId);
|
await _pushService.PushSyncVaultAsync(importingUserId);
|
||||||
|
|||||||
@@ -33,28 +33,12 @@ public interface ICipherRepository : IRepository<Cipher, Guid>
|
|||||||
Task DeleteByUserIdAsync(Guid userId);
|
Task DeleteByUserIdAsync(Guid userId);
|
||||||
Task DeleteByOrganizationIdAsync(Guid organizationId);
|
Task DeleteByOrganizationIdAsync(Guid organizationId);
|
||||||
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
|
Task UpdateCiphersAsync(Guid userId, IEnumerable<Cipher> ciphers);
|
||||||
/// <inheritdoc cref="UpdateCiphersAsync(Guid, IEnumerable{Cipher})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// This version uses the bulk resource creation service to create the temp table.
|
|
||||||
/// </remarks>
|
|
||||||
Task UpdateCiphersAsync_vNext(Guid userId, IEnumerable<Cipher> ciphers);
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create ciphers and folders for the specified UserId. Must not be used to create organization owned items.
|
/// Create ciphers and folders for the specified UserId. Must not be used to create organization owned items.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task CreateAsync(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
Task CreateAsync(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
||||||
/// <inheritdoc cref="CreateAsync(Guid, IEnumerable{Cipher}, IEnumerable{Folder})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// This version uses the bulk resource creation service to create the temp tables.
|
|
||||||
/// </remarks>
|
|
||||||
Task CreateAsync_vNext(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders);
|
|
||||||
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
||||||
IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers);
|
IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers);
|
||||||
/// <inheritdoc cref="CreateAsync(IEnumerable{Cipher}, IEnumerable{Collection}, IEnumerable{CollectionCipher}, IEnumerable{CollectionUser})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// This version uses the bulk resource creation service to create the temp tables.
|
|
||||||
/// </remarks>
|
|
||||||
Task CreateAsync_vNext(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
|
||||||
IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers);
|
|
||||||
Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId);
|
Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId);
|
||||||
Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
|
Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
|
||||||
Task<DateTime> UnarchiveAsync(IEnumerable<Guid> ids, Guid userId);
|
Task<DateTime> UnarchiveAsync(IEnumerable<Guid> ids, Guid userId);
|
||||||
@@ -92,10 +76,4 @@ public interface ICipherRepository : IRepository<Cipher, Guid>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Task<IEnumerable<CipherOrganizationDetailsWithCollections>>
|
Task<IEnumerable<CipherOrganizationDetailsWithCollections>>
|
||||||
GetManyCipherOrganizationDetailsExcludingDefaultCollectionsAsync(Guid organizationId);
|
GetManyCipherOrganizationDetailsExcludingDefaultCollectionsAsync(Guid organizationId);
|
||||||
/// <inheritdoc cref="UpdateForKeyRotation(Guid, IEnumerable{Cipher})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// This version uses the bulk resource creation service to create the temp table.
|
|
||||||
/// </remarks>
|
|
||||||
UpdateEncryptedDataForKeyRotation UpdateForKeyRotation_vNext(Guid userId,
|
|
||||||
IEnumerable<Cipher> ciphers);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -644,15 +644,7 @@ public class CipherService : ICipherService
|
|||||||
cipherIds.Add(cipher.Id);
|
cipherIds.Add(cipher.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
var useBulkResourceCreationService = _featureService.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation);
|
await _cipherRepository.UpdateCiphersAsync(sharingUserId, cipherInfos.Select(c => c.cipher));
|
||||||
if (useBulkResourceCreationService)
|
|
||||||
{
|
|
||||||
await _cipherRepository.UpdateCiphersAsync_vNext(sharingUserId, cipherInfos.Select(c => c.cipher));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _cipherRepository.UpdateCiphersAsync(sharingUserId, cipherInfos.Select(c => c.cipher));
|
|
||||||
}
|
|
||||||
await _collectionCipherRepository.UpdateCollectionsForCiphersAsync(cipherIds, sharingUserId,
|
await _collectionCipherRepository.UpdateCollectionsForCiphersAsync(cipherIds, sharingUserId,
|
||||||
organizationId, collectionIds);
|
organizationId, collectionIds);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ using Bit.Core.Vault.Models.Data;
|
|||||||
using Bit.Core.Vault.Repositories;
|
using Bit.Core.Vault.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.AdminConsole.Helpers;
|
using Bit.Infrastructure.Dapper.AdminConsole.Helpers;
|
||||||
using Bit.Infrastructure.Dapper.Repositories;
|
using Bit.Infrastructure.Dapper.Repositories;
|
||||||
using Bit.Infrastructure.Dapper.Vault.Helpers;
|
|
||||||
using Dapper;
|
using Dapper;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
@@ -383,63 +382,6 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
|||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bulk copy data into temp table
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "#TempCipher";
|
|
||||||
var ciphersTable = ciphers.ToDataTable();
|
|
||||||
foreach (DataColumn col in ciphersTable.Columns)
|
|
||||||
{
|
|
||||||
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
|
|
||||||
}
|
|
||||||
|
|
||||||
ciphersTable.PrimaryKey = new DataColumn[] { ciphersTable.Columns[0] };
|
|
||||||
await bulkCopy.WriteToServerAsync(ciphersTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update cipher table from temp table
|
|
||||||
var sql = @"
|
|
||||||
UPDATE
|
|
||||||
[dbo].[Cipher]
|
|
||||||
SET
|
|
||||||
[Data] = TC.[Data],
|
|
||||||
[Attachments] = TC.[Attachments],
|
|
||||||
[RevisionDate] = TC.[RevisionDate],
|
|
||||||
[Key] = TC.[Key]
|
|
||||||
FROM
|
|
||||||
[dbo].[Cipher] C
|
|
||||||
INNER JOIN
|
|
||||||
#TempCipher TC ON C.Id = TC.Id
|
|
||||||
WHERE
|
|
||||||
C.[UserId] = @UserId
|
|
||||||
|
|
||||||
DROP TABLE #TempCipher";
|
|
||||||
|
|
||||||
await using (var cmd = new SqlCommand(sql, connection, transaction))
|
|
||||||
{
|
|
||||||
cmd.Parameters.Add("@UserId", SqlDbType.UniqueIdentifier).Value = userId;
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation_vNext(
|
|
||||||
Guid userId, IEnumerable<Cipher> ciphers)
|
|
||||||
{
|
|
||||||
return async (SqlConnection connection, SqlTransaction transaction) =>
|
|
||||||
{
|
|
||||||
// Create temp table
|
|
||||||
var sqlCreateTemp = @"
|
|
||||||
SELECT TOP 0 *
|
|
||||||
INTO #TempCipher
|
|
||||||
FROM [dbo].[Cipher]";
|
|
||||||
|
|
||||||
await using (var cmd = new SqlCommand(sqlCreateTemp, connection, transaction))
|
|
||||||
{
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bulk copy data into temp table
|
// Bulk copy data into temp table
|
||||||
await BulkResourceCreationService.CreateTempCiphersAsync(connection, transaction, ciphers);
|
await BulkResourceCreationService.CreateTempCiphersAsync(connection, transaction, ciphers);
|
||||||
|
|
||||||
@@ -476,88 +418,6 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
|
||||||
{
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using (var transaction = connection.BeginTransaction())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 1. Create temp tables to bulk copy into.
|
|
||||||
|
|
||||||
var sqlCreateTemp = @"
|
|
||||||
SELECT TOP 0 *
|
|
||||||
INTO #TempCipher
|
|
||||||
FROM [dbo].[Cipher]";
|
|
||||||
|
|
||||||
using (var cmd = new SqlCommand(sqlCreateTemp, connection, transaction))
|
|
||||||
{
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Bulk copy into temp tables.
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "#TempCipher";
|
|
||||||
var dataTable = BuildCiphersTable(bulkCopy, ciphers);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Insert into real tables from temp tables and clean up.
|
|
||||||
|
|
||||||
// Intentionally not including Favorites, Folders, and CreationDate
|
|
||||||
// since those are not meant to be bulk updated at this time
|
|
||||||
var sql = @"
|
|
||||||
UPDATE
|
|
||||||
[dbo].[Cipher]
|
|
||||||
SET
|
|
||||||
[UserId] = TC.[UserId],
|
|
||||||
[OrganizationId] = TC.[OrganizationId],
|
|
||||||
[Type] = TC.[Type],
|
|
||||||
[Data] = TC.[Data],
|
|
||||||
[Attachments] = TC.[Attachments],
|
|
||||||
[RevisionDate] = TC.[RevisionDate],
|
|
||||||
[DeletedDate] = TC.[DeletedDate],
|
|
||||||
[Key] = TC.[Key]
|
|
||||||
FROM
|
|
||||||
[dbo].[Cipher] C
|
|
||||||
INNER JOIN
|
|
||||||
#TempCipher TC ON C.Id = TC.Id
|
|
||||||
WHERE
|
|
||||||
C.[UserId] = @UserId
|
|
||||||
|
|
||||||
DROP TABLE #TempCipher";
|
|
||||||
|
|
||||||
using (var cmd = new SqlCommand(sql, connection, transaction))
|
|
||||||
{
|
|
||||||
cmd.Parameters.Add("@UserId", SqlDbType.UniqueIdentifier).Value = userId;
|
|
||||||
cmd.ExecuteNonQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
await connection.ExecuteAsync(
|
|
||||||
$"[{Schema}].[User_BumpAccountRevisionDate]",
|
|
||||||
new { Id = userId },
|
|
||||||
commandType: CommandType.StoredProcedure, transaction: transaction);
|
|
||||||
|
|
||||||
transaction.Commit();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
transaction.Rollback();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateCiphersAsync_vNext(Guid userId, IEnumerable<Cipher> ciphers)
|
|
||||||
{
|
|
||||||
if (!ciphers.Any())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
@@ -635,54 +495,6 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
|
||||||
{
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using (var transaction = connection.BeginTransaction())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (folders.Any())
|
|
||||||
{
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Folder]";
|
|
||||||
var dataTable = BuildFoldersTable(bulkCopy, folders);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Cipher]";
|
|
||||||
var dataTable = BuildCiphersTable(bulkCopy, ciphers);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
await connection.ExecuteAsync(
|
|
||||||
$"[{Schema}].[User_BumpAccountRevisionDate]",
|
|
||||||
new { Id = userId },
|
|
||||||
commandType: CommandType.StoredProcedure, transaction: transaction);
|
|
||||||
|
|
||||||
transaction.Commit();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
transaction.Rollback();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateAsync_vNext(Guid userId, IEnumerable<Cipher> ciphers, IEnumerable<Folder> folders)
|
|
||||||
{
|
|
||||||
if (!ciphers.Any())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
@@ -722,75 +534,6 @@ public class CipherRepository : Repository<Cipher, Guid>, ICipherRepository
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
|
||||||
{
|
|
||||||
connection.Open();
|
|
||||||
|
|
||||||
using (var transaction = connection.BeginTransaction())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Cipher]";
|
|
||||||
var dataTable = BuildCiphersTable(bulkCopy, ciphers);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collections.Any())
|
|
||||||
{
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[Collection]";
|
|
||||||
var dataTable = BuildCollectionsTable(bulkCopy, collections);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionCiphers.Any())
|
|
||||||
{
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[CollectionCipher]";
|
|
||||||
var dataTable = BuildCollectionCiphersTable(bulkCopy, collectionCiphers);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (collectionUsers.Any())
|
|
||||||
{
|
|
||||||
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, transaction))
|
|
||||||
{
|
|
||||||
bulkCopy.DestinationTableName = "[dbo].[CollectionUser]";
|
|
||||||
var dataTable = BuildCollectionUsersTable(bulkCopy, collectionUsers);
|
|
||||||
bulkCopy.WriteToServer(dataTable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await connection.ExecuteAsync(
|
|
||||||
$"[{Schema}].[User_BumpAccountRevisionDateByOrganizationId]",
|
|
||||||
new { OrganizationId = ciphers.First().OrganizationId },
|
|
||||||
commandType: CommandType.StoredProcedure, transaction: transaction);
|
|
||||||
|
|
||||||
transaction.Commit();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
transaction.Rollback();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateAsync_vNext(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
|
||||||
IEnumerable<CollectionCipher> collectionCiphers, IEnumerable<CollectionUser> collectionUsers)
|
|
||||||
{
|
|
||||||
if (!ciphers.Any())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var connection = new SqlConnection(ConnectionString))
|
using (var connection = new SqlConnection(ConnectionString))
|
||||||
{
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|||||||
@@ -168,16 +168,6 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="CreateAsync(Guid, IEnumerable{Cipher}, IEnumerable{Folder})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// EF does not use the bulk resource creation service, so we need to use the regular create method.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task CreateAsync_vNext(Guid userId, IEnumerable<Core.Vault.Entities.Cipher> ciphers,
|
|
||||||
IEnumerable<Core.Vault.Entities.Folder> folders)
|
|
||||||
{
|
|
||||||
await CreateAsync(userId, ciphers, folders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateAsync(IEnumerable<Core.Vault.Entities.Cipher> ciphers,
|
public async Task CreateAsync(IEnumerable<Core.Vault.Entities.Cipher> ciphers,
|
||||||
IEnumerable<Core.Entities.Collection> collections,
|
IEnumerable<Core.Entities.Collection> collections,
|
||||||
IEnumerable<Core.Entities.CollectionCipher> collectionCiphers,
|
IEnumerable<Core.Entities.CollectionCipher> collectionCiphers,
|
||||||
@@ -216,18 +206,6 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="CreateAsync(IEnumerable{Cipher}, IEnumerable{Collection}, IEnumerable{CollectionCipher}, IEnumerable{CollectionUser})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// EF does not use the bulk resource creation service, so we need to use the regular create method.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task CreateAsync_vNext(IEnumerable<Core.Vault.Entities.Cipher> ciphers,
|
|
||||||
IEnumerable<Core.Entities.Collection> collections,
|
|
||||||
IEnumerable<Core.Entities.CollectionCipher> collectionCiphers,
|
|
||||||
IEnumerable<Core.Entities.CollectionUser> collectionUsers)
|
|
||||||
{
|
|
||||||
await CreateAsync(ciphers, collections, collectionCiphers, collectionUsers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
public async Task DeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||||
{
|
{
|
||||||
await ToggleDeleteCipherStatesAsync(ids, userId, CipherStateAction.HardDelete);
|
await ToggleDeleteCipherStatesAsync(ids, userId, CipherStateAction.HardDelete);
|
||||||
@@ -986,15 +964,6 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="UpdateCiphersAsync(Guid, IEnumerable{Cipher})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// EF does not use the bulk resource creation service, so we need to use the regular update method.
|
|
||||||
/// </remarks>
|
|
||||||
public async Task UpdateCiphersAsync_vNext(Guid userId, IEnumerable<Core.Vault.Entities.Cipher> ciphers)
|
|
||||||
{
|
|
||||||
await UpdateCiphersAsync(userId, ciphers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite)
|
public async Task UpdatePartialAsync(Guid id, Guid userId, Guid? folderId, bool favorite)
|
||||||
{
|
{
|
||||||
using (var scope = ServiceScopeFactory.CreateScope())
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
@@ -1107,16 +1076,6 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="UpdateForKeyRotation(Guid, IEnumerable{Cipher})"/>
|
|
||||||
/// <remarks>
|
|
||||||
/// EF does not use the bulk resource creation service, so we need to use the regular update method.
|
|
||||||
/// </remarks>
|
|
||||||
public UpdateEncryptedDataForKeyRotation UpdateForKeyRotation_vNext(
|
|
||||||
Guid userId, IEnumerable<Core.Vault.Entities.Cipher> ciphers)
|
|
||||||
{
|
|
||||||
return UpdateForKeyRotation(userId, ciphers);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpsertAsync(CipherDetails cipher)
|
public async Task UpsertAsync(CipherDetails cipher)
|
||||||
{
|
{
|
||||||
if (cipher.Id.Equals(default))
|
if (cipher.Id.Equals(default))
|
||||||
|
|||||||
@@ -53,38 +53,6 @@ public class ImportCiphersAsyncCommandTests
|
|||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ImportIntoIndividualVaultAsync_WithBulkResourceCreationServiceEnabled_Success(
|
|
||||||
Guid importingUserId,
|
|
||||||
List<CipherDetails> ciphers,
|
|
||||||
SutProvider<ImportCiphersCommand> sutProvider)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyService>()
|
|
||||||
.AnyPoliciesApplicableToUserAsync(importingUserId, PolicyType.OrganizationDataOwnership)
|
|
||||||
.Returns(false);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFolderRepository>()
|
|
||||||
.GetManyByUserIdAsync(importingUserId)
|
|
||||||
.Returns(new List<Folder>());
|
|
||||||
|
|
||||||
var folders = new List<Folder> { new Folder { UserId = importingUserId } };
|
|
||||||
|
|
||||||
var folderRelationships = new List<KeyValuePair<int, int>>();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await sutProvider.Sut.ImportIntoIndividualVaultAsync(folders, ciphers, folderRelationships, importingUserId);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
await sutProvider.GetDependency<ICipherRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.CreateAsync_vNext(importingUserId, ciphers, Arg.Any<List<Folder>>());
|
|
||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ImportIntoIndividualVaultAsync_WithPolicyRequirementsEnabled_WithOrganizationDataOwnershipPolicyDisabled_Success(
|
public async Task ImportIntoIndividualVaultAsync_WithPolicyRequirementsEnabled_WithOrganizationDataOwnershipPolicyDisabled_Success(
|
||||||
Guid importingUserId,
|
Guid importingUserId,
|
||||||
@@ -117,42 +85,6 @@ public class ImportCiphersAsyncCommandTests
|
|||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ImportIntoIndividualVaultAsync_WithBulkResourceCreationServiceEnabled_WithPolicyRequirementsEnabled_WithOrganizationDataOwnershipPolicyDisabled_Success(
|
|
||||||
Guid importingUserId,
|
|
||||||
List<CipherDetails> ciphers,
|
|
||||||
SutProvider<ImportCiphersCommand> sutProvider)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.PolicyRequirements)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IPolicyRequirementQuery>()
|
|
||||||
.GetAsync<OrganizationDataOwnershipPolicyRequirement>(importingUserId)
|
|
||||||
.Returns(new OrganizationDataOwnershipPolicyRequirement(
|
|
||||||
OrganizationDataOwnershipState.Disabled,
|
|
||||||
[]));
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFolderRepository>()
|
|
||||||
.GetManyByUserIdAsync(importingUserId)
|
|
||||||
.Returns(new List<Folder>());
|
|
||||||
|
|
||||||
var folders = new List<Folder> { new Folder { UserId = importingUserId } };
|
|
||||||
|
|
||||||
var folderRelationships = new List<KeyValuePair<int, int>>();
|
|
||||||
|
|
||||||
await sutProvider.Sut.ImportIntoIndividualVaultAsync(folders, ciphers, folderRelationships, importingUserId);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<ICipherRepository>()
|
|
||||||
.Received(1)
|
|
||||||
.CreateAsync_vNext(importingUserId, ciphers, Arg.Any<List<Folder>>());
|
|
||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ImportIntoIndividualVaultAsync_ThrowsBadRequestException(
|
public async Task ImportIntoIndividualVaultAsync_ThrowsBadRequestException(
|
||||||
List<Folder> folders,
|
List<Folder> folders,
|
||||||
@@ -259,66 +191,6 @@ public class ImportCiphersAsyncCommandTests
|
|||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ImportIntoOrganizationalVaultAsync_WithBulkResourceCreationServiceEnabled_Success(
|
|
||||||
Organization organization,
|
|
||||||
Guid importingUserId,
|
|
||||||
OrganizationUser importingOrganizationUser,
|
|
||||||
List<Collection> collections,
|
|
||||||
List<CipherDetails> ciphers,
|
|
||||||
SutProvider<ImportCiphersCommand> sutProvider)
|
|
||||||
{
|
|
||||||
organization.MaxCollections = null;
|
|
||||||
importingOrganizationUser.OrganizationId = organization.Id;
|
|
||||||
|
|
||||||
foreach (var collection in collections)
|
|
||||||
{
|
|
||||||
collection.OrganizationId = organization.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var cipher in ciphers)
|
|
||||||
{
|
|
||||||
cipher.OrganizationId = organization.Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyValuePair<int, int>[] collectionRelationships = {
|
|
||||||
new(0, 0),
|
|
||||||
new(1, 1),
|
|
||||||
new(2, 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>()
|
|
||||||
.GetByIdAsync(organization.Id)
|
|
||||||
.Returns(organization);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
|
||||||
.GetByOrganizationAsync(organization.Id, importingUserId)
|
|
||||||
.Returns(importingOrganizationUser);
|
|
||||||
|
|
||||||
// Set up a collection that already exists in the organization
|
|
||||||
sutProvider.GetDependency<ICollectionRepository>()
|
|
||||||
.GetManyByOrganizationIdAsync(organization.Id)
|
|
||||||
.Returns(new List<Collection> { collections[0] });
|
|
||||||
|
|
||||||
await sutProvider.Sut.ImportIntoOrganizationalVaultAsync(collections, ciphers, collectionRelationships, importingUserId);
|
|
||||||
|
|
||||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).CreateAsync_vNext(
|
|
||||||
ciphers,
|
|
||||||
Arg.Is<IEnumerable<Collection>>(cols => cols.Count() == collections.Count - 1 &&
|
|
||||||
!cols.Any(c => c.Id == collections[0].Id) && // Check that the collection that already existed in the organization was not added
|
|
||||||
cols.All(c => collections.Any(x => c.Name == x.Name))),
|
|
||||||
Arg.Is<IEnumerable<CollectionCipher>>(c => c.Count() == ciphers.Count),
|
|
||||||
Arg.Is<IEnumerable<CollectionUser>>(cus =>
|
|
||||||
cus.Count() == collections.Count - 1 &&
|
|
||||||
!cus.Any(cu => cu.CollectionId == collections[0].Id) && // Check that access was not added for the collection that already existed in the organization
|
|
||||||
cus.All(cu => cu.OrganizationUserId == importingOrganizationUser.Id && cu.Manage == true)));
|
|
||||||
await sutProvider.GetDependency<IPushNotificationService>().Received(1).PushSyncVaultAsync(importingUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
[Theory, BitAutoData]
|
||||||
public async Task ImportIntoOrganizationalVaultAsync_ThrowsBadRequestException(
|
public async Task ImportIntoOrganizationalVaultAsync_ThrowsBadRequestException(
|
||||||
Organization organization,
|
Organization organization,
|
||||||
|
|||||||
@@ -674,32 +674,6 @@ public class CipherServiceTests
|
|||||||
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[BitAutoData("")]
|
|
||||||
[BitAutoData("Correct Time")]
|
|
||||||
public async Task ShareManyAsync_CorrectRevisionDate_WithBulkResourceCreationServiceEnabled_Passes(string revisionDateString,
|
|
||||||
SutProvider<CipherService> sutProvider, IEnumerable<CipherDetails> ciphers, Organization organization, List<Guid> collectionIds)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id)
|
|
||||||
.Returns(new Organization
|
|
||||||
{
|
|
||||||
PlanType = PlanType.EnterpriseAnnually,
|
|
||||||
MaxStorageGb = 100
|
|
||||||
});
|
|
||||||
|
|
||||||
var cipherInfos = ciphers.Select(c => (c,
|
|
||||||
string.IsNullOrEmpty(revisionDateString) ? null : (DateTime?)c.RevisionDate));
|
|
||||||
var sharingUserId = ciphers.First().UserId.Value;
|
|
||||||
|
|
||||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organization.Id, collectionIds, sharingUserId);
|
|
||||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync_vNext(sharingUserId,
|
|
||||||
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async Task RestoreAsync_UpdatesUserCipher(Guid restoringUserId, CipherDetails cipher, SutProvider<CipherService> sutProvider)
|
public async Task RestoreAsync_UpdatesUserCipher(Guid restoringUserId, CipherDetails cipher, SutProvider<CipherService> sutProvider)
|
||||||
@@ -1120,33 +1094,6 @@ public class CipherServiceTests
|
|||||||
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData]
|
|
||||||
public async Task ShareManyAsync_PaidOrgWithAttachment_WithBulkResourceCreationServiceEnabled_Passes(SutProvider<CipherService> sutProvider,
|
|
||||||
IEnumerable<CipherDetails> ciphers, Guid organizationId, List<Guid> collectionIds)
|
|
||||||
{
|
|
||||||
sutProvider.GetDependency<IFeatureService>()
|
|
||||||
.IsEnabled(FeatureFlagKeys.CipherRepositoryBulkResourceCreation)
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId)
|
|
||||||
.Returns(new Organization
|
|
||||||
{
|
|
||||||
PlanType = PlanType.EnterpriseAnnually,
|
|
||||||
MaxStorageGb = 100
|
|
||||||
});
|
|
||||||
ciphers.FirstOrDefault().Attachments =
|
|
||||||
"{\"attachment1\":{\"Size\":\"250\",\"FileName\":\"superCoolFile\","
|
|
||||||
+ "\"Key\":\"superCoolFile\",\"ContainerName\":\"testContainer\",\"Validated\":false}}";
|
|
||||||
|
|
||||||
var cipherInfos = ciphers.Select(c => (c,
|
|
||||||
(DateTime?)c.RevisionDate));
|
|
||||||
var sharingUserId = ciphers.First().UserId.Value;
|
|
||||||
|
|
||||||
await sutProvider.Sut.ShareManyAsync(cipherInfos, organizationId, collectionIds, sharingUserId);
|
|
||||||
await sutProvider.GetDependency<ICipherRepository>().Received(1).UpdateCiphersAsync_vNext(sharingUserId,
|
|
||||||
Arg.Is<IEnumerable<Cipher>>(arg => !arg.Except(ciphers).Any()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SaveDetailsAsyncDependencies
|
private class SaveDetailsAsyncDependencies
|
||||||
{
|
{
|
||||||
public CipherDetails CipherDetails { get; set; }
|
public CipherDetails CipherDetails { get; set; }
|
||||||
|
|||||||
@@ -949,36 +949,7 @@ public class CipherRepositoryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData]
|
[DatabaseTheory, DatabaseData]
|
||||||
public async Task UpdateCiphersAsync_Works(ICipherRepository cipherRepository, IUserRepository userRepository)
|
public async Task CreateAsync_WithFolders_Works(
|
||||||
{
|
|
||||||
var user = await userRepository.CreateAsync(new User
|
|
||||||
{
|
|
||||||
Name = "Test User",
|
|
||||||
Email = $"test+{Guid.NewGuid()}@email.com",
|
|
||||||
ApiKey = "TEST",
|
|
||||||
SecurityStamp = "stamp",
|
|
||||||
});
|
|
||||||
|
|
||||||
var cipher1 = await CreatePersonalCipher(user, cipherRepository);
|
|
||||||
var cipher2 = await CreatePersonalCipher(user, cipherRepository);
|
|
||||||
|
|
||||||
cipher1.Type = CipherType.SecureNote;
|
|
||||||
cipher2.Attachments = "new_attachments";
|
|
||||||
|
|
||||||
await cipherRepository.UpdateCiphersAsync(user.Id, [cipher1, cipher2]);
|
|
||||||
|
|
||||||
var updatedCipher1 = await cipherRepository.GetByIdAsync(cipher1.Id);
|
|
||||||
var updatedCipher2 = await cipherRepository.GetByIdAsync(cipher2.Id);
|
|
||||||
|
|
||||||
Assert.NotNull(updatedCipher1);
|
|
||||||
Assert.NotNull(updatedCipher2);
|
|
||||||
|
|
||||||
Assert.Equal(CipherType.SecureNote, updatedCipher1.Type);
|
|
||||||
Assert.Equal("new_attachments", updatedCipher2.Attachments);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData]
|
|
||||||
public async Task CreateAsync_vNext_WithFolders_Works(
|
|
||||||
IUserRepository userRepository, ICipherRepository cipherRepository, IFolderRepository folderRepository)
|
IUserRepository userRepository, ICipherRepository cipherRepository, IFolderRepository folderRepository)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
@@ -996,7 +967,7 @@ public class CipherRepositoryTests
|
|||||||
var cipher2 = new Cipher { Id = CoreHelpers.GenerateComb(), Type = CipherType.SecureNote, UserId = user.Id, Data = "" };
|
var cipher2 = new Cipher { Id = CoreHelpers.GenerateComb(), Type = CipherType.SecureNote, UserId = user.Id, Data = "" };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await cipherRepository.CreateAsync_vNext(
|
await cipherRepository.CreateAsync(
|
||||||
userId: user.Id,
|
userId: user.Id,
|
||||||
ciphers: [cipher1, cipher2],
|
ciphers: [cipher1, cipher2],
|
||||||
folders: [folder1, folder2]);
|
folders: [folder1, folder2]);
|
||||||
@@ -1014,7 +985,7 @@ public class CipherRepositoryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData]
|
[DatabaseTheory, DatabaseData]
|
||||||
public async Task CreateAsync_vNext_WithCollectionsAndUsers_Works(
|
public async Task CreateAsync_WithCollectionsAndUsers_Works(
|
||||||
IOrganizationRepository orgRepository,
|
IOrganizationRepository orgRepository,
|
||||||
IOrganizationUserRepository orgUserRepository,
|
IOrganizationUserRepository orgUserRepository,
|
||||||
ICollectionRepository collectionRepository,
|
ICollectionRepository collectionRepository,
|
||||||
@@ -1059,7 +1030,7 @@ public class CipherRepositoryTests
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await cipherRepository.CreateAsync_vNext(
|
await cipherRepository.CreateAsync(
|
||||||
ciphers: [cipher],
|
ciphers: [cipher],
|
||||||
collections: [collection],
|
collections: [collection],
|
||||||
collectionCiphers: [collectionCipher],
|
collectionCiphers: [collectionCipher],
|
||||||
@@ -1084,7 +1055,7 @@ public class CipherRepositoryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DatabaseTheory, DatabaseData]
|
[DatabaseTheory, DatabaseData]
|
||||||
public async Task UpdateCiphersAsync_vNext_Works(
|
public async Task UpdateCiphersAsync_Works(
|
||||||
IUserRepository userRepository, ICipherRepository cipherRepository)
|
IUserRepository userRepository, ICipherRepository cipherRepository)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
@@ -1110,7 +1081,7 @@ public class CipherRepositoryTests
|
|||||||
c2.Attachments = expectedNewAttachments;
|
c2.Attachments = expectedNewAttachments;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
await cipherRepository.UpdateCiphersAsync_vNext(user.Id, [c1, c2]);
|
await cipherRepository.UpdateCiphersAsync(user.Id, [c1, c2]);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var updated1 = await cipherRepository.GetByIdAsync(c1.Id);
|
var updated1 = await cipherRepository.GetByIdAsync(c1.Id);
|
||||||
|
|||||||
Reference in New Issue
Block a user