Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F16979268
D5032.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
D5032.diff
View Options
diff --git a/plugins/kolab_tags/README b/plugins/kolab_tags/README
new file mode 100644
--- /dev/null
+++ b/plugins/kolab_tags/README
@@ -0,0 +1,69 @@
+A mail tags module for Roundcube
+--------------------------------------
+
+This plugin currently supports a local database or a Kolab groupware
+server as backends for tags storage.
+
+
+REQUIREMENTS
+------------
+
+Some functions are shared with other plugins and therefore being moved to
+library plugins. Thus in order to run the kolab_tags plugin, you also need the
+following plugins installed:
+
+* kolab/libkolab [1]
+
+
+INSTALLATION
+------------
+
+For a manual installation of the plugin (and its dependencies),
+execute the following steps. This will set it up with the database backend
+driver.
+
+1. Get the source from git
+
+ $ cd /tmp
+ $ git clone https://git.kolab.org/diffusion/RPK/roundcubemail-plugins-kolab.git
+ $ cd /<path-to-roundcube>/plugins
+ $ cp -r /tmp/roundcubemail-plugins-kolab/plugins/kolab_tags .
+ $ cp -r /tmp/roundcubemail-plugins-kolab/plugins/libkolab .
+
+2. Create kolab_tags plugin configuration
+
+ $ cd kolab_tags/
+ $ cp config.inc.php.dist config.inc.php
+ $ edit config.inc.php
+
+3. Initialize the plugin database tables
+
+ $ cd ../../
+ $ bin/initdb.sh --dir=plugins/kolab_tags/drivers/database/SQL
+
+4. Build css styles for the Elastic skin (if needed)
+
+ $ lessc --relative-urls -x plugins/libkolab/skins/elastic/libkolab.less > plugins/libkolab/skins/elastic/libkolab.min.css
+
+5. Enable the plugin
+
+ $ edit config/config.inc.php
+
+Add 'kolab_tags' to the list of active plugins:
+
+ $config['plugins'] = [
+ (...)
+ 'kolab_tags',
+ ];
+
+
+IMPORTANT
+---------
+
+This plugin doesn't work with the Classic skin of Roundcube because no
+templates are available for that skin.
+
+Use Roundcube `skins_allowed` option to limit skins available to the user
+or remove incompatible skins from the skins folder.
+
+[1] https://git.kolab.org/diffusion/RPK/
diff --git a/plugins/kolab_tags/composer.json b/plugins/kolab_tags/composer.json
--- a/plugins/kolab_tags/composer.json
+++ b/plugins/kolab_tags/composer.json
@@ -4,7 +4,7 @@
"description": "Email tags plugin",
"homepage": "https://git.kolab.org/diffusion/RPK/",
"license": "AGPLv3",
- "version": "3.5.2",
+ "version": "3.5.3",
"authors": [
{
"name": "Aleksander Machniak",
diff --git a/plugins/kolab_tags/config.inc.php.dist b/plugins/kolab_tags/config.inc.php.dist
new file mode 100644
--- /dev/null
+++ b/plugins/kolab_tags/config.inc.php.dist
@@ -0,0 +1,4 @@
+<?php
+
+// Storage backend type (database, kolab)
+$config['kolab_tags_driver'] = 'kolab';
diff --git a/plugins/kolab_tags/drivers/DriverInterface.php b/plugins/kolab_tags/drivers/DriverInterface.php
new file mode 100644
--- /dev/null
+++ b/plugins/kolab_tags/drivers/DriverInterface.php
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * Kolab Tags backend driver interface
+ *
+ * @author Aleksander Machniak <machniak@kolabsys.com>
+ *
+ * Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace KolabTags\Drivers;
+
+interface DriverInterface
+{
+ /**
+ * Tags list
+ *
+ * @param array $filter Search filter
+ *
+ * @return array List of tags
+ */
+ public function list_tags($filter = []);
+
+ /**
+ * Create tag object
+ *
+ * @param array $tag Tag data
+ *
+ * @return false|array Tag data on success, False on failure
+ */
+ public function create($tag);
+
+ /**
+ * Update tag object
+ *
+ * @param array $tag Tag data
+ *
+ * @return false|array Tag data on success, False on failure
+ */
+ public function update($tag);
+
+ /**
+ * Remove tag object
+ *
+ * @param string $uid Object unique identifier
+ *
+ * @return bool True on success, False on failure
+ */
+ public function remove($uid);
+
+ /**
+ * Resolve members to folder/UID
+ *
+ * @param array $tag Tag object
+ * @param bool $force Force members list update
+ *
+ * @return array Folder/UID list
+ */
+ public function get_tag_messages(&$tag, $force = true);
+}
diff --git a/plugins/kolab_tags/drivers/database/Driver.php b/plugins/kolab_tags/drivers/database/Driver.php
new file mode 100644
--- /dev/null
+++ b/plugins/kolab_tags/drivers/database/Driver.php
@@ -0,0 +1,254 @@
+<?php
+
+/**
+ * Kolab Tags backend driver for SQL database.
+ *
+ * @author Aleksander Machniak <machniak@apheleia-it.ch>
+ *
+ * Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+namespace KolabTags\Drivers\Database;
+
+use KolabTags\Drivers\DriverInterface;
+use kolab_storage_cache;
+use kolab_storage_config;
+use rcube;
+
+class Driver implements DriverInterface
+{
+ private $members_table = 'kolab_tag_members';
+ private $tags_table = 'kolab_tags';
+ private $tag_cols = ['name', 'color'];
+
+
+ /**
+ * Tags list
+ *
+ * @param array $filter Search filter
+ *
+ * @return array List of tags
+ */
+ public function list_tags($filter = [])
+ {
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+ $user_id = $rcube->get_user_id();
+
+ // Parse filter, convert 'uid' into 'id'
+ foreach ($filter as $idx => $record) {
+ if ($record[0] == 'uid') {
+ $filter[$idx][0] = 'id';
+ }
+ }
+
+ // TODO: Support 'members' filter
+
+ $where = kolab_storage_cache::sql_where($filter);
+
+ $query = $db->query("SELECT * FROM `{$this->tags_table}` WHERE `user_id` = {$user_id}" . $where);
+
+ $result = [];
+ while ($tag = $db->fetch_assoc($query)) {
+ $tag['uid'] = $tag['id']; // the API expects 'uid' property
+ $tag['members'] = [];
+ unset($tag['id']);
+ $result[$tag['uid']] = $tag;
+ }
+
+ // Get the tag's members
+ if (!empty($result)) {
+ $ids = $db->array2list(array_keys($result), 'int');
+ $query = $db->query("SELECT `tag_id`, `url` FROM `{$this->members_table}` WHERE `tag_id` IN ({$ids})");
+
+ while ($member = $db->fetch_assoc($query)) {
+ $result[$member['tag_id']]['members'][] = $member['url'];
+ }
+ }
+
+ return array_values($result);
+ }
+
+ /**
+ * Create tag object
+ *
+ * @param array $tag Tag data
+ *
+ * @return false|array Tag data on success, False on failure
+ */
+ public function create($tag)
+ {
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+ $user_id = $rcube->get_user_id();
+ $insert = [];
+
+ foreach ($this->tag_cols as $col) {
+ if (isset($tag[$col])) {
+ $insert[$db->quoteIdentifier($col)] = $db->quote($tag[$col]);
+ }
+ }
+
+ if (empty($insert)) {
+ return false;
+ }
+
+ $now = new \DateTime('now', new \DateTimeZone('UTC'));
+
+ $insert['user_id'] = $user_id;
+ $insert['created'] = $insert['updated'] = $now->format("'Y-m-d H:i:s'");
+
+ $result = $db->query("INSERT INTO `{$this->tags_table}`"
+ . " (" . implode(', ', array_keys($insert)) . ")"
+ . " VALUES(" . implode(', ', array_values($insert)) . ")"
+ );
+
+ $tag['uid'] = $db->insert_id($this->tags_table);
+
+ if (empty($tag['uid'])) {
+ return false;
+ }
+
+ $this->save_members($tag, false);
+
+ return $tag;
+ }
+
+ /**
+ * Update tag object
+ *
+ * @param array $tag Tag data
+ *
+ * @return false|array Tag data on success, False on failure
+ */
+ public function update($tag)
+ {
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+ $user_id = $rcube->get_user_id();
+ $update = [];
+
+ foreach ($this->tag_cols as $col) {
+ if (isset($tag[$col])) {
+ $update[] = $db->quoteIdentifier($col) . ' = ' . $db->quote($tag[$col]);
+ }
+ }
+
+ if (!empty($update)) {
+ $now = new \DateTime('now', new \DateTimeZone('UTC'));
+ $update[] = '`updated` = ' . $db->quote($now->format('Y-m-d H:i:s'));
+
+ $result = $db->query("UPDATE `{$this->tags_table}` SET " . implode(', ', $update)
+ . " WHERE `id` = ? AND `user_id` = ?", $tag['uid'], $user_id);
+
+ if ($result === false) {
+ return false;
+ }
+ }
+
+ // Update members
+ $this->save_members($tag);
+
+ return $tag;
+ }
+
+ /**
+ * Remove tag object
+ *
+ * @param string $uid Object unique identifier
+ *
+ * @return bool True on success, False on failure
+ */
+ public function remove($uid)
+ {
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+ $user_id = $rcube->get_user_id();
+
+ $result = $db->query("DELETE FROM `{$this->tags_table}` WHERE `id` = ? AND `user_id` = ?", $uid, $user_id);
+
+ return $db->affected_rows($result) > 0;
+ }
+
+ /**
+ * Resolve members to folder/UID
+ *
+ * @param array $tag Tag object
+ * @param bool $force Force members list update
+ *
+ * @return array Folder/UID list
+ */
+ public function get_tag_messages(&$tag, $force = true)
+ {
+ $result = kolab_storage_config::resolve_members($tag, $force, false);
+
+ if ($force) {
+ // Update tag members
+ $this->save_members($tag);
+ }
+
+ return $result;
+ }
+
+ protected function save_members($tag, $update = true)
+ {
+ if (empty($tag['uid']) || !isset($tag['members'])) {
+ return;
+ }
+
+ $rcube = rcube::get_instance();
+ $db = $rcube->get_dbh();
+ $existing = [];
+
+ if ($update) {
+ $query = $db->query("SELECT `url` FROM `{$this->members_table}` WHERE `tag_id` = ?", $tag['uid']);
+
+ while ($member = $db->fetch_assoc($query)) {
+ $existing[] = $member['url'];
+ }
+ }
+
+ if (!empty($existing)) {
+ $insert = array_diff($tag['members'], $existing);
+ $delete = array_diff($existing, $tag['members']);
+ } else {
+ $insert = $tag['members'];
+ $delete = [];
+ }
+
+ if (!empty($delete)) {
+ foreach (array_chunk($delete, 100) as $chunk) {
+ $query = $db->query("DELETE FROM `{$this->members_table}` WHERE `tag_id` = ?"
+ . " AND `url` IN (" . $db->array2list($chunk) . ")",
+ $tag['uid']
+ );
+ }
+ }
+
+ if (!empty($insert)) {
+ $ts = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d H:i:s');
+
+ foreach (array_chunk($insert, 100) as $chunk) {
+ $query = "INSERT INTO `{$this->members_table}` (`tag_id`, `url`, `created`) VALUES ";
+ foreach ($chunk as $idx => $url) {
+ $chunk[$idx] = sprintf("(%d, %s, %s)", $tag['uid'], $db->quote($url), $db->quote($ts));
+ }
+
+ $query = $db->query($query . implode(', ', $chunk));
+ }
+ }
+ }
+}
diff --git a/plugins/kolab_tags/drivers/database/SQL/mysql.initial.sql b/plugins/kolab_tags/drivers/database/SQL/mysql.initial.sql
new file mode 100644
--- /dev/null
+++ b/plugins/kolab_tags/drivers/database/SQL/mysql.initial.sql
@@ -0,0 +1,26 @@
+
+CREATE TABLE IF NOT EXISTS `kolab_tags` (
+ `id` int UNSIGNED NOT NULL AUTO_INCREMENT,
+ `user_id` int(10) UNSIGNED NOT NULL,
+ `name` varchar(255) NOT NULL,
+ `color` varchar(8) DEFAULT NULL,
+ `created` datetime DEFAULT NULL,
+ `updated` datetime DEFAULT NULL,
+ PRIMARY KEY(`id`),
+ UNIQUE KEY `user_id_name_idx` (`user_id`, `name`),
+ INDEX (`updated`),
+ CONSTRAINT `fk_kolab_tags_user_id` FOREIGN KEY (`user_id`)
+ REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ROW_FORMAT=DYNAMIC ENGINE=INNODB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+
+CREATE TABLE IF NOT EXISTS `kolab_tag_members` (
+ `tag_id` int UNSIGNED NOT NULL,
+ `url` varchar(2048) BINARY NOT NULL,
+ `created` datetime DEFAULT NULL,
+ PRIMARY KEY(`tag_id`, `url`),
+ INDEX (`created`),
+ CONSTRAINT `fk_kolab_tag_members_tag_id` FOREIGN KEY (`tag_id`)
+ REFERENCES `kolab_tags`(`id`) ON DELETE CASCADE ON UPDATE CASCADE
+) ROW_FORMAT=DYNAMIC ENGINE=INNODB CHARACTER SET ascii;
+
+REPLACE INTO `system` (`name`, `value`) VALUES ('kolab-tags-database-version', '2024112000');
diff --git a/plugins/kolab_tags/lib/kolab_tags_backend.php b/plugins/kolab_tags/drivers/kolab/Driver.php
rename from plugins/kolab_tags/lib/kolab_tags_backend.php
rename to plugins/kolab_tags/drivers/kolab/Driver.php
--- a/plugins/kolab_tags/lib/kolab_tags_backend.php
+++ b/plugins/kolab_tags/drivers/kolab/Driver.php
@@ -1,11 +1,11 @@
<?php
/**
- * Kolab Tags backend
+ * Kolab Tags backend driver for Kolab v3
*
- * @author Aleksander Machniak <machniak@kolabsys.com>
+ * @author Aleksander Machniak <machniak@apheleia-it.ch>
*
- * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
+ * Copyright (C) 2024, Apheleia IT AG <contact@apheleia-it.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -21,7 +21,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-class kolab_tags_backend
+namespace KolabTags\Drivers\Kolab;
+
+use KolabTags\Drivers\DriverInterface;
+use kolab_storage_config;
+
+class Driver implements DriverInterface
{
private $tag_cols = ['name', 'category', 'color', 'parent', 'iconName', 'priority', 'members'];
@@ -53,7 +58,7 @@
*
* @param array $tag Tag data
*
- * @return boolean|array Tag data on success, False on failure
+ * @return false|array Tag data on success, False on failure
*/
public function create($tag)
{
@@ -72,7 +77,7 @@
*
* @param array $tag Tag data
*
- * @return boolean|array Tag data on success, False on failure
+ * @return false|array Tag data on success, False on failure
*/
public function update($tag)
{
@@ -99,7 +104,7 @@
*
* @param string $uid Object unique identifier
*
- * @return boolean True on success, False on failure
+ * @return bool True on success, False on failure
*/
public function remove($uid)
{
@@ -107,4 +112,17 @@
return $config->delete($uid);
}
+
+ /**
+ * Resolve members to folder/UID
+ *
+ * @param array $tag Tag object
+ * @param bool $force Force members list update
+ *
+ * @return array Folder/UID list
+ */
+ public function get_tag_messages(&$tag, $force = true)
+ {
+ return kolab_storage_config::resolve_members($tag, $force);
+ }
}
diff --git a/plugins/kolab_tags/kolab_tags.js b/plugins/kolab_tags/kolab_tags.js
--- a/plugins/kolab_tags/kolab_tags.js
+++ b/plugins/kolab_tags/kolab_tags.js
@@ -776,7 +776,6 @@
{
var selection = list.get_selection(),
has_tags = selection.length && rcmail.env.tags.length;
-
if (has_tags && !rcmail.select_all_mode) {
has_tags = false;
$.each(selection, function() {
diff --git a/plugins/kolab_tags/kolab_tags.php b/plugins/kolab_tags/kolab_tags.php
--- a/plugins/kolab_tags/kolab_tags.php
+++ b/plugins/kolab_tags/kolab_tags.php
@@ -57,12 +57,12 @@
private function engine()
{
if ($this->engine === null) {
- // the files module can be enabled/disabled by the kolab_auth plugin
+ // the plugin can be enabled/disabled by the kolab_auth plugin
if ($this->rc->config->get('kolab_tags_disabled') || !$this->rc->config->get('kolab_tags_enabled', true)) {
return $this->engine = false;
}
- // $this->load_config();
+ $this->load_config();
require_once $this->home . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'kolab_tags_engine.php';
diff --git a/plugins/kolab_tags/lib/kolab_tags_engine.php b/plugins/kolab_tags/lib/kolab_tags_engine.php
--- a/plugins/kolab_tags/lib/kolab_tags_engine.php
+++ b/plugins/kolab_tags/lib/kolab_tags_engine.php
@@ -35,11 +35,16 @@
{
$plugin->require_plugin('libkolab');
- require_once $plugin->home . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'kolab_tags_backend.php';
-
- $this->backend = new kolab_tags_backend();
$this->plugin = $plugin;
$this->rc = $plugin->rc;
+
+ $driver = $this->rc->config->get('kolab_tags_driver') ?: 'database';
+ $class = "\\KolabTags\\Drivers\\" . ucfirst($driver) . "\\Driver";
+
+ require_once "{$plugin->home}/drivers/DriverInterface.php";
+ require_once "{$plugin->home}/drivers/{$driver}/Driver.php";
+
+ $this->backend = new $class();
}
/**
@@ -497,24 +502,12 @@
];
if ($list) {
- $result['uids'] = $this->get_tag_messages($tag, $force);
+ $result['uids'] = $this->backend->get_tag_messages($tag, $force);
}
return $result;
}
- /**
- * Resolve members to folder/UID
- *
- * @param array $tag Tag object
- *
- * @return array Folder/UID list
- */
- protected function get_tag_messages(&$tag, $force = true)
- {
- return kolab_storage_config::resolve_members($tag, $force);
- }
-
/**
* Build array of member URIs from set of messages
*/
diff --git a/plugins/kolab_tags/skins/elastic/templates/ui.html b/plugins/kolab_tags/skins/elastic/templates/ui.html
--- a/plugins/kolab_tags/skins/elastic/templates/ui.html
+++ b/plugins/kolab_tags/skins/elastic/templates/ui.html
@@ -17,8 +17,8 @@
<div id="tagmessagemenu" class="popupmenu" aria-hidden="true">
<ul class="menu iconized">
<li class="separator"><label><roundcube:label name="kolab_tags.tags" /></label></li>
- <roundcube:button type="link-menuitem" command="tag-add" label="kolab_tags.tagadd" classAct="tag add active" class="tag add disabled" />
- <roundcube:button type="link-menuitem" command="tag-remove" label="kolab_tags.tagremove" classAct="tag remove active" class="tag remove disabled" />
+ <roundcube:button type="link-menuitem" command="tag-add" label="kolab_tags.tagadd" classAct="tag add active" class="tag add disabled" innerclass="inner" aria-haspopup="true" />
+ <roundcube:button type="link-menuitem" command="tag-remove" label="kolab_tags.tagremove" classAct="tag remove active" class="tag remove disabled" innerclass="inner" aria-haspopup="true" />
<roundcube:button type="link-menuitem" command="tag-remove-all" label="kolab_tags.tagremoveall" classAct="tag remove all active" class="tag remove all disabled" />
</ul>
</div>
diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -777,7 +777,7 @@
$sql_query = "SELECT " . ($fetchall ? '*' : "`msguid` AS `_msguid`, `uid`")
. " FROM `{$this->cache_table}` WHERE `folder_id` = ?"
- . $this->_sql_where($query)
+ . self::sql_where($query)
. (!empty($this->order_by) ? " ORDER BY " . $this->order_by : '');
$sql_result = $this->limit ?
@@ -866,7 +866,7 @@
$sql_result = $this->db->query(
"SELECT COUNT(*) AS `numrows` FROM `{$this->cache_table}` " .
- "WHERE `folder_id` = ?" . $this->_sql_where($query),
+ "WHERE `folder_id` = ?" . self::sql_where($query),
$this->folder_id
);
@@ -946,40 +946,42 @@
/**
* Helper method to compose a valid SQL query from pseudo filter triplets
*/
- protected function _sql_where($query)
+ public static function sql_where($query)
{
+ $db = rcube::get_instance()->get_dbh();
$sql_where = '';
+
foreach ((array) $query as $param) {
if (is_array($param[0])) {
$subq = [];
foreach ($param[0] as $q) {
- $subq[] = preg_replace('/^\s*AND\s+/i', '', $this->_sql_where([$q]));
+ $subq[] = preg_replace('/^\s*AND\s+/i', '', self::sql_where([$q]));
}
if (!empty($subq)) {
$sql_where .= ' AND (' . implode($param[1] == 'OR' ? ' OR ' : ' AND ', $subq) . ')';
}
continue;
} elseif ($param[1] == '=' && is_array($param[2])) {
- $qvalue = '(' . implode(',', array_map([$this->db, 'quote'], $param[2])) . ')';
+ $qvalue = '(' . implode(',', array_map([$db, 'quote'], $param[2])) . ')';
$param[1] = 'IN';
} elseif ($param[1] == '~' || $param[1] == 'LIKE' || $param[1] == '!~' || $param[1] == '!LIKE') {
$not = ($param[1] == '!~' || $param[1] == '!LIKE') ? 'NOT ' : '';
$param[1] = $not . 'LIKE';
- $qvalue = $this->db->quote('%' . preg_replace('/(^\^|\$$)/', ' ', $param[2]) . '%');
+ $qvalue = $db->quote('%' . preg_replace('/(^\^|\$$)/', ' ', $param[2]) . '%');
} elseif ($param[1] == '~*' || $param[1] == '!~*') {
$not = $param[1][1] == '!' ? 'NOT ' : '';
$param[1] = $not . 'LIKE';
- $qvalue = $this->db->quote(preg_replace('/(^\^|\$$)/', ' ', $param[2]) . '%');
+ $qvalue = $db->quote(preg_replace('/(^\^|\$$)/', ' ', $param[2]) . '%');
} elseif ($param[0] == 'tags') {
$param[1] = ($param[1] == '!=' ? 'NOT ' : '') . 'LIKE';
- $qvalue = $this->db->quote('% ' . $param[2] . ' %');
+ $qvalue = $db->quote('% ' . $param[2] . ' %');
} else {
- $qvalue = $this->db->quote($param[2]);
+ $qvalue = $db->quote($param[2]);
}
$sql_where .= sprintf(
' AND %s %s %s',
- $this->db->quote_identifier($param[0]),
+ $db->quote_identifier($param[0]),
$param[1],
$qvalue
);
diff --git a/plugins/libkolab/lib/kolab_storage_cache_configuration.php b/plugins/libkolab/lib/kolab_storage_cache_configuration.php
--- a/plugins/libkolab/lib/kolab_storage_cache_configuration.php
+++ b/plugins/libkolab/lib/kolab_storage_cache_configuration.php
@@ -80,7 +80,7 @@
/**
* Helper method to compose a valid SQL query from pseudo filter triplets
*/
- protected function _sql_where($query)
+ public static function sql_where($query)
{
if (is_array($query)) {
foreach ($query as $idx => $param) {
@@ -100,7 +100,7 @@
}
}
- return parent::_sql_where($query);
+ return parent::sql_where($query);
}
/**
diff --git a/plugins/libkolab/lib/kolab_storage_config.php b/plugins/libkolab/lib/kolab_storage_config.php
--- a/plugins/libkolab/lib/kolab_storage_config.php
+++ b/plugins/libkolab/lib/kolab_storage_config.php
@@ -448,7 +448,7 @@
*
* @return array Folder/UIDs list
*/
- public static function resolve_members(&$tag, $force = true)
+ public static function resolve_members(&$tag, $force = true, $update = true)
{
$result = [];
@@ -558,7 +558,9 @@
// update tag object with new members list
$tag['members'] = array_unique($tag['members']);
- kolab_storage_config::get_instance()->save($tag, 'relation');
+ if ($update) {
+ kolab_storage_config::get_instance()->save($tag, 'relation');
+ }
}
return $result;
diff --git a/plugins/libkolab/lib/kolab_storage_dav_cache.php b/plugins/libkolab/lib/kolab_storage_dav_cache.php
--- a/plugins/libkolab/lib/kolab_storage_dav_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_dav_cache.php
@@ -413,7 +413,7 @@
$sql_query = "SELECT " . ($uids ? "`uid`" : '*')
. " FROM `{$this->cache_table}` WHERE `folder_id` = ?"
- . $this->_sql_where($query)
+ . self::sql_where($query)
. (!empty($this->order_by) ? " ORDER BY " . $this->order_by : '');
$sql_result = $this->limit ?
@@ -454,7 +454,7 @@
$sql_result = $this->db->query(
"SELECT COUNT(*) AS `numrows` FROM `{$this->cache_table}` " .
- "WHERE `folder_id` = ?" . $this->_sql_where($query),
+ "WHERE `folder_id` = ?" . self::sql_where($query),
$this->folder_id
);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Nov 29, 12:28 AM (20 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10298914
Default Alt Text
D5032.diff (25 KB)
Attached To
Mode
D5032: Kolab Tags SQL Database Driver
Attached
Detach File
Event Timeline
Log In to Comment