/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ use crate::{ Server, auth::AccountCache, storage::{ObjectQuota, TenantQuota}, }; use registry::{ schema::enums::{StorageQuota, TenantStorageQuota}, types::EnumImpl, }; use store::{ValueKey, write::ValueClass}; use trc::AddContext; impl Server { pub async fn get_used_quota_account(&self, account_id: u32) -> trc::Result { self.core .storage .data .get_counter(ValueKey { account_id, collection: 0, document_id: 0, class: ValueClass::Quota, }) .await .add_context(|err| err.caused_by(trc::location!()).account_id(account_id)) } // inbuxa: MT-20: storage used by all a tenant's members together pub async fn get_used_quota_tenant(&self, tenant_id: u32) -> trc::Result { inbuxa_features::tenancy::quota::used(&self.core.storage.data, tenant_id).await } pub async fn has_available_quota( &self, account: &AccountCache, item_size: u64, ) -> trc::Result<()> { if account.quota_disk != 0 { let used_quota = self.get_used_quota_account(account.id).await?.max(0) as u64; if used_quota + item_size > account.quota_disk { return Err(trc::LimitEvent::Quota .into_err() .ctx(trc::Key::Limit, account.quota_disk) .ctx(trc::Key::Size, used_quota)); } } // inbuxa: MT-19: the tenant's limit applies too, whichever is reached first if let Some(tenant_id) = account.id_tenant { let tenant = self.tenant(tenant_id).await?; if tenant.quota_disk != 0 { let used_quota = self.get_used_quota_tenant(tenant_id).await?.max(0) as u64; if used_quota + item_size > tenant.quota_disk { return Err(trc::LimitEvent::TenantQuota .into_err() .ctx(trc::Key::Id, tenant_id) .ctx(trc::Key::Limit, tenant.quota_disk) .ctx(trc::Key::Size, used_quota)); } } } Ok(()) } #[inline(always)] pub fn object_quota(&self, user_quotas: Option<&ObjectQuota>, object: StorageQuota) -> u32 { user_quotas.unwrap_or(&self.core.email.max_objects).0[object as usize] } } impl ObjectQuota { #[inline(always)] pub fn set(&mut self, item: StorageQuota, max: u32) { self.0[item as usize] = max; } #[inline(always)] pub fn get(&self, item: StorageQuota) -> u32 { self.0[item as usize] } } impl TenantQuota { #[inline(always)] pub fn set(&mut self, item: TenantStorageQuota, max: u32) { self.0[item as usize] = max; } #[inline(always)] pub fn get(&self, item: TenantStorageQuota) -> u32 { self.0[item as usize] } } impl Default for ObjectQuota { fn default() -> Self { Self([u32::MAX; StorageQuota::COUNT - 1]) } } impl Default for TenantQuota { fn default() -> Self { Self([u32::MAX; TenantStorageQuota::COUNT - 1]) } }