- 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))
{
case 'string': // YYYYMMDD or iso8601 YYYY-MM-DDThh:mm:ss[Z|[+-]hh:mm] string
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')
if (is_numeric($date) && $date > 21000000)
{
$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
$date = str_replace(array('-',':','T','Z',' ','+'),'',$date);
$date = array(
'year' => (int) substr($date,0,4),
'month' => (int) substr($date,4,2),
'day' => (int) substr($date,6,2),
'hour' => (int) substr($date,8,2),
'minute' => (int) substr($date,10,2),
'second' => (int) substr($date,12,2),
);
// fall-through
// removing all non-nummerical chars, gives YYYYMMDDhhmmss, independent of the iso8601 format
$date = str_replace(array('-',':','T','Z',' ','+'),'',$date);
$date = array(
'year' => (int) substr($date,0,4),
'month' => (int) substr($date,4,2),
'day' => (int) substr($date,6,2),
'hour' => (int) substr($date,8,2),
'minute' => (int) substr($date,10,2),
'second' => (int) substr($date,12,2),
);
// fall-through
case 'array': // day, month and year keys
if (isset($date['raw']) && $date['raw']) // we already have a timestamp
{
$date = $date['raw'];
if (isset($date['raw']) && $date['raw']) // we already have a timestamp
{
$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;
}
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
break;
break;
default: // eg. boolean, means now in user-time (!)
$date = $this->now_su;
break;
$date = $this->now_su;
break;
}
if ($time_offset)
{
@ -1490,13 +1490,7 @@ class calendar_bo
$names = array();
foreach($event['participants'] as $id => $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];
calendar_so::split_status($status,$quantity,$role);
if ($status == 'G' && !$show_group_invitation) continue; // dont show group-invitation
@ -1526,8 +1520,22 @@ class calendar_bo
{
$status = '('.$this->verbose_status[$status].')';
}
$names[$id] = $this->participant_name($id).($quantity ? ' ('.$quantity.')' : '').
' '.$status.($role ? ' '.lang(str_replace('X-','',$role)) : '');
$names[$id] = $this->participant_name($id).($quantity > 1 ? ' ('.$quantity.')' : '').' '.$status;
// 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;
}

View File

@ -103,12 +103,12 @@ class calendar_boupdate extends calendar_bo
// set owner as participant if none is given
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
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
@ -792,14 +792,15 @@ class calendar_boupdate extends calendar_bo
*
* @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 boolean $ignore_acl=false true for no ACL check, default do ACL check
* @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);
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;
}

View File

@ -271,14 +271,7 @@ class calendar_ical extends calendar_boupdate
// RB: MAILTO href contains only the email-address, NO cn!
$attributes['ATTENDEE'][] = $info['email'] ? 'MAILTO:'.$info['email'] : '';
// ROLE={CHAIR|REQ-PARTICIPANT|OPT-PARTICIPANT|NON-PARTICIPANT|X-*}
$role = 'REQ-PARTICIPANT';
$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];
}
calendar_so::split_status($status,$quantity,$role);
// RSVP={TRUE|FALSE} // resonse expected, not set in eGW => status=U
$rsvp = $status == 'U' ? 'TRUE' : 'FALSE';
// 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,
'RSVP' => $rsvp,
)+($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;
@ -1893,19 +1886,18 @@ class calendar_ical extends calendar_boupdate
case 'ATTENDEE':
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']))
{
$event['participants'][$uid] = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])];
$status = $this->status_ical2egw[strtoupper($attributes['params']['STATUS'])];
}
else
{
$event['participants'][$uid] = ($uid == $event['owner'] ? 'A' : 'U');
$status = ($uid == $event['owner'] ? 'A' : 'U');
}
// add quantiy and ROLE
if ((int)$attributes['params']['X-EGROUPWARE-QUANTITY'] > 1) $event['participants'][$uid] .= (int)$attributes['params']['X-EGROUPWARE-QUANTITY'];
if ($attributes['params']['ROLE']) $event['participants'][$uid] .= $attributes['params']['ROLE'];
// add quantity and role
$event['participants'][$uid] = calendar_so::combine_status($status,$attributes['params']['X-EGROUPWARE-QUANTITY'],$attributes['params']['ROLE']);
break;
case 'ORGANIZER':
if (is_numeric($uid))
@ -1916,6 +1908,7 @@ class calendar_ical extends calendar_boupdate
{
$event['owner'] = $this->user;
}
// RalfBecker: this is not allways true, owner can choose to NOT participate in EGroupware
$event['participants'][$uid] = 'A';
break;
}

View File

@ -112,9 +112,12 @@ class calendar_so
*/
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'];
} else {
}
else
{
$minimum_uid_length = 8;
}
@ -193,22 +196,12 @@ class calendar_so
'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
{
// if the type is not an ordinary user (eg. contact or resource)...
if ($row['cal_user_type'] && $row['cal_user_type'] != 'u')
{
// prefix the id with the type
$user_id = $row['cal_user_type'].$row['cal_user_id'];
// and append quantity
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'];
// combine all participant data in uid and status values
$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']);
$events[$row['cal_id']]['participants'][$uid] = $status;
$events[$row['cal_id']]['participant_types'][$row['cal_user_type']][$row['cal_user_id']] = $status;
}
// custom fields
@ -420,11 +413,9 @@ class calendar_so
if (!isset($events[$id])) continue; // not needed first entry of recuring event
// add quantity
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'];
$events[$id]['participants'][$this->combine_user($row['cal_user_type'],$row['cal_user_id'])] = $row['cal_status'];
// combine all participant data in uid and status values
$events[$id]['participants'][self::combine_user($row['cal_user_type'],$row['cal_user_id'])] =
self::combine_status($row['cal_status'],$row['cal_quantity'],$row['cal_role']);
}
/* 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)
@ -522,7 +513,7 @@ ORDER BY cal_user_type, cal_usre_id
$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)");
$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
}
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
{
@ -576,15 +560,6 @@ ORDER BY cal_user_type, cal_usre_id
return false;
}
$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)
{
@ -795,7 +770,7 @@ ORDER BY cal_user_type, cal_usre_id
* @param string|int $user_id 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')
{
@ -811,7 +786,7 @@ ORDER BY cal_user_type, cal_usre_id
* @param string &$user_type 1-char type: 'u' = user, ...
* @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))
{
@ -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(!)
*
@ -835,12 +846,12 @@ ORDER BY cal_user_type, cal_usre_id
*/
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
foreach($participants as $uid => $status)
{
if ($status == 'G')
if ($status[0] == 'G')
{
unset($participants[$uid]);
}
@ -902,7 +913,7 @@ ORDER BY cal_user_type, cal_usre_id
// 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)
{
$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
@ -912,16 +923,13 @@ ORDER BY cal_user_type, cal_usre_id
if (in_array($uid,$existing_participants)) continue; // don't update existing participants
$id = null;
$this->split_user($uid,$type,$id);
self::split_user($uid,$type,$id);
self::split_status($status,$quantity,$role);
$set = array(
'cal_status' => $status !== true ? $status[0] : 'U',
'cal_quantity' => substr($status,1) > 1 ? (int)substr($status,1) : 1,
'cal_status' => $status,
'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)
{
$this->db->insert($this->user_table,$set,array(
@ -1147,8 +1155,9 @@ ORDER BY cal_user_type, cal_usre_id
$datetime = $GLOBALS['egw']->datetime;
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
$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');
return $id;
}
@ -1180,11 +1189,12 @@ ORDER BY cal_user_type, cal_usre_id
{
// update the modification information of the related event
list(,$cal_id) = explode(':',$id);
if ($cal_id) {
if ($cal_id)
{
$datetime = $GLOBALS['egw']->datetime;
$now = ($now_su ? $now_su : time() + $datetime->this->tz_offset);
$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');
}
return $this->async->cancel_timer($id);
@ -1384,5 +1394,4 @@ ORDER BY cal_user_type, cal_usre_id
sort($days);
return $days;
}
}