Let libkolabxml generate UIDs; preserve object properties Roundcube doens't understand by loading old XML object before updating

This commit is contained in:
Thomas Bruederli 2012-03-14 18:51:38 +01:00
parent edaad9b47c
commit 3f78d8f7b5
6 changed files with 95 additions and 54 deletions

View file

@ -518,8 +518,6 @@ class rcube_kolab_contacts extends rcube_addressbook
if (!$existing) {
// generate new Kolab contact item
$object = $this->_from_rcube_contact($save_data);
$object['uid'] = kolab_format::generate_uid();
$saved = $this->storagefolder->save($object, 'contact');
if (!$saved) {
@ -554,7 +552,7 @@ class rcube_kolab_contacts extends rcube_addressbook
{
$updated = false;
if ($old = $this->storagefolder->get_object($this->_id2uid($id))) {
$object = array_merge($old, $this->_from_rcube_contact($save_data));
$object = $this->_from_rcube_contact($save_data, $old);
$saved = $this->storagefolder->save($object, 'contact', $uid);
if (!$saved) {
@ -1030,9 +1028,9 @@ class rcube_kolab_contacts extends rcube_addressbook
}
/**
* Map fields from Roundcube format to internal Kolab_Format
* Map fields from Roundcube format to internal kolab_format_contact properties
*/
private function _from_rcube_contact($contact)
private function _from_rcube_contact($contact, $old = array())
{
if (!$contact['uid'] && $contact['ID'])
$contact['uid'] = $this->_id2uid($contact['ID']);
@ -1085,7 +1083,14 @@ class rcube_kolab_contacts extends rcube_addressbook
$contact['_attachments']['photo.attachment'] = false;
}
return $contact;
// copy meta data (starting with _) from old object
foreach ((array)$old as $key => $val) {
if (!isset($contact[$key]) && $key[0] == '_')
$contact[$key] = $val;
}
// add empty values for some fields which can be removed in the UI
return $contact + array('nickname' => '', 'birthday' => '', 'anniversary' => '', 'freebusyurl' => '');
}
}

View file

@ -26,6 +26,9 @@ abstract class kolab_format
{
public static $timezone;
protected $obj;
protected $data;
/**
* Factory method to instantiate a kolab_format object of the given type
*/
@ -42,28 +45,18 @@ abstract class kolab_format
return PEAR::raiseError(sprintf("Failed to load Kolab Format wrapper for type %s", $type));
}
/**
* Generate random UID for Kolab objects
*
* @return string UUID with a unique MD5 value
*/
public static function generate_uid()
{
return 'urn:uuid:' . md5(uniqid(mt_rand(), true));
}
/**
* Convert the given date/time value into a cDateTime object
*
* @param mixed Date/Time value either as unix timestamp, date string or PHP DateTime object
* @param DateTimeZone The timezone the date/time is in. Use global default if empty
* @param boolean True of the given date has no time component
* @return object The libkolabxml date/time object or null on error
* @return object The libkolabxml date/time object
*/
public static function get_datetime($datetime, $tz = null, $dateonly = false)
{
if (!$tz) $tz = self::$timezone;
$result = null;
$result = new cDateTime();
if (is_numeric($datetime))
$datetime = new DateTime('@'.$datetime, $tz);
@ -71,7 +64,6 @@ abstract class kolab_format
$datetime = new DateTime($datetime, $tz);
if (is_a($datetime, 'DateTime')) {
$result = new cDateTime();
$result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j'));
if (!$dateonly)
@ -141,11 +133,34 @@ abstract class kolab_format
public static function array2vector($arr)
{
$vec = new vectors;
foreach ((array)$arr as $val)
$vec->push($val);
foreach ((array)$arr as $val) {
if (strlen($val))
$vec->push($val);
}
return $vec;
}
/**
* Save the last generated UID to the object properties.
* Should be called after kolabformat::writeXXXX();
*/
protected function update_uid()
{
// get generated UID
if (!$this->data['uid']) {
$this->data['uid'] = kolabformat::getSerializedUID();
$this->obj->setUid($this->data['uid']);
}
}
/**
* Direct getter for object properties
*/
function __get($var)
{
return $this->data[$var];
}
/**
* Load Kolab object data from the given XML block
*

View file

@ -24,8 +24,10 @@ class kolab_format_contact extends kolab_format
'work' => Address::Work,
);
private $data;
private $obj;
private $gendermap = array(
'female' => Contact::Female,
'male' => Contact::Male,
);
// old Kolab 2 format field map
private $kolab2_fieldmap = array(
@ -98,7 +100,9 @@ class kolab_format_contact extends kolab_format
*/
public function write()
{
return kolabformat::writeContact($this->obj);
$xml = kolabformat::writeContact($this->obj);
parent::update_uid();
return $xml;
}
/**
@ -109,18 +113,16 @@ class kolab_format_contact extends kolab_format
public function set(&$object)
{
// set some automatic values if missing
if (empty($object['uid']))
$object['uid'] = self::generate_uid();
if (false && !$this->obj->created()) {
if (!empty($object['created']))
$object['created'] = new DateTime('now', self::$timezone);
$this->obj->setCreated(self::get_datetime($object['created']));
}
// do the hard work of setting object values
$this->obj->setUid($object['uid']);
if (!empty($object['uid']))
$this->obj->setUid($object['uid']);
// do the hard work of setting object values
$nc = new NameComponents;
$nc->setSurnames(self::array2vector($object['surname']));
$nc->setGiven(self::array2vector($object['firstname']));
@ -130,7 +132,7 @@ class kolab_format_contact extends kolab_format
$this->obj->setNameComponents($nc);
$this->obj->setName($object['name']);
if ($object['nickname'])
if (isset($object['nickname']))
$this->obj->setNickNames(self::array2vector($object['nickname']));
// organisation related properties (affiliation)
@ -191,15 +193,15 @@ class kolab_format_contact extends kolab_format
}
$this->obj->setTelephones($tels);
if ($object['gender'])
$this->obj->setGender($object['gender'] == 'female' ? Contact::Female : Contact::Male);
if ($object['notes'])
if (isset($object['gender']))
$this->obj->setGender($this->gendermap[$object['gender']] ? $this->gendermap[$object['gender']] : Contact::NotSet);
if (isset($object['notes']))
$this->obj->setNote($object['notes']);
if ($object['freebusyurl'])
if (isset($object['freebusyurl']))
$this->obj->setFreeBusyUrl($object['freebusyurl']);
if ($object['birthday'])
if (isset($object['birthday']))
$this->obj->setBDay(self::get_datetime($object['birthday'], null, true));
if ($object['anniversary'])
if (isset($object['anniversary']))
$this->obj->setAnniversary(self::get_datetime($object['anniversary'], null, true));
if (!empty($object['photo'])) {
@ -304,8 +306,9 @@ class kolab_format_contact extends kolab_format
if ($anniversary = self::php_datetime($this->obj->anniversary()))
$object['anniversary'] = $anniversary->format('c');
if ($g = $this->obj->gender())
$object['gender'] = $g == Contact::Female ? 'female' : 'male';
$gendermap = array_flip($this->gendermap);
if (($g = $this->obj->gender()) && $gendermap[$g])
$object['gender'] = $gendermap[$g];
if ($this->obj->photoMimetype())
$object['photo'] = $this->obj->photo();

View file

@ -5,9 +5,6 @@ class kolab_format_distributionlist extends kolab_format
{
public $CTYPE = 'application/vcard+xml';
private $data;
private $obj;
function __construct()
{
$this->obj = new DistList;
@ -30,17 +27,17 @@ class kolab_format_distributionlist extends kolab_format
*/
public function write()
{
return kolabformat::writeDistlist($this->obj);
$xml = kolabformat::writeDistlist($this->obj);
parent::update_uid();
return $xml;
}
public function set(&$object)
{
// set some automatic values if missing
if (empty($object['uid']))
$object['uid'] = self::generate_uid();
if (!empty($object['uid']))
$this->obj->setUid($object['uid']);
// do the hard work of setting object values
$this->obj->setUid($object['uid']);
$this->obj->setName($object['name']);
$members = new vectormember;

View file

@ -5,9 +5,6 @@ class kolab_format_event extends kolab_format
{
public $CTYPE = 'application/calendar+xml';
private $data;
private $obj;
function __construct()
{
$obj = new Event;
@ -20,7 +17,9 @@ class kolab_format_event extends kolab_format
public function write()
{
return kolabformat::writeEvent($this->obj);
$xml = kolabformat::writeEvent($this->obj);
parent::update_uid();
return $xml;
}
public function set(&$object)

View file

@ -44,6 +44,7 @@ class kolab_storage_folder
private $imap;
private $info;
private $owner;
private $objcache = array();
private $uid2msg = array();
@ -239,7 +240,8 @@ class kolab_storage_folder
*
* @param string The IMAP message UID to fetch
* @param string The object type expected
* @return array Hash array representing the Kolab object
* @param string The folder name where the message is stored
* @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found
*/
private function read_object($msguid, $type = null, $folder = null)
{
@ -247,6 +249,10 @@ class kolab_storage_folder
if (!$folder) $folder = $this->name;
$ctype= self::KTYPE_PREFIX . $type;
// requested message not in local cache
if ($this->objcache[$msguid])
return $this->objcache[$msguid];
$this->imap->set_folder($folder);
$message = new rcube_message($msguid);
$attachments = array();
@ -296,10 +302,16 @@ class kolab_storage_folder
}
if ($format->is_valid()) {
if ($formatobj)
return $format;
$object = $format->to_array();
$object['_msguid'] = $msguid;
$object['_mailbox'] = $this->name;
$object['_attachments'] = $attachments;
$object['_formatobj'] = $format;
$this->objcache[$msguid] = $object;
return $object;
}
@ -425,11 +437,21 @@ class kolab_storage_folder
*/
private function build_message(&$object, $type)
{
$format = kolab_format::factory($type);
// load old object to preserve data we don't understand/process
if (is_object($object['_formatobj']))
$format = $object['_formatobj'];
else if ($object['_msguid'] && ($old = $this->read_object($object['_msguid'], $type, $object['_mailbox'])))
$format = $old['_formatobj'];
// create new kolab_format instance
if (!$format)
$format = kolab_format::factory($type);
$format->set($object);
$xml = $format->write();
$object['uid'] = $format->uid; // get read UID from format
if (!$format->is_valid()) {
if (!$format->is_valid() || empty($object['uid'])) {
return false;
}
@ -450,7 +472,7 @@ class kolab_storage_folder
$mime->headers($headers);
$mime->setTXTBody('This is a Kolab Groupware object. '
. 'To view this object you will need an email client that understands the Kolab Groupware format. '
. "For a list of such email clients please visit http://www.kolab.org/kolab2-clients.html\n\n");
. "For a list of such email clients please visit http://www.kolab.org/\n\n");
$mime->addAttachment($xml,
$format->CTYPE,