Skip to content

Commit 282341a

Browse files
authored
Merge pull request #55738 from nextcloud/carl/cleanup-preview-command
fix(preview-cleanup): Also delete previews stored in the oc_previews table
2 parents a7a64de + 247b66c commit 282341a

File tree

3 files changed

+66
-0
lines changed

3 files changed

+66
-0
lines changed

core/Command/Preview/Cleanup.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
namespace OC\Core\Command\Preview;
1111

1212
use OC\Core\Command\Base;
13+
use OC\Preview\PreviewService;
14+
use OCP\DB\Exception;
1315
use OCP\Files\Folder;
1416
use OCP\Files\IRootFolder;
1517
use OCP\Files\NotFoundException;
@@ -23,6 +25,7 @@ class Cleanup extends Base {
2325
public function __construct(
2426
private IRootFolder $rootFolder,
2527
private LoggerInterface $logger,
28+
private PreviewService $previewService,
2629
) {
2730
parent::__construct();
2831
}
@@ -34,6 +37,31 @@ protected function configure(): void {
3437
}
3538

3639
protected function execute(InputInterface $input, OutputInterface $output): int {
40+
if ($this->deletePreviewFromPreviewTable($output) !== 0) {
41+
return 1;
42+
}
43+
44+
return $this->deletePreviewFromFileCacheTable($output);
45+
}
46+
47+
/**
48+
* Delete from the new oc_previews table.
49+
*/
50+
private function deletePreviewFromPreviewTable(OutputInterface $output): int {
51+
try {
52+
$this->previewService->deleteAll();
53+
return 0;
54+
} catch (NotPermittedException|Exception $e) {
55+
$this->logger->error("Previews can't be removed: exception occurred: " . $e->getMessage(), ['exception' => $e]);
56+
$output->writeln("Previews can't be removed: " . $e->getMessage() . '. See the logs for more details.');
57+
return 1;
58+
}
59+
}
60+
61+
/**
62+
* Legacy in case there are still previews stored there.
63+
*/
64+
private function deletePreviewFromFileCacheTable(OutputInterface $output): int {
3765
try {
3866
$appDataFolder = $this->rootFolder->get($this->rootFolder->getAppDataDirectoryName());
3967

lib/private/Preview/PreviewService.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
use OC\Preview\Db\Preview;
1414
use OC\Preview\Db\PreviewMapper;
1515
use OC\Preview\Storage\StorageFactory;
16+
use OCP\DB\Exception;
17+
use OCP\Files\NotPermittedException;
1618
use OCP\IDBConnection;
1719

1820
class PreviewService {
@@ -23,6 +25,10 @@ public function __construct(
2325
) {
2426
}
2527

28+
/**
29+
* @throws NotPermittedException
30+
* @throws Exception
31+
*/
2632
public function deletePreview(Preview $preview): void {
2733
$this->storageFactory->deletePreview($preview);
2834
$this->previewMapper->delete($preview);
@@ -99,11 +105,19 @@ public function getPreviewsForMimeTypes(array $mimeTypes): \Generator {
99105
return $this->previewMapper->getPreviewsForMimeTypes($mimeTypes);
100106
}
101107

108+
/**
109+
* @throws NotPermittedException
110+
* @throws Exception
111+
*/
102112
public function deleteAll(): void {
103113
$lastId = 0;
104114
while (true) {
105115
$previews = $this->previewMapper->getPreviews($lastId, 1000);
106116
$i = 0;
117+
118+
// FIXME: Should we use transaction here? Du to the I/O created when
119+
// deleting the previews from the storage, which might be on a network
120+
// This might take a non trivial amount of time where the DB is locked.
107121
foreach ($previews as $preview) {
108122
$this->deletePreview($preview);
109123
$i++;

tests/Core/Command/Preview/CleanupTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Core\Command\Preview;
88

99
use OC\Core\Command\Preview\Cleanup;
10+
use OC\Preview\PreviewService;
1011
use OCP\Files\Folder;
1112
use OCP\Files\IRootFolder;
1213
use OCP\Files\NotFoundException;
@@ -22,22 +23,27 @@ class CleanupTest extends TestCase {
2223
private LoggerInterface&MockObject $logger;
2324
private InputInterface&MockObject $input;
2425
private OutputInterface&MockObject $output;
26+
private PreviewService&MockObject $previewService;
2527
private Cleanup $repair;
2628

2729
protected function setUp(): void {
2830
parent::setUp();
2931
$this->rootFolder = $this->createMock(IRootFolder::class);
3032
$this->logger = $this->createMock(LoggerInterface::class);
33+
$this->previewService = $this->createMock(PreviewService::class);
3134
$this->repair = new Cleanup(
3235
$this->rootFolder,
3336
$this->logger,
37+
$this->previewService,
3438
);
3539

3640
$this->input = $this->createMock(InputInterface::class);
3741
$this->output = $this->createMock(OutputInterface::class);
3842
}
3943

4044
public function testCleanup(): void {
45+
$this->previewService->expects($this->once())->method('deleteAll');
46+
4147
$previewFolder = $this->createMock(Folder::class);
4248
$previewFolder->expects($this->once())
4349
->method('isDeletable')
@@ -73,6 +79,8 @@ public function testCleanup(): void {
7379
}
7480

7581
public function testCleanupWhenNotDeletable(): void {
82+
$this->previewService->expects($this->once())->method('deleteAll');
83+
7684
$previewFolder = $this->createMock(Folder::class);
7785
$previewFolder->expects($this->once())
7886
->method('isDeletable')
@@ -102,6 +110,8 @@ public function testCleanupWhenNotDeletable(): void {
102110

103111
#[\PHPUnit\Framework\Attributes\DataProvider('dataForTestCleanupWithDeleteException')]
104112
public function testCleanupWithDeleteException(string $exceptionClass, string $errorMessage): void {
113+
$this->previewService->expects($this->once())->method('deleteAll');
114+
105115
$previewFolder = $this->createMock(Folder::class);
106116
$previewFolder->expects($this->once())
107117
->method('isDeletable')
@@ -138,6 +148,8 @@ public static function dataForTestCleanupWithDeleteException(): array {
138148
}
139149

140150
public function testCleanupWithCreateException(): void {
151+
$this->previewService->expects($this->once())->method('deleteAll');
152+
141153
$previewFolder = $this->createMock(Folder::class);
142154
$previewFolder->expects($this->once())
143155
->method('isDeletable')
@@ -172,4 +184,16 @@ public function testCleanupWithCreateException(): void {
172184

173185
$this->assertEquals(1, $this->repair->run($this->input, $this->output));
174186
}
187+
188+
public function testCleanupWithPreviewServiceException(): void {
189+
$this->previewService->expects($this->once())->method('deleteAll')
190+
->willThrowException(new NotPermittedException('abc'));
191+
192+
$this->logger->expects($this->once())->method('error')->with("Previews can't be removed: exception occurred: abc");
193+
194+
$this->rootFolder->expects($this->never())
195+
->method('get');
196+
197+
$this->assertEquals(1, $this->repair->run($this->input, $this->output));
198+
}
175199
}

0 commit comments

Comments
 (0)