diff --git a/calendar/inc/class.calendar_bo.inc.php b/calendar/inc/class.calendar_bo.inc.php index f80c7de0cb..40c1cbcc11 100644 --- a/calendar/inc/class.calendar_bo.inc.php +++ b/calendar/inc/class.calendar_bo.inc.php @@ -1918,14 +1918,14 @@ class calendar_bo /** * Get the etag for an entry * + * As all update routines (incl. set_status and add/delete alarms) update (series master) modified timestamp, + * we do NOT need any special handling for series master anymore + * * @param array|int|string $event array with event or cal_id, or cal_id:recur_date for virtual exceptions * @param string &$schedule_tag=null on return schedule-tag (egw_cal.cal_id:egw_cal.cal_etag, no participant modifications!) - * @param boolean $client_share_uid_excpetions Does client understand exceptions to be included in VCALENDAR component of series master sharing its UID - * @param boolean $master_only=false only take into account recurrance masters - * (for ActiveSync which does not support different participants/status on recurrences/exceptions!) * @return string|boolean string with etag or false */ - function get_etag($entry, &$schedule_tag=null, $client_share_uid_excpetions=true,$master_only=false) + function get_etag($entry, &$schedule_tag=null) { if (!is_array($entry)) { @@ -1936,35 +1936,6 @@ class calendar_bo $etag = $schedule_tag = $entry['id'].':'.$entry['etag']; $etag .= ':'.$entry['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']) - { - foreach($this->so->get_cal_data(array( - 'cal_reference' => $entry['id'], - ), 'cal_id,cal_reference,cal_etag,cal_modified'.(!$master_only ? ',cal_user_modified' : '')) as $recurrence) - { - $recurrence = egw_db::strip_array_keys($data, 'cal_'); - if ($recurrence['reference'] && $recurrence['id'] != $entry['id']) // ignore series master - { - // modified need to be max from modified and user_modified - if (!$master_only && $recurrence['modified'] < $recurrence['user_modified']) - { - $recurrence['modified'] = $recurrence['user_modified']; - } - $exception_etag = $this->get_etag($recurrence); - // if $master_only, only add cal_etag, not max. user modification date - if ($master_only) list(,$exception_etag) = explode(':',$exception_etag); - - $exception_etags .= ':'.$exception_etag; - } - } - if ($exception_etags) - { - $etag .= ':'.md5($exception_etags); // limit size, as there can be many exceptions - } - //error_log(__METHOD__."($entry[id]: $entry[title]) returning $etag ".function_backtrace()); - } //error_log(__METHOD__ . "($entry[id],$client_share_uid_excpetions) entry=".array2string($entry)." --> etag=$etag"); return $etag; } diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index a0d34e064e..fc2cb7c806 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -1755,7 +1755,7 @@ class calendar_boupdate extends calendar_bo $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now); - return $this->so->save_alarm($cal_id,$alarm, $this->now); + return $this->so->save_alarm($cal_id,$alarm); } /** @@ -1775,7 +1775,7 @@ class calendar_boupdate extends calendar_bo $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now); - return $this->so->delete_alarm($id, $this->now); + return $this->so->delete_alarm($id); } /** diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index b717dec2a4..37b19e5991 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -7,7 +7,7 @@ * @author Ralf Becker * @author Christian Binder * @author Joerg Lehrke - * @copyright (c) 2005-11 by RalfBecker-At-outdoor-training.de + * @copyright (c) 2005-13 by RalfBecker-At-outdoor-training.de * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @version $Id$ */ @@ -68,6 +68,9 @@ define('WEEK_s',7*DAY_s); * DB-model uses egw_cal_user.cal_status='X' for participants who got deleted. They never get returned by * read or search methods, but influence the ctag of the deleted users calendar! * + * All update methods not take care to update modification time of (evtl. existing) series master too, + * to force an etag, ctag and sync-token change! Methods not doing that are private to this class. + * * range_start/_end in main-table contains start and end of whole event series (range_end is NULL for unlimited recuring events), * saving the need to always join dates table, to query non-enumerating recuring events (like CalDAV or ActiveSync does). * This effectivly stores MIN(cal_start) and MAX(cal_end) permanently as column in main-table and improves speed tremendiously @@ -1321,7 +1324,7 @@ ORDER BY cal_user_type, cal_usre_id { continue; // pgoerzen: don't add alarm in the past } - $this->save_alarm($cal_id,$alarm); + $this->save_alarm($cal_id, $alarm, false); // false: not update modified, we do it anyway } } if (is_null($etag)) @@ -1683,13 +1686,7 @@ ORDER BY cal_user_type, cal_usre_id // update modified and modifier in main table if (($ret = $this->db->affected_rows())) { - $this->updateModified($cal_id); - - // if event is an exception: update modified of master, to force etag, ctag and sync-token change - if (($master_id = $this->db->select($this->cal_table, 'cal_reference', array('cal_id' => $cal_id), __LINE__, __FILE__)->fetchColumn())) - { - $this->updateModified($master_id); - } + $this->updateModified($cal_id, true); // true = update series master too } //error_log(__METHOD__."($cal_id,$user_type,$user_id,$status,$recur_date) = $ret"); return $ret; @@ -1770,6 +1767,9 @@ ORDER BY cal_user_type, cal_usre_id $this->delete_alarms($cal_id); + // update timestamp of series master, updates own timestamp too, which does not hurt ;-) + $this->updateModified($cal_id, true); + foreach($this->all_tables as $table) { $this->db->delete($table,array('cal_id'=>$cal_id),__LINE__,__FILE__,'calendar'); @@ -1859,10 +1859,10 @@ ORDER BY cal_user_type, cal_usre_id * * @param int $cal_id Id of the calendar-entry * @param array $alarm array with fields: text, owner, enabled, .. - * @param timestamp $now=0 timestamp for modification of related event + * @param boolean $update_modified=true call update modified, default true * @return string id of the alarm */ - function save_alarm($cal_id, $alarm, $now=0) + function save_alarm($cal_id, $alarm, $update_modified=true) { //echo "

save_alarm(cal_id=$cal_id, alarm="; print_r($alarm); echo ")

\n"; //error_log(__METHOD__."(.$cal_id,$now,".array2string($alarm).')'); @@ -1890,21 +1890,20 @@ ORDER BY cal_user_type, cal_usre_id } // update the modification information of the related event - if (!$now) $now = time(); - $modifier = $GLOBALS['egw_info']['user']['account_id']; - $this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier), - array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar'); + if ($update_modified) $this->updateModified($cal_id, true); return $id; } /** - * delete all alarms of a calendar-entry + * Delete all alarms of a calendar-entry + * + * Does not update timestamps of series master, therefore private! * * @param int $cal_id Id of the calendar-entry * @return int number of alarms deleted */ - function delete_alarms($cal_id) + private function delete_alarms($cal_id) { $alarms = $this->read_alarms($cal_id); @@ -1919,19 +1918,15 @@ ORDER BY cal_user_type, cal_usre_id * delete one alarms identified by its id * * @param string $id alarm-id is a string of 'cal:'.$cal_id.':'.$alarm_nr, it is used as the job-id too - * @param timestamp $now=0 timestamp for modification of related event * @return int number of alarms deleted */ - function delete_alarm($id, $now=0) + function delete_alarm($id) { // update the modification information of the related event list(,$cal_id) = explode(':',$id); if ($cal_id) { - if (!$now) $now = time(); - $modifier = $GLOBALS['egw_info']['user']['account_id']; - $this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier), - array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar'); + $this->updateModified($cal_id, true); } return $this->async->cancel_timer($id); } @@ -2453,19 +2448,29 @@ ORDER BY cal_user_type, cal_usre_id } /** - * Udates the modification timestamp + * Updates the modification timestamp to force an etag, ctag and sync-token change * - * @param id event id - * @param time new timestamp, default current (server-)time - * @param modifier uid of the modifier, default current user + * @param int $id event id + * @param int|boolean $update_master=false id of series master or true, to update series master too + * @param int $time=null new timestamp, default current (server-)time + * @param int $modifier=null uid of the modifier, default current user */ - function updateModified($id, $time=null, $modifier=null) + function updateModified($id, $update_master=false, $time=null, $modifier=null) { - if (is_null($time)) $time = time(); + if (is_null($time) || !$time) $time = time(); if (is_null($modifier)) $modifier = $GLOBALS['egw_info']['user']['account_id']; $this->db->update($this->cal_table, array('cal_modified' => $time, 'cal_modifier' => $modifier), array('cal_id' => $id), __LINE__,__FILE__, 'calendar'); + + // if event is an exception: update modified of master, to force etag, ctag and sync-token change + if ($update_master) + { + if ($update_master !== true || ($update_master = $this->db->select($this->cal_table, 'cal_reference', array('cal_id' => $id), __LINE__, __FILE__)->fetchColumn())) + { + $this->updateModified($update_master, false, $time, $modifier); + } + } } }