diff options
-rw-r--r-- | apps/files/ajax/list.php | 69 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 23 | ||||
-rw-r--r-- | apps/files_sharing/css/public.css | 14 | ||||
-rw-r--r-- | apps/files_sharing/js/external.js | 2 | ||||
-rw-r--r-- | apps/files_sharing/js/public.js | 1 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/manager.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/scanner.php | 18 | ||||
-rw-r--r-- | apps/files_sharing/lib/external/storage.php | 85 | ||||
-rw-r--r-- | apps/files_sharing/templates/public.php | 2 | ||||
-rw-r--r-- | apps/files_sharing/tests/externalstorage.php | 1 | ||||
-rw-r--r-- | core/css/mobile.css | 14 | ||||
-rw-r--r-- | lib/private/appframework/http/dispatcher.php | 2 | ||||
-rw-r--r-- | lib/private/connector/sabre/objecttree.php | 10 | ||||
-rw-r--r-- | lib/private/files/mount/manager.php | 4 | ||||
-rw-r--r-- | lib/private/files/storage/dav.php | 44 | ||||
-rw-r--r-- | lib/public/files/storageinvalidexception.php | 22 | ||||
-rw-r--r-- | lib/public/files/storagenotavailableexception.php | 22 | ||||
-rw-r--r-- | public.php | 2 |
18 files changed, 249 insertions, 88 deletions
diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index bae3628402f..b4641343ed4 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -2,29 +2,54 @@ OCP\JSON::checkLoggedIn(); \OC::$session->close(); +$l = OC_L10N::get('files'); // Load the files -$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; +$dir = isset($_GET['dir']) ? $_GET['dir'] : ''; $dir = \OC\Files\Filesystem::normalizePath($dir); -$dirInfo = \OC\Files\Filesystem::getFileInfo($dir); -if (!$dirInfo || !$dirInfo->getType() === 'dir') { - header("HTTP/1.0 404 Not Found"); - exit(); -} - -$data = array(); -$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; - -$permissions = $dirInfo->getPermissions(); - -$sortAttribute = isset( $_GET['sort'] ) ? $_GET['sort'] : 'name'; -$sortDirection = isset( $_GET['sortdirection'] ) ? ($_GET['sortdirection'] === 'desc') : false; -// make filelist -$files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); - -$data['directory'] = $dir; -$data['files'] = \OCA\Files\Helper::formatFileInfos($files); -$data['permissions'] = $permissions; - -OCP\JSON::success(array('data' => $data)); +try { + $dirInfo = \OC\Files\Filesystem::getFileInfo($dir); + if (!$dirInfo || !$dirInfo->getType() === 'dir') { + header("HTTP/1.0 404 Not Found"); + exit(); + } + + $data = array(); + $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; + + $permissions = $dirInfo->getPermissions(); + + $sortAttribute = isset($_GET['sort']) ? $_GET['sort'] : 'name'; + $sortDirection = isset($_GET['sortdirection']) ? ($_GET['sortdirection'] === 'desc') : false; + + // make filelist + + $files = \OCA\Files\Helper::getFiles($dir, $sortAttribute, $sortDirection); + $data['directory'] = $dir; + $data['files'] = \OCA\Files\Helper::formatFileInfos($files); + $data['permissions'] = $permissions; + + OCP\JSON::success(array('data' => $data)); +} catch (\OCP\Files\StorageNotAvailableException $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageNotAvailableException', + 'message' => $l->t('Storage not available') + ) + )); +} catch (\OCP\Files\StorageInvalidException $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\OCP\Files\StorageInvalidException', + 'message' => $l->t('Storage invalid') + ) + )); +} catch (\Exception $e) { + OCP\JSON::error(array( + 'data' => array( + 'exception' => '\Exception', + 'message' => $l->t('Unknown error') + ) + )); +} diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index c7fccc5dd66..94f161943a1 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -846,13 +846,18 @@ * @param {boolean} force set to true to force changing directory */ changeDirectory: function(targetDir, changeUrl, force) { + var self = this; var currentDir = this.getCurrentDirectory(); targetDir = targetDir || '/'; if (!force && currentDir === targetDir) { return; } this._setCurrentDir(targetDir, changeUrl); - this.reload(); + this.reload().then(function(success){ + if (!success) { + self.changeDirectory(currentDir, true); + } + }); }, linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); @@ -912,7 +917,6 @@ * @brief Reloads the file list using ajax call */ reload: function() { - var self = this; this._selectedFiles = {}; this._selectionSummary.clear(); this.$el.find('.select-all').prop('checked', false); @@ -926,14 +930,10 @@ dir : this.getCurrentDirectory(), sort: this._sort, sortdirection: this._sortDirection - }, - error: function(result) { - self.reloadCallback(result); - }, - success: function(result) { - self.reloadCallback(result); } }); + var callBack = this.reloadCallback.bind(this); + return this._reloadCall.then(callBack, callBack); }, reloadCallback: function(result) { delete this._reloadCall; @@ -941,17 +941,17 @@ if (!result || result.status === 'error') { OC.Notification.show(result.data.message); - return; + return false; } if (result.status === 404) { // go back home this.changeDirectory('/'); - return; + return false; } // aborted ? if (result.status === 0){ - return; + return true; } // TODO: should rather return upload file size through @@ -963,6 +963,7 @@ } this.setFiles(result.data.files); + return true }, updateStorageStatistics: function(force) { diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css index 31c3bca8748..ddd9d10d664 100644 --- a/apps/files_sharing/css/public.css +++ b/apps/files_sharing/css/public.css @@ -88,20 +88,6 @@ thead { max-width: 90%; } -.header-right { - transition: opacity 500ms ease 0s; - -moz-transition: opacity 500ms ease 0s; - -ms-transition: opacity 500ms ease 0s; - -o-transition: opacity 500ms ease 0s; - -webkit-transition: opacity 500ms ease 0s; -} - -.header-right:hover, .header-right.active { - opacity: 1; - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; - filter: alpha(opacity=100); -} - /* within #save */ #remote_address { margin: 0; diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js index 1eb447da896..969a2b184d4 100644 --- a/apps/files_sharing/js/external.js +++ b/apps/files_sharing/js/external.js @@ -58,7 +58,7 @@ $(document).ready(function () { if (params.remote && params.token && params.owner && params.name) { // clear hash, it is unlikely that it contain any extra parameters location.hash = ''; - params.passwordProtected = parseInt(params.passwordProtected, 10) === 1; + params.passwordProtected = parseInt(params.protected, 10) === 1; OCA.Sharing.showAddExternalDialog( params.remote, params.token, diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js index f911f3689eb..a5027da0cfb 100644 --- a/apps/files_sharing/js/public.js +++ b/apps/files_sharing/js/public.js @@ -165,7 +165,6 @@ OCA.Sharing.PublicApp = { $('#save > button').click(function () { $(this).hide(); - $('.header-right').addClass('active'); $('.save-form').css('display', 'inline'); $('#remote_address').focus(); }); diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php index af317cc2027..dda283f4952 100644 --- a/apps/files_sharing/lib/external/manager.php +++ b/apps/files_sharing/lib/external/manager.php @@ -113,7 +113,9 @@ class Manager { * @return Mount */ protected function mountShare($data) { + $data['manager'] = $this; $mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint']; + $data['mountpoint'] = $mountPoint; $mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader); $this->mountManager->addMount($mount); return $mount; diff --git a/apps/files_sharing/lib/external/scanner.php b/apps/files_sharing/lib/external/scanner.php index 8921dd1a4c0..4dc5d4be9d8 100644 --- a/apps/files_sharing/lib/external/scanner.php +++ b/apps/files_sharing/lib/external/scanner.php @@ -19,23 +19,7 @@ class Scanner extends \OC\Files\Cache\Scanner { } public function scanAll() { - $remote = $this->storage->getRemote(); - $token = $this->storage->getToken(); - $password = $this->storage->getPassword(); - $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; - - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, - http_build_query(array('password' => $password))); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - - $result = curl_exec($ch); - curl_close($ch); - - $data = json_decode($result, true); + $data = $this->storage->getShareInfo(); if ($data['status'] === 'success') { $this->addResult($data['data'], ''); } else { diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php index 454196f15ae..3a0de51192e 100644 --- a/apps/files_sharing/lib/external/storage.php +++ b/apps/files_sharing/lib/external/storage.php @@ -10,7 +10,11 @@ namespace OCA\Files_Sharing\External; use OC\Files\Filesystem; use OC\Files\Storage\DAV; +use OC\ForbiddenException; use OCA\Files_Sharing\ISharedStorage; +use OCP\Files\NotFoundException; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; class Storage extends DAV implements ISharedStorage { /** @@ -35,7 +39,13 @@ class Storage extends DAV implements ISharedStorage { private $updateChecked = false; + /** + * @var \OCA\Files_Sharing\External\Manager + */ + private $manager; + public function __construct($options) { + $this->manager = $options['manager']; $this->remote = $options['remote']; $this->remoteUser = $options['owner']; list($protocol, $remote) = explode('://', $this->remote); @@ -108,6 +118,8 @@ class Storage extends DAV implements ISharedStorage { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException + * @throws \OCP\Files\StorageInvalidException * @return bool */ public function hasUpdated($path, $time) { @@ -117,6 +129,77 @@ class Storage extends DAV implements ISharedStorage { return false; } $this->updateChecked = true; - return parent::hasUpdated('', $time); + try { + return parent::hasUpdated('', $time); + } catch (StorageNotAvailableException $e) { + // see if we can find out why the share is unavailable\ + try { + $this->getShareInfo(); + } catch (NotFoundException $shareException) { + // a 404 can either mean that the share no longer exists or there is no ownCloud on the remote + if ($this->testRemote()) { + // valid ownCloud instance means that the public share no longer exists + // since this is permanent (re-sharing the file will create a new token) + // we remove the invalid storage + $this->manager->removeShare($this->mountPoint); + $this->manager->getMountManager()->removeMount($this->mountPoint); + throw new StorageInvalidException(); + } else { + // ownCloud instance is gone, likely to be a temporary server configuration error + throw $e; + } + } catch(\Exception $shareException) { + // todo, maybe handle 403 better and ask the user for a new password + throw $e; + } + throw $e; + } + } + + /** + * check if the configured remote is a valid ownCloud instance + * + * @return bool + */ + protected function testRemote() { + try { + $result = file_get_contents($this->remote . '/status.php'); + $data = json_decode($result); + return is_object($data) and !empty($data->version); + } catch (\Exception $e) { + return false; + } + } + + public function getShareInfo() { + $remote = $this->getRemote(); + $token = $this->getToken(); + $password = $this->getPassword(); + $url = $remote . '/index.php/apps/files_sharing/shareinfo?t=' . $token; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, + http_build_query(array('password' => $password))); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + $result = curl_exec($ch); + + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + + switch ($status) { + case 401: + case 403: + throw new ForbiddenException(); + case 404: + throw new NotFoundException(); + case 500: + throw new \Exception(); + } + + return json_decode($result, true); } } diff --git a/apps/files_sharing/templates/public.php b/apps/files_sharing/templates/public.php index c053aaabece..65e620a3425 100644 --- a/apps/files_sharing/templates/public.php +++ b/apps/files_sharing/templates/public.php @@ -17,7 +17,7 @@ <div class="header-right"> <span id="details"> <span id="save" data-protected="<?php p($_['protected'])?>" data-owner="<?php p($_['displayName'])?>" data-name="<?php p($_['filename'])?>"> - <button><?php p($l->t('Save to ownCloud')) ?></button> + <button><?php p($l->t('Add to your ownCloud')) ?></button> <form class="save-form hidden" action="#"> <input type="text" id="remote_address" placeholder="<?php p($l->t('example.com/owncloud')) ?>"/> <input type="submit" value="<?php p($l->t('Save')) ?>"/> diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php index 60c5787f295..1258148af53 100644 --- a/apps/files_sharing/tests/externalstorage.php +++ b/apps/files_sharing/tests/externalstorage.php @@ -72,6 +72,7 @@ class Test_Files_Sharing_External_Storage extends \PHPUnit_Framework_TestCase { 'mountpoint' => 'remoteshare', 'token' => 'abcdef', 'password' => '', + 'manager' => null ) ); $this->assertEquals($baseUri, $storage->getBaseUri()); diff --git a/core/css/mobile.css b/core/css/mobile.css index 2003e0a7f45..bdca29d888a 100644 --- a/core/css/mobile.css +++ b/core/css/mobile.css @@ -82,6 +82,11 @@ background-color: #fff; overflow-x: hidden !important; } +/* allow horizontal scrollbar in settings + otherwise user management is not usable on mobile */ +#body-settings #app-content { + overflow-x: auto !important; +} #app-navigation-toggle { position: fixed; @@ -129,6 +134,15 @@ table.multiselect thead { } +/* prevent overflow in user management controls bar */ +#usersearchform { + display: none; +} +#body-settings #controls { + min-width: 768px !important; +} + + /* fix controls bar jumping when navigation is slid out */ .snapjs-left #app-navigation-toggle, .snapjs-left #controls { diff --git a/lib/private/appframework/http/dispatcher.php b/lib/private/appframework/http/dispatcher.php index fa8d3c47a8b..7f2717951a5 100644 --- a/lib/private/appframework/http/dispatcher.php +++ b/lib/private/appframework/http/dispatcher.php @@ -145,7 +145,7 @@ class Dispatcher { ) { $value = false; - } elseif(in_array($type, $types)) { + } elseif($value !== null && in_array($type, $types)) { settype($value, $type); } diff --git a/lib/private/connector/sabre/objecttree.php b/lib/private/connector/sabre/objecttree.php index 54596db3c47..d7a96cfc88e 100644 --- a/lib/private/connector/sabre/objecttree.php +++ b/lib/private/connector/sabre/objecttree.php @@ -11,6 +11,8 @@ namespace OC\Connector\Sabre; use OC\Files\FileInfo; use OC\Files\Filesystem; use OC\Files\Mount\MoveableMount; +use OCP\Files\StorageInvalidException; +use OCP\Files\StorageNotAvailableException; class ObjectTree extends \Sabre\DAV\ObjectTree { @@ -83,7 +85,13 @@ class ObjectTree extends \Sabre\DAV\ObjectTree { } } else { // read from cache - $info = $this->fileView->getFileInfo($path); + try { + $info = $this->fileView->getFileInfo($path); + } catch (StorageNotAvailableException $e) { + throw new \Sabre\DAV\Exception\ServiceUnavailable('Storage not available'); + } catch (StorageInvalidException $e){ + throw new \Sabre\DAV\Exception\NotFound('Storage ' . $path . ' is invalid'); + } } if (!$info) { diff --git a/lib/private/files/mount/manager.php b/lib/private/files/mount/manager.php index 45a9f339fba..e5180cfe173 100644 --- a/lib/private/files/mount/manager.php +++ b/lib/private/files/mount/manager.php @@ -27,6 +27,10 @@ class Manager { * @param string $mountPoint */ public function removeMount($mountPoint) { + $mountPoint = Filesystem::normalizePath($mountPoint); + if (strlen($mountPoint) > 1) { + $mountPoint .= '/'; + } unset($this->mounts[$mountPoint]); } diff --git a/lib/private/files/storage/dav.php b/lib/private/files/storage/dav.php index 8b97f750204..726688fe444 100644 --- a/lib/private/files/storage/dav.php +++ b/lib/private/files/storage/dav.php @@ -8,6 +8,9 @@ namespace OC\Files\Storage; +use OCP\Files\StorageNotAvailableException; +use Sabre\DAV\Exception; + class DAV extends \OC\Files\Storage\Common { protected $password; protected $user; @@ -463,29 +466,36 @@ class DAV extends \OC\Files\Storage\Common { * * @param string $path * @param int $time + * @throws \OCP\Files\StorageNotAvailableException * @return bool */ public function hasUpdated($path, $time) { $this->init(); - $response = $this->client->propfind($this->encodePath($path), array( - '{DAV:}getlastmodified', - '{DAV:}getetag', - '{http://owncloud.org/ns}permissions' - )); - if (isset($response['{DAV:}getetag'])) { - $cachedData = $this->getCache()->get($path); - $etag = trim($response['{DAV:}getetag'], '"'); - if ($cachedData['etag'] !== $etag) { - return true; - } else if (isset($response['{http://owncloud.org/ns}permissions'])) { - $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); - return $permissions !== $cachedData['permissions']; + try { + $response = $this->client->propfind($this->encodePath($path), array( + '{DAV:}getlastmodified', + '{DAV:}getetag', + '{http://owncloud.org/ns}permissions' + )); + if (isset($response['{DAV:}getetag'])) { + $cachedData = $this->getCache()->get($path); + $etag = trim($response['{DAV:}getetag'], '"'); + if ($cachedData['etag'] !== $etag) { + return true; + } else if (isset($response['{http://owncloud.org/ns}permissions'])) { + $permissions = $this->parsePermissions($response['{http://owncloud.org/ns}permissions']); + return $permissions !== $cachedData['permissions']; + } else { + return false; + } } else { - return false; + $remoteMtime = strtotime($response['{DAV:}getlastmodified']); + return $remoteMtime > $time; } - } else { - $remoteMtime = strtotime($response['{DAV:}getlastmodified']); - return $remoteMtime > $time; + } catch (Exception\NotFound $e) { + return false; + } catch (Exception $e) { + throw new StorageNotAvailableException(); } } } diff --git a/lib/public/files/storageinvalidexception.php b/lib/public/files/storageinvalidexception.php new file mode 100644 index 00000000000..7419ccc1d11 --- /dev/null +++ b/lib/public/files/storageinvalidexception.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Storage has invalid configuration + */ +class StorageInvalidException extends \Exception { +} diff --git a/lib/public/files/storagenotavailableexception.php b/lib/public/files/storagenotavailableexception.php new file mode 100644 index 00000000000..b526cb4ea0f --- /dev/null +++ b/lib/public/files/storagenotavailableexception.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com> + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +/** + * Public interface of ownCloud for apps to use. + * Files/AlreadyExistsException class + */ + +// use OCP namespace for all classes that are considered public. +// This means that they should be used by apps instead of the internal ownCloud classes +namespace OCP\Files; + +/** + * Storage is temporarily not available + */ +class StorageNotAvailableException extends \Exception { +} diff --git a/public.php b/public.php index 1f858fd073d..2ac082dba57 100644 --- a/public.php +++ b/public.php @@ -17,7 +17,7 @@ try { if (!$pathInfo && !isset($_GET['service'])) { header('HTTP/1.0 404 Not Found'); exit; - } elseif ($_GET['service']) { + } elseif (isset($_GET['service'])) { $service = $_GET['service']; } else { $pathInfo = trim($pathInfo, '/'); |