diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base.php | 26 | ||||
-rw-r--r-- | lib/connector/sabre/node.php | 16 | ||||
-rw-r--r-- | lib/db.php | 72 | ||||
-rw-r--r-- | lib/filecache.php | 8 | ||||
-rw-r--r-- | lib/fileproxy/quota.php | 16 | ||||
-rw-r--r-- | lib/files.php | 26 | ||||
-rw-r--r-- | lib/filesystem.php | 4 | ||||
-rw-r--r-- | lib/filesystemview.php | 7 | ||||
-rw-r--r-- | lib/helper.php | 2 | ||||
-rw-r--r-- | lib/l10n/sr.php | 25 | ||||
-rw-r--r-- | lib/l10n/zh_CN.GB2312.php | 1 | ||||
-rw-r--r-- | lib/migrate.php | 48 | ||||
-rw-r--r-- | lib/public/constants.php | 38 | ||||
-rw-r--r-- | lib/public/db.php | 21 | ||||
-rw-r--r-- | lib/public/share.php | 21 | ||||
-rw-r--r-- | lib/setup.php | 54 | ||||
-rw-r--r-- | lib/template.php | 6 | ||||
-rwxr-xr-x | lib/util.php | 29 | ||||
-rw-r--r-- | lib/vcategories.php | 632 |
19 files changed, 863 insertions, 189 deletions
diff --git a/lib/base.php b/lib/base.php index d4eeac82daa..c97700b3dbf 100644 --- a/lib/base.php +++ b/lib/base.php @@ -20,6 +20,8 @@ * */ +require_once 'public/constants.php'; + /** * Class that is a namespace for all global OC variables * No, we can not put this class in its own file because it is used by @@ -225,12 +227,10 @@ class OC{ if (isset($_SERVER['SERVER_SOFTWARE']) && strstr($_SERVER['SERVER_SOFTWARE'], 'Apache')) { if(!OC_Util::ishtaccessworking()) { if(!file_exists(OC::$SERVERROOT.'/data/.htaccess')) { - $content = "deny from all\n"; - $content.= "IndexIgnore *"; - file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content); + OC_Setup::protectDataDirectory(); } } - } + } OC_Log::write('core', 'starting upgrade from '.$installedVersion.' to '.$currentVersion, OC_Log::DEBUG); $result=OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/db_structure.xml'); if(!$result) { @@ -288,7 +288,7 @@ class OC{ // (re)-initialize session session_start(); - + // regenerate session id periodically to avoid session fixation if (!isset($_SESSION['SID_CREATED'])) { $_SESSION['SID_CREATED'] = time(); @@ -356,6 +356,10 @@ class OC{ //try to set the session lifetime to 60min @ini_set('gc_maxlifetime', '3600'); + //copy http auth headers for apache+php-fcgid work around + if (isset($_SERVER['HTTP_XAUTHORIZATION']) && !isset($_SERVER['HTTP_AUTHORIZATION'])) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['HTTP_XAUTHORIZATION']; + } //set http auth headers for apache+php-cgi work around if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) { @@ -475,17 +479,7 @@ class OC{ */ public static function handleRequest() { if (!OC_Config::getValue('installed', false)) { - // Check for autosetup: - $autosetup_file = OC::$SERVERROOT."/config/autoconfig.php"; - if( file_exists( $autosetup_file )) { - OC_Log::write('core', 'Autoconfig file found, setting up owncloud...', OC_Log::INFO); - include $autosetup_file; - $_POST['install'] = 'true'; - $_POST = array_merge ($_POST, $AUTOCONFIG); - unlink($autosetup_file); - } - OC_Util::addScript('setup'); - require_once 'setup.php'; + require_once 'core/setup.php'; exit(); } // Handle WebDAV diff --git a/lib/connector/sabre/node.php b/lib/connector/sabre/node.php index 5fc106b85ed..9fffa108d2a 100644 --- a/lib/connector/sabre/node.php +++ b/lib/connector/sabre/node.php @@ -26,6 +26,13 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr const LASTMODIFIED_PROPERTYNAME = '{DAV:}lastmodified'; /** + * Allow configuring the method used to generate Etags + * + * @var array(class_name, function_name) + */ + public static $ETagFunction = null; + + /** * The path to the current node * * @var string @@ -178,7 +185,7 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * If the array is empty, all properties should be returned * * @param array $properties - * @return void + * @return array */ public function getProperties($properties) { if (is_null($this->property_cache)) { @@ -209,7 +216,12 @@ abstract class OC_Connector_Sabre_Node implements Sabre_DAV_INode, Sabre_DAV_IPr * @return string|null Returns null if the ETag can not effectively be determined */ static protected function createETag($path) { - return uniqid('', true); + if(self::$ETagFunction) { + $hash = call_user_func(self::$ETagFunction, $path); + return $hash; + }else{ + return uniqid('', true); + } } /** diff --git a/lib/db.php b/lib/db.php index fba2687967f..de42626563d 100644 --- a/lib/db.php +++ b/lib/db.php @@ -542,6 +542,78 @@ class OC_DB { } /** + * @brief Insert a row if a matching row doesn't exists. + * @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(); + $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' ) { + // 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() . '"<br />'; + $entry .= 'Offending command was: ' . $query . '<br />'; + 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 \'' + . 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() . '"<br />'; + $entry .= 'Offending command was: ' . $query.'<br />'; + OC_Log::write('core', $entry, OC_Log::FATAL); + error_log('DB error: ' . $entry); + die( $entry ); + } + + return $result->execute(); + } + + /** * @brief does minor changes to query * @param string $query Query string * @return string corrected query string diff --git a/lib/filecache.php b/lib/filecache.php index 6263e03fc64..4a7dbd0250d 100644 --- a/lib/filecache.php +++ b/lib/filecache.php @@ -502,11 +502,11 @@ class OC_FileCache{ */ public static function triggerUpdate($user='') { if($user) { - $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`="httpd/unix-directory"'); - $query->execute(array($user)); + $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 WHERE `user`=? AND `mimetype`= ? '); + $query->execute(array($user,'httpd/unix-directory')); }else{ - $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`="httpd/unix-directory"'); - $query->execute(); + $query=OC_DB::prepare('UPDATE `*PREFIX*fscache` SET `mtime`=0 AND `mimetype`= ? '); + $query->execute(array('httpd/unix-directory')); } } } diff --git a/lib/fileproxy/quota.php b/lib/fileproxy/quota.php index 46bc8dc16d8..742e02d471b 100644 --- a/lib/fileproxy/quota.php +++ b/lib/fileproxy/quota.php @@ -43,7 +43,7 @@ class OC_FileProxy_Quota extends OC_FileProxy{ $userQuota=OC_AppConfig::getValue('files', 'default_quota', 'none'); } if($userQuota=='none') { - $this->userQuota[$user]=0; + $this->userQuota[$user]=-1; }else{ $this->userQuota[$user]=OC_Helper::computerFileSize($userQuota); } @@ -61,8 +61,8 @@ class OC_FileProxy_Quota extends OC_FileProxy{ $owner=$storage->getOwner($path); $totalSpace=$this->getQuota($owner); - if($totalSpace==0) { - return 0; + if($totalSpace==-1) { + return -1; } $rootInfo=OC_FileCache::get('', "/".$owner."/files"); @@ -79,7 +79,7 @@ class OC_FileProxy_Quota extends OC_FileProxy{ public function postFree_space($path, $space) { $free=$this->getFreeSpace($path); - if($free==0) { + if($free==-1) { return $space; } return min($free, $space); @@ -89,21 +89,21 @@ class OC_FileProxy_Quota extends OC_FileProxy{ if (is_resource($data)) { $data = '';//TODO: find a way to get the length of the stream without emptying it } - return (strlen($data)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==0); + return (strlen($data)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1); } public function preCopy($path1, $path2) { if(!self::$rootView) { self::$rootView = new OC_FilesystemView(''); } - return (self::$rootView->filesize($path1)<$this->getFreeSpace($path2) or $this->getFreeSpace($path2)==0); + return (self::$rootView->filesize($path1)<$this->getFreeSpace($path2) or $this->getFreeSpace($path2)==-1); } public function preFromTmpFile($tmpfile, $path) { - return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==0); + return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1); } public function preFromUploadedFile($tmpfile, $path) { - return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==0); + return (filesize($tmpfile)<$this->getFreeSpace($path) or $this->getFreeSpace($path)==-1); } } diff --git a/lib/files.php b/lib/files.php index 5a14083c285..e5bf78d032f 100644 --- a/lib/files.php +++ b/lib/files.php @@ -42,16 +42,20 @@ class OC_Files { * - versioned */ public static function getFileInfo($path) { + $path = OC_Filesystem::normalizePath($path); if (($path == '/Shared' || substr($path, 0, 8) == '/Shared/') && OC_App::isEnabled('files_sharing')) { if ($path == '/Shared') { list($info) = OCP\Share::getItemsSharedWith('file', OC_Share_Backend_File::FORMAT_FILE_APP_ROOT); - }else{ - $info['size'] = OC_Filesystem::filesize($path); - $info['mtime'] = OC_Filesystem::filemtime($path); - $info['ctime'] = OC_Filesystem::filectime($path); - $info['mimetype'] = OC_Filesystem::getMimeType($path); - $info['encrypted'] = false; - $info['versioned'] = false; + } else { + $info = array(); + if (OC_Filesystem::file_exists($path)) { + $info['size'] = OC_Filesystem::filesize($path); + $info['mtime'] = OC_Filesystem::filemtime($path); + $info['ctime'] = OC_Filesystem::filectime($path); + $info['mimetype'] = OC_Filesystem::getMimeType($path); + $info['encrypted'] = false; + $info['versioned'] = false; + } } } else { $info = OC_FileCache::get($path); @@ -87,16 +91,16 @@ class OC_Files { foreach ($files as &$file) { $file['directory'] = $directory; $file['type'] = ($file['mimetype'] == 'httpd/unix-directory') ? 'dir' : 'file'; - $permissions = OCP\Share::PERMISSION_READ; + $permissions = OCP\PERMISSION_READ; // NOTE: Remove check when new encryption is merged if (!$file['encrypted']) { - $permissions |= OCP\Share::PERMISSION_SHARE; + $permissions |= OCP\PERMISSION_SHARE; } if ($file['type'] == 'dir' && $file['writable']) { - $permissions |= OCP\Share::PERMISSION_CREATE; + $permissions |= OCP\PERMISSION_CREATE; } if ($file['writable']) { - $permissions |= OCP\Share::PERMISSION_UPDATE | OCP\Share::PERMISSION_DELETE; + $permissions |= OCP\PERMISSION_UPDATE | OCP\PERMISSION_DELETE; } $file['permissions'] = $permissions; } diff --git a/lib/filesystem.php b/lib/filesystem.php index 4635f8b4f30..aa03593908d 100644 --- a/lib/filesystem.php +++ b/lib/filesystem.php @@ -232,8 +232,8 @@ class OC_Filesystem{ } if(isset($mountConfig['user'])) { - foreach($mountConfig['user'] as $user=>$mounts) { - if($user==='all' or strtolower($user)===strtolower($user)) { + foreach($mountConfig['user'] as $mountUser=>$mounts) { + if($user==='all' or strtolower($mountUser)===strtolower($user)) { foreach($mounts as $mountPoint=>$options) { $mountPoint=self::setUserVars($mountPoint, $user); foreach($options as &$option) { diff --git a/lib/filesystemview.php b/lib/filesystemview.php index 936e1feb412..0229213ebcb 100644 --- a/lib/filesystemview.php +++ b/lib/filesystemview.php @@ -47,11 +47,8 @@ class OC_FilesystemView { $this->fakeRoot=$root; } - public function getAbsolutePath($path) { - if(!$path) { - $path='/'; - } - if($path[0]!=='/') { + public function getAbsolutePath($path = '/') { + if(!$path || $path[0]!=='/') { $path='/'.$path; } return $this->fakeRoot.$path; diff --git a/lib/helper.php b/lib/helper.php index ed459dab624..ccceb58cd4c 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -319,7 +319,7 @@ class OC_Helper { self::copyr("$src/$file", "$dest/$file"); } } - }elseif(file_exists($src)) { + }elseif(file_exists($src) && !OC_Filesystem::isFileBlacklisted($src)) { copy($src, $dest); } } diff --git a/lib/l10n/sr.php b/lib/l10n/sr.php index cec7ea703fb..a48830551bd 100644 --- a/lib/l10n/sr.php +++ b/lib/l10n/sr.php @@ -3,6 +3,29 @@ "Personal" => "Лично", "Settings" => "Подешавања", "Users" => "Корисници", +"Apps" => "Апликације", +"Admin" => "Администрација", +"ZIP download is turned off." => "Преузимање ЗИПа је искључено.", +"Files need to be downloaded one by one." => "Преузимање морате радити једану по једану.", +"Back to Files" => "Назад на датотеке", +"Selected files too large to generate zip file." => "Изабране датотеке су превелике да бисте правили зип датотеку.", +"Application is not enabled" => "Апликација није укључена", "Authentication error" => "Грешка при аутентификацији", -"Text" => "Текст" +"Token expired. Please reload page." => "Токен је истекао. Поново учитајте страну.", +"Files" => "Датотеке", +"Text" => "Текст", +"Images" => "Слике", +"seconds ago" => "пре неколико секунди", +"1 minute ago" => "пре 1 минута", +"%d minutes ago" => "%d минута раније", +"today" => "данас", +"yesterday" => "јуче", +"%d days ago" => "%d дана раније", +"last month" => "прошлог месеца", +"months ago" => "месеци раније", +"last year" => "прошле године", +"years ago" => "година раније", +"%s is available. Get <a href=\"%s\">more information</a>" => "%s је доступна. Погледајте <a href=\"%s\">више информација</a>", +"up to date" => "је ажурна", +"updates check is disabled" => "провера ажурирања је искључена" ); diff --git a/lib/l10n/zh_CN.GB2312.php b/lib/l10n/zh_CN.GB2312.php index adc5c3bc6a9..4fbdb66ff22 100644 --- a/lib/l10n/zh_CN.GB2312.php +++ b/lib/l10n/zh_CN.GB2312.php @@ -14,6 +14,7 @@ "Token expired. Please reload page." => "会话过期。请刷新页面。", "Files" => "文件", "Text" => "文本", +"Images" => "图片", "seconds ago" => "秒前", "1 minute ago" => "1 分钟前", "%d minutes ago" => "%d 分钟前", diff --git a/lib/migrate.php b/lib/migrate.php index 96f5a0001f7..2cc0a3067b8 100644 --- a/lib/migrate.php +++ b/lib/migrate.php @@ -200,7 +200,7 @@ class OC_Migrate{ $scan = scandir( $extractpath ); // Check for export_info.json if( !in_array( 'export_info.json', $scan ) ) { - OC_Log::write( 'migration', 'Invalid import file, export_info.json note found', OC_Log::ERROR ); + OC_Log::write( 'migration', 'Invalid import file, export_info.json not found', OC_Log::ERROR ); return json_encode( array( 'success' => false ) ); } $json = json_decode( file_get_contents( $extractpath . 'export_info.json' ) ); @@ -235,12 +235,19 @@ class OC_Migrate{ return json_encode( array( 'success' => false ) ); } // Copy data - if( !self::copy_r( $extractpath . $json->exporteduser, $datadir . '/' . self::$uid ) ) { - return json_encode( array( 'success' => false ) ); + $userfolder = $extractpath . $json->exporteduser; + $newuserfolder = $datadir . '/' . self::$uid; + foreach(scandir($userfolder) as $file){ + if($file !== '.' && $file !== '..' && is_dir($file)) { + // Then copy the folder over + OC_Helper::copyr($userfolder.'/'.$file, $newuserfolder.'/'.$file); + } } // Import user app data - if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ) { - return json_encode( array( 'success' => false ) ); + if(file_exists($extractpath . $json->exporteduser . '/migration.db')) { + if( !$appsimported = self::importAppData( $extractpath . $json->exporteduser . '/migration.db', $json, self::$uid ) ) { + return json_encode( array( 'success' => false ) ); + } } // All done! if( !self::unlink_r( $extractpath ) ) { @@ -305,37 +312,6 @@ class OC_Migrate{ } /** - * @brief copies recursively - * @param $path string path to source folder - * @param $dest string path to destination - * @return bool - */ - private static function copy_r( $path, $dest ) { - if( is_dir($path) ) { - @mkdir( $dest ); - $objects = scandir( $path ); - if( sizeof( $objects ) > 0 ) { - foreach( $objects as $file ) { - if( $file == "." || $file == ".." || $file == ".htaccess") - continue; - // go on - if( is_dir( $path . '/' . $file ) ) { - self::copy_r( $path .'/' . $file, $dest . '/' . $file ); - } else { - copy( $path . '/' . $file, $dest . '/' . $file ); - } - } - } - return true; - } - elseif( is_file( $path ) ) { - return copy( $path, $dest ); - } else { - return false; - } - } - - /** * @brief tries to extract the import zip * @param $path string path to the zip * @return string path to extract location (with a trailing slash) or false on failure diff --git a/lib/public/constants.php b/lib/public/constants.php new file mode 100644 index 00000000000..bc979c9031f --- /dev/null +++ b/lib/public/constants.php @@ -0,0 +1,38 @@ +<?php +/** + * ownCloud + * + * @author Thomas Tanghus + * @copyright 2012 Thomas Tanghus (thomas@tanghus.net) + * + * 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 <http://www.gnu.org/licenses/>. + * + */ + +/** + * This file defines common constants used in ownCloud + */ + +namespace OCP; + +/** + * CRUDS permissions. + */ +const PERMISSION_CREATE = 4; +const PERMISSION_READ = 1; +const PERMISSION_UPDATE = 2; +const PERMISSION_DELETE = 8; +const PERMISSION_SHARE = 16; +const PERMISSION_ALL = 31; + diff --git a/lib/public/db.php b/lib/public/db.php index d2484b6eb83..92ff8f93a22 100644 --- a/lib/public/db.php +++ b/lib/public/db.php @@ -46,6 +46,27 @@ class DB { } /** + * @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 * @returns id diff --git a/lib/public/share.php b/lib/public/share.php index 071304ec249..dcb1b5c278e 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -46,12 +46,8 @@ class Share { * Check if permission is granted with And (&) e.g. Check if delete is granted: if ($permissions & PERMISSION_DELETE) * Remove permissions with And (&) and Not (~) e.g. Remove the update permission: $permissions &= ~PERMISSION_UPDATE * Apps are required to handle permissions on their own, this class only stores and manages the permissions of shares + * @see lib/public/constants.php */ - const PERMISSION_CREATE = 4; - const PERMISSION_READ = 1; - const PERMISSION_UPDATE = 2; - const PERMISSION_DELETE = 8; - const PERMISSION_SHARE = 16; const FORMAT_NONE = -1; const FORMAT_STATUSES = -2; @@ -402,7 +398,7 @@ class Share { // Check if permissions were removed if ($item['permissions'] & ~$permissions) { // If share permission is removed all reshares must be deleted - if (($item['permissions'] & self::PERMISSION_SHARE) && (~$permissions & self::PERMISSION_SHARE)) { + if (($item['permissions'] & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE)) { self::delete($item['id'], true); } else { $ids = array(); @@ -552,7 +548,7 @@ class Share { $itemTypes = $collectionTypes; } $placeholders = join(',', array_fill(0, count($itemTypes), '?')); - $where .= ' WHERE item_type IN ('.$placeholders.'))'; + $where .= ' WHERE `item_type` IN ('.$placeholders.'))'; $queryArgs = $itemTypes; } else { $where = ' WHERE `item_type` = ?'; @@ -629,7 +625,7 @@ class Share { $queryArgs[] = $item; if ($includeCollections && $collectionTypes) { $placeholders = join(',', array_fill(0, count($collectionTypes), '?')); - $where .= ' OR item_type IN ('.$placeholders.'))'; + $where .= ' OR `item_type` IN ('.$placeholders.'))'; $queryArgs = array_merge($queryArgs, $collectionTypes); } } @@ -677,6 +673,9 @@ class Share { $root = strlen($root); $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); $result = $query->execute($queryArgs); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, \OC_Log::ERROR); + } $items = array(); $targets = array(); while ($row = $result->fetchRow()) { @@ -701,7 +700,7 @@ class Share { $items[$id]['share_with'] = $row['share_with']; } // Switch ids if sharing permission is granted on only one share to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & self::PERMISSION_SHARE && (int)$row['permissions'] & self::PERMISSION_SHARE) { + if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE && (int)$row['permissions'] & PERMISSION_SHARE) { $items[$row['id']] = $items[$id]; unset($items[$id]); $id = $row['id']; @@ -847,7 +846,7 @@ class Share { throw new \Exception($message); } // Check if share permissions is granted - if ((int)$checkReshare['permissions'] & self::PERMISSION_SHARE) { + if ((int)$checkReshare['permissions'] & PERMISSION_SHARE) { if (~(int)$checkReshare['permissions'] & $permissions) { $message = 'Sharing '.$itemSource.' failed, because the permissions exceed permissions granted to '.$uidOwner; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); @@ -1133,7 +1132,7 @@ class Share { $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, $item['uid_owner'], $item['parent']))->fetchRow(); if ($duplicateParent) { // Change the parent to the other item id if share permission is granted - if ($duplicateParent['permissions'] & self::PERMISSION_SHARE) { + if ($duplicateParent['permissions'] & PERMISSION_SHARE) { $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); $query->execute(array($duplicateParent['id'], $item['id'])); continue; diff --git a/lib/setup.php b/lib/setup.php index 726b3352d50..264cd55795e 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -1,45 +1,5 @@ <?php -$hasSQLite = (is_callable('sqlite_open') or class_exists('SQLite3')); -$hasMySQL = is_callable('mysql_connect'); -$hasPostgreSQL = is_callable('pg_connect'); -$hasOracle = is_callable('oci_connect'); -$datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data'); - -// Test if .htaccess is working -$content = "deny from all"; -file_put_contents(OC::$SERVERROOT.'/data/.htaccess', $content); - -$opts = array( - 'hasSQLite' => $hasSQLite, - 'hasMySQL' => $hasMySQL, - 'hasPostgreSQL' => $hasPostgreSQL, - 'hasOracle' => $hasOracle, - 'directory' => $datadir, - 'secureRNG' => OC_Util::secureRNG_available(), - 'htaccessWorking' => OC_Util::ishtaccessworking(), - 'errors' => array(), -); - -if(isset($_POST['install']) AND $_POST['install']=='true') { - // We have to launch the installation process : - $e = OC_Setup::install($_POST); - $errors = array('errors' => $e); - - if(count($e) > 0) { - //OC_Template::printGuestPage("", "error", array("errors" => $errors)); - $options = array_merge($_POST, $opts, $errors); - OC_Template::printGuestPage("", "installation", $options); - } - else { - header("Location: ".OC::$WEBROOT.'/'); - exit(); - } -} -else { - OC_Template::printGuestPage("", "installation", $opts); -} - class OC_Setup { public static function install($options) { $error = array(); @@ -573,7 +533,15 @@ class OC_Setup { * create .htaccess files for apache hosts */ private static function createHtaccess() { - $content = "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page + $content = "<IfModule mod_fcgid.c>\n"; + $content.= "<IfModule mod_setenvif.c>\n"; + $content.= "<IfModule mod_headers.c>\n"; + $content.= "SetEnvIfNoCase ^Authorization$ \"(.+)\" XAUTHORIZATION=$1\n"; + $content.= "RequestHeader set XAuthorization %{XAUTHORIZATION}e env=XAUTHORIZATION\n"; + $content.= "</IfModule>\n"; + $content.= "</IfModule>\n"; + $content.= "</IfModule>\n"; + $content.= "ErrorDocument 403 ".OC::$WEBROOT."/core/templates/403.php\n";//custom 403 error page $content.= "ErrorDocument 404 ".OC::$WEBROOT."/core/templates/404.php\n";//custom 404 error page $content.= "<IfModule mod_php5.c>\n"; $content.= "php_value upload_max_filesize 512M\n";//upload limit @@ -599,6 +567,10 @@ class OC_Setup { $content.= "Options -Indexes\n"; @file_put_contents(OC::$SERVERROOT.'/.htaccess', $content); //supress errors in case we don't have permissions for it + self::protectDataDirectory(); + } + + public static function protectDataDirectory() { $content = "deny from all\n"; $content.= "IndexIgnore *"; file_put_contents(OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data').'/.htaccess', $content); diff --git a/lib/template.php b/lib/template.php index 3d3589abd1e..a10cabf5931 100644 --- a/lib/template.php +++ b/lib/template.php @@ -103,13 +103,13 @@ function relative_modified_date($timestamp) { if($timediff < 60) { return $l->t('seconds ago'); } else if($timediff < 120) { return $l->t('1 minute ago'); } else if($timediff < 3600) { return $l->t('%d minutes ago', $diffminutes); } - //else if($timediff < 7200) { return '1 hour ago'; } - //else if($timediff < 86400) { return $diffhours.' hours ago'; } + else if($timediff < 7200) { return $l->t('1 hour ago'); } + else if($timediff < 86400) { return $l->t('%d hours ago', $diffhours); } else if((date('G')-$diffhours) > 0) { return $l->t('today'); } else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); } else if($timediff < 2678400) { return $l->t('%d days ago', $diffdays); } else if($timediff < 5184000) { return $l->t('last month'); } - else if((date('n')-$diffmonths) > 0) { return $l->t('months ago'); } + else if((date('n')-$diffmonths) > 0) { return $l->t('%d months ago', $diffmonths); } else if($timediff < 63113852) { return $l->t('last year'); } else { return $l->t('years ago'); } } diff --git a/lib/util.php b/lib/util.php index 40b44bf9d6e..da57b226ba0 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); } /** @@ -584,6 +584,33 @@ class OC_Util { } } + + /** + * Check if the ownCloud server can connect to the internet + */ + public static function isinternetconnectionworking() { + + // try to connect to owncloud.org to see if http connections to the internet are possible. + $connected = @fsockopen("www.owncloud.org", 80); + if ($connected) { + fclose($connected); + return true; + }else{ + + // second try in case one server is down + $connected = @fsockopen("apps.owncloud.com", 80); + if ($connected) { + fclose($connected); + return true; + }else{ + return false; + } + + } + + } + + /** * @brief Generates a cryptographical secure pseudorandom string * @param Int with the length of the random string diff --git a/lib/vcategories.php b/lib/vcategories.php index 46256def9c4..406a4eb1074 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. @@ -28,50 +29,261 @@ * 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(); - private $app = null; + /** + * Used for storing objectid/categoryname pairs while rescanning. + */ + private static $relations = array(); + + private $type = null; private $user = null; + const CATEGORY_TABLE = '*PREFIX*vcategory'; + const RELATION_TABLE = '*PREFIX*vcategory_to_object'; + + const CATEGORY_FAVORITE = '_$!<Favorite>!$_'; + + 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->addMulti($defcategories, true); + } + } + + /** + * @brief Load categories from db. + */ + private function loadCategories() { + $this->categories = array(); + $result = null; + $sql = 'SELECT `id`, `category` FROM `' . self::CATEGORY_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ? ORDER BY `category`'; + 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); + } + + 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']; + } + } + OCP\Util::writeLog('core', __METHOD__.', categories: ' . print_r($this->categories, true), + OCP\Util::DEBUG); + } + + + /** + * @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 `' . self::CATEGORY_TABLE . '` ' + . 'WHERE `uid` = ? AND `type` = ?'; + 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(), + OCP\Util::ERROR); + return false; } - $this->categories = is_array($categories) ? $categories : $defcategories; } /** * @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) { + if($category !== self::CATEGORY_FAVORITE) { + $catmap[] = array( + 'id' => $this->array_searchi($category, $this->categories), + 'name' => $category + ); + } + } + return $catmap; + } + + // 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; + } + } + + /** + * 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)); + 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)) { + while( $row = $result->fetchRow()) { + $ids[] = (int)$row['objid']; + } + } + + 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 or false on error. + */ + 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)); + 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)) { + 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; } /** @@ -84,22 +296,51 @@ 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); + $this->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) { + public function addMulti($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 +355,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->addMulti($vobject->getAsArray('CATEGORIES'), $sync, $id); } /** @@ -128,23 +369,62 @@ 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) { + $result = null; + // Find all objectid/categoryid pairs. + try { + $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); + } + + // And delete them. + if(!is_null($result)) { + $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 `' . 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); + 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,16 +435,224 @@ 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(self::CATEGORY_TABLE, + 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(self::RELATION_TABLE, + 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 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 `' . 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); + } + + 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::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); + } + } + + /** + * @brief Delete category/object relations from the db + * @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 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`= ?'); + $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); + return false; + } + 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. + * @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 Returns false on database error. + */ + public function addToCategory($objid, $category, $type = null) { + $type = is_null($type) ? $this->type : $type; + if(is_string($category) && !is_numeric($category)) { + if(!$this->hasCategory($category)) { + $this->add($category, true); + } + $categoryid = $this->array_searchi($category, $this->categories); + } else { + $categoryid = $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 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 . '` ' + . '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; + } + + /** * @brief Delete categories from the db and from all the vobject supplied * @param $names An array of categories to delete * @param $objects An array of arrays with [id,vobject] (as text) pairs suitable for updating the apps object table. @@ -173,37 +661,87 @@ 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); + $id = null; + 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)]); + $id = $this->array_searchi($name, $this->categories); + unset($this->categories[$id]); + } + try { + $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); + } + 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 (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); + return false; + } } } - $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); } } } @@ -224,5 +762,5 @@ class OC_VCategories { } return array_search(strtolower($needle), array_map('strtolower', $haystack)); } - } + |