Skip to content

Commit 7619988

Browse files
fix: Thumbnails are not deleted on room deletion (#34851)
1 parent 1b17bb1 commit 7619988

File tree

5 files changed

+122
-4
lines changed

5 files changed

+122
-4
lines changed

.changeset/twelve-pumas-behave.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rocket.chat/meteor": patch
3+
---
4+
5+
Fixes thumbnails not being deleted from storage on room deletion

apps/meteor/.mocharc.js

+1
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,6 @@ module.exports = {
3737
'tests/unit/server/**/*.tests.ts',
3838
'tests/unit/server/**/*.spec.ts',
3939
'app/api/**/*.spec.ts',
40+
'app/file-upload/server/**/*.spec.ts',
4041
],
4142
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { expect } from 'chai';
2+
import { before, beforeEach, describe, it } from 'mocha';
3+
import proxyquire from 'proxyquire';
4+
import sinon from 'sinon';
5+
6+
import { createFakeMessageWithAttachment } from '../../../../tests/mocks/data';
7+
8+
const fakeStorageModel = { findOneById: sinon.stub(), deleteFile: sinon.stub() };
9+
const settingsStub = { watch: sinon.stub(), get: sinon.stub() };
10+
const settingsGetMap = new Map();
11+
const messagesModelStub = {
12+
find: sinon.stub(),
13+
};
14+
15+
const { FileUpload, FileUploadClass } = proxyquire.noCallThru().load('./FileUpload', {
16+
'@rocket.chat/models': {
17+
Messages: messagesModelStub,
18+
},
19+
'meteor/check': sinon.stub(),
20+
'meteor/meteor': sinon.stub(),
21+
'meteor/ostrio:cookies': { Cookies: sinon.stub() },
22+
'sharp': sinon.stub(),
23+
'stream-buffers': sinon.stub(),
24+
'./streamToBuffer': sinon.stub(),
25+
'../../../../server/lib/i18n': sinon.stub(),
26+
'../../../../server/lib/logger/system': sinon.stub(),
27+
'../../../../server/lib/rooms/roomCoordinator': sinon.stub(),
28+
'../../../../server/ufs': sinon.stub(),
29+
'../../../../server/ufs/ufs-methods': sinon.stub(),
30+
'../../../settings/server': { settings: settingsStub },
31+
'../../../utils/lib/mimeTypes': sinon.stub(),
32+
'../../../utils/server/lib/JWTHelper': sinon.stub(),
33+
'../../../utils/server/restrictions': sinon.stub(),
34+
});
35+
36+
describe('FileUpload', () => {
37+
before(() => {
38+
new FileUploadClass({ name: 'fakeStorage:Uploads', model: fakeStorageModel, store: {} });
39+
settingsGetMap.set('FileUpload_Storage_Type', 'fakeStorage');
40+
settingsStub.get.callsFake((settingName) => settingsGetMap.get(settingName));
41+
});
42+
43+
beforeEach(() => {
44+
messagesModelStub.find.reset();
45+
fakeStorageModel.findOneById.reset();
46+
fakeStorageModel.deleteFile.reset();
47+
});
48+
49+
it('should not remove any file if no room id is provided', async () => {
50+
expect(await FileUpload.removeFilesByRoomId()).to.be.undefined;
51+
52+
expect(messagesModelStub.find.called).to.be.false;
53+
expect(fakeStorageModel.findOneById.called).to.be.false;
54+
});
55+
56+
it('should not remove any file if an empty room id is provided', async () => {
57+
expect(await FileUpload.removeFilesByRoomId('')).to.be.undefined;
58+
59+
expect(messagesModelStub.find.called).to.be.false;
60+
expect(fakeStorageModel.findOneById.called).to.be.false;
61+
});
62+
63+
it('should not remove any file if an invalid room id is provided', async () => {
64+
messagesModelStub.find.returns([]);
65+
expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined;
66+
67+
expect(messagesModelStub.find.called).to.be.true;
68+
expect(fakeStorageModel.findOneById.called).to.be.false;
69+
});
70+
71+
it('should delete file from storage if message contains a single file', async () => {
72+
fakeStorageModel.findOneById.resolves({ _id: 'file-id', store: 'fakeStorage:Uploads' });
73+
74+
const fakeMessage = createFakeMessageWithAttachment();
75+
messagesModelStub.find.returns([fakeMessage]);
76+
expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined;
77+
78+
expect(messagesModelStub.find.called).to.be.true;
79+
expect(fakeStorageModel.findOneById.calledOnceWith(fakeMessage.files?.[0]._id)).to.be.true;
80+
expect(fakeStorageModel.deleteFile.calledOnceWith('file-id')).to.be.true;
81+
});
82+
83+
it('should delete multiple files from storage if message contains many files (e.g. image and thumbnail)', async () => {
84+
fakeStorageModel.findOneById.callsFake((_id) => ({ _id, store: 'fakeStorage:Uploads' }));
85+
86+
const fakeMessage = createFakeMessageWithAttachment({
87+
files: [
88+
{ _id: 'file-id', name: 'image', size: 100, type: 'image/png', format: 'png' },
89+
{ _id: 'thumbnail-id', name: 'thumbnail-image', size: 25, type: 'image/png', format: 'png' },
90+
],
91+
});
92+
messagesModelStub.find.returns([fakeMessage]);
93+
expect(await FileUpload.removeFilesByRoomId('invalid')).to.be.undefined;
94+
95+
expect(messagesModelStub.find.called).to.be.true;
96+
expect(fakeStorageModel.findOneById.calledTwice).to.be.true;
97+
expect(fakeStorageModel.findOneById.calledWith('file-id')).to.be.true;
98+
expect(fakeStorageModel.findOneById.calledWith('thumbnail-id')).to.be.true;
99+
expect(fakeStorageModel.deleteFile.calledTwice).to.be.true;
100+
expect(fakeStorageModel.deleteFile.calledWith('file-id')).to.be.true;
101+
expect(fakeStorageModel.deleteFile.calledWith('thumbnail-id')).to.be.true;
102+
});
103+
});

apps/meteor/app/file-upload/server/lib/FileUpload.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -638,20 +638,20 @@ export const FileUpload = {
638638
const cursor = Messages.find(
639639
{
640640
rid,
641-
'file._id': {
641+
'files._id': {
642642
$exists: true,
643643
},
644644
},
645645
{
646646
projection: {
647-
'file._id': 1,
647+
'files._id': 1,
648648
},
649649
},
650650
);
651651

652652
for await (const document of cursor) {
653-
if (document.file) {
654-
await FileUpload.getStore('Uploads').deleteById(document.file._id);
653+
if (document.files) {
654+
await Promise.all(document.files.map((file) => FileUpload.getStore('Uploads').deleteById(file._id)));
655655
}
656656
}
657657
},

apps/meteor/tests/mocks/data.ts

+9
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ export function createFakeMessageWithAttachment(overrides?: Partial<IMessage>):
253253
title_link: `/file-upload/${fileId}/${fileName}`,
254254
},
255255
],
256+
files: [
257+
{
258+
_id: fileId,
259+
name: fileName,
260+
type: 'text/plain',
261+
size: faker.number.int(),
262+
format: faker.string.alpha(),
263+
},
264+
],
256265
...overrides,
257266
};
258267
}

0 commit comments

Comments
 (0)