diff --git a/src/Api/Vault/Controllers/CiphersController.cs b/src/Api/Vault/Controllers/CiphersController.cs index cd70d7a6c0..efc9a0eb88 100644 --- a/src/Api/Vault/Controllers/CiphersController.cs +++ b/src/Api/Vault/Controllers/CiphersController.cs @@ -1110,6 +1110,33 @@ public class CiphersController : Controller }); } + /// + /// Returns true if the user is an admin or owner of an organization with unassigned ciphers (i.e. ciphers that + /// are not assigned to a collection). + /// + /// + [HttpGet("has-unassigned-ciphers")] + public async Task HasUnassignedCiphers() + { + var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync(); + + var adminOrganizations = _currentContext.Organizations + .Where(o => o.Type is OrganizationUserType.Admin or OrganizationUserType.Owner && + orgAbilities.ContainsKey(o.Id) && orgAbilities[o.Id].FlexibleCollections); + + foreach (var org in adminOrganizations) + { + var unassignedCiphers = await _cipherRepository.GetManyUnassignedOrganizationDetailsByOrganizationIdAsync(org.Id); + // We only care about non-deleted ciphers + if (unassignedCiphers.Any(c => c.DeletedDate == null)) + { + return true; + } + } + + return false; + } + private void ValidateAttachment() { if (!Request?.ContentType.Contains("multipart/") ?? true) diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index 8f5cc0773b..749419644a 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -132,6 +132,7 @@ public static class FeatureFlagKeys public const string ShowPaymentMethodWarningBanners = "show-payment-method-warning-banners"; public const string EnableConsolidatedBilling = "enable-consolidated-billing"; public const string AC1795_UpdatedSubscriptionStatusSection = "AC-1795_updated-subscription-status-section"; + public const string UnassignedItemsBanner = "unassigned-items-banner"; public static List GetAllKeys() {