From 41470de3b4fbde00398c4b7e6916a12972c6ffb7 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Tue, 25 Sep 2012 14:40:17 +0000 Subject: [PATCH] * Calendar/CalDAV/eSync: tracking participant status changes now in modified date and user of calendar entry (main table), fixes sometimes not synced status changes and simplifies code a lot --- calendar/inc/class.calendar_bo.inc.php | 17 +--- calendar/inc/class.calendar_groupdav.inc.php | 16 ++-- calendar/inc/class.calendar_ical.inc.php | 6 +- calendar/inc/class.calendar_so.inc.php | 95 +++----------------- calendar/setup/setup.inc.php | 2 +- calendar/setup/tables_update.inc.php | 19 +++- 6 files changed, 40 insertions(+), 115 deletions(-) diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index db82d399a6..2d2fc3699e 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -631,7 +631,6 @@ class calendar_bo 'owner' => $event['owner'], 'recur_type' => MCAL_RECUR_NONE, 'etag' => $event['etag'], - 'max_user_modified' => $event['max_user_modified'], 'participants' => array_intersect_key($event['participants'],array_flip($allowed_participants)), 'public'=> 0, 'category' => $event['category'], // category is visible anyway, eg. by using planner by cat @@ -803,11 +802,11 @@ class calendar_bo $time->setTime(23, 59, 59); $event['recur_enddate'] = egw_time::to($time, $date_format); } - $timestamps = array('modified','created','max_user_modified'); + $timestamps = array('modified','created'); } else { - $timestamps = array('start','end','modified','created','recur_enddate','recurrence','max_user_modified'); + $timestamps = array('start','end','modified','created','recur_enddate','recurrence'); } // we convert here from the server-time timestamps to user-time and (optional) to a different date-format! foreach ($timestamps as $ts) @@ -1931,18 +1930,8 @@ class calendar_bo if (!$this->check_perms(EGW_ACL_FREEBUSY, $entry, 0, 'server')) return false; $entry = $this->read($entry, $recur_date, true, 'server'); } - $etag = $schedule_tag = $entry['id'].':'.$entry['etag']; + $etag = $schedule_tag = $entry['id'].':'.$entry['etag'].':'.$entry['modified']; - // use new MAX(modification date) of egw_cal_user table (deals with virtual exceptions too) - if (isset($entry['max_user_modified'])) - { - $modified = max($entry['max_user_modified'], $entry['modified']); - } - else - { - $modified = max($this->so->max_user_modified($entry['id'],false,$master_only), $entry['modified']); - } - $etag .= ':' . $modified; // include exception etags into our own etag, if exceptions are included if ($client_share_uid_excpetions && !empty($entry['uid']) && $entry['recur_type'] != MCAL_RECUR_NONE && $entry['recur_exception']) diff --git a/calendar/inc/class.calendar_groupdav.inc.php b/calendar/inc/class.calendar_groupdav.inc.php index a05079ef73..92d5311db8 100644 --- a/calendar/inc/class.calendar_groupdav.inc.php +++ b/calendar/inc/class.calendar_groupdav.inc.php @@ -232,7 +232,7 @@ class calendar_groupdav extends groupdav_handler $props = array( 'getcontenttype' => $this->agent != 'kde' ? 'text/calendar; charset=utf-8; component=VEVENT' : 'text/calendar', 'getetag' => '"'.$etag.'"', - 'getlastmodified' => max($event['modified'], $event['max_user_modified']), + 'getlastmodified' => $event['modified'], ); if ($this->use_schedule_tag) { @@ -1215,15 +1215,17 @@ class calendar_groupdav extends groupdav_handler } $props['supported-calendar-component-set'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV, 'supported-calendar-component-set',$supported_components); - $props['supported-report-set'] = HTTP_WebDAV_Server::mkprop('supported-report-set',array( - HTTP_WebDAV_Server::mkprop('supported-report',array( + $props['supported-report-set'] = array( + 'calendar-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))), + HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-query',''))))), + 'calendar-multiget' => HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))), + HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-multiget',''))))), + 'free-busy-query' => HTTP_WebDAV_Server::mkprop('supported-report',array( HTTP_WebDAV_Server::mkprop('report',array( - HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'free-busy-query',''))), - )))); + HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'free-busy-query',''))))), + ); $props['supported-calendar-data'] = HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'supported-calendar-data',array( HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data', array('content-type' => 'text/calendar', 'version'=> '2.0')), HTTP_WebDAV_Server::mkprop(groupdav::CALDAV,'calendar-data', array('content-type' => 'text/x-calendar', 'version'=> '1.0')))); diff --git a/calendar/inc/class.calendar_ical.inc.php b/calendar/inc/class.calendar_ical.inc.php index 3f68f2a699..1d11d69514 100644 --- a/calendar/inc/class.calendar_ical.inc.php +++ b/calendar/inc/class.calendar_ical.inc.php @@ -856,11 +856,7 @@ class calendar_ical extends calendar_boupdate { $attributes['CREATED'] = $event['created'] ? $event['created'] : $event['modified']; } - if ($event['max_user_modified']) - { - $attributes['LAST-MODIFIED'] = max($event['modified'], $event['max_user_modified']); - } - elseif ($event['modified']) + if ($event['modified']) { $attributes['LAST-MODIFIED'] = $event['modified']; } diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index de67848076..25370d0cb6 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -241,7 +241,6 @@ class calendar_so } } - $need_max_user_modified = array(); // participants, if a recur_date give, we read that recurance, plus the one users from the default entry with recur_date=0 // sorting by cal_recur_date ASC makes sure recurence status always overwrites series status foreach($this->db->select($this->user_table,'*',array( @@ -256,23 +255,6 @@ class calendar_so $events[$row['cal_id']]['participants'][$uid] = $status; $events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $status; - - if ($events[$row['cal_id']]['recur_type']) - { - $need_max_user_modified[$row['cal_id']] = $row['cal_id']; - } - elseif (($modified = $this->db->from_timestamp($row['cal_user_modified'])) > $events[$row['cal_id']]['max_user_modified']) - { - $events[$row['cal_id']]['max_user_modified'] = $modified; - } - } - // max_user_modified for recurring events has to include all recurrences, above code only querys $recur_date! - if ($need_max_user_modified) - { - foreach($this->max_user_modified($need_max_user_modified) as $id => $modified) - { - $events[$id]['max_user_modified'] = $modified; - } } // custom fields @@ -297,44 +279,6 @@ class calendar_so return $events; } - /** - * Get maximum modification time of participant data of given event(s) - * - * This includes ALL recurences of an event series - * - * @param int|array $ids one or multiple cal_id's - * @param boolean $return_maximum=false if true return only the maximum, even for multiple ids - * @param boolean $master_only=false only check recurance master (egw_cal_user.recur_date=0) - * @return int|array (array of) modification timestamp(s) - */ - function max_user_modified($ids, $return_maximum=false, $master_only=false) - { - if (!is_array($ids)) $return_maximum = true; - - $where = array('cal_id' => $ids); - if ($master_only) $where['cal_recur_date'] = 0; - - if ($return_maximum) - { - if (($etags = $this->db->select($this->user_table,'MAX(cal_user_modified)',$where, - __LINE__,__FILE__,false,'','calendar')->fetchColumn())) - { - $etags = $this->db->from_timestamp($etags); - } - } - else - { - $etags = array(); - foreach($this->db->select($this->user_table,'cal_id,MAX(cal_user_modified) AS user_etag',$where, - __LINE__,__FILE__,false,'GROUP BY cal_id','calendar') as $row) - { - $etags[$row['cal_id']] = $this->db->from_timestamp($row['user_etag']); - } - } - //error_log(__METHOD__.'('.array2string($ids).', '.array2string($return_maximum).', '.array2string($master_only).') = '.array2string($etags).' '.function_backtrace()); - return $etags; - } - /** * Get maximum modification time of events for given participants and optional owned by them * @@ -347,6 +291,10 @@ class calendar_so */ function get_ctag($users, $owner_too=false,$master_only=false) { + static $ctags = array(); // some per-request caching + $signature = serialize(func_get_args()); + if (isset($ctags[$signature])) return $ctags[$signature]; + $where = array( 'cal_user_type' => 'u', 'cal_user_id' => $users, @@ -367,14 +315,8 @@ class calendar_so 'cal_owner' => $users, ),')'); } - if (($data = $this->db->select($this->user_table,array( - 'MAX(cal_user_modified) AS max_user_modified', - 'MAX(cal_modified) AS max_modified', - ),$where,__LINE__,__FILE__,false,'','calendar',0,'JOIN egw_cal ON egw_cal.cal_id=egw_cal_user.cal_id')->fetch())) - { - $data = max($this->db->from_timestamp($data['max_user_modified']),$data['max_modified']); - } - return $data; + return $ctags[$signature] = $this->db->select($this->user_table,'MAX(cal_modified) AS max_modified', + $where,__LINE__,__FILE__,false,'','calendar',0,'JOIN egw_cal ON egw_cal.cal_id=egw_cal_user.cal_id')->fetchColumn(); } /** @@ -729,7 +671,6 @@ class calendar_so { $ids = array_unique($ids); - $need_max_user_modified = array(); // now ready all users with the given cal_id AND (cal_recur_date=0 or the fitting recur-date) // This will always read the first entry of each recuring event too, we eliminate it later $recur_dates[] = 0; @@ -762,16 +703,6 @@ class calendar_so // set data, if recurrence is requested if (isset($events[$id])) $events[$id]['participants'][$uid] = $status; - - // fill max_user_modified: - if (!$params['master_only'] && $events[$id]['recur_type']) - { - $need_max_user_modified[$id] = $id; - } - elseif (isset($events[$id]) && ($modified = $this->db->from_timestamp($row['cal_user_modified'])) > $events[$id]['max_user_modified']) - { - $events[$id]['max_user_modified'] = $modified; - } } // query recurrance exceptions, if needed if (!$params['enum_recuring']) @@ -787,14 +718,6 @@ class calendar_so } } } - // max_user_modified for recurring events has to include all recurrences, above code only querys $recur_date! - if (!$params['enum_recuring'] && $need_max_user_modified) - { - foreach($this->max_user_modified($need_max_user_modified) as $id => $modified) - { - $events[$id]['max_user_modified'] = $modified; - } - } //custom fields are not shown in the regular views, so we only query them, if explicitly required if (!is_null($params['cfs'])) { @@ -1651,7 +1574,11 @@ ORDER BY cal_user_type, cal_usre_id if (!is_null($role) && $role != 'REQ-PARTICIPANT') $set['cal_role'] = $role; $this->db->insert($this->user_table,$set,$where,__LINE__,__FILE__,'calendar'); } - $ret = $this->db->affected_rows(); + // update modified and modifier in main table + if (($ret = $this->db->affected_rows())) + { + $this->updateModified($cal_id, time(), $GLOBALS['egw_info']['user']['account_id']); + } //error_log(__METHOD__."($cal_id,$user_type,$user_id,$status,$recur_date) = $ret"); return $ret; } diff --git a/calendar/setup/setup.inc.php b/calendar/setup/setup.inc.php index 40f882dfad..7757ee4e0a 100755 --- a/calendar/setup/setup.inc.php +++ b/calendar/setup/setup.inc.php @@ -10,7 +10,7 @@ */ $setup_info['calendar']['name'] = 'calendar'; -$setup_info['calendar']['version'] = '1.9.008'; +$setup_info['calendar']['version'] = '1.9.009'; $setup_info['calendar']['app_order'] = 3; $setup_info['calendar']['enable'] = 1; $setup_info['calendar']['index'] = 'calendar.calendar_uiviews.index'; diff --git a/calendar/setup/tables_update.inc.php b/calendar/setup/tables_update.inc.php index c6846f2f3e..1b202e897b 100644 --- a/calendar/setup/tables_update.inc.php +++ b/calendar/setup/tables_update.inc.php @@ -2212,9 +2212,9 @@ function calendar_upgrade1_9_007() { foreach(array('egw_cal_repeats','egw_cal_dates','egw_cal_user','egw_cal_extra') as $table) { - $GLOBALS['egw_setup']->db->query("DELETE FROM $table WHERE cal_id IN (SELECT cal_id FROM egw_cal WHERE range_start=0 OR range_start IS NULL)"); + $GLOBALS['egw_setup']->db->query("DELETE FROM $table WHERE cal_id IN (SELECT cal_id FROM egw_cal WHERE range_start=0 OR range_start IS NULL)", __LINE__, __FILE__); } - $GLOBALS['egw_setup']->db->query("DELETE FROM egw_cal WHERE range_start=0 OR range_start IS NULL"); + $GLOBALS['egw_setup']->db->query("DELETE FROM egw_cal WHERE range_start=0 OR range_start IS NULL", __LINE__, __FILE__); // now we can remove temporary default of 0 from range_start and set it NOT NULL $GLOBALS['egw_setup']->oProc->AlterColumn('egw_cal','range_start',array( @@ -2227,10 +2227,21 @@ function calendar_upgrade1_9_007() return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.008'; } +/** + * UPDATE cal_modified to contain maximum of cal_user_modified and current cal_modified, to get a single modification date per calendar-entry + */ +function calendar_upgrade1_9_008() +{ + $max_user_modified = 'SELECT '.$GLOBALS['egw_setup']->db->unix_timestamp('MAX(cal_user_modified)').' FROM egw_cal_user WHERE egw_cal.cal_id=egw_cal_user.cal_id'; + $GLOBALS['egw_setup']->db->query("UPDATE egw_cal SET cal_modified=($max_user_modified) WHERE cal_modified < ($max_user_modified)", __LINE__, __FILE__); + + return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.009'; +} + /** * Add cal_rrule columns, drop egw_cal_repeats table */ -/*function calendar_upgrade1_9_008() +/*function calendar_upgrade1_9_009() { $GLOBALS['egw_setup']->oProc->AddColumn('egw_cal','cal_rrule',array( 'type' => 'varchar', @@ -2255,6 +2266,6 @@ function calendar_upgrade1_9_007() } $GLOBALS['egw_setup']->oProc->DropTable('egw_cal_repeats'); - return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.009'; + return $GLOBALS['setup_info']['calendar']['currentver'] = '1.9.010'; } */