From 7a3f2c474444d413907f21ab20488c9d9688a8d5 Mon Sep 17 00:00:00 2001 From: Andrew McMillan Date: Fri, 6 Apr 2012 14:03:55 +1200 Subject: [PATCH] Make it so that PUT of a calendar collection becomes a synchronisation. We only write events which differ, and only delete events which aren't present in the new upload. If done in append mode then events which already exist will be updated more cleanly too. --- inc/caldav-PUT-functions.php | 79 +++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/inc/caldav-PUT-functions.php b/inc/caldav-PUT-functions.php index aaef0a85..fb7cebe7 100644 --- a/inc/caldav-PUT-functions.php +++ b/inc/caldav-PUT-functions.php @@ -728,6 +728,7 @@ function import_calendar_collection( $ics_content, $user_no, $path, $caldav_cont $qry = new AwlQuery( $sql, array( ':displayname' => $displayname, ':dav_name' => $path) ); if ( ! $qry->Exec('PUT',__LINE__,__FILE__) ) rollback_on_error( $caldav_context, $user_no, $path ); } + $tz_ids = array(); foreach( $timezones AS $k => $tz ) { @@ -762,20 +763,29 @@ function import_calendar_collection( $ics_content, $user_no, $path, $caldav_cont rollback_on_error( $caldav_context, $user_no, $path ); } $collection = $qry->Fetch(); - + $collection_id = $collection->collection_id; + + // Fetch the current collection data + $qry->QDo('SELECT dav_name, caldav_data FROM caldav_data WHERE collection_id=:collection_id', array( + ':collection_id' => $collection_id + )); + $current_data = array(); + while( $row = $qry->Fetch() ) + $current_data[$row->dav_name] = $row->caldav_data; + if ( !(isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import) ) $qry->Begin(); - $base_params = array( ':collection_id' => $collection->collection_id ); - if ( !$appending ) { - if ( !$qry->QDo('DELETE FROM calendar_item WHERE collection_id = :collection_id', $base_params) - || !$qry->QDo('DELETE FROM caldav_data WHERE collection_id = :collection_id', $base_params) ) - rollback_on_error( $caldav_context, $user_no, $collection->collection_id ); - } + $base_params = array( ':collection_id' => $collection_id ); $dav_data_insert = << $resource ) { - if ( isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import ) $qry->Begin(); /** Construct the VCALENDAR data */ $vcal = new vCalendar(); $vcal->SetComponents($resource); $icalendar = $vcal->Render(); + $dav_name = sprintf( '%s%s.ics', $path, preg_replace('{[&?\\/@%+:]}','',$uid) ); + /** Do we need to do anything? */ + $inserting = true; + if ( isset($current_data[$dav_name]) ) { + if ( $icalendar == $current_data[$dav_name] ) { + unset($current_data[$dav_name]); + continue; + } + $sync_change = 200; + unset($current_data[$dav_name]); + $inserting = false; + } + else + $sync_change = 201; + + if ( isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import ) $qry->Begin(); + /** As ever, we mostly deal with the first resource component */ $first = $resource[0]; $dav_data_params = $base_params; $dav_data_params[':user_no'] = $user_no; // We don't allow any of &?\/@%+: in the UID to appear in the path, but anything else is fair game. - $dav_data_params[':dav_name'] = sprintf( '%s%s.ics', $path, preg_replace('{[&?\\/@%+:]}','',$uid) ); + $dav_data_params[':dav_name'] = $dav_name; $dav_data_params[':etag'] = md5($icalendar); $calitem_params = $dav_data_params; $dav_data_params[':dav_data'] = $icalendar; $dav_data_params[':caldav_type'] = $first->GetType(); $dav_data_params[':session_user'] = $session->user_no; - if ( !$qry->QDo($dav_data_insert,$dav_data_params) ) rollback_on_error( $caldav_context, $user_no, $path ); + if ( !$qry->QDo( ($inserting ? $dav_data_insert : $dav_data_update), $dav_data_params) ) + rollback_on_error( $caldav_context, $user_no, $path ); $qry->QDo('SELECT dav_id FROM caldav_data WHERE dav_name = :dav_name ', array(':dav_name' => $dav_data_params[':dav_name'])); if ( $qry->rows() == 1 && $row = $qry->Fetch() ) { @@ -896,7 +932,7 @@ EOSQL; $tz = $olson = $tzid = null; } - $sql = str_replace( '##dtend##', $dtend, $calitem_insert ); + $sql = str_replace( '##dtend##', $dtend, ($inserting ? $calitem_insert : $calitem_update) ); $calitem_params[':tzid'] = $tzid; $calitem_params[':uid'] = $first->GetPValue('UID'); $calitem_params[':summary'] = $first->GetPValue('SUMMARY'); @@ -910,19 +946,34 @@ EOSQL; $calitem_params[':percent_complete'] = $first->GetPValue('PERCENT-COMPLETE'); $calitem_params[':status'] = $first->GetPValue('STATUS'); - $created = $first->GetPValue('CREATED'); - if ( $created == '00001231T000000Z' ) $created = '20001231T000000Z'; - $calitem_params[':created'] = $created; + if ( $inserting ) { + $created = $first->GetPValue('CREATED'); + if ( $created == '00001231T000000Z' ) $created = '20001231T000000Z'; + $calitem_params[':created'] = $created; + } if ( !$qry->QDo($sql,$calitem_params) ) rollback_on_error( $caldav_context, $user_no, $path); write_alarms($dav_id, $first); write_attendees($dav_id, $vcal); + $qry->QDo("SELECT write_sync_change( $collection_id, $sync_change, :dav_name)", array(':dav_name' => $dav_name ) ); + do_scheduling_requests( $vcal, true ); if ( isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import ) $qry->Commit(); } + if ( !$appending && count($current_data) > 0 ) { + $params = array( ':collection_id' => $collection_id ); + if ( isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import ) $qry->Begin(); + foreach( $current_data AS $dav_name => $data ) { + $params[':dav_name'] = $dav_name; + $qry->QDo('DELETE FROM caldav_data WHERE collection_id = :collection_id AND dav_name = :dav_name', $params); + $qry->QDo('SELECT write_sync_change(:collection_id, 404, :dav_name)', $params); + } + if ( isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import ) $qry->Commit(); + } + if ( !(isset($c->skip_bad_event_on_import) && $c->skip_bad_event_on_import) ) { if ( ! $qry->Commit() ) rollback_on_error( $caldav_context, $user_no, $path); }