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();
|
OCP\JSON::checkLoggedIn();
|
||||||
\OC::$session->close();
|
\OC::$session->close();
|
||||||
|
$l = OC_L10N::get('files');
|
||||||
|
|
||||||
// Load the files
|
// Load the files
|
||||||
$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : '';
|
$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
|
||||||
$dir = \OC\Files\Filesystem::normalizePath($dir);
|
$dir = \OC\Files\Filesystem::normalizePath($dir);
|
||||||
$dirInfo = \OC\Files\Filesystem::getFileInfo($dir);
|
|
||||||
if (!$dirInfo || !$dirInfo->getType() === 'dir') {
|
try {
|
||||||
|
$dirInfo = \OC\Files\Filesystem::getFileInfo($dir);
|
||||||
|
if (!$dirInfo || !$dirInfo->getType() === 'dir') {
|
||||||
header("HTTP/1.0 404 Not Found");
|
header("HTTP/1.0 404 Not Found");
|
||||||
exit();
|
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
|
* @param {boolean} force set to true to force changing directory
|
||||||
*/
|
*/
|
||||||
changeDirectory: function(targetDir, changeUrl, force) {
|
changeDirectory: function(targetDir, changeUrl, force) {
|
||||||
|
var self = this;
|
||||||
var currentDir = this.getCurrentDirectory();
|
var currentDir = this.getCurrentDirectory();
|
||||||
targetDir = targetDir || '/';
|
targetDir = targetDir || '/';
|
||||||
if (!force && currentDir === targetDir) {
|
if (!force && currentDir === targetDir) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._setCurrentDir(targetDir, changeUrl);
|
this._setCurrentDir(targetDir, changeUrl);
|
||||||
this.reload();
|
this.reload().then(function(success){
|
||||||
|
if (!success) {
|
||||||
|
self.changeDirectory(currentDir, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
linkTo: function(dir) {
|
linkTo: function(dir) {
|
||||||
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
|
||||||
|
@ -912,7 +917,6 @@
|
||||||
* @brief Reloads the file list using ajax call
|
* @brief Reloads the file list using ajax call
|
||||||
*/
|
*/
|
||||||
reload: function() {
|
reload: function() {
|
||||||
var self = this;
|
|
||||||
this._selectedFiles = {};
|
this._selectedFiles = {};
|
||||||
this._selectionSummary.clear();
|
this._selectionSummary.clear();
|
||||||
this.$el.find('.select-all').prop('checked', false);
|
this.$el.find('.select-all').prop('checked', false);
|
||||||
|
@ -926,14 +930,10 @@
|
||||||
dir : this.getCurrentDirectory(),
|
dir : this.getCurrentDirectory(),
|
||||||
sort: this._sort,
|
sort: this._sort,
|
||||||
sortdirection: this._sortDirection
|
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) {
|
reloadCallback: function(result) {
|
||||||
delete this._reloadCall;
|
delete this._reloadCall;
|
||||||
|
@ -941,17 +941,17 @@
|
||||||
|
|
||||||
if (!result || result.status === 'error') {
|
if (!result || result.status === 'error') {
|
||||||
OC.Notification.show(result.data.message);
|
OC.Notification.show(result.data.message);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.status === 404) {
|
if (result.status === 404) {
|
||||||
// go back home
|
// go back home
|
||||||
this.changeDirectory('/');
|
this.changeDirectory('/');
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// aborted ?
|
// aborted ?
|
||||||
if (result.status === 0){
|
if (result.status === 0){
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should rather return upload file size through
|
// TODO: should rather return upload file size through
|
||||||
|
@ -963,6 +963,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setFiles(result.data.files);
|
this.setFiles(result.data.files);
|
||||||
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
updateStorageStatistics: function(force) {
|
updateStorageStatistics: function(force) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ $(document).ready(function () {
|
||||||
if (params.remote && params.token && params.owner && params.name) {
|
if (params.remote && params.token && params.owner && params.name) {
|
||||||
// clear hash, it is unlikely that it contain any extra parameters
|
// clear hash, it is unlikely that it contain any extra parameters
|
||||||
location.hash = '';
|
location.hash = '';
|
||||||
params.passwordProtected = parseInt(params.passwordProtected, 10) === 1;
|
params.passwordProtected = parseInt(params.protected, 10) === 1;
|
||||||
OCA.Sharing.showAddExternalDialog(
|
OCA.Sharing.showAddExternalDialog(
|
||||||
params.remote,
|
params.remote,
|
||||||
params.token,
|
params.token,
|
||||||
|
|
|
@ -113,7 +113,9 @@ class Manager {
|
||||||
* @return Mount
|
* @return Mount
|
||||||
*/
|
*/
|
||||||
protected function mountShare($data) {
|
protected function mountShare($data) {
|
||||||
|
$data['manager'] = $this;
|
||||||
$mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
|
$mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
|
||||||
|
$data['mountpoint'] = $mountPoint;
|
||||||
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
|
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
|
||||||
$this->mountManager->addMount($mount);
|
$this->mountManager->addMount($mount);
|
||||||
return $mount;
|
return $mount;
|
||||||
|
|
|
@ -19,23 +19,7 @@ class Scanner extends \OC\Files\Cache\Scanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scanAll() {
|
public function scanAll() {
|
||||||
$remote = $this->storage->getRemote();
|
$data = $this->storage->getShareInfo();
|
||||||
$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);
|
|
||||||
if ($data['status'] === 'success') {
|
if ($data['status'] === 'success') {
|
||||||
$this->addResult($data['data'], '');
|
$this->addResult($data['data'], '');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,7 +10,11 @@ namespace OCA\Files_Sharing\External;
|
||||||
|
|
||||||
use OC\Files\Filesystem;
|
use OC\Files\Filesystem;
|
||||||
use OC\Files\Storage\DAV;
|
use OC\Files\Storage\DAV;
|
||||||
|
use OC\ForbiddenException;
|
||||||
use OCA\Files_Sharing\ISharedStorage;
|
use OCA\Files_Sharing\ISharedStorage;
|
||||||
|
use OCP\Files\NotFoundException;
|
||||||
|
use OCP\Files\StorageInvalidException;
|
||||||
|
use OCP\Files\StorageNotAvailableException;
|
||||||
|
|
||||||
class Storage extends DAV implements ISharedStorage {
|
class Storage extends DAV implements ISharedStorage {
|
||||||
/**
|
/**
|
||||||
|
@ -35,7 +39,13 @@ class Storage extends DAV implements ISharedStorage {
|
||||||
|
|
||||||
private $updateChecked = false;
|
private $updateChecked = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \OCA\Files_Sharing\External\Manager
|
||||||
|
*/
|
||||||
|
private $manager;
|
||||||
|
|
||||||
public function __construct($options) {
|
public function __construct($options) {
|
||||||
|
$this->manager = $options['manager'];
|
||||||
$this->remote = $options['remote'];
|
$this->remote = $options['remote'];
|
||||||
$this->remoteUser = $options['owner'];
|
$this->remoteUser = $options['owner'];
|
||||||
list($protocol, $remote) = explode('://', $this->remote);
|
list($protocol, $remote) = explode('://', $this->remote);
|
||||||
|
@ -108,6 +118,8 @@ class Storage extends DAV implements ISharedStorage {
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param int $time
|
* @param int $time
|
||||||
|
* @throws \OCP\Files\StorageNotAvailableException
|
||||||
|
* @throws \OCP\Files\StorageInvalidException
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasUpdated($path, $time) {
|
public function hasUpdated($path, $time) {
|
||||||
|
@ -117,6 +129,77 @@ class Storage extends DAV implements ISharedStorage {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$this->updateChecked = true;
|
$this->updateChecked = true;
|
||||||
|
try {
|
||||||
return parent::hasUpdated('', $time);
|
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',
|
'mountpoint' => 'remoteshare',
|
||||||
'token' => 'abcdef',
|
'token' => 'abcdef',
|
||||||
'password' => '',
|
'password' => '',
|
||||||
|
'manager' => null
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$this->assertEquals($baseUri, $storage->getBaseUri());
|
$this->assertEquals($baseUri, $storage->getBaseUri());
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace OC\Connector\Sabre;
|
||||||
use OC\Files\FileInfo;
|
use OC\Files\FileInfo;
|
||||||
use OC\Files\Filesystem;
|
use OC\Files\Filesystem;
|
||||||
use OC\Files\Mount\MoveableMount;
|
use OC\Files\Mount\MoveableMount;
|
||||||
|
use OCP\Files\StorageInvalidException;
|
||||||
|
use OCP\Files\StorageNotAvailableException;
|
||||||
|
|
||||||
class ObjectTree extends \Sabre\DAV\ObjectTree {
|
class ObjectTree extends \Sabre\DAV\ObjectTree {
|
||||||
|
|
||||||
|
@ -83,7 +85,13 @@ class ObjectTree extends \Sabre\DAV\ObjectTree {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// read from cache
|
// read from cache
|
||||||
|
try {
|
||||||
$info = $this->fileView->getFileInfo($path);
|
$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) {
|
if (!$info) {
|
||||||
|
|
|
@ -27,6 +27,10 @@ class Manager {
|
||||||
* @param string $mountPoint
|
* @param string $mountPoint
|
||||||
*/
|
*/
|
||||||
public function removeMount($mountPoint) {
|
public function removeMount($mountPoint) {
|
||||||
|
$mountPoint = Filesystem::normalizePath($mountPoint);
|
||||||
|
if (strlen($mountPoint) > 1) {
|
||||||
|
$mountPoint .= '/';
|
||||||
|
}
|
||||||
unset($this->mounts[$mountPoint]);
|
unset($this->mounts[$mountPoint]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
|
|
||||||
namespace OC\Files\Storage;
|
namespace OC\Files\Storage;
|
||||||
|
|
||||||
|
use OCP\Files\StorageNotAvailableException;
|
||||||
|
use Sabre\DAV\Exception;
|
||||||
|
|
||||||
class DAV extends \OC\Files\Storage\Common {
|
class DAV extends \OC\Files\Storage\Common {
|
||||||
protected $password;
|
protected $password;
|
||||||
protected $user;
|
protected $user;
|
||||||
|
@ -463,10 +466,12 @@ class DAV extends \OC\Files\Storage\Common {
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param int $time
|
* @param int $time
|
||||||
|
* @throws \OCP\Files\StorageNotAvailableException
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function hasUpdated($path, $time) {
|
public function hasUpdated($path, $time) {
|
||||||
$this->init();
|
$this->init();
|
||||||
|
try {
|
||||||
$response = $this->client->propfind($this->encodePath($path), array(
|
$response = $this->client->propfind($this->encodePath($path), array(
|
||||||
'{DAV:}getlastmodified',
|
'{DAV:}getlastmodified',
|
||||||
'{DAV:}getetag',
|
'{DAV:}getetag',
|
||||||
|
@ -487,6 +492,11 @@ class DAV extends \OC\Files\Storage\Common {
|
||||||
$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
|
$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
|
||||||
return $remoteMtime > $time;
|
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