plugins/kolab_notes plugins/kolab_tags plugins/libkolab
Aleksander Machniak
machniak at kolabsys.com
Fri Aug 1 10:04:39 CEST 2014
plugins/kolab_notes/kolab_notes.php | 250 ++++++++++++++++++--------
plugins/kolab_notes/notes.js | 4
plugins/kolab_tags/lib/kolab_tags_engine.php | 105 ----------
plugins/libkolab/lib/kolab_storage_config.php | 131 +++++++++++++
4 files changed, 313 insertions(+), 177 deletions(-)
New commits:
commit 79ebe9e2277af9ad29541994bd83dfc9fd7bc2be
Author: Aleksander Machniak <machniak at kolabsys.com>
Date: Fri Aug 1 03:58:09 2014 -0400
Refactored links to email messages using libkolabxml relation objects (#3091)
diff --git a/plugins/kolab_notes/kolab_notes.php b/plugins/kolab_notes/kolab_notes.php
index 4c816a2..6dbfa17 100644
--- a/plugins/kolab_notes/kolab_notes.php
+++ b/plugins/kolab_notes/kolab_notes.php
@@ -488,7 +488,7 @@ class kolab_notes extends rcube_plugin
public function note_record()
{
$data = $this->get_note(array(
- 'uid' => rcube_utils::get_input_value('_id', RCUBE_INPUT_GPC),
+ 'uid' => rcube_utils::get_input_value('_id', RCUBE_INPUT_GPC),
'list' => rcube_utils::get_input_value('_list', RCUBE_INPUT_GPC),
));
@@ -562,12 +562,10 @@ class kolab_notes extends rcube_plugin
}
// resolve message links
- if (is_array($note['links'])) {
- $me = $this;
- $note['links'] = array_map(function($link) use ($me, $resolve){
+ $me = $this;
+ $note['links'] = array_map(function($link) use ($me, $resolve) {
return $me->get_message_reference($link, $resolve) ?: array('uri' => $link);
- }, $note['links']);
- }
+ }, $this->get_links($note['uid']));
return $note;
}
@@ -622,7 +620,7 @@ class kolab_notes extends rcube_plugin
else {
$this->rc->output->show_message('errorsaving', 'error');
}
-
+
// unlock client
$this->rc->output->command('plugin.unlock_saving');
@@ -666,6 +664,11 @@ class kolab_notes extends rcube_plugin
// generate new note object from input
$object = $this->_write_preprocess($note, $old);
+
+ // email links are handled separately
+ $links = $object['links'];
+ unset($object['links']);
+
$saved = $folder->save($object, 'note', $note['uid']);
if (!$saved) {
@@ -677,7 +680,10 @@ class kolab_notes extends rcube_plugin
$saved = false;
}
else {
- $note = $object;
+ // save links in configuration.relation object
+ $this->save_links($object['uid'], $links);
+
+ $note = $object;
$note['list'] = $list_id;
// cache this in memory for later read
@@ -716,10 +722,17 @@ class kolab_notes extends rcube_plugin
$this->_read_lists();
$list_id = $note['list'];
- if (!$list_id || !($folder = $this->get_folder($list_id)))
+ if (!$list_id || !($folder = $this->get_folder($list_id))) {
return false;
+ }
+
+ $status = $folder->delete($note['uid'], $force);
- return $folder->delete($note['uid'], $force);
+ if ($status) {
+ $this->save_links($note['uid'], null);
+ }
+
+ return $status;
}
/**
@@ -873,23 +886,12 @@ class kolab_notes extends rcube_plugin
}
/**
- * Lookup backend storage and find notes tagged with the given message-ID
+ * Lookup backend storage and find notes associated with the given message
*/
public function mail_message_load($p)
{
- $this->message = $p['object'];
- $this->message_notes = array();
-
- // TODO: only query for notes if message was flagged with $KolabNotes ?
-
- $message_id = trim($p['object']->headers->messageID, '<> ');
- if ($message_id && $p['object']->uid) {
- $query = array(array('tags','=','ref:' . $message_id));
- foreach (kolab_storage::select($query, 'note') as $record) {
- $record['list'] = kolab_storage::folder_id($record['_mailbox']);
- $this->message_notes[] = $record;
- }
- }
+ $this->message = $p['object'];
+ $this->message_notes = $this->get_message_notes($this->message->headers, $this->message->folder);
}
/**
@@ -964,76 +966,180 @@ class kolab_notes extends rcube_plugin
return $message->getMessage();
}
+ private function save_links($uid, $links)
+ {
+ $config = kolab_storage_config::get_instance();
+ $search = kolab_storage_config::build_member_url($uid);
+ $relations = $this->get_relations($uid);
+
+ // @TODO: here we support only one-way relations, i.e.
+ // such relation can contain only note and mail members
+ // So, when we remove a note member the whole relation
+ // will be removed
+
+ foreach ($relations as $relation) {
+ if (empty($links)) {
+ $config->delete($relation['uid']);
+ $this->relations = null; // clear in-memory cache
+ }
+ else {
+ // assign all links to one relation, others will be removed
+ $members = array_merge($links, array($search));
+ $diff1 = array_diff($members, $relation['members']);
+ $diff1 = array_diff($relation['members'], $members);
+
+ if (count($diff1) || count($diff2)) {
+ $relation['members'] = $members;
+ $config->save($relation, 'relation');
+ $this->relations = null; // clear in-memory cache
+ }
+
+ $links = null;
+ }
+ }
+
+ // create a new relation
+ if (!empty($links)) {
+ $relation = array(
+ 'members' => array_merge($links, array($search)),
+ 'category' => 'generic',
+ );
+
+ $config->save($relation, 'relation');
+ $this->relations = null; // clear in-memory cache
+ }
+ }
+
/**
- * Build a URI representing the given message reference
+ * Find messages assigned to specified note
*/
- private function get_message_uri($headers, $folder)
+ private function get_links($uid)
{
- return sprintf('imap://%s/%s?message-id=%s&subject=%s',
- $headers->folder ?: $folder,
- $headers->uid,
- urlencode($headers->messageID),
- urlencode($headers->get('subject'))
- );
+ $result = array();
+ $search = kolab_storage_config::build_member_url($uid);
+
+ foreach ($this->get_relations($uid) as $relation) {
+ if (in_array($search, (array) $relation['members'])) {
+ foreach ($relation['members'] as $member) {
+ if ($member != $search) {
+ $result[] = $member;
+ }
+ }
+ }
+ }
+
+ return array_unique($result);
}
/**
- * Extract message reference components from the given URI
+ * Find notes assigned to specified message
*/
- private function parse_message_uri($uri)
+ private function get_message_notes($message, $folder)
{
- $url = parse_url($uri);
- if ($url['scheme'] == 'imap') {
- parse_str($url['query'], $param);
- $linkref = array(
- 'uri' => $uri,
- 'message_id' => $param['message-id'] ?: urldecode($url['fragment']),
- 'subject' => $param['subject'],
- );
+ $result = array();
+ $uids = array();
+
+ // TODO: only query for notes if message was flagged with $KolabNotes ?
+
+ // get UIDs of assigned notes
+ foreach ($this->get_relations() as $relation) {
+ foreach ($relation['members'] as $member) {
+ $member = kolab_storage_config::parse_member_url($member);
+ 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);
+ }
+ }
- $path = explode('/', $url['host'] . $url['path']);
- $linkref['msguid'] = array_pop($path);
- $linkref['folder'] = join('/', $path);
+ continue 2;
+ }
+ }
+ }
- return $linkref;
+ // get Note objects
+ if (!empty($uids)) {
+ $query = array(array('uid', '=', $uids));
+ foreach (kolab_storage::select($query, 'note') as $record) {
+ $record['list'] = kolab_storage::folder_id($record['_mailbox']);
+ $result[] = $record;
+ }
}
- return false;
+ return $result;
}
/**
- * Resolve the email message reference from the given URI
+ * Find relation objects referring to specified note
*/
- public function get_message_reference($uri, $resolve = false)
+ private function get_relations($uid = null)
{
- if ($linkref = $this->parse_message_uri($uri)) {
- // fetch message subject
- if ($resolve || empty($linkref['subject'])) {
- $imap = $this->rc->get_storage();
- if (!($message = $imap->get_message_headers($linrkef['msguid'], $linkref['folder']))) {
- // try to find message using the message_id fragment
- $index = $imap->search_once($imap->list_folders_subscribed('', '*', 'mail', null, true), 'HEADER MESSAGE-ID ' . $linkref['message_id']);
- if ($index->count()) {
- $uid = reset($index->get());
- $folder = $index->get_parameters('MAILBOX');
- if ($message = $imap->get_message_headers($uid, $folder)) {
- // replace metadata
- $linkref['subject'] = $message->get('subject');
- $linkref['msguid'] = $message->uid;
- $linkref['folder'] = $message->folder;
- $linkref['uri'] = $this->get_message_uri($message, $folder);
- }
- }
- }
+ if (!isset($this->relations)) {
+ $config = kolab_storage_config::get_instance();
+ $filter = array(array('type', '=', 'relation'));
+ $default = true;
+ $data_filter = array('category' => 'generic');
+
+ $this->relations = $config->get_objects($filter, $default, $data_filter);
+ }
+
+ if ($uid === null) {
+ return $this->relations;
+ }
+
+ $result = array();
+ $search = kolab_storage_config::build_member_url($uid);
+
+ foreach ($this->relations as $relation) {
+ if (in_array($search, (array) $relation['members'])) {
+ $result[] = $relation;
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Build a URI representing the given message reference
+ */
+ private function get_message_uri($headers, $folder)
+ {
+ $params = array(
+ 'folder' => $headers->folder ?: $folder,
+ 'uid' => $headers->uid,
+ );
+
+ if (($messageid = $headers->get('message-id', false)) && ($date = $headers->get('date', false))) {
+ $params['message-id'] = $messageid;
+ $params['date'] = $date;
+
+ if ($subject = $headers->get('subject')) {
+ $params['subject'] = $subject;
}
+ }
+ return kolab_storage_config::build_member_url($params);
+ }
+
+ /**
+ * Resolve the email message reference from the given URI
+ */
+ public function get_message_reference($uri, $resolve = false)
+ {
+ if ($linkref = kolab_storage_config::parse_member_url($uri)) {
+ $linkref['subject'] = $linkref['params']['subject'];
+ $linkref['uri'] = $uri;
$linkref['mailurl'] = $this->rc->url(array(
- 'task' => 'mail',
+ 'task' => 'mail',
'action' => 'show',
- 'mbox' => $linkref['folder'],
- 'uid' => $linkref['msguid'],
- 'rel' => 'note',
+ 'mbox' => $linkref['folder'],
+ 'uid' => $linkref['uid'],
+ 'rel' => 'note',
));
+
+ unset($linkref['params']);
}
return $linkref;
diff --git a/plugins/kolab_notes/notes.js b/plugins/kolab_notes/notes.js
index 8f59c19..7edded5 100644
--- a/plugins/kolab_notes/notes.js
+++ b/plugins/kolab_notes/notes.js
@@ -811,13 +811,13 @@ function rcube_kolab_notes_ui(settings)
});
if (data.links) {
- $.each(data.links, function(i, link){
+ $.each(data.links, function(i, link) {
var li = $('<li>').addClass('link')
.addClass('message eml')
.append($('<a>')
.attr('href', link.mailurl)
.addClass('messagelink')
- .html(Q(link.subject || link.message_id || link.uri))
+ .text(link.subject || link.uri)
)
.appendTo(attachmentslist);
/*
diff --git a/plugins/kolab_tags/lib/kolab_tags_engine.php b/plugins/kolab_tags/lib/kolab_tags_engine.php
index 684041b..1551726 100644
--- a/plugins/kolab_tags/lib/kolab_tags_engine.php
+++ b/plugins/kolab_tags/lib/kolab_tags_engine.php
@@ -552,57 +552,7 @@ class kolab_tags_engine
*/
protected function parse_member_url($url)
{
- // Look for IMAP URI:
- // imap:///(user/username@domain|shared)/<folder>/<UID>?<search_params>
- if (strpos($url, 'imap:///') === 0) {
- $rcube = rcube::get_instance();
- $storage = $rcube->get_storage();
-
- // parse_url does not work with imap:/// prefix
- $url = parse_url(substr($url, 8));
- $path = explode('/', $url['path']);
- parse_str($url['query'], $params);
-
- $uid = array_pop($path);
- $ns = array_shift($path);
- $path = array_map('rawurldecode', $path);
-
- // resolve folder name
- if ($ns == 'shared') {
- $folder = implode('/', $path);
- // Note: this assumes there's only one shared namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = $prefix . '/' . $folder;
- }
- }
- }
- else if ($ns == 'user') {
- $username = array_shift($path);
- $folder = implode('/', $path);
-
- if ($username != $rcube->get_user_name()) {
- // Note: this assumes there's only one other users namespace root
- if ($ns = $storage->get_namespace('other')) {
- if ($prefix = $ns[0][0]) {
- $folder = $prefix . '/' . $username . '/' . $folder;
- }
- }
- }
- else if (!strlen($folder)) {
- $folder = 'INBOX';
- }
- }
- else {
- return;
- }
-
- return array(
- 'folder' => $folder,
- 'uid' => $uid,
- 'params' => $params,
- );
- }
+ return kolab_storage_config::parse_member_url($url);
}
/**
@@ -614,57 +564,6 @@ class kolab_tags_engine
*/
protected function build_member_url($params)
{
- if (empty($params) || !strlen($params['folder'])) {
- return null;
- }
-
- $rcube = rcube::get_instance();
- $storage = $rcube->get_storage();
-
- // modify folder spec. according to namespace
- $folder = $params['folder'];
- $ns = $storage->folder_namespace($folder);
-
- if ($ns == 'shared') {
- // Note: this assumes there's only one shared namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = 'shared' . substr($folder, strlen($prefix));
- }
- }
- }
- else {
- if ($ns == 'other') {
- // Note: this assumes there's only one other users namespace root
- if ($ns = $storage->get_namespace('shared')) {
- if ($prefix = $ns[0][0]) {
- $folder = 'user' . substr($folder, strlen($prefix));
- }
- }
- }
- else {
- $folder = 'user' . '/' . $rcube->get_user_name() . '/' . $folder;
- }
- }
-
- $folder = implode('/', array_map('rawurlencode', explode('/', $folder)));
-
- // build URI
- $url = 'imap:///' . $folder;
-
- // UID is optional here because sometimes we want
- // to build just a member uri prefix
- if ($params['uid']) {
- $url .= '/' . $params['uid'];
- }
-
- unset($params['folder']);
- unset($params['uid']);
-
- if (!empty($params)) {
- $url .= '?' . http_build_query($params, '', '&');
- }
-
- return $url;
+ return kolab_storage_config::build_member_url($params);
}
}
diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php
index 9dd1116..d253aba 100644
--- a/plugins/libkolab/lib/kolab_storage_config.php
+++ b/plugins/libkolab/lib/kolab_storage_config.php
@@ -183,4 +183,135 @@ class kolab_storage_config
return $folder;
}
+
+ /**
+ * Builds relation member URI
+ *
+ * @param string|array Object UUID or Message folder, UID, Search headers (Message-Id, Date)
+ *
+ * @return string $url Member URI
+ */
+ public static function build_member_url($params)
+ {
+ // param is object UUID
+ if (is_string($params) && !empty($params)) {
+ return 'urn:uuid:' . $params;
+ }
+
+ if (empty($params) || !strlen($params['folder'])) {
+ return null;
+ }
+
+ $rcube = rcube::get_instance();
+ $storage = $rcube->get_storage();
+
+ // modify folder spec. according to namespace
+ $folder = $params['folder'];
+ $ns = $storage->folder_namespace($folder);
+
+ if ($ns == 'shared') {
+ // Note: this assumes there's only one shared namespace root
+ if ($ns = $storage->get_namespace('shared')) {
+ if ($prefix = $ns[0][0]) {
+ $folder = 'shared' . substr($folder, strlen($prefix));
+ }
+ }
+ }
+ else {
+ if ($ns == 'other') {
+ // Note: this assumes there's only one other users namespace root
+ if ($ns = $storage->get_namespace('shared')) {
+ if ($prefix = $ns[0][0]) {
+ $folder = 'user' . substr($folder, strlen($prefix));
+ }
+ }
+ }
+ else {
+ $folder = 'user' . '/' . $rcube->get_user_name() . '/' . $folder;
+ }
+ }
+
+ $folder = implode('/', array_map('rawurlencode', explode('/', $folder)));
+
+ // build URI
+ $url = 'imap:///' . $folder;
+
+ // UID is optional here because sometimes we want
+ // to build just a member uri prefix
+ if ($params['uid']) {
+ $url .= '/' . $params['uid'];
+ }
+
+ unset($params['folder']);
+ unset($params['uid']);
+
+ if (!empty($params)) {
+ $url .= '?' . http_build_query($params, '', '&');
+ }
+
+ return $url;
+ }
+
+ /**
+ * Parses relation member string
+ *
+ * @param string $url Member URI
+ *
+ * @return array Message folder, UID, Search headers (Message-Id, Date)
+ */
+ public static function parse_member_url($url)
+ {
+ // Look for IMAP URI:
+ // imap:///(user/username@domain|shared)/<folder>/<UID>?<search_params>
+ if (strpos($url, 'imap:///') === 0) {
+ $rcube = rcube::get_instance();
+ $storage = $rcube->get_storage();
+
+ // parse_url does not work with imap:/// prefix
+ $url = parse_url(substr($url, 8));
+ $path = explode('/', $url['path']);
+ parse_str($url['query'], $params);
+
+ $uid = array_pop($path);
+ $ns = array_shift($path);
+ $path = array_map('rawurldecode', $path);
+
+ // resolve folder name
+ if ($ns == 'shared') {
+ $folder = implode('/', $path);
+ // Note: this assumes there's only one shared namespace root
+ if ($ns = $storage->get_namespace('shared')) {
+ if ($prefix = $ns[0][0]) {
+ $folder = $prefix . '/' . $folder;
+ }
+ }
+ }
+ else if ($ns == 'user') {
+ $username = array_shift($path);
+ $folder = implode('/', $path);
+
+ if ($username != $rcube->get_user_name()) {
+ // Note: this assumes there's only one other users namespace root
+ if ($ns = $storage->get_namespace('other')) {
+ if ($prefix = $ns[0][0]) {
+ $folder = $prefix . '/' . $username . '/' . $folder;
+ }
+ }
+ }
+ else if (!strlen($folder)) {
+ $folder = 'INBOX';
+ }
+ }
+ else {
+ return;
+ }
+
+ return array(
+ 'folder' => $folder,
+ 'uid' => $uid,
+ 'params' => $params,
+ );
+ }
+ }
+
}
More information about the commits
mailing list