1use crate::domain::entities::gdpr_export::{
2 DocumentData, ExpenseData, GdprExport, MeetingData, OwnerData, UnitOwnershipData, UserData,
3};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
8pub struct GdprExportResponseDto {
9 pub export_date: String, pub user: UserDataDto,
11 pub owners: Vec<OwnerDataDto>,
12 pub units: Vec<UnitOwnershipDataDto>,
13 pub expenses: Vec<ExpenseDataDto>,
14 pub documents: Vec<DocumentDataDto>,
15 pub meetings: Vec<MeetingDataDto>,
16 pub total_items: usize,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
20pub struct UserDataDto {
21 pub id: String,
22 pub email: String,
23 pub first_name: String,
24 pub last_name: String,
25 pub organization_id: Option<String>,
26 pub is_active: bool,
27 pub is_anonymized: bool,
28 pub created_at: String,
29 pub updated_at: String,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
33pub struct OwnerDataDto {
34 pub id: String,
35 pub organization_id: String,
36 pub first_name: String,
37 pub last_name: String,
38 pub email: Option<String>,
39 pub phone: Option<String>,
40 pub address: Option<String>,
41 pub city: Option<String>,
42 pub postal_code: Option<String>,
43 pub country: Option<String>,
44 pub is_anonymized: bool,
45 pub created_at: String,
46 pub updated_at: String,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
50pub struct UnitOwnershipDataDto {
51 pub building_name: String,
52 pub building_address: String,
53 pub unit_number: String,
54 pub floor: Option<i32>,
55 pub ownership_percentage: rust_decimal::Decimal,
56 pub start_date: String,
57 pub end_date: Option<String>,
58 pub is_primary_contact: bool,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
62pub struct ExpenseDataDto {
63 pub description: String,
64 #[schema(value_type = String, example = "100.00")]
65 pub amount: rust_decimal::Decimal,
66 pub due_date: String,
67 pub paid: bool,
68 pub building_name: String,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
72pub struct DocumentDataDto {
73 pub title: String,
74 pub document_type: String,
75 pub uploaded_at: String,
76 pub building_name: Option<String>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, utoipa::ToSchema)]
80pub struct MeetingDataDto {
81 pub title: String,
82 pub meeting_date: String,
83 pub agenda: Option<String>,
84 pub building_name: String,
85}
86
87impl From<GdprExport> for GdprExportResponseDto {
88 fn from(export: GdprExport) -> Self {
89 let total_items = export.total_items();
90 Self {
91 export_date: export.export_date.to_rfc3339(),
92 user: UserDataDto::from(export.user_data),
93 owners: export
94 .owner_profiles
95 .into_iter()
96 .map(OwnerDataDto::from)
97 .collect(),
98 units: export
99 .related_data
100 .units
101 .into_iter()
102 .map(UnitOwnershipDataDto::from)
103 .collect(),
104 expenses: export
105 .related_data
106 .expenses
107 .into_iter()
108 .map(ExpenseDataDto::from)
109 .collect(),
110 documents: export
111 .related_data
112 .documents
113 .into_iter()
114 .map(DocumentDataDto::from)
115 .collect(),
116 meetings: export
117 .related_data
118 .meetings
119 .into_iter()
120 .map(MeetingDataDto::from)
121 .collect(),
122 total_items,
123 }
124 }
125}
126
127impl From<UserData> for UserDataDto {
128 fn from(user: UserData) -> Self {
129 Self {
130 id: user.id.to_string(),
131 email: user.email,
132 first_name: user.first_name,
133 last_name: user.last_name,
134 organization_id: user.organization_id.map(|id| id.to_string()),
135 is_active: user.is_active,
136 is_anonymized: user.is_anonymized,
137 created_at: user.created_at.to_rfc3339(),
138 updated_at: user.updated_at.to_rfc3339(),
139 }
140 }
141}
142
143impl From<OwnerData> for OwnerDataDto {
144 fn from(owner: OwnerData) -> Self {
145 Self {
146 id: owner.id.to_string(),
147 organization_id: owner
148 .organization_id
149 .map(|id| id.to_string())
150 .unwrap_or_else(|| "none".to_string()),
151 first_name: owner.first_name,
152 last_name: owner.last_name,
153 email: owner.email,
154 phone: owner.phone,
155 address: owner.address,
156 city: owner.city,
157 postal_code: owner.postal_code,
158 country: owner.country,
159 is_anonymized: owner.is_anonymized,
160 created_at: owner.created_at.to_rfc3339(),
161 updated_at: owner.updated_at.to_rfc3339(),
162 }
163 }
164}
165
166impl From<UnitOwnershipData> for UnitOwnershipDataDto {
167 fn from(unit: UnitOwnershipData) -> Self {
168 Self {
169 building_name: unit.building_name,
170 building_address: unit.building_address,
171 unit_number: unit.unit_number,
172 floor: unit.floor,
173 ownership_percentage: unit.ownership_percentage,
174 start_date: unit.start_date.to_rfc3339(),
175 end_date: unit.end_date.map(|d| d.to_rfc3339()),
176 is_primary_contact: unit.is_primary_contact,
177 }
178 }
179}
180
181impl From<ExpenseData> for ExpenseDataDto {
182 fn from(expense: ExpenseData) -> Self {
183 Self {
184 description: expense.description,
185 amount: expense.amount,
186 due_date: expense.due_date.to_rfc3339(),
187 paid: expense.paid,
188 building_name: expense.building_name,
189 }
190 }
191}
192
193impl From<DocumentData> for DocumentDataDto {
194 fn from(document: DocumentData) -> Self {
195 Self {
196 title: document.title,
197 document_type: document.document_type,
198 uploaded_at: document.uploaded_at.to_rfc3339(),
199 building_name: document.building_name,
200 }
201 }
202}
203
204impl From<MeetingData> for MeetingDataDto {
205 fn from(meeting: MeetingData) -> Self {
206 Self {
207 title: meeting.title,
208 meeting_date: meeting.meeting_date.to_rfc3339(),
209 agenda: meeting.agenda,
210 building_name: meeting.building_name,
211 }
212 }
213}
214
215#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
217pub struct GdprEraseRequestDto {
218 pub password: String,
222 pub confirmation: Option<String>,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
228pub struct GdprEraseResponseDto {
229 pub success: bool,
230 pub message: String,
231 pub anonymized_at: String,
232 pub user_id: String,
233 pub user_email: String,
234 pub user_first_name: String,
235 pub user_last_name: String,
236 pub owners_anonymized: usize,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
241pub struct GdprRectifyRequest {
242 pub email: Option<String>,
243 pub first_name: Option<String>,
244 pub last_name: Option<String>,
245}
246
247#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
249pub struct GdprRestrictProcessingRequest {
250 }
252
253#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
255pub struct GdprMarketingPreferenceRequest {
256 pub opt_out: bool,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)]
261pub struct GdprActionResponse {
262 pub success: bool,
263 pub message: String,
264 pub updated_at: String,
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270 use chrono::Utc;
271 use uuid::Uuid;
272
273 fn create_test_gdpr_export() -> GdprExport {
274 let user_data = UserData {
275 id: Uuid::new_v4(),
276 email: "test@example.com".to_string(),
277 first_name: "John".to_string(),
278 last_name: "Doe".to_string(),
279 organization_id: Some(Uuid::new_v4()),
280 is_active: true,
281 is_anonymized: false,
282 created_at: Utc::now(),
283 updated_at: Utc::now(),
284 };
285
286 GdprExport::new(user_data)
287 }
288
289 #[test]
290 fn test_gdpr_export_response_dto_from_domain() {
291 let export = create_test_gdpr_export();
292 let user_email = export.user_data.email.clone();
293
294 let dto = GdprExportResponseDto::from(export);
295
296 assert_eq!(dto.user.email, user_email);
297 assert_eq!(dto.total_items, 1); assert!(dto.export_date.contains('T')); }
300
301 #[test]
302 fn test_user_data_dto_conversion() {
303 let user_data = UserData {
304 id: Uuid::new_v4(),
305 email: "test@example.com".to_string(),
306 first_name: "John".to_string(),
307 last_name: "Doe".to_string(),
308 organization_id: Some(Uuid::new_v4()),
309 is_active: true,
310 is_anonymized: false,
311 created_at: Utc::now(),
312 updated_at: Utc::now(),
313 };
314
315 let dto = UserDataDto::from(user_data.clone());
316
317 assert_eq!(dto.email, user_data.email);
318 assert_eq!(dto.first_name, user_data.first_name);
319 assert_eq!(dto.last_name, user_data.last_name);
320 assert!(!dto.is_anonymized);
321 }
322
323 #[test]
324 fn test_owner_data_dto_conversion() {
325 let owner_data = OwnerData {
326 id: Uuid::new_v4(),
327 organization_id: Some(Uuid::new_v4()),
328 first_name: "Jane".to_string(),
329 last_name: "Smith".to_string(),
330 email: Some("jane@example.com".to_string()),
331 phone: Some("+1234567890".to_string()),
332 address: Some("123 Main St".to_string()),
333 city: Some("Brussels".to_string()),
334 postal_code: Some("1000".to_string()),
335 country: Some("Belgium".to_string()),
336 is_anonymized: false,
337 created_at: Utc::now(),
338 updated_at: Utc::now(),
339 };
340
341 let dto = OwnerDataDto::from(owner_data.clone());
342
343 assert_eq!(dto.first_name, owner_data.first_name);
344 assert_eq!(dto.email, owner_data.email);
345 assert_eq!(dto.phone, owner_data.phone);
346 }
347
348 #[test]
349 fn test_json_serialization() {
350 let export = create_test_gdpr_export();
351 let dto = GdprExportResponseDto::from(export);
352
353 let json = serde_json::to_string(&dto).expect("Should serialize to JSON");
355 assert!(json.contains("export_date"));
356 assert!(json.contains("test@example.com"));
357 assert!(json.contains("total_items"));
358
359 let deserialized: GdprExportResponseDto =
361 serde_json::from_str(&json).expect("Should deserialize from JSON");
362 assert_eq!(deserialized.user.email, dto.user.email);
363 }
364
365 #[test]
366 fn test_erase_request_dto() {
367 let request = GdprEraseRequestDto {
368 password: "s3cret".to_string(),
369 confirmation: Some("CONFIRM_DELETE".to_string()),
370 };
371
372 let json = serde_json::to_string(&request).expect("Should serialize");
373 assert!(json.contains("CONFIRM_DELETE"));
374 }
375
376 #[test]
377 fn test_erase_response_dto() {
378 let response = GdprEraseResponseDto {
379 success: true,
380 message: "Data successfully anonymized".to_string(),
381 anonymized_at: Utc::now().to_rfc3339(),
382 user_id: Uuid::new_v4().to_string(),
383 user_email: "test@example.com".to_string(),
384 user_first_name: "John".to_string(),
385 user_last_name: "Doe".to_string(),
386 owners_anonymized: 2,
387 };
388
389 let json = serde_json::to_string(&response).expect("Should serialize");
390 assert!(json.contains("success"));
391 assert!(json.contains("owners_anonymized"));
392 assert!(json.contains("test@example.com"));
393 }
394}