Implement complete recurring event drag modification system
- Add recurring edit modal with three modification options: • "Only this event" - Creates exception for single occurrence • "This and future events" - Splits series from occurrence forward • "All occurrences in this series" - Updates entire series time - Enhance backend update API to support series modifications: • Add update_action parameter for recurring event operations • Implement time-only updates that preserve original start dates • Convert timestamped occurrence UIDs to base UIDs for series updates • Preserve recurrence rules during series modifications - Fix recurring event drag operations: • Show modal for recurring events instead of direct updates • Handle EXDATE creation for single occurrence modifications • Support series splitting with UNTIL clause modifications • Maintain proper UID management for different modification types - Clean up debug logging and restore page refresh for data consistency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -768,8 +768,7 @@ pub async fn update_event(
|
||||
headers: HeaderMap,
|
||||
Json(request): Json<UpdateEventRequest>,
|
||||
) -> Result<Json<UpdateEventResponse>, ApiError> {
|
||||
println!("📝 Update event request received: uid='{}', title='{}', calendar_path={:?}",
|
||||
request.uid, request.title, request.calendar_path);
|
||||
// Handle update request
|
||||
|
||||
// Extract and verify token
|
||||
let token = extract_bearer_token(&headers)?;
|
||||
@@ -805,10 +804,14 @@ pub async fn update_event(
|
||||
return Err(ApiError::BadRequest("No calendars available for event update".to_string()));
|
||||
}
|
||||
|
||||
// Determine if this is a series update
|
||||
let search_uid = request.uid.clone();
|
||||
let is_series_update = request.update_action.as_deref() == Some("update_series");
|
||||
|
||||
// Search for the event by UID across the specified calendars
|
||||
let mut found_event: Option<(CalendarEvent, String, String)> = None; // (event, calendar_path, href)
|
||||
for calendar_path in &calendar_paths {
|
||||
match client.fetch_event_by_uid(calendar_path, &request.uid).await {
|
||||
match client.fetch_event_by_uid(calendar_path, &search_uid).await {
|
||||
Ok(Some(event)) => {
|
||||
if let Some(href) = event.href.clone() {
|
||||
found_event = Some((event, calendar_path.clone(), href));
|
||||
@@ -824,7 +827,7 @@ pub async fn update_event(
|
||||
}
|
||||
|
||||
let (mut event, calendar_path, event_href) = found_event
|
||||
.ok_or_else(|| ApiError::NotFound(format!("Event with UID '{}' not found", request.uid)))?;
|
||||
.ok_or_else(|| ApiError::NotFound(format!("Event with UID '{}' not found", search_uid)))?;
|
||||
|
||||
// Parse dates and times for the updated event
|
||||
let start_datetime = parse_event_datetime(&request.start_date, &request.start_time, request.all_day)
|
||||
@@ -963,8 +966,28 @@ pub async fn update_event(
|
||||
} else {
|
||||
Some(request.description.clone())
|
||||
};
|
||||
event.start = start_datetime;
|
||||
event.end = Some(end_datetime);
|
||||
// Handle date/time updates based on update type
|
||||
if is_series_update {
|
||||
// For series updates, only update the TIME, keep the original DATE
|
||||
let original_start_date = event.start.date_naive();
|
||||
let original_end_date = event.end.map(|e| e.date_naive()).unwrap_or(original_start_date);
|
||||
|
||||
let new_start_time = start_datetime.time();
|
||||
let new_end_time = end_datetime.time();
|
||||
|
||||
// Combine original date with new time
|
||||
let updated_start = original_start_date.and_time(new_start_time).and_utc();
|
||||
let updated_end = original_end_date.and_time(new_end_time).and_utc();
|
||||
|
||||
// Preserve original date with new time
|
||||
|
||||
event.start = updated_start;
|
||||
event.end = Some(updated_end);
|
||||
} else {
|
||||
// For regular updates, update both date and time
|
||||
event.start = start_datetime;
|
||||
event.end = Some(end_datetime);
|
||||
}
|
||||
event.location = if request.location.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
@@ -981,10 +1004,28 @@ pub async fn update_event(
|
||||
event.attendees = attendees;
|
||||
event.categories = categories;
|
||||
event.last_modified = Some(chrono::Utc::now());
|
||||
event.recurrence_rule = recurrence_rule;
|
||||
event.all_day = request.all_day;
|
||||
event.reminders = reminders;
|
||||
|
||||
// Handle recurrence rule and UID for series updates
|
||||
if is_series_update {
|
||||
// For series updates, preserve existing recurrence rule and convert UID to base UID
|
||||
let parts: Vec<&str> = request.uid.split('-').collect();
|
||||
if parts.len() > 1 {
|
||||
let last_part = parts[parts.len() - 1];
|
||||
if last_part.chars().all(|c| c.is_numeric()) {
|
||||
let base_uid = parts[0..parts.len()-1].join("-");
|
||||
event.uid = base_uid;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep existing recurrence rule (don't overwrite with recurrence_rule variable)
|
||||
// event.recurrence_rule stays as-is from the original event
|
||||
} else {
|
||||
// For regular updates, use the new recurrence rule
|
||||
event.recurrence_rule = recurrence_rule;
|
||||
}
|
||||
|
||||
// Update the event on the CalDAV server
|
||||
client.update_event(&calendar_path, &event, &event_href)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user