use serde::{Deserialize, Serialize};
use crate::{CalendarId, GrantId, ResourceId};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Calendar {
pub id: CalendarId,
pub grant_id: GrantId,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<String>,
pub timezone: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_primary: Option<bool>,
#[serde(default)]
pub read_only: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_owned_by_user: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hex_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hex_foreground_color: Option<String>,
#[serde(default = "default_object_type")]
pub object: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
}
fn default_object_type() -> String {
"calendar".to_string()
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CreateCalendarRequest {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timezone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
}
impl CreateCalendarRequest {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
description: None,
location: None,
timezone: None,
metadata: None,
}
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn location(mut self, location: impl Into<String>) -> Self {
self.location = Some(location.into());
self
}
pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
self.timezone = Some(timezone.into());
self
}
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
self.metadata = Some(metadata);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct UpdateCalendarRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub location: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timezone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
}
impl UpdateCalendarRequest {
pub fn new() -> Self {
Self::default()
}
pub fn name(mut self, name: impl Into<String>) -> Self {
self.name = Some(name.into());
self
}
pub fn description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn location(mut self, location: impl Into<String>) -> Self {
self.location = Some(location.into());
self
}
pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
self.timezone = Some(timezone.into());
self
}
pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
self.metadata = Some(metadata);
self
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CalendarResource {
pub id: ResourceId,
pub email: String,
pub name: String,
#[serde(rename = "type")]
pub resource_type: ResourceType,
#[serde(skip_serializing_if = "Option::is_none")]
pub building: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub floor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capacity: Option<i32>,
#[serde(default)]
pub features: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ResourceType {
Room,
Equipment,
Workspace,
Other,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_calendar_creation() {
let calendar = Calendar {
id: CalendarId::new("cal_123"),
grant_id: GrantId::new("grant_123"),
name: "My Calendar".to_string(),
description: Some("Test calendar".to_string()),
location: None,
timezone: "UTC".to_string(),
is_primary: Some(true),
read_only: false,
is_owned_by_user: Some(true),
hex_color: Some("#039be5".to_string()),
hex_foreground_color: Some("#ffffff".to_string()),
object: "calendar".to_string(),
metadata: None,
};
assert_eq!(calendar.name, "My Calendar");
assert_eq!(calendar.timezone, "UTC");
assert_eq!(calendar.is_primary, Some(true));
}
#[test]
fn test_calendar_serialization() {
let calendar = Calendar {
id: CalendarId::new("cal_123"),
grant_id: GrantId::new("grant_123"),
name: "Test".to_string(),
description: None,
location: None,
timezone: "America/New_York".to_string(),
is_primary: Some(false),
read_only: false,
is_owned_by_user: Some(true),
hex_color: None,
hex_foreground_color: None,
object: "calendar".to_string(),
metadata: None,
};
let json = serde_json::to_string(&calendar).unwrap();
assert!(json.contains("cal_123"));
assert!(json.contains("Test"));
assert!(json.contains("America/New_York"));
let deserialized: Calendar = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, calendar);
}
#[test]
fn test_create_calendar_request_builder() {
let request = CreateCalendarRequest::new("Work Calendar")
.description("My work events")
.timezone("America/Los_Angeles")
.location("Office");
assert_eq!(request.name, "Work Calendar");
assert_eq!(request.description, Some("My work events".to_string()));
assert_eq!(request.timezone, Some("America/Los_Angeles".to_string()));
assert_eq!(request.location, Some("Office".to_string()));
}
#[test]
fn test_update_calendar_request_builder() {
let request = UpdateCalendarRequest::new()
.name("Updated Calendar")
.timezone("UTC");
assert_eq!(request.name, Some("Updated Calendar".to_string()));
assert_eq!(request.timezone, Some("UTC".to_string()));
assert_eq!(request.description, None);
}
#[test]
fn test_create_calendar_request_serialization() {
let request = CreateCalendarRequest::new("Test Calendar").description("Test description");
let json = serde_json::to_string(&request).unwrap();
assert!(json.contains("Test Calendar"));
assert!(json.contains("Test description"));
let deserialized: CreateCalendarRequest = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, request);
}
#[test]
fn test_resource_id_creation() {
let id = ResourceId::new("resource_123");
assert_eq!(id.as_str(), "resource_123");
}
#[test]
fn test_resource_type_serialization() {
let room = ResourceType::Room;
let json = serde_json::to_string(&room).unwrap();
assert_eq!(json, "\"room\"");
}
#[test]
fn test_resource_deserialization() {
let json = r#"{
"id": "res_123",
"email": "room1@company.com",
"name": "Conference Room 1",
"type": "room",
"capacity": 10,
"features": ["projector", "whiteboard"]
}"#;
let resource: CalendarResource = serde_json::from_str(json).unwrap();
assert_eq!(resource.name, "Conference Room 1");
assert_eq!(resource.capacity, Some(10));
}
}