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