From 8beba0d664bc85161ead7fec1bd02b4469468077 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 | 27 ++++++++++++ .../lib/Service/UserGlobalStoragesService.php | 12 ++--- .../lib/Service/UserStoragesService.php | 10 ++--- .../Service/GlobalStoragesServiceTest.php | 2 +- .../tests/Service/StoragesServiceTest.php | 44 +++++-------------- .../Service/UserGlobalStoragesServiceTest.php | 1 + .../tests/Service/UserStoragesServiceTest.php | 4 +- 12 files changed, 107 insertions(+), 60 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 bc2786cc3b4..3e80dda221f 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.23.0 + 1.23.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 589b70a078b..d884d221398 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 0399f47685c..72a889fcc02 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 3820f6b0d96..18e301b4a7b 100644 --- a/apps/files_external/lib/Service/DBConfigService.php +++ b/apps/files_external/lib/Service/DBConfigService.php @@ -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; + } } diff --git a/apps/files_external/lib/Service/StoragesService.php b/apps/files_external/lib/Service/StoragesService.php index 67de6e8b6b8..c2bdcc14569 100644 --- a/apps/files_external/lib/Service/StoragesService.php +++ b/apps/files_external/lib/Service/StoragesService.php @@ -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); + } + } + } } diff --git a/apps/files_external/lib/Service/UserGlobalStoragesService.php b/apps/files_external/lib/Service/UserGlobalStoragesService.php index 01bc91ef3ff..3f9a3947445 100644 --- a/apps/files_external/lib/Service/UserGlobalStoragesService.php +++ b/apps/files_external/lib/Service/UserGlobalStoragesService.php @@ -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; } diff --git a/apps/files_external/lib/Service/UserStoragesService.php b/apps/files_external/lib/Service/UserStoragesService.php index defa97451cd..5b3dbd57ffc 100644 --- a/apps/files_external/lib/Service/UserStoragesService.php +++ b/apps/files_external/lib/Service/UserStoragesService.php @@ -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() { diff --git a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php index b4907f7f00f..4e0daa7d691 100644 --- a/apps/files_external/tests/Service/GlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/GlobalStoragesServiceTest.php @@ -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 { diff --git a/apps/files_external/tests/Service/StoragesServiceTest.php b/apps/files_external/tests/Service/StoragesServiceTest.php index 797d4382ae9..1f028cd8bb9 100644 --- a/apps/files_external/tests/Service/StoragesServiceTest.php +++ b/apps/files_external/tests/Service/StoragesServiceTest.php @@ -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 = diff --git a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php index 571664b32c8..5ada2dd5fd2 100644 --- a/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php @@ -83,6 +83,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 7bf101ebfc4..388fcf84bed 100644 --- a/apps/files_external/tests/Service/UserStoragesServiceTest.php +++ b/apps/files_external/tests/Service/UserStoragesServiceTest.php @@ -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() {