]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(files_versions): Improve files version listing 44037/head
authorLouis Chemineau <louis@chmn.me>
Wed, 6 Mar 2024 15:44:18 +0000 (16:44 +0100)
committerLouis <louis@chmn.me>
Fri, 8 Mar 2024 16:08:21 +0000 (16:08 +0000)
Signed-off-by: Louis Chemineau <louis@chmn.me>
apps/files_versions/lib/Command/CleanUp.php
apps/files_versions/lib/Db/VersionsMapper.php
apps/files_versions/tests/Command/CleanupTest.php

index 519b3689a58dace89e02aa536531adfac81b785b..eda482357b3cbae47f67818a798234ce1e96176c 100644 (file)
@@ -24,6 +24,7 @@
  */
 namespace OCA\Files_Versions\Command;
 
+use OCA\Files_Versions\Db\VersionsMapper;
 use OCP\Files\IRootFolder;
 use OCP\IUserBackend;
 use OCP\IUserManager;
@@ -37,6 +38,7 @@ class CleanUp extends Command {
        public function __construct(
                protected IRootFolder $rootFolder,
                protected IUserManager $userManager,
+               protected VersionsMapper $versionMapper,
        ) {
                parent::__construct();
        }
@@ -119,6 +121,9 @@ class CleanUp extends Command {
                \OC_Util::tearDownFS();
                \OC_Util::setupFS($user);
 
+               $userHomeStorageId = $this->rootFolder->getUserFolder($user)->getStorage()->getCache()->getNumericStorageId();
+               $this->versionMapper->deleteAllVersionsForUser($userHomeStorageId, $path);
+
                $fullPath = '/' . $user . '/files_versions' . ($path ? '/' . $path : '');
                if ($this->rootFolder->nodeExists($fullPath)) {
                        $this->rootFolder->get($fullPath)->delete();
index bc6e8b264dee98139776e3624df29e0ceae2bc0d..f7f92c70f034c249df921e2ddf281393b8e8eab2 100644 (file)
@@ -27,6 +27,7 @@ declare(strict_types=1);
 namespace OCA\Files_Versions\Db;
 
 use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
 use OCP\IDBConnection;
 
 /**
@@ -83,4 +84,38 @@ class VersionsMapper extends QBMapper {
                         ->where($qb->expr()->eq('file_id', $qb->createNamedParameter($fileId)))
                         ->executeStatement();
        }
+
+       public function deleteAllVersionsForUser(int $storageId, string $path = null): void {
+               $fileIdsGenerator = $this->getFileIdsGenerator($storageId, $path);
+
+               $versionEntitiesDeleteQuery = $this->db->getQueryBuilder();
+               $versionEntitiesDeleteQuery->delete($this->getTableName())
+                       ->where($versionEntitiesDeleteQuery->expr()->in('file_id', $versionEntitiesDeleteQuery->createParameter('file_ids')));
+
+               foreach ($fileIdsGenerator as $fileIds) {
+                       $versionEntitiesDeleteQuery->setParameter('file_ids', $fileIds, IQueryBuilder::PARAM_INT_ARRAY);
+                       $versionEntitiesDeleteQuery->executeStatement();
+               }
+       }
+
+       private function getFileIdsGenerator(int $storageId, ?string $path): \Generator {
+               $offset = 0;
+               do {
+                       $filesIdsSelect = $this->db->getQueryBuilder();
+                       $filesIdsSelect->select('fileid')
+                               ->from('filecache')
+                               ->where($filesIdsSelect->expr()->eq('storage', $filesIdsSelect->createNamedParameter($storageId, IQueryBuilder::PARAM_STR)))
+                               ->andWhere($filesIdsSelect->expr()->like('path', $filesIdsSelect->createNamedParameter('files' . ($path ? '/' . $this->db->escapeLikeParameter($path) : '') . '/%', IQueryBuilder::PARAM_STR)))
+                               ->andWhere($filesIdsSelect->expr()->gt('fileid', $filesIdsSelect->createParameter('offset')))
+                               ->setMaxResults(1000)
+                               ->orderBy('fileid', 'ASC');
+
+                       $filesIdsSelect->setParameter('offset', $offset, IQueryBuilder::PARAM_INT);
+                       $result = $filesIdsSelect->executeQuery();
+                       $fileIds = $result->fetchAll(\PDO::FETCH_COLUMN);
+                       $offset = end($fileIds);
+
+                       yield $fileIds;
+               } while (!empty($fileIds));
+       }
 }
index b5463aa61db1422ae6b3f909c8e0b31adcacea86..085b25822f3dc7e66f15d10d892130381274244f 100644 (file)
@@ -27,7 +27,10 @@ namespace OCA\Files_Versions\Tests\Command;
 
 use OC\User\Manager;
 use OCA\Files_Versions\Command\CleanUp;
+use OCP\Files\Cache\ICache;
+use OCP\Files\Folder;
 use OCP\Files\IRootFolder;
+use OCP\Files\Storage\IStorage;
 use Test\TestCase;
 
 /**
@@ -48,6 +51,9 @@ class CleanupTest extends TestCase {
        /** @var \PHPUnit\Framework\MockObject\MockObject | IRootFolder */
        protected $rootFolder;
 
+       /** @var \PHPUnit\Framework\MockObject\MockObject | VersionsMapper */
+       protected $versionMapper;
+
        protected function setUp(): void {
                parent::setUp();
 
@@ -55,9 +61,10 @@ class CleanupTest extends TestCase {
                        ->disableOriginalConstructor()->getMock();
                $this->userManager = $this->getMockBuilder('OC\User\Manager')
                        ->disableOriginalConstructor()->getMock();
+               $this->versionMapper = $this->getMockBuilder('OCA\Files_Versions\Db\VersionsMapper')
+                       ->disableOriginalConstructor()->getMock();
 
-
-               $this->cleanup = new CleanUp($this->rootFolder, $this->userManager);
+               $this->cleanup = new CleanUp($this->rootFolder, $this->userManager, $this->versionMapper);
        }
 
        /**
@@ -70,6 +77,21 @@ class CleanupTest extends TestCase {
                        ->with('/testUser/files_versions')
                        ->willReturn($nodeExists);
 
+               $userFolder = $this->createMock(Folder::class);
+               $userHomeStorage = $this->createMock(IStorage::class);
+               $userHomeStorageCache = $this->createMock(ICache::class);
+               $this->rootFolder->expects($this->once())
+                       ->method('getUserFolder')
+                       ->willReturn($userFolder);
+               $userFolder->expects($this->once())
+                       ->method('getStorage')
+                       ->willReturn($userHomeStorage);
+               $userHomeStorage->expects($this->once())
+                       ->method('getCache')
+                       ->willReturn($userHomeStorageCache);
+               $userHomeStorageCache->expects($this->once())
+                       ->method('getNumericStorageId')
+                       ->willReturn(1);
 
                if ($nodeExists) {
                        $this->rootFolder->expects($this->once())
@@ -104,7 +126,7 @@ class CleanupTest extends TestCase {
 
                $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
                        ->setMethods(['deleteVersions'])
-                       ->setConstructorArgs([$this->rootFolder, $this->userManager])
+                       ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
                        ->getMock();
                $instance->expects($this->exactly(count($userIds)))
                        ->method('deleteVersions')
@@ -136,7 +158,7 @@ class CleanupTest extends TestCase {
 
                $instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
                        ->setMethods(['deleteVersions'])
-                       ->setConstructorArgs([$this->rootFolder, $this->userManager])
+                       ->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
                        ->getMock();
 
                $backend = $this->getMockBuilder(\OCP\UserInterface::class)