Skip to content

Commit

Permalink
Merge pull request #44035 from nextcloud/backport/43263/stable26
Browse files Browse the repository at this point in the history
[stable26] Cleanup versions entities in versions:clean command
  • Loading branch information
susnux authored Mar 7, 2024
2 parents 321240d + 16803d4 commit d25cb6a
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 5 deletions.
10 changes: 9 additions & 1 deletion apps/files_versions/lib/Command/CleanUp.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -45,7 +46,11 @@ class CleanUp extends Command {
* @param IRootFolder $rootFolder
* @param IUserManager $userManager
*/
public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
public function __construct(
IRootFolder $rootFolder,
IUserManager $userManager,
protected VersionsMapper $versionMapper,
) {
parent::__construct();
$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
Expand Down Expand Up @@ -130,6 +135,9 @@ protected function deleteVersions(string $user, string $path = null): void {
\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();
Expand Down
35 changes: 35 additions & 0 deletions apps/files_versions/lib/Db/VersionsMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

use OCA\Files_Versions\Db\VersionEntity;
use OCP\IDBConnection;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\AppFramework\Db\QBMapper;
use OCP\DB\IResult;

Expand Down Expand Up @@ -85,4 +86,38 @@ public function deleteAllVersionsForFileId(int $fileId): int {
->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));
}
}
30 changes: 26 additions & 4 deletions apps/files_versions/tests/Command/CleanupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@

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;

/**
Expand All @@ -48,16 +51,20 @@ 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();

$this->rootFolder = $this->getMockBuilder('OCP\Files\IRootFolder')
->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);
}

/**
Expand All @@ -70,6 +77,21 @@ public function testDeleteVersions($nodeExists) {
->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())
Expand Down Expand Up @@ -104,7 +126,7 @@ public function testExecuteDeleteListOfUsers() {

$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')
Expand Down Expand Up @@ -136,7 +158,7 @@ public function testExecuteAllUsers() {

$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)
Expand Down

0 comments on commit d25cb6a

Please sign in to comment.