Implement complete calendar creation functionality
Add full end-to-end calendar creation feature including: - Create Calendar button in sidebar footer - Modal form with name, description, and color picker (16 predefined colors in 4x4 grid) - Form validation and error handling with loading states - Backend API endpoint for calendar creation with authentication - CalDAV MKCALENDAR protocol implementation with proper XML generation - Real-time calendar list refresh after successful creation - Responsive design for mobile and desktop 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -590,6 +590,74 @@ impl CalDAVClient {
|
||||
|
||||
Err(CalDAVError::ParseError(format!("Unable to parse datetime: {}", datetime_str)))
|
||||
}
|
||||
|
||||
/// Create a new calendar on the CalDAV server using MKCALENDAR
|
||||
pub async fn create_calendar(&self, name: &str, description: Option<&str>, color: Option<&str>) -> Result<(), CalDAVError> {
|
||||
// Sanitize calendar name for URL path
|
||||
let calendar_id = name
|
||||
.chars()
|
||||
.map(|c| if c.is_alphanumeric() { c } else { '-' })
|
||||
.collect::<String>()
|
||||
.to_lowercase();
|
||||
|
||||
let calendar_path = format!("/calendars/{}/{}/", self.config.username, calendar_id);
|
||||
let full_url = format!("{}{}", self.config.server_url.trim_end_matches('/'), calendar_path);
|
||||
|
||||
// Build color property if provided
|
||||
let color_property = if let Some(color) = color {
|
||||
format!(r#"<ic:calendar-color xmlns:ic="http://apple.com/ns/ical/">{}</ic:calendar-color>"#, color)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
let description_property = if let Some(desc) = description {
|
||||
format!(r#"<c:calendar-description xmlns:c="urn:ietf:params:xml:ns:caldav">{}</c:calendar-description>"#, desc)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
// Create the MKCALENDAR request body
|
||||
let mkcalendar_body = format!(
|
||||
r#"<?xml version="1.0" encoding="utf-8" ?>
|
||||
<c:mkcalendar xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav" xmlns:ic="http://apple.com/ns/ical/">
|
||||
<d:set>
|
||||
<d:prop>
|
||||
<d:displayname>{}</d:displayname>
|
||||
<c:supported-calendar-component-set>
|
||||
<c:comp name="VEVENT"/>
|
||||
</c:supported-calendar-component-set>
|
||||
{}
|
||||
{}
|
||||
</d:prop>
|
||||
</d:set>
|
||||
</c:mkcalendar>"#,
|
||||
name, color_property, description_property
|
||||
);
|
||||
|
||||
println!("Creating calendar at: {}", full_url);
|
||||
println!("MKCALENDAR body: {}", mkcalendar_body);
|
||||
|
||||
let response = self.http_client
|
||||
.request(reqwest::Method::from_bytes(b"MKCALENDAR").unwrap(), &full_url)
|
||||
.header("Content-Type", "application/xml; charset=utf-8")
|
||||
.header("Authorization", format!("Basic {}", self.config.get_basic_auth()))
|
||||
.body(mkcalendar_body)
|
||||
.send()
|
||||
.await
|
||||
.map_err(|e| CalDAVError::ParseError(e.to_string()))?;
|
||||
|
||||
println!("Calendar creation response status: {}", response.status());
|
||||
|
||||
if response.status().is_success() {
|
||||
println!("✅ Calendar created successfully at {}", calendar_path);
|
||||
Ok(())
|
||||
} else {
|
||||
let status = response.status();
|
||||
let error_body = response.text().await.unwrap_or_default();
|
||||
println!("❌ Calendar creation failed: {} - {}", status, error_body);
|
||||
Err(CalDAVError::ServerError(status.as_u16()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct for extracting calendar data from XML responses
|
||||
@@ -688,7 +756,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Test parsing a sample iCal event
|
||||
}
|
||||
|
||||
/// Test parsing a sample iCal event
|
||||
#[test]
|
||||
fn test_parse_ical_event() {
|
||||
let sample_ical = r#"BEGIN:VCALENDAR
|
||||
@@ -780,4 +850,3 @@ END:VCALENDAR"#;
|
||||
|
||||
println!("✓ Event enum tests passed!");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user