1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
8pub struct GdprExport {
9 pub export_date: DateTime<Utc>,
10 pub user_data: UserData,
11 pub owner_profiles: Vec<OwnerData>,
12 pub related_data: RelatedData,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
17pub struct UserData {
18 pub id: Uuid,
19 pub email: String,
20 pub first_name: String,
21 pub last_name: String,
22 pub organization_id: Option<Uuid>,
23 pub is_active: bool,
24 pub is_anonymized: bool,
25 pub created_at: DateTime<Utc>,
26 pub updated_at: DateTime<Utc>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
31pub struct OwnerData {
32 pub id: Uuid,
33 pub organization_id: Option<Uuid>,
34 pub first_name: String,
35 pub last_name: String,
36 pub email: Option<String>,
37 pub phone: Option<String>,
38 pub address: Option<String>,
39 pub city: Option<String>,
40 pub postal_code: Option<String>,
41 pub country: Option<String>,
42 pub is_anonymized: bool,
43 pub created_at: DateTime<Utc>,
44 pub updated_at: DateTime<Utc>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
49pub struct RelatedData {
50 pub units: Vec<UnitOwnershipData>,
51 pub expenses: Vec<ExpenseData>,
52 pub documents: Vec<DocumentData>,
53 pub meetings: Vec<MeetingData>,
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
57pub struct UnitOwnershipData {
58 pub building_name: String,
59 pub building_address: String,
60 pub unit_number: String,
61 pub floor: Option<i32>,
62 pub ownership_percentage: f64,
63 pub start_date: DateTime<Utc>,
64 pub end_date: Option<DateTime<Utc>>,
65 pub is_primary_contact: bool,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
69pub struct ExpenseData {
70 pub description: String,
71 pub amount: f64,
72 pub due_date: DateTime<Utc>,
73 pub paid: bool,
74 pub building_name: String,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78pub struct DocumentData {
79 pub title: String,
80 pub document_type: String,
81 pub uploaded_at: DateTime<Utc>,
82 pub building_name: Option<String>,
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
86pub struct MeetingData {
87 pub title: String,
88 pub meeting_date: DateTime<Utc>,
89 pub agenda: Option<String>,
90 pub building_name: String,
91}
92
93impl GdprExport {
94 pub fn new(user_data: UserData) -> Self {
96 Self {
97 export_date: Utc::now(),
98 user_data,
99 owner_profiles: Vec::new(),
100 related_data: RelatedData::default(),
101 }
102 }
103
104 pub fn add_owner_profile(&mut self, owner: OwnerData) {
106 self.owner_profiles.push(owner);
107 }
108
109 pub fn add_unit_ownership(&mut self, unit: UnitOwnershipData) {
111 self.related_data.units.push(unit);
112 }
113
114 pub fn add_expense(&mut self, expense: ExpenseData) {
116 self.related_data.expenses.push(expense);
117 }
118
119 pub fn add_document(&mut self, document: DocumentData) {
121 self.related_data.documents.push(document);
122 }
123
124 pub fn add_meeting(&mut self, meeting: MeetingData) {
126 self.related_data.meetings.push(meeting);
127 }
128
129 pub fn is_anonymized(&self) -> bool {
131 self.user_data.is_anonymized
132 }
133
134 pub fn total_items(&self) -> usize {
136 1 + self.owner_profiles.len()
138 + self.related_data.units.len()
139 + self.related_data.expenses.len()
140 + self.related_data.documents.len()
141 + self.related_data.meetings.len()
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 fn create_test_user_data() -> UserData {
150 UserData {
151 id: Uuid::new_v4(),
152 email: "test@example.com".to_string(),
153 first_name: "John".to_string(),
154 last_name: "Doe".to_string(),
155 organization_id: Some(Uuid::new_v4()),
156 is_active: true,
157 is_anonymized: false,
158 created_at: Utc::now(),
159 updated_at: Utc::now(),
160 }
161 }
162
163 fn create_test_owner_data() -> OwnerData {
164 OwnerData {
165 id: Uuid::new_v4(),
166 organization_id: Some(Uuid::new_v4()),
167 first_name: "John".to_string(),
168 last_name: "Doe".to_string(),
169 email: Some("john.doe@example.com".to_string()),
170 phone: Some("+1234567890".to_string()),
171 address: Some("123 Main St".to_string()),
172 city: Some("Brussels".to_string()),
173 postal_code: Some("1000".to_string()),
174 country: Some("Belgium".to_string()),
175 is_anonymized: false,
176 created_at: Utc::now(),
177 updated_at: Utc::now(),
178 }
179 }
180
181 #[test]
182 fn test_create_gdpr_export() {
183 let user_data = create_test_user_data();
184 let export = GdprExport::new(user_data.clone());
185
186 assert_eq!(export.user_data, user_data);
187 assert_eq!(export.owner_profiles.len(), 0);
188 assert_eq!(export.related_data.units.len(), 0);
189 assert!(!export.is_anonymized());
190 }
191
192 #[test]
193 fn test_add_owner_profile() {
194 let user_data = create_test_user_data();
195 let mut export = GdprExport::new(user_data);
196 let owner = create_test_owner_data();
197
198 export.add_owner_profile(owner.clone());
199
200 assert_eq!(export.owner_profiles.len(), 1);
201 assert_eq!(export.owner_profiles[0], owner);
202 }
203
204 #[test]
205 fn test_add_unit_ownership() {
206 let user_data = create_test_user_data();
207 let mut export = GdprExport::new(user_data);
208 let unit = UnitOwnershipData {
209 building_name: "Building A".to_string(),
210 building_address: "123 Main St".to_string(),
211 unit_number: "101".to_string(),
212 floor: Some(1),
213 ownership_percentage: 50.0,
214 start_date: Utc::now(),
215 end_date: None,
216 is_primary_contact: true,
217 };
218
219 export.add_unit_ownership(unit.clone());
220
221 assert_eq!(export.related_data.units.len(), 1);
222 assert_eq!(export.related_data.units[0], unit);
223 }
224
225 #[test]
226 fn test_add_expense() {
227 let user_data = create_test_user_data();
228 let mut export = GdprExport::new(user_data);
229 let expense = ExpenseData {
230 description: "Monthly maintenance".to_string(),
231 amount: 100.0,
232 due_date: Utc::now(),
233 paid: true,
234 building_name: "Building A".to_string(),
235 };
236
237 export.add_expense(expense.clone());
238
239 assert_eq!(export.related_data.expenses.len(), 1);
240 assert_eq!(export.related_data.expenses[0], expense);
241 }
242
243 #[test]
244 fn test_add_document() {
245 let user_data = create_test_user_data();
246 let mut export = GdprExport::new(user_data);
247 let document = DocumentData {
248 title: "Meeting Minutes".to_string(),
249 document_type: "PDF".to_string(),
250 uploaded_at: Utc::now(),
251 building_name: Some("Building A".to_string()),
252 };
253
254 export.add_document(document.clone());
255
256 assert_eq!(export.related_data.documents.len(), 1);
257 assert_eq!(export.related_data.documents[0], document);
258 }
259
260 #[test]
261 fn test_add_meeting() {
262 let user_data = create_test_user_data();
263 let mut export = GdprExport::new(user_data);
264 let meeting = MeetingData {
265 title: "Annual General Meeting".to_string(),
266 meeting_date: Utc::now(),
267 agenda: Some("Budget approval".to_string()),
268 building_name: "Building A".to_string(),
269 };
270
271 export.add_meeting(meeting.clone());
272
273 assert_eq!(export.related_data.meetings.len(), 1);
274 assert_eq!(export.related_data.meetings[0], meeting);
275 }
276
277 #[test]
278 fn test_is_anonymized() {
279 let mut user_data = create_test_user_data();
280 user_data.is_anonymized = true;
281 let export = GdprExport::new(user_data);
282
283 assert!(export.is_anonymized());
284 }
285
286 #[test]
287 fn test_total_items() {
288 let user_data = create_test_user_data();
289 let mut export = GdprExport::new(user_data);
290
291 assert_eq!(export.total_items(), 1);
293
294 export.add_owner_profile(create_test_owner_data());
295 assert_eq!(export.total_items(), 2);
296
297 export.add_unit_ownership(UnitOwnershipData {
298 building_name: "Building A".to_string(),
299 building_address: "123 Main St".to_string(),
300 unit_number: "101".to_string(),
301 floor: Some(1),
302 ownership_percentage: 50.0,
303 start_date: Utc::now(),
304 end_date: None,
305 is_primary_contact: true,
306 });
307 assert_eq!(export.total_items(), 3);
308 }
309
310 #[test]
311 fn test_serialization() {
312 let user_data = create_test_user_data();
313 let export = GdprExport::new(user_data);
314
315 let json = serde_json::to_string(&export).expect("Should serialize to JSON");
317 assert!(json.contains("export_date"));
318 assert!(json.contains("user_data"));
319 assert!(json.contains("test@example.com"));
320
321 let deserialized: GdprExport =
323 serde_json::from_str(&json).expect("Should deserialize from JSON");
324 assert_eq!(deserialized.user_data.email, export.user_data.email);
325 }
326}