1use serde::{Deserialize, Serialize};
4
5use crate::{Attachment, DraftId, EmailAddress, FolderId, GrantId, ThreadId};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
34pub struct Draft {
35 pub id: DraftId,
37
38 pub grant_id: GrantId,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub thread_id: Option<ThreadId>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub subject: Option<String>,
48
49 #[serde(default)]
51 pub from: Vec<EmailAddress>,
52
53 #[serde(default)]
55 pub to: Vec<EmailAddress>,
56
57 #[serde(default)]
59 pub cc: Vec<EmailAddress>,
60
61 #[serde(default)]
63 pub bcc: Vec<EmailAddress>,
64
65 #[serde(default)]
67 pub reply_to: Vec<EmailAddress>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub body: Option<String>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub starred: Option<bool>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub snippet: Option<String>,
80
81 #[serde(default)]
83 pub attachments: Vec<Attachment>,
84
85 #[serde(default)]
87 pub folders: Vec<FolderId>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub created_at: Option<i64>,
92}
93
94#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
108pub struct CreateDraftRequest {
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub subject: Option<String>,
112
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub from: Option<Vec<EmailAddress>>,
116
117 #[serde(skip_serializing_if = "Option::is_none")]
119 pub to: Option<Vec<EmailAddress>>,
120
121 #[serde(skip_serializing_if = "Option::is_none")]
123 pub cc: Option<Vec<EmailAddress>>,
124
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub bcc: Option<Vec<EmailAddress>>,
128
129 #[serde(skip_serializing_if = "Option::is_none")]
131 pub reply_to: Option<Vec<EmailAddress>>,
132
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub body: Option<String>,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub thread_id: Option<String>,
140
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub starred: Option<bool>,
144}
145
146impl CreateDraftRequest {
147 pub fn builder() -> CreateDraftRequestBuilder {
149 CreateDraftRequestBuilder::default()
150 }
151}
152
153#[derive(Debug, Clone, Default)]
155pub struct CreateDraftRequestBuilder {
156 request: CreateDraftRequest,
157}
158
159impl CreateDraftRequestBuilder {
160 pub fn subject(mut self, subject: impl Into<String>) -> Self {
162 self.request.subject = Some(subject.into());
163 self
164 }
165
166 pub fn from(mut self, from: Vec<EmailAddress>) -> Self {
168 self.request.from = Some(from);
169 self
170 }
171
172 pub fn to(mut self, to: Vec<EmailAddress>) -> Self {
174 self.request.to = Some(to);
175 self
176 }
177
178 pub fn cc(mut self, cc: Vec<EmailAddress>) -> Self {
180 self.request.cc = Some(cc);
181 self
182 }
183
184 pub fn bcc(mut self, bcc: Vec<EmailAddress>) -> Self {
186 self.request.bcc = Some(bcc);
187 self
188 }
189
190 pub fn reply_to(mut self, reply_to: Vec<EmailAddress>) -> Self {
192 self.request.reply_to = Some(reply_to);
193 self
194 }
195
196 pub fn body(mut self, body: impl Into<String>) -> Self {
198 self.request.body = Some(body.into());
199 self
200 }
201
202 pub fn thread_id(mut self, thread_id: impl Into<String>) -> Self {
204 self.request.thread_id = Some(thread_id.into());
205 self
206 }
207
208 pub fn starred(mut self, starred: bool) -> Self {
210 self.request.starred = Some(starred);
211 self
212 }
213
214 pub fn build(self) -> CreateDraftRequest {
216 self.request
217 }
218}
219
220#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
232pub struct UpdateDraftRequest {
233 #[serde(skip_serializing_if = "Option::is_none")]
235 pub subject: Option<String>,
236
237 #[serde(skip_serializing_if = "Option::is_none")]
239 pub from: Option<Vec<EmailAddress>>,
240
241 #[serde(skip_serializing_if = "Option::is_none")]
243 pub to: Option<Vec<EmailAddress>>,
244
245 #[serde(skip_serializing_if = "Option::is_none")]
247 pub cc: Option<Vec<EmailAddress>>,
248
249 #[serde(skip_serializing_if = "Option::is_none")]
251 pub bcc: Option<Vec<EmailAddress>>,
252
253 #[serde(skip_serializing_if = "Option::is_none")]
255 pub reply_to: Option<Vec<EmailAddress>>,
256
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub body: Option<String>,
260
261 #[serde(skip_serializing_if = "Option::is_none")]
263 pub starred: Option<bool>,
264}
265
266impl UpdateDraftRequest {
267 pub fn builder() -> UpdateDraftRequestBuilder {
269 UpdateDraftRequestBuilder::default()
270 }
271}
272
273#[derive(Debug, Clone, Default)]
275pub struct UpdateDraftRequestBuilder {
276 request: UpdateDraftRequest,
277}
278
279impl UpdateDraftRequestBuilder {
280 pub fn subject(mut self, subject: impl Into<String>) -> Self {
282 self.request.subject = Some(subject.into());
283 self
284 }
285
286 pub fn from(mut self, from: Vec<EmailAddress>) -> Self {
288 self.request.from = Some(from);
289 self
290 }
291
292 pub fn to(mut self, to: Vec<EmailAddress>) -> Self {
294 self.request.to = Some(to);
295 self
296 }
297
298 pub fn cc(mut self, cc: Vec<EmailAddress>) -> Self {
300 self.request.cc = Some(cc);
301 self
302 }
303
304 pub fn bcc(mut self, bcc: Vec<EmailAddress>) -> Self {
306 self.request.bcc = Some(bcc);
307 self
308 }
309
310 pub fn reply_to(mut self, reply_to: Vec<EmailAddress>) -> Self {
312 self.request.reply_to = Some(reply_to);
313 self
314 }
315
316 pub fn body(mut self, body: impl Into<String>) -> Self {
318 self.request.body = Some(body.into());
319 self
320 }
321
322 pub fn starred(mut self, starred: bool) -> Self {
324 self.request.starred = Some(starred);
325 self
326 }
327
328 pub fn build(self) -> UpdateDraftRequest {
330 self.request
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337
338 #[test]
339 fn test_draft_creation() {
340 let draft = Draft {
341 id: DraftId::new("draft_123"),
342 grant_id: GrantId::new("grant_123"),
343 thread_id: Some(ThreadId::new("thread_123")),
344 subject: Some("Test Draft".to_string()),
345 from: vec![],
346 to: vec![],
347 cc: vec![],
348 bcc: vec![],
349 reply_to: vec![],
350 body: Some("Draft body".to_string()),
351 starred: Some(false),
352 snippet: Some("Draft snippet".to_string()),
353 attachments: vec![],
354 folders: vec![],
355 created_at: Some(1234567890),
356 };
357
358 assert_eq!(draft.id.as_str(), "draft_123");
359 assert_eq!(draft.grant_id.as_str(), "grant_123");
360 assert_eq!(draft.subject, Some("Test Draft".to_string()));
361 }
362
363 #[test]
364 fn test_draft_serialization() {
365 let draft = Draft {
366 id: DraftId::new("draft_123"),
367 grant_id: GrantId::new("grant_123"),
368 thread_id: None,
369 subject: Some("Test".to_string()),
370 from: vec![],
371 to: vec![],
372 cc: vec![],
373 bcc: vec![],
374 reply_to: vec![],
375 body: Some("Body".to_string()),
376 starred: Some(false),
377 snippet: Some("Snippet".to_string()),
378 attachments: vec![],
379 folders: vec![],
380 created_at: Some(1234567890),
381 };
382
383 let json = serde_json::to_string(&draft).unwrap();
384 assert!(json.contains("draft_123"));
385 assert!(json.contains("grant_123"));
386 assert!(json.contains("Test"));
387
388 let deserialized: Draft = serde_json::from_str(&json).unwrap();
389 assert_eq!(deserialized, draft);
390 }
391
392 #[test]
393 fn test_create_draft_request_builder() {
394 let to = vec![EmailAddress::new("recipient@example.com").unwrap()];
395 let draft = CreateDraftRequest::builder()
396 .subject("Test")
397 .to(to.clone())
398 .body("Test body")
399 .build();
400
401 assert_eq!(draft.subject, Some("Test".to_string()));
402 assert_eq!(draft.to, Some(to));
403 assert_eq!(draft.body, Some("Test body".to_string()));
404 }
405
406 #[test]
407 fn test_create_draft_request_all_fields() {
408 let from = vec![EmailAddress::new("sender@example.com").unwrap()];
409 let to = vec![EmailAddress::new("recipient@example.com").unwrap()];
410 let cc = vec![EmailAddress::new("cc@example.com").unwrap()];
411
412 let draft = CreateDraftRequest::builder()
413 .subject("Subject")
414 .from(from.clone())
415 .to(to.clone())
416 .cc(cc.clone())
417 .body("Body content")
418 .thread_id("thread_123")
419 .starred(true)
420 .build();
421
422 assert_eq!(draft.subject, Some("Subject".to_string()));
423 assert_eq!(draft.from, Some(from));
424 assert_eq!(draft.to, Some(to));
425 assert_eq!(draft.cc, Some(cc));
426 assert_eq!(draft.body, Some("Body content".to_string()));
427 assert_eq!(draft.thread_id, Some("thread_123".to_string()));
428 assert_eq!(draft.starred, Some(true));
429 }
430
431 #[test]
432 fn test_create_draft_request_serialization() {
433 let to = vec![EmailAddress::new("recipient@example.com").unwrap()];
434 let draft = CreateDraftRequest::builder()
435 .subject("Test")
436 .to(to)
437 .body("Body")
438 .build();
439
440 let json = serde_json::to_string(&draft).unwrap();
441 let deserialized: CreateDraftRequest = serde_json::from_str(&json).unwrap();
442 assert_eq!(deserialized, draft);
443 }
444
445 #[test]
446 fn test_update_draft_request_builder() {
447 let update = UpdateDraftRequest::builder()
448 .subject("Updated subject")
449 .body("Updated body")
450 .starred(true)
451 .build();
452
453 assert_eq!(update.subject, Some("Updated subject".to_string()));
454 assert_eq!(update.body, Some("Updated body".to_string()));
455 assert_eq!(update.starred, Some(true));
456 }
457
458 #[test]
459 fn test_update_draft_request_with_recipients() {
460 let to = vec![EmailAddress::new("new@example.com").unwrap()];
461 let update = UpdateDraftRequest::builder()
462 .to(to.clone())
463 .subject("New subject")
464 .build();
465
466 assert_eq!(update.to, Some(to));
467 assert_eq!(update.subject, Some("New subject".to_string()));
468 }
469
470 #[test]
471 fn test_update_draft_request_serialization() {
472 let update = UpdateDraftRequest::builder()
473 .subject("Test")
474 .body("Body")
475 .build();
476
477 let json = serde_json::to_string(&update).unwrap();
478 let deserialized: UpdateDraftRequest = serde_json::from_str(&json).unwrap();
479 assert_eq!(deserialized, update);
480 }
481}