From 70c6e9cae67552f5af2272a5451b4e06e4798599 Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Fri, 26 Sep 2025 17:10:05 +0200 Subject: [PATCH] feat(files): Mark homefolder as overwritten when an external storage mounted at / exists Signed-off-by: Robin Appelman Signed-off-by: Louis Chemineau --- apps/files_external/appinfo/info.xml | 2 +- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + .../Version1025Date20250228162604.php | 35 +++++++++++++++++++ .../lib/Service/DBConfigService.php | 28 +++++++++++---- .../lib/Service/StoragesService.php | 28 +++++++++++++++ .../lib/Service/UserGlobalStoragesService.php | 12 ++----- .../lib/Service/UserStoragesService.php | 10 ++---- .../Service/GlobalStoragesServiceTest.php | 2 +- .../tests/Service/StoragesServiceTestCase.php | 5 ++- .../Service/UserGlobalStoragesServiceTest.php | 1 + .../tests/Service/UserStoragesServiceTest.php | 4 +-- 12 files changed, 101 insertions(+), 28 deletions(-) create mode 100644 apps/files_external/lib/Migration/Version1025Date20250228162604.php diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index e746f052619..b652e7533c5 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -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. - 1.24.0 + 1.24.1 agpl Robin Appelman Michael Gapczynski diff --git a/apps/files_external/composer/composer/autoload_classmap.php b/apps/files_external/composer/composer/autoload_classmap.php index 8ac551013bd..61165ee67fb 100644 --- a/apps/files_external/composer/composer/autoload_classmap.php +++ b/apps/files_external/composer/composer/autoload_classmap.php @@ -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', diff --git a/apps/files_external/composer/composer/autoload_static.php b/apps/files_external/composer/composer/autoload_static.php index 4468ce1b6bb..5b8b6ab0294 100644 --- a/apps/files_external/composer/composer/autoload_static.php +++ b/apps/files_external/composer/composer/autoload_static.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', diff --git a/apps/files_external/lib/Migration/Version1025Date20250228162604.php b/apps/files_external/lib/Migration/Version1025Date20250228162604.php new file mode 100644 index 00000000000..f3d76ed7baa --- /dev/null +++ b/apps/files_external/lib/Migration/Version1025Date20250228162604.php @@ -0,0 +1,35 @@ +globalStoragesServices->updateOverwriteHomeFolders(); + } +} diff --git a/apps/files_external/lib/Service/DBConfigService.php b/apps/files_external/lib/Service/DBConfigService.php index 41ec4512d70..2338f0bac5d 100644 --- a/apps/files_external/lib/Service/DBConfigService.php +++ b/apps/files_external/lib/Service/DBConfigService.php @@ -5,6 +5,7 @@ * SPDX-FileCopyrightText: 2016 ownCloud, Inc. * SPDX-License-Identifier: AGPL-3.0-only */ + namespace OCA\Files_External\Service; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; @@ -64,16 +65,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); @@ -94,8 +95,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(); @@ -227,7 +228,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(); @@ -498,4 +499,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; + } } diff --git a/apps/files_external/lib/Service/StoragesService.php b/apps/files_external/lib/Service/StoragesService.php index a12a8fc245a..7b1b7ba2dc1 100644 --- a/apps/files_external/lib/Service/StoragesService.php +++ b/apps/files_external/lib/Service/StoragesService.php @@ -9,6 +9,9 @@ namespace OCA\Files_External\Service; use OC\Files\Cache\Storage; use OC\Files\Filesystem; +use OCA\Files\AppInfo\Application as FilesApplication; +use OCA\Files\ConfigLexicon; +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; @@ -20,6 +23,7 @@ use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; use OCP\Files\Events\InvalidateMountCacheEvent; use OCP\Files\StorageNotAvailableException; +use OCP\IAppConfig; use OCP\Server; use OCP\Util; use Psr\Log\LoggerInterface; @@ -40,6 +44,7 @@ abstract class StoragesService { protected DBConfigService $dbConfig, protected IUserMountCache $userMountCache, protected IEventDispatcher $eventDispatcher, + protected IAppConfig $appConfig, ) { } @@ -242,6 +247,9 @@ abstract class StoragesService { $this->triggerHooks($newStorage, Filesystem::signal_create_mount); $newStorage->setStatus(StorageNotAvailableException::STATUS_SUCCESS); + + $this->updateOverwriteHomeFolders(); + return $newStorage; } @@ -425,6 +433,8 @@ abstract class StoragesService { } } + $this->updateOverwriteHomeFolders(); + return $this->getStorage($id); } @@ -449,6 +459,8 @@ abstract class StoragesService { // delete oc_storages entries and oc_filecache Storage::cleanByMountId($id); + + $this->updateOverwriteHomeFolders(); } /** @@ -473,4 +485,20 @@ abstract class StoragesService { return -1; } } + + public function updateOverwriteHomeFolders(): void { + $appIdsList = $this->appConfig->getValueArray(FilesApplication::APP_ID, ConfigLexicon::OVERWRITES_HOME_FOLDERS); + + if ($this->dbConfig->hasHomeFolderOverwriteMount()) { + if (!in_array(Application::APP_ID, $appIdsList)) { + $appIdsList[] = Application::APP_ID; + $this->appConfig->setValueArray(FilesApplication::APP_ID, ConfigLexicon::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, ConfigLexicon::OVERWRITES_HOME_FOLDERS, $appIdsList); + } + } + } } diff --git a/apps/files_external/lib/Service/UserGlobalStoragesService.php b/apps/files_external/lib/Service/UserGlobalStoragesService.php index aaa59c85d62..6c943247b20 100644 --- a/apps/files_external/lib/Service/UserGlobalStoragesService.php +++ b/apps/files_external/lib/Service/UserGlobalStoragesService.php @@ -10,6 +10,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; @@ -21,14 +22,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, @@ -36,8 +29,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; } diff --git a/apps/files_external/lib/Service/UserStoragesService.php b/apps/files_external/lib/Service/UserStoragesService.php index 9d4192734b6..bd8dd2d348c 100644 --- a/apps/files_external/lib/Service/UserStoragesService.php +++ b/apps/files_external/lib/Service/UserStoragesService.php @@ -13,6 +13,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; /** @@ -24,12 +25,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, @@ -37,9 +32,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() { diff --git a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php index 0a3749981c8..b4c8617830b 100644 --- a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php @@ -19,7 +19,7 @@ use OCA\Files_External\Service\GlobalStoragesService; class GlobalStoragesServiceTest extends StoragesServiceTestCase { 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 { diff --git a/apps/files_external/tests/Service/StoragesServiceTestCase.php b/apps/files_external/tests/Service/StoragesServiceTestCase.php index b41eb409468..991921880e8 100644 --- a/apps/files_external/tests/Service/StoragesServiceTestCase.php +++ b/apps/files_external/tests/Service/StoragesServiceTestCase.php @@ -28,6 +28,7 @@ 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\IConfig; use OCP\IDBConnection; use OCP\IUser; @@ -57,12 +58,13 @@ class CleaningDBConfig extends DBConfigService { */ abstract class StoragesServiceTestCase extends \Test\TestCase { protected StoragesService $service; - protected BackendService $backendService; + 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(); @@ -77,6 +79,7 @@ abstract class StoragesServiceTestCase 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 = $this->createMock(BackendService::class); diff --git a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php index 2a2f4596fda..2119872ea5b 100644 --- a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php @@ -75,6 +75,7 @@ class UserGlobalStoragesServiceTest extends GlobalStoragesServiceTest { $this->groupManager, $this->mountCache, $this->eventDispatcher, + $this->appConfig, ); } diff --git a/apps/files_external/tests/Service/UserStoragesServiceTest.php b/apps/files_external/tests/Service/UserStoragesServiceTest.php index 0a2f291f6e4..8c7c4d1f2db 100644 --- a/apps/files_external/tests/Service/UserStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserStoragesServiceTest.php @@ -36,7 +36,7 @@ class UserStoragesServiceTest extends StoragesServiceTestCase { 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); @@ -49,7 +49,7 @@ class UserStoragesServiceTest extends StoragesServiceTestCase { ->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() {