Improved relation members handling code
This commit is contained in:
parent
944985314e
commit
08581c0a94
3 changed files with 180 additions and 124 deletions
|
@ -983,6 +983,9 @@ class kolab_notes extends rcube_plugin
|
||||||
$this->relations = null; // clear in-memory cache
|
$this->relations = null; // clear in-memory cache
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// make relation members up-to-date
|
||||||
|
kolab_storage_config::resolve_members($relation);
|
||||||
|
|
||||||
// assign all links to one relation, others will be removed
|
// assign all links to one relation, others will be removed
|
||||||
$members = array_merge($links, array($search));
|
$members = array_merge($links, array($search));
|
||||||
$diff1 = array_diff($members, $relation['members']);
|
$diff1 = array_diff($members, $relation['members']);
|
||||||
|
@ -1020,6 +1023,9 @@ class kolab_notes extends rcube_plugin
|
||||||
|
|
||||||
foreach ($this->get_relations($uid) as $relation) {
|
foreach ($this->get_relations($uid) as $relation) {
|
||||||
if (in_array($search, (array) $relation['members'])) {
|
if (in_array($search, (array) $relation['members'])) {
|
||||||
|
// make relation members up-to-date
|
||||||
|
kolab_storage_config::resolve_members($relation);
|
||||||
|
|
||||||
foreach ($relation['members'] as $member) {
|
foreach ($relation['members'] as $member) {
|
||||||
if ($member != $search) {
|
if ($member != $search) {
|
||||||
$result[] = $member;
|
$result[] = $member;
|
||||||
|
@ -1043,18 +1049,15 @@ class kolab_notes extends rcube_plugin
|
||||||
|
|
||||||
// get UIDs of assigned notes
|
// get UIDs of assigned notes
|
||||||
foreach ($this->get_relations() as $relation) {
|
foreach ($this->get_relations() as $relation) {
|
||||||
foreach ($relation['members'] as $member) {
|
// get Folder/UIDs of relation members
|
||||||
$member = kolab_storage_config::parse_member_url($member);
|
$messages = kolab_storage_config::resolve_members($relation);
|
||||||
if ($member['folder'] == $folder && $member['uid'] == $message->uid) {
|
|
||||||
reset($relation['members']);
|
|
||||||
// find note UID(s)
|
|
||||||
foreach ($relation['members'] as $member) {
|
|
||||||
if (strpos($member, 'urn:uuid:') === 0) {
|
|
||||||
$uids[] = substr($member, 9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
continue 2;
|
if (!empty($messages[$folder]) && in_array($message->uid, $messages[$folder])) {
|
||||||
|
// find note UID(s)
|
||||||
|
foreach ($relation['members'] as $member) {
|
||||||
|
if (strpos($member, 'urn:uuid:') === 0) {
|
||||||
|
$uids[] = substr($member, 9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,12 +220,6 @@ class kolab_tags_engine
|
||||||
|
|
||||||
// for every tag...
|
// for every tag...
|
||||||
foreach ($taglist as $tag) {
|
foreach ($taglist as $tag) {
|
||||||
$updated = false;
|
|
||||||
|
|
||||||
// make sure members list is up-to-date (UIDs are up-to-date)
|
|
||||||
// @todo: maybe there's a faster way?
|
|
||||||
$this->get_tag_messages($tag);
|
|
||||||
|
|
||||||
$tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
|
$tag['members'] = array_unique(array_merge((array) $tag['members'], $members));
|
||||||
|
|
||||||
// update tag object
|
// update tag object
|
||||||
|
@ -429,91 +423,9 @@ class kolab_tags_engine
|
||||||
*
|
*
|
||||||
* @return array Folder/UID list
|
* @return array Folder/UID list
|
||||||
*/
|
*/
|
||||||
protected function get_tag_messages(&$tag)
|
protected function get_tag_messages(&$tag, $force = true)
|
||||||
{
|
{
|
||||||
$result = array();
|
return kolab_storage_config::resolve_members($tag, $force);
|
||||||
|
|
||||||
foreach ((array) $tag['members'] as $member) {
|
|
||||||
if ($url = $this->parse_member_url($member)) {
|
|
||||||
$folder = $url['folder'];
|
|
||||||
$result[$folder]['uid'][] = $url['uid'];
|
|
||||||
$result[$folder]['params'][] = $url['params'];
|
|
||||||
$result[$folder]['member'][] = $member;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($result)) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
// @TODO: caching?
|
|
||||||
|
|
||||||
$rcube = rcube::get_instance();
|
|
||||||
$storage = $rcube->get_storage();
|
|
||||||
|
|
||||||
foreach ($result as $folder => $data) {
|
|
||||||
// first, we search messages by UID
|
|
||||||
// @FIXME: maybe better use index() which is cached?
|
|
||||||
// @TODO: consider skip_deleted option
|
|
||||||
$index = $storage->search_once($folder, 'UID ' . rcube_imap_generic::compressMessageSet($data['uid']));
|
|
||||||
$uids = $index->get();
|
|
||||||
|
|
||||||
// search by search parameters
|
|
||||||
$not_found = array_diff($data['uid'], $uids);
|
|
||||||
if (!empty($not_found)) {
|
|
||||||
$params = array();
|
|
||||||
$old_members = array();
|
|
||||||
$new_members = array();
|
|
||||||
|
|
||||||
foreach ($not_found as $uid) {
|
|
||||||
$idx = array_search($uid, $data['uid']);
|
|
||||||
|
|
||||||
if ($p = $data['params'][$idx]) {
|
|
||||||
$params[$idx] = $p;
|
|
||||||
}
|
|
||||||
|
|
||||||
$old_members[] = $data['member'][$idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($params)) {
|
|
||||||
// @TODO: do this search in chunks (for e.g. 10 messages)?
|
|
||||||
$search_str = '';
|
|
||||||
|
|
||||||
foreach ($params as $p) {
|
|
||||||
$search = array();
|
|
||||||
foreach ($p as $key => $val) {
|
|
||||||
$search[] = 'HEADER ' . strtoupper($key) . ' ' . rcube_imap_generic::escape($val);
|
|
||||||
}
|
|
||||||
|
|
||||||
$search_str .= ' (' . implode(' ', $search) . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
$search_str = str_repeat(' OR', count($params)-1) . $search_str;
|
|
||||||
|
|
||||||
// @TODO: we should search all folders
|
|
||||||
$index = $storage->search_once($folder, $search_str);
|
|
||||||
$_uids = $index->get();
|
|
||||||
|
|
||||||
if (!empty($_uids)) {
|
|
||||||
$uids = array_merge($uids, $_uids);
|
|
||||||
$msgs = $storage->fetch_headers($folder, $_uids, false);
|
|
||||||
|
|
||||||
$new_members = array_merge($new_members, $this->build_members($folder, $msgs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge members
|
|
||||||
$tag['members'] = array_diff($tag['members'], $old_members);
|
|
||||||
$tag['members'] = array_unique(array_merge($tag['members'], $new_members));
|
|
||||||
|
|
||||||
// update tag object with new members list
|
|
||||||
$this->backend->update($tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
$result[$folder] = array_unique($uids);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -521,26 +433,7 @@ class kolab_tags_engine
|
||||||
*/
|
*/
|
||||||
protected function build_members($folder, $messages)
|
protected function build_members($folder, $messages)
|
||||||
{
|
{
|
||||||
$members = array();
|
return kolab_storage_config::build_members($folder, $messages);
|
||||||
|
|
||||||
foreach ((array) $messages as $msg) {
|
|
||||||
$params = array(
|
|
||||||
'folder' => $folder,
|
|
||||||
'uid' => $msg->uid,
|
|
||||||
);
|
|
||||||
|
|
||||||
// add search parameters
|
|
||||||
// we don't want to build "invalid" searches e.g. that
|
|
||||||
// will return false positives (more or wrong messages)
|
|
||||||
if (($messageid = $msg->get('message-id', false)) && ($date = $msg->get('date', false))) {
|
|
||||||
$params['message-id'] = $messageid;
|
|
||||||
$params['date'] = $date;
|
|
||||||
}
|
|
||||||
|
|
||||||
$members[] = $this->build_member_url($params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,6 +27,7 @@ class kolab_storage_config
|
||||||
{
|
{
|
||||||
const FOLDER_TYPE = 'configuration';
|
const FOLDER_TYPE = 'configuration';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singleton instace of kolab_storage_config
|
* Singleton instace of kolab_storage_config
|
||||||
*
|
*
|
||||||
|
@ -165,9 +166,11 @@ class kolab_storage_config
|
||||||
|
|
||||||
$folder = $this->find_folder($object);
|
$folder = $this->find_folder($object);
|
||||||
|
|
||||||
$object['type'] = $type;
|
if ($type) {
|
||||||
|
$object['type'] = $type;
|
||||||
|
}
|
||||||
|
|
||||||
return $folder->save($object, self::FOLDER_TYPE . '.' . $type, $object['uid']);
|
return $folder->save($object, self::FOLDER_TYPE . '.' . $object['type'], $object['uid']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -199,7 +202,7 @@ class kolab_storage_config
|
||||||
/**
|
/**
|
||||||
* Find folder
|
* Find folder
|
||||||
*/
|
*/
|
||||||
private function find_folder($object = array())
|
public function find_folder($object = array())
|
||||||
{
|
{
|
||||||
// find folder object
|
// find folder object
|
||||||
if ($object['_mailbox']) {
|
if ($object['_mailbox']) {
|
||||||
|
@ -345,4 +348,161 @@ class kolab_storage_config
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build array of member URIs from set of messages
|
||||||
|
*
|
||||||
|
* @param string $folder Folder name
|
||||||
|
* @param array $messages Array of rcube_message objects
|
||||||
|
*
|
||||||
|
* @return array List of members (IMAP URIs)
|
||||||
|
*/
|
||||||
|
public static function build_members($folder, $messages)
|
||||||
|
{
|
||||||
|
$members = array();
|
||||||
|
|
||||||
|
foreach ((array) $messages as $msg) {
|
||||||
|
$params = array(
|
||||||
|
'folder' => $folder,
|
||||||
|
'uid' => $msg->uid,
|
||||||
|
);
|
||||||
|
|
||||||
|
// add search parameters:
|
||||||
|
// we don't want to build "invalid" searches e.g. that
|
||||||
|
// will return false positives (more or wrong messages)
|
||||||
|
if (($messageid = $msg->get('message-id', false)) && ($date = $msg->get('date', false))) {
|
||||||
|
$params['message-id'] = $messageid;
|
||||||
|
$params['date'] = $date;
|
||||||
|
|
||||||
|
if ($subject = $msg->get('subject', false)) {
|
||||||
|
$params['subject'] = substr($subject, 0, 256);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$members[] = self::build_member_url($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $members;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve/validate/update members (which are IMAP URIs) of relation object.
|
||||||
|
*
|
||||||
|
* @param array $tag Tag object
|
||||||
|
* @param bool $force Force members list update
|
||||||
|
*
|
||||||
|
* @return array Folder/UIDs list
|
||||||
|
*/
|
||||||
|
public static function resolve_members(&$tag, $force = true)
|
||||||
|
{
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
foreach ((array) $tag['members'] as $member) {
|
||||||
|
// IMAP URI members
|
||||||
|
if ($url = self::parse_member_url($member)) {
|
||||||
|
$folder = $url['folder'];
|
||||||
|
|
||||||
|
if (!$force) {
|
||||||
|
$result[$folder][] = $url['uid'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$result[$folder]['uid'][] = $url['uid'];
|
||||||
|
$result[$folder]['params'][] = $url['params'];
|
||||||
|
$result[$folder]['member'][] = $member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($result) || !$force) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rcube = rcube::get_instance();
|
||||||
|
$storage = $rcube->get_storage();
|
||||||
|
$search = array();
|
||||||
|
$missing = array();
|
||||||
|
|
||||||
|
// first we search messages by Folder+UID
|
||||||
|
foreach ($result as $folder => $data) {
|
||||||
|
// @FIXME: maybe better use index() which is cached?
|
||||||
|
// @TODO: consider skip_deleted option
|
||||||
|
$index = $storage->search_once($folder, 'UID ' . rcube_imap_generic::compressMessageSet($data['uid']));
|
||||||
|
$uids = $index->get();
|
||||||
|
|
||||||
|
// messages that were not found need to be searched by search parameters
|
||||||
|
$not_found = array_diff($data['uid'], $uids);
|
||||||
|
if (!empty($not_found)) {
|
||||||
|
foreach ($not_found as $uid) {
|
||||||
|
$idx = array_search($uid, $data['uid']);
|
||||||
|
|
||||||
|
if ($p = $data['params'][$idx]) {
|
||||||
|
$search[] = $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
$missing[] = $result[$folder]['member'][$idx];
|
||||||
|
|
||||||
|
unset($result[$folder]['uid'][$idx]);
|
||||||
|
unset($result[$folder]['params'][$idx]);
|
||||||
|
unset($result[$folder]['member'][$idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$folder] = $uids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// search in all subscribed mail folders using search parameters
|
||||||
|
if (!empty($search)) {
|
||||||
|
// remove not found members from the members list
|
||||||
|
$tag['members'] = array_diff($tag['members'], $missing);
|
||||||
|
|
||||||
|
// get subscribed folders
|
||||||
|
$folders = $storage->list_folders_subscribed('', '*', 'mail', null, true);
|
||||||
|
|
||||||
|
// @TODO: do this search in chunks (for e.g. 10 messages)?
|
||||||
|
$search_str = '';
|
||||||
|
|
||||||
|
foreach ($search as $p) {
|
||||||
|
$search_params = array();
|
||||||
|
foreach ($p as $key => $val) {
|
||||||
|
$key = strtoupper($key);
|
||||||
|
// don't search by subject, we don't want false-positives
|
||||||
|
if ($key != 'SUBJECT') {
|
||||||
|
$search_params[] = 'HEADER ' . $key . ' ' . rcube_imap_generic::escape($val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_str .= ' (' . implode(' ', $search_params) . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_str = trim(str_repeat(' OR', count($search)-1) . $search_str);
|
||||||
|
|
||||||
|
// search
|
||||||
|
$search = $storage->search_once($folders, $search_str);
|
||||||
|
|
||||||
|
// handle search result
|
||||||
|
$folders = (array) $search->get_parameters('MAILBOX');
|
||||||
|
|
||||||
|
foreach ($folders as $folder) {
|
||||||
|
$set = $search->get_set($folder);
|
||||||
|
$uids = $set->get();
|
||||||
|
|
||||||
|
if (!empty($uids)) {
|
||||||
|
$msgs = $storage->fetch_headers($folder, $uids, false);
|
||||||
|
$members = self::build_members($folder, $msgs);
|
||||||
|
|
||||||
|
// merge new members into the tag members list
|
||||||
|
$tag['members'] = array_merge($tag['members'], $members);
|
||||||
|
|
||||||
|
// add UIDs into the result
|
||||||
|
$result[$folder] = array_unique(array_merge((array)$result[$folder], $uids));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update tag object with new members list
|
||||||
|
$tag['members'] = array_unique($tag['members']);
|
||||||
|
kolab_storage_config::get_instance()->save($tag, 'relation', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue