allow status update via CalDAV/GroupDAV PUT and DELETE for attendees (with no other rights on the event), moved that code from bocalupdate (wasnt working because of wrong param code) to boical, this should work for SyncML and CalDAV/GroupDAV - thought SyncML does not handle the delete to reject an event so far

This commit is contained in:
Ralf Becker 2008-05-17 13:00:34 +00:00
parent a659e4eb6b
commit 89eba8038d
3 changed files with 73 additions and 48 deletions

View File

@ -81,7 +81,7 @@ class bocalupdate extends bocal
*/
function update(&$event,$ignore_conflicts=false,$touch_modified=true,$ignore_acl=false)
{
//error_log(__METHOD__."(".str_replace(array("\n",' '),'',print_r($event,true)).",$ignore_conflicts,$touch_modified,$ignore_acl)");
//error_log(__METHOD__."(".array2string($event).",$ignore_conflicts,$touch_modified,$ignore_acl)");
if ($this->debug > 1 || $this->debug == 'update')
{
$this->debug_message('bocalupdate::update(%1,ignore_conflict=%2,touch_modified=%3,ignore_acl=%4)',
@ -117,21 +117,6 @@ class bocalupdate extends bocal
!$event['id'] && !$this->check_perms(EGW_ACL_EDIT,0,$event['owner'])) &&
!$this->check_perms(EGW_ACL_ADD,0,$event['owner']))
{
// Just update the status, if the user is in the event already
// is user is in both original and updated event
$egw_event = $this->read($event['id']);
if ( isset($egw_event['participants'][$this->user])
&& isset($event['participants'][$this->user]))
{
// Update their status in the event and say we're done.
// Admittedly, this is false, it's dropping any changes on the floor,
// But this will work better than dropping -everything- silently on
// the floor
$this->set_status($event['id'],'u',$this->user,$event['participants'][$this->user],0);
unset($egw_event);
return $event['id'];
}
return false;
}

View File

@ -234,7 +234,8 @@
break;
case 'ORGANIZER': // according to iCalendar standard, ORGANIZER not used for events in the own calendar
if (!isset($event['participants'][$event['owner']]) || count($event['participants']) > 1)
if ($event['owner'] != $this->user)
//if (!isset($event['participants'][$event['owner']]) || count($event['participants']) > 1)
{
$mailtoOrganizer = $GLOBALS['egw']->accounts->id2name($event['owner'],'account_email');
$attributes['ORGANIZER'] = $mailtoOrganizer ? 'MAILTO:'.$mailtoOrganizer : '';
@ -475,7 +476,8 @@
$_vcalData = preg_replace("/[\r\n]+ /",'',$_vcalData);
$vcal = &new Horde_iCalendar;
if(!$vcal->parsevCalendar($_vcalData)) {
if(!$vcal->parsevCalendar($_vcalData))
{
return FALSE;
}
@ -850,6 +852,10 @@
{
$event['id'] = $cal_id;
}
elseif($event['id'] && $cal_id <= 0)
{
$cal_id = $event['id']; // event[id] set via uid
}
while(($fieldName = array_shift($supportedFields)))
{
switch($fieldName)
@ -892,10 +898,9 @@
// If this is an updated meeting, and the client doesn't support
// participants, add them back
if( $cal_id >0 && !isset($this->supportedFields['participants']))
if( $cal_id > 0 && !isset($this->supportedFields['participants']))
{
$egw_event = $this->read($cal_id);
if ($egw_event)
if (($egw_event = $this->read($cal_id)))
{
$event['participants'] = $egw_event['participants'];
$event['participant_types'] = $egw_event['participant_types'];
@ -906,22 +911,26 @@
if( $cal_id > 0 )
{
// for each existing participant:
$egw_event = $this->read($cal_id);
if ( $egw_event )
if (($egw_event = $this->read($cal_id)))
{
foreach( $egw_event['participants'] as $uid => $status )
{
// Is it a resource?
if ( preg_match("/^r(.*)/", $uid, $matches) )
// Is it a resource and not longer present in the event?
if ( $uid[0] == 'r' && !isset($event['participants'][$uid]) )
{
// Add it back in
$event['participants'][$uid] = 'A';
$event['participant_types']['r'][$matches[1]] = 'A';
$event['participants'][$uid] = $event['participant_types']['r'][substr($uid,1)] = $status;
}
}
}
}
// check if iCal changes the organizer, which is not allowed
if ($cal_id > 0 && ($egw_event = $this->read($cal_id)) && $event['owner'] != $egw_event['owner'])
{
$event['owner'] = $egw_event['owner']; // set it back to the original owner
}
#error_log('ALARMS');
#error_log(print_r($event, true));
@ -932,6 +941,16 @@
}
if (!($Ok = $this->update($event, TRUE)))
{
// check if current user is an attendee and tried to change his status
if ($Ok === false && $cal_id && ($egw_event = $this->read($cal_id)) && isset($egw_event['participants'][$this->user]) &&
$egw_event['participants'][$this->user] !== $event['participants'][$this->user])
{
$this->set_status($egw_event,$this->user,
$status = $event['participants'][$this->user] ? $event['participants'][$this->user] : 'R');
$Ok = $cal_id;
continue;
}
break; // stop with the first error
}
else

View File

@ -38,9 +38,16 @@ class calendar_groupdav extends groupdav_handler
//'RECURRENCE-ID'
);
function __construct($debug=null)
/**
* Constructor
*
* @param string $app 'calendar', 'addressbook' or 'infolog'
* @param int $debug=null debug-level to set
* @param string $base_uri=null base url of handler
*/
function __construct($app,$debug=null,$base_uri=null)
{
parent::__construct('calendar',$debug);
parent::__construct($app,$debug,$base_uri);
$this->bo =& new bocalupdate();
}
@ -57,7 +64,7 @@ class calendar_groupdav extends groupdav_handler
*/
function propfind($path,$options,&$files,$user,$id='')
{
if ($this->debug > 2) error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user,$id)");
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user,$id)");
// ToDo: add parameter to only return id & etag
$cal_filters = array(
@ -68,7 +75,7 @@ class calendar_groupdav extends groupdav_handler
'daywise' => false,
'date_format' => 'server',
);
error_log(__METHOD__."($path,,,$user,$id) cal_filters=".str_replace(array("\n",' '),'',print_r($cal_filters,true)));
if ($this->debug > 1) error_log(__METHOD__."($path,,,$user,$id) cal_filters=".array2string($cal_filters));
// process REPORT filters or multiget href's
if (($id || $options['root']['name'] != 'propfind') && !$this->_report_filters($options,$cal_filters,$id))
@ -131,13 +138,13 @@ class calendar_groupdav extends groupdav_handler
switch($filter['name'])
{
case 'comp-filter':
error_log(__METHOD__."($path,...) comp-filter='{$filter['attrs']['name']}'");
if ($this->debug > 1) error_log(__METHOD__."($path,...) comp-filter='{$filter['attrs']['name']}'");
switch($filter['attrs']['name'])
{
case 'VTODO':
return false; // return nothing for now, todo: check if we can pass it on to the infolog handler
// todos are handled by the infolog handler
$infolog_handler = new infolog_groupdav();
$infolog_handler = new groupdav_infolog();
return $infolog_handler->propfind($path,$options,$files,$user,$method);
case 'VCALENDAR':
CASE 'VEVENT':
@ -145,14 +152,14 @@ class calendar_groupdav extends groupdav_handler
}
break;
case 'prop-filter':
error_log(__METHOD__."($path,...) prop-filter='{$filter['attrs']['name']}'");
if ($this->debug > 1) error_log(__METHOD__."($path,...) prop-filter='{$filter['attrs']['name']}'");
$prop_filter = $filter['attrs']['name'];
break;
case 'text-match':
error_log(__METHOD__."($path,...) text-match: $prop_filter='{$filter['data']}'");
if ($this->debug > 1) error_log(__METHOD__."($path,...) text-match: $prop_filter='{$filter['data']}'");
if (!isset($this->filter_prop2cal[strtoupper($prop_filter)]))
{
error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown property '$prop_filter' --> ignored");
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user) unknown property '$prop_filter' --> ignored");
}
else
{
@ -161,14 +168,15 @@ class calendar_groupdav extends groupdav_handler
unset($prop_filter);
break;
case 'param-filter':
error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}'");
if ($this->debug) error_log(__METHOD__."($path,...) param-filter='{$filter['attrs']['name']}' not (yet) implemented!");
break;
case 'time-range':
error_log(__METHOD__."($path,...) time-range={$filter['attrs']['start']}-{$filter['attrs']['end']}");
if ($this->debug > 1) error_log(__METHOD__."($path,...) time-range={$filter['attrs']['start']}-{$filter['attrs']['end']}");
$cal_filters['start'] = $filter['attrs']['start'];
$cal_filters['end'] = $filter['attrs']['end'];
break;
default:
error_log(__METHOD__."($path,".str_replace(array("\n",' '),'',print_r($options,true)).",,$user) unknown filter --> ignored");
if ($this->debug) error_log(__METHOD__."($path,".array2string($options).",,$user) unknown filter --> ignored");
break;
}
}
@ -214,7 +222,7 @@ class calendar_groupdav extends groupdav_handler
{
$cal_filters['query'][] = 'egw_cal.cal_id IN ('.implode(',',array_map(create_function('$n','return (int)$n;'),$ids)).')';
}
//error_log(__METHOD__."($path,,,$user,$id) calendar-multiget: ids=".implode(',',$ids));
if ($this->debug) error_log(__METHOD__."($path,,,$user,$id) calendar-multiget: ids=".implode(',',$ids));
}
return true;
}
@ -249,7 +257,8 @@ class calendar_groupdav extends groupdav_handler
*/
function put(&$options,$id,$user=null)
{
$event = $this->_common_get_put_delete('PUT',$options,$id);
$return_no_access=true; // as handled by importVCal anyway and allows it to set the status for participants
$event = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access);
if (!is_null($event) && !is_array($event))
{
return $event;
@ -257,14 +266,14 @@ class calendar_groupdav extends groupdav_handler
if (!($cal_id = ExecMethod2('calendar.boical.importVCal',$options['content'],is_numeric($id) ? $id : -1,
self::etag2value($this->http_if_match))))
{
if ($this->debug) error_log(__METHOD__."(,$id) import_vevent($options[content]) returned false");
return false; // something went wrong ...
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
return '403 Forbidden';
}
header('ETag: '.$this->get_etag($cal_id));
if (is_null($event))
if (is_null($event) || !$return_no_access) // let lightning think the event is added
{
error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event));
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event));
header('Location: '.$this->base_uri.'/calendar/'.$cal_id);
return '201 Created';
}
@ -274,14 +283,24 @@ class calendar_groupdav extends groupdav_handler
/**
* Handle delete request for an event
*
* If current user has no right to delete the event, but is an attendee, we reject the event for him.
*
* @param array &$options
* @param int $id
* @return mixed boolean true on success, false on failure or string with http status (eg. '404 Not Found')
*/
function delete(&$options,$id)
{
if (!is_array($event = $this->_common_get_put_delete('DELETE',$options,$id)))
$return_no_access=true; // to allow to check if current use is a participant and reject the event for him
if (!is_array($event = $this->_common_get_put_delete('DELETE',$options,$id,$return_no_access)) || !$return_no_access)
{
if (!$return_no_access)
{
$ret = isset($event['participants'][$this->bo->user]) &&
$this->bo->set_status($event,$this->bo->user,'R') ? true : '403 Forbidden';
if ($this->debug) error_log(__METHOD__."(,$id) return_no_access=$return_no_access, event[participants]=".array2string($event['participants']).", user={$this->bo->user} --> return $ret");
return $ret;
}
return $event;
}
return $this->bo->delete($id);
@ -306,16 +325,18 @@ class calendar_groupdav extends groupdav_handler
*/
function get_etag($entry)
{
$e_in = $entry;
if (!is_array($entry))
{
$entry = $this->read($entry);
}
if (!$entry['id'] || !isset($entry['etag']) || !isset($entry['participants'])) error_log(__METHOD__."($e_in): id=$entry[id], etag=$entry[etag], isset(participants)=".(int)isset($entry['participants']).", title=$entry[title]: id, etag or participants not set!!!");
$etag = $entry['id'].':'.$entry['etag'];
// add a hash over the participants and their stati
ksort($entry['participants']); // create a defined order
$etag .= ':'.md5(serialize($entry['participants']));
//error_log(__METHOD__."($entry[id] ($entry[etag]): $entry[title] --> etag=$etag");
return $etag;
return $etag.'x';
}
/**