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(); $handler = self::_get_handler();
} }
unset($filter['address_data']); unset($filter['address_data']);
$files = array(); $files = array();
// we query etag and modified, as LDAP does not have the strong sql etag // 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))) 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) 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('getcontentlength',bytes($content));
$props[] = HTTP_WebDAV_Server::mkprop(groupdav::CARDDAV,'address-data',$content,true); $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) function put(&$options,$id,$user=null)
{ {
if ($this->debug) error_log(__METHOD__.'('.array2string($options).",$id,$user)"); 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(); $handler = self::_get_handler();
$vCard = htmlspecialchars_decode($options['content']); $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'])) if (is_array($contact['category']))
{ {
$contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId)); $contact['category'] = implode(',',$this->bo->find_or_add_categories($contact['category'], $contactId));
} }
elseif ($contactId > 0) 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 // dont allow the client to overwrite certain values
$contact['uid'] = $ok['uid']; $contact['uid'] = $oldContact['uid'];
$contact['owner'] = $ok['owner']; $contact['owner'] = $oldContact['owner'];
$contact['private'] = $ok['private']; $contact['private'] = $oldContact['private'];
} }
else else
{ {
$contact['owner'] = $user; $contact['owner'] = $user;
} }
if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match); if ($this->http_if_match) $contact['etag'] = self::etag2value($this->http_if_match);
if (!($save_ok = $this->bo->save($contact))) if (!($save_ok = $this->bo->save($contact)))
@ -309,18 +342,19 @@ class addressbook_groupdav extends groupdav_handler
} }
return false; return false;
} }
if (!isset($contact['etag'])) if (!isset($contact['etag']))
{ {
$contact = $this->read($save_ok); $contact = $this->read($save_ok);
} }
header('ETag: '.$this->get_etag($contact)); header('ETag: '.$this->get_etag($contact));
if (is_null($ok)) if ($retval !== true)
{ {
$path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']); $path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header($h='Location: '.$path.self::get_path($contact)); header($h='Location: '.$this->base_uri.$path.self::get_path($contact));
if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): 201 Created"); if ($this->debug) error_log(__METHOD__."($method,,$id) header('$h'): $retval");
return '201 Created'; return $retval;
} }
return true; return true;
} }

View File

@ -437,16 +437,16 @@ class calendar_groupdav extends groupdav_handler
function put(&$options,$id,$user=null) function put(&$options,$id,$user=null)
{ {
if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true)); 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()); if ($this->debug) error_log(__METHOD__.print_r($oldEvent,true).function_backtrace());
return $event; 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 // we have not permission on this user's calendar
if ($this->debug) error_log(__METHOD__."(,$user) we have not enough rights on this 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(); $handler = $this->_get_handler();
$vCalendar = htmlspecialchars_decode($options['content']); $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))) self::etag2value($this->http_if_match), false, 0, $this->principalURL, $user)))
{ {
if ($this->debug) error_log(__METHOD__."(,$id) importVCal($options[content]) returned false"); 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)); 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']); $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)); if ($this->debug) error_log(__METHOD__."(,$id,$user) cal_id=$cal_id: $retval");
header('Location: '.$path.self::get_path($cal_id)); header('Location: '.$this->base_uri.$path.self::get_path($cal_id));
return '201 Created'; return $retval;
} }
return true; return true;
} }

View File

@ -193,26 +193,61 @@ class infolog_groupdav extends groupdav_handler
*/ */
function put(&$options,$id,$user=null) function put(&$options,$id,$user=null)
{ {
$ok = $this->_common_get_put_delete('PUT',$options,$id); if ($this->debug) error_log(__METHOD__."($id, $user)".print_r($options,true));
if (!is_null($ok) && !is_array($ok))
$oldTask = $this->_common_get_put_delete('PUT',$options,$id);
if (!is_null($oldTask) && !is_array($oldTask))
{ {
return $ok; return $oldTask;
} }
$handler = $this->_get_handler(); $handler = $this->_get_handler();
$vTodo = htmlspecialchars_decode($options['content']); $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"); if ($this->debug) error_log(__METHOD__."(,$id) import_vtodo($options[content]) returned false");
return '403 Forbidden'; 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']); $path = preg_replace('|(.*)/[^/]*|', '\1/', $options['path']);
header('Location: '.$path.self::get_path($info_id)); header('Location: '.$this->base_uri.$path.self::get_path($infoId));
return '201 Created'; return $retval;
} }
return true; return true;
} }

View File

@ -238,7 +238,7 @@ abstract class groupdav_handler
* @param array &$options * @param array &$options
* @param int $id * @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 * @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) 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() public function key()
{ {
$current = $this->current(); $current = current($this->files);
if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path'])); if ($this->debug) error_log(__METHOD__."() returning ".array2string($current['path']));
return $current['path']; // we return path as key return $current['path']; // we return path as key