mirror of
https://github.com/bitwarden/server
synced 2025-12-24 20:23:21 +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
@@ -71,7 +71,8 @@ public class UserCipherDetailsQuery : IQuery<CipherDetails>
|
||||
Manage = cu == null ? (cg != null && cg.Manage == true) : cu.Manage == true,
|
||||
OrganizationUseTotp = o.UseTotp,
|
||||
c.Reprompt,
|
||||
c.Key
|
||||
c.Key,
|
||||
c.ArchivedDate
|
||||
};
|
||||
|
||||
var query2 = from c in dbContext.Ciphers
|
||||
@@ -94,7 +95,8 @@ public class UserCipherDetailsQuery : IQuery<CipherDetails>
|
||||
Manage = true,
|
||||
OrganizationUseTotp = false,
|
||||
c.Reprompt,
|
||||
c.Key
|
||||
c.Key,
|
||||
c.ArchivedDate
|
||||
};
|
||||
|
||||
var union = query.Union(query2).Select(c => new CipherDetails
|
||||
@@ -115,7 +117,8 @@ public class UserCipherDetailsQuery : IQuery<CipherDetails>
|
||||
ViewPassword = c.ViewPassword,
|
||||
Manage = c.Manage,
|
||||
OrganizationUseTotp = c.OrganizationUseTotp,
|
||||
Key = c.Key
|
||||
Key = c.Key,
|
||||
ArchivedDate = c.ArchivedDate
|
||||
});
|
||||
return union;
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
|
||||
public async Task DeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
await ToggleCipherStates(ids, userId, CipherStateAction.HardDelete);
|
||||
await ToggleDeleteCipherStatesAsync(ids, userId, CipherStateAction.HardDelete);
|
||||
}
|
||||
|
||||
public async Task DeleteAttachmentAsync(Guid cipherId, string attachmentId)
|
||||
@@ -508,7 +508,8 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
ViewPassword = true,
|
||||
Manage = true,
|
||||
OrganizationUseTotp = false,
|
||||
Key = c.Key
|
||||
Key = c.Key,
|
||||
ArchivedDate = c.ArchivedDate,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -751,9 +752,14 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<DateTime> UnarchiveAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
return await ToggleArchiveCipherStatesAsync(ids, userId, CipherStateAction.Unarchive);
|
||||
}
|
||||
|
||||
public async Task<DateTime> RestoreAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
return await ToggleCipherStates(ids, userId, CipherStateAction.Restore);
|
||||
return await ToggleDeleteCipherStatesAsync(ids, userId, CipherStateAction.Restore);
|
||||
}
|
||||
|
||||
public async Task<DateTime> RestoreByIdsOrganizationIdAsync(IEnumerable<Guid> ids, Guid organizationId)
|
||||
@@ -781,20 +787,25 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
public async Task<DateTime> ArchiveAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
await ToggleCipherStates(ids, userId, CipherStateAction.SoftDelete);
|
||||
return await ToggleArchiveCipherStatesAsync(ids, userId, CipherStateAction.Archive);
|
||||
}
|
||||
|
||||
private async Task<DateTime> ToggleCipherStates(IEnumerable<Guid> ids, Guid userId, CipherStateAction action)
|
||||
public async Task SoftDeleteAsync(IEnumerable<Guid> ids, Guid userId)
|
||||
{
|
||||
static bool FilterDeletedDate(CipherStateAction action, CipherDetails ucd)
|
||||
await ToggleDeleteCipherStatesAsync(ids, userId, CipherStateAction.SoftDelete);
|
||||
}
|
||||
|
||||
private async Task<DateTime> ToggleArchiveCipherStatesAsync(IEnumerable<Guid> ids, Guid userId, CipherStateAction action)
|
||||
{
|
||||
static bool FilterArchivedDate(CipherStateAction action, CipherDetails ucd)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
CipherStateAction.Restore => ucd.DeletedDate != null,
|
||||
CipherStateAction.SoftDelete => ucd.DeletedDate == null,
|
||||
_ => true,
|
||||
CipherStateAction.Unarchive => ucd.ArchivedDate != null,
|
||||
CipherStateAction.Archive => ucd.ArchivedDate == null,
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
|
||||
@@ -802,8 +813,49 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var userCipherDetailsQuery = new UserCipherDetailsQuery(userId);
|
||||
var cipherEntitiesToCheck = await (dbContext.Ciphers.Where(c => ids.Contains(c.Id))).ToListAsync();
|
||||
var query = from ucd in await (userCipherDetailsQuery.Run(dbContext)).ToListAsync()
|
||||
var cipherEntitiesToCheck = await dbContext.Ciphers.Where(c => ids.Contains(c.Id)).ToListAsync();
|
||||
var query = from ucd in await userCipherDetailsQuery.Run(dbContext).ToListAsync()
|
||||
join c in cipherEntitiesToCheck
|
||||
on ucd.Id equals c.Id
|
||||
where ucd.Edit && FilterArchivedDate(action, ucd)
|
||||
select c;
|
||||
|
||||
var utcNow = DateTime.UtcNow;
|
||||
var cipherIdsToModify = query.Select(c => c.Id);
|
||||
var cipherEntitiesToModify = dbContext.Ciphers.Where(x => cipherIdsToModify.Contains(x.Id));
|
||||
|
||||
await cipherEntitiesToModify.ForEachAsync(cipher =>
|
||||
{
|
||||
dbContext.Attach(cipher);
|
||||
cipher.ArchivedDate = action == CipherStateAction.Unarchive ? null : utcNow;
|
||||
cipher.RevisionDate = utcNow;
|
||||
});
|
||||
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return utcNow;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<DateTime> ToggleDeleteCipherStatesAsync(IEnumerable<Guid> ids, Guid userId, CipherStateAction action)
|
||||
{
|
||||
static bool FilterDeletedDate(CipherStateAction action, CipherDetails ucd)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
CipherStateAction.Restore => ucd.DeletedDate != null,
|
||||
CipherStateAction.SoftDelete => ucd.DeletedDate == null,
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var userCipherDetailsQuery = new UserCipherDetailsQuery(userId);
|
||||
var cipherEntitiesToCheck = await dbContext.Ciphers.Where(c => ids.Contains(c.Id)).ToListAsync();
|
||||
var query = from ucd in await userCipherDetailsQuery.Run(dbContext).ToListAsync()
|
||||
join c in cipherEntitiesToCheck
|
||||
on ucd.Id equals c.Id
|
||||
where ucd.Edit && FilterDeletedDate(action, ucd)
|
||||
@@ -841,6 +893,7 @@ public class CipherRepository : Repository<Core.Vault.Entities.Cipher, Cipher, G
|
||||
}
|
||||
await dbContext.UserBumpAccountRevisionDateAsync(userId);
|
||||
await dbContext.SaveChangesAsync();
|
||||
|
||||
return utcNow;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public class CipherDetailsQuery : IQuery<CipherDetails>
|
||||
FolderId = (_ignoreFolders || !_userId.HasValue || c.Folders == null || !c.Folders.ToLowerInvariant().Contains(_userId.Value.ToString())) ?
|
||||
null :
|
||||
CoreHelpers.LoadClassFromJsonData<Dictionary<Guid, Guid>>(c.Folders)[_userId.Value],
|
||||
ArchivedDate = c.ArchivedDate,
|
||||
};
|
||||
return query;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user