1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 00:22:50 -05:00

Feature.web.534.allow multi select in org vault (#830)

* Set up API methods for bulk admin delete
This commit is contained in:
Addison Beck
2020-07-22 11:38:53 -05:00
committed by GitHub
parent 51fd87df0b
commit 229478adae
9 changed files with 191 additions and 12 deletions

View File

@ -204,6 +204,7 @@ namespace Bit.Core.Models.Api
{
[Required]
public IEnumerable<string> Ids { get; set; }
public string OrganizationId { get; set; }
}
public class CipherBulkRestoreRequestModel

View File

@ -24,6 +24,7 @@ namespace Bit.Core.Repositories
Task UpdateAttachmentAsync(CipherAttachment attachment);
Task DeleteAttachmentAsync(Guid cipherId, string attachmentId);
Task DeleteAsync(IEnumerable<Guid> ids, Guid userId);
Task DeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId);
Task DeleteByUserIdAsync(Guid userId);
Task DeleteByOrganizationIdAsync(Guid organizationId);
@ -33,6 +34,7 @@ namespace Bit.Core.Repositories
Task CreateAsync(IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
IEnumerable<CollectionCipher> collectionCiphers);
Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId);
Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId);
Task RestoreAsync(IEnumerable<Guid> ids, Guid userId);
}
}

View File

@ -226,6 +226,28 @@ namespace Bit.Core.Repositories.SqlServer
}
}
public async Task DeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Cipher_DeleteByIdsOrganizationId]",
new { Ids = ids.ToGuidIdArrayTVP(), OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
}
}
public async Task SoftDeleteByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.ExecuteAsync(
$"[{Schema}].[Cipher_SoftDeleteByIdsOrganizationId]",
new { Ids = ids.ToGuidIdArrayTVP(), OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
}
}
public async Task MoveAsync(IEnumerable<Guid> ids, Guid? folderId, Guid userId)
{
using (var connection = new SqlConnection(ConnectionString))

View File

@ -18,7 +18,7 @@ namespace Bit.Core.Services
Task CreateAttachmentShareAsync(Cipher cipher, Stream stream, long requestLength, string attachmentId,
Guid organizationShareId);
Task DeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false);
Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId);
Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false);
Task DeleteAttachmentAsync(Cipher cipher, string attachmentId, Guid deletingUserId, bool orgAdmin = false);
Task PurgeAsync(Guid organizationId);
Task MoveManyAsync(IEnumerable<Guid> cipherIds, Guid? destinationFolderId, Guid movingUserId);
@ -34,7 +34,7 @@ namespace Bit.Core.Services
Task ImportCiphersAsync(List<Collection> collections, List<CipherDetails> ciphers,
IEnumerable<KeyValuePair<int, int>> collectionRelationships, Guid importingUserId);
Task SoftDeleteAsync(Cipher cipher, Guid deletingUserId, bool orgAdmin = false);
Task SoftDeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId);
Task SoftDeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false);
Task RestoreAsync(Cipher cipher, Guid restoringUserId, bool orgAdmin = false);
Task RestoreManyAsync(IEnumerable<Guid> cipherIds, Guid restoringUserId);
}

View File

@ -288,13 +288,23 @@ namespace Bit.Core.Services
await _pushService.PushSyncCipherDeleteAsync(cipher);
}
public async Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId)
public async Task DeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId = null, bool orgAdmin = false)
{
var cipherIdsSet = new HashSet<Guid>(cipherIds);
var ciphers = await _cipherRepository.GetManyByUserIdAsync(deletingUserId);
var deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id) && c.Edit);
var deletingCiphers = new List<Cipher>();
await _cipherRepository.DeleteAsync(cipherIds, deletingUserId);
if (orgAdmin && organizationId.HasValue)
{
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(organizationId.Value);
deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id)).ToList();
await _cipherRepository.DeleteByIdsOrganizationIdAsync(deletingCiphers.Select(c => c.Id), organizationId.Value);
}
else
{
var ciphers = await _cipherRepository.GetManyByUserIdAsync(deletingUserId);
deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id) && c.Edit).Select(x => (Cipher)x).ToList();
await _cipherRepository.DeleteAsync(deletingCiphers.Select(c => c.Id), deletingUserId);
}
var events = deletingCiphers.Select(c =>
new Tuple<Cipher, EventType, DateTime?>(c, EventType.Cipher_Deleted, null));
@ -693,13 +703,23 @@ namespace Bit.Core.Services
await _pushService.PushSyncCipherUpdateAsync(cipher, null);
}
public async Task SoftDeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId)
public async Task SoftDeleteManyAsync(IEnumerable<Guid> cipherIds, Guid deletingUserId, Guid? organizationId, bool orgAdmin)
{
var cipherIdsSet = new HashSet<Guid>(cipherIds);
var ciphers = await _cipherRepository.GetManyByUserIdAsync(deletingUserId);
var deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id) && c.Edit);
var deletingCiphers = new List<Cipher>();
await _cipherRepository.SoftDeleteAsync(cipherIds, deletingUserId);
if (orgAdmin && organizationId.HasValue)
{
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(organizationId.Value);
deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id)).ToList();
await _cipherRepository.SoftDeleteByIdsOrganizationIdAsync(deletingCiphers.Select(c => c.Id), organizationId.Value);
}
else
{
var ciphers = await _cipherRepository.GetManyByUserIdAsync(deletingUserId);
deletingCiphers = ciphers.Where(c => cipherIdsSet.Contains(c.Id) && c.Edit).Select(x => (Cipher)x).ToList();
await _cipherRepository.SoftDeleteAsync(deletingCiphers.Select(c => c.Id), deletingUserId);
}
var events = deletingCiphers.Select(c =>
new Tuple<Cipher, EventType, DateTime?>(c, EventType.Cipher_SoftDeleted, null));