1use serde::{Deserialize, Serialize};
4
5use crate::{CalendarId, GrantId, ResourceId};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32pub struct Calendar {
33 pub id: CalendarId,
35
36 pub grant_id: GrantId,
38
39 pub name: String,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub description: Option<String>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub location: Option<String>,
49
50 pub timezone: String,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub is_primary: Option<bool>,
56
57 #[serde(default)]
59 pub read_only: bool,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub is_owned_by_user: Option<bool>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub hex_color: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub hex_foreground_color: Option<String>,
72
73 #[serde(default = "default_object_type")]
75 pub object: String,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub metadata: Option<serde_json::Value>,
80}
81
82fn default_object_type() -> String {
83 "calendar".to_string()
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
88pub struct CreateCalendarRequest {
89 pub name: String,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub description: Option<String>,
95
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub location: Option<String>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub timezone: Option<String>,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub metadata: Option<serde_json::Value>,
107}
108
109impl CreateCalendarRequest {
110 pub fn new(name: impl Into<String>) -> Self {
112 Self {
113 name: name.into(),
114 description: None,
115 location: None,
116 timezone: None,
117 metadata: None,
118 }
119 }
120
121 pub fn description(mut self, description: impl Into<String>) -> Self {
123 self.description = Some(description.into());
124 self
125 }
126
127 pub fn location(mut self, location: impl Into<String>) -> Self {
129 self.location = Some(location.into());
130 self
131 }
132
133 pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
135 self.timezone = Some(timezone.into());
136 self
137 }
138
139 pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
141 self.metadata = Some(metadata);
142 self
143 }
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
148pub struct UpdateCalendarRequest {
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub name: Option<String>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub description: Option<String>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub location: Option<String>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub timezone: Option<String>,
164
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub metadata: Option<serde_json::Value>,
168}
169
170impl UpdateCalendarRequest {
171 pub fn new() -> Self {
173 Self::default()
174 }
175
176 pub fn name(mut self, name: impl Into<String>) -> Self {
178 self.name = Some(name.into());
179 self
180 }
181
182 pub fn description(mut self, description: impl Into<String>) -> Self {
184 self.description = Some(description.into());
185 self
186 }
187
188 pub fn location(mut self, location: impl Into<String>) -> Self {
190 self.location = Some(location.into());
191 self
192 }
193
194 pub fn timezone(mut self, timezone: impl Into<String>) -> Self {
196 self.timezone = Some(timezone.into());
197 self
198 }
199
200 pub fn metadata(mut self, metadata: serde_json::Value) -> Self {
202 self.metadata = Some(metadata);
203 self
204 }
205}
206
207#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
209pub struct CalendarResource {
210 pub id: ResourceId,
212
213 pub email: String,
215
216 pub name: String,
218
219 #[serde(rename = "type")]
221 pub resource_type: ResourceType,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub building: Option<String>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub floor: Option<String>,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub capacity: Option<i32>,
234
235 #[serde(default)]
237 pub features: Vec<String>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub description: Option<String>,
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
246#[serde(rename_all = "lowercase")]
247pub enum ResourceType {
248 Room,
250 Equipment,
252 Workspace,
254 Other,
256}
257
258#[cfg(test)]
259mod tests {
260 use super::*;
261
262 #[test]
263 fn test_calendar_creation() {
264 let calendar = Calendar {
265 id: CalendarId::new("cal_123"),
266 grant_id: GrantId::new("grant_123"),
267 name: "My Calendar".to_string(),
268 description: Some("Test calendar".to_string()),
269 location: None,
270 timezone: "UTC".to_string(),
271 is_primary: Some(true),
272 read_only: false,
273 is_owned_by_user: Some(true),
274 hex_color: Some("#039be5".to_string()),
275 hex_foreground_color: Some("#ffffff".to_string()),
276 object: "calendar".to_string(),
277 metadata: None,
278 };
279
280 assert_eq!(calendar.name, "My Calendar");
281 assert_eq!(calendar.timezone, "UTC");
282 assert_eq!(calendar.is_primary, Some(true));
283 }
284
285 #[test]
286 fn test_calendar_serialization() {
287 let calendar = Calendar {
288 id: CalendarId::new("cal_123"),
289 grant_id: GrantId::new("grant_123"),
290 name: "Test".to_string(),
291 description: None,
292 location: None,
293 timezone: "America/New_York".to_string(),
294 is_primary: Some(false),
295 read_only: false,
296 is_owned_by_user: Some(true),
297 hex_color: None,
298 hex_foreground_color: None,
299 object: "calendar".to_string(),
300 metadata: None,
301 };
302
303 let json = serde_json::to_string(&calendar).unwrap();
304 assert!(json.contains("cal_123"));
305 assert!(json.contains("Test"));
306 assert!(json.contains("America/New_York"));
307
308 let deserialized: Calendar = serde_json::from_str(&json).unwrap();
309 assert_eq!(deserialized, calendar);
310 }
311
312 #[test]
313 fn test_create_calendar_request_builder() {
314 let request = CreateCalendarRequest::new("Work Calendar")
315 .description("My work events")
316 .timezone("America/Los_Angeles")
317 .location("Office");
318
319 assert_eq!(request.name, "Work Calendar");
320 assert_eq!(request.description, Some("My work events".to_string()));
321 assert_eq!(request.timezone, Some("America/Los_Angeles".to_string()));
322 assert_eq!(request.location, Some("Office".to_string()));
323 }
324
325 #[test]
326 fn test_update_calendar_request_builder() {
327 let request = UpdateCalendarRequest::new()
328 .name("Updated Calendar")
329 .timezone("UTC");
330
331 assert_eq!(request.name, Some("Updated Calendar".to_string()));
332 assert_eq!(request.timezone, Some("UTC".to_string()));
333 assert_eq!(request.description, None);
334 }
335
336 #[test]
337 fn test_create_calendar_request_serialization() {
338 let request = CreateCalendarRequest::new("Test Calendar").description("Test description");
339
340 let json = serde_json::to_string(&request).unwrap();
341 assert!(json.contains("Test Calendar"));
342 assert!(json.contains("Test description"));
343
344 let deserialized: CreateCalendarRequest = serde_json::from_str(&json).unwrap();
345 assert_eq!(deserialized, request);
346 }
347
348 #[test]
349 fn test_resource_id_creation() {
350 let id = ResourceId::new("resource_123");
351 assert_eq!(id.as_str(), "resource_123");
352 }
353
354 #[test]
355 fn test_resource_type_serialization() {
356 let room = ResourceType::Room;
357 let json = serde_json::to_string(&room).unwrap();
358 assert_eq!(json, "\"room\"");
359 }
360
361 #[test]
362 fn test_resource_deserialization() {
363 let json = r#"{
364 "id": "res_123",
365 "email": "room1@company.com",
366 "name": "Conference Room 1",
367 "type": "room",
368 "capacity": 10,
369 "features": ["projector", "whiteboard"]
370 }"#;
371
372 let resource: CalendarResource = serde_json::from_str(json).unwrap();
373 assert_eq!(resource.name, "Conference Room 1");
374 assert_eq!(resource.capacity, Some(10));
375 }
376}