koprogo_api/domain/entities/
consent.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use uuid::Uuid;
4
5const VALID_CONSENT_TYPES: [&str; 2] = ["privacy_policy", "terms"];
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct ConsentRecord {
15 pub id: Uuid,
16 pub user_id: Uuid,
17 pub organization_id: Uuid,
18 pub consent_type: String,
19 pub accepted_at: DateTime<Utc>,
20 pub ip_address: Option<String>,
21 pub user_agent: Option<String>,
22 pub policy_version: String,
23 pub created_at: DateTime<Utc>,
24 pub updated_at: DateTime<Utc>,
25}
26
27impl ConsentRecord {
28 pub fn new(
38 user_id: Uuid,
39 organization_id: Uuid,
40 consent_type: &str,
41 ip_address: Option<String>,
42 user_agent: Option<String>,
43 policy_version: Option<String>,
44 ) -> Result<Self, String> {
45 if !VALID_CONSENT_TYPES.contains(&consent_type) {
47 return Err(format!(
48 "Invalid consent type '{}'. Must be one of: {}",
49 consent_type,
50 VALID_CONSENT_TYPES.join(", ")
51 ));
52 }
53
54 let version = policy_version.unwrap_or_else(|| "1.0".to_string());
55 if version.is_empty() {
56 return Err("Policy version cannot be empty".to_string());
57 }
58
59 let now = Utc::now();
60
61 Ok(Self {
62 id: Uuid::new_v4(),
63 user_id,
64 organization_id,
65 consent_type: consent_type.to_string(),
66 accepted_at: now,
67 ip_address,
68 user_agent,
69 policy_version: version,
70 created_at: now,
71 updated_at: now,
72 })
73 }
74
75 pub fn is_privacy_policy(&self) -> bool {
77 self.consent_type == "privacy_policy"
78 }
79
80 pub fn is_terms(&self) -> bool {
82 self.consent_type == "terms"
83 }
84}
85
86#[derive(Debug, Clone, Default, Serialize, Deserialize)]
88pub struct ConsentStatus {
89 pub privacy_policy_accepted: bool,
90 pub terms_accepted: bool,
91 pub privacy_policy_accepted_at: Option<DateTime<Utc>>,
92 pub terms_accepted_at: Option<DateTime<Utc>>,
93 pub privacy_policy_version: Option<String>,
94 pub terms_version: Option<String>,
95}
96
97
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn test_new_privacy_policy_consent() {
105 let user_id = Uuid::new_v4();
106 let org_id = Uuid::new_v4();
107 let record = ConsentRecord::new(
108 user_id,
109 org_id,
110 "privacy_policy",
111 Some("192.168.1.1".to_string()),
112 Some("Mozilla/5.0".to_string()),
113 Some("1.2".to_string()),
114 )
115 .unwrap();
116
117 assert_eq!(record.user_id, user_id);
118 assert_eq!(record.organization_id, org_id);
119 assert_eq!(record.consent_type, "privacy_policy");
120 assert_eq!(record.policy_version, "1.2");
121 assert!(record.is_privacy_policy());
122 assert!(!record.is_terms());
123 assert_eq!(record.ip_address.as_deref(), Some("192.168.1.1"));
124 assert_eq!(record.user_agent.as_deref(), Some("Mozilla/5.0"));
125 }
126
127 #[test]
128 fn test_new_terms_consent() {
129 let record =
130 ConsentRecord::new(Uuid::new_v4(), Uuid::new_v4(), "terms", None, None, None).unwrap();
131
132 assert_eq!(record.consent_type, "terms");
133 assert_eq!(record.policy_version, "1.0"); assert!(record.is_terms());
135 assert!(!record.is_privacy_policy());
136 }
137
138 #[test]
139 fn test_invalid_consent_type() {
140 let result = ConsentRecord::new(
141 Uuid::new_v4(),
142 Uuid::new_v4(),
143 "invalid_type",
144 None,
145 None,
146 None,
147 );
148 assert!(result.is_err());
149 assert!(result
150 .unwrap_err()
151 .contains("Invalid consent type 'invalid_type'"));
152 }
153
154 #[test]
155 fn test_empty_policy_version() {
156 let result = ConsentRecord::new(
157 Uuid::new_v4(),
158 Uuid::new_v4(),
159 "privacy_policy",
160 None,
161 None,
162 Some("".to_string()),
163 );
164 assert!(result.is_err());
165 assert!(result
166 .unwrap_err()
167 .contains("Policy version cannot be empty"));
168 }
169
170 #[test]
171 fn test_consent_generates_unique_ids() {
172 let r1 =
173 ConsentRecord::new(Uuid::new_v4(), Uuid::new_v4(), "terms", None, None, None).unwrap();
174 let r2 =
175 ConsentRecord::new(Uuid::new_v4(), Uuid::new_v4(), "terms", None, None, None).unwrap();
176 assert_ne!(r1.id, r2.id);
177 }
178
179 #[test]
180 fn test_consent_status_default() {
181 let status = ConsentStatus::default();
182 assert!(!status.privacy_policy_accepted);
183 assert!(!status.terms_accepted);
184 assert!(status.privacy_policy_accepted_at.is_none());
185 assert!(status.terms_accepted_at.is_none());
186 }
187}