use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FreeBusyRequest {
pub emails: Vec<String>,
pub start_time: i64,
pub end_time: i64,
}
impl FreeBusyRequest {
pub fn builder() -> FreeBusyRequestBuilder {
FreeBusyRequestBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct FreeBusyRequestBuilder {
emails: Vec<String>,
start_time: Option<i64>,
end_time: Option<i64>,
}
impl FreeBusyRequestBuilder {
pub fn emails(mut self, emails: Vec<String>) -> Self {
self.emails = emails;
self
}
pub fn add_email(mut self, email: impl Into<String>) -> Self {
self.emails.push(email.into());
self
}
pub fn start_time(mut self, timestamp: i64) -> Self {
self.start_time = Some(timestamp);
self
}
pub fn end_time(mut self, timestamp: i64) -> Self {
self.end_time = Some(timestamp);
self
}
pub fn build(self) -> FreeBusyRequest {
FreeBusyRequest {
emails: self.emails,
start_time: self.start_time.expect("start_time is required"),
end_time: self.end_time.expect("end_time is required"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FreeBusyResponse {
pub calendars: Vec<FreeBusyCalendar>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FreeBusyCalendar {
pub email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub calendar_id: Option<String>,
pub time_slots: Vec<FreeBusyTimeSlot>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FreeBusyTimeSlot {
pub start_time: i64,
pub end_time: i64,
pub status: BusyStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub event_id: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum BusyStatus {
Busy,
Tentative,
Free,
#[serde(rename = "out-of-office")]
OutOfOffice,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_free_busy_request_builder() {
let request = FreeBusyRequest::builder()
.emails(vec!["user1@example.com".to_string()])
.start_time(1735689600)
.end_time(1735776000)
.build();
assert_eq!(request.emails.len(), 1);
assert_eq!(request.start_time, 1735689600);
assert_eq!(request.end_time, 1735776000);
}
#[test]
fn test_free_busy_request_add_email() {
let request = FreeBusyRequest::builder()
.add_email("user1@example.com")
.add_email("user2@example.com")
.start_time(1735689600)
.end_time(1735776000)
.build();
assert_eq!(request.emails.len(), 2);
}
#[test]
#[should_panic(expected = "start_time is required")]
fn test_free_busy_request_missing_start_time() {
FreeBusyRequest::builder()
.emails(vec!["user@example.com".to_string()])
.end_time(1735776000)
.build();
}
#[test]
#[should_panic(expected = "end_time is required")]
fn test_free_busy_request_missing_end_time() {
FreeBusyRequest::builder()
.emails(vec!["user@example.com".to_string()])
.start_time(1735689600)
.build();
}
#[test]
fn test_free_busy_request_serialization() {
let request = FreeBusyRequest::builder()
.emails(vec!["user@example.com".to_string()])
.start_time(1735689600)
.end_time(1735776000)
.build();
let json = serde_json::to_string(&request).unwrap();
let deserialized: FreeBusyRequest = serde_json::from_str(&json).unwrap();
assert_eq!(request, deserialized);
}
#[test]
fn test_busy_status_serialization() {
let status = BusyStatus::Busy;
let json = serde_json::to_string(&status).unwrap();
assert_eq!(json, "\"busy\"");
let status = BusyStatus::OutOfOffice;
let json = serde_json::to_string(&status).unwrap();
assert_eq!(json, "\"out-of-office\"");
}
#[test]
fn test_free_busy_response_serialization() {
let response = FreeBusyResponse {
calendars: vec![FreeBusyCalendar {
email: "user@example.com".to_string(),
calendar_id: Some("cal_123".to_string()),
time_slots: vec![FreeBusyTimeSlot {
start_time: 1735689600,
end_time: 1735693200,
status: BusyStatus::Busy,
event_id: Some("event_456".to_string()),
}],
}],
};
let json = serde_json::to_string(&response).unwrap();
let deserialized: FreeBusyResponse = serde_json::from_str(&json).unwrap();
assert_eq!(response, deserialized);
}
}