From: Thomas Müller Date: Mon, 30 Sep 2013 14:39:03 +0000 (+0200) Subject: reorganize file in lib X-Git-Tag: v6.0.0alpha2~116^2~2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8e0060405dd585a33f58d6a5520532726b3af5d6;p=nextcloud-server.git reorganize file in lib --- diff --git a/lib/connector/sabre/aborteduploaddetectionplugin.php b/lib/connector/sabre/aborteduploaddetectionplugin.php deleted file mode 100644 index 15dca3a6809..00000000000 --- a/lib/connector/sabre/aborteduploaddetectionplugin.php +++ /dev/null @@ -1,101 +0,0 @@ - - * This file is licensed under the Affero General Public License version 3 or - * later. - * See the COPYING-README file. - */ - -/** - * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin - * - * This plugin will verify if the uploaded data has been stored completely. - * This is done by comparing the content length of the request with the file size on storage. - */ -class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPlugin { - - /** - * Reference to main server object - * - * @var Sabre_DAV_Server - */ - private $server; - - /** - * is kept public to allow overwrite for unit testing - * - * @var \OC\Files\View - */ - public $fileView; - - /** - * This initializes the plugin. - * - * This function is called by Sabre_DAV_Server, after - * addPlugin is called. - * - * This method should set up the requires event subscriptions. - * - * @param Sabre_DAV_Server $server - */ - public function initialize(Sabre_DAV_Server $server) { - - $this->server = $server; - - $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10); - $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10); - } - - /** - * @param $filePath - * @param Sabre_DAV_INode $node - * @throws Sabre_DAV_Exception_BadRequest - */ - public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { - - // ownCloud chunked upload will be handled in its own plugin - $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); - if ($chunkHeader) { - return; - } - - // compare expected and actual size - $expected = $this->getLength(); - if (!$expected) { - return; - } - $actual = $this->getFileView()->filesize($filePath); - if ($actual != $expected) { - $this->getFileView()->unlink($filePath); - throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); - } - - } - - /** - * @return string - */ - public function getLength() - { - $req = $this->server->httpRequest; - $length = $req->getHeader('X-Expected-Entity-Length'); - if (!$length) { - $length = $req->getHeader('Content-Length'); - } - - return $length; - } - - /** - * @return \OC\Files\View - */ - public function getFileView() - { - if (is_null($this->fileView)) { - // initialize fileView - $this->fileView = \OC\Files\Filesystem::getView(); - } - - return $this->fileView; - } -} diff --git a/lib/private/connector/sabre/aborteduploaddetectionplugin.php b/lib/private/connector/sabre/aborteduploaddetectionplugin.php new file mode 100644 index 00000000000..15dca3a6809 --- /dev/null +++ b/lib/private/connector/sabre/aborteduploaddetectionplugin.php @@ -0,0 +1,101 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Class OC_Connector_Sabre_AbortedUploadDetectionPlugin + * + * This plugin will verify if the uploaded data has been stored completely. + * This is done by comparing the content length of the request with the file size on storage. + */ +class OC_Connector_Sabre_AbortedUploadDetectionPlugin extends Sabre_DAV_ServerPlugin { + + /** + * Reference to main server object + * + * @var Sabre_DAV_Server + */ + private $server; + + /** + * is kept public to allow overwrite for unit testing + * + * @var \OC\Files\View + */ + public $fileView; + + /** + * This initializes the plugin. + * + * This function is called by Sabre_DAV_Server, after + * addPlugin is called. + * + * This method should set up the requires event subscriptions. + * + * @param Sabre_DAV_Server $server + */ + public function initialize(Sabre_DAV_Server $server) { + + $this->server = $server; + + $server->subscribeEvent('afterCreateFile', array($this, 'verifyContentLength'), 10); + $server->subscribeEvent('afterWriteContent', array($this, 'verifyContentLength'), 10); + } + + /** + * @param $filePath + * @param Sabre_DAV_INode $node + * @throws Sabre_DAV_Exception_BadRequest + */ + public function verifyContentLength($filePath, Sabre_DAV_INode $node = null) { + + // ownCloud chunked upload will be handled in its own plugin + $chunkHeader = $this->server->httpRequest->getHeader('OC-Chunked'); + if ($chunkHeader) { + return; + } + + // compare expected and actual size + $expected = $this->getLength(); + if (!$expected) { + return; + } + $actual = $this->getFileView()->filesize($filePath); + if ($actual != $expected) { + $this->getFileView()->unlink($filePath); + throw new Sabre_DAV_Exception_BadRequest('expected filesize ' . $expected . ' got ' . $actual); + } + + } + + /** + * @return string + */ + public function getLength() + { + $req = $this->server->httpRequest; + $length = $req->getHeader('X-Expected-Entity-Length'); + if (!$length) { + $length = $req->getHeader('Content-Length'); + } + + return $length; + } + + /** + * @return \OC\Files\View + */ + public function getFileView() + { + if (is_null($this->fileView)) { + // initialize fileView + $this->fileView = \OC\Files\Filesystem::getView(); + } + + return $this->fileView; + } +} diff --git a/lib/private/tagmanager.php b/lib/private/tagmanager.php new file mode 100644 index 00000000000..9a371a11253 --- /dev/null +++ b/lib/private/tagmanager.php @@ -0,0 +1,68 @@ + +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ + +/** + * Factory class creating instances of \OCP\ITags + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class TagManager implements \OCP\ITagManager { + + /** + * User + * + * @var string + */ + private $user = null; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user) { + + $this->user = $user; + + } + + /** + * Create a new \OCP\ITags instance and load tags from db. + * + * @see \OCP\ITags + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + * @return \OCP\ITags + */ + public function load($type, $defaultTags=array()) { + return new Tags($this->user, $type, $defaultTags); + } + +} \ No newline at end of file diff --git a/lib/private/tags.php b/lib/private/tags.php new file mode 100644 index 00000000000..9fdb35a7d6e --- /dev/null +++ b/lib/private/tags.php @@ -0,0 +1,642 @@ + +* @copyright 2012 Bart Visscher bartv@thisnet.nl +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see . +* +*/ + +/** + * Class for easily tagging objects by their id + * + * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or + * anything else that is either parsed from a vobject or that the user chooses + * to add. + * Tag names are not case-sensitive, but will be saved with the case they + * are entered in. If a user already has a tag 'family' for a type, and + * tries to add a tag named 'Family' it will be silently ignored. + */ + +namespace OC; + +class Tags implements \OCP\ITags { + + /** + * Tags + * + * @var array + */ + private $tags = array(); + + /** + * Used for storing objectid/categoryname pairs while rescanning. + * + * @var array + */ + private static $relations = array(); + + /** + * Type + * + * @var string + */ + private $type = null; + + /** + * User + * + * @var string + */ + private $user = null; + + const TAG_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const TAG_FAVORITE = '_$!!$_'; + + /** + * Constructor. + * + * @param string $user The user whos data the object will operate on. + */ + public function __construct($user, $type, $defaultTags = array()) { + $this->user = $user; + $this->type = $type; + $this->loadTags($defaultTags); + } + + /** + * Load tags from db. + * + * @param string $type The type identifier e.g. 'contact' or 'event'. + * @param array $defaultTags An array of default tags to be used if none are stored. + */ + protected function loadTags($defaultTags=array()) { + $this->tags = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + + if(!is_null($result)) { + while( $row = $result->fetchRow()) { + $this->tags[$row['id']] = $row['category']; + } + } + + if(count($defaultTags) > 0 && count($this->tags) === 0) { + $this->addMultiple($defaultTags, true); + } + \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), + \OCP\Util::DEBUG); + + } + + /** + * Check if any tags are saved for this type and user. + * + * @return boolean. + */ + public function isEmpty() { + $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($this->user, $this->type)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + return ((int)$result->fetchOne() === 0); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + + /** + * Get the tags for a specific user. + * + * This returns an array with id/name maps: + * [ + * ['id' => 0, 'name' = 'First tag'], + * ['id' => 1, 'name' = 'Second tag'], + * ] + * + * @return array + */ + public function getTags() { + if(!count($this->tags)) { + return array(); + } + + $tags = array_values($this->tags); + uasort($tags, 'strnatcasecmp'); + $tagMap = array(); + + foreach($tags as $tag) { + if($tag !== self::TAG_FAVORITE) { + $tagMap[] = array( + 'id' => $this->array_searchi($tag, $this->tags), + 'name' => $tag + ); + } + } + return $tagMap; + + } + + /** + * Get the a list if items tagged with $tag. + * + * Throws an exception if the tag could not be found. + * + * @param string|integer $tag Tag id or name. + * @return array An array of object ids or false on error. + */ + public function getIdsForTag($tag) { + $result = null; + if(is_numeric($tag)) { + $tagId = $tag; + } elseif(is_string($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } + + if($tagId === false) { + $l10n = \OC_L10N::get('core'); + throw new \Exception( + $l10n->t('Could not find category "%s"', $tag) + ); + } + + $ids = array(); + $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE + . '` WHERE `categoryid` = ?'; + + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($tagId)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } 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[] = (int)$row['objid']; + } + } + + return $ids; + } + + /** + * Checks whether a tag is already saved. + * + * @param string $name The name to check for. + * @return bool + */ + public function hasTag($name) { + return $this->in_arrayi($name, $this->tags); + } + + /** + * Add a new tag. + * + * @param string $name A string with a name of the tag + * @return int the id of the added tag or false if it already exists. + */ + public function add($name) { + $name = trim($name); + + if($this->hasTag($name)) { + \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); + return false; + } + try { + $result = \OCP\DB::insertIfNotExist( + self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $name, + ) + ); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } elseif((int)$result === 0) { + \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $id = \OCP\DB::insertid(self::TAG_TABLE); + \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); + $this->tags[$id] = $name; + return $id; + } + + /** + * Rename tag. + * + * @param string $from The name of the existing tag + * @param string $to The new name of the tag. + * @return bool + */ + public function rename($from, $to) { + $from = trim($from); + $to = trim($to); + $id = $this->array_searchi($from, $this->tags); + if($id === false) { + \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); + return false; + } + + $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' + . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; + try { + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($to, $this->user, $this->type, $id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + $this->tags[$id] = $to; + return true; + } + + /** + * Add a list of new tags. + * + * @param string[] $names A string with a name or an array of strings containing + * the name(s) of the to add. + * @param bool $sync When true, save the tags + * @param int|null $id int Optional object id to add to this|these tag(s) + * @return bool Returns false on error. + */ + public function addMultiple($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->tags) == false) && $name !== '') { + $newones[] = $name; + } + if(!is_null($id) ) { + // Insert $objectid, $categoryid pairs if not exist. + self::$relations[] = array('objid' => $id, 'tag' => $name); + } + } + $this->tags = array_merge($this->tags, $newones); + if($sync === true) { + $this->save(); + } + + return true; + } + + /** + * Save the list of tags and their object relations + */ + protected function save() { + if(is_array($this->tags)) { + foreach($this->tags as $tag) { + try { + \OCP\DB::insertIfNotExist(self::TAG_TABLE, + array( + 'uid' => $this->user, + 'type' => $this->type, + 'category' => $tag, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + // reload tags to get the proper ids. + $this->loadTags(); + // Loop through temporarily cached objectid/tagname pairs + // and save relations. + $tags = $this->tags; + // For some reason this is needed or array_search(i) will return 0..? + ksort($tags); + foreach(self::$relations as $relation) { + $tagId = $this->array_searchi($relation['tag'], $tags); + \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); + if($tagId) { + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $relation['objid'], + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + } + } + } + self::$relations = array(); // reset + } else { + \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' + . print_r($this->tags, true), \OCP\Util::ERROR); + } + } + + /** + * Delete tags and tag/object relations for a user. + * + * For hooking up on post_deleteUser + * + * @param array + */ + public static function post_deleteUser($arguments) { + // Find all objectid/tagId pairs. + $result = null; + try { + $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } 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 `' . self::RELATION_TABLE . '` ' + . '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 `' . self::TAG_TABLE . '` ' + . 'WHERE `uid` = ?'); + $result = $stmt->execute(array($arguments['uid'])); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + } + } + + /** + * Delete tag/object relations from the db + * + * @param array $ids The ids of the objects + * @return boolean Returns false on error. + */ + public function purgeObjects(array $ids) { + if(count($ids) === 0) { + // job done ;) + return true; + } + $updates = $ids; + try { + $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; + $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; + $query .= 'AND `type`= ?'; + $updates[] = $this->type; + $stmt = \OCP\DB::prepare($query); + $result = $stmt->execute($updates); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Get favorites for an object type + * + * @return array An array of object ids. + */ + public function getFavorites() { + try { + return $this->getIdsForTag(self::TAG_FAVORITE); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), + \OCP\Util::ERROR); + return array(); + } + } + + /** + * Add an object to favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function addToFavorites($objid) { + if(!$this->hasTag(self::TAG_FAVORITE)) { + $this->add(self::TAG_FAVORITE, true); + } + return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Remove an object from favorites + * + * @param int $objid The id of the object + * @return boolean + */ + public function removeFromFavorites($objid) { + return $this->unTag($objid, self::TAG_FAVORITE, $this->type); + } + + /** + * Creates a tag/object relation. + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean Returns false on database error. + */ + public function tagAs($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + if(!$this->hasTag($tag)) { + $this->add($tag, true); + } + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + try { + \OCP\DB::insertIfNotExist(self::RELATION_TABLE, + array( + 'objid' => $objid, + 'categoryid' => $tagId, + 'type' => $this->type, + )); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete single tag/object relation from the db + * + * @param int $objid The id of the object + * @param int|string $tag The id or name of the tag + * @return boolean + */ + public function unTag($objid, $tag) { + if(is_string($tag) && !is_numeric($tag)) { + $tag = trim($tag); + $tagId = $this->array_searchi($tag, $this->tags); + } else { + $tagId = $tag; + } + + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; + $stmt = \OCP\DB::prepare($sql); + $stmt->execute(array($objid, $tagId, $this->type)); + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + return true; + } + + /** + * Delete tags from the + * + * @param string[] $names An array of tags to delete + * @return bool Returns false on error + */ + public function delete($names) { + if(!is_array($names)) { + $names = array($names); + } + + $names = array_map('trim', $names); + + \OCP\Util::writeLog('core', __METHOD__ . ', before: ' + . print_r($this->tags, true), \OCP\Util::DEBUG); + foreach($names as $name) { + $id = null; + + if($this->hasTag($name)) { + $id = $this->array_searchi($name, $this->tags); + unset($this->tags[$id]); + } + try { + $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' + . '`uid` = ? AND `type` = ? AND `category` = ?'); + $result = $stmt->execute(array($this->user, $this->type, $name)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' + . $e->getMessage(), \OCP\Util::ERROR); + return false; + } + if(!is_null($id) && $id !== false) { + try { + $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' + . 'WHERE `categoryid` = ?'; + $stmt = \OCP\DB::prepare($sql); + $result = $stmt->execute(array($id)); + if (\OCP\DB::isError($result)) { + \OCP\Util::writeLog('core', + __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), + \OCP\Util::ERROR); + return false; + } + } catch(\Exception $e) { + \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), + \OCP\Util::ERROR); + return false; + } + } + } + return true; + } + + // case-insensitive in_array + private function in_arrayi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return in_array(strtolower($needle), array_map('strtolower', $haystack)); + } + + // case-insensitive array_search + private function array_searchi($needle, $haystack) { + if(!is_array($haystack)) { + return false; + } + return array_search(strtolower($needle), array_map('strtolower', $haystack)); + } +} diff --git a/lib/tagmanager.php b/lib/tagmanager.php deleted file mode 100644 index 9a371a11253..00000000000 --- a/lib/tagmanager.php +++ /dev/null @@ -1,68 +0,0 @@ - -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see . -* -*/ - -/** - * Factory class creating instances of \OCP\ITags - * - * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Tag names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a tag 'family' for a type, and - * tries to add a tag named 'Family' it will be silently ignored. - */ - -namespace OC; - -class TagManager implements \OCP\ITagManager { - - /** - * User - * - * @var string - */ - private $user = null; - - /** - * Constructor. - * - * @param string $user The user whos data the object will operate on. - */ - public function __construct($user) { - - $this->user = $user; - - } - - /** - * Create a new \OCP\ITags instance and load tags from db. - * - * @see \OCP\ITags - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - * @return \OCP\ITags - */ - public function load($type, $defaultTags=array()) { - return new Tags($this->user, $type, $defaultTags); - } - -} \ No newline at end of file diff --git a/lib/tags.php b/lib/tags.php deleted file mode 100644 index 9fdb35a7d6e..00000000000 --- a/lib/tags.php +++ /dev/null @@ -1,642 +0,0 @@ - -* @copyright 2012 Bart Visscher bartv@thisnet.nl -* -* This library is free software; you can redistribute it and/or -* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE -* License as published by the Free Software Foundation; either -* version 3 of the License, or any later version. -* -* This library is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU AFFERO GENERAL PUBLIC LICENSE for more details. -* -* You should have received a copy of the GNU Affero General Public -* License along with this library. If not, see . -* -*/ - -/** - * Class for easily tagging objects by their id - * - * A tag can be e.g. 'Family', 'Work', 'Chore', 'Special Occation' or - * anything else that is either parsed from a vobject or that the user chooses - * to add. - * Tag names are not case-sensitive, but will be saved with the case they - * are entered in. If a user already has a tag 'family' for a type, and - * tries to add a tag named 'Family' it will be silently ignored. - */ - -namespace OC; - -class Tags implements \OCP\ITags { - - /** - * Tags - * - * @var array - */ - private $tags = array(); - - /** - * Used for storing objectid/categoryname pairs while rescanning. - * - * @var array - */ - private static $relations = array(); - - /** - * Type - * - * @var string - */ - private $type = null; - - /** - * User - * - * @var string - */ - private $user = null; - - const TAG_TABLE = '*PREFIX*vcategory'; - const RELATION_TABLE = '*PREFIX*vcategory_to_object'; - - const TAG_FAVORITE = '_$!!$_'; - - /** - * Constructor. - * - * @param string $user The user whos data the object will operate on. - */ - public function __construct($user, $type, $defaultTags = array()) { - $this->user = $user; - $this->type = $type; - $this->loadTags($defaultTags); - } - - /** - * Load tags from db. - * - * @param string $type The type identifier e.g. 'contact' or 'event'. - * @param array $defaultTags An array of default tags to be used if none are stored. - */ - protected function loadTags($defaultTags=array()) { - $this->tags = array(); - $result = null; - $sql = 'SELECT `id`, `category` FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - - if(!is_null($result)) { - while( $row = $result->fetchRow()) { - $this->tags[$row['id']] = $row['category']; - } - } - - if(count($defaultTags) > 0 && count($this->tags) === 0) { - $this->addMultiple($defaultTags, true); - } - \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true), - \OCP\Util::DEBUG); - - } - - /** - * Check if any tags are saved for this type and user. - * - * @return boolean. - */ - public function isEmpty() { - $sql = 'SELECT COUNT(*) FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ? AND `type` = ?'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($this->user, $this->type)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - return ((int)$result->fetchOne() === 0); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - } - - /** - * Get the tags for a specific user. - * - * This returns an array with id/name maps: - * [ - * ['id' => 0, 'name' = 'First tag'], - * ['id' => 1, 'name' = 'Second tag'], - * ] - * - * @return array - */ - public function getTags() { - if(!count($this->tags)) { - return array(); - } - - $tags = array_values($this->tags); - uasort($tags, 'strnatcasecmp'); - $tagMap = array(); - - foreach($tags as $tag) { - if($tag !== self::TAG_FAVORITE) { - $tagMap[] = array( - 'id' => $this->array_searchi($tag, $this->tags), - 'name' => $tag - ); - } - } - return $tagMap; - - } - - /** - * Get the a list if items tagged with $tag. - * - * Throws an exception if the tag could not be found. - * - * @param string|integer $tag Tag id or name. - * @return array An array of object ids or false on error. - */ - public function getIdsForTag($tag) { - $result = null; - if(is_numeric($tag)) { - $tagId = $tag; - } elseif(is_string($tag)) { - $tag = trim($tag); - $tagId = $this->array_searchi($tag, $this->tags); - } - - if($tagId === false) { - $l10n = \OC_L10N::get('core'); - throw new \Exception( - $l10n->t('Could not find category "%s"', $tag) - ); - } - - $ids = array(); - $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE - . '` WHERE `categoryid` = ?'; - - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($tagId)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } 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[] = (int)$row['objid']; - } - } - - return $ids; - } - - /** - * Checks whether a tag is already saved. - * - * @param string $name The name to check for. - * @return bool - */ - public function hasTag($name) { - return $this->in_arrayi($name, $this->tags); - } - - /** - * Add a new tag. - * - * @param string $name A string with a name of the tag - * @return int the id of the added tag or false if it already exists. - */ - public function add($name) { - $name = trim($name); - - if($this->hasTag($name)) { - \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', \OCP\Util::DEBUG); - return false; - } - try { - $result = \OCP\DB::insertIfNotExist( - self::TAG_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $name, - ) - ); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } elseif((int)$result === 0) { - \OCP\Util::writeLog('core', __METHOD__.', Tag already exists: ' . $name, \OCP\Util::DEBUG); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - $id = \OCP\DB::insertid(self::TAG_TABLE); - \OCP\Util::writeLog('core', __METHOD__.', id: ' . $id, \OCP\Util::DEBUG); - $this->tags[$id] = $name; - return $id; - } - - /** - * Rename tag. - * - * @param string $from The name of the existing tag - * @param string $to The new name of the tag. - * @return bool - */ - public function rename($from, $to) { - $from = trim($from); - $to = trim($to); - $id = $this->array_searchi($from, $this->tags); - if($id === false) { - \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', \OCP\Util::DEBUG); - return false; - } - - $sql = 'UPDATE `' . self::TAG_TABLE . '` SET `category` = ? ' - . 'WHERE `uid` = ? AND `type` = ? AND `id` = ?'; - try { - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($to, $this->user, $this->type, $id)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - $this->tags[$id] = $to; - return true; - } - - /** - * Add a list of new tags. - * - * @param string[] $names A string with a name or an array of strings containing - * the name(s) of the to add. - * @param bool $sync When true, save the tags - * @param int|null $id int Optional object id to add to this|these tag(s) - * @return bool Returns false on error. - */ - public function addMultiple($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->tags) == false) && $name !== '') { - $newones[] = $name; - } - if(!is_null($id) ) { - // Insert $objectid, $categoryid pairs if not exist. - self::$relations[] = array('objid' => $id, 'tag' => $name); - } - } - $this->tags = array_merge($this->tags, $newones); - if($sync === true) { - $this->save(); - } - - return true; - } - - /** - * Save the list of tags and their object relations - */ - protected function save() { - if(is_array($this->tags)) { - foreach($this->tags as $tag) { - try { - \OCP\DB::insertIfNotExist(self::TAG_TABLE, - array( - 'uid' => $this->user, - 'type' => $this->type, - 'category' => $tag, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - // reload tags to get the proper ids. - $this->loadTags(); - // Loop through temporarily cached objectid/tagname pairs - // and save relations. - $tags = $this->tags; - // For some reason this is needed or array_search(i) will return 0..? - ksort($tags); - foreach(self::$relations as $relation) { - $tagId = $this->array_searchi($relation['tag'], $tags); - \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, \OCP\Util::DEBUG); - if($tagId) { - try { - \OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $relation['objid'], - 'categoryid' => $tagId, - 'type' => $this->type, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - } - } - } - self::$relations = array(); // reset - } else { - \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! ' - . print_r($this->tags, true), \OCP\Util::ERROR); - } - } - - /** - * Delete tags and tag/object relations for a user. - * - * For hooking up on post_deleteUser - * - * @param array - */ - public static function post_deleteUser($arguments) { - // Find all objectid/tagId pairs. - $result = null; - try { - $stmt = \OCP\DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } 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 `' . self::RELATION_TABLE . '` ' - . '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 `' . self::TAG_TABLE . '` ' - . 'WHERE `uid` = ?'); - $result = $stmt->execute(array($arguments['uid'])); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), \OCP\Util::ERROR); - } - } - - /** - * Delete tag/object relations from the db - * - * @param array $ids The ids of the objects - * @return boolean Returns false on error. - */ - public function purgeObjects(array $ids) { - if(count($ids) === 0) { - // job done ;) - return true; - } - $updates = $ids; - try { - $query = 'DELETE FROM `' . self::RELATION_TABLE . '` '; - $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) '; - $query .= 'AND `type`= ?'; - $updates[] = $this->type; - $stmt = \OCP\DB::prepare($query); - $result = $stmt->execute($updates); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Get favorites for an object type - * - * @return array An array of object ids. - */ - public function getFavorites() { - try { - return $this->getIdsForTag(self::TAG_FAVORITE); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: ' . $e->getMessage(), - \OCP\Util::ERROR); - return array(); - } - } - - /** - * Add an object to favorites - * - * @param int $objid The id of the object - * @return boolean - */ - public function addToFavorites($objid) { - if(!$this->hasTag(self::TAG_FAVORITE)) { - $this->add(self::TAG_FAVORITE, true); - } - return $this->tagAs($objid, self::TAG_FAVORITE, $this->type); - } - - /** - * Remove an object from favorites - * - * @param int $objid The id of the object - * @return boolean - */ - public function removeFromFavorites($objid) { - return $this->unTag($objid, self::TAG_FAVORITE, $this->type); - } - - /** - * Creates a tag/object relation. - * - * @param int $objid The id of the object - * @param int|string $tag The id or name of the tag - * @return boolean Returns false on database error. - */ - public function tagAs($objid, $tag) { - if(is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - if(!$this->hasTag($tag)) { - $this->add($tag, true); - } - $tagId = $this->array_searchi($tag, $this->tags); - } else { - $tagId = $tag; - } - try { - \OCP\DB::insertIfNotExist(self::RELATION_TABLE, - array( - 'objid' => $objid, - 'categoryid' => $tagId, - 'type' => $this->type, - )); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Delete single tag/object relation from the db - * - * @param int $objid The id of the object - * @param int|string $tag The id or name of the tag - * @return boolean - */ - public function unTag($objid, $tag) { - if(is_string($tag) && !is_numeric($tag)) { - $tag = trim($tag); - $tagId = $this->array_searchi($tag, $this->tags); - } else { - $tagId = $tag; - } - - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?'; - $stmt = \OCP\DB::prepare($sql); - $stmt->execute(array($objid, $tagId, $this->type)); - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - return true; - } - - /** - * Delete tags from the - * - * @param string[] $names An array of tags to delete - * @return bool Returns false on error - */ - public function delete($names) { - if(!is_array($names)) { - $names = array($names); - } - - $names = array_map('trim', $names); - - \OCP\Util::writeLog('core', __METHOD__ . ', before: ' - . print_r($this->tags, true), \OCP\Util::DEBUG); - foreach($names as $name) { - $id = null; - - if($this->hasTag($name)) { - $id = $this->array_searchi($name, $this->tags); - unset($this->tags[$id]); - } - try { - $stmt = \OCP\DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` WHERE ' - . '`uid` = ? AND `type` = ? AND `category` = ?'); - $result = $stmt->execute(array($this->user, $this->type, $name)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), \OCP\Util::ERROR); - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__ . ', exception: ' - . $e->getMessage(), \OCP\Util::ERROR); - return false; - } - if(!is_null($id) && $id !== false) { - try { - $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` ' - . 'WHERE `categoryid` = ?'; - $stmt = \OCP\DB::prepare($sql); - $result = $stmt->execute(array($id)); - if (\OCP\DB::isError($result)) { - \OCP\Util::writeLog('core', - __METHOD__. 'DB error: ' . \OCP\DB::getErrorMessage($result), - \OCP\Util::ERROR); - return false; - } - } catch(\Exception $e) { - \OCP\Util::writeLog('core', __METHOD__.', exception: '.$e->getMessage(), - \OCP\Util::ERROR); - return false; - } - } - } - return true; - } - - // case-insensitive in_array - private function in_arrayi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return in_array(strtolower($needle), array_map('strtolower', $haystack)); - } - - // case-insensitive array_search - private function array_searchi($needle, $haystack) { - if(!is_array($haystack)) { - return false; - } - return array_search(strtolower($needle), array_map('strtolower', $haystack)); - } -}