use crate::providers::ResourceProvider;
use crate::resource::{RequestContext, TenantContext};
use uuid::Uuid;
pub trait MultiTenantProvider: ResourceProvider {
fn effective_tenant_id(&self, context: &RequestContext) -> String {
context.tenant_id().unwrap_or("default").to_string()
}
fn tenant_scoped_key(&self, tenant_id: &str, resource_type: &str, resource_id: &str) -> String {
format!("tenant:{}:{}:{}", tenant_id, resource_type, resource_id)
}
fn tenant_scoped_prefix(&self, tenant_id: &str, resource_type: &str) -> String {
format!("tenant:{}:{}:", tenant_id, resource_type)
}
fn is_valid_tenant_context(&self, context: &RequestContext, require_tenant: bool) -> bool {
if require_tenant {
context.tenant_id().is_some()
} else {
true }
}
fn extract_tenant_context<'a>(&self, context: &'a RequestContext) -> Option<&'a TenantContext> {
context.tenant_context.as_ref()
}
fn generate_tenant_resource_id(&self, _tenant_id: &str, _resource_type: &str) -> String {
Uuid::new_v4().to_string()
}
fn same_tenant(&self, context1: &RequestContext, context2: &RequestContext) -> bool {
self.effective_tenant_id(context1) == self.effective_tenant_id(context2)
}
fn tenant_error_message(&self, context: &RequestContext, base_message: &str) -> String {
let tenant_id = self.effective_tenant_id(context);
if tenant_id == "default" {
base_message.to_string()
} else {
format!("[Tenant: {}] {}", tenant_id, base_message)
}
}
fn is_single_tenant_context(&self, context: &RequestContext) -> bool {
context.tenant_id().is_none()
}
fn is_multi_tenant_context(&self, context: &RequestContext) -> bool {
context.tenant_id().is_some()
}
fn get_client_id<'a>(&self, context: &'a RequestContext) -> Option<&'a str> {
context
.tenant_context
.as_ref()
.map(|tc| tc.client_id.as_str())
}
fn normalize_tenant_id(&self, tenant_id: &str) -> String {
tenant_id
.trim()
.to_lowercase()
.replace(' ', "-")
.chars()
.filter(|c| c.is_alphanumeric() || *c == '-' || *c == '_')
.collect()
}
fn is_valid_tenant_id(&self, tenant_id: &str) -> bool {
!tenant_id.trim().is_empty()
&& tenant_id.len() <= 64
&& tenant_id
.chars()
.all(|c| c.is_alphanumeric() || c == '-' || c == '_')
&& !tenant_id.starts_with('-')
&& !tenant_id.ends_with('-')
}
}
impl<T: ResourceProvider> MultiTenantProvider for T {}