mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 08:44:07 -04:00
Merge pull request #16158 from owncloud/mountprovider-after-setup
Call newly registered mount providers after the filesystem is setup
This commit is contained in:
commit
a968b8409d
13 changed files with 206 additions and 97 deletions
|
|
@ -22,12 +22,16 @@
|
|||
|
||||
namespace OC\Files\Config;
|
||||
|
||||
use OC\Hooks\Emitter;
|
||||
use OC\Hooks\EmitterTrait;
|
||||
use OCP\Files\Config\IMountProviderCollection;
|
||||
use OCP\Files\Config\IMountProvider;
|
||||
use OCP\Files\Storage\IStorageFactory;
|
||||
use OCP\IUser;
|
||||
|
||||
class MountProviderCollection implements IMountProviderCollection {
|
||||
class MountProviderCollection implements IMountProviderCollection, Emitter {
|
||||
use EmitterTrait;
|
||||
|
||||
/**
|
||||
* @var \OCP\Files\Config\IMountProvider[]
|
||||
*/
|
||||
|
|
@ -65,5 +69,6 @@ class MountProviderCollection implements IMountProviderCollection {
|
|||
*/
|
||||
public function registerProvider(IMountProvider $provider) {
|
||||
$this->providers[] = $provider;
|
||||
$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,11 @@
|
|||
|
||||
namespace OC\Files;
|
||||
|
||||
use OC\Cache\File;
|
||||
use OC\Files\Config\MountProviderCollection;
|
||||
use OC\Files\Storage\StorageFactory;
|
||||
use OCP\Files\Config\IMountProvider;
|
||||
use OCP\IUserManager;
|
||||
|
||||
class Filesystem {
|
||||
|
||||
|
|
@ -78,6 +82,8 @@ class Filesystem {
|
|||
|
||||
static private $normalizedPathCache = array();
|
||||
|
||||
static private $listeningForProviders = false;
|
||||
|
||||
/**
|
||||
* classname which used for hooks handling
|
||||
* used as signalclass in OC_Hooks::emit()
|
||||
|
|
@ -371,14 +377,15 @@ class Filesystem {
|
|||
|
||||
$root = \OC_User::getHome($user);
|
||||
|
||||
$userObject = \OC_User::getManager()->get($user);
|
||||
$userManager = \OC::$server->getUserManager();
|
||||
$userObject = $userManager->get($user);
|
||||
|
||||
if (is_null($userObject)) {
|
||||
\OCP\Util::writeLog('files', ' Backends provided no user object for '.$user, \OCP\Util::ERROR);
|
||||
\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, \OCP\Util::ERROR);
|
||||
throw new \OC\User\NoUserException();
|
||||
}
|
||||
|
||||
$homeStorage = \OC_Config::getValue( 'objectstore' );
|
||||
$homeStorage = \OC_Config::getValue('objectstore');
|
||||
if (!empty($homeStorage)) {
|
||||
// sanity checks
|
||||
if (empty($homeStorage['class'])) {
|
||||
|
|
@ -412,16 +419,41 @@ class Filesystem {
|
|||
self::mountCacheDir($user);
|
||||
|
||||
// Chance to mount for other storages
|
||||
if($userObject) {
|
||||
$mountConfigManager = \OC::$server->getMountProviderCollection();
|
||||
/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
|
||||
$mountConfigManager = \OC::$server->getMountProviderCollection();
|
||||
if ($userObject) {
|
||||
$mounts = $mountConfigManager->getMountsForUser($userObject);
|
||||
array_walk($mounts, array(self::$mounts, 'addMount'));
|
||||
}
|
||||
|
||||
self::listenForNewMountProviders($mountConfigManager, $userManager);
|
||||
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get mounts from mount providers that are registered after setup
|
||||
*
|
||||
* @param MountProviderCollection $mountConfigManager
|
||||
* @param IUserManager $userManager
|
||||
*/
|
||||
private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
|
||||
if (!self::$listeningForProviders) {
|
||||
self::$listeningForProviders = true;
|
||||
$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
|
||||
foreach (Filesystem::$usersSetup as $user => $setup) {
|
||||
$userObject = $userManager->get($user);
|
||||
if ($userObject) {
|
||||
$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
|
||||
array_walk($mounts, array(self::$mounts, 'addMount'));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts the cache directory
|
||||
*
|
||||
* @param string $user user name
|
||||
*/
|
||||
private static function mountCacheDir($user) {
|
||||
|
|
@ -455,6 +487,7 @@ class Filesystem {
|
|||
|
||||
/**
|
||||
* get the relative path of the root data directory for the current user
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* Returns path like /admin/files
|
||||
|
|
@ -537,7 +570,7 @@ class Filesystem {
|
|||
if (!$path || $path[0] !== '/') {
|
||||
$path = '/' . $path;
|
||||
}
|
||||
if (strpos($path, '/../') !== FALSE || strrchr($path, '/') === '/..') {
|
||||
if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -577,6 +610,7 @@ class Filesystem {
|
|||
/**
|
||||
* check if the directory should be ignored when scanning
|
||||
* NOTE: the special directories . and .. would cause never ending recursion
|
||||
*
|
||||
* @param String $dir
|
||||
* @return boolean
|
||||
*/
|
||||
|
|
@ -745,6 +779,7 @@ class Filesystem {
|
|||
|
||||
/**
|
||||
* Fix common problems with a file path
|
||||
*
|
||||
* @param string $path
|
||||
* @param bool $stripTrailingSlash
|
||||
* @param bool $isAbsolutePath
|
||||
|
|
@ -761,7 +796,7 @@ class Filesystem {
|
|||
|
||||
$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath]);
|
||||
|
||||
if(isset(self::$normalizedPathCache[$cacheKey])) {
|
||||
if (isset(self::$normalizedPathCache[$cacheKey])) {
|
||||
return self::$normalizedPathCache[$cacheKey];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class Root extends Folder implements IRootFolder {
|
|||
* @param string $method
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function listen($scope, $method, $callback) {
|
||||
public function listen($scope, $method, callable $callback) {
|
||||
$this->emitter->listen($scope, $method, $callback);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +103,7 @@ class Root extends Folder implements IRootFolder {
|
|||
* @param string $method optional
|
||||
* @param callable $callback optional
|
||||
*/
|
||||
public function removeListener($scope = null, $method = null, $callback = null) {
|
||||
public function removeListener($scope = null, $method = null, callable $callback = null) {
|
||||
$this->emitter->removeListener($scope, $method, $callback);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,81 +23,5 @@
|
|||
namespace OC\Hooks;
|
||||
|
||||
abstract class BasicEmitter implements Emitter {
|
||||
|
||||
/**
|
||||
* @var (callable[])[] $listeners
|
||||
*/
|
||||
protected $listeners = array();
|
||||
|
||||
/**
|
||||
* @param string $scope
|
||||
* @param string $method
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function listen($scope, $method, $callback) {
|
||||
$eventName = $scope . '::' . $method;
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
$this->listeners[$eventName] = array();
|
||||
}
|
||||
if (array_search($callback, $this->listeners[$eventName]) === false) {
|
||||
$this->listeners[$eventName][] = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scope optional
|
||||
* @param string $method optional
|
||||
* @param callable $callback optional
|
||||
*/
|
||||
public function removeListener($scope = null, $method = null, $callback = null) {
|
||||
$names = array();
|
||||
$allNames = array_keys($this->listeners);
|
||||
if ($scope and $method) {
|
||||
$name = $scope . '::' . $method;
|
||||
if (isset($this->listeners[$name])) {
|
||||
$names[] = $name;
|
||||
}
|
||||
} elseif ($scope) {
|
||||
foreach ($allNames as $name) {
|
||||
$parts = explode('::', $name, 2);
|
||||
if ($parts[0] == $scope) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
} elseif ($method) {
|
||||
foreach ($allNames as $name) {
|
||||
$parts = explode('::', $name, 2);
|
||||
if ($parts[1] == $method) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$names = $allNames;
|
||||
}
|
||||
|
||||
foreach ($names as $name) {
|
||||
if ($callback) {
|
||||
$index = array_search($callback, $this->listeners[$name]);
|
||||
if ($index !== false) {
|
||||
unset($this->listeners[$name][$index]);
|
||||
}
|
||||
} else {
|
||||
$this->listeners[$name] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scope
|
||||
* @param string $method
|
||||
* @param array $arguments optional
|
||||
*/
|
||||
protected function emit($scope, $method, $arguments = array()) {
|
||||
$eventName = $scope . '::' . $method;
|
||||
if (isset($this->listeners[$eventName])) {
|
||||
foreach ($this->listeners[$eventName] as $callback) {
|
||||
call_user_func_array($callback, $arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
use EmitterTrait;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ interface Emitter {
|
|||
* @param callable $callback
|
||||
* @return void
|
||||
*/
|
||||
public function listen($scope, $method, $callback);
|
||||
public function listen($scope, $method, callable $callback);
|
||||
|
||||
/**
|
||||
* @param string $scope optional
|
||||
|
|
@ -45,5 +45,5 @@ interface Emitter {
|
|||
* @param callable $callback optional
|
||||
* @return void
|
||||
*/
|
||||
public function removeListener($scope = null, $method = null, $callback = null);
|
||||
public function removeListener($scope = null, $method = null, callable $callback = null);
|
||||
}
|
||||
|
|
|
|||
103
lib/private/hooks/emittertrait.php
Normal file
103
lib/private/hooks/emittertrait.php
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Morris Jobke <hey@morrisjobke.de>
|
||||
* @author Robin Appelman <icewind@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2015, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
*
|
||||
* This code is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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, version 3,
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OC\Hooks;
|
||||
|
||||
trait EmitterTrait {
|
||||
|
||||
/**
|
||||
* @var (callable[])[] $listeners
|
||||
*/
|
||||
protected $listeners = array();
|
||||
|
||||
/**
|
||||
* @param string $scope
|
||||
* @param string $method
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function listen($scope, $method, callable $callback) {
|
||||
$eventName = $scope . '::' . $method;
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
$this->listeners[$eventName] = array();
|
||||
}
|
||||
if (array_search($callback, $this->listeners[$eventName], true) === false) {
|
||||
$this->listeners[$eventName][] = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scope optional
|
||||
* @param string $method optional
|
||||
* @param callable $callback optional
|
||||
*/
|
||||
public function removeListener($scope = null, $method = null, callable $callback = null) {
|
||||
$names = array();
|
||||
$allNames = array_keys($this->listeners);
|
||||
if ($scope and $method) {
|
||||
$name = $scope . '::' . $method;
|
||||
if (isset($this->listeners[$name])) {
|
||||
$names[] = $name;
|
||||
}
|
||||
} elseif ($scope) {
|
||||
foreach ($allNames as $name) {
|
||||
$parts = explode('::', $name, 2);
|
||||
if ($parts[0] == $scope) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
} elseif ($method) {
|
||||
foreach ($allNames as $name) {
|
||||
$parts = explode('::', $name, 2);
|
||||
if ($parts[1] == $method) {
|
||||
$names[] = $name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$names = $allNames;
|
||||
}
|
||||
|
||||
foreach ($names as $name) {
|
||||
if ($callback) {
|
||||
$index = array_search($callback, $this->listeners[$name], true);
|
||||
if ($index !== false) {
|
||||
unset($this->listeners[$name][$index]);
|
||||
}
|
||||
} else {
|
||||
$this->listeners[$name] = array();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scope
|
||||
* @param string $method
|
||||
* @param array $arguments optional
|
||||
*/
|
||||
protected function emit($scope, $method, array $arguments = array()) {
|
||||
$eventName = $scope . '::' . $method;
|
||||
if (isset($this->listeners[$eventName])) {
|
||||
foreach ($this->listeners[$eventName] as $callback) {
|
||||
call_user_func_array($callback, $arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ abstract class ForwardingEmitter extends BasicEmitter {
|
|||
* @param string $method
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function listen($scope, $method, $callback) {
|
||||
public function listen($scope, $method, callable $callback) {
|
||||
parent::listen($scope, $method, $callback);
|
||||
foreach ($this->forwardEmitters as $emitter) {
|
||||
$emitter->listen($scope, $method, $callback);
|
||||
|
|
@ -50,7 +50,7 @@ abstract class ForwardingEmitter extends BasicEmitter {
|
|||
/**
|
||||
* @param \OC\Hooks\Emitter $emitter
|
||||
*/
|
||||
protected function forward($emitter) {
|
||||
protected function forward(Emitter $emitter) {
|
||||
$this->forwardEmitters[] = $emitter;
|
||||
|
||||
//forward all previously connected hooks
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
namespace OC\Hooks;
|
||||
|
||||
abstract class LegacyEmitter extends BasicEmitter {
|
||||
protected function emit($scope, $method, $arguments = array()) {
|
||||
protected function emit($scope, $method, array $arguments = array()) {
|
||||
\OC_Hook::emit($scope, $method, $arguments);
|
||||
parent::emit($scope, $method, $arguments);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class PublicEmitter extends BasicEmitter {
|
|||
* @param string $method
|
||||
* @param array $arguments optional
|
||||
*/
|
||||
public function emit($scope, $method, $arguments = array()) {
|
||||
public function emit($scope, $method, array $arguments = array()) {
|
||||
parent::emit($scope, $method, $arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class Repair extends BasicEmitter {
|
|||
*
|
||||
* Re-declared as public to allow invocation from within the closure above in php 5.3
|
||||
*/
|
||||
public function emit($scope, $method, $arguments = array()) {
|
||||
public function emit($scope, $method, array $arguments = array()) {
|
||||
parent::emit($scope, $method, $arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class Session implements IUserSession, Emitter {
|
|||
* @param string $method
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function listen($scope, $method, $callback) {
|
||||
public function listen($scope, $method, callable $callback) {
|
||||
$this->manager->listen($scope, $method, $callback);
|
||||
}
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ class Session implements IUserSession, Emitter {
|
|||
* @param string $method optional
|
||||
* @param callable $callback optional
|
||||
*/
|
||||
public function removeListener($scope = null, $method = null, $callback = null) {
|
||||
public function removeListener($scope = null, $method = null, callable $callback = null) {
|
||||
$this->manager->removeListener($scope, $method, $callback);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,11 +22,39 @@
|
|||
|
||||
namespace Test\Files;
|
||||
|
||||
use OC\Files\Mount\MountPoint;
|
||||
use OC\Files\Storage\Temporary;
|
||||
use OC\User\NoUserException;
|
||||
use OCP\Files\Config\IMountProvider;
|
||||
use OCP\Files\Storage\IStorageFactory;
|
||||
use OCP\IUser;
|
||||
|
||||
class DummyMountProvider implements IMountProvider {
|
||||
private $mounts = [];
|
||||
|
||||
/**
|
||||
* @param array $mounts
|
||||
*/
|
||||
public function __construct(array $mounts) {
|
||||
$this->mounts = $mounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pre-registered mount points
|
||||
*
|
||||
* @param IUser $user
|
||||
* @param IStorageFactory $loader
|
||||
* @return \OCP\Files\Mount\IMountPoint[]
|
||||
*/
|
||||
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
|
||||
return isset($this->mounts[$user->getUID()]) ? $this->mounts[$user->getUID()] : [];
|
||||
}
|
||||
}
|
||||
|
||||
class Filesystem extends \Test\TestCase {
|
||||
|
||||
const TEST_FILESYSTEM_USER1 = "test-filesystem-user1";
|
||||
const TEST_FILESYSTEM_USER2 = "test-filesystem-user1";
|
||||
|
||||
/**
|
||||
* @var array tmpDirs
|
||||
|
|
@ -44,6 +72,10 @@ class Filesystem extends \Test\TestCase {
|
|||
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$userBackend = new \OC_User_Dummy();
|
||||
$userBackend->createUser(self::TEST_FILESYSTEM_USER1, self::TEST_FILESYSTEM_USER1);
|
||||
$userBackend->createUser(self::TEST_FILESYSTEM_USER2, self::TEST_FILESYSTEM_USER2);
|
||||
\OC::$server->getUserManager()->registerBackend($userBackend);
|
||||
$this->loginAsUser();
|
||||
}
|
||||
|
||||
|
|
@ -271,6 +303,7 @@ class Filesystem extends \Test\TestCase {
|
|||
|
||||
/**
|
||||
* Tests that an exception is thrown when passed user does not exist.
|
||||
*
|
||||
* @expectedException \OC\User\NoUserException
|
||||
*/
|
||||
public function testLocalMountWhenUserDoesNotExist() {
|
||||
|
|
@ -380,4 +413,13 @@ class Filesystem extends \Test\TestCase {
|
|||
|
||||
\OC_Config::setValue('cache_path', $oldCachePath);
|
||||
}
|
||||
|
||||
public function testRegisterMountProviderAfterSetup() {
|
||||
\OC\Files\Filesystem::initMountPoints(self::TEST_FILESYSTEM_USER2);
|
||||
$this->assertEquals('/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
|
||||
$mount = new MountPoint(new Temporary([]), '/foo/bar');
|
||||
$mountProvider = new DummyMountProvider([self::TEST_FILESYSTEM_USER2 => [$mount]]);
|
||||
\OC::$server->getMountProviderCollection()->registerProvider($mountProvider);
|
||||
$this->assertEquals('/foo/bar/', \OC\Files\Filesystem::getMountPoint('/foo/bar'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class DummyForwardingEmitter extends \OC\Hooks\ForwardingEmitter {
|
|||
/**
|
||||
* @param \OC\Hooks\Emitter $emitter
|
||||
*/
|
||||
public function forward($emitter) {
|
||||
public function forward(\OC\Hooks\Emitter $emitter) {
|
||||
parent::forward($emitter);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue