Fix GroupDAV entry duplication issue

This commit is contained in:
Jörg Lehrke 2010-03-05 12:07:50 +00:00
parent 796beca7b1
commit 8175306dea
4 changed files with 146 additions and 38 deletions

View File

@ -132,7 +132,6 @@ class addressbook_groupdav extends groupdav_handler
$handler = self::_get_handler();
}
unset($filter['address_data']);
$files = array();
// we query etag and modified, as LDAP does not have the strong sql etag
if (($contacts =& $this->bo->search(array(),$address_data ? false : array('id','uid','etag','modified'),'contact_id','','',False,'AND',$start,$filter)))
@ -147,7 +146,7 @@ class addressbook_groupdav extends groupdav_handler
);
if ($address_data)
{
$content = $handler->getVCard($contact,$this->charset,false);
$content = $handler->getVCard($contact['id'],$this->charset,false);
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength',bytes($content));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true);
}
@ -269,35 +268,69 @@ class addressbook_groupdav extends groupdav_handler
function put(&$options,$id,$user=null)
{
if ($this->debug) error_log(__METHOD__.'('.array2string($options).",$id,$user)");
$ok = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($ok) && !is_array($ok))
$oldContact = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($oldContact) && !is_array($oldContact))
{
return $ok;
return $oldContact;
}
$handler = self::_get_handler();
$vCard = htmlspecialchars_decode($options['content']);
$contactId = (is_array($ok) ? -1 : $ok['id']);
$contact = $handler->vcardtoegw($vCard, $contactId);
if (is_array($oldContact))
{
$contactId = $oldContact['id'];
$retval = true;
}
else
{
// new entry?
if (($foundContacts = $handler->search($vCard)))
{
if (($contactId = array_shift($foundContacts)) &&
($oldContact = $this->bo->read($contactId)))
{
$retval = '301 Moved Permanently';
}
else
{
// to be safe
$contactId = -1;
$retval = '201 Created';
}
}
else
{
// new entry
$contactId = -1;
$retval = '201 Created';
}
}
$contact = $handler->vcardtoegw($vCard);
if (is_array($contact['category']))
{
$contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId));
}
elseif ($contactId > 0)
{
$contact['category'] = $ok['category'];
$contact['category'] = $oldContact['category'];
}
if (!is_null($ok))
if (is_array($oldContact))
{
$contact['id'] = $ok['id'];
$contact['id'] = $oldContact['id'];
// dont allow the client to overwrite certain values
$contact['uid'] = $ok['uid'];
$contact['owner'] = $ok['owner'];
$contact['private'] = $ok['private'];
$contact['uid'] = $oldContact['uid'];
$contact['owner'] = $oldContact['owner'];
$contact['private'] = $oldContact['private'];
}
else
{
$contact['owner'] = $user;
}
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
if (!($save_ok = $this->bo->save($contact)))
@ -309,18 +342,19 @@ class addressbook_groupdav extends groupdav_handler
}
return false;
}
if (!isset($contact['etag']))
{
$contact = $this->read($save_ok);
}
header('ETag: '.$this->get_etag($contact));
if (is_null($ok))
if ($retval !== true)
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header($h='Location: '.$path.self::get_path($contact));
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created");
return '201 Created';
header($h='Location: '.$this->base_uri.$path.self::get_path($contact));
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): $retval");
return $retval;
}
return true;
}

View File

@ -437,16 +437,16 @@ class calendar_groupdav extends groupdav_handler
function put(&$options,$id,$user=null)
{
if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
$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_no_access=true; // as handled by importVCal anyway and allows it to set the status for participants
$oldEvent = $this->_common_get_put_delete('PUT',$options,$id,$return_no_access);
if (!is_null($oldEvent) && !is_array($oldEvent))
{
if ($this->debug) error_log(__METHOD__.print_r($event,true).function_backtrace());
return $event;
if ($this->debug) error_log(__METHOD__.print_r($oldEvent,true).function_backtrace());
return $oldEvent;
}
if (is_null($event) && !$this->bo->check_perms(EGW_ACL_ADD, 0, $user))
if (is_null($oldEvent) && !$this->bo->check_perms(EGW_ACL_ADD, 0, $user))
{
// we have not permission on this user's calendar
if ($this->debug) error_log(__METHOD__."(,$user) we have not enough rights on this calendar");
@ -456,7 +456,46 @@ class calendar_groupdav extends groupdav_handler
$handler = $this->_get_handler();
$vCalendar = htmlspecialchars_decode($options['content']);
if (!($cal_id = $handler->importVCal($vCalendar, is_numeric($id) ? $id : -1,
if (is_array($oldEvent))
{
$eventId = $oldEvent['id'];
if ($return_no_access)
{
$retval = true;
}
else
{
// let lightning think the event is added
$retval = '201 Created';
}
}
else
{
// new entry?
if (($foundEvents = $handler->search($vCalendar)))
{
if (($eventId = array_shift($foundEvents)) &&
(list($eventId) = explode(':', $eventId)) &&
($oldEvent = $this->bo->read($eventId)))
{
$retval = '301 Moved Permanently';
}
else
{
// to be safe
$eventId = -1;
$retval = '201 Created';
}
}
else
{
// new entry
$eventId = -1;
$retval = '201 Created';
}
}
if (!($cal_id = $handler->importVCal($vCalendar, $eventId,
self::etag2value($this->http_if_match), false, 0, $this->principalURL, $user)))
{
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false");
@ -464,12 +503,12 @@ class calendar_groupdav extends groupdav_handler
}
header('ETag: '.$this->get_etag($cal_id));
if (is_null($event) || !$return_no_access) // let lightning think the event is added
if ($retval !== true)
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id, is_null(\$event)=".(int)is_null($event));
header('Location: '.$path.self::get_path($cal_id));
return '201 Created';
if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id: $retval");
header('Location: '.$this->base_uri.$path.self::get_path($cal_id));
return $retval;
}
return true;
}

View File

@ -193,26 +193,61 @@ class infolog_groupdav extends groupdav_handler
*/
function put(&$options,$id,$user=null)
{
$ok = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($ok) && !is_array($ok))
if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
$oldTask = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($oldTask) && !is_array($oldTask))
{
return $ok;
return $oldTask;
}
$handler = $this->_get_handler();
$vTodo = htmlspecialchars_decode($options['content']);
if (!($info_id = $handler->importVTODO($vTodo,is_numeric($id) ? $id : -1, false, $user)))
if (is_array($oldTask))
{
$taskId = $oldTask['info_id'];
$retval = true;
}
else
{
// new entry?
if (($foundTasks = $handler->searchVTODO($vTodo)))
{
if (($taskId = array_shift($foundTasks)) &&
($oldTask = $this->bo->read($taskId)))
{
$retval = '301 Moved Permanently';
}
else
{
// to be safe
$taskId = -1;
$retval = '201 Created';
}
}
else
{
// new entry
$taskId = -1;
$retval = '201 Created';
}
}
if (!($infoId = $handler->importVTODO($vTodo, $taskId, false, $user)))
{
if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
return '403 Forbidden';
}
header('ETag: '.$this->get_etag($info_id));
if (is_null($ok) || $id != $info_id)
if ($infoId != $taskId) $retval = '201 Created';
header('ETag: '.$this->get_etag($infoId));
if ($retval !== true)
{
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header('Location: '.$path.self::get_path($info_id));
return '201 Created';
header('Location: '.$this->base_uri.$path.self::get_path($infoId));
return $retval;
}
return true;
}

View File

@ -238,7 +238,7 @@ abstract class groupdav_handler
* @param array &$options
* @param int $id
* @param boolean &$return_no_access=false if set to true on call, instead of '403 Forbidden' the entry is returned and $return_no_access===false
* @return array/string entry on success, string with http-error-code on failure, null for PUT on an unknown id
* @return array|string entry on success, string with http-error-code on failure, null for PUT on an unknown id
*/
function _common_get_put_delete($method,&$options,$id,&$return_no_access=false)
{
@ -463,7 +463,7 @@ class groupdav_propfind_iterator implements Iterator
*/
public function key()
{
$current = $this->current();
$current = current($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path']));
return $current['path']; // we return path as key