From ffe04182a86a326861763a5e6afa3577c52e07a5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 17 Sep 2012 16:01:25 +0200 Subject: [PATCH 01/48] Added methods OC_DB::insertIfNotExist() and OCP\DB::insertIfNotExist(). --- lib/db.php | 49 +++++++++++++++++++++++++++++++++++++++++++++++ lib/public/db.php | 21 ++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/lib/db.php b/lib/db.php index 4d8e5a1a86..8598f659ca 100644 --- a/lib/db.php +++ b/lib/db.php @@ -512,6 +512,55 @@ class OC_DB { return true; } + /** + * @brief Insert a row if a matching row doesn't exists. + * @returns true/false + * + */ + public static function insertIfNotExist($table, $input) { + self::connect(); + $prefix = OC_Config::getValue( "dbtableprefix", "oc_" ); + $table = str_replace( '*PREFIX*', $prefix, $table ); + + if(is_null(self::$type)) { + self::$type=OC_Config::getValue( "dbtype", "sqlite" ); + } + $type = self::$type; + + $query = ''; + // differences in escaping of table names ('`' for mysql) and getting the current timestamp + if( $type == 'sqlite' || $type == 'sqlite3' ) { + $query = 'REPLACE OR INSERT INTO "' . $table . '" ("' + . implode('","', array_keys($input)) . '") VALUES("' + . implode('","', array_values($input)) . '")'; + } elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql') { + $query = 'INSERT INTO `' .$table . '` (' + . implode(',', array_keys($input)) . ') SELECT \'' + . implode('\',\'', array_values($input)) . '\' FROM ' . $table . ' WHERE '; + + foreach($input as $key => $value) { + $query .= $key . " = '" . $value . '\' AND '; + } + $query = substr($query, 0, strlen($query) - 5); + $query .= ' HAVING COUNT(*) = 0'; + } + // TODO: oci should be use " (quote) instead of ` (backtick). + //OC_Log::write('core', __METHOD__ . ', type: ' . $type . ', query: ' . $query, OC_Log::DEBUG); + + try { + $result=self::$connection->prepare($query); + } catch(PDOException $e) { + $entry = 'DB Error: "'.$e->getMessage().'"
'; + $entry .= 'Offending command was: '.$query.'
'; + OC_Log::write('core', $entry,OC_Log::FATAL); + error_log('DB error: '.$entry); + die( $entry ); + } + + $result = new PDOStatementWrapper($result); + $result->execute(); + } + /** * @brief does minor chages to query * @param $query Query string diff --git a/lib/public/db.php b/lib/public/db.php index 6ce62b27ca..b9e56985e9 100644 --- a/lib/public/db.php +++ b/lib/public/db.php @@ -45,6 +45,27 @@ class DB { return(\OC_DB::prepare($query,$limit,$offset)); } + /** + * @brief Insert a row if a matching row doesn't exists. + * @param $table string The table name (will replace *PREFIX*) to perform the replace on. + * @param $input array + * + * The input array if in the form: + * + * array ( 'id' => array ( 'value' => 6, + * 'key' => true + * ), + * 'name' => array ('value' => 'Stoyan'), + * 'family' => array ('value' => 'Stefanov'), + * 'birth_date' => array ('value' => '1975-06-20') + * ); + * @returns true/false + * + */ + public static function insertIfNotExist($table, $input) { + return(\OC_DB::insertIfNotExist($table, $input)); + } + /** * @brief gets last value of autoincrement * @param $table string The optional table name (will replace *PREFIX*) and add sequence suffix From b1a6acde30232367f4e8d66372fedfd1065c5d5a Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 17 Sep 2012 16:03:15 +0200 Subject: [PATCH 02/48] Added separate table for OC_VCategories and category/object (event/contact etc.) relations. --- db_structure.xml | 138 ++++++++++++++++++ lib/vcategories.php | 339 ++++++++++++++++++++++++++++++++++++++------ 2 files changed, 430 insertions(+), 47 deletions(-) diff --git a/db_structure.xml b/db_structure.xml index 2256dff943..5576db1ab8 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -661,4 +661,142 @@ + + + *dbprefix*vcategory + + + + + id + integer + 0 + true + 1 + true + 4 + + + + uid + text + + true + 64 + + + + type + text + + true + 64 + + + + category + text + + true + 255 + + + + uid_index + + uid + ascending + + + + + type_index + + type + ascending + + + + + category_index + + category + ascending + + + + + uid_type_category_index + true + + uid + ascending + + + type + ascending + + + category + ascending + + + + +
+ + + + *dbprefix*vcategory_to_object + + + + + objid + integer + 0 + true + true + 4 + + + + categoryid + integer + 0 + true + true + 4 + + + + type + text + + true + 64 + + + + true + true + category_object_index + + categoryid + ascending + + + objid + ascending + + + type + ascending + + + + + +
+ diff --git a/lib/vcategories.php b/lib/vcategories.php index 6b1d6a316f..08faa0d903 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -28,52 +28,187 @@ * anything else that is either parsed from a vobject or that the user chooses * to add. * Category names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a category 'family' for an app, and + * are entered in. If a user already has a category 'family' for a type, and * tries to add a category named 'Family' it will be silently ignored. - * NOTE: There is a limitation in that the the configvalue field in the - * preferences table is a varchar(255). */ class OC_VCategories { - const PREF_CATEGORIES_LABEL = 'extra_categories'; + /** * Categories */ private $categories = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + */ + private static $relations = array(); - private $app = null; + private $type = null; private $user = null; + private static $category_table = '*PREFIX*vcategory'; + private static $relation_table = '*PREFIX*vcategory_to_object'; + + const FORMAT_LIST = 0; + const FORMAT_MAP = 1; /** * @brief Constructor. - * @param $app The application identifier e.g. 'contacts' or 'calendar'. + * @param $type The type identifier e.g. 'contact' or 'event'. * @param $user The user whos data the object will operate on. This * parameter should normally be omitted but to make an app able to * update categories for all users it is made possible to provide it. * @param $defcategories An array of default categories to be used if none is stored. */ - public function __construct($app, $user=null, $defcategories=array()) { - $this->app = $app; + public function __construct($type, $user=null, $defcategories=array()) { + $this->type = $type; $this->user = is_null($user) ? OC_User::getUser() : $user; - $categories = trim(OC_Preferences::getValue($this->user, $app, self::PREF_CATEGORIES_LABEL, '')); - if ($categories) { - $categories = @unserialize($categories); + + $this->loadCategories(); + OCP\Util::writeLog('core', __METHOD__ . ', categories: ' + . print_r($this->categories, true), + OCP\Util::DEBUG + ); + + if($defcategories && count($this->categories) === 0) { + $this->add($defcategories, true); } - $this->categories = is_array($categories) ? $categories : $defcategories; } + /** + * @brief Load categories from db. + */ + private function loadCategories() { + $this->categories = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + // The keys are prefixed because array_search wouldn't work otherwise :-/ + $this->categories[$row['id']] = $row['category']; + } + } + } + + + /** + * @brief Check if any categories are saved for this type and user. + * @returns boolean. + * @param $type The type identifier e.g. 'contact' or 'event'. + * @param $user The user whos categories will be checked. If not set current user will be used. + */ + public static function isEmpty($type, $user = null) { + $user = is_null($user) ? OC_User::getUser() : $user; + $sql = 'SELECT COUNT(*) FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($user, $type)); + return ($result->numRows() == 0); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + return false; + } + } + /** * @brief Get the categories for a specific user. + * @param * @returns array containing the categories as strings. */ - public function categories() { - //OC_Log::write('core','OC_VCategories::categories: '.print_r($this->categories, true), OC_Log::DEBUG); + public function categories($format = null) { if(!$this->categories) { return array(); } - usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys - return $this->categories; + $categories = array_values($this->categories); + uasort($categories, 'strnatcasecmp'); + if($format == self::FORMAT_MAP) { + $catmap = array(); + foreach($categories as $category) { + $catmap[] = array( + 'id' => $this->array_searchi($category, $this->categories), + 'name' => $category + ); + } + return $catmap; + } + return $categories; } + /** + * @brief Get the a list if items belonging to $category. + * @param string|integer $category Category id or name. + * @param string $table The name of table to query. + * @param int $limit + * @param int $offset + * + * This generic method queries a table assuming that the id + * field is called 'id' and the table name provided is in + * the form '*PREFIX*table_name'. + * + * If the category name cannot be resolved an exception is thrown. + * + * TODO: Maybe add the getting permissions for objects? + * + * @returns array containing the resulting items. + */ + public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { + $result = null; + if(is_numeric($category)) { + $catid = $category; + } elseif(is_string($category)) { + $catid = $this->array_searchi($category, $this->categories); + } + OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); + if($catid === false) { + $l10n = OC_L10N::get('core'); + throw new Exception( + $l10n->t( + 'Could not find category "%s"', $category + ) + ); + } + $fields = ''; + foreach($tableinfo['fields'] as $field) { + $fields .= '`' . $tableinfo['tablename'] . '`.`' . $field . '`,'; + } + $fields = substr($fields, 0, -1); + + $items = array(); + $sql = 'SELECT `' . self::$relation_table . '`.`categoryid`, ' . $fields + . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' + . self::$relation_table . '` ON `' . $tableinfo['tablename'] + . '`.`id` = `' . self::$relation_table . '`.`objid` WHERE `' + . self::$relation_table . '`.`categoryid` = ?'; + + try { + $stmt = OCP\DB::prepare($sql, $limit, $offset); + $result = $stmt->execute(array($catid)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $items[] = $row; + } + } + //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); + //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); + + return $items; + } + /** * @brief Checks whether a category is already saved. * @param $name The name to check for. @@ -90,16 +225,21 @@ class OC_VCategories { * @param $sync bool When true, save the categories * @returns bool Returns false on error. */ - public function add($names, $sync=false) { + public function add($names, $sync=false, $id = null) { if(!is_array($names)) { $names = array($names); } $names = array_map('trim', $names); $newones = array(); foreach($names as $name) { - if(($this->in_arrayi($name, $this->categories) == false) && $name != '') { + if(($this->in_arrayi( + $name, $this->categories) == false) && $name != '') { $newones[] = $name; } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'category' => $name); + } } if(count($newones) > 0) { $this->categories = array_merge($this->categories, $newones); @@ -114,8 +254,8 @@ class OC_VCategories { * @brief Extracts categories from a vobject and add the ones not already present. * @param $vobject The instance of OC_VObject to load the categories from. */ - public function loadFromVObject($vobject, $sync=false) { - $this->add($vobject->getAsArray('CATEGORIES'), $sync); + public function loadFromVObject($id, $vobject, $sync=false) { + $this->add($vobject->getAsArray('CATEGORIES'), $sync, $id); } /** @@ -128,23 +268,54 @@ class OC_VCategories { * $result = $stmt->execute(); * $objects = array(); * if(!is_null($result)) { - * while( $row = $result->fetchRow()) { - * $objects[] = $row['carddata']; + * while( $row = $result->fetchRow()){ + * $objects[] = array($row['id'], $row['carddata']); * } * } * $categories->rescan($objects); */ public function rescan($objects, $sync=true, $reset=true) { - if($reset === true) { + + if($reset === true) { + $result = null; + // Find all objectid/categoryid pairs. + try { + $stmt = OCP\DB::prepare('SELECT `id` FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ? AND `type` = ?'); + $result = $stmt->execute(array($this->user, $this->type)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + + // And delete them. + if(!is_null($result)) { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + . 'WHERE `categoryid` = ? AND `type`= ?'); + while( $row = $result->fetchRow()) { + $stmt->execute(array($row['id'], $this->type)); + } + } + try { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ? AND `type` = ?'); + $result = $stmt->execute(array($this->user, $this->type)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + return; + } $this->categories = array(); } + // Parse all the VObjects foreach($objects as $object) { - //OC_Log::write('core','OC_VCategories::rescan: '.substr($object, 0, 100).'(...)', OC_Log::DEBUG); - $vobject = OC_VObject::parse($object); + $vobject = OC_VObject::parse($object[1]); if(!is_null($vobject)) { - $this->loadFromVObject($vobject, $sync); + // Load the categories + $this->loadFromVObject($object[0], $vobject, $sync); } else { - OC_Log::write('core','OC_VCategories::rescan, unable to parse. ID: '.', '.substr($object, 0, 100).'(...)', OC_Log::DEBUG); + OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' + . substr($object, 0, 100) . '(...)', OC_Log::DEBUG); } } $this->save(); @@ -155,15 +326,58 @@ class OC_VCategories { */ private function save() { if(is_array($this->categories)) { - usort($this->categories, 'strnatcasecmp'); // usort to also renumber the keys - $escaped_categories = serialize($this->categories); - OC_Preferences::setValue($this->user, $this->app, self::PREF_CATEGORIES_LABEL, $escaped_categories); - OC_Log::write('core','OC_VCategories::save: '.print_r($this->categories, true), OC_Log::DEBUG); + foreach($this->categories as $category) { + OCP\DB::insertIfNotExist('*PREFIX*vcategory', + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $category, + )); + } + // reload categories to get the proper ids. + $this->loadCategories(); + // Loop through temporarily cached objectid/categoryname pairs + // and save relations. + $categories = $this->categories; + // For some reason this is needed or array_search(i) will return 0..? + ksort($categories); + foreach(self::$relations as $relation) { + $catid = $this->array_searchi($relation['category'], $categories); + OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); + if($catid) { + OCP\DB::insertIfNotExist('*PREFIX*vcategory_to_object', + array( + 'objid' => $relation['objid'], + 'categoryid' => $catid, + 'type' => $this->type, + )); + } + } + self::$relations = array(); // reset } else { - OC_Log::write('core','OC_VCategories::save: $this->categories is not an array! '.print_r($this->categories, true), OC_Log::ERROR); + OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' + . print_r($this->categories, true), OC_Log::ERROR); } } - + + /** + * @brief Delete category/object relations from the db + * @param $id The id of the object + * @param $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + */ + public function purgeObject($id, $type = null) { + $type = is_null($type) ? $this->type : $type; + try { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + . 'WHERE `objid` = ? AND `type`= ?'); + $stmt->execute(array($id, $type)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + } + /** * @brief Delete categories from the db and from all the vobject supplied * @param $names An array of categories to delete @@ -173,37 +387,65 @@ class OC_VCategories { if(!is_array($names)) { $names = array($names); } - OC_Log::write('core','OC_VCategories::delete, before: '.print_r($this->categories, true), OC_Log::DEBUG); + //OC_Log::write('core', __METHOD__ . ', before: ' + // . print_r($this->categories, true), OC_Log::DEBUG); foreach($names as $name) { - OC_Log::write('core','OC_VCategories::delete: '.$name, OC_Log::DEBUG); + //OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); if($this->hasCategory($name)) { - //OC_Log::write('core','OC_VCategories::delete: '.$name.' got it', OC_Log::DEBUG); unset($this->categories[$this->array_searchi($name, $this->categories)]); } + try { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + } } - $this->save(); - OC_Log::write('core','OC_VCategories::delete, after: '.print_r($this->categories, true), OC_Log::DEBUG); + //OC_Log::write('core', __METHOD__.', after: ' + // . print_r($this->categories, true), OC_Log::DEBUG); if(!is_null($objects)) { foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); if(!is_null($vobject)) { - $categories = $vobject->getAsArray('CATEGORIES'); - //OC_Log::write('core','OC_VCategories::delete, before: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); + $object = null; + $componentname = ''; + if (isset($vobject->VEVENT)) { + $object = $vobject->VEVENT; + $componentname = 'VEVENT'; + } else + if (isset($vobject->VTODO)) { + $object = $vobject->VTODO; + $componentname = 'VTODO'; + } else + if (isset($vobject->VJOURNAL)) { + $object = $vobject->VJOURNAL; + $componentname = 'VJOURNAL'; + } else { + $object = $vobject; + } + $categories = $object->getAsArray('CATEGORIES'); foreach($names as $name) { $idx = $this->array_searchi($name, $categories); - //OC_Log::write('core','OC_VCategories::delete, loop: '.$name.', '.print_r($idx, true), OC_Log::DEBUG); if($idx !== false) { - OC_Log::write('core','OC_VCategories::delete, unsetting: '.$categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG); + OC_Log::write('core', __METHOD__ + .', unsetting: ' + . $categories[$this->array_searchi($name, $categories)], + OC_Log::DEBUG); unset($categories[$this->array_searchi($name, $categories)]); - //unset($categories[$idx]); } } - //OC_Log::write('core','OC_VCategories::delete, after: '.$key.': '.print_r($categories, true), OC_Log::DEBUG); - $vobject->setString('CATEGORIES', implode(',', $categories)); + $object->setString('CATEGORIES', implode(',', $categories)); + if($vobject !== $object) { + $vobject[$componentname] = $object; + } $value[1] = $vobject->serialize(); $objects[$key] = $value; } else { - OC_Log::write('core','OC_VCategories::delete, unable to parse. ID: '.$value[0].', '.substr($value[1], 0, 50).'(...)', OC_Log::DEBUG); + OC_Log::write('core', __METHOD__ + .', unable to parse. ID: ' . $value[0] . ', ' + . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG); } } } @@ -222,7 +464,10 @@ class OC_VCategories { if(!is_array($haystack)) { return false; } - return array_search(strtolower($needle),array_map('strtolower',$haystack)); + return array_search( + strtolower($needle), + array_map('strtolower', $haystack) + ); } } From 6bfb2ca2a8ca18fe45997d720b1adc7781d51d2a Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 2 Oct 2012 22:46:37 +0200 Subject: [PATCH 03/48] Added post_deleteUser hook to VCategories. Added methods for adding/removing object/category relations. --- lib/vcategories.php | 116 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 6 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 08faa0d903..499fffad3f 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -21,6 +21,7 @@ * */ +OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUser'); /** * Class for easy access to categories in VCARD, VEVENT, VTODO and VJOURNAL. @@ -147,7 +148,7 @@ class OC_VCategories { /** * @brief Get the a list if items belonging to $category. * @param string|integer $category Category id or name. - * @param string $table The name of table to query. + * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} * @param int $limit * @param int $offset * @@ -327,7 +328,7 @@ class OC_VCategories { private function save() { if(is_array($this->categories)) { foreach($this->categories as $category) { - OCP\DB::insertIfNotExist('*PREFIX*vcategory', + OCP\DB::insertIfNotExist(self::$category_table, array( 'uid' => $this->user, 'type' => $this->type, @@ -345,7 +346,7 @@ class OC_VCategories { $catid = $this->array_searchi($relation['category'], $categories); OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); if($catid) { - OCP\DB::insertIfNotExist('*PREFIX*vcategory_to_object', + OCP\DB::insertIfNotExist(self::$relation_table, array( 'objid' => $relation['objid'], 'categoryid' => $catid, @@ -360,22 +361,125 @@ class OC_VCategories { } } + /** + * @brief Delete categories and category/object relations for a user. + * For hooking up on post_deleteUser + * @param string $uid The user id for which entries should be purged. + */ + public static function post_deleteUser($arguments) { + // Find all objectid/categoryid pairs. + $result = null; + try { + $stmt = OCP\DB::prepare('SELECT `id` FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + + if(!is_null($result)) { + try { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + . 'WHERE `categoryid` = ?'); + while( $row = $result->fetchRow()) { + try { + $stmt->execute(array($row['id'])); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + } + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + } + } + try { + $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` ' + . 'WHERE `uid` = ? AND'); + $result = $stmt->execute(array($arguments['uid'])); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), OCP\Util::ERROR); + } + } + /** * @brief Delete category/object relations from the db - * @param $id The id of the object - * @param $type The type of object (event/contact/task/journal). + * @param int $id The id of the object + * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance + * @returns boolean */ public function purgeObject($id, $type = null) { $type = is_null($type) ? $this->type : $type; try { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::$relation_table . '` ' . 'WHERE `objid` = ? AND `type`= ?'); $stmt->execute(array($id, $type)); } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); + return false; } + return true; + } + + /** + * @brief Creates a category/object relation. + * @param int $objid The id of the object + * @param int|string $category The id or name of the category + * @param string $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + * @returns boolean + */ + public function createRelation($objid, $category, $type = null) { + $type = is_null($type) ? $this->type : $type; + $categoryid = (is_string($category) && !is_numeric($category)) + ? $this->array_searchi($category, $this->categories) + : $category; + try { + OCP\DB::insertIfNotExist(self::$relation_table, + array( + 'objid' => $objid, + 'categoryid' => $categoryid, + 'type' => $type, + )); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * @brief Delete single category/object relation from the db + * @param int $objid The id of the object + * @param int|string $category The id or name of the category + * @param string $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + * @returns boolean + */ + public function removeRelation($objid, $category, $type = null) { + $type = is_null($type) ? $this->type : $type; + $categoryid = (is_string($category) && !is_numeric($category)) + ? $this->array_searchi($category, $this->categories) + : $category; + try { + $sql = 'DELETE FROM `' . self::$relation_table . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, + OCP\Util::DEBUG); + $stmt = OCP\DB::prepare($sql); + $stmt->execute(array($objid, $categoryid, $type)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + return false; + } + return true; } /** From f4fd4a5a529aac331c7453bc1d3372da5c71f05c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:06:18 +0200 Subject: [PATCH 04/48] Updated category ajax files to use type instead of app and add callCheck. --- core/ajax/vcategories/add.php | 21 ++++++++++++--------- core/ajax/vcategories/delete.php | 24 ++++++++++++++---------- core/ajax/vcategories/edit.php | 15 +++++++++------ 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/core/ajax/vcategories/add.php b/core/ajax/vcategories/add.php index 81fa06dbf1..e97612c28f 100644 --- a/core/ajax/vcategories/add.php +++ b/core/ajax/vcategories/add.php @@ -15,23 +15,26 @@ function debug($msg) { } require_once '../../../lib/base.php'; -OC_JSON::checkLoggedIn(); -$category = isset($_GET['category'])?strip_tags($_GET['category']):null; -$app = isset($_GET['app'])?$_GET['app']:null; -if(is_null($app)) { - bailOut(OC_Contacts_App::$l10n->t('Application name not provided.')); +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + +$l = OC_L10N::get('core'); + +$category = isset($_POST['category']) ? strip_tags($_POST['category']) : null; +$type = isset($_POST['type']) ? $_POST['type'] : null; + +if(is_null($type)) { + bailOut($l->t('Category type not provided.')); } -OC_JSON::checkAppEnabled($app); - if(is_null($category)) { - bailOut(OC_Contacts_App::$l10n->t('No category to add?')); + bailOut($l->t('No category to add?')); } debug(print_r($category, true)); -$categories = new OC_VCategories($app); +$categories = new OC_VCategories($type); if($categories->hasCategory($category)) { bailOut(OC_Contacts_App::$l10n->t('This category already exists: '.$category)); } else { diff --git a/core/ajax/vcategories/delete.php b/core/ajax/vcategories/delete.php index cd46a25b79..fd7b71be5d 100644 --- a/core/ajax/vcategories/delete.php +++ b/core/ajax/vcategories/delete.php @@ -16,21 +16,25 @@ function debug($msg) { } require_once '../../../lib/base.php'; -OC_JSON::checkLoggedIn(); -$app = isset($_POST['app'])?$_POST['app']:null; -$categories = isset($_POST['categories'])?$_POST['categories']:null; -if(is_null($app)) { - bailOut(OC_Contacts_App::$l10n->t('Application name not provided.')); + +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + +$l = OC_L10N::get('core'); + +$type = isset($_POST['type']) ? $_POST['type'] : null; +$categories = isset($_POST['categories']) ? $_POST['categories'] : null; + +if(is_null($type)) { + bailOut($l->t('Object type not provided.')); } -OC_JSON::checkAppEnabled($app); - -debug('The application "'.$app.'" uses the default file. OC_VObjects will not be updated.'); +debug('The application using category type "' . $type . '" uses the default file for deletion. OC_VObjects will not be updated.'); if(is_null($categories)) { - bailOut('No categories selected for deletion.'); + bailOut($l->t('No categories selected for deletion.')); } -$vcategories = new OC_VCategories($app); +$vcategories = new OC_VCategories($type); $vcategories->delete($categories); OC_JSON::success(array('data' => array('categories'=>$vcategories->categories()))); diff --git a/core/ajax/vcategories/edit.php b/core/ajax/vcategories/edit.php index a0e67841c5..4e9c9c17b5 100644 --- a/core/ajax/vcategories/edit.php +++ b/core/ajax/vcategories/edit.php @@ -17,16 +17,19 @@ function debug($msg) { require_once '../../../lib/base.php'; OC_JSON::checkLoggedIn(); -$app = isset($_GET['app'])?$_GET['app']:null; -if(is_null($app)) { - bailOut('Application name not provided.'); +$l = OC_L10N::get('core'); + +$type = isset($_GET['type']) ? $_GET['type'] : null; + +if(is_null($type)) { + bailOut($l->t('Category type not provided.')); } -OC_JSON::checkAppEnabled($app); -$tmpl = new OC_TEMPLATE("core", "edit_categories_dialog"); +OC_JSON::checkAppEnabled($type); +$tmpl = new OCP\Template("core", "edit_categories_dialog"); -$vcategories = new OC_VCategories($app); +$vcategories = new OC_VCategories($type); $categories = $vcategories->categories(); debug(print_r($categories, true)); $tmpl->assign('categories', $categories); From 26719005a466a0730bd24110115192188c5e60dd Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:07:41 +0200 Subject: [PATCH 05/48] Added ajax files for favorite category handling. --- core/ajax/vcategories/addToFavorites.php | 40 +++++++++++++++++++ core/ajax/vcategories/favorites.php | 33 +++++++++++++++ core/ajax/vcategories/removeFromFavorites.php | 40 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 core/ajax/vcategories/addToFavorites.php create mode 100644 core/ajax/vcategories/favorites.php create mode 100644 core/ajax/vcategories/removeFromFavorites.php diff --git a/core/ajax/vcategories/addToFavorites.php b/core/ajax/vcategories/addToFavorites.php new file mode 100644 index 0000000000..f330d19c8a --- /dev/null +++ b/core/ajax/vcategories/addToFavorites.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); +} + +require_once '../../../lib/base.php'; + +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + +$l = OC_L10N::get('core'); + +$id = isset($_POST['id']) ? strip_tags($_POST['id']) : null; +$type = isset($_POST['type']) ? $_POST['type'] : null; + +if(is_null($type)) { + bailOut($l->t('Object type not provided.')); +} + +if(is_null($id)) { + bailOut($l->t('%s ID not provided.', $type)); +} + +$categories = new OC_VCategories($type); +if(!$categories->addToFavorites($id, $type)) { + bailOut($l->t('Error adding %s to favorites.', $id)); +} + +OC_JSON::success(); diff --git a/core/ajax/vcategories/favorites.php b/core/ajax/vcategories/favorites.php new file mode 100644 index 0000000000..35b23e29c1 --- /dev/null +++ b/core/ajax/vcategories/favorites.php @@ -0,0 +1,33 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); +} + +require_once '../../../lib/base.php'; + +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + + +$type = isset($_POST['type']) ? $_POST['type'] : null; + +if(is_null($type)) { + $l = OC_L10N::get('core'); + bailOut($l->t('Object type not provided.')); +} + +$categories = new OC_VCategories($type); +$ids = $categories->getFavorites($type)) { + +OC_JSON::success(array('ids' => $ids)); diff --git a/core/ajax/vcategories/removeFromFavorites.php b/core/ajax/vcategories/removeFromFavorites.php new file mode 100644 index 0000000000..f779df48f2 --- /dev/null +++ b/core/ajax/vcategories/removeFromFavorites.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ +function bailOut($msg) { + OC_JSON::error(array('data' => array('message' => $msg))); + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); + exit(); +} +function debug($msg) { + OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); +} + +require_once '../../../lib/base.php'; + +OCP\JSON::checkLoggedIn(); +OCP\JSON::callCheck(); + +$l = OC_L10N::get('core'); + +$id = isset($_POST['id']) ? strip_tags($_POST['id']) : null; +$type = isset($_POST['type']) ? $_POST['type'] : null; + +if(is_null($type)) { + bailOut($l->t('Object type not provided.')); +} + +if(is_null($id)) { + bailOut($l->t('%s ID not provided.', $type)); +} + +$categories = new OC_VCategories($type); +if(!$categories->removeFromFavorites($id, $type)) { + bailOut($l->t('Error removing %s from favorites.', $id)); +} + +OC_JSON::success(); From 97c884c54804832a24e153273c5c619b76d3ebe9 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:09:07 +0200 Subject: [PATCH 06/48] Updated category js for handling favorites and use post instead of get. --- core/js/oc-vcategories.js | 61 +++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js index c99dd51f53..f3935911b8 100644 --- a/core/js/oc-vcategories.js +++ b/core/js/oc-vcategories.js @@ -1,14 +1,15 @@ -var OCCategories={ - edit:function(){ +var OCCategories= { + edit:function() { if(OCCategories.app == undefined) { OC.dialogs.alert('OCCategories.app is not set!'); return; } $('body').append('
'); - $('#category_dialog').load(OC.filePath('core', 'ajax', 'vcategories/edit.php')+'?app='+OCCategories.app, function(response){ + $('#category_dialog').load( + OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?app=' + OCCategories.app, function(response) { try { var jsondata = jQuery.parseJSON(response); - if(response.status == 'error'){ + if(response.status == 'error') { OC.dialogs.alert(response.data.message, 'Error'); return; } @@ -32,7 +33,7 @@ var OCCategories={ $('#category_dialog').remove(); }, open : function(event, ui) { - $('#category_addinput').live('input',function(){ + $('#category_addinput').live('input',function() { if($(this).val().length > 0) { $('#category_addbutton').removeAttr('disabled'); } @@ -43,7 +44,7 @@ var OCCategories={ $('#category_addbutton').attr('disabled', 'disabled'); return false; }); - $('#category_addbutton').live('click',function(e){ + $('#category_addbutton').live('click',function(e) { e.preventDefault(); if($('#category_addinput').val().length > 0) { OCCategories.add($('#category_addinput').val()); @@ -55,14 +56,37 @@ var OCCategories={ } }); }, - _processDeleteResult:function(jsondata, status, xhr){ - if(jsondata.status == 'success'){ + _processDeleteResult:function(jsondata, status, xhr) { + if(jsondata.status == 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } }, - doDelete:function(){ + favorites:function(type, cb) { + $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/favorites.php'),function(jsondata) { + if(jsondata.status === 'success') { + OCCategories._update(jsondata.data.categories); + } else { + OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + } + }); + }, + addToFavorites:function(id, type) { + $.post(OC.filePath('core', 'ajax', 'vcategories/addToFavorites.php'), {id:id, type:type}, function(jsondata) { + if(jsondata.status !== 'success') { + OC.dialogs.alert(jsondata.data.message, 'Error'); + } + }); + }, + removeFromFavorites:function(id, type) { + $.post(OC.filePath('core', 'ajax', 'vcategories/removeFromFavorites.php'), {id:id, type:type}, function(jsondata) { + if(jsondata.status !== 'success') { + OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + } + }); + }, + doDelete:function() { var categories = $('#categorylist').find('input:checkbox').serialize(); if(categories == '' || categories == undefined) { OC.dialogs.alert(t('core', 'No categories selected for deletion.'), t('core', 'Error')); @@ -76,30 +100,31 @@ var OCCategories={ } }); }, - add:function(category){ - $.getJSON(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'app':OCCategories.app},function(jsondata){ - if(jsondata.status == 'success'){ + add:function(category) { + $.post(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'app':OCCategories.app},function(jsondata) { + if(jsondata.status === 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } }); - return false; }, - rescan:function(){ - $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr){ - if(jsondata.status == 'success'){ + rescan:function() { + $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr) { + if(jsondata.status === 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } }).error(function(xhr){ if (xhr.status == 404) { - OC.dialogs.alert('The required file ' + OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php') + ' is not installed!', 'Error'); + OC.dialogs.alert( + t('core', 'The required file {file} is not installed!', + {file: OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php')}, t('core', 'Error'))); } }); }, - _update:function(categories){ + _update:function(categories) { var categorylist = $('#categorylist'); categorylist.find('li').remove(); for(var category in categories) { From 1f7baeb9741be2c77caa892b55b12c23caa47253 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:13:34 +0200 Subject: [PATCH 07/48] Use consts all places and rename some daft method names. --- lib/vcategories.php | 50 +++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 499fffad3f..d71d570e4f 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -46,8 +46,11 @@ class OC_VCategories { private $type = null; private $user = null; - private static $category_table = '*PREFIX*vcategory'; - private static $relation_table = '*PREFIX*vcategory_to_object'; + + const CATEGORY_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const CATEGORY_FAVORITE = '_$!!$_'; const FORMAT_LIST = 0; const FORMAT_MAP = 1; @@ -81,7 +84,7 @@ class OC_VCategories { private function loadCategories() { $this->categories = array(); $result = null; - $sql = 'SELECT `id`, `category` FROM `*PREFIX*vcategory` ' + $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; try { $stmt = OCP\DB::prepare($sql); @@ -108,7 +111,7 @@ class OC_VCategories { */ public static function isEmpty($type, $user = null) { $user = is_null($user) ? OC_User::getUser() : $user; - $sql = 'SELECT COUNT(*) FROM `*PREFIX*vcategory` ' + $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; try { $stmt = OCP\DB::prepare($sql); @@ -185,11 +188,11 @@ class OC_VCategories { $fields = substr($fields, 0, -1); $items = array(); - $sql = 'SELECT `' . self::$relation_table . '`.`categoryid`, ' . $fields + $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' - . self::$relation_table . '` ON `' . $tableinfo['tablename'] - . '`.`id` = `' . self::$relation_table . '`.`objid` WHERE `' - . self::$relation_table . '`.`categoryid` = ?'; + . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] + . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' + . self::RELATION_TABLE . '`.`categoryid` = ?'; try { $stmt = OCP\DB::prepare($sql, $limit, $offset); @@ -281,7 +284,7 @@ class OC_VCategories { $result = null; // Find all objectid/categoryid pairs. try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `*PREFIX*vcategory` ' + $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); } catch(Exception $e) { @@ -291,14 +294,14 @@ class OC_VCategories { // And delete them. if(!is_null($result)) { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `categoryid` = ? AND `type`= ?'); while( $row = $result->fetchRow()) { $stmt->execute(array($row['id'], $this->type)); } } try { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); } catch(Exception $e) { @@ -328,7 +331,7 @@ class OC_VCategories { private function save() { if(is_array($this->categories)) { foreach($this->categories as $category) { - OCP\DB::insertIfNotExist(self::$category_table, + OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, array( 'uid' => $this->user, 'type' => $this->type, @@ -346,7 +349,7 @@ class OC_VCategories { $catid = $this->array_searchi($relation['category'], $categories); OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); if($catid) { - OCP\DB::insertIfNotExist(self::$relation_table, + OCP\DB::insertIfNotExist(self::RELATION_TABLE, array( 'objid' => $relation['objid'], 'categoryid' => $catid, @@ -370,7 +373,7 @@ class OC_VCategories { // Find all objectid/categoryid pairs. $result = null; try { - $stmt = OCP\DB::prepare('SELECT `id` FROM `*PREFIX*vcategory` ' + $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); } catch(Exception $e) { @@ -380,7 +383,7 @@ class OC_VCategories { if(!is_null($result)) { try { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory_to_object` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `categoryid` = ?'); while( $row = $result->fetchRow()) { try { @@ -396,7 +399,7 @@ class OC_VCategories { } } try { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND'); $result = $stmt->execute(array($arguments['uid'])); } catch(Exception $e) { @@ -415,7 +418,7 @@ class OC_VCategories { public function purgeObject($id, $type = null) { $type = is_null($type) ? $this->type : $type; try { - $stmt = OCP\DB::prepare('DELETE FROM `' . self::$relation_table . '` ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `type`= ?'); $stmt->execute(array($id, $type)); } catch(Exception $e) { @@ -434,13 +437,16 @@ class OC_VCategories { * Defaults to the type set in the instance * @returns boolean */ - public function createRelation($objid, $category, $type = null) { + public function addToCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; + if(is_string($category) && !$this->hasCategory($category)) { + $this->add($category, true); + } $categoryid = (is_string($category) && !is_numeric($category)) ? $this->array_searchi($category, $this->categories) : $category; try { - OCP\DB::insertIfNotExist(self::$relation_table, + OCP\DB::insertIfNotExist(self::RELATION_TABLE, array( 'objid' => $objid, 'categoryid' => $categoryid, @@ -462,13 +468,13 @@ class OC_VCategories { * Defaults to the type set in the instance * @returns boolean */ - public function removeRelation($objid, $category, $type = null) { + public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; $categoryid = (is_string($category) && !is_numeric($category)) ? $this->array_searchi($category, $this->categories) : $category; try { - $sql = 'DELETE FROM `' . self::$relation_table . '` ' + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, OCP\Util::DEBUG); @@ -499,7 +505,7 @@ class OC_VCategories { unset($this->categories[$this->array_searchi($name, $this->categories)]); } try { - $stmt = OCP\DB::prepare('DELETE FROM `*PREFIX*vcategory` WHERE ' + $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' . '`uid` = ? AND `type` = ? AND `category` = ?'); $result = $stmt->execute(array($this->user, $this->type, $name)); } catch(Exception $e) { From 09e26145b7d9c5bbbcf5f52e5b3742dafe789333 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:15:58 +0200 Subject: [PATCH 08/48] Add favorite handling methods to OC_VCategories. --- lib/vcategories.php | 99 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index d71d570e4f..e6680450f8 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -149,7 +149,57 @@ class OC_VCategories { } /** - * @brief Get the a list if items belonging to $category. + * Get the a list if items belonging to $category. + * + * Throws an exception if the category could not be found. + * + * @param string|integer $category Category id or name. + * @returns array An array of object ids or false on error. + */ + public function idsForCategory($category) { + $result = null; + if(is_numeric($category)) { + $catid = $category; + } elseif(is_string($category)) { + $catid = $this->array_searchi($category, $this->categories); + } + OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); + if($catid === false) { + $l10n = OC_L10N::get('core'); + throw new Exception( + $l10n->t('Could not find category "%s"', $category) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . ' WHERE `categoryid` = ?'; + + try { + $stmt = OCP\DB::prepare($sql); + $result = $stmt->execute(array($catid)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + return false; + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $ids[] = $row['objid']; + } + } + //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); + //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); + + return $ids; + } + + /** + * Get the a list if items belonging to $category. + * + * Throws an exception if the category could not be found. + * * @param string|integer $category Category id or name. * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} * @param int $limit @@ -428,6 +478,53 @@ class OC_VCategories { } return true; } + + /** + * Get favorites for an object type + * + * @param string $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + * @returns array An array of object ids. + */ + public function getFavorites($type = null) { + $type = is_null($type) ? $this->type : $type; + + try { + return $this->idsForCategory(self::CATEGORY_FAVORITE); + } catch(Exception $e) { + // No favorites + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @param string $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + * @returns boolean + */ + public function addToFavorites($objid, $type = null) { + $type = is_null($type) ? $this->type : $type; + if(!$this->hasCategory(self::CATEGORY_FAVORITE)) { + $this->add(self::CATEGORY_FAVORITE, true); + } + return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @param string $type The type of object (event/contact/task/journal). + * Defaults to the type set in the instance + * @returns boolean + */ + public function removeFromFavorites($objid, $type = null) { + $type = is_null($type) ? $this->type : $type; + return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type); + } /** * @brief Creates a category/object relation. From 8a777022e4757cd6434853773f782575ef714a21 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:16:53 +0200 Subject: [PATCH 09/48] Formatting --- lib/vcategories.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index e6680450f8..1f1626c551 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -226,9 +226,7 @@ class OC_VCategories { if($catid === false) { $l10n = OC_L10N::get('core'); throw new Exception( - $l10n->t( - 'Could not find category "%s"', $category - ) + $l10n->t('Could not find category "%s"', $category) ); } $fields = ''; From 4827de4a276c83ad92eb1fa890dd3ade5d7a1514 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:20:27 +0200 Subject: [PATCH 10/48] White space fix. --- lib/vcategories.php | 138 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 1f1626c551..19274390c5 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -33,12 +33,12 @@ OC_Hook::connect('OC_User', 'post_deleteUser', 'OC_VCategories', 'post_deleteUse * tries to add a category named 'Family' it will be silently ignored. */ class OC_VCategories { - + /** * Categories */ private $categories = array(); - + /** * Used for storing objectid/categoryname pairs while rescanning. */ @@ -46,12 +46,12 @@ class OC_VCategories { private $type = null; private $user = null; - + const CATEGORY_TABLE = '*PREFIX*vcategory'; const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - + const CATEGORY_FAVORITE = '_$!!$_'; - + const FORMAT_LIST = 0; const FORMAT_MAP = 1; @@ -66,13 +66,13 @@ class OC_VCategories { public function __construct($type, $user=null, $defcategories=array()) { $this->type = $type; $this->user = is_null($user) ? OC_User::getUser() : $user; - + $this->loadCategories(); - OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r($this->categories, true), + OCP\Util::writeLog('core', __METHOD__ . ', categories: ' + . print_r($this->categories, true), OCP\Util::DEBUG ); - + if($defcategories && count($this->categories) === 0) { $this->add($defcategories, true); } @@ -90,7 +90,7 @@ class OC_VCategories { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($this->user, $this->type)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } @@ -101,8 +101,8 @@ class OC_VCategories { } } } - - + + /** * @brief Check if any categories are saved for this type and user. * @returns boolean. @@ -118,12 +118,12 @@ class OC_VCategories { $result = $stmt->execute(array($user, $type)); return ($result->numRows() == 0); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); return false; } } - + /** * @brief Get the categories for a specific user. * @param @@ -150,9 +150,9 @@ class OC_VCategories { /** * Get the a list if items belonging to $category. - * + * * Throws an exception if the category could not be found. - * + * * @param string|integer $category Category id or name. * @returns array An array of object ids or false on error. */ @@ -172,14 +172,14 @@ class OC_VCategories { } $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE . ' WHERE `categoryid` = ?'; try { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($catid)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); return false; } @@ -191,28 +191,28 @@ class OC_VCategories { } //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); - + return $ids; } - + /** * Get the a list if items belonging to $category. * * Throws an exception if the category could not be found. - * + * * @param string|integer $category Category id or name. * @param array $tableinfo Array in the form {'tablename' => table, 'fields' => ['field1', 'field2']} * @param int $limit * @param int $offset - * + * * This generic method queries a table assuming that the id * field is called 'id' and the table name provided is in * the form '*PREFIX*table_name'. - * + * * If the category name cannot be resolved an exception is thrown. - * + * * TODO: Maybe add the getting permissions for objects? - * + * * @returns array containing the resulting items. */ public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { @@ -236,17 +236,17 @@ class OC_VCategories { $fields = substr($fields, 0, -1); $items = array(); - $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields - . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' - . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] - . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' + $sql = 'SELECT `' . self::RELATION_TABLE . '`.`categoryid`, ' . $fields + . ' FROM `' . $tableinfo['tablename'] . '` JOIN `' + . self::RELATION_TABLE . '` ON `' . $tableinfo['tablename'] + . '`.`id` = `' . self::RELATION_TABLE . '`.`objid` WHERE `' . self::RELATION_TABLE . '`.`categoryid` = ?'; try { $stmt = OCP\DB::prepare($sql, $limit, $offset); $result = $stmt->execute(array($catid)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } @@ -257,10 +257,10 @@ class OC_VCategories { } //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); - + return $items; } - + /** * @brief Checks whether a category is already saved. * @param $name The name to check for. @@ -327,8 +327,8 @@ class OC_VCategories { * $categories->rescan($objects); */ public function rescan($objects, $sync=true, $reset=true) { - - if($reset === true) { + + if($reset === true) { $result = null; // Find all objectid/categoryid pairs. try { @@ -336,7 +336,7 @@ class OC_VCategories { . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } @@ -353,7 +353,7 @@ class OC_VCategories { . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); return; } @@ -366,7 +366,7 @@ class OC_VCategories { // Load the categories $this->loadFromVObject($object[0], $vobject, $sync); } else { - OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' + OC_Log::write('core', __METHOD__ . ', unable to parse. ID: ' . ', ' . substr($object, 0, 100) . '(...)', OC_Log::DEBUG); } } @@ -379,7 +379,7 @@ class OC_VCategories { private function save() { if(is_array($this->categories)) { foreach($this->categories as $category) { - OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, + OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, array( 'uid' => $this->user, 'type' => $this->type, @@ -392,12 +392,12 @@ class OC_VCategories { // and save relations. $categories = $this->categories; // For some reason this is needed or array_search(i) will return 0..? - ksort($categories); + ksort($categories); foreach(self::$relations as $relation) { $catid = $this->array_searchi($relation['category'], $categories); OC_Log::write('core', __METHOD__ . 'catid, ' . $relation['category'] . ' ' . $catid, OC_Log::DEBUG); if($catid) { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, + OCP\DB::insertIfNotExist(self::RELATION_TABLE, array( 'objid' => $relation['objid'], 'categoryid' => $catid, @@ -407,11 +407,11 @@ class OC_VCategories { } self::$relations = array(); // reset } else { - OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' + OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' . print_r($this->categories, true), OC_Log::ERROR); } } - + /** * @brief Delete categories and category/object relations for a user. * For hooking up on post_deleteUser @@ -425,10 +425,10 @@ class OC_VCategories { . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } - + if(!is_null($result)) { try { $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' @@ -437,12 +437,12 @@ class OC_VCategories { try { $stmt->execute(array($row['id'])); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } } } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); } } @@ -451,11 +451,11 @@ class OC_VCategories { . 'WHERE `uid` = ? AND'); $result = $stmt->execute(array($arguments['uid'])); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); } } - + /** * @brief Delete category/object relations from the db * @param int $id The id of the object @@ -470,7 +470,7 @@ class OC_VCategories { . 'WHERE `objid` = ? AND `type`= ?'); $stmt->execute(array($id, $type)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); return false; } @@ -479,14 +479,14 @@ class OC_VCategories { /** * Get favorites for an object type - * + * * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance * @returns array An array of object ids. */ public function getFavorites($type = null) { $type = is_null($type) ? $this->type : $type; - + try { return $this->idsForCategory(self::CATEGORY_FAVORITE); } catch(Exception $e) { @@ -497,7 +497,7 @@ class OC_VCategories { /** * Add an object to favorites - * + * * @param int $objid The id of the object * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance @@ -510,10 +510,10 @@ class OC_VCategories { } return $this->addToCategory($objid, self::CATEGORY_FAVORITE, $type); } - + /** * Remove an object from favorites - * + * * @param int $objid The id of the object * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance @@ -523,7 +523,7 @@ class OC_VCategories { $type = is_null($type) ? $this->type : $type; return $this->removeFromCategory($objid, self::CATEGORY_FAVORITE, $type); } - + /** * @brief Creates a category/object relation. * @param int $objid The id of the object @@ -538,23 +538,23 @@ class OC_VCategories { $this->add($category, true); } $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) + ? $this->array_searchi($category, $this->categories) : $category; try { - OCP\DB::insertIfNotExist(self::RELATION_TABLE, + OCP\DB::insertIfNotExist(self::RELATION_TABLE, array( 'objid' => $objid, 'categoryid' => $categoryid, 'type' => $type, )); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); return false; } return true; } - + /** * @brief Delete single category/object relation from the db * @param int $objid The id of the object @@ -566,23 +566,23 @@ class OC_VCategories { public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) + ? $this->array_searchi($category, $this->categories) : $category; try { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, + OCP\Util::writeLog('core', __METHOD__.', sql: ' . $objid . ' ' . $categoryid . ' ' . $type, OCP\Util::DEBUG); $stmt = OCP\DB::prepare($sql); $stmt->execute(array($objid, $categoryid, $type)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); return false; } return true; } - + /** * @brief Delete categories from the db and from all the vobject supplied * @param $names An array of categories to delete @@ -592,7 +592,7 @@ class OC_VCategories { if(!is_array($names)) { $names = array($names); } - //OC_Log::write('core', __METHOD__ . ', before: ' + //OC_Log::write('core', __METHOD__ . ', before: ' // . print_r($this->categories, true), OC_Log::DEBUG); foreach($names as $name) { //OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); @@ -604,11 +604,11 @@ class OC_VCategories { . '`uid` = ? AND `type` = ? AND `category` = ?'); $result = $stmt->execute(array($this->user, $this->type, $name)); } catch(Exception $e) { - OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); } } - //OC_Log::write('core', __METHOD__.', after: ' + //OC_Log::write('core', __METHOD__.', after: ' // . print_r($this->categories, true), OC_Log::DEBUG); if(!is_null($objects)) { foreach($objects as $key=>&$value) { @@ -635,7 +635,7 @@ class OC_VCategories { $idx = $this->array_searchi($name, $categories); if($idx !== false) { OC_Log::write('core', __METHOD__ - .', unsetting: ' + .', unsetting: ' . $categories[$this->array_searchi($name, $categories)], OC_Log::DEBUG); unset($categories[$this->array_searchi($name, $categories)]); @@ -649,7 +649,7 @@ class OC_VCategories { $objects[$key] = $value; } else { OC_Log::write('core', __METHOD__ - .', unable to parse. ID: ' . $value[0] . ', ' + .', unable to parse. ID: ' . $value[0] . ', ' . substr($value[1], 0, 50) . '(...)', OC_Log::DEBUG); } } @@ -670,7 +670,7 @@ class OC_VCategories { return false; } return array_search( - strtolower($needle), + strtolower($needle), array_map('strtolower', $haystack) ); } From b9c9fdfe200d42bc75afe42d9ecfa98e3ccef8c1 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:38:23 +0200 Subject: [PATCH 11/48] Use get for loading dialog. --- core/ajax/vcategories/favorites.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ajax/vcategories/favorites.php b/core/ajax/vcategories/favorites.php index 35b23e29c1..b72fc7a9fe 100644 --- a/core/ajax/vcategories/favorites.php +++ b/core/ajax/vcategories/favorites.php @@ -20,7 +20,7 @@ OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); -$type = isset($_POST['type']) ? $_POST['type'] : null; +$type = isset($_GET['type']) ? $_GET['type'] : null; if(is_null($type)) { $l = OC_L10N::get('core'); From 81536a81e3df86289afcc80308a0bb7f22df3cc1 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 00:39:09 +0200 Subject: [PATCH 12/48] More js updates for app/type in OCCategories --- core/js/oc-vcategories.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js index f3935911b8..b0256c7ec0 100644 --- a/core/js/oc-vcategories.js +++ b/core/js/oc-vcategories.js @@ -1,12 +1,12 @@ var OCCategories= { edit:function() { - if(OCCategories.app == undefined) { - OC.dialogs.alert('OCCategories.app is not set!'); + if(OCCategories.type == undefined) { + OC.dialogs.alert('OCCategories.type is not set!'); return; } $('body').append('
'); $('#category_dialog').load( - OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?app=' + OCCategories.app, function(response) { + OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?type=' + OCCategories.type, function(response) { try { var jsondata = jQuery.parseJSON(response); if(response.status == 'error') { @@ -64,7 +64,7 @@ var OCCategories= { } }, favorites:function(type, cb) { - $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/favorites.php'),function(jsondata) { + $.getJSON(OC.filePath('core', 'ajax', 'categories/favorites.php'), {type: type},function(jsondata) { if(jsondata.status === 'success') { OCCategories._update(jsondata.data.categories); } else { @@ -92,13 +92,13 @@ var OCCategories= { OC.dialogs.alert(t('core', 'No categories selected for deletion.'), t('core', 'Error')); return false; } - categories += '&app=' + OCCategories.app; - $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'), categories, OCCategories._processDeleteResult) - .error(function(xhr){ - if (xhr.status == 404) { - $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), categories, OCCategories._processDeleteResult); - } - }); + var q = categories + '&type=' + OCCategories.type; + if(OCCategories.app) { + q += '&app=' + OCCategories.app; + $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'), q, OCCategories._processDeleteResult); + } else { + $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), q, OCCategories._processDeleteResult); + } }, add:function(category) { $.post(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'app':OCCategories.app},function(jsondata) { From e55cc2313299d770733a0d488bb11d3ff256bc76 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 02:24:57 +0200 Subject: [PATCH 13/48] app !== type --- core/ajax/vcategories/edit.php | 1 - 1 file changed, 1 deletion(-) diff --git a/core/ajax/vcategories/edit.php b/core/ajax/vcategories/edit.php index 4e9c9c17b5..e7f2ff8ce5 100644 --- a/core/ajax/vcategories/edit.php +++ b/core/ajax/vcategories/edit.php @@ -26,7 +26,6 @@ if(is_null($type)) { bailOut($l->t('Category type not provided.')); } -OC_JSON::checkAppEnabled($type); $tmpl = new OCP\Template("core", "edit_categories_dialog"); $vcategories = new OC_VCategories($type); From fdf3ec1027c0be5fe01bdd4e4780fef812f999af Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 02:25:39 +0200 Subject: [PATCH 14/48] Add wait state to category dialog while processing. --- core/js/oc-vcategories.js | 50 ++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js index b0256c7ec0..f08df9c069 100644 --- a/core/js/oc-vcategories.js +++ b/core/js/oc-vcategories.js @@ -14,18 +14,34 @@ var OCCategories= { return; } } catch(e) { - $('#edit_categories_dialog').dialog({ + var setEnabled = function(d, enable) { + if(enable) { + dlg.css('cursor', 'default').find('input,button:not(#category_addbutton)') + .prop('disabled', false).css('cursor', 'default'); + } else { + d.css('cursor', 'wait').find('input,button:not(#category_addbutton)') + .prop('disabled', true).css('cursor', 'wait'); + } + } + var dlg = $('#edit_categories_dialog').dialog({ modal: true, height: 350, minHeight:200, width: 250, minWidth: 200, buttons: { 'Close': function() { - $(this).dialog("close"); + $(this).dialog('close'); }, 'Delete':function() { - OCCategories.doDelete(); + var categories = $('#categorylist').find('input:checkbox').serialize(); + setEnabled(dlg, false); + OCCategories.doDelete(categories, function() { + setEnabled(dlg, true); + }); }, 'Rescan':function() { - OCCategories.rescan(); + setEnabled(dlg, false); + OCCategories.rescan(function() { + setEnabled(dlg, true); + }); } }, close : function(event, ui) { @@ -56,12 +72,15 @@ var OCCategories= { } }); }, - _processDeleteResult:function(jsondata, status, xhr) { + _processDeleteResult:function(jsondata, cb) { if(jsondata.status == 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } + if(typeof cb == 'function') { + cb(); + } }, favorites:function(type, cb) { $.getJSON(OC.filePath('core', 'ajax', 'categories/favorites.php'), {type: type},function(jsondata) { @@ -86,8 +105,7 @@ var OCCategories= { } }); }, - doDelete:function() { - var categories = $('#categorylist').find('input:checkbox').serialize(); + doDelete:function(categories, cb) { if(categories == '' || categories == undefined) { OC.dialogs.alert(t('core', 'No categories selected for deletion.'), t('core', 'Error')); return false; @@ -95,9 +113,13 @@ var OCCategories= { var q = categories + '&type=' + OCCategories.type; if(OCCategories.app) { q += '&app=' + OCCategories.app; - $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'), q, OCCategories._processDeleteResult); + $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'), q, function(jsondata) { + OCCategories._processDeleteResult(jsondata, cb) + }); } else { - $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), q, OCCategories._processDeleteResult); + $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), q, function(jsondata) { + OCCategories._processDeleteResult(jsondata, cb) + }); } }, add:function(category) { @@ -109,19 +131,25 @@ var OCCategories= { } }); }, - rescan:function() { + rescan:function(cb) { $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr) { if(jsondata.status === 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } + if(typeof cb == 'function') { + cb(); + } }).error(function(xhr){ if (xhr.status == 404) { OC.dialogs.alert( t('core', 'The required file {file} is not installed!', {file: OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php')}, t('core', 'Error'))); } + if(typeof cb == 'function') { + cb(); + } }); }, _update:function(categories) { @@ -131,7 +159,7 @@ var OCCategories= { var item = '
  • ' + categories[category] + '
  • '; $(item).appendTo(categorylist); } - if(OCCategories.changed != undefined) { + if(typeof OCCategories.changed === 'function') { OCCategories.changed(categories); } } From afa3f49c933a08af1f30eb8a2ff18529f4398e2c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 02:26:36 +0200 Subject: [PATCH 15/48] Make categories var static. --- lib/vcategories.php | 56 +++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 19274390c5..22bd8a3c85 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -37,7 +37,7 @@ class OC_VCategories { /** * Categories */ - private $categories = array(); + private static $categories = array(); /** * Used for storing objectid/categoryname pairs while rescanning. @@ -69,11 +69,11 @@ class OC_VCategories { $this->loadCategories(); OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r($this->categories, true), + . print_r(self::$categories, true), OCP\Util::DEBUG ); - if($defcategories && count($this->categories) === 0) { + if($defcategories && count(self::$categories) === 0) { $this->add($defcategories, true); } } @@ -82,7 +82,7 @@ class OC_VCategories { * @brief Load categories from db. */ private function loadCategories() { - $this->categories = array(); + self::$categories = array(); $result = null; $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; @@ -97,9 +97,11 @@ class OC_VCategories { if(!is_null($result)) { while( $row = $result->fetchRow()) { // The keys are prefixed because array_search wouldn't work otherwise :-/ - $this->categories[$row['id']] = $row['category']; + self::$categories[$row['id']] = $row['category']; } } + OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r(self::$categories, true), + OCP\Util::DEBUG); } @@ -130,16 +132,16 @@ class OC_VCategories { * @returns array containing the categories as strings. */ public function categories($format = null) { - if(!$this->categories) { + if(!self::$categories) { return array(); } - $categories = array_values($this->categories); + $categories = array_values(self::$categories); uasort($categories, 'strnatcasecmp'); if($format == self::FORMAT_MAP) { $catmap = array(); foreach($categories as $category) { $catmap[] = array( - 'id' => $this->array_searchi($category, $this->categories), + 'id' => $this->array_searchi($category, self::$categories), 'name' => $category ); } @@ -161,7 +163,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { - $catid = $this->array_searchi($category, $this->categories); + $catid = $this->array_searchi($category, self::$categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); if($catid === false) { @@ -220,7 +222,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { - $catid = $this->array_searchi($category, $this->categories); + $catid = $this->array_searchi($category, self::$categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); if($catid === false) { @@ -267,7 +269,7 @@ class OC_VCategories { * @returns bool */ public function hasCategory($name) { - return $this->in_arrayi($name, $this->categories); + return $this->in_arrayi($name, self::$categories); } /** @@ -285,7 +287,7 @@ class OC_VCategories { $newones = array(); foreach($names as $name) { if(($this->in_arrayi( - $name, $this->categories) == false) && $name != '') { + $name, self::$categories) == false) && $name != '') { $newones[] = $name; } if(!is_null($id) ) { @@ -294,7 +296,7 @@ class OC_VCategories { } } if(count($newones) > 0) { - $this->categories = array_merge($this->categories, $newones); + self::$categories = array_merge(self::$categories, $newones); if($sync === true) { $this->save(); } @@ -357,7 +359,7 @@ class OC_VCategories { . $e->getMessage(), OCP\Util::ERROR); return; } - $this->categories = array(); + self::$categories = array(); } // Parse all the VObjects foreach($objects as $object) { @@ -377,8 +379,8 @@ class OC_VCategories { * @brief Save the list with categories */ private function save() { - if(is_array($this->categories)) { - foreach($this->categories as $category) { + if(is_array(self::$categories)) { + foreach(self::$categories as $category) { OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, array( 'uid' => $this->user, @@ -390,7 +392,7 @@ class OC_VCategories { $this->loadCategories(); // Loop through temporarily cached objectid/categoryname pairs // and save relations. - $categories = $this->categories; + $categories = self::$categories; // For some reason this is needed or array_search(i) will return 0..? ksort($categories); foreach(self::$relations as $relation) { @@ -407,8 +409,8 @@ class OC_VCategories { } self::$relations = array(); // reset } else { - OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' - . print_r($this->categories, true), OC_Log::ERROR); + OC_Log::write('core', __METHOD__.', self::$categories is not an array! ' + . print_r(self::$categories, true), OC_Log::ERROR); } } @@ -538,7 +540,7 @@ class OC_VCategories { $this->add($category, true); } $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) + ? $this->array_searchi($category, self::$categories) : $category; try { OCP\DB::insertIfNotExist(self::RELATION_TABLE, @@ -566,7 +568,7 @@ class OC_VCategories { public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, $this->categories) + ? $this->array_searchi($category, self::$categories) : $category; try { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' @@ -592,12 +594,12 @@ class OC_VCategories { if(!is_array($names)) { $names = array($names); } - //OC_Log::write('core', __METHOD__ . ', before: ' - // . print_r($this->categories, true), OC_Log::DEBUG); + OC_Log::write('core', __METHOD__ . ', before: ' + . print_r(self::$categories, true), OC_Log::DEBUG); foreach($names as $name) { - //OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); + OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); if($this->hasCategory($name)) { - unset($this->categories[$this->array_searchi($name, $this->categories)]); + unset(self::$categories[$this->array_searchi($name, self::$categories)]); } try { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' @@ -608,8 +610,8 @@ class OC_VCategories { . $e->getMessage(), OCP\Util::ERROR); } } - //OC_Log::write('core', __METHOD__.', after: ' - // . print_r($this->categories, true), OC_Log::DEBUG); + OC_Log::write('core', __METHOD__.', after: ' + . print_r(self::$categories, true), OC_Log::DEBUG); if(!is_null($objects)) { foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); From 1c9929d44f9d826493de7222ad42ff220cfd0cab Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 13:18:57 +0200 Subject: [PATCH 16/48] Added unit tests for OC_DB::insertIfNotExist() --- tests/data/db_structure.xml | 84 +++++++++++++++++++++++++++++++++++++ tests/lib/db.php | 26 ++++++++++++ 2 files changed, 110 insertions(+) diff --git a/tests/data/db_structure.xml b/tests/data/db_structure.xml index 03d7502c44..8a80819adf 100644 --- a/tests/data/db_structure.xml +++ b/tests/data/db_structure.xml @@ -135,4 +135,88 @@ + + + *dbprefix*vcategory + + + + + id + integer + 0 + true + 1 + true + 4 + + + + uid + text + + true + 64 + + + + type + text + + true + 64 + + + + category + text + + true + 255 + + + + uid_index + + uid + ascending + + + + + type_index + + type + ascending + + + + + category_index + + category + ascending + + + + + uid_type_category_index + true + + uid + ascending + + + type + ascending + + + category + ascending + + + + +
    + diff --git a/tests/lib/db.php b/tests/lib/db.php index 2344f7d8ec..5d30f6ac46 100644 --- a/tests/lib/db.php +++ b/tests/lib/db.php @@ -24,6 +24,7 @@ class Test_DB extends UnitTestCase { $this->test_prefix = $r; $this->table1 = $this->test_prefix.'contacts_addressbooks'; $this->table2 = $this->test_prefix.'contacts_cards'; + $this->table3 = $this->test_prefix.'vcategory'; } public function tearDown() { @@ -67,4 +68,29 @@ class Test_DB extends UnitTestCase { $result = $query->execute(array('uri_3')); $this->assertTrue($result); } + + public function testinsertIfNotExist() { + $categoryentries = array( + array('user' => 'test', 'type' => 'contact', 'category' => 'Family'), + array('user' => 'test', 'type' => 'contact', 'category' => 'Friends'), + array('user' => 'test', 'type' => 'contact', 'category' => 'Coworkers'), + array('user' => 'test', 'type' => 'contact', 'category' => 'Coworkers'), + array('user' => 'test', 'type' => 'contact', 'category' => 'School'), + ); + + foreach($categoryentries as $entry) { + $result = OC_DB::insertIfNotExist('*PREFIX*'.$this->table3, + array( + 'uid' => $entry['user'], + 'type' => $entry['type'], + 'category' => $entry['category'], + )); + $this->assertTrue($result); + } + + $query = OC_DB::prepare('SELECT * FROM *PREFIX*'.$this->table3); + $result = $query->execute(); + $this->assertTrue($result); + $this->assertEqual($result->numRows(), '4'); + } } From 0e4ed2887cb413db0e3eecdb0595a09dc3b01a0f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 13:20:08 +0200 Subject: [PATCH 17/48] Return result from OC_DB::insertIfNotExist(). --- lib/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/db.php b/lib/db.php index 6ad65201e1..f32e8549ce 100644 --- a/lib/db.php +++ b/lib/db.php @@ -587,7 +587,7 @@ class OC_DB { } $result = new PDOStatementWrapper($result); - $result->execute(); + return $result->execute(); } /** From 180326028587be3e266aa0c7d4ec9e870bd55265 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 13:21:05 +0200 Subject: [PATCH 18/48] Renamed OC_VCategories::add() to addMulti() and let the add() method return the id of the newly created category. --- lib/vcategories.php | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 22bd8a3c85..c958368238 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -74,7 +74,7 @@ class OC_VCategories { ); if($defcategories && count(self::$categories) === 0) { - $this->add($defcategories, true); + $this->addMulti($defcategories, true); } } @@ -273,13 +273,37 @@ class OC_VCategories { } /** - * @brief Add a new category name. + * @brief Add a new category. + * @param $name A string with a name of the category + * @returns int the id of the added category or false if it already exists. + */ + public function add($name) { + OCP\Util::writeLog('core', __METHOD__.', name: ' . $name, OCP\Util::DEBUG); + if($this->hasCategory($name)) { + OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', OCP\Util::DEBUG); + return false; + } + OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + )); + $id = OCP\DB::insertid(self::CATEGORY_TABLE); + OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG); + self::$categories[$id] = $name; + return $id; + } + + /** + * @brief Add a new category. * @param $names A string with a name or an array of strings containing * the name(s) of the categor(y|ies) to add. * @param $sync bool When true, save the categories + * @param $id int Optional object id to add to this|these categor(y|ies) * @returns bool Returns false on error. */ - public function add($names, $sync=false, $id = null) { + public function addMulti($names, $sync=false, $id = null) { if(!is_array($names)) { $names = array($names); } @@ -309,7 +333,7 @@ class OC_VCategories { * @param $vobject The instance of OC_VObject to load the categories from. */ public function loadFromVObject($id, $vobject, $sync=false) { - $this->add($vobject->getAsArray('CATEGORIES'), $sync, $id); + $this->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id); } /** From 394e4e4d5fe5cbd5e52df63984a67dc0786685a4 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 16:15:47 +0200 Subject: [PATCH 19/48] Removed useless ORDER BY from query. --- lib/vcategories.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index c958368238..fb315ca960 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -114,7 +114,7 @@ class OC_VCategories { public static function isEmpty($type, $user = null) { $user = is_null($user) ? OC_User::getUser() : $user; $sql = 'SELECT COUNT(*) FROM `' . self::CATEGORY_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + . 'WHERE `uid` = ? AND `type` = ?'; try { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($user, $type)); From 10e29da8be495cce0cea7aa35942bd2a92b868d8 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 17:21:23 +0200 Subject: [PATCH 20/48] Use self::prepare() instead of self::$connection->prepare. --- lib/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/db.php b/lib/db.php index f32e8549ce..ff06ec3e00 100644 --- a/lib/db.php +++ b/lib/db.php @@ -577,7 +577,7 @@ class OC_DB { //OC_Log::write('core', __METHOD__ . ', type: ' . $type . ', query: ' . $query, OC_Log::DEBUG); try { - $result=self::$connection->prepare($query); + $result = self::prepare($query); } catch(PDOException $e) { $entry = 'DB Error: "'.$e->getMessage().'"
    '; $entry .= 'Offending command was: '.$query.'
    '; From 73c743076e64384ecf7892921e9cf96ce68abdca Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 17:23:54 +0200 Subject: [PATCH 21/48] Remove index that might cause problems. --- db_structure.xml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/db_structure.xml b/db_structure.xml index 64abdff368..fe580c4a2f 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -735,23 +735,6 @@ - - uid_type_category_index - true - - uid - ascending - - - type - ascending - - - category - ascending - - - From 2456401672e4d0bf1a7042d4a25f316c1f4a9347 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 18:11:13 +0200 Subject: [PATCH 22/48] Remove redundant class wrapping. --- lib/db.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/db.php b/lib/db.php index ff06ec3e00..8472978d81 100644 --- a/lib/db.php +++ b/lib/db.php @@ -586,7 +586,6 @@ class OC_DB { die( $entry ); } - $result = new PDOStatementWrapper($result); return $result->execute(); } From fc6d1bf5006f6630f342eed92cad25167a5d4d8e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Fri, 19 Oct 2012 19:42:59 +0200 Subject: [PATCH 23/48] Clean indentation. --- db_structure.xml | 202 +++++++++++++++++++++++------------------------ 1 file changed, 101 insertions(+), 101 deletions(-) diff --git a/db_structure.xml b/db_structure.xml index fe580c4a2f..851c8aa998 100644 --- a/db_structure.xml +++ b/db_structure.xml @@ -671,125 +671,125 @@ - +
    - *dbprefix*vcategory + *dbprefix*vcategory - + - - id - integer - 0 - true - 1 - true - 4 - + + id + integer + 0 + true + 1 + true + 4 + - - uid - text - - true - 64 - + + uid + text + + true + 64 + - - type - text - - true - 64 - + + type + text + + true + 64 + - - category - text - - true - 255 - + + category + text + + true + 255 + - - uid_index - - uid - ascending - - + + uid_index + + uid + ascending + + - - type_index - - type - ascending - - + + type_index + + type + ascending + + - - category_index - - category - ascending - - + + category_index + + category + ascending + + - -
    + + - +
    - *dbprefix*vcategory_to_object + *dbprefix*vcategory_to_object - + - - objid - integer - 0 - true - true - 4 - + + objid + integer + 0 + true + true + 4 + - - categoryid - integer - 0 - true - true - 4 - + + categoryid + integer + 0 + true + true + 4 + - - type - text - - true - 64 - + + type + text + + true + 64 + - - true - true - category_object_index - - categoryid - ascending - - - objid - ascending - - - type - ascending - - + + true + true + category_object_index + + categoryid + ascending + + + objid + ascending + + + type + ascending + + - + -
    + From ab167c3e2c55895fddac50cd1c9d8d5d92b10845 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 20 Oct 2012 13:42:57 +0200 Subject: [PATCH 24/48] Filter out special Favorites category. --- lib/vcategories.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index fb315ca960..2ea70d167f 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -140,14 +140,23 @@ class OC_VCategories { if($format == self::FORMAT_MAP) { $catmap = array(); foreach($categories as $category) { - $catmap[] = array( - 'id' => $this->array_searchi($category, self::$categories), - 'name' => $category - ); + if($category !== self::CATEGORY_FAVORITE) { + $catmap[] = array( + 'id' => $this->array_searchi($category, self::$categories), + 'name' => $category + ); + } } return $catmap; } - return $categories; + + // Don't add favorites to normal categories. + $favpos = array_search(self::CATEGORY_FAVORITE, $categories); + if($favpos !== false) { + return array_splice($categories, $favpos); + } else { + return $categories; + } } /** From 26618704a924723505be7b723e90c63055017658 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sat, 20 Oct 2012 13:45:18 +0200 Subject: [PATCH 25/48] Fix accidentally creating new categories with the id as name. --- lib/vcategories.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 2ea70d167f..c220821eca 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -149,7 +149,7 @@ class OC_VCategories { } return $catmap; } - + // Don't add favorites to normal categories. $favpos = array_search(self::CATEGORY_FAVORITE, $categories); if($favpos !== false) { @@ -569,12 +569,14 @@ class OC_VCategories { */ public function addToCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; - if(is_string($category) && !$this->hasCategory($category)) { - $this->add($category, true); + if(is_string($category) && !is_numeric($category)) { + if(!$this->hasCategory($category)) { + $this->add($category, true); + } + $categoryid = $this->array_searchi($category, self::$categories); + } else { + $categoryid = $category; } - $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, self::$categories) - : $category; try { OCP\DB::insertIfNotExist(self::RELATION_TABLE, array( @@ -711,3 +713,4 @@ class OC_VCategories { } } + From 273fdb7b642b79b1d1b0d6abb31d684b6f2ed66f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 22 Oct 2012 15:40:08 +0200 Subject: [PATCH 26/48] Added type and callback arguments to most methods. --- core/js/oc-vcategories.js | 141 +++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 46 deletions(-) diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js index f08df9c069..53065933be 100644 --- a/core/js/oc-vcategories.js +++ b/core/js/oc-vcategories.js @@ -1,12 +1,13 @@ var OCCategories= { - edit:function() { - if(OCCategories.type == undefined) { - OC.dialogs.alert('OCCategories.type is not set!'); - return; + category_favorites:'_$!!$_', + edit:function(type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; } + type = type ? type : this.type; $('body').append('
    '); $('#category_dialog').load( - OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?type=' + OCCategories.type, function(response) { + OC.filePath('core', 'ajax', 'vcategories/edit.php') + '?type=' + type, function(response) { try { var jsondata = jQuery.parseJSON(response); if(response.status == 'error') { @@ -27,8 +28,8 @@ var OCCategories= { modal: true, height: 350, minHeight:200, width: 250, minWidth: 200, buttons: { - 'Close': function() { - $(this).dialog('close'); + 'Close': function() { + $(this).dialog('close'); }, 'Delete':function() { var categories = $('#categorylist').find('input:checkbox').serialize(); @@ -72,83 +73,131 @@ var OCCategories= { } }); }, - _processDeleteResult:function(jsondata, cb) { + _processDeleteResult:function(jsondata) { if(jsondata.status == 'success') { OCCategories._update(jsondata.data.categories); } else { OC.dialogs.alert(jsondata.data.message, 'Error'); } - if(typeof cb == 'function') { - cb(); - } }, favorites:function(type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; + } + type = type ? type : this.type; $.getJSON(OC.filePath('core', 'ajax', 'categories/favorites.php'), {type: type},function(jsondata) { - if(jsondata.status === 'success') { - OCCategories._update(jsondata.data.categories); + if(typeof cb == 'function') { + cb(jsondata); } else { - OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + if(jsondata.status === 'success') { + OCCategories._update(jsondata.data.categories); + } else { + OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + } } }); }, - addToFavorites:function(id, type) { + addToFavorites:function(id, type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; + } + type = type ? type : this.type; $.post(OC.filePath('core', 'ajax', 'vcategories/addToFavorites.php'), {id:id, type:type}, function(jsondata) { - if(jsondata.status !== 'success') { - OC.dialogs.alert(jsondata.data.message, 'Error'); + if(typeof cb == 'function') { + cb(jsondata); + } else { + if(jsondata.status !== 'success') { + OC.dialogs.alert(jsondata.data.message, 'Error'); + } } }); }, - removeFromFavorites:function(id, type) { + removeFromFavorites:function(id, type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; + } + type = type ? type : this.type; $.post(OC.filePath('core', 'ajax', 'vcategories/removeFromFavorites.php'), {id:id, type:type}, function(jsondata) { - if(jsondata.status !== 'success') { - OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + if(typeof cb == 'function') { + cb(jsondata); + } else { + if(jsondata.status !== 'success') { + OC.dialogs.alert(jsondata.data.message, t('core', 'Error')); + } } }); }, - doDelete:function(categories, cb) { + doDelete:function(categories, type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; + } + type = type ? type : this.type; if(categories == '' || categories == undefined) { OC.dialogs.alert(t('core', 'No categories selected for deletion.'), t('core', 'Error')); return false; } - var q = categories + '&type=' + OCCategories.type; - if(OCCategories.app) { - q += '&app=' + OCCategories.app; - $.post(OC.filePath(OCCategories.app, 'ajax', 'categories/delete.php'), q, function(jsondata) { - OCCategories._processDeleteResult(jsondata, cb) + var self = this; + var q = categories + '&type=' + type; + if(this.app) { + q += '&app=' + this.app; + $.post(OC.filePath(this.app, 'ajax', 'categories/delete.php'), q, function(jsondata) { + if(typeof cb == 'function') { + cb(jsondata); + } else { + self._processDeleteResult(jsondata); + } }); } else { $.post(OC.filePath('core', 'ajax', 'vcategories/delete.php'), q, function(jsondata) { - OCCategories._processDeleteResult(jsondata, cb) + if(typeof cb == 'function') { + cb(jsondata); + } else { + self._processDeleteResult(jsondata); + } }); } }, - add:function(category) { - $.post(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'app':OCCategories.app},function(jsondata) { - if(jsondata.status === 'success') { - OCCategories._update(jsondata.data.categories); + add:function(category, type, cb) { + if(!type && !this.type) { + throw { name: 'MissingParameter', message: t('core', 'The object type is not specified.') }; + } + type = type ? type : this.type; + $.post(OC.filePath('core', 'ajax', 'vcategories/add.php'),{'category':category, 'type':type},function(jsondata) { + if(typeof cb == 'function') { + cb(jsondata); } else { - OC.dialogs.alert(jsondata.data.message, 'Error'); + if(jsondata.status === 'success') { + OCCategories._update(jsondata.data.categories); + } else { + OC.dialogs.alert(jsondata.data.message, 'Error'); + } } }); }, - rescan:function(cb) { - $.getJSON(OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr) { - if(jsondata.status === 'success') { - OCCategories._update(jsondata.data.categories); - } else { - OC.dialogs.alert(jsondata.data.message, 'Error'); - } + rescan:function(app, cb) { + if(!app && !this.app) { + throw { name: 'MissingParameter', message: t('core', 'The app name is not specified.') }; + } + app = app ? app : this.app; + $.getJSON(OC.filePath(app, 'ajax', 'categories/rescan.php'),function(jsondata, status, xhr) { if(typeof cb == 'function') { - cb(); + cb(jsondata); + } else { + if(jsondata.status === 'success') { + OCCategories._update(jsondata.data.categories); + } else { + OC.dialogs.alert(jsondata.data.message, 'Error'); + } } }).error(function(xhr){ if (xhr.status == 404) { - OC.dialogs.alert( - t('core', 'The required file {file} is not installed!', - {file: OC.filePath(OCCategories.app, 'ajax', 'categories/rescan.php')}, t('core', 'Error'))); - } - if(typeof cb == 'function') { - cb(); + var errormessage = t('core', 'The required file {file} is not installed!', + {file: OC.filePath(app, 'ajax', 'categories/rescan.php')}, t('core', 'Error')); + if(typeof cb == 'function') { + cb({status:'error', data:{message:errormessage}}); + } else { + OC.dialogs.alert(errormessage); + } } }); }, From b5817dcc2e7a531bbd1548b4486d07be5ffdf12f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 22 Oct 2012 15:41:00 +0200 Subject: [PATCH 27/48] Added missing backtick to sql query. --- lib/vcategories.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index c220821eca..607a995cb3 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -184,7 +184,7 @@ class OC_VCategories { $ids = array(); $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . ' WHERE `categoryid` = ?'; + . '` WHERE `categoryid` = ?'; try { $stmt = OCP\DB::prepare($sql); From 2fc495a91a1c38e0fbf53f0c78d157698e7ff024 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 24 Oct 2012 22:39:34 +0200 Subject: [PATCH 28/48] Also delete category/object relations when deleting a category. --- lib/vcategories.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index ec243297a4..116c1d1cd9 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -632,9 +632,11 @@ class OC_VCategories { OC_Log::write('core', __METHOD__ . ', before: ' . print_r(self::$categories, true), OC_Log::DEBUG); foreach($names as $name) { + $id = null; OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); if($this->hasCategory($name)) { - unset(self::$categories[$this->array_searchi($name, self::$categories)]); + $id = $this->array_searchi($name, self::$categories); + unset(self::$categories[$id]); } try { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' @@ -644,6 +646,18 @@ class OC_VCategories { OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = OCP\DB::prepare($sql); + $stmt->execute(array($id)); + } catch(Exception $e) { + OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + OCP\Util::ERROR); + return false; + } + } } OC_Log::write('core', __METHOD__.', after: ' . print_r(self::$categories, true), OC_Log::DEBUG); From b434c20c18a389521bb0a30fa7c0c025bb6dd50c Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 31 Oct 2012 16:51:36 +0100 Subject: [PATCH 29/48] Added unit test testinsertIfNotExistDontOverwrite. --- tests/lib/db.php | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/tests/lib/db.php b/tests/lib/db.php index 5d30f6ac46..ead4b19b38 100644 --- a/tests/lib/db.php +++ b/tests/lib/db.php @@ -93,4 +93,41 @@ class Test_DB extends UnitTestCase { $this->assertTrue($result); $this->assertEqual($result->numRows(), '4'); } + + public function testinsertIfNotExistDontOverwrite() { + $fullname = 'fullname test'; + $uri = 'uri_1'; + $carddata = 'This is a vCard'; + + // Normal test to have same known data inserted. + $query = OC_DB::prepare('INSERT INTO *PREFIX*'.$this->table2.' (`fullname`, `uri`, `carddata`) VALUES (?, ?, ?)'); + $result = $query->execute(array($fullname, $uri, $carddata)); + $this->assertTrue($result); + $query = OC_DB::prepare('SELECT `fullname`, `uri`, `carddata` FROM *PREFIX*'.$this->table2.' WHERE `uri` = ?'); + $result = $query->execute(array($uri)); + $this->assertTrue($result); + $row = $result->fetchRow(); + $this->assertArrayHasKey('carddata', $row); + $this->assertEqual($row['carddata'], $carddata); + $this->assertEqual($result->numRows(), '1'); + + // Try to insert a new row + $result = OC_DB::insertIfNotExist('*PREFIX*'.$this->table2, + array( + 'fullname' => $fullname, + 'uri' => $uri, + )); + $this->assertTrue($result); + + $query = OC_DB::prepare('SELECT `fullname`, `uri`, `carddata` FROM *PREFIX*'.$this->table2.' WHERE `uri` = ?'); + $result = $query->execute(array($uri)); + $this->assertTrue($result); + $row = $result->fetchRow(); + $this->assertArrayHasKey('carddata', $row); + // Test that previously inserted data isn't overwritten + $this->assertEqual($row['carddata'], $carddata); + // And that a new row hasn't been inserted. + $this->assertEqual($result->numRows(), '1'); + + } } From 5a738380f6a9b5b254890830ad7ee9517eee19b3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 31 Oct 2012 20:06:39 +0100 Subject: [PATCH 30/48] Cast object ids to integers. --- lib/vcategories.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 116c1d1cd9..ee7c7c8ab1 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -197,7 +197,7 @@ class OC_VCategories { if(!is_null($result)) { while( $row = $result->fetchRow()) { - $ids[] = $row['objid']; + $ids[] = (int)$row['objid']; } } //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); @@ -565,7 +565,7 @@ class OC_VCategories { * @param int|string $category The id or name of the category * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance - * @returns boolean + * @returns boolean Returns false on database error. */ public function addToCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; From 8fc0f53a4835c139a66d49cab41c7ff541cda63d Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 31 Oct 2012 20:07:28 +0100 Subject: [PATCH 31/48] Added unit tests for OC_VCategories. --- tests/lib/vcategories.php | 114 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/lib/vcategories.php diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php new file mode 100644 index 0000000000..640fdaf48f --- /dev/null +++ b/tests/lib/vcategories.php @@ -0,0 +1,114 @@ +. +* +*/ + +//require_once("../lib/template.php"); + +class Test_VCategories extends UnitTestCase { + + protected $objectType; + protected $user; + protected $backupGlobals = FALSE; + + public function setUp() { + + OC_User::clearBackends(); + OC_User::useBackend('dummy'); + $this->user = uniqid('user_'); + $this->objectType = uniqid('type_'); + OC_User::createUser($this->user, 'pass'); + OC_User::setUserId($this->user); + + } + + public function tearDown() { + //$query = OC_DB::prepare('DELETE FROM `*PREFIX*vcategories` WHERE `item_type` = ?'); + //$query->execute(array('test')); + } + + public function testInstantiateWithDefaults() { + $defcategories = array('Friends', 'Family', 'Work', 'Other'); + + $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); + + $this->assertEqual(count($catmgr->categories()), 4); + } + + public function testAddCategories() { + $categories = array('Friends', 'Family', 'Work', 'Other'); + + $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); + + foreach($categories as $category) { + $result = $catmgr->add($category); + $this->assertTrue($result); + } + + $this->assertFalse($catmgr->add('Family')); + $this->assertFalse($catmgr->add('fAMILY')); + + $this->assertEqual(count($catmgr->categories()), 4); + } + + public function testdeleteCategories() { + $defcategories = array('Friends', 'Family', 'Work', 'Other'); + $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); + $this->assertEqual(count($catmgr->categories()), 4); + + $catmgr->delete('family'); + $this->assertEqual(count($catmgr->categories()), 3); + + $catmgr->delete(array('Friends', 'Work', 'Other')); + $this->assertEqual(count($catmgr->categories()), 0); + + } + + public function testAddToCategory() { + $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + $catmgr = new OC_VCategories($this->objectType, $this->user); + + foreach($objids as $id) { + $catmgr->addToCategory($id, 'Family'); + } + + $this->assertEqual(count($catmgr->categories()), 1); + $this->assertEqual(count($catmgr->idsForCategory('Family')), 9); + } + + public function testRemoveFromCategory() { + $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); + + // Is this "legal"? + $this->testAddToCategory(); + $catmgr = new OC_VCategories($this->objectType, $this->user); + + foreach($objids as $id) { + $this->assertTrue(in_array($id, $catmgr->idsForCategory('Family'))); + $catmgr->removeFromCategory($id, 'Family'); + $this->assertFalse(in_array($id, $catmgr->idsForCategory('Family'))); + } + + $this->assertEqual(count($catmgr->categories()), 1); + $this->assertEqual(count($catmgr->idsForCategory('Family')), 0); + } + +} From 8cffbb5f7dca943f0ecebd3d4d414b004f348f06 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 31 Oct 2012 20:47:04 +0100 Subject: [PATCH 32/48] Added some more error checking on db queries. --- lib/vcategories.php | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index ee7c7c8ab1..3660d84ee1 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -89,6 +89,9 @@ class OC_VCategories { try { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($this->user, $this->type)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); @@ -118,6 +121,10 @@ class OC_VCategories { try { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($user, $type)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } return ($result->numRows() == 0); } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), @@ -189,6 +196,10 @@ class OC_VCategories { try { $stmt = OCP\DB::prepare($sql); $result = $stmt->execute(array($catid)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); @@ -200,8 +211,6 @@ class OC_VCategories { $ids[] = (int)$row['objid']; } } - //OCP\Util::writeLog('core', __METHOD__.', count: ' . count($items), OCP\Util::DEBUG); - //OCP\Util::writeLog('core', __METHOD__.', sql: ' . $sql, OCP\Util::DEBUG); return $ids; } @@ -224,7 +233,7 @@ class OC_VCategories { * * TODO: Maybe add the getting permissions for objects? * - * @returns array containing the resulting items. + * @returns array containing the resulting items or false on error. */ public function itemsForCategory($category, $tableinfo, $limit = null, $offset = null) { $result = null; @@ -256,9 +265,14 @@ class OC_VCategories { try { $stmt = OCP\DB::prepare($sql, $limit, $offset); $result = $stmt->execute(array($catid)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); + return false; } if(!is_null($result)) { @@ -370,6 +384,10 @@ class OC_VCategories { $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); @@ -387,6 +405,10 @@ class OC_VCategories { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ?'); $result = $stmt->execute(array($this->user, $this->type)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return; + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); @@ -459,6 +481,9 @@ class OC_VCategories { $stmt = OCP\DB::prepare('SELECT `id` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ?'); $result = $stmt->execute(array($arguments['uid'])); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); @@ -485,6 +510,9 @@ class OC_VCategories { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND'); $result = $stmt->execute(array($arguments['uid'])); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); @@ -496,14 +524,18 @@ class OC_VCategories { * @param int $id The id of the object * @param string $type The type of object (event/contact/task/journal). * Defaults to the type set in the instance - * @returns boolean + * @returns boolean Returns false on error. */ public function purgeObject($id, $type = null) { $type = is_null($type) ? $this->type : $type; try { $stmt = OCP\DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `objid` = ? AND `type`= ?'); - $stmt->execute(array($id, $type)); + $result = $stmt->execute(array($id, $type)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + return false; + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); From 8509ca257f2feb55a9a545bec71574d1115afb08 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Wed, 31 Oct 2012 21:24:03 +0100 Subject: [PATCH 33/48] Switch expectation and result in unit tests. --- tests/lib/vcategories.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php index 640fdaf48f..1d188297ad 100644 --- a/tests/lib/vcategories.php +++ b/tests/lib/vcategories.php @@ -49,7 +49,7 @@ class Test_VCategories extends UnitTestCase { $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - $this->assertEqual(count($catmgr->categories()), 4); + $this->assertEqual(4, count($catmgr->categories())); } public function testAddCategories() { @@ -65,19 +65,19 @@ class Test_VCategories extends UnitTestCase { $this->assertFalse($catmgr->add('Family')); $this->assertFalse($catmgr->add('fAMILY')); - $this->assertEqual(count($catmgr->categories()), 4); + $this->assertEqual(4, count($catmgr->categories())); } public function testdeleteCategories() { $defcategories = array('Friends', 'Family', 'Work', 'Other'); $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); - $this->assertEqual(count($catmgr->categories()), 4); + $this->assertEqual(4, count($catmgr->categories())); $catmgr->delete('family'); - $this->assertEqual(count($catmgr->categories()), 3); + $this->assertEqual(3, count($catmgr->categories())); $catmgr->delete(array('Friends', 'Work', 'Other')); - $this->assertEqual(count($catmgr->categories()), 0); + $this->assertEqual(0, count($catmgr->categories())); } @@ -90,10 +90,13 @@ class Test_VCategories extends UnitTestCase { $catmgr->addToCategory($id, 'Family'); } - $this->assertEqual(count($catmgr->categories()), 1); - $this->assertEqual(count($catmgr->idsForCategory('Family')), 9); + $this->assertEqual(1, count($catmgr->categories())); + $this->assertEqual(9, count($catmgr->idsForCategory('Family'))); } + /** + * @depends testAddToCategory + */ public function testRemoveFromCategory() { $objids = array(1, 2, 3, 4, 5, 6, 7, 8, 9); @@ -107,8 +110,8 @@ class Test_VCategories extends UnitTestCase { $this->assertFalse(in_array($id, $catmgr->idsForCategory('Family'))); } - $this->assertEqual(count($catmgr->categories()), 1); - $this->assertEqual(count($catmgr->idsForCategory('Family')), 0); + $this->assertEqual(1, count($catmgr->categories())); + $this->assertEqual(0, count($catmgr->idsForCategory('Family'))); } } From 290d0714dfd4aae8e2c09194affd738de3df88f3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 1 Nov 2012 03:05:48 +0100 Subject: [PATCH 34/48] Add routes for vcategory favorites. --- core/routes.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/routes.php b/core/routes.php index cc0aa53a21..3ac943f7c6 100644 --- a/core/routes.php +++ b/core/routes.php @@ -27,6 +27,12 @@ $this->create('core_ajax_vcategories_add', '/core/ajax/vcategories/add.php') ->actionInclude('core/ajax/vcategories/add.php'); $this->create('core_ajax_vcategories_delete', '/core/ajax/vcategories/delete.php') ->actionInclude('core/ajax/vcategories/delete.php'); +$this->create('core_ajax_vcategories_addtofavorites', '/core/ajax/vcategories/addToFavorites.php') + ->actionInclude('core/ajax/vcategories/addToFavorites.php'); +$this->create('core_ajax_vcategories_removefromfavorites', '/core/ajax/vcategories/removeFromFavorites.php') + ->actionInclude('core/ajax/vcategories/removeFromFavorites.php'); +$this->create('core_ajax_vcategories_favorites', '/core/ajax/vcategories/favorites.php') + ->actionInclude('core/ajax/vcategories/favorites.php'); $this->create('core_ajax_vcategories_edit', '/core/ajax/vcategories/edit.php') ->actionInclude('core/ajax/vcategories/edit.php'); // Routing From b0ae67d5c5af56b6174815795360a7c5a4026e57 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Thu, 1 Nov 2012 03:06:20 +0100 Subject: [PATCH 35/48] Update vcategories ajax scripts. --- core/ajax/vcategories/addToFavorites.php | 2 -- core/ajax/vcategories/favorites.php | 3 --- core/ajax/vcategories/removeFromFavorites.php | 6 ++---- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/core/ajax/vcategories/addToFavorites.php b/core/ajax/vcategories/addToFavorites.php index f330d19c8a..52f62d5fc6 100644 --- a/core/ajax/vcategories/addToFavorites.php +++ b/core/ajax/vcategories/addToFavorites.php @@ -14,8 +14,6 @@ function debug($msg) { OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; - OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); diff --git a/core/ajax/vcategories/favorites.php b/core/ajax/vcategories/favorites.php index b72fc7a9fe..20accea61c 100644 --- a/core/ajax/vcategories/favorites.php +++ b/core/ajax/vcategories/favorites.php @@ -14,12 +14,9 @@ function debug($msg) { OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; - OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); - $type = isset($_GET['type']) ? $_GET['type'] : null; if(is_null($type)) { diff --git a/core/ajax/vcategories/removeFromFavorites.php b/core/ajax/vcategories/removeFromFavorites.php index f779df48f2..ba6e95c249 100644 --- a/core/ajax/vcategories/removeFromFavorites.php +++ b/core/ajax/vcategories/removeFromFavorites.php @@ -7,15 +7,13 @@ */ function bailOut($msg) { OC_JSON::error(array('data' => array('message' => $msg))); - OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('core', 'ajax/vcategories/removeFromFavorites.php: '.$msg, OC_Log::DEBUG); exit(); } function debug($msg) { - OC_Log::write('core', 'ajax/vcategories/addToFavorites.php: '.$msg, OC_Log::DEBUG); + OC_Log::write('core', 'ajax/vcategories/removeFromFavorites.php: '.$msg, OC_Log::DEBUG); } -require_once '../../../lib/base.php'; - OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); From 4648dcfa466ca366ea50178e6b3ab9d7e7568ba6 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 4 Nov 2012 12:09:04 +0100 Subject: [PATCH 36/48] VCategories: Use correct variable. --- core/js/oc-vcategories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/js/oc-vcategories.js b/core/js/oc-vcategories.js index 53065933be..609703f2cc 100644 --- a/core/js/oc-vcategories.js +++ b/core/js/oc-vcategories.js @@ -17,7 +17,7 @@ var OCCategories= { } catch(e) { var setEnabled = function(d, enable) { if(enable) { - dlg.css('cursor', 'default').find('input,button:not(#category_addbutton)') + d.css('cursor', 'default').find('input,button:not(#category_addbutton)') .prop('disabled', false).css('cursor', 'default'); } else { d.css('cursor', 'wait').find('input,button:not(#category_addbutton)') From 7c67d2fdd61eb7e3cb3cf769613d3e7b644f7cbc Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 4 Nov 2012 12:09:54 +0100 Subject: [PATCH 37/48] VCategories: Swap expected and actual in unit tests. --- tests/lib/db.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/lib/db.php b/tests/lib/db.php index ead4b19b38..e73b30e213 100644 --- a/tests/lib/db.php +++ b/tests/lib/db.php @@ -108,8 +108,8 @@ class Test_DB extends UnitTestCase { $this->assertTrue($result); $row = $result->fetchRow(); $this->assertArrayHasKey('carddata', $row); - $this->assertEqual($row['carddata'], $carddata); - $this->assertEqual($result->numRows(), '1'); + $this->assertEqual($carddata, $row['carddata']); + $this->assertEqual('1', $result->numRows()); // Try to insert a new row $result = OC_DB::insertIfNotExist('*PREFIX*'.$this->table2, @@ -125,9 +125,9 @@ class Test_DB extends UnitTestCase { $row = $result->fetchRow(); $this->assertArrayHasKey('carddata', $row); // Test that previously inserted data isn't overwritten - $this->assertEqual($row['carddata'], $carddata); + $this->assertEqual($carddata, $row['carddata']); // And that a new row hasn't been inserted. - $this->assertEqual($result->numRows(), '1'); + $this->assertEqual('1', $result->numRows()); } } From 8e5b6bf21d14b6022e543869cba503bb582b1cb5 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 4 Nov 2012 12:24:49 +0100 Subject: [PATCH 38/48] VCategories: Make $categories non-static again. --- lib/vcategories.php | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index 3660d84ee1..b7a9ee175f 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -37,7 +37,7 @@ class OC_VCategories { /** * Categories */ - private static $categories = array(); + private $categories = array(); /** * Used for storing objectid/categoryname pairs while rescanning. @@ -69,11 +69,11 @@ class OC_VCategories { $this->loadCategories(); OCP\Util::writeLog('core', __METHOD__ . ', categories: ' - . print_r(self::$categories, true), + . print_r($this->categories, true), OCP\Util::DEBUG ); - if($defcategories && count(self::$categories) === 0) { + if($defcategories && count($this->categories) === 0) { $this->addMulti($defcategories, true); } } @@ -82,7 +82,7 @@ class OC_VCategories { * @brief Load categories from db. */ private function loadCategories() { - self::$categories = array(); + $this->categories = array(); $result = null; $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; @@ -100,10 +100,10 @@ class OC_VCategories { if(!is_null($result)) { while( $row = $result->fetchRow()) { // The keys are prefixed because array_search wouldn't work otherwise :-/ - self::$categories[$row['id']] = $row['category']; + $this->categories[$row['id']] = $row['category']; } } - OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r(self::$categories, true), + OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true), OCP\Util::DEBUG); } @@ -139,17 +139,17 @@ class OC_VCategories { * @returns array containing the categories as strings. */ public function categories($format = null) { - if(!self::$categories) { + if(!$this->categories) { return array(); } - $categories = array_values(self::$categories); + $categories = array_values($this->categories); uasort($categories, 'strnatcasecmp'); if($format == self::FORMAT_MAP) { $catmap = array(); foreach($categories as $category) { if($category !== self::CATEGORY_FAVORITE) { $catmap[] = array( - 'id' => $this->array_searchi($category, self::$categories), + 'id' => $this->array_searchi($category, $this->categories), 'name' => $category ); } @@ -179,7 +179,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { - $catid = $this->array_searchi($category, self::$categories); + $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); if($catid === false) { @@ -240,7 +240,7 @@ class OC_VCategories { if(is_numeric($category)) { $catid = $category; } elseif(is_string($category)) { - $catid = $this->array_searchi($category, self::$categories); + $catid = $this->array_searchi($category, $this->categories); } OCP\Util::writeLog('core', __METHOD__.', category: '.$catid.' '.$category, OCP\Util::DEBUG); if($catid === false) { @@ -292,7 +292,7 @@ class OC_VCategories { * @returns bool */ public function hasCategory($name) { - return $this->in_arrayi($name, self::$categories); + return $this->in_arrayi($name, $this->categories); } /** @@ -314,7 +314,7 @@ class OC_VCategories { )); $id = OCP\DB::insertid(self::CATEGORY_TABLE); OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, OCP\Util::DEBUG); - self::$categories[$id] = $name; + $this->categories[$id] = $name; return $id; } @@ -334,7 +334,7 @@ class OC_VCategories { $newones = array(); foreach($names as $name) { if(($this->in_arrayi( - $name, self::$categories) == false) && $name != '') { + $name, $this->categories) == false) && $name != '') { $newones[] = $name; } if(!is_null($id) ) { @@ -343,7 +343,7 @@ class OC_VCategories { } } if(count($newones) > 0) { - self::$categories = array_merge(self::$categories, $newones); + $this->categories = array_merge($this->categories, $newones); if($sync === true) { $this->save(); } @@ -414,7 +414,7 @@ class OC_VCategories { . $e->getMessage(), OCP\Util::ERROR); return; } - self::$categories = array(); + $this->categories = array(); } // Parse all the VObjects foreach($objects as $object) { @@ -434,8 +434,8 @@ class OC_VCategories { * @brief Save the list with categories */ private function save() { - if(is_array(self::$categories)) { - foreach(self::$categories as $category) { + if(is_array($this->categories)) { + foreach($this->categories as $category) { OCP\DB::insertIfNotExist(self::CATEGORY_TABLE, array( 'uid' => $this->user, @@ -447,7 +447,7 @@ class OC_VCategories { $this->loadCategories(); // Loop through temporarily cached objectid/categoryname pairs // and save relations. - $categories = self::$categories; + $categories = $this->categories; // For some reason this is needed or array_search(i) will return 0..? ksort($categories); foreach(self::$relations as $relation) { @@ -464,8 +464,8 @@ class OC_VCategories { } self::$relations = array(); // reset } else { - OC_Log::write('core', __METHOD__.', self::$categories is not an array! ' - . print_r(self::$categories, true), OC_Log::ERROR); + OC_Log::write('core', __METHOD__.', $this->categories is not an array! ' + . print_r($this->categories, true), OC_Log::ERROR); } } @@ -605,7 +605,7 @@ class OC_VCategories { if(!$this->hasCategory($category)) { $this->add($category, true); } - $categoryid = $this->array_searchi($category, self::$categories); + $categoryid = $this->array_searchi($category, $this->categories); } else { $categoryid = $category; } @@ -635,7 +635,7 @@ class OC_VCategories { public function removeFromCategory($objid, $category, $type = null) { $type = is_null($type) ? $this->type : $type; $categoryid = (is_string($category) && !is_numeric($category)) - ? $this->array_searchi($category, self::$categories) + ? $this->array_searchi($category, $this->categories) : $category; try { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' @@ -662,13 +662,13 @@ class OC_VCategories { $names = array($names); } OC_Log::write('core', __METHOD__ . ', before: ' - . print_r(self::$categories, true), OC_Log::DEBUG); + . print_r($this->categories, true), OC_Log::DEBUG); foreach($names as $name) { $id = null; OC_Log::write('core', __METHOD__.', '.$name, OC_Log::DEBUG); if($this->hasCategory($name)) { - $id = $this->array_searchi($name, self::$categories); - unset(self::$categories[$id]); + $id = $this->array_searchi($name, $this->categories); + unset($this->categories[$id]); } try { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' @@ -692,7 +692,7 @@ class OC_VCategories { } } OC_Log::write('core', __METHOD__.', after: ' - . print_r(self::$categories, true), OC_Log::DEBUG); + . print_r($this->categories, true), OC_Log::DEBUG); if(!is_null($objects)) { foreach($objects as $key=>&$value) { $vobject = OC_VObject::parse($value[1]); From 88b91a7304f2de998f71a674f4f62e85f5b83e54 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Sun, 4 Nov 2012 12:33:32 +0100 Subject: [PATCH 39/48] Swap expected and actual. --- tests/lib/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/db.php b/tests/lib/db.php index e73b30e213..c2eb38dae8 100644 --- a/tests/lib/db.php +++ b/tests/lib/db.php @@ -91,7 +91,7 @@ class Test_DB extends UnitTestCase { $query = OC_DB::prepare('SELECT * FROM *PREFIX*'.$this->table3); $result = $query->execute(); $this->assertTrue($result); - $this->assertEqual($result->numRows(), '4'); + $this->assertEqual('4', $result->numRows()); } public function testinsertIfNotExistDontOverwrite() { From a50f98606de9ff43b7c8185609af92d48295ae71 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 5 Nov 2012 16:24:16 +0100 Subject: [PATCH 40/48] Check DB result. --- lib/vcategories.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/vcategories.php b/lib/vcategories.php index bae9e3d039..406a4eb107 100644 --- a/lib/vcategories.php +++ b/lib/vcategories.php @@ -675,6 +675,9 @@ class OC_VCategories { $stmt = OCP\DB::prepare('DELETE FROM `' . self::CATEGORY_TABLE . '` WHERE ' . '`uid` = ? AND `type` = ? AND `category` = ?'); $result = $stmt->execute(array($this->user, $this->type, $name)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__ . ', exception: ' . $e->getMessage(), OCP\Util::ERROR); @@ -684,7 +687,10 @@ class OC_VCategories { $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' . 'WHERE `categoryid` = ?'; $stmt = OCP\DB::prepare($sql); - $stmt->execute(array($id)); + $result = $stmt->execute(array($id)); + if (OC_DB::isError($result)) { + OC_Log::write('core', __METHOD__. 'DB error: ' . OC_DB::getErrorMessage($result), OC_Log::ERROR); + } } catch(Exception $e) { OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), OCP\Util::ERROR); From 831c2cac1ef0e6475a8a9cc73bafe116e13e91f6 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 5 Nov 2012 16:29:44 +0100 Subject: [PATCH 41/48] Remove unused variable. --- tests/lib/vcategories.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/vcategories.php b/tests/lib/vcategories.php index 1d188297ad..63516a063d 100644 --- a/tests/lib/vcategories.php +++ b/tests/lib/vcategories.php @@ -55,7 +55,7 @@ class Test_VCategories extends UnitTestCase { public function testAddCategories() { $categories = array('Friends', 'Family', 'Work', 'Other'); - $catmgr = new OC_VCategories($this->objectType, $this->user, $defcategories); + $catmgr = new OC_VCategories($this->objectType, $this->user); foreach($categories as $category) { $result = $catmgr->add($category); From 3c59bc41d7a83c6811f55ac7986ac77743e60d9e Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 5 Nov 2012 16:32:20 +0100 Subject: [PATCH 42/48] VCategories: Line too long. --- core/ajax/vcategories/delete.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/ajax/vcategories/delete.php b/core/ajax/vcategories/delete.php index 057c9bb0e9..dfec378574 100644 --- a/core/ajax/vcategories/delete.php +++ b/core/ajax/vcategories/delete.php @@ -27,7 +27,9 @@ if(is_null($type)) { bailOut($l->t('Object type not provided.')); } -debug('The application using category type "' . $type . '" uses the default file for deletion. OC_VObjects will not be updated.'); +debug('The application using category type "' + . $type + . '" uses the default file for deletion. OC_VObjects will not be updated.'); if(is_null($categories)) { bailOut($l->t('No categories selected for deletion.')); From 8c492a86fce1b280a4e1be1108a3037fc8881f25 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 5 Nov 2012 16:35:25 +0100 Subject: [PATCH 43/48] VCategories: Line too long. --- core/templates/edit_categories_dialog.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/templates/edit_categories_dialog.php b/core/templates/edit_categories_dialog.php index 8997fa586b..7144896571 100644 --- a/core/templates/edit_categories_dialog.php +++ b/core/templates/edit_categories_dialog.php @@ -11,6 +11,9 @@ $categories = isset($_['categories'])?$_['categories']:array(); -
    +
    + + +
    From be77d81152b584834c90e517ec6ce4271c519fd3 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 5 Nov 2012 16:38:23 +0100 Subject: [PATCH 44/48] VCategories: Closing brace must be on a line by itself. --- core/templates/edit_categories_dialog.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/templates/edit_categories_dialog.php b/core/templates/edit_categories_dialog.php index 7144896571..d0b7b5ee62 100644 --- a/core/templates/edit_categories_dialog.php +++ b/core/templates/edit_categories_dialog.php @@ -6,9 +6,9 @@ $categories = isset($_['categories'])?$_['categories']:array();
      - +
    • - +
    From 42b871dcf1353ceddf9d98a960b133fecddbff6f Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 12 Nov 2012 18:45:56 +0100 Subject: [PATCH 45/48] Correct SQL syntax. --- lib/db.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/db.php b/lib/db.php index 48e0ec82da..2ed624cdd7 100644 --- a/lib/db.php +++ b/lib/db.php @@ -559,7 +559,7 @@ class OC_DB { $query = ''; // differences in escaping of table names ('`' for mysql) and getting the current timestamp if( $type == 'sqlite' || $type == 'sqlite3' ) { - $query = 'REPLACE OR INSERT INTO "' . $table . '" ("' + $query = 'INSERT OR REPLACE INTO "' . $table . '" ("' . implode('","', array_keys($input)) . '") VALUES("' . implode('","', array_values($input)) . '")'; } elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql') { From d809efc1e5a90ee6e699620ce7081ad4c34876c2 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 12 Nov 2012 23:34:02 +0100 Subject: [PATCH 46/48] Change insertIfNotExist() for sqlite. Not fast, but more reliable than previous attempt. --- lib/db.php | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/lib/db.php b/lib/db.php index 2ed624cdd7..de42626563 100644 --- a/lib/db.php +++ b/lib/db.php @@ -543,8 +543,9 @@ class OC_DB { /** * @brief Insert a row if a matching row doesn't exists. - * @returns true/false - * + * @param string $table. The table to insert into in the form '*PREFIX*tableName' + * @param array $input. An array of fieldname/value pairs + * @returns The return value from PDOStatementWrapper->execute() */ public static function insertIfNotExist($table, $input) { self::connect(); @@ -559,30 +560,53 @@ class OC_DB { $query = ''; // differences in escaping of table names ('`' for mysql) and getting the current timestamp if( $type == 'sqlite' || $type == 'sqlite3' ) { - $query = 'INSERT OR REPLACE INTO "' . $table . '" ("' - . implode('","', array_keys($input)) . '") VALUES("' - . implode('","', array_values($input)) . '")'; + // NOTE: For SQLite we have to use this clumsy approach + // otherwise all fieldnames used must have a unique key. + $query = 'SELECT * FROM "' . $table . '" WHERE '; + foreach($input as $key => $value) { + $query .= $key . " = '" . $value . '\' AND '; + } + $query = substr($query, 0, strlen($query) - 5); + try { + $stmt = self::prepare($query); + $result = $stmt->execute(); + } catch(PDOException $e) { + $entry = 'DB Error: "'.$e->getMessage() . '"
    '; + $entry .= 'Offending command was: ' . $query . '
    '; + OC_Log::write('core', $entry, OC_Log::FATAL); + error_log('DB error: '.$entry); + die( $entry ); + } + + if($result->numRows() == 0) { + $query = 'INSERT INTO "' . $table . '" ("' + . implode('","', array_keys($input)) . '") VALUES("' + . implode('","', array_values($input)) . '")'; + } else { + return true; + } } elseif( $type == 'pgsql' || $type == 'oci' || $type == 'mysql') { - $query = 'INSERT INTO `' .$table . '` (' - . implode(',', array_keys($input)) . ') SELECT \'' + $query = 'INSERT INTO `' .$table . '` (' + . implode(',', array_keys($input)) . ') SELECT \'' . implode('\',\'', array_values($input)) . '\' FROM ' . $table . ' WHERE '; - + foreach($input as $key => $value) { $query .= $key . " = '" . $value . '\' AND '; } $query = substr($query, 0, strlen($query) - 5); $query .= ' HAVING COUNT(*) = 0'; } + // TODO: oci should be use " (quote) instead of ` (backtick). //OC_Log::write('core', __METHOD__ . ', type: ' . $type . ', query: ' . $query, OC_Log::DEBUG); try { $result = self::prepare($query); } catch(PDOException $e) { - $entry = 'DB Error: "'.$e->getMessage().'"
    '; - $entry .= 'Offending command was: '.$query.'
    '; - OC_Log::write('core', $entry,OC_Log::FATAL); - error_log('DB error: '.$entry); + $entry = 'DB Error: "'.$e->getMessage() . '"
    '; + $entry .= 'Offending command was: ' . $query.'
    '; + OC_Log::write('core', $entry, OC_Log::FATAL); + error_log('DB error: ' . $entry); die( $entry ); } From c127c78df498214ed03982c9a406d8c52135123b Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Mon, 12 Nov 2012 23:35:42 +0100 Subject: [PATCH 47/48] Don't use indexes in test data as postgres complains over duplicate keys. --- tests/data/db_structure.xml | 41 ------------------------------------- 1 file changed, 41 deletions(-) diff --git a/tests/data/db_structure.xml b/tests/data/db_structure.xml index 8a80819adf..af2e5ce343 100644 --- a/tests/data/db_structure.xml +++ b/tests/data/db_structure.xml @@ -175,47 +175,6 @@ 255 - - uid_index - - uid - ascending - - - - - type_index - - type - ascending - - - - - category_index - - category - ascending - - - - - uid_type_category_index - true - - uid - ascending - - - type - ascending - - - category - ascending - - - From bfb6faa85077ef8f7e56a7e706f57587460a2125 Mon Sep 17 00:00:00 2001 From: Thomas Tanghus Date: Tue, 13 Nov 2012 12:11:18 +0100 Subject: [PATCH 48/48] Bump version to trigger update. --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/util.php b/lib/util.php index 73b72bad1a..da57b226ba 100755 --- a/lib/util.php +++ b/lib/util.php @@ -95,7 +95,7 @@ class OC_Util { */ public static function getVersion() { // hint: We only can count up. So the internal version number of ownCloud 4.5 will be 4.90.0. This is not visible to the user - return array(4, 91, 00); + return array(4, 91, 01); } /**