Contact groups
This commit is contained in:
parent
b6cc8c0715
commit
5fbfa61a4b
4 changed files with 164 additions and 47 deletions
|
@ -32,7 +32,7 @@ class carddav_contacts extends rcube_addressbook
|
|||
public $rights = 'lrs';
|
||||
public $readonly = true;
|
||||
public $undelete = false;
|
||||
public $groups = false; // TODO
|
||||
public $groups = true;
|
||||
|
||||
public $coltypes = [
|
||||
'name' => ['limit' => 1],
|
||||
|
@ -108,7 +108,7 @@ class carddav_contacts extends rcube_addressbook
|
|||
'manager',
|
||||
'assistant',
|
||||
'spouse',
|
||||
'children',
|
||||
// 'children',
|
||||
'notes',
|
||||
];
|
||||
|
||||
|
@ -810,30 +810,34 @@ class carddav_contacts extends rcube_addressbook
|
|||
function create_group($name)
|
||||
{
|
||||
$this->_fetch_groups();
|
||||
$result = false;
|
||||
|
||||
$rcube = rcube::get_instance();
|
||||
|
||||
$list = [
|
||||
'name' => $name,
|
||||
'uid' => strtoupper(md5(time() . uniqid(rand())) . '-' . substr(md5($rcube->user->get_username()), 0, 16)),
|
||||
'name' => $name,
|
||||
'kind' => 'group',
|
||||
'member' => [],
|
||||
];
|
||||
$saved = $this->storage->save($list, 'distribution-list');
|
||||
|
||||
$saved = $this->storage->save($list, 'contact');
|
||||
|
||||
if (!$saved) {
|
||||
rcube::raise_error([
|
||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error saving distribution-list object to CardDAV server"
|
||||
'message' => "Error saving a contact group to CardDAV server"
|
||||
],
|
||||
true, false
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$id = $this->uid2id($list['uid']);
|
||||
$this->distlists[$id] = $list;
|
||||
$result = ['id' => $id, 'name' => $name];
|
||||
}
|
||||
|
||||
return $result;
|
||||
$id = $this->uid2id($list['uid']);
|
||||
|
||||
$this->distlists[$id] = $list;
|
||||
|
||||
return ['id' => $id, 'name' => $name];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -846,25 +850,25 @@ class carddav_contacts extends rcube_addressbook
|
|||
function delete_group($gid)
|
||||
{
|
||||
$this->_fetch_groups();
|
||||
$result = false;
|
||||
|
||||
if ($list = $this->distlists[$gid]) {
|
||||
$deleted = $this->storage->delete($list['uid']);
|
||||
$list = $this->distlists[$gid];
|
||||
|
||||
if (!$list) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$deleted = $this->storage->delete($list['uid']);
|
||||
|
||||
if (!$deleted) {
|
||||
rcube::raise_error([
|
||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error deleting distribution-list object from the CardDAV server"
|
||||
'message' => "Error deleting a contact group from the CardDAV server"
|
||||
],
|
||||
true, false
|
||||
);
|
||||
}
|
||||
else {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -874,25 +878,33 @@ class carddav_contacts extends rcube_addressbook
|
|||
* @param string New name to set for this group
|
||||
* @param string New group identifier (if changed, otherwise don't set)
|
||||
*
|
||||
* @return bool New name on success, false if no data was changed
|
||||
* @return string|false New name on success, false if no data was changed
|
||||
*/
|
||||
function rename_group($gid, $newname, &$newid)
|
||||
{
|
||||
$this->_fetch_groups();
|
||||
|
||||
$list = $this->distlists[$gid];
|
||||
|
||||
if ($newname != $list['name']) {
|
||||
$list['name'] = $newname;
|
||||
$saved = $this->storage->save($list, 'distribution-list', $list['uid']);
|
||||
if (!$list) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($newname === $list['name']) {
|
||||
return $newname;
|
||||
}
|
||||
|
||||
$list['name'] = $newname;
|
||||
$saved = $this->storage->save($list, 'contact', $list['uid']);
|
||||
|
||||
if (!$saved) {
|
||||
rcube::raise_error([
|
||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error saving distribution-list object to CardDAV server"
|
||||
'message' => "Error saving a contact group to CardDAV server"
|
||||
],
|
||||
true, false
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -904,7 +916,8 @@ class carddav_contacts extends rcube_addressbook
|
|||
*
|
||||
* @param string Group identifier
|
||||
* @param array List of contact identifiers to be added
|
||||
* @return int Number of contacts added
|
||||
*
|
||||
* @return int Number of contacts added
|
||||
*/
|
||||
function add_to_group($gid, $ids)
|
||||
{
|
||||
|
@ -914,12 +927,17 @@ class carddav_contacts extends rcube_addressbook
|
|||
|
||||
$this->_fetch_groups(true);
|
||||
|
||||
$list = $this->distlists[$gid];
|
||||
$list = $this->distlists[$gid];
|
||||
|
||||
if (!$list) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$added = 0;
|
||||
$uids = [];
|
||||
$exists = [];
|
||||
|
||||
foreach ((array)$list['member'] as $member) {
|
||||
foreach ((array) $list['member'] as $member) {
|
||||
$exists[] = $member['ID'];
|
||||
}
|
||||
|
||||
|
@ -952,7 +970,7 @@ class carddav_contacts extends rcube_addressbook
|
|||
}
|
||||
|
||||
if ($added) {
|
||||
$saved = $this->storage->save($list, 'distribution-list', $list['uid']);
|
||||
$saved = $this->storage->save($list, 'contact', $list['uid']);
|
||||
}
|
||||
else {
|
||||
$saved = true;
|
||||
|
@ -961,7 +979,7 @@ class carddav_contacts extends rcube_addressbook
|
|||
if (!$saved) {
|
||||
rcube::raise_error([
|
||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error saving distribution-list to CardDAV server"
|
||||
'message' => "Error saving a contact-group to CardDAV server"
|
||||
],
|
||||
true, false
|
||||
);
|
||||
|
@ -986,13 +1004,16 @@ class carddav_contacts extends rcube_addressbook
|
|||
*/
|
||||
function remove_from_group($gid, $ids)
|
||||
{
|
||||
if (!is_array($ids)) {
|
||||
$ids = explode(',', $ids);
|
||||
$this->_fetch_groups();
|
||||
|
||||
$list = $this->distlists[$gid];
|
||||
|
||||
if (!$list) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_fetch_groups();
|
||||
if (!($list = $this->distlists[$gid])) {
|
||||
return false;
|
||||
if (!is_array($ids)) {
|
||||
$ids = explode(',', $ids);
|
||||
}
|
||||
|
||||
$new_member = [];
|
||||
|
@ -1004,12 +1025,12 @@ class carddav_contacts extends rcube_addressbook
|
|||
|
||||
// write distribution list back to server
|
||||
$list['member'] = $new_member;
|
||||
$saved = $this->storage->save($list, 'distribution-list', $list['uid']);
|
||||
$saved = $this->storage->save($list, 'contact', $list['uid']);
|
||||
|
||||
if (!$saved) {
|
||||
rcube::raise_error([
|
||||
'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
|
||||
'message' => "Error saving distribution-list object to CardDAV server"
|
||||
'message' => "Error saving a contact group to CardDAV server"
|
||||
],
|
||||
true, false
|
||||
);
|
||||
|
@ -1020,7 +1041,9 @@ class carddav_contacts extends rcube_addressbook
|
|||
$j = array_search($gid, $this->groupmembers[$id]);
|
||||
unset($this->groupmembers[$id][$j]);
|
||||
}
|
||||
|
||||
$this->distlists[$gid] = $list;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1130,15 +1153,17 @@ class carddav_contacts extends rcube_addressbook
|
|||
}
|
||||
|
||||
/**
|
||||
* Read distribution-lists AKA groups from server
|
||||
* Read contact groups from server
|
||||
*/
|
||||
private function _fetch_groups($with_contacts = false)
|
||||
{
|
||||
return; // TODO
|
||||
|
||||
if (!isset($this->distlists)) {
|
||||
$this->distlists = $this->groupmembers = [];
|
||||
foreach ($this->storage->select('distribution-list', true) as $record) {
|
||||
|
||||
// Set order (and LIMIT to skip the count(*) select)
|
||||
$this->storage->set_order_and_limit(['name'], 200, 0);
|
||||
|
||||
foreach ($this->storage->select('group', true) as $record) {
|
||||
$record['ID'] = $this->uid2id($record['uid']);
|
||||
foreach ((array)$record['member'] as $i => $member) {
|
||||
$mid = $this->uid2id($member['uid'] ? $member['uid'] : 'mailto:' . $member['email']);
|
||||
|
@ -1150,8 +1175,11 @@ class carddav_contacts extends rcube_addressbook
|
|||
$this->contacts[$mid] = $record['member'][$i];
|
||||
}
|
||||
}
|
||||
|
||||
$this->distlists[$record['ID']] = $record;
|
||||
}
|
||||
|
||||
$this->storage->set_order_and_limit($this->_sort_columns(), null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ class kolab_storage_dav
|
|||
/**
|
||||
* Get a list of storage folders for the given data type
|
||||
*
|
||||
* @param string Data type to list folders for (contact,distribution-list,event,task,note)
|
||||
* @param string Data type to list folders for (contact,event,task,note)
|
||||
*
|
||||
* @return array List of kolab_storage_dav_folder objects
|
||||
*/
|
||||
|
@ -87,7 +87,7 @@ class kolab_storage_dav
|
|||
/**
|
||||
* Getter for the storage folder for the given type
|
||||
*
|
||||
* @param string Data type to list folders for (contact,distribution-list,event,task,note)
|
||||
* @param string Data type to list folders for (contact,event,task,note)
|
||||
*
|
||||
* @return object kolab_storage_dav_folder The folder object
|
||||
*/
|
||||
|
|
|
@ -38,6 +38,10 @@ class kolab_storage_dav_cache_contact extends kolab_storage_dav_cache
|
|||
$sql_data = parent::_serialize($object);
|
||||
$sql_data['type'] = $object['_type'] ?: 'contact';
|
||||
|
||||
if ($sql_data['type'] == 'group' || (!empty($object['kind']) && $object['kind'] == 'group')) {
|
||||
$sql_data['type'] = 'group';
|
||||
}
|
||||
|
||||
// columns for sorting
|
||||
$sql_data['name'] = rcube_charset::clean($object['name'] . $object['prefix']);
|
||||
$sql_data['firstname'] = rcube_charset::clean($object['firstname'] . $object['middlename'] . $object['surname']);
|
||||
|
|
|
@ -483,10 +483,52 @@ class kolab_storage_dav_folder extends kolab_storage_folder
|
|||
return false;
|
||||
}
|
||||
|
||||
$vcard = new rcube_vcard($object['data'], RCUBE_CHARSET, false);
|
||||
// vCard properties not supported by rcube_vcard
|
||||
$map = [
|
||||
'uid' => 'UID',
|
||||
'kind' => 'KIND',
|
||||
'member' => 'MEMBER',
|
||||
'x-kind' => 'X-ADDRESSBOOKSERVER-KIND',
|
||||
'x-member' => 'X-ADDRESSBOOKSERVER-MEMBER',
|
||||
];
|
||||
|
||||
// TODO: We should probably use Sabre/Vobject to parse the vCard
|
||||
|
||||
$vcard = new rcube_vcard($object['data'], RCUBE_CHARSET, false, $map);
|
||||
|
||||
if (!empty($vcard->displayname) || !empty($vcard->surname) || !empty($vcard->firstname) || !empty($vcard->email)) {
|
||||
$result = $vcard->get_assoc();
|
||||
|
||||
// Contact groups
|
||||
if (!empty($result['x-kind']) && implode($result['x-kind']) == 'group') {
|
||||
$result['_type'] = 'group';
|
||||
$members = isset($result['x-member']) ? $result['x-member'] : [];
|
||||
unset($result['x-kind'], $result['x-member']);
|
||||
}
|
||||
else if (!empty($result['kind']) && implode($result['kind']) == 'group') {
|
||||
$result['_type'] = 'group';
|
||||
$members = isset($result['member']) ? $result['member'] : [];
|
||||
unset($result['kind'], $result['member']);
|
||||
}
|
||||
|
||||
if (isset($members)) {
|
||||
$result['member'] = [];
|
||||
foreach ($members as $member) {
|
||||
if (strpos($member, 'urn:uuid:') === 0) {
|
||||
$result['member'][] = ['uid' => substr($member, 9)];
|
||||
}
|
||||
else if (strpos($member, 'mailto:') === 0) {
|
||||
$member = reset(rcube_mime::decode_address_list(urldecode(substr($member, 7))));
|
||||
if (!empty($member['mailto'])) {
|
||||
$result['member'][] = ['email' => $member['mailto'], 'name' => $member['name']];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($result['uid'])) {
|
||||
$result['uid'] = preg_replace('/^urn:uuid:/', '', implode($result['uid']));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
@ -517,9 +559,17 @@ class kolab_storage_dav_folder extends kolab_storage_folder
|
|||
}
|
||||
else if ($this->type == 'contact') {
|
||||
// copy values into vcard object
|
||||
$vcard = new rcube_vcard('', RCUBE_CHARSET, false, ['uid' => 'UID']);
|
||||
// TODO: We should probably use Sabre/Vobject to create the vCard
|
||||
|
||||
$vcard->set('groups', null);
|
||||
// vCard properties not supported by rcube_vcard
|
||||
$map = ['uid' => 'UID', 'kind' => 'KIND'];
|
||||
$vcard = new rcube_vcard('', RCUBE_CHARSET, false, $map);
|
||||
|
||||
if ((!empty($object['_type']) && $object['_type'] == 'group')
|
||||
|| (!empty($object['type']) && $object['type'] == 'group')
|
||||
) {
|
||||
$object['kind'] = 'group';
|
||||
}
|
||||
|
||||
foreach ($object as $key => $values) {
|
||||
list($field, $section) = rcube_utils::explode(':', $key);
|
||||
|
@ -537,6 +587,41 @@ class kolab_storage_dav_folder extends kolab_storage_folder
|
|||
}
|
||||
|
||||
$result = $vcard->export(false);
|
||||
|
||||
if (!empty($object['kind']) && $object['kind'] == 'group') {
|
||||
$members = '';
|
||||
foreach ((array) $object['member'] as $member) {
|
||||
$value = null;
|
||||
if (!empty($member['uid'])) {
|
||||
$value = 'urn:uuid:' . $member['uid'];
|
||||
}
|
||||
else if (!empty($member['email']) && !empty($member['name'])) {
|
||||
$value = 'mailto:' . urlencode(sprintf('"%s" <%s>', addcslashes($member['name'], '"'), $member['email']));
|
||||
}
|
||||
else if (!empty($member['email'])) {
|
||||
$value = 'mailto:' . $member['email'];
|
||||
}
|
||||
|
||||
if ($value) {
|
||||
$members .= "MEMBER:{$value}\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($members) {
|
||||
$result = preg_replace('/\r\nEND:VCARD/', "\r\n{$members}END:VCARD", $result);
|
||||
}
|
||||
|
||||
/**
|
||||
Version 4.0 of the vCard format requires Cyrus >= 3.6.0, we'll use Version 3.0 for now
|
||||
|
||||
$result = preg_replace('/\r\nVERSION:3\.0\r\n/', "\r\nVERSION:4.0\r\n", $result);
|
||||
$result = preg_replace('/\r\nN:[^\r]+/', '', $result);
|
||||
$result = preg_replace('/\r\nUID:([^\r]+)/', "\r\nUID:urn:uuid:\\1", $result);
|
||||
*/
|
||||
|
||||
$result = preg_replace('/\r\nMEMBER:([^\r]+)/', "\r\nX-ADDRESSBOOKSERVER-MEMBER:\\1", $result);
|
||||
$result = preg_replace('/\r\nKIND:([^\r]+)/', "\r\nX-ADDRESSBOOKSERVER-KIND:\\1", $result);
|
||||
}
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
|
@ -578,7 +663,7 @@ class kolab_storage_dav_folder extends kolab_storage_folder
|
|||
/**
|
||||
* Return folder name as string representation of this object
|
||||
*
|
||||
* @return string Full IMAP folder name
|
||||
* @return string Folder display name
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue