koprogo_api/domain/entities/
gdpr_restriction.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10pub struct GdprRestrictionRequest {
11 pub id: Uuid,
12 pub user_id: Uuid,
13 pub organization_id: Option<Uuid>,
14 pub requested_at: DateTime<Utc>,
15 pub status: RestrictionStatus,
16 pub reason: RestrictionReason,
17 pub justification: Option<String>,
18 pub effective_from: Option<DateTime<Utc>>,
19 pub effective_until: Option<DateTime<Utc>>,
20 pub processed_at: Option<DateTime<Utc>>,
21 pub processed_by: Option<Uuid>,
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25pub enum RestrictionStatus {
26 Pending,
27 Active, Lifted, Expired, Rejected,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
35pub enum RestrictionReason {
36 AccuracyContested,
38 UnlawfulProcessing,
40 LegalClaims,
42 ObjectionPending,
44}
45
46impl GdprRestrictionRequest {
47 pub fn new(
49 user_id: Uuid,
50 organization_id: Option<Uuid>,
51 reason: RestrictionReason,
52 justification: Option<String>,
53 ) -> Self {
54 Self {
55 id: Uuid::new_v4(),
56 user_id,
57 organization_id,
58 requested_at: Utc::now(),
59 status: RestrictionStatus::Pending,
60 reason,
61 justification,
62 effective_from: None,
63 effective_until: None,
64 processed_at: None,
65 processed_by: None,
66 }
67 }
68
69 pub fn activate(&mut self, admin_id: Uuid, duration_days: Option<u32>) {
71 let now = Utc::now();
72 self.status = RestrictionStatus::Active;
73 self.effective_from = Some(now);
74 self.effective_until = duration_days.map(|days| now + chrono::Duration::days(days as i64));
75 self.processed_at = Some(now);
76 self.processed_by = Some(admin_id);
77 }
78
79 pub fn lift(&mut self, admin_id: Uuid) {
81 self.status = RestrictionStatus::Lifted;
82 self.effective_until = Some(Utc::now());
83 self.processed_at = Some(Utc::now());
84 self.processed_by = Some(admin_id);
85 }
86
87 pub fn reject(&mut self, admin_id: Uuid) {
89 self.status = RestrictionStatus::Rejected;
90 self.processed_at = Some(Utc::now());
91 self.processed_by = Some(admin_id);
92 }
93
94 pub fn is_active(&self) -> bool {
96 if self.status != RestrictionStatus::Active {
97 return false;
98 }
99
100 let now = Utc::now();
101
102 if let Some(from) = self.effective_from {
104 if now < from {
105 return false;
106 }
107 }
108
109 if let Some(until) = self.effective_until {
111 if now > until {
112 return false;
113 }
114 }
115
116 true
117 }
118
119 pub fn is_pending(&self) -> bool {
121 matches!(self.status, RestrictionStatus::Pending)
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_create_restriction_request() {
131 let user_id = Uuid::new_v4();
132 let org_id = Uuid::new_v4();
133
134 let request = GdprRestrictionRequest::new(
135 user_id,
136 Some(org_id),
137 RestrictionReason::AccuracyContested,
138 Some("My email address is incorrect".to_string()),
139 );
140
141 assert_eq!(request.user_id, user_id);
142 assert_eq!(request.organization_id, Some(org_id));
143 assert!(request.is_pending());
144 assert_eq!(request.reason, RestrictionReason::AccuracyContested);
145 }
146
147 #[test]
148 fn test_activate_restriction_without_duration() {
149 let user_id = Uuid::new_v4();
150 let admin_id = Uuid::new_v4();
151
152 let mut request =
153 GdprRestrictionRequest::new(user_id, None, RestrictionReason::ObjectionPending, None);
154
155 request.activate(admin_id, None);
156
157 assert_eq!(request.status, RestrictionStatus::Active);
158 assert!(request.effective_from.is_some());
159 assert!(request.effective_until.is_none());
160 assert!(request.is_active());
161 }
162
163 #[test]
164 fn test_activate_restriction_with_duration() {
165 let user_id = Uuid::new_v4();
166 let admin_id = Uuid::new_v4();
167
168 let mut request =
169 GdprRestrictionRequest::new(user_id, None, RestrictionReason::AccuracyContested, None);
170
171 request.activate(admin_id, Some(30)); assert_eq!(request.status, RestrictionStatus::Active);
174 assert!(request.effective_from.is_some());
175 assert!(request.effective_until.is_some());
176 assert!(request.is_active());
177
178 let from = request.effective_from.unwrap();
180 let until = request.effective_until.unwrap();
181 let duration = until - from;
182 assert!((duration.num_days() - 30).abs() < 1);
183 }
184
185 #[test]
186 fn test_lift_restriction() {
187 let user_id = Uuid::new_v4();
188 let admin_id = Uuid::new_v4();
189
190 let mut request =
191 GdprRestrictionRequest::new(user_id, None, RestrictionReason::UnlawfulProcessing, None);
192
193 request.activate(admin_id, None);
194 assert!(request.is_active());
195
196 request.lift(admin_id);
197 assert_eq!(request.status, RestrictionStatus::Lifted);
198 assert!(!request.is_active());
199 }
200
201 #[test]
202 fn test_reject_restriction() {
203 let user_id = Uuid::new_v4();
204 let admin_id = Uuid::new_v4();
205
206 let mut request =
207 GdprRestrictionRequest::new(user_id, None, RestrictionReason::LegalClaims, None);
208
209 request.reject(admin_id);
210
211 assert_eq!(request.status, RestrictionStatus::Rejected);
212 assert!(!request.is_active());
213 assert!(!request.is_pending());
214 }
215}