diff --git a/calendar/inc/class.calendar_boupdate.inc.php b/calendar/inc/class.calendar_boupdate.inc.php index 9d4cb95c31..af1f8bd111 100644 --- a/calendar/inc/class.calendar_boupdate.inc.php +++ b/calendar/inc/class.calendar_boupdate.inc.php @@ -99,10 +99,22 @@ class calendar_boupdate extends calendar_bo * @param array &$messages=null messages about because of missing ACL removed participants or categories * @return mixed on success: int $cal_id > 0, on error false or array with conflicting events (only if $check_conflicts) * Please note: the events are not garantied to be readable by the user (no read grant or private)! + * + * @ToDo current conflict checking code does NOT cope quantity-wise correct with multiple non-overlapping + * events overlapping the event to store: the quantity sum is used, even as the events dont overlap! + * + * ++++++++ ++++++++ + * + + + B + If A get checked for conflicts, the check used for resource quantity is + * + + ++++++++ + * + A + quantity(A,resource)+quantity(B,resource)+quantity(C,resource) > maxBookable(resource) + * + + ++++++++ + * + + + C + which is clearly wrong for everything with a maximum quantity > 1 + * ++++++++ ++++++++ */ function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false,$updateTS=true,&$messages=null) { //error_log(__METHOD__."(".array2string($event).",$ignore_conflicts,$touch_modified,$ignore_acl)"); + if ($this->debug > 1 || $this->debug == 'update') { $this->debug_message('calendar_boupdate::update(%1,ignore_conflict=%2,touch_modified=%3,ignore_acl=%4)', @@ -119,7 +131,7 @@ class calendar_boupdate extends calendar_bo } $status_reset_to_unknown = false; - + if (($new_event = !$event['id'])) // some defaults for new entries { // if no owner given, set user to owner @@ -265,7 +277,9 @@ class calendar_boupdate extends calendar_bo $common_parts = array_intersect($users,array_keys($overlap['participants'])); foreach($common_parts as $n => $uid) { - if ($overlap['participants'][$uid][0] == 'R') + $status = $overlap['participants'][$uid]; + calendar_so::split_status($status, $q, $r); + if ($status == 'R') { unset($common_parts[$n]); continue; @@ -279,7 +293,7 @@ class calendar_boupdate extends calendar_bo $res_info = $this->resource_info($uid); $max_quantity[$uid] = $res_info[$this->resources[$uid[0]]['max_quantity']]; } - $quantity[$uid] += max(1,(int) substr($overlap['participants'][$uid],2)); + $quantity[$uid] += $q; if ($quantity[$uid] <= $max_quantity[$uid]) { $possible_quantity_conflicts[$uid][] =& $overlapping_events[$k]; // an other event can give the conflict @@ -356,7 +370,7 @@ class calendar_boupdate extends calendar_bo { // Restored, bring back links egw_link::restore('calendar', $cal_id); - } + } if ($this->log_file) { $this->log2file($event2save,$event,$old_event); @@ -715,22 +729,22 @@ class calendar_boupdate extends calendar_bo break; } $timeformat = $part_prefs['common']['dateformat'] . ', ' . $timeformat; - + $startdate->setTimezone($timezone); $details['startdate'] = $startdate->format($timeformat); - + $enddate->setTimezone($timezone); $details['enddate'] = $enddate->format($timeformat); - + $modified->setTimezone($timezone); $details['updated'] = $modified->format($timeformat) . ', ' . common::grab_owner_name($event['modifier']); - + if ($old_event != False) { $olddate->setTimezone($timezone); $details['olddate'] = $olddate->format($timeformat); } - + list($subject,$body) = explode("\n",$GLOBALS['egw']->preferences->parse_notify($notify_msg,$details),2); switch($part_prefs['calendar']['update_format']) @@ -857,8 +871,8 @@ class calendar_boupdate extends calendar_bo */ function save($event,$ignore_acl=false,$updateTS=true) { - //echo '
'.__METHOD__.'('.array2string($event).",$ignore_acl)
\n"; //error_log(__METHOD__.'('.array2string($event).",$etag)"); + // check if user has the permission to update / create the event if (!$ignore_acl && ($event['id'] && !$this->check_perms(EGW_ACL_EDIT,$event['id']) || !$event['id'] && !$this->check_perms(EGW_ACL_EDIT,0,$event['owner']) && @@ -1179,7 +1193,7 @@ class calendar_boupdate extends calendar_bo { $GLOBALS['egw']->contenthistory->updateTimeStamp('calendar', $cal_id, 'modify', $this->now); } - + static $status2msg = array( 'R' => MSG_REJECTED, 'T' => MSG_TENTATIVE, @@ -1620,7 +1634,7 @@ class calendar_boupdate extends calendar_bo } if (!isset($event['recurrence'])) $event['recurrence'] = 0; - + if ($filter == 'master') { $query[] = 'recur_type!='. MCAL_RECUR_NONE; @@ -1636,9 +1650,9 @@ class calendar_boupdate extends calendar_bo { $query[] = 'recur_type IS NULL'; } - $query['cal_recurrence'] = $event['recurrence']; + $query['cal_recurrence'] = $event['recurrence']; } - + if ($event['id']) { if ($this->log) @@ -1823,9 +1837,9 @@ class calendar_boupdate extends calendar_bo error_log(__FILE__.'['.__LINE__.'] '.__METHOD__. '[FOUND]: ' . array2string($egwEvent)."\n",3,$this->logfile); } - + if (in_array($egwEvent['id'], $matchingEvents)) continue; - + // convert timezone id of event to tzid (iCal id like 'Europe/Berlin') if (!$egwEvent['tz_id'] || !($egwEvent['tzid'] = calendar_timezones::id2tz($egwEvent['tz_id']))) { @@ -1843,7 +1857,7 @@ class calendar_boupdate extends calendar_bo { self::$tz_cache[$event['tzid']] = calendar_timezones::DateTimeZone($event['tzid']); } - + if (!empty($event['uid'])) { if ($filter == 'master') @@ -1851,8 +1865,8 @@ class calendar_boupdate extends calendar_bo // We found the master $matchingEvents = array($egwEvent['id']);; break; - } - if ($filter == 'exact') + } + if ($filter == 'exact') { // UID found if (empty($event['recurrence'])) @@ -1862,7 +1876,7 @@ class calendar_boupdate extends calendar_bo $dtstart = new egw_time($event['start'], egw_time::$server_timezone); $dtstart->setTimezone(self::$tz_cache[$event['tzid']]); if ($egwEvent['recur_type'] == MCAL_RECUR_NONE && - $event['recur_type'] == MCAL_RECUR_NONE || + $event['recur_type'] == MCAL_RECUR_NONE || $egwEvent['recur_type'] != MCAL_RECUR_NONE && $event['recur_type'] != MCAL_RECUR_NONE) { @@ -1876,7 +1890,7 @@ class calendar_boupdate extends calendar_bo } else { - $matchingEvents[] = $egwEvent['id']; + $matchingEvents[] = $egwEvent['id']; } } continue; @@ -2090,7 +2104,7 @@ class calendar_boupdate extends calendar_bo } $matchingEvents[] = $egwEvent['id']; // exact match } - + if ($filter == 'exact' && !empty($event['uid']) && count($matchingEvents) > 1 || $filter != 'master' && !empty($egwEvent['recur_type']) && empty($event['recur_type'])) { @@ -2102,7 +2116,7 @@ class calendar_boupdate extends calendar_bo } $matchingEvents = array(); } - + // append pseudos as last entries $matchingEvents = array_merge($matchingEvents, $pseudos); diff --git a/calendar/inc/class.calendar_so.inc.php b/calendar/inc/class.calendar_so.inc.php index b699ce8962..9c0323e988 100644 --- a/calendar/inc/class.calendar_so.inc.php +++ b/calendar/inc/class.calendar_so.inc.php @@ -830,7 +830,6 @@ ORDER BY cal_user_type, cal_usre_id $old_min = $old_duration = 0; - //echo ''.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event); //error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)"); $cal_id = (int) $event['id']; @@ -1262,6 +1261,8 @@ ORDER BY cal_user_type, cal_usre_id */ function participants($cal_id,$participants,$change_since=0,$add_only=false) { + //error_log(__METHOD__."($cal_id,".array2string($participants).",$change_since,$add_only"); + $recurrences = array(); // remove group-invitations, they are NOT stored in the db @@ -1312,8 +1313,15 @@ ORDER BY cal_user_type, cal_usre_id } } - // only keep added participants for further steps - we do not touch existing ones - $participants = array_diff_key($participants,$old_participants); + // only keep added OR status (incl. quantity!) changed participants for further steps + // we do not touch unchanged (!) existing ones + foreach($participants as $uid => $status) + { + if ($old_participants[$uid] === $status) + { + unset($participants[$uid]); + } + } // delete participants tagged for delete if ($add_only === false && count($deleted))