Skip to content

Commit bb53964

Browse files
committed
fix(files_versions): Improve files version listing
Signed-off-by: Louis Chemineau <[email protected]> [skip ci] Signed-off-by: Louis Chemineau <[email protected]>
1 parent d813657 commit bb53964

File tree

3 files changed

+70
-5
lines changed

3 files changed

+70
-5
lines changed

apps/files_versions/lib/Command/CleanUp.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
namespace OCA\Files_Versions\Command;
2626

27+
use OCA\Files_Versions\Db\VersionsMapper;
2728
use OCP\Files\IRootFolder;
2829
use OCP\IUserBackend;
2930
use OCP\IUserManager;
@@ -45,7 +46,11 @@ class CleanUp extends Command {
4546
* @param IRootFolder $rootFolder
4647
* @param IUserManager $userManager
4748
*/
48-
public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
49+
public function __construct(
50+
IRootFolder $rootFolder,
51+
IUserManager $userManager,
52+
protected VersionsMapper $versionMapper,
53+
) {
4954
parent::__construct();
5055
$this->userManager = $userManager;
5156
$this->rootFolder = $rootFolder;
@@ -130,6 +135,9 @@ protected function deleteVersions(string $user, string $path = null): void {
130135
\OC_Util::tearDownFS();
131136
\OC_Util::setupFS($user);
132137

138+
$userHomeStorageId = $this->rootFolder->getUserFolder($user)->getStorage()->getCache()->getNumericStorageId();
139+
$this->versionMapper->deleteAllVersionsForUser($userHomeStorageId, $path);
140+
133141
$fullPath = '/' . $user . '/files_versions' . ($path ? '/' . $path : '');
134142
if ($this->rootFolder->nodeExists($fullPath)) {
135143
$this->rootFolder->get($fullPath)->delete();

apps/files_versions/lib/Db/VersionsMapper.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
use OCA\Files_Versions\Db\VersionEntity;
3030
use OCP\IDBConnection;
31+
use OCP\DB\QueryBuilder\IQueryBuilder;
3132
use OCP\AppFramework\Db\QBMapper;
3233
use OCP\DB\IResult;
3334

@@ -85,4 +86,38 @@ public function deleteAllVersionsForFileId(int $fileId): int {
8586
->where($qb->expr()->eq('file_id', $qb->createNamedParameter($fileId)))
8687
->executeStatement();
8788
}
89+
90+
public function deleteAllVersionsForUser(int $storageId, string $path = null): void {
91+
$fileIdsGenerator = $this->getFileIdsGenerator($storageId, $path);
92+
93+
$versionEntitiesDeleteQuery = $this->db->getQueryBuilder();
94+
$versionEntitiesDeleteQuery->delete($this->getTableName())
95+
->where($versionEntitiesDeleteQuery->expr()->in('file_id', $versionEntitiesDeleteQuery->createParameter('file_ids')));
96+
97+
foreach ($fileIdsGenerator as $fileIds) {
98+
$versionEntitiesDeleteQuery->setParameter('file_ids', $fileIds, IQueryBuilder::PARAM_INT_ARRAY);
99+
$versionEntitiesDeleteQuery->executeStatement();
100+
}
101+
}
102+
103+
private function getFileIdsGenerator(int $storageId, ?string $path): \Generator {
104+
$offset = 0;
105+
do {
106+
$filesIdsSelect = $this->db->getQueryBuilder();
107+
$filesIdsSelect->select('fileid')
108+
->from('filecache')
109+
->where($filesIdsSelect->expr()->eq('storage', $filesIdsSelect->createNamedParameter($storageId, IQueryBuilder::PARAM_STR)))
110+
->andWhere($filesIdsSelect->expr()->like('path', $filesIdsSelect->createNamedParameter('files' . ($path ? '/' . $this->db->escapeLikeParameter($path) : '') . '/%', IQueryBuilder::PARAM_STR)))
111+
->andWhere($filesIdsSelect->expr()->gt('fileid', $filesIdsSelect->createParameter('offset')))
112+
->setMaxResults(1000)
113+
->orderBy('fileid', 'ASC');
114+
115+
$filesIdsSelect->setParameter('offset', $offset, IQueryBuilder::PARAM_INT);
116+
$result = $filesIdsSelect->executeQuery();
117+
$fileIds = $result->fetchAll(\PDO::FETCH_COLUMN);
118+
$offset = end($fileIds);
119+
120+
yield $fileIds;
121+
} while (!empty($fileIds));
122+
}
88123
}

apps/files_versions/tests/Command/CleanupTest.php

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@
2727

2828
use OC\User\Manager;
2929
use OCA\Files_Versions\Command\CleanUp;
30+
use OCP\Files\Cache\ICache;
31+
use OCP\Files\Folder;
3032
use OCP\Files\IRootFolder;
33+
use OCP\Files\Storage\IStorage;
3134
use Test\TestCase;
3235

3336
/**
@@ -48,16 +51,20 @@ class CleanupTest extends TestCase {
4851
/** @var \PHPUnit\Framework\MockObject\MockObject | IRootFolder */
4952
protected $rootFolder;
5053

54+
/** @var \PHPUnit\Framework\MockObject\MockObject | VersionsMapper */
55+
protected $versionMapper;
56+
5157
protected function setUp(): void {
5258
parent::setUp();
5359

5460
$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')
5561
->disableOriginalConstructor()->getMock();
5662
$this->userManager = $this->getMockBuilder('OC\User\Manager')
5763
->disableOriginalConstructor()->getMock();
64+
$this->versionMapper = $this->getMockBuilder('OCA\Files_Versions\Db\VersionsMapper')
65+
->disableOriginalConstructor()->getMock();
5866

59-
60-
$this->cleanup = new CleanUp($this->rootFolder, $this->userManager);
67+
$this->cleanup = new CleanUp($this->rootFolder, $this->userManager, $this->versionMapper);
6168
}
6269

6370
/**
@@ -70,6 +77,21 @@ public function testDeleteVersions($nodeExists) {
7077
->with('/testUser/files_versions')
7178
->willReturn($nodeExists);
7279

80+
$userFolder = $this->createMock(Folder::class);
81+
$userHomeStorage = $this->createMock(IStorage::class);
82+
$userHomeStorageCache = $this->createMock(ICache::class);
83+
$this->rootFolder->expects($this->once())
84+
->method('getUserFolder')
85+
->willReturn($userFolder);
86+
$userFolder->expects($this->once())
87+
->method('getStorage')
88+
->willReturn($userHomeStorage);
89+
$userHomeStorage->expects($this->once())
90+
->method('getCache')
91+
->willReturn($userHomeStorageCache);
92+
$userHomeStorageCache->expects($this->once())
93+
->method('getNumericStorageId')
94+
->willReturn(1);
7395

7496
if ($nodeExists) {
7597
$this->rootFolder->expects($this->once())
@@ -104,7 +126,7 @@ public function testExecuteDeleteListOfUsers() {
104126

105127
$instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
106128
->setMethods(['deleteVersions'])
107-
->setConstructorArgs([$this->rootFolder, $this->userManager])
129+
->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
108130
->getMock();
109131
$instance->expects($this->exactly(count($userIds)))
110132
->method('deleteVersions')
@@ -136,7 +158,7 @@ public function testExecuteAllUsers() {
136158

137159
$instance = $this->getMockBuilder('OCA\Files_Versions\Command\CleanUp')
138160
->setMethods(['deleteVersions'])
139-
->setConstructorArgs([$this->rootFolder, $this->userManager])
161+
->setConstructorArgs([$this->rootFolder, $this->userManager, $this->versionMapper])
140162
->getMock();
141163

142164
$backend = $this->getMockBuilder(\OCP\UserInterface::class)

0 commit comments

Comments
 (0)