snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import { expect } from 'chai';
|
||||
import { before, describe, it } from 'mocha';
|
||||
import proxyquire from 'proxyquire';
|
||||
import sinon from 'sinon';
|
||||
|
||||
import type { MessageData } from '../../../../../server/lib/dataExport/exportRoomMessagesToFile';
|
||||
import { exportMessagesMock } from '../../../app/apps/server/mocks/data/messages.data';
|
||||
|
||||
// Create stubs for dependencies
|
||||
const stubs = {
|
||||
findPaginatedMessages: sinon.stub(),
|
||||
mkdir: sinon.stub(),
|
||||
writeFile: sinon.stub(),
|
||||
findPaginatedMessagesCursor: sinon.stub(),
|
||||
findPaginatedMessagesTotal: sinon.stub(),
|
||||
translateKey: sinon.stub(),
|
||||
settings: sinon.stub(),
|
||||
};
|
||||
|
||||
const { getMessageData, exportRoomMessages, exportMessageObject } = proxyquire
|
||||
.noCallThru()
|
||||
.load('../../../../../server/lib/dataExport/exportRoomMessagesToFile.ts', {
|
||||
'@rocket.chat/models': {
|
||||
Messages: {
|
||||
findPaginated: stubs.findPaginatedMessages,
|
||||
},
|
||||
},
|
||||
'fs/promises': {
|
||||
mkdir: stubs.mkdir,
|
||||
writeFile: stubs.writeFile,
|
||||
},
|
||||
'../i18n': {
|
||||
i18n: {
|
||||
t: stubs.translateKey,
|
||||
},
|
||||
},
|
||||
'../../settings': {
|
||||
settings: stubs.settings,
|
||||
},
|
||||
});
|
||||
|
||||
describe('Export - exportMessageObject', () => {
|
||||
let messagesData: MessageData[];
|
||||
const translationPlaceholder = 'translation-placeholder';
|
||||
before(() => {
|
||||
stubs.translateKey.returns(translationPlaceholder);
|
||||
messagesData = exportMessagesMock.map((message) => getMessageData(message, false));
|
||||
});
|
||||
|
||||
it('should only stringify message object when exporting message as json', async () => {
|
||||
const result = await exportMessageObject('json', messagesData[3]);
|
||||
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(JSON.stringify(messagesData[3]));
|
||||
});
|
||||
|
||||
it('should correctly add tags when exporting plain text message object as html', async () => {
|
||||
const result = await exportMessageObject('html', messagesData[3]);
|
||||
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(
|
||||
`<p><strong>${messagesData[3].username}</strong> (${new Date(messagesData[3].ts).toUTCString()}):<br/>\n${messagesData[3].msg}\n</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly format system messages when exporting message object as html', async () => {
|
||||
const result = await exportMessageObject('html', messagesData[0]);
|
||||
|
||||
expect(messagesData[0].msg).to.equal(translationPlaceholder);
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(
|
||||
`<p><strong>${messagesData[0].username}</strong> (${new Date(messagesData[0].ts).toUTCString()}):<br/>\n<i>${
|
||||
messagesData[0].msg
|
||||
}</i>\n</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly format non italic system messages when exporting message object as html', async () => {
|
||||
const result = await exportMessageObject('html', messagesData[4]);
|
||||
|
||||
expect(messagesData[4].msg).to.equal(translationPlaceholder);
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(
|
||||
`<p><strong>${messagesData[4].username}</strong> (${new Date(messagesData[4].ts).toUTCString()}):<br/>\n${messagesData[4].msg}\n</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should correctly reference file when exporting a message object with an attachment as html', async () => {
|
||||
const result = await exportMessageObject('html', messagesData[1], [exportMessagesMock[1].file]);
|
||||
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(
|
||||
`<p><strong>${messagesData[1].username}</strong> (${new Date(messagesData[1].ts).toUTCString()}):<br/>\n${
|
||||
messagesData[1].msg
|
||||
}\n<br/><a href="./assets/${exportMessagesMock[1].file?._id}-${exportMessagesMock[1].file?.name}">${
|
||||
messagesData[1].attachments?.[0].title
|
||||
}</a>\n</p>`,
|
||||
);
|
||||
});
|
||||
|
||||
it('should use fallback attachment description when no title is provided on message object export as html', async () => {
|
||||
const result = await exportMessageObject('html', messagesData[2], [exportMessagesMock[2].file]);
|
||||
|
||||
expect(stubs.translateKey.calledWith('Message_Attachments')).to.be.true;
|
||||
expect(result).to.be.a.string;
|
||||
expect(result).to.equal(
|
||||
`<p><strong>${messagesData[2].username}</strong> (${new Date(messagesData[2].ts).toUTCString()}):<br/>\n${
|
||||
exportMessagesMock[1].msg
|
||||
}\n<br/><a href="./assets/${exportMessagesMock[2].file?._id}-${
|
||||
exportMessagesMock[2].file?.name
|
||||
}">${translationPlaceholder}</a>\n</p>`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Export - exportMessageObject HTML escaping (XSS prevention)', () => {
|
||||
const ts = new Date('2020-01-01T00:00:00.000Z');
|
||||
|
||||
it('should escape HTML in the message body when exporting as html', async () => {
|
||||
const result = await exportMessageObject('html', {
|
||||
msg: '<img src=x onerror="alert(1)">',
|
||||
username: 'attacker',
|
||||
ts,
|
||||
});
|
||||
|
||||
expect(result).to.contain('<img src=x onerror="alert(1)">');
|
||||
expect(result).to.not.contain('<img src=x');
|
||||
});
|
||||
|
||||
it('should escape HTML in the username when exporting as html', async () => {
|
||||
const result = await exportMessageObject('html', {
|
||||
msg: 'hello',
|
||||
username: '<script>alert(1)</script>',
|
||||
ts,
|
||||
});
|
||||
|
||||
expect(result).to.contain('<script>alert(1)</script>');
|
||||
expect(result).to.not.contain('<script>');
|
||||
});
|
||||
|
||||
it('should escape HTML inside italicized (system) messages when exporting as html', async () => {
|
||||
const result = await exportMessageObject('html', {
|
||||
msg: '<img src=x onerror=alert(1)>',
|
||||
username: 'attacker',
|
||||
ts,
|
||||
type: 'wm',
|
||||
});
|
||||
|
||||
expect(result).to.contain('<i><img src=x onerror=alert(1)></i>');
|
||||
expect(result).to.not.contain('<img src=x');
|
||||
});
|
||||
|
||||
it('should escape HTML in the attachment description and prevent href attribute breakout', async () => {
|
||||
const result = await exportMessageObject(
|
||||
'html',
|
||||
{
|
||||
msg: 'file',
|
||||
username: 'attacker',
|
||||
ts,
|
||||
attachments: [
|
||||
{
|
||||
type: 'file',
|
||||
title: '<img src=x onerror=alert(1)>',
|
||||
title_link: '/file-upload/evil-id/x',
|
||||
},
|
||||
] as any,
|
||||
},
|
||||
[{ _id: 'evil-id', name: '"><img src=x onerror=alert(1)>.png' } as any],
|
||||
);
|
||||
|
||||
expect(result).to.contain('<img src=x');
|
||||
expect(result).to.not.contain('<img src=x');
|
||||
// the crafted filename must not break out of the href="" attribute
|
||||
expect(result).to.not.contain('"><img');
|
||||
});
|
||||
|
||||
it('should not escape plain JSON exports (escaping is html-only)', async () => {
|
||||
const messageObject = { msg: '<b>x</b>', username: 'attacker', ts };
|
||||
const result = await exportMessageObject('json', messageObject);
|
||||
|
||||
expect(result).to.equal(JSON.stringify(messageObject));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Export - exportRoomMessages', () => {
|
||||
const totalMessages = 10;
|
||||
const userData = {
|
||||
_id: faker.database.mongodbObjectId(),
|
||||
name: faker.person.fullName(),
|
||||
username: faker.internet.userName(),
|
||||
};
|
||||
|
||||
before(() => {
|
||||
stubs.findPaginatedMessagesCursor.resolves(exportMessagesMock);
|
||||
stubs.findPaginatedMessagesTotal.resolves(totalMessages);
|
||||
stubs.findPaginatedMessages.returns({
|
||||
cursor: { toArray: stubs.findPaginatedMessagesCursor },
|
||||
totalCount: stubs.findPaginatedMessagesTotal(),
|
||||
});
|
||||
stubs.translateKey.returns('translated-placeholder-uj');
|
||||
});
|
||||
|
||||
it('should correctly export multiple messages to result when exporting room as json', async () => {
|
||||
const result = await exportRoomMessages('test-rid', 'json', 0, 100, userData);
|
||||
|
||||
expect(stubs.translateKey.calledWith('User_joined_the_channel')).to.be.true;
|
||||
expect(result).to.be.an('object');
|
||||
expect(result).to.have.property('total', totalMessages);
|
||||
expect(result).to.have.property('exported', exportMessagesMock.length);
|
||||
expect(result).to.have.property('messages').that.is.an('array').of.length(exportMessagesMock.length);
|
||||
const messagesWithFiles = exportMessagesMock.filter((message) => message.file);
|
||||
expect(result).to.have.property('uploads').that.is.an('array').of.length(messagesWithFiles.length);
|
||||
});
|
||||
|
||||
it('should correctly export multiple messages to result when exporting room as html', async () => {
|
||||
const result = await exportRoomMessages('test-rid', 'html', 0, 100, userData);
|
||||
|
||||
expect(stubs.translateKey.calledWith('User_joined_the_channel')).to.be.true;
|
||||
expect(result).to.be.an('object');
|
||||
expect(result).to.have.property('total', totalMessages);
|
||||
expect(result).to.have.property('exported', exportMessagesMock.length);
|
||||
expect(result).to.have.property('messages').that.is.an('array').of.length(exportMessagesMock.length);
|
||||
const messagesWithFiles = exportMessagesMock.filter((message) => message.file);
|
||||
expect(result).to.have.property('uploads').that.is.an('array').of.length(messagesWithFiles.length);
|
||||
});
|
||||
|
||||
it('should export multiple files and filter out thumbnails', async () => {
|
||||
const message = {
|
||||
_id: faker.database.mongodbObjectId(),
|
||||
rid: 'test-rid',
|
||||
ts: new Date(),
|
||||
u: { _id: faker.database.mongodbObjectId(), username: 'testuser' },
|
||||
msg: 'Message with files',
|
||||
files: [
|
||||
{ _id: 'file-1', name: 'photo.jpg', type: 'image/jpeg', size: 500000 },
|
||||
{ _id: 'file-2', name: 'doc.pdf', type: 'application/pdf', size: 10000 },
|
||||
{ _id: 'thumb-1', name: 'photo_thumb.jpg', type: 'image/jpeg', size: 5000, typeGroup: 'thumb' },
|
||||
],
|
||||
attachments: [{ type: 'file', title: 'photo.jpg', title_link: '/file-upload/file-1/photo.jpg' }],
|
||||
};
|
||||
|
||||
stubs.findPaginatedMessagesCursor.resolves([message]);
|
||||
stubs.findPaginatedMessagesTotal.resolves(1);
|
||||
stubs.findPaginatedMessages.returns({
|
||||
cursor: { toArray: stubs.findPaginatedMessagesCursor },
|
||||
totalCount: stubs.findPaginatedMessagesTotal(),
|
||||
});
|
||||
|
||||
const result = await exportRoomMessages('test-rid', 'html', 0, 100, userData);
|
||||
|
||||
expect(result.uploads).to.have.length(2);
|
||||
expect(result.uploads.some((f: { typeGroup?: string }) => f.typeGroup === 'thumb')).to.be.false;
|
||||
});
|
||||
|
||||
it('should fallback to msg.file when msg.files is not available', async () => {
|
||||
const message = {
|
||||
_id: faker.database.mongodbObjectId(),
|
||||
rid: 'test-rid',
|
||||
ts: new Date(),
|
||||
u: { _id: faker.database.mongodbObjectId(), username: 'testuser' },
|
||||
msg: 'Old format message',
|
||||
file: { _id: 'single-file', name: 'doc.pdf', type: 'application/pdf', size: 10000 },
|
||||
attachments: [{ type: 'file', title: 'doc.pdf', title_link: '/file-upload/single-file/doc.pdf' }],
|
||||
};
|
||||
|
||||
stubs.findPaginatedMessagesCursor.resolves([message]);
|
||||
stubs.findPaginatedMessagesTotal.resolves(1);
|
||||
stubs.findPaginatedMessages.returns({
|
||||
cursor: { toArray: stubs.findPaginatedMessagesCursor },
|
||||
totalCount: stubs.findPaginatedMessagesTotal(),
|
||||
});
|
||||
|
||||
const result = await exportRoomMessages('test-rid', 'html', 0, 100, userData);
|
||||
|
||||
expect(result.uploads).to.have.length(1);
|
||||
expect(result.uploads[0]._id).to.equal('single-file');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
import { expect } from 'chai';
|
||||
import { before, describe, it } from 'mocha';
|
||||
import proxyquire from 'proxyquire';
|
||||
import sinon from 'sinon';
|
||||
|
||||
// Create stubs for dependencies
|
||||
const stubs = {
|
||||
findOneUserById: sinon.stub(),
|
||||
randomId: sinon.stub(),
|
||||
stat: sinon.stub(),
|
||||
getStore: sinon.stub(),
|
||||
insertFileStub: sinon.stub(),
|
||||
createReadStream: sinon.stub(),
|
||||
};
|
||||
|
||||
const { uploadZipFile } = proxyquire.noCallThru().load('../../../../../server/lib/dataExport/uploadZipFile.ts', {
|
||||
'@rocket.chat/models': {
|
||||
Users: {
|
||||
findOneById: stubs.findOneUserById,
|
||||
},
|
||||
},
|
||||
'@rocket.chat/random': {
|
||||
Random: {
|
||||
id: stubs.randomId,
|
||||
},
|
||||
},
|
||||
'node:fs/promises': {
|
||||
stat: stubs.stat,
|
||||
},
|
||||
'node:fs': {
|
||||
createReadStream: stubs.createReadStream,
|
||||
},
|
||||
'../media/file-upload': {
|
||||
FileUpload: {
|
||||
getStore: stubs.getStore,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
describe('Export - uploadZipFile', () => {
|
||||
const randomId = 'random-id';
|
||||
const fileStat = 100;
|
||||
const userName = 'John Doe';
|
||||
const userUsername = 'john.doe';
|
||||
const userId = 'user-id';
|
||||
const filePath = 'random-path';
|
||||
|
||||
before(() => {
|
||||
stubs.findOneUserById.returns({ name: userName });
|
||||
stubs.stat.returns({ size: fileStat });
|
||||
stubs.randomId.returns(randomId);
|
||||
stubs.getStore.returns({ insert: stubs.insertFileStub });
|
||||
stubs.insertFileStub.callsFake((details) => ({ _id: details._id, name: details.name }));
|
||||
});
|
||||
|
||||
it('should correctly build file name for json exports', async () => {
|
||||
const result = await uploadZipFile(filePath, userId, 'json');
|
||||
|
||||
expect(stubs.findOneUserById.calledWith(userId)).to.be.true;
|
||||
expect(stubs.stat.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.createReadStream.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.getStore.calledWith('UserDataFiles')).to.be.true;
|
||||
expect(
|
||||
stubs.insertFileStub.calledWith(
|
||||
sinon.match({
|
||||
_id: randomId,
|
||||
userId,
|
||||
type: 'application/zip',
|
||||
size: fileStat,
|
||||
}),
|
||||
),
|
||||
).to.be.true;
|
||||
|
||||
expect(result).to.have.property('_id', randomId);
|
||||
expect(result).to.have.property('name').that.is.a.string;
|
||||
const fileName: string = result.name;
|
||||
expect(fileName.endsWith(encodeURIComponent(`${userName}-data-${randomId}.zip`))).to.be.true;
|
||||
});
|
||||
|
||||
it('should correctly build file name for html exports', async () => {
|
||||
const result = await uploadZipFile(filePath, userId, 'html');
|
||||
|
||||
expect(stubs.findOneUserById.calledWith(userId)).to.be.true;
|
||||
expect(stubs.stat.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.createReadStream.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.getStore.calledWith('UserDataFiles')).to.be.true;
|
||||
expect(
|
||||
stubs.insertFileStub.calledWith(
|
||||
sinon.match({
|
||||
_id: randomId,
|
||||
userId,
|
||||
type: 'application/zip',
|
||||
size: fileStat,
|
||||
}),
|
||||
),
|
||||
).to.be.true;
|
||||
|
||||
expect(result).to.have.property('_id', randomId);
|
||||
expect(result).to.have.property('name').that.is.a.string;
|
||||
const fileName: string = result.name;
|
||||
expect(fileName.endsWith(encodeURIComponent(`${userName}-${randomId}.zip`))).to.be.true;
|
||||
});
|
||||
|
||||
it("should use username as a fallback in the zip file name when user's name is not defined", async () => {
|
||||
stubs.findOneUserById.returns({ username: userUsername });
|
||||
const result = await uploadZipFile(filePath, userId, 'html');
|
||||
|
||||
expect(stubs.findOneUserById.calledWith(userId)).to.be.true;
|
||||
expect(stubs.stat.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.createReadStream.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.getStore.calledWith('UserDataFiles')).to.be.true;
|
||||
expect(
|
||||
stubs.insertFileStub.calledWith(
|
||||
sinon.match({
|
||||
_id: randomId,
|
||||
userId,
|
||||
type: 'application/zip',
|
||||
size: fileStat,
|
||||
}),
|
||||
),
|
||||
).to.be.true;
|
||||
|
||||
expect(result).to.have.property('_id', randomId);
|
||||
expect(result).to.have.property('name').that.is.a.string;
|
||||
const fileName: string = result.name;
|
||||
expect(fileName.endsWith(`${userUsername}-${randomId}.zip`)).to.be.true;
|
||||
});
|
||||
|
||||
it("should use userId as a fallback in the zip file name when user's name and username are not defined", async () => {
|
||||
stubs.findOneUserById.returns(undefined);
|
||||
const result = await uploadZipFile(filePath, userId, 'html');
|
||||
|
||||
expect(stubs.findOneUserById.calledWith(userId)).to.be.true;
|
||||
expect(stubs.stat.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.createReadStream.calledWith(filePath)).to.be.true;
|
||||
expect(stubs.getStore.calledWith('UserDataFiles')).to.be.true;
|
||||
expect(
|
||||
stubs.insertFileStub.calledWith(
|
||||
sinon.match({
|
||||
_id: randomId,
|
||||
userId,
|
||||
type: 'application/zip',
|
||||
size: fileStat,
|
||||
}),
|
||||
),
|
||||
).to.be.true;
|
||||
|
||||
expect(result).to.have.property('_id', randomId);
|
||||
expect(result).to.have.property('name').that.is.a.string;
|
||||
const fileName: string = result.name;
|
||||
expect(fileName.endsWith(`${userId}-${randomId}.zip`)).to.be.true;
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user