mirror of
https://github.com/nextcloud/server.git
synced 2026-02-20 00:12:30 -05:00
feat(files): Mark homefolder as overwritten when an external storage mounted at / exists
Signed-off-by: Robin Appelman <robin@icewind.nl> Signed-off-by: Louis Chemineau <louis@chmn.me>
This commit is contained in:
parent
4249a5f66a
commit
8beba0d664
12 changed files with 107 additions and 60 deletions
|
|
@ -14,7 +14,7 @@ This application enables administrators to configure connections to external sto
|
|||
|
||||
External storage can be configured using the GUI or at the command line. This second option provides the administration with more flexibility for configuring bulk external storage mounts and setting mount priorities. More information is available in the external storage GUI documentation and the external storage Configuration File documentation.
|
||||
</description>
|
||||
<version>1.23.0</version>
|
||||
<version>1.23.1</version>
|
||||
<licence>agpl</licence>
|
||||
<author>Robin Appelman</author>
|
||||
<author>Michael Gapczynski</author>
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ return array(
|
|||
'OCA\\Files_External\\Migration\\Version1011Date20200630192246' => $baseDir . '/../lib/Migration/Version1011Date20200630192246.php',
|
||||
'OCA\\Files_External\\Migration\\Version1015Date20211104103506' => $baseDir . '/../lib/Migration/Version1015Date20211104103506.php',
|
||||
'OCA\\Files_External\\Migration\\Version1016Date20220324154536' => $baseDir . '/../lib/Migration/Version1016Date20220324154536.php',
|
||||
'OCA\\Files_External\\Migration\\Version1025Date20250228162604' => $baseDir . '/../lib/Migration/Version1025Date20250228162604.php',
|
||||
'OCA\\Files_External\\Migration\\Version22000Date20210216084416' => $baseDir . '/../lib/Migration/Version22000Date20210216084416.php',
|
||||
'OCA\\Files_External\\MountConfig' => $baseDir . '/../lib/MountConfig.php',
|
||||
'OCA\\Files_External\\NotFoundException' => $baseDir . '/../lib/NotFoundException.php',
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ class ComposerStaticInitFiles_External
|
|||
'OCA\\Files_External\\Migration\\Version1011Date20200630192246' => __DIR__ . '/..' . '/../lib/Migration/Version1011Date20200630192246.php',
|
||||
'OCA\\Files_External\\Migration\\Version1015Date20211104103506' => __DIR__ . '/..' . '/../lib/Migration/Version1015Date20211104103506.php',
|
||||
'OCA\\Files_External\\Migration\\Version1016Date20220324154536' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date20220324154536.php',
|
||||
'OCA\\Files_External\\Migration\\Version1025Date20250228162604' => __DIR__ . '/..' . '/../lib/Migration/Version1025Date20250228162604.php',
|
||||
'OCA\\Files_External\\Migration\\Version22000Date20210216084416' => __DIR__ . '/..' . '/../lib/Migration/Version22000Date20210216084416.php',
|
||||
'OCA\\Files_External\\MountConfig' => __DIR__ . '/..' . '/../lib/MountConfig.php',
|
||||
'OCA\\Files_External\\NotFoundException' => __DIR__ . '/..' . '/../lib/NotFoundException.php',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\Files_External\Migration;
|
||||
|
||||
use Closure;
|
||||
use OCA\Files_External\Service\GlobalStoragesService;
|
||||
use OCP\DB\ISchemaWrapper;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\Migration\IOutput;
|
||||
use OCP\Migration\SimpleMigrationStep;
|
||||
|
||||
/**
|
||||
* Check for any external storage overwriting the home folder
|
||||
*/
|
||||
class Version1025Date20250228162604 extends SimpleMigrationStep {
|
||||
public function __construct(
|
||||
private GlobalStoragesService $globalStoragesServices,
|
||||
private IAppConfig $appConfig,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Closure(): ISchemaWrapper $schemaClosure
|
||||
*/
|
||||
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void {
|
||||
$this->globalStoragesServices->updateOverwriteHomeFolders();
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
namespace OCA\Files_External\Service;
|
||||
|
||||
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
|
||||
|
|
@ -63,16 +64,16 @@ class DBConfigService {
|
|||
->where($builder->expr()->orX(
|
||||
$builder->expr()->andX( // global mounts
|
||||
$builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_GLOBAL, IQueryBuilder::PARAM_INT)),
|
||||
$builder->expr()->isNull('a.value')
|
||||
$builder->expr()->isNull('a.value'),
|
||||
),
|
||||
$builder->expr()->andX( // mounts for user
|
||||
$builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_USER, IQueryBuilder::PARAM_INT)),
|
||||
$builder->expr()->eq('a.value', $builder->createNamedParameter($userId))
|
||||
$builder->expr()->eq('a.value', $builder->createNamedParameter($userId)),
|
||||
),
|
||||
$builder->expr()->andX( // mounts for group
|
||||
$builder->expr()->eq('a.type', $builder->createNamedParameter(self::APPLICABLE_TYPE_GROUP, IQueryBuilder::PARAM_INT)),
|
||||
$builder->expr()->in('a.value', $builder->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY))
|
||||
)
|
||||
$builder->expr()->in('a.value', $builder->createNamedParameter($groupIds, IQueryBuilder::PARAM_STR_ARRAY)),
|
||||
),
|
||||
));
|
||||
|
||||
return $this->getMountsFromQuery($query);
|
||||
|
|
@ -93,8 +94,8 @@ class DBConfigService {
|
|||
->leftJoin('a', 'external_applicable', 'b', $builder->expr()->eq('a.mount_id', 'b.mount_id'))
|
||||
->where($builder->expr()->andX(
|
||||
$builder->expr()->eq('b.type', $builder->createNamedParameter($applicableType, IQueryBuilder::PARAM_INT)),
|
||||
$builder->expr()->eq('b.value', $builder->createNamedParameter($applicableId))
|
||||
)
|
||||
$builder->expr()->eq('b.value', $builder->createNamedParameter($applicableId)),
|
||||
),
|
||||
)
|
||||
->groupBy(['a.mount_id']);
|
||||
$stmt = $query->executeQuery();
|
||||
|
|
@ -226,7 +227,7 @@ class DBConfigService {
|
|||
'storage_backend' => $builder->createNamedParameter($storageBackend, IQueryBuilder::PARAM_STR),
|
||||
'auth_backend' => $builder->createNamedParameter($authBackend, IQueryBuilder::PARAM_STR),
|
||||
'priority' => $builder->createNamedParameter($priority, IQueryBuilder::PARAM_INT),
|
||||
'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT)
|
||||
'type' => $builder->createNamedParameter($type, IQueryBuilder::PARAM_INT),
|
||||
]);
|
||||
$query->executeStatement();
|
||||
return $query->getLastInsertId();
|
||||
|
|
@ -497,4 +498,17 @@ class DBConfigService {
|
|||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any mountpoint is configured that overwrite the home folder
|
||||
*/
|
||||
public function hasHomeFolderOverwriteMount(): bool {
|
||||
$builder = $this->connection->getQueryBuilder();
|
||||
$query = $builder->select('mount_id')
|
||||
->from('external_mounts')
|
||||
->where($builder->expr()->eq('mount_point', $builder->createNamedParameter('/')))
|
||||
->setMaxResults(1);
|
||||
$result = $query->executeQuery();
|
||||
return count($result->fetchAll()) > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ namespace OCA\Files_External\Service;
|
|||
|
||||
use OC\Files\Cache\Storage;
|
||||
use OC\Files\Filesystem;
|
||||
use OCA\Files\AppInfo\Application as FilesApplication;
|
||||
use OCA\Files_External\AppInfo\Application;
|
||||
use OCA\Files_External\Lib\Auth\AuthMechanism;
|
||||
use OCA\Files_External\Lib\Auth\InvalidAuth;
|
||||
use OCA\Files_External\Lib\Backend\Backend;
|
||||
|
|
@ -19,6 +21,7 @@ use OCP\EventDispatcher\IEventDispatcher;
|
|||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\Events\InvalidateMountCacheEvent;
|
||||
use OCP\Files\StorageNotAvailableException;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\Util;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
|
@ -38,6 +41,7 @@ abstract class StoragesService {
|
|||
protected DBConfigService $dbConfig,
|
||||
protected IUserMountCache $userMountCache,
|
||||
protected IEventDispatcher $eventDispatcher,
|
||||
protected IAppConfig $appConfig,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -240,6 +244,9 @@ abstract class StoragesService {
|
|||
$this->triggerHooks($newStorage, Filesystem::signal_create_mount);
|
||||
|
||||
$newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS);
|
||||
|
||||
$this->updateOverwriteHomeFolders();
|
||||
|
||||
return $newStorage;
|
||||
}
|
||||
|
||||
|
|
@ -423,6 +430,8 @@ abstract class StoragesService {
|
|||
}
|
||||
}
|
||||
|
||||
$this->updateOverwriteHomeFolders();
|
||||
|
||||
return $this->getStorage($id);
|
||||
}
|
||||
|
||||
|
|
@ -447,6 +456,8 @@ abstract class StoragesService {
|
|||
|
||||
// delete oc_storages entries and oc_filecache
|
||||
Storage::cleanByMountId($id);
|
||||
|
||||
$this->updateOverwriteHomeFolders();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -471,4 +482,20 @@ abstract class StoragesService {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateOverwriteHomeFolders(): void {
|
||||
$appIdsList = $this->appConfig->getValueArray(FilesApplication::APP_ID, 'overwrites_home_folders');
|
||||
|
||||
if ($this->dbConfig->hasHomeFolderOverwriteMount()) {
|
||||
if (!in_array(Application::APP_ID, $appIdsList)) {
|
||||
$appIdsList[] = Application::APP_ID;
|
||||
$this->appConfig->setValueArray(FilesApplication::APP_ID, 'overwrites_home_folders', $appIdsList);
|
||||
}
|
||||
} else {
|
||||
if (in_array(Application::APP_ID, $appIdsList)) {
|
||||
$appIdsList = array_values(array_filter($appIdsList, fn ($v) => $v !== Application::APP_ID));
|
||||
$this->appConfig->setValueArray(FilesApplication::APP_ID, 'overwrites_home_folders', $appIdsList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace OCA\Files_External\Service;
|
|||
use OCA\Files_External\Lib\StorageConfig;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserSession;
|
||||
|
|
@ -20,14 +21,6 @@ use OCP\IUserSession;
|
|||
class UserGlobalStoragesService extends GlobalStoragesService {
|
||||
use UserTrait;
|
||||
|
||||
/**
|
||||
* @param BackendService $backendService
|
||||
* @param DBConfigService $dbConfig
|
||||
* @param IUserSession $userSession
|
||||
* @param IGroupManager $groupManager
|
||||
* @param IUserMountCache $userMountCache
|
||||
* @param IEventDispatcher $eventDispatcher
|
||||
*/
|
||||
public function __construct(
|
||||
BackendService $backendService,
|
||||
DBConfigService $dbConfig,
|
||||
|
|
@ -35,8 +28,9 @@ class UserGlobalStoragesService extends GlobalStoragesService {
|
|||
protected IGroupManager $groupManager,
|
||||
IUserMountCache $userMountCache,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
IAppConfig $appConfig,
|
||||
) {
|
||||
parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher);
|
||||
parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher, $appConfig);
|
||||
$this->userSession = $userSession;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use OCA\Files_External\MountConfig;
|
|||
use OCA\Files_External\NotFoundException;
|
||||
use OCP\EventDispatcher\IEventDispatcher;
|
||||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IUserSession;
|
||||
|
||||
/**
|
||||
|
|
@ -23,12 +24,6 @@ class UserStoragesService extends StoragesService {
|
|||
|
||||
/**
|
||||
* Create a user storages service
|
||||
*
|
||||
* @param BackendService $backendService
|
||||
* @param DBConfigService $dbConfig
|
||||
* @param IUserSession $userSession user session
|
||||
* @param IUserMountCache $userMountCache
|
||||
* @param IEventDispatcher $eventDispatcher
|
||||
*/
|
||||
public function __construct(
|
||||
BackendService $backendService,
|
||||
|
|
@ -36,9 +31,10 @@ class UserStoragesService extends StoragesService {
|
|||
IUserSession $userSession,
|
||||
IUserMountCache $userMountCache,
|
||||
IEventDispatcher $eventDispatcher,
|
||||
IAppConfig $appConfig,
|
||||
) {
|
||||
$this->userSession = $userSession;
|
||||
parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher);
|
||||
parent::__construct($backendService, $dbConfig, $userMountCache, $eventDispatcher, $appConfig);
|
||||
}
|
||||
|
||||
protected function readDBConfig() {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use OCA\Files_External\Service\GlobalStoragesService;
|
|||
class GlobalStoragesServiceTest extends StoragesServiceTest {
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->service = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher);
|
||||
$this->service = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher, $this->appConfig);
|
||||
}
|
||||
|
||||
protected function tearDown(): void {
|
||||
|
|
|
|||
|
|
@ -25,10 +25,12 @@ use OCP\Files\Cache\ICache;
|
|||
use OCP\Files\Config\IUserMountCache;
|
||||
use OCP\Files\Mount\IMountPoint;
|
||||
use OCP\Files\Storage\IStorage;
|
||||
use OCP\IAppConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\IUser;
|
||||
use OCP\Server;
|
||||
use OCP\Util;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class CleaningDBConfig extends DBConfigService {
|
||||
private $mountIds = [];
|
||||
|
|
@ -50,40 +52,15 @@ class CleaningDBConfig extends DBConfigService {
|
|||
* @group DB
|
||||
*/
|
||||
abstract class StoragesServiceTest extends \Test\TestCase {
|
||||
/**
|
||||
* @var StoragesService
|
||||
*/
|
||||
/** @var StoragesService $service */
|
||||
protected $service;
|
||||
|
||||
/** @var BackendService */
|
||||
protected $backendService;
|
||||
|
||||
/**
|
||||
* Data directory
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $dataDir;
|
||||
|
||||
/** @var CleaningDBConfig */
|
||||
protected $dbConfig;
|
||||
|
||||
/**
|
||||
* Hook calls
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $hookCalls;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IUserMountCache
|
||||
*/
|
||||
protected $mountCache;
|
||||
|
||||
/**
|
||||
* @var \PHPUnit\Framework\MockObject\MockObject|IEventDispatcher
|
||||
*/
|
||||
protected IEventDispatcher $eventDispatcher;
|
||||
protected BackendService&MockObject $backendService;
|
||||
protected string $dataDir;
|
||||
protected CleaningDBConfig $dbConfig;
|
||||
protected static array $hookCalls;
|
||||
protected IUserMountCache&MockObject $mountCache;
|
||||
protected IEventDispatcher&MockObject $eventDispatcher;
|
||||
protected IAppConfig&MockObject $appConfig;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -98,6 +75,7 @@ abstract class StoragesServiceTest extends \Test\TestCase {
|
|||
|
||||
$this->mountCache = $this->createMock(IUserMountCache::class);
|
||||
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
|
||||
$this->appConfig = $this->createMock(IAppConfig::class);
|
||||
|
||||
// prepare BackendService mock
|
||||
$this->backendService =
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest {
|
|||
$this->groupManager,
|
||||
$this->mountCache,
|
||||
$this->eventDispatcher,
|
||||
$this->appConfig,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
|
|||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->globalStoragesService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher);
|
||||
$this->globalStoragesService = new GlobalStoragesService($this->backendService, $this->dbConfig, $this->mountCache, $this->eventDispatcher, $this->appConfig);
|
||||
|
||||
$this->userId = $this->getUniqueID('user_');
|
||||
$this->createUser($this->userId, $this->userId);
|
||||
|
|
@ -48,7 +48,7 @@ class UserStoragesServiceTest extends StoragesServiceTest {
|
|||
->method('getUser')
|
||||
->willReturn($this->user);
|
||||
|
||||
$this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession, $this->mountCache, $this->eventDispatcher);
|
||||
$this->service = new UserStoragesService($this->backendService, $this->dbConfig, $userSession, $this->mountCache, $this->eventDispatcher, $this->appConfig);
|
||||
}
|
||||
|
||||
private function makeTestStorageData() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue