koprogo_api/application/use_cases/
energy_bill_upload_use_cases.rs1use std::sync::Arc;
2use uuid::Uuid;
3
4use crate::application::ports::{EnergyBillUploadRepository, EnergyCampaignRepository};
5use crate::domain::entities::{CampaignStatus, EnergyBillUpload};
6
7pub struct EnergyBillUploadUseCases {
8 upload_repo: Arc<dyn EnergyBillUploadRepository>,
9 campaign_repo: Arc<dyn EnergyCampaignRepository>,
10}
11
12impl EnergyBillUploadUseCases {
13 pub fn new(
14 upload_repo: Arc<dyn EnergyBillUploadRepository>,
15 campaign_repo: Arc<dyn EnergyCampaignRepository>,
16 ) -> Self {
17 Self {
18 upload_repo,
19 campaign_repo,
20 }
21 }
22
23 pub async fn upload_bill(&self, upload: EnergyBillUpload) -> Result<EnergyBillUpload, String> {
25 let campaign = self
27 .campaign_repo
28 .find_by_id(upload.campaign_id)
29 .await?
30 .ok_or_else(|| "Campaign not found".to_string())?;
31
32 if campaign.status != CampaignStatus::CollectingData {
33 return Err("Campaign is not collecting data".to_string());
34 }
35
36 let existing = self
38 .upload_repo
39 .find_by_campaign_and_unit(upload.campaign_id, upload.unit_id)
40 .await?;
41
42 if existing.is_some() {
43 return Err("Unit has already uploaded bill for this campaign".to_string());
44 }
45
46 self.upload_repo.create(&upload).await
47 }
48
49 pub async fn get_upload(&self, id: Uuid) -> Result<Option<EnergyBillUpload>, String> {
51 self.upload_repo.find_by_id(id).await
52 }
53
54 pub async fn get_uploads_by_campaign(
56 &self,
57 campaign_id: Uuid,
58 ) -> Result<Vec<EnergyBillUpload>, String> {
59 self.upload_repo.find_by_campaign(campaign_id).await
60 }
61
62 pub async fn get_my_uploads(&self, unit_id: Uuid) -> Result<Vec<EnergyBillUpload>, String> {
64 self.upload_repo.find_by_unit(unit_id).await
65 }
66
67 pub async fn verify_upload(
69 &self,
70 upload_id: Uuid,
71 verified_by: Uuid,
72 ) -> Result<EnergyBillUpload, String> {
73 let mut upload = self
74 .upload_repo
75 .find_by_id(upload_id)
76 .await?
77 .ok_or_else(|| "Upload not found".to_string())?;
78
79 upload.mark_verified(verified_by)?;
80 self.upload_repo.update(&upload).await
81 }
82
83 pub async fn anonymize_upload(&self, upload_id: Uuid) -> Result<EnergyBillUpload, String> {
85 let mut upload = self
86 .upload_repo
87 .find_by_id(upload_id)
88 .await?
89 .ok_or_else(|| "Upload not found".to_string())?;
90
91 upload.anonymize()?;
92 self.upload_repo.update(&upload).await
93 }
94
95 pub async fn batch_anonymize_campaign(&self, campaign_id: Uuid) -> Result<i32, String> {
97 let uploads = self
98 .upload_repo
99 .find_verified_by_campaign(campaign_id)
100 .await?;
101
102 let mut count = 0;
103 for mut upload in uploads {
104 if !upload.anonymized {
105 if upload.anonymize().is_ok() {
106 self.upload_repo.update(&upload).await?;
107 count += 1;
108 }
109 }
110 }
111
112 Ok(count)
113 }
114
115 pub async fn decrypt_consumption(
117 &self,
118 upload_id: Uuid,
119 requester_unit_id: Uuid,
120 encryption_key: &[u8; 32],
121 ) -> Result<f64, String> {
122 let upload = self
123 .upload_repo
124 .find_by_id(upload_id)
125 .await?
126 .ok_or_else(|| "Upload not found".to_string())?;
127
128 if upload.unit_id != requester_unit_id {
130 return Err("Unauthorized: You can only access your own data".to_string());
131 }
132
133 upload.decrypt_kwh(encryption_key)
134 }
135
136 pub async fn delete_upload(
138 &self,
139 upload_id: Uuid,
140 requester_unit_id: Uuid,
141 ) -> Result<(), String> {
142 let mut upload = self
143 .upload_repo
144 .find_by_id(upload_id)
145 .await?
146 .ok_or_else(|| "Upload not found".to_string())?;
147
148 if upload.unit_id != requester_unit_id {
150 return Err("Unauthorized: You can only delete your own data".to_string());
151 }
152
153 upload.delete()?;
154 self.upload_repo.update(&upload).await?;
155 Ok(())
156 }
157
158 pub async fn withdraw_consent(
160 &self,
161 upload_id: Uuid,
162 requester_unit_id: Uuid,
163 ) -> Result<(), String> {
164 let mut upload = self
165 .upload_repo
166 .find_by_id(upload_id)
167 .await?
168 .ok_or_else(|| "Upload not found".to_string())?;
169
170 if upload.unit_id != requester_unit_id {
172 return Err("Unauthorized: You can only withdraw your own consent".to_string());
173 }
174
175 upload.withdraw_consent()?;
176 self.upload_repo.update(&upload).await?;
177 Ok(())
178 }
179
180 pub async fn get_verified_count(&self, campaign_id: Uuid) -> Result<i32, String> {
182 self.upload_repo
183 .count_verified_by_campaign(campaign_id)
184 .await
185 }
186
187 pub async fn check_k_anonymity(&self, campaign_id: Uuid) -> Result<bool, String> {
189 let count = self.get_verified_count(campaign_id).await?;
190 Ok(count >= 5)
191 }
192
193 pub async fn cleanup_expired(&self) -> Result<i32, String> {
195 self.upload_repo.delete_expired().await
196 }
197
198 pub async fn get_expired_count(&self) -> Result<usize, String> {
200 let expired = self.upload_repo.find_expired().await?;
201 Ok(expired.len())
202 }
203}