Page MenuHomePhorge

D5032.id14406.diff
No OneTemporary

D5032.id14406.diff

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

Mime Type
text/plain
Expires
Fri, Nov 29, 2:21 AM (21 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10298914
Default Alt Text
D5032.id14406.diff (25 KB)

Event Timeline