mirror of
https://github.com/bitwarden/server
synced 2026-01-06 10:34:01 +00:00
[PM-19151] [PM-19161] Innovation/archive/server (#5672)
* Added the ArchivedDate to cipher entity and response model * Created migration scripts for sqlserver and ef core migration to add the ArchivedDate column --------- Co-authored-by: gbubemismith <gsmithwalter@gmail.com> Co-authored-by: SmithThe4th <gsmith@bitwarden.com> Co-authored-by: Shane <smelton@bitwarden.com> Co-authored-by: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Co-authored-by: jng <jng@bitwarden.com>
This commit is contained in:
committed by
GitHub
parent
18aed0bd79
commit
4e64d35f89
61
src/Core/Vault/Commands/ArchiveCiphersCommand.cs
Normal file
61
src/Core/Vault/Commands/ArchiveCiphersCommand.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Vault.Commands.Interfaces;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
|
||||
namespace Bit.Core.Vault.Commands;
|
||||
|
||||
public class ArchiveCiphersCommand : IArchiveCiphersCommand
|
||||
{
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly IPushNotificationService _pushService;
|
||||
|
||||
public ArchiveCiphersCommand(
|
||||
ICipherRepository cipherRepository,
|
||||
IPushNotificationService pushService
|
||||
)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
_pushService = pushService;
|
||||
}
|
||||
|
||||
public async Task<ICollection<CipherDetails>> ArchiveManyAsync(IEnumerable<Guid> cipherIds,
|
||||
Guid archivingUserId)
|
||||
{
|
||||
var cipherIdEnumerable = cipherIds as Guid[] ?? cipherIds.ToArray();
|
||||
if (cipherIds == null || cipherIdEnumerable.Length == 0)
|
||||
throw new BadRequestException("No cipher ids provided.");
|
||||
|
||||
var cipherIdsSet = new HashSet<Guid>(cipherIdEnumerable);
|
||||
|
||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(archivingUserId);
|
||||
|
||||
if (ciphers == null || ciphers.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var archivingCiphers = ciphers
|
||||
.Where(c => cipherIdsSet.Contains(c.Id) && c is { Edit: true, OrganizationId: null, ArchivedDate: null })
|
||||
.ToList();
|
||||
|
||||
var revisionDate = await _cipherRepository.ArchiveAsync(archivingCiphers.Select(c => c.Id), archivingUserId);
|
||||
|
||||
// Adding specifyKind because revisionDate is currently coming back as Unspecified from the database
|
||||
revisionDate = DateTime.SpecifyKind(revisionDate, DateTimeKind.Utc);
|
||||
|
||||
archivingCiphers.ForEach(c =>
|
||||
{
|
||||
c.RevisionDate = revisionDate;
|
||||
c.ArchivedDate = revisionDate;
|
||||
});
|
||||
|
||||
// Will not log an event because the archive feature is limited to individual ciphers, and event logs only apply to organization ciphers.
|
||||
// Add event logging here if this is expanded to organization ciphers in the future.
|
||||
|
||||
await _pushService.PushSyncCiphersAsync(archivingUserId);
|
||||
|
||||
return archivingCiphers;
|
||||
}
|
||||
}
|
||||
14
src/Core/Vault/Commands/Interfaces/IArchiveCiphersCommand.cs
Normal file
14
src/Core/Vault/Commands/Interfaces/IArchiveCiphersCommand.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
|
||||
namespace Bit.Core.Vault.Commands.Interfaces;
|
||||
|
||||
public interface IArchiveCiphersCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Archives a cipher. This fills in the ArchivedDate property on a Cipher.
|
||||
/// </summary>
|
||||
/// <param name="cipherIds">Cipher ID to archive.</param>
|
||||
/// <param name="archivingUserId">User ID to check against the Ciphers that are trying to be archived.</param>
|
||||
/// <returns></returns>
|
||||
public Task<ICollection<CipherDetails>> ArchiveManyAsync(IEnumerable<Guid> cipherIds, Guid archivingUserId);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
|
||||
namespace Bit.Core.Vault.Commands.Interfaces;
|
||||
|
||||
public interface IUnarchiveCiphersCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Unarchives a cipher. This nulls the ArchivedDate property on a Cipher.
|
||||
/// </summary>
|
||||
/// <param name="cipherIds">Cipher ID to unarchive.</param>
|
||||
/// <param name="unarchivingUserId">User ID to check against the Ciphers that are trying to be unarchived.</param>
|
||||
/// <returns></returns>
|
||||
public Task<ICollection<CipherDetails>> UnarchiveManyAsync(IEnumerable<Guid> cipherIds, Guid unarchivingUserId);
|
||||
}
|
||||
60
src/Core/Vault/Commands/UnarchiveCiphersCommand.cs
Normal file
60
src/Core/Vault/Commands/UnarchiveCiphersCommand.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Vault.Commands.Interfaces;
|
||||
using Bit.Core.Vault.Models.Data;
|
||||
using Bit.Core.Vault.Repositories;
|
||||
|
||||
namespace Bit.Core.Vault.Commands;
|
||||
|
||||
public class UnarchiveCiphersCommand : IUnarchiveCiphersCommand
|
||||
{
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly IPushNotificationService _pushService;
|
||||
|
||||
public UnarchiveCiphersCommand(
|
||||
ICipherRepository cipherRepository,
|
||||
IPushNotificationService pushService
|
||||
)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
_pushService = pushService;
|
||||
}
|
||||
|
||||
public async Task<ICollection<CipherDetails>> UnarchiveManyAsync(IEnumerable<Guid> cipherIds,
|
||||
Guid unarchivingUserId)
|
||||
{
|
||||
var cipherIdEnumerable = cipherIds as Guid[] ?? cipherIds.ToArray();
|
||||
if (cipherIds == null || cipherIdEnumerable.Length == 0)
|
||||
throw new BadRequestException("No cipher ids provided.");
|
||||
|
||||
var cipherIdsSet = new HashSet<Guid>(cipherIdEnumerable);
|
||||
|
||||
var ciphers = await _cipherRepository.GetManyByUserIdAsync(unarchivingUserId);
|
||||
|
||||
if (ciphers == null || ciphers.Count == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var unarchivingCiphers = ciphers
|
||||
.Where(c => cipherIdsSet.Contains(c.Id) && c is { Edit: true, ArchivedDate: not null })
|
||||
.ToList();
|
||||
|
||||
var revisionDate =
|
||||
await _cipherRepository.UnarchiveAsync(unarchivingCiphers.Select(c => c.Id), unarchivingUserId);
|
||||
// Adding specifyKind because revisionDate is currently coming back as Unspecified from the database
|
||||
revisionDate = DateTime.SpecifyKind(revisionDate, DateTimeKind.Utc);
|
||||
|
||||
unarchivingCiphers.ForEach(c =>
|
||||
{
|
||||
c.RevisionDate = revisionDate;
|
||||
c.ArchivedDate = null;
|
||||
});
|
||||
// Will not log an event because the archive feature is limited to individual ciphers, and event logs only apply to organization ciphers.
|
||||
// Add event logging here if this is expanded to organization ciphers in the future.
|
||||
|
||||
await _pushService.PushSyncCiphersAsync(unarchivingUserId);
|
||||
|
||||
return unarchivingCiphers;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user