Skip to main content

allsource_core/application/use_cases/
manage_tenant.rs

1use crate::application::dto::{
2    CreateTenantRequest, CreateTenantResponse, ListTenantsResponse, TenantDto, UpdateTenantRequest,
3    UpdateTenantResponse,
4};
5use crate::domain::entities::Tenant;
6use crate::domain::value_objects::TenantId;
7use crate::error::Result;
8
9/// Use Case: Create Tenant
10///
11/// Creates a new tenant with specified quotas.
12pub struct CreateTenantUseCase;
13
14impl CreateTenantUseCase {
15    pub fn execute(request: CreateTenantRequest) -> Result<CreateTenantResponse> {
16        // Validate and create tenant ID
17        let tenant_id = TenantId::new(request.tenant_id)?;
18
19        // Create tenant with quotas (or use default)
20        let tenant = if let Some(quotas_dto) = request.quotas {
21            Tenant::new(tenant_id, request.name, quotas_dto.into())?
22        } else {
23            // Use free tier by default
24            Tenant::new(
25                tenant_id,
26                request.name,
27                crate::domain::entities::TenantQuotas::free_tier(),
28            )?
29        };
30
31        Ok(CreateTenantResponse {
32            tenant: TenantDto::from(&tenant),
33        })
34    }
35}
36
37/// Use Case: Update Tenant
38///
39/// Updates tenant information and/or quotas.
40pub struct UpdateTenantUseCase;
41
42impl UpdateTenantUseCase {
43    pub fn execute(
44        mut tenant: Tenant,
45        request: UpdateTenantRequest,
46    ) -> Result<UpdateTenantResponse> {
47        // Update name if provided
48        if let Some(name) = request.name {
49            tenant.update_name(name)?;
50        }
51
52        // Update quotas if provided
53        if let Some(quotas_dto) = request.quotas {
54            tenant.update_quotas(quotas_dto.into());
55        }
56
57        Ok(UpdateTenantResponse {
58            tenant: TenantDto::from(&tenant),
59        })
60    }
61}
62
63/// Use Case: Activate Tenant
64///
65/// Activates a previously deactivated tenant.
66pub struct ActivateTenantUseCase;
67
68impl ActivateTenantUseCase {
69    pub fn execute(mut tenant: Tenant) -> Result<TenantDto> {
70        tenant.activate();
71        Ok(TenantDto::from(&tenant))
72    }
73}
74
75/// Use Case: Deactivate Tenant
76///
77/// Deactivates a tenant, preventing event ingestion and queries.
78pub struct DeactivateTenantUseCase;
79
80impl DeactivateTenantUseCase {
81    pub fn execute(mut tenant: Tenant) -> Result<TenantDto> {
82        tenant.deactivate();
83        Ok(TenantDto::from(&tenant))
84    }
85}
86
87/// Use Case: List Tenants
88///
89/// Returns a list of all tenants (would typically come from a repository).
90pub struct ListTenantsUseCase;
91
92impl ListTenantsUseCase {
93    pub fn execute(tenants: Vec<Tenant>) -> ListTenantsResponse {
94        let tenant_dtos: Vec<TenantDto> = tenants.iter().map(TenantDto::from).collect();
95        let count = tenant_dtos.len();
96
97        ListTenantsResponse {
98            tenants: tenant_dtos,
99            count,
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use crate::application::dto::TenantQuotasDto;
108
109    #[test]
110    fn test_create_tenant_with_default_quotas() {
111        let request = CreateTenantRequest {
112            tenant_id: "test-tenant".to_string(),
113            name: "Test Tenant".to_string(),
114            quotas: None,
115        };
116
117        let response = CreateTenantUseCase::execute(request);
118        assert!(response.is_ok());
119
120        let response = response.unwrap();
121        assert_eq!(response.tenant.name, "Test Tenant");
122        assert_eq!(response.tenant.tenant_id, "test-tenant");
123        assert!(response.tenant.is_active);
124    }
125
126    #[test]
127    fn test_create_tenant_with_custom_quotas() {
128        let request = CreateTenantRequest {
129            tenant_id: "premium-tenant".to_string(),
130            name: "Premium Tenant".to_string(),
131            quotas: Some(TenantQuotasDto {
132                max_events_per_day: Some(1_000_000),
133                max_storage_bytes: Some(10_000_000_000),
134                max_queries_per_hour: Some(10_000),
135                max_api_keys: Some(50),
136                max_projections: Some(100),
137                max_pipelines: Some(50),
138            }),
139        };
140
141        let response = CreateTenantUseCase::execute(request);
142        assert!(response.is_ok());
143
144        let response = response.unwrap();
145        assert_eq!(response.tenant.quotas.max_events_per_day, Some(1_000_000));
146    }
147
148    #[test]
149    fn test_update_tenant_name() {
150        let tenant_id = TenantId::new("test-tenant".to_string()).unwrap();
151        let tenant = Tenant::new(
152            tenant_id,
153            "Old Name".to_string(),
154            crate::domain::entities::TenantQuotas::free_tier(),
155        )
156        .unwrap();
157
158        let request = UpdateTenantRequest {
159            name: Some("New Name".to_string()),
160            quotas: None,
161        };
162
163        let response = UpdateTenantUseCase::execute(tenant, request);
164        assert!(response.is_ok());
165
166        let response = response.unwrap();
167        assert_eq!(response.tenant.name, "New Name");
168    }
169
170    #[test]
171    fn test_activate_deactivate_tenant() {
172        let tenant_id = TenantId::new("test-tenant".to_string()).unwrap();
173        let tenant = Tenant::new(
174            tenant_id,
175            "Test".to_string(),
176            crate::domain::entities::TenantQuotas::free_tier(),
177        )
178        .unwrap();
179
180        // Deactivate
181        let result = DeactivateTenantUseCase::execute(tenant.clone());
182        assert!(result.is_ok());
183        assert!(!result.unwrap().is_active);
184
185        // Activate
186        let mut deactivated = tenant.clone();
187        deactivated.deactivate();
188        let result = ActivateTenantUseCase::execute(deactivated);
189        assert!(result.is_ok());
190        assert!(result.unwrap().is_active);
191    }
192
193    #[test]
194    fn test_list_tenants() {
195        let tenants = vec![
196            Tenant::new(
197                TenantId::new("tenant-1".to_string()).unwrap(),
198                "Tenant 1".to_string(),
199                crate::domain::entities::TenantQuotas::free_tier(),
200            )
201            .unwrap(),
202            Tenant::new(
203                TenantId::new("tenant-2".to_string()).unwrap(),
204                "Tenant 2".to_string(),
205                crate::domain::entities::TenantQuotas::standard(),
206            )
207            .unwrap(),
208        ];
209
210        let response = ListTenantsUseCase::execute(tenants);
211        assert_eq!(response.count, 2);
212        assert_eq!(response.tenants.len(), 2);
213    }
214}