- methods to combine and split status, quantity and role

- $ignore_acl parameter for calendar_boupdate::delete()
- removed setting owner always as participant: owner is allowed to
  remove himself as participant from an event
  (owner only get's set, if there are no other participants in BO)
This commit is contained in:
Ralf Becker 2009-08-06 11:29:05 +00:00
parent 95e36754ce
commit bb5511cc9f
4 changed files with 137 additions and 126 deletions

View File

@ -1081,54 +1081,54 @@ class calendar_bo
switch(gettype($date)) switch(gettype($date))
{ {
case 'string': // YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss[Z|[+-]hh:mm] string case 'string': // YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss[Z|[+-]hh:mm] string
if (is_numeric($date) && $date > 21000000) if (is_numeric($date) && $date > 21000000)
{
$date = (int) $date; // this is already as timestamp
break;
}
// evaluate evtl. added timezone
if (strlen($date) > 12)
{
if (substr($date,-1) == 'Z')
{ {
$time_offset = date('Z'); $date = (int) $date; // this is already as timestamp
break;
} }
elseif(preg_match('/([+-]{1})([0-9]{2}):?([0-9]{2})$/',$date,$matches)) // evaluate evtl. added timezone
if (strlen($date) > 12)
{ {
$time_offset = date('Z')-($matches[1] == '+' ? 1 : -1)*(3600*$matches[2]+60*$matches[3]); if (substr($date,-1) == 'Z')
{
$time_offset = date('Z');
}
elseif(preg_match('/([+-]{1})([0-9]{2}):?([0-9]{2})$/',$date,$matches))
{
$time_offset = date('Z')-($matches[1] == '+' ? 1 : -1)*(3600*$matches[2]+60*$matches[3]);
}
} }
} // removing all non-nummerical chars, gives YYYYMMDDhhmmss, independent of the iso8601 format
// removing all non-nummerical chars, gives YYYYMMDDhhmmss, independent of the iso8601 format $date = str_replace(array('-',':','T','Z',' ','+'),'',$date);
$date = str_replace(array('-',':','T','Z',' ','+'),'',$date); $date = array(
$date = array( 'year' => (int) substr($date,0,4),
'year' => (int) substr($date,0,4), 'month' => (int) substr($date,4,2),
'month' => (int) substr($date,4,2), 'day' => (int) substr($date,6,2),
'day' => (int) substr($date,6,2), 'hour' => (int) substr($date,8,2),
'hour' => (int) substr($date,8,2), 'minute' => (int) substr($date,10,2),
'minute' => (int) substr($date,10,2), 'second' => (int) substr($date,12,2),
'second' => (int) substr($date,12,2), );
); // fall-through
// fall-through
case 'array': // day, month and year keys case 'array': // day, month and year keys
if (isset($date['raw']) && $date['raw']) // we already have a timestamp if (isset($date['raw']) && $date['raw']) // we already have a timestamp
{ {
$date = $date['raw']; $date = $date['raw'];
break;
}
if (!isset($date['year']) && isset($date['full']))
{
$date['year'] = (int) substr($date['full'],0,4);
$date['month'] = (int) substr($date['full'],4,2);
$date['day'] = (int) substr($date['full'],6,2);
}
$date = adodb_mktime((int)$date['hour'],(int)$date['minute'],(int)$date['second'],(int)$date['month'],
(int) (isset($date['day']) ? $date['day'] : $date['mday']),(int)$date['year']);
break; break;
}
if (!isset($date['year']) && isset($date['full']))
{
$date['year'] = (int) substr($date['full'],0,4);
$date['month'] = (int) substr($date['full'],4,2);
$date['day'] = (int) substr($date['full'],6,2);
}
$date = adodb_mktime((int)$date['hour'],(int)$date['minute'],(int)$date['second'],(int)$date['month'],
(int) (isset($date['day']) ? $date['day'] : $date['mday']),(int)$date['year']);
break;
case 'integer': // already a timestamp case 'integer': // already a timestamp
break; break;
default: // eg. boolean, means now in user-time (!) default: // eg. boolean, means now in user-time (!)
$date = $this->now_su; $date = $this->now_su;
break; break;
} }
if ($time_offset) if ($time_offset)
{ {
@ -1490,13 +1490,7 @@ class calendar_bo
$names = array(); $names = array();
foreach($event['participants'] as $id => $status) foreach($event['participants'] as $id => $status)
{ {
$quantity = $role = ''; calendar_so::split_status($status,$quantity,$role);
if (strlen($status) > 1 && preg_match('/^.([0-9]*)(.*)$/',$status,$matches))
{
if ((int)$matches[1] > 1) $quantity = (int)$matches[1];
$role = $matches[2];
}
$status = $status[0];
if ($status == 'G' && !$show_group_invitation) continue; // dont show group-invitation if ($status == 'G' && !$show_group_invitation) continue; // dont show group-invitation
@ -1526,8 +1520,22 @@ class calendar_bo
{ {
$status = '('.$this->verbose_status[$status].')'; $status = '('.$this->verbose_status[$status].')';
} }
$names[$id] = $this->participant_name($id).($quantity ? ' ('.$quantity.')' : ''). $names[$id] = $this->participant_name($id).($quantity > 1 ? ' ('.$quantity.')' : '').' '.$status;
' '.$status.($role ? ' '.lang(str_replace('X-','',$role)) : '');
// add role, if not a regular participant
if ($role != 'REQ-PARTICIPANT')
{
// allow to use cats as roles (beside regular iCal ones)
if (substr($role,0,6) == 'X-CAT-' && ($cat_id = (int)substr($role,6)) > 0)
{
$role = $GLOBALS['egw']->categories->id2name($cat_id);
}
else
{
$role = lang(str_replace('X-','',$role));
}
$names[$id] .= ' '.$role;
}
} }
return $names; return $names;
} }

View File

@ -103,12 +103,12 @@ class calendar_boupdate extends calendar_bo
// set owner as participant if none is given // set owner as participant if none is given
if (!is_array($event['participants']) || !count($event['participants'])) if (!is_array($event['participants']) || !count($event['participants']))
{ {
$event['participants'][$event['owner']] = 'U'; $event['participants'] = array($event['owner'] => 'U');
} }
// set the status of the current user to 'A' = accepted // set the status of the current user to 'A' = accepted
if (isset($event['participants'][$this->user]) && $event['participants'][$this->user] != 'A') if (isset($event['participants'][$this->user]) && $event['participants'][$this->user][0] != 'A')
{ {
$event['participants'][$this->user] = 'A'; $event['participants'][$this->user][0] = 'A';
} }
} }
// check if user has the permission to update / create the event // check if user has the permission to update / create the event
@ -792,14 +792,15 @@ class calendar_boupdate extends calendar_bo
* *
* @param int $cal_id id of the event to delete * @param int $cal_id id of the event to delete
* @param int $recur_date=0 if a single event from a series should be deleted, its date * @param int $recur_date=0 if a single event from a series should be deleted, its date
* @param boolean $ignore_acl=false true for no ACL check, default do ACL check
* @return boolean true on success, false on error (usually permission denied) * @return boolean true on success, false on error (usually permission denied)
*/ */
function delete($cal_id,$recur_date=0) function delete($cal_id,$recur_date=0,$ignore_acl=false)
{ {
$event = $this->read($cal_id,$recur_date); $event = $this->read($cal_id,$recur_date);
if (!($event = $this->read($cal_id,$recur_date)) || if (!($event = $this->read($cal_id,$recur_date)) ||
!$this->check_perms(EGW_ACL_DELETE,$event)) !$ignore_acl && !$this->check_perms(EGW_ACL_DELETE,$event))
{ {
return false; return false;
} }

View File

@ -271,14 +271,7 @@ class calendar_ical extends calendar_boupdate
// RB: MAILTO href contains only the email-address, NO cn! // RB: MAILTO href contains only the email-address, NO cn!
$attributes['ATTENDEE'][] = $info['email'] ? 'MAILTO:'.$info['email'] : ''; $attributes['ATTENDEE'][] = $info['email'] ? 'MAILTO:'.$info['email'] : '';
// ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT|X-*} // ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT|X-*}
$role = 'REQ-PARTICIPANT'; calendar_so::split_status($status,$quantity,$role);
$quantity = '';
if (strlen($status) > 1 && preg_match('/^.([0-9]*)(.*)$/',$status,$matches))
{
if ((int)$matches[1] > 1) $quantity = (int)$matches[1];
if ($matches[2]) $role = $matches[2];
$status = $status[0];
}
// RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U // RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U
$rsvp = $status == 'U' ? 'TRUE' : 'FALSE'; $rsvp = $status == 'U' ? 'TRUE' : 'FALSE';
// PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm. // PARTSTAT={NEEDS-ACTION|ACCEPTED|DECLINED|TENTATIVE|DELEGATED|COMPLETED|IN-PROGRESS} everything from delegated is NOT used by eGW atm.
@ -308,7 +301,7 @@ class calendar_ical extends calendar_boupdate
'CUTYPE' => $cutype, 'CUTYPE' => $cutype,
'RSVP' => $rsvp, 'RSVP' => $rsvp,
)+($info['type'] != 'e' ? array('X-EGROUPWARE-UID' => $uid) : array())+ )+($info['type'] != 'e' ? array('X-EGROUPWARE-UID' => $uid) : array())+
($quantity ? array('X-EGROUPWARE-QUANTITY' => $quantity) : array()); ($quantity > 1 ? array('X-EGROUPWARE-QUANTITY' => $quantity) : array());
} }
break; break;
@ -1893,19 +1886,18 @@ class calendar_ical extends calendar_boupdate
case 'ATTENDEE': case 'ATTENDEE':
if (isset($attributes['params']['PARTSTAT'])) if (isset($attributes['params']['PARTSTAT']))
{ {
$event['participants'][$uid] = $this->status_ical2egw[strtoupper($attributes['params']['PARTSTAT'])]; $status = $this->status_ical2egw[strtoupper($attributes['params']['PARTSTAT'])];
} }
elseif (isset($attributes['params']['STATUS'])) elseif (isset($attributes['params']['STATUS']))
{ {
$event['participants'][$uid] = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])]; $status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])];
} }
else else
{ {
$event['participants'][$uid] = ($uid == $event['owner'] ? 'A' : 'U'); $status = ($uid == $event['owner'] ? 'A' : 'U');
} }
// add quantiy and ROLE // add quantity and role
if ((int)$attributes['params']['X-EGROUPWARE-QUANTITY'] > 1) $event['participants'][$uid] .= (int)$attributes['params']['X-EGROUPWARE-QUANTITY']; $event['participants'][$uid] = calendar_so::combine_status($status,$attributes['params']['X-EGROUPWARE-QUANTITY'],$attributes['params']['ROLE']);
if ($attributes['params']['ROLE']) $event['participants'][$uid] .= $attributes['params']['ROLE'];
break; break;
case 'ORGANIZER': case 'ORGANIZER':
if (is_numeric($uid)) if (is_numeric($uid))
@ -1916,6 +1908,7 @@ class calendar_ical extends calendar_boupdate
{ {
$event['owner'] = $this->user; $event['owner'] = $this->user;
} }
// RalfBecker: this is not allways true, owner can choose to NOT participate in EGroupware
$event['participants'][$uid] = 'A'; $event['participants'][$uid] = 'A';
break; break;
} }

View File

@ -112,9 +112,12 @@ class calendar_so
*/ */
function read($ids,$recur_date=0) function read($ids,$recur_date=0)
{ {
if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'])) { if (isset($GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']))
{
$minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length']; $minimum_uid_length = $GLOBALS['egw_info']['user']['preferences']['syncml']['minimum_uid_length'];
} else { }
else
{
$minimum_uid_length = 8; $minimum_uid_length = 8;
} }
@ -193,22 +196,12 @@ class calendar_so
'cal_recur_date' => $recur_date, 'cal_recur_date' => $recur_date,
),__LINE__,__FILE__,false,'ORDER BY cal_user_type DESC,'.self::STATUS_SORT,'calendar') as $row) // DESC puts users before resources and contacts ),__LINE__,__FILE__,false,'ORDER BY cal_user_type DESC,'.self::STATUS_SORT,'calendar') as $row) // DESC puts users before resources and contacts
{ {
// if the type is not an ordinary user (eg. contact or resource)... // combine all participant data in uid and status values
if ($row['cal_user_type'] && $row['cal_user_type'] != 'u') $uid = self::combine_user($row['cal_user_type'],$row['cal_user_id']);
{ $status = self::combine_status($row['cal_status'],$row['cal_quantity'],$row['cal_role']);
// prefix the id with the type
$user_id = $row['cal_user_type'].$row['cal_user_id']; $events[$row['cal_id']]['participants'][$uid] = $status;
// and append quantity $events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $status;
if ($row['cal_quantity'] > 1) $row['cal_status'] .= $row['cal_quantity'];
// append role to status, if != 'REQ-PARTICIPANT'
if ($row['cal_role'] != 'REQ-PARTICIPANT') $row['cal_status'] .= $row['cal_role'];
}
else
{
$user_id = (int) $row['cal_user_id'];
}
$events[$row['cal_id']]['participants'][$user_id] = $row['cal_status'];
$events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $row['cal_status'];
} }
// custom fields // custom fields
@ -420,11 +413,9 @@ class calendar_so
if (!isset($events[$id])) continue; // not needed first entry of recuring event if (!isset($events[$id])) continue; // not needed first entry of recuring event
// add quantity // combine all participant data in uid and status values
if ($row['cal_quantity'] > 1) $row['cal_status'] .= $row['cal_quantity']; $events[$id]['participants'][self::combine_user($row['cal_user_type'],$row['cal_user_id'])] =
// append role to status, if != 'REQ-PARTICIPANT' self::combine_status($row['cal_status'],$row['cal_quantity'],$row['cal_role']);
if ($row['cal_role'] != 'REQ-PARTICIPANT') $row['cal_status'] .= $row['cal_role'];
$events[$id]['participants'][$this->combine_user($row['cal_user_type'],$row['cal_user_id'])] = $row['cal_status'];
} }
/* custom fields are not shown in the regular views, so we can ignore them here for the moment /* custom fields are not shown in the regular views, so we can ignore them here for the moment
foreach($this->db->select($this->extra_table,'*',array('cal_id'=>$ids),__LINE__,__FILE__,false,'','calendar') as $row) foreach($this->db->select($this->extra_table,'*',array('cal_id'=>$ids),__LINE__,__FILE__,false,'','calendar') as $row)
@ -522,7 +513,7 @@ ORDER BY cal_user_type, cal_usre_id
$minimum_uid_length = 8; $minimum_uid_length = 8;
} }
//echo "<p>socal::save(,$change_since) event="; _debug_array($event); //echo '<p>'.__METHOD__."(,$change_since) event="; _debug_array($event);
//error_log(__METHOD__."(".str_replace(array("\n",' '),'',print_r($event,true)).",$set_recurrences,$change_since,$etag)"); //error_log(__METHOD__."(".str_replace(array("\n",' '),'',print_r($event,true)).",$set_recurrences,$change_since,$etag)");
$cal_id = (int) $event['id']; $cal_id = (int) $event['id'];
@ -555,13 +546,6 @@ ORDER BY cal_user_type, cal_usre_id
return 0; // wrong etag, someone else updated the entry return 0; // wrong etag, someone else updated the entry
} }
if (!is_null($etag)) ++$etag; if (!is_null($etag)) ++$etag;
// events need to have at least one participant, default to the owner
if (!isset($event['cal_participants'])) {
$event['cal_participants'] = array($event['cal_owner'] => 'A');
}
if (!isset($event['cal_participants'][$event['cal_owner']])) {
$event['cal_participants'][$event['cal_owner']] = 'A';
}
} }
else else
{ {
@ -576,15 +560,6 @@ ORDER BY cal_user_type, cal_usre_id
return false; return false;
} }
$etag = 0; $etag = 0;
// new events need to have at least one participant, default to the owner
if (!isset($event['cal_participants']))
{
$event['cal_participants'] = array($event['cal_owner'] => 'A');
}
if (!isset($event['cal_participants'][$event['cal_owner']]))
{
$event['cal_participants'][$event['cal_owner']] = 'A';
}
} }
if (!isset($event['cal_uid']) || strlen($event['cal_uid']) < $minimum_uid_length) if (!isset($event['cal_uid']) || strlen($event['cal_uid']) < $minimum_uid_length)
{ {
@ -795,7 +770,7 @@ ORDER BY cal_user_type, cal_usre_id
* @param string|int $user_id id * @param string|int $user_id id
* @return string|int combined id * @return string|int combined id
*/ */
function combine_user($user_type,$user_id) static function combine_user($user_type,$user_id)
{ {
if (!$user_type || $user_type == 'u') if (!$user_type || $user_type == 'u')
{ {
@ -811,7 +786,7 @@ ORDER BY cal_user_type, cal_usre_id
* @param string &$user_type 1-char type: 'u' = user, ... * @param string &$user_type 1-char type: 'u' = user, ...
* @param string|int &$user_id id * @param string|int &$user_id id
*/ */
function split_user($uid,&$user_type,&$user_id) static function split_user($uid,&$user_type,&$user_id)
{ {
if (is_numeric($uid)) if (is_numeric($uid))
{ {
@ -825,6 +800,42 @@ ORDER BY cal_user_type, cal_usre_id
} }
} }
/**
* Combine status, quantity and role into one value
*
* @param string $status
* @param int $quantity
* @param string $role
* @return string
*/
static function combine_status($status,$quantity,$role)
{
if ((int)$quantity > 1) $status .= (int)$quantity;
if ($role != 'REQ-PARTICIPANT') $status .= $role;
return $status;
}
/**
* splits the combined status, quantity and role
*
* @param string &$status I: combined value, O: status letter: U, T, A, R
* @param int &$quantity only O: quantity
* @param string &$role only O: role
*/
static function split_status(&$status,&$quantity,&$role)
{
$quantity = 1;
$role = 'REQ-PARTICIPANT';
if (strlen($status) > 1 && preg_match('/^.([0-9]*)(.*)$/',$status,$matches))
{
if ((int)$matches[1] > 0) $quantity = (int)$matches[1];
$role = $matches[2];
$status = $status[0];
}
}
/** /**
* updates the participants of an event, taken into account the evtl. recurrences of the event(!) * updates the participants of an event, taken into account the evtl. recurrences of the event(!)
* *
@ -835,12 +846,12 @@ ORDER BY cal_user_type, cal_usre_id
*/ */
function participants($cal_id,$participants,$change_since=0) function participants($cal_id,$participants,$change_since=0)
{ {
//echo "<p>socal::participants($cal_id,".print_r($participants,true).",$change_since)</p>\n"; //echo '<p>'.__METHOD__."($cal_id,".print_r($participants,true).",$change_since)</p>\n";
// remove group-invitations, they are NOT stored in the db // remove group-invitations, they are NOT stored in the db
foreach($participants as $uid => $status) foreach($participants as $uid => $status)
{ {
if ($status == 'G') if ($status[0] == 'G')
{ {
unset($participants[$uid]); unset($participants[$uid]);
} }
@ -902,7 +913,7 @@ ORDER BY cal_user_type, cal_usre_id
// existing participants must not be updated // existing participants must not be updated
foreach($this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id',$where,__LINE__,__FILE__,false,'','calendar') as $row) foreach($this->db->select($this->user_table,'DISTINCT cal_user_type,cal_user_id',$where,__LINE__,__FILE__,false,'','calendar') as $row)
{ {
$existing_participants[] = $this->combine_user($row['cal_user_type'],$row['cal_user_id']); $existing_participants[] = self::combine_user($row['cal_user_type'],$row['cal_user_id']);
} }
} }
if (!count($recurrences)) $recurrences[] = 0; // insert the default one if (!count($recurrences)) $recurrences[] = 0; // insert the default one
@ -912,16 +923,13 @@ ORDER BY cal_user_type, cal_usre_id
if (in_array($uid,$existing_participants)) continue; // don't update existing participants if (in_array($uid,$existing_participants)) continue; // don't update existing participants
$id = null; $id = null;
$this->split_user($uid,$type,$id); self::split_user($uid,$type,$id);
self::split_status($status,$quantity,$role);
$set = array( $set = array(
'cal_status' => $status !== true ? $status[0] : 'U', 'cal_status' => $status,
'cal_quantity' => substr($status,1) > 1 ? (int)substr($status,1) : 1, 'cal_quantity' => $quantity,
'cal_role' => $role,
); );
// update role if set, it's apended to status and quantity
if (strlen($status) > 1 && preg_match('/^.[0-9]*(.*)$/',$status,$matches))
{
$set['cal_role'] = $matches[1];
}
foreach($recurrences as $recur_date) foreach($recurrences as $recur_date)
{ {
$this->db->insert($this->user_table,$set,array( $this->db->insert($this->user_table,$set,array(
@ -1147,8 +1155,9 @@ ORDER BY cal_user_type, cal_usre_id
$datetime = $GLOBALS['egw']->datetime; $datetime = $GLOBALS['egw']->datetime;
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset); $now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
$modifier = $GLOBALS['egw_info']['user']['account_id']; $modifier = $GLOBALS['egw_info']['user']['account_id'];
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier), $this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar'); array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
return $id; return $id;
} }
@ -1180,11 +1189,12 @@ ORDER BY cal_user_type, cal_usre_id
{ {
// update the modification information of the related event // update the modification information of the related event
list(,$cal_id) = explode(':',$id); list(,$cal_id) = explode(':',$id);
if ($cal_id) { if ($cal_id)
{
$datetime = $GLOBALS['egw']->datetime; $datetime = $GLOBALS['egw']->datetime;
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset); $now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
$modifier = $GLOBALS['egw_info']['user']['account_id']; $modifier = $GLOBALS['egw_info']['user']['account_id'];
$this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier), $this->db->update($this->cal_table, array('cal_modified' => $now, 'cal_modifier' => $modifier),
array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar'); array('cal_id' => $cal_id), __LINE__, __FILE__, 'calendar');
} }
return $this->async->cancel_timer($id); return $this->async->cancel_timer($id);
@ -1384,5 +1394,4 @@ ORDER BY cal_user_type, cal_usre_id
sort($days); sort($days);
return $days; return $days;
} }
} }