Introduce UserGlobalStoragesService

UserGlobalStoragesService reads the global storage configuration,
cherry-picking storages applicable to a user. Writing storages through
this service is forbidden, on punishment of throwing an exception.
Storage IDs may also be config hashes when retrieved from this service,
as it is unable to update the storages with real IDs.

As UserGlobalStoragesService and UserStoragesService share a bit of code
relating to users, that has been split into UserTrait. UserTrait also
allows for the user set to be overridden, rather than using the user
from IUserSession.

Config\ConfigAdapter has been reworked to use UserStoragesService and
UserGlobalStoragesService instead of
OC_Mount_Config::getAbsoluteMountPoints(), further reducing dependance
on that horrible static class.
This commit is contained in:
Robin McCorkell 2015-08-12 14:22:27 +01:00
parent 37beb58c6f
commit a6a69ef1df
6 changed files with 312 additions and 36 deletions

View File

@ -2,6 +2,7 @@
/**
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <icewind@owncloud.com>
* @author Robin McCorkell <rmccorkell@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
@ -22,23 +23,67 @@
namespace OCA\Files_External\Config;
use OCP\Files\Storage;
use OC\Files\Mount\MountPoint;
use OCP\Files\Storage\IStorageFactory;
use OCA\Files_External\Lib\PersonalMount;
use OCP\Files\Config\IMountProvider;
use OCP\IUser;
use OCA\Files_external\Service\UserStoragesService;
use OCA\Files_External\Service\UserGlobalStoragesService;
use OCA\Files_External\Lib\StorageConfig;
/**
* Make the old files_external config work with the new public mount config api
*/
class ConfigAdapter implements IMountProvider {
/** @var UserStoragesService */
private $userStoragesService;
/** @var UserGlobalStoragesService */
private $userGlobalStoragesService;
/**
* @param UserStoragesService $userStoragesService
* @param UserGlobalStoragesService $userGlobalStoragesService
*/
public function __construct(UserStoragesService $userStoragesService) {
public function __construct(
UserStoragesService $userStoragesService,
UserGlobalStoragesService $userGlobalStoragesService
) {
$this->userStoragesService = $userStoragesService;
$this->userGlobalStoragesService = $userGlobalStoragesService;
}
/**
* Process storage ready for mounting
*
* @param StorageConfig $storage
*/
private function prepareStorageConfig(StorageConfig &$storage) {
$objectStore = $storage->getBackendOption('objectstore');
if ($objectStore) {
$objectClass = $objectStore['class'];
$storage->setBackendOption('objectstore', new $objectClass($objectStore));
}
$storage->getBackend()->manipulateStorageConfig($storage);
}
/**
* Construct the storage implementation
*
* @param StorageConfig $storageConfig
* @return Storage
*/
private function constructStorage(StorageConfig $storageConfig) {
$class = $storageConfig->getBackend()->getStorageClass();
$storage = new $class($storageConfig->getBackendOptions());
$storage = $storageConfig->getBackend()->wrapStorage($storage);
return $storage;
}
/**
@ -49,21 +94,44 @@ class ConfigAdapter implements IMountProvider {
* @return \OCP\Files\Mount\IMountPoint[]
*/
public function getMountsForUser(IUser $user, IStorageFactory $loader) {
$mountPoints = \OC_Mount_Config::getAbsoluteMountPoints($user->getUID());
$mounts = array();
foreach ($mountPoints as $mountPoint => $options) {
if (isset($options['options']['objectstore'])) {
$objectClass = $options['options']['objectstore']['class'];
$options['options']['objectstore'] = new $objectClass($options['options']['objectstore']);
}
$mountOptions = isset($options['mountOptions']) ? $options['mountOptions'] : [];
if (isset($options['personal']) && $options['personal']) {
$mount = new PersonalMount($this->userStoragesService, $options['id'], $options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
$mounts[] = $mount;
} else {
$mounts[] = new MountPoint($options['class'], $mountPoint, $options['options'], $loader, $mountOptions);
}
$mounts = [];
$this->userStoragesService->setUser($user);
$this->userGlobalStoragesService->setUser($user);
foreach ($this->userGlobalStoragesService->getAllStorages() as $storage) {
$this->prepareStorageConfig($storage);
$impl = $this->constructStorage($storage);
$mount = new MountPoint(
$impl,
'/'.$user->getUID().'/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
);
$mounts[$storage->getMountPoint()] = $mount;
}
foreach ($this->userStoragesService->getAllStorages() as $storage) {
$this->prepareStorageConfig($storage);
$impl = $this->constructStorage($storage);
$mount = new PersonalMount(
$this->userStoragesService,
$storage->getId(),
$impl,
'/'.$user->getUID().'/files' . $storage->getMountPoint(),
null,
$loader,
$storage->getMountOptions()
);
$mounts[$storage->getMountPoint()] = $mount;
}
$this->userStoragesService->resetUser();
$this->userGlobalStoragesService->resetUser();
return $mounts;
}
}

View File

@ -92,7 +92,7 @@ class GlobalStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
\OC_Mount_Config::writeData(null, $mountPoints);
$this->writeLegacyConfig($mountPoints);
}
/**

View File

@ -55,6 +55,16 @@ abstract class StoragesService {
return \OC_Mount_Config::readData();
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
// write global config
\OC_Mount_Config::writeData(null, $mountPoints);
}
/**
* Copy legacy storage options into the given storage config object.
*
@ -202,20 +212,30 @@ abstract class StoragesService {
// process storages with config hash, they must get a real id
if (!empty($storagesWithConfigHash)) {
$nextId = $this->generateNextId($storages);
foreach ($storagesWithConfigHash as $storage) {
$storage->setId($nextId);
$storages[$nextId] = $storage;
$nextId++;
}
// re-save the config with the generated ids
$this->writeConfig($storages);
$this->setRealStorageIds($storages, $storagesWithConfigHash);
}
return $storages;
}
/**
* Replace config hash ID with real IDs, for migrating legacy storages
*
* @param StorageConfig[] $storages Storages with real IDs
* @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
*/
protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
$nextId = $this->generateNextId($storages);
foreach ($storagesWithConfigHash as $storage) {
$storage->setId($nextId);
$storages[$nextId] = $storage;
$nextId++;
}
// re-save the config with the generated ids
$this->writeConfig($storages);
}
/**
* Add mount point into the messy mount point structure
*

View File

@ -0,0 +1,107 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@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 OCA\Files_External\Service;
use \OCA\Files_external\Service\GlobalStoragesService;
use \OCA\Files_External\Service\BackendService;
use \OCP\IUserSession;
use \OCP\IGroupManager;
use \OCA\Files_External\Service\UserTrait;
/**
* Service class to read global storages applicable to the user
* Read-only access available, attempting to write will throw DomainException
*/
class UserGlobalStoragesService extends GlobalStoragesService {
use UserTrait;
/** @var IGroupManager */
protected $groupManager;
/**
* @param BackendService $backendService
* @param IUserSession $userSession
* @param IGroupManager $groupManager
*/
public function __construct(
BackendService $backendService,
IUserSession $userSession,
IGroupManager $groupManager
) {
parent::__construct($backendService);
$this->userSession = $userSession;
$this->groupManager = $groupManager;
}
/**
* Replace config hash ID with real IDs, for migrating legacy storages
*
* @param StorageConfig[] $storages Storages with real IDs
* @param StorageConfig[] $storagesWithConfigHash Storages with config hash IDs
*/
protected function setRealStorageIds(array &$storages, array $storagesWithConfigHash) {
// as a read-only view, storage IDs don't need to be real
foreach ($storagesWithConfigHash as $storage) {
$storages[$storage->getId()] = $storage;
}
}
/**
* Read legacy config data
*
* @return array list of mount configs
*/
protected function readLegacyConfig() {
// read global config
$data = parent::readLegacyConfig();
$userId = $this->getUser()->getUID();
if (isset($data[\OC_Mount_Config::MOUNT_TYPE_USER])) {
$data[\OC_Mount_Config::MOUNT_TYPE_USER] = array_filter(
$data[\OC_Mount_Config::MOUNT_TYPE_USER], function($key) use ($userId) {
return (strtolower($key) === strtolower($userId) || $key === 'all');
}, ARRAY_FILTER_USE_KEY
);
}
if (isset($data[\OC_Mount_Config::MOUNT_TYPE_GROUP])) {
$data[\OC_Mount_Config::MOUNT_TYPE_GROUP] = array_filter(
$data[\OC_Mount_Config::MOUNT_TYPE_GROUP], function($key) use ($userId) {
return ($this->groupManager->isInGroup($userId, $key));
}, ARRAY_FILTER_USE_KEY
);
}
return $data;
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
throw new \DomainException('UserGlobalStoragesService writing disallowed');
}
}

View File

@ -27,6 +27,7 @@ use \OC\Files\Filesystem;
use \OCA\Files_external\Lib\StorageConfig;
use \OCA\Files_external\NotFoundException;
use \OCA\Files_External\Service\BackendService;
use \OCA\Files_External\Service\UserTrait;
/**
* Service class to manage user external storages
@ -34,12 +35,7 @@ use \OCA\Files_External\Service\BackendService;
*/
class UserStoragesService extends StoragesService {
/**
* User session
*
* @var IUserSession
*/
private $userSession;
use UserTrait;
/**
* Create a user storages service
@ -62,17 +58,28 @@ class UserStoragesService extends StoragesService {
*/
protected function readLegacyConfig() {
// read user config
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
return \OC_Mount_Config::readData($user);
}
/**
* Write legacy config data
*
* @param array $mountPoints
*/
protected function writeLegacyConfig(array $mountPoints) {
// write user config
$user = $this->getUser()->getUID();
\OC_Mount_Config::writeData($user, $mountPoints);
}
/**
* Read the external storages config
*
* @return array map of storage id to storage config
*/
protected function readConfig() {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// TODO: in the future don't rely on the global config reading code
$storages = parent::readConfig();
@ -99,7 +106,7 @@ class UserStoragesService extends StoragesService {
* @param array $storages map of storage id to storage config
*/
public function writeConfig($storages) {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// let the horror begin
$mountPoints = [];
@ -127,7 +134,7 @@ class UserStoragesService extends StoragesService {
$storageConfig->setBackendOptions($oldBackendOptions);
}
\OC_Mount_Config::writeData($user, $mountPoints);
$this->writeLegacyConfig($mountPoints);
}
/**
@ -138,7 +145,7 @@ class UserStoragesService extends StoragesService {
* @param string $signal signal to trigger
*/
protected function triggerHooks(StorageConfig $storage, $signal) {
$user = $this->userSession->getUser()->getUID();
$user = $this->getUser()->getUID();
// trigger hook for the current user
$this->triggerApplicableHooks(

View File

@ -0,0 +1,74 @@
<?php
/**
* @author Robin McCorkell <rmccorkell@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 OCA\Files_External\Service;
use \OCP\IUserSession;
use \OCP\IUser;
/**
* Trait for getting user information in a service
*/
trait UserTrait {
/** @var IUserSession */
protected $userSession;
/**
* User override
*
* @var IUser|null
*/
private $user = null;
/**
* @return IUser|null
*/
protected function getUser() {
if ($this->user) {
return $this->user;
}
return $this->userSession->getUser();
}
/**
* Override the user from the session
* Unset with ->resetUser() when finished!
*
* @param IUser
* @return self
*/
public function setUser(IUser $user) {
$this->user = $user;
return $this;
}
/**
* Reset the user override
*
* @return self
*/
public function resetUser() {
$this->user = null;
return $this;
}
}