Merge pull request #9311 from owncloud/storage-not-available
Handle storages not being available in webui and webdav
This commit is contained in:
commit
f4eb90e229
|
@ -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();
|
||||
|
||||
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')
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
$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));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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 {
|
||||
}
|
Loading…
Reference in New Issue