Skip to main content

allsource_core/application/use_cases/
manage_tenant.rs

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