1use serde::{Deserialize, Serialize};
6
7use crate::common::{GrantId, Provider};
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(untagged)]
12pub enum CustomAuthSettings {
13 Google {
15 refresh_token: String,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 client_id: Option<String>,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 client_secret: Option<String>,
25 },
26
27 Microsoft {
29 refresh_token: String,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 client_id: Option<String>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 client_secret: Option<String>,
39 },
40
41 Imap {
43 imap_host: String,
45
46 imap_port: u16,
48
49 imap_username: String,
51
52 imap_password: String,
54
55 smtp_host: String,
57
58 smtp_port: u16,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 smtp_username: Option<String>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 smtp_password: Option<String>,
68 },
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
73#[serde(untagged)]
74pub enum GrantSettings {
75 AccessToken {
77 access_token: String,
79 },
80
81 Custom(CustomAuthSettings),
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
87#[serde(rename_all = "lowercase")]
88pub enum GrantStatus {
89 Valid,
91 Invalid,
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
121pub struct Grant {
122 pub id: GrantId,
124
125 pub provider: Provider,
127
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub grant_status: Option<GrantStatus>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub email: Option<String>,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub scope: Option<Vec<String>>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub user_timezone: Option<String>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub created_at: Option<i64>,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub updated_at: Option<i64>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub provider_user_id: Option<String>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub ip: Option<String>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub state: Option<String>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub user_agent: Option<String>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub settings: Option<serde_json::Value>,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
174 pub metadata: Option<serde_json::Value>,
175}
176
177#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
192pub struct CreateGrantRequest {
193 pub provider: Provider,
195
196 pub settings: GrantSettings,
198
199 #[serde(skip_serializing_if = "Option::is_none")]
201 pub state: Option<GrantStatus>,
202
203 #[serde(skip_serializing_if = "Option::is_none")]
205 pub scope: Option<Vec<String>>,
206
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub metadata: Option<serde_json::Value>,
210}
211
212impl CreateGrantRequest {
213 pub fn builder(provider: Provider) -> CreateGrantRequestBuilder {
215 CreateGrantRequestBuilder::new(provider)
216 }
217
218 pub fn from_access_token(provider: Provider, access_token: String) -> Self {
231 Self {
232 provider,
233 settings: GrantSettings::AccessToken { access_token },
234 state: None,
235 scope: None,
236 metadata: None,
237 }
238 }
239
240 pub fn from_custom_auth(provider: Provider, settings: CustomAuthSettings) -> Self {
264 Self {
265 provider,
266 settings: GrantSettings::Custom(settings),
267 state: None,
268 scope: None,
269 metadata: None,
270 }
271 }
272}
273
274#[derive(Debug, Clone)]
276pub struct CreateGrantRequestBuilder {
277 provider: Provider,
278 settings: Option<GrantSettings>,
279 grant_status: Option<GrantStatus>,
280 scope: Option<Vec<String>>,
281 metadata: Option<serde_json::Value>,
282}
283
284impl CreateGrantRequestBuilder {
285 pub fn new(provider: Provider) -> Self {
287 Self {
288 provider,
289 settings: None,
290 grant_status: None,
291 scope: None,
292 metadata: None,
293 }
294 }
295
296 pub fn settings(mut self, settings: GrantSettings) -> Self {
298 self.settings = Some(settings);
299 self
300 }
301
302 pub fn access_token(mut self, token: String) -> Self {
304 self.settings = Some(GrantSettings::AccessToken {
305 access_token: token,
306 });
307 self
308 }
309
310 pub fn custom_auth(mut self, auth: CustomAuthSettings) -> Self {
312 self.settings = Some(GrantSettings::Custom(auth));
313 self
314 }
315
316 pub fn grant_status(mut self, status: GrantStatus) -> Self {
318 self.grant_status = Some(status);
319 self
320 }
321
322 pub fn scope(mut self, scope: Vec<String>) -> Self {
324 self.scope = Some(scope);
325 self
326 }
327
328 pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
330 self.metadata = Some(metadata);
331 self
332 }
333
334 pub fn build(self) -> CreateGrantRequest {
340 CreateGrantRequest {
341 provider: self.provider,
342 settings: self.settings.expect("settings are required"),
343 state: self.grant_status,
344 scope: self.scope,
345 metadata: self.metadata,
346 }
347 }
348}
349
350#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
352pub struct UpdateGrantRequest {
353 #[serde(skip_serializing_if = "Option::is_none")]
355 pub settings: Option<GrantSettings>,
356
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub state: Option<GrantStatus>,
360
361 #[serde(skip_serializing_if = "Option::is_none")]
363 pub scope: Option<Vec<String>>,
364
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub metadata: Option<serde_json::Value>,
368}
369
370impl UpdateGrantRequest {
371 pub fn builder() -> UpdateGrantRequestBuilder {
373 UpdateGrantRequestBuilder::default()
374 }
375}
376
377#[derive(Debug, Clone, Default)]
379pub struct UpdateGrantRequestBuilder {
380 settings: Option<GrantSettings>,
381 state: Option<GrantStatus>,
382 scope: Option<Vec<String>>,
383 metadata: Option<serde_json::Value>,
384}
385
386impl UpdateGrantRequestBuilder {
387 pub fn settings(mut self, settings: GrantSettings) -> Self {
389 self.settings = Some(settings);
390 self
391 }
392
393 pub fn state(mut self, state: GrantStatus) -> Self {
395 self.state = Some(state);
396 self
397 }
398
399 pub fn scope(mut self, scope: Vec<String>) -> Self {
401 self.scope = Some(scope);
402 self
403 }
404
405 pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
407 self.metadata = Some(metadata);
408 self
409 }
410
411 pub fn build(self) -> UpdateGrantRequest {
413 UpdateGrantRequest {
414 settings: self.settings,
415 state: self.state,
416 scope: self.scope,
417 metadata: self.metadata,
418 }
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425
426 #[test]
427 fn test_grant_serialization() {
428 let grant = Grant {
429 id: GrantId::new("grant_123"),
430 provider: Provider::Google,
431 grant_status: Some(GrantStatus::Valid),
432 email: Some("user@example.com".to_string()),
433 scope: Some(vec![
434 "https://www.googleapis.com/auth/gmail.readonly".to_string()
435 ]),
436 user_timezone: None,
437 created_at: Some(1234567890),
438 updated_at: Some(1234567890),
439 provider_user_id: None,
440 ip: None,
441 state: None,
442 user_agent: None,
443 settings: None,
444 metadata: None,
445 };
446
447 let json = serde_json::to_string(&grant).unwrap();
448 assert!(json.contains("grant_123"));
449 assert!(json.contains("google"));
450 assert!(json.contains("user@example.com"));
451 }
452
453 #[test]
454 fn test_grant_deserialization() {
455 let json = r#"{
456 "id": "grant_123",
457 "provider": "google",
458 "grant_status": "valid",
459 "email": "user@example.com",
460 "scope": ["https://www.googleapis.com/auth/gmail.readonly"],
461 "created_at": 1234567890,
462 "updated_at": 1234567890
463 }"#;
464
465 let grant: Grant = serde_json::from_str(json).unwrap();
466 assert_eq!(grant.id.as_str(), "grant_123");
467 assert_eq!(grant.provider, Provider::Google);
468 assert_eq!(grant.grant_status, Some(GrantStatus::Valid));
469 assert_eq!(grant.email, Some("user@example.com".to_string()));
470 }
471
472 #[test]
473 fn test_grant_status_serialization() {
474 assert_eq!(
475 serde_json::to_string(&GrantStatus::Valid).unwrap(),
476 r#""valid""#
477 );
478 assert_eq!(
479 serde_json::to_string(&GrantStatus::Invalid).unwrap(),
480 r#""invalid""#
481 );
482 }
483
484 #[test]
485 fn test_create_grant_request_builder() {
486 let request = CreateGrantRequest::builder(Provider::Google)
487 .access_token("token_123".to_string())
488 .scope(vec![
489 "https://www.googleapis.com/auth/gmail.readonly".to_string()
490 ])
491 .grant_status(GrantStatus::Valid)
492 .build();
493
494 assert_eq!(request.provider, Provider::Google);
495 assert!(request.scope.is_some());
496 assert_eq!(request.state, Some(GrantStatus::Valid));
497 assert!(request.metadata.is_none());
498 }
499
500 #[test]
501 fn test_create_grant_request_with_metadata() {
502 let metadata = serde_json::json!({"team": "engineering"});
503 let request = CreateGrantRequest::builder(Provider::Microsoft)
504 .access_token("token_456".to_string())
505 .metadata(metadata.clone())
506 .build();
507
508 assert_eq!(request.provider, Provider::Microsoft);
509 assert_eq!(request.metadata, Some(metadata));
510 }
511
512 #[test]
513 fn test_create_grant_from_access_token() {
514 let request =
515 CreateGrantRequest::from_access_token(Provider::Google, "token_123".to_string());
516
517 assert_eq!(request.provider, Provider::Google);
518 assert!(matches!(
519 request.settings,
520 GrantSettings::AccessToken { .. }
521 ));
522 }
523
524 #[test]
525 fn test_create_grant_from_custom_auth() {
526 let custom_auth = CustomAuthSettings::Imap {
527 imap_host: "imap.example.com".to_string(),
528 imap_port: 993,
529 imap_username: "user@example.com".to_string(),
530 imap_password: "password".to_string(),
531 smtp_host: "smtp.example.com".to_string(),
532 smtp_port: 587,
533 smtp_username: None,
534 smtp_password: None,
535 };
536
537 let request = CreateGrantRequest::from_custom_auth(Provider::Imap, custom_auth);
538
539 assert_eq!(request.provider, Provider::Imap);
540 assert!(matches!(request.settings, GrantSettings::Custom(_)));
541 }
542
543 #[test]
544 fn test_update_grant_request_builder() {
545 let metadata = serde_json::json!({"updated": true});
546 let request = UpdateGrantRequest::builder()
547 .metadata(metadata.clone())
548 .scope(vec!["new_scope".to_string()])
549 .state(GrantStatus::Invalid)
550 .build();
551
552 assert_eq!(request.metadata, Some(metadata));
553 assert_eq!(request.scope, Some(vec!["new_scope".to_string()]));
554 assert_eq!(request.state, Some(GrantStatus::Invalid));
555 assert!(request.settings.is_none());
556 }
557
558 #[test]
559 fn test_update_grant_request_default() {
560 let request = UpdateGrantRequest::default();
561 assert!(request.settings.is_none());
562 assert!(request.state.is_none());
563 assert!(request.scope.is_none());
564 assert!(request.metadata.is_none());
565 }
566}