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:
251
apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
Normal file
251
apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
Normal file
@@ -0,0 +1,251 @@
|
||||
import fs from 'node:fs';
|
||||
|
||||
import type { IExportOperation } from '@rocket.chat/core-typings';
|
||||
import { expect } from 'chai';
|
||||
import proxyquire from 'proxyquire';
|
||||
import Sinon from 'sinon';
|
||||
|
||||
let exportOperation: IExportOperation | null = null;
|
||||
|
||||
const modelsMock = {
|
||||
ExportOperations: {
|
||||
findLastOperationByUser: async (userId: string, fullExport = false) => {
|
||||
if (exportOperation?.userId === userId && exportOperation?.fullExport === fullExport) {
|
||||
return exportOperation;
|
||||
}
|
||||
},
|
||||
countAllPendingBeforeMyRequest: async (requestDay: Date) => {
|
||||
if (
|
||||
exportOperation &&
|
||||
exportOperation.createdAt < requestDay &&
|
||||
exportOperation.status !== 'completed' &&
|
||||
exportOperation.status !== 'skipped'
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
create: async (data: any) => {
|
||||
exportOperation = {
|
||||
userNameTable: null, // need to keep this null for testing purposes
|
||||
...data,
|
||||
_id: 'exportOp1',
|
||||
createdAt: new Date(),
|
||||
};
|
||||
return exportOperation?._id as IExportOperation['_id'];
|
||||
},
|
||||
updateOperation: async (data: IExportOperation) => {
|
||||
if (exportOperation && exportOperation._id === data._id) {
|
||||
exportOperation = { ...exportOperation, ...data };
|
||||
}
|
||||
return { modifiedCount: 1 };
|
||||
},
|
||||
|
||||
findOnePending: async () => {
|
||||
if (exportOperation && exportOperation.status !== 'completed' && exportOperation.status !== 'skipped') {
|
||||
return exportOperation;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
},
|
||||
UserDataFiles: {
|
||||
findOneById: async (fileId: string) => {
|
||||
if (exportOperation?.fileId === fileId) {
|
||||
return {
|
||||
_id: fileId,
|
||||
};
|
||||
}
|
||||
},
|
||||
findLastFileByUser: async (userId: string) => {
|
||||
if (exportOperation?.userId === userId && exportOperation.fileId) {
|
||||
return {
|
||||
_id: exportOperation.fileId,
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
Avatars: {
|
||||
findOneByName: async (_name: string) => {
|
||||
return null;
|
||||
},
|
||||
},
|
||||
Subscriptions: {
|
||||
findByUserId: (_userId: string) => {
|
||||
return [
|
||||
{
|
||||
rid: 'general',
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
Messages: {
|
||||
findPaginated: (_query: object, _options: object) => {
|
||||
return {
|
||||
cursor: {
|
||||
toArray: async () => [
|
||||
{
|
||||
_id: 'msg1',
|
||||
rid: 'general',
|
||||
ts: new Date(),
|
||||
msg: 'Hello World',
|
||||
u: { _id: 'user1', username: 'userone' },
|
||||
},
|
||||
{
|
||||
_id: 'msg2',
|
||||
rid: 'general',
|
||||
ts: new Date(),
|
||||
msg: 'Second message',
|
||||
u: { _id: 'user2', username: 'usertwo' },
|
||||
},
|
||||
],
|
||||
},
|
||||
totalCount: Promise.resolve(0),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { exportRoomMessagesToFile } = proxyquire.noCallThru().load('./exportRoomMessagesToFile.ts', {
|
||||
'@rocket.chat/models': modelsMock,
|
||||
'../../settings': {
|
||||
settings: {
|
||||
get: (_key: string) => {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
},
|
||||
'../i18n': {
|
||||
i18n: {
|
||||
t: (key: string) => key,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const { requestDataDownload } = proxyquire.noCallThru().load('../../meteor-methods/platform/requestDataDownload.ts', {
|
||||
'@rocket.chat/models': modelsMock,
|
||||
'../../settings': {
|
||||
settings: {
|
||||
get: (_key: string) => {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
},
|
||||
'../../lib/dataExport': {
|
||||
getPath: (fileId: string) => `/data-download/${fileId}`,
|
||||
},
|
||||
'meteor/meteor': {
|
||||
Meteor: {
|
||||
methods: Sinon.stub(),
|
||||
},
|
||||
},
|
||||
}) as {
|
||||
requestDataDownload: (args: { userData: { _id: string }; fullExport?: boolean }) => Promise<{
|
||||
requested: boolean;
|
||||
exportOperation: IExportOperation;
|
||||
url: string | null;
|
||||
pendingOperationsBeforeMyRequest: number;
|
||||
}>;
|
||||
};
|
||||
|
||||
const { processDataDownloads } = proxyquire.noCallThru().load('./processDataDownloads.ts', {
|
||||
'@rocket.chat/models': modelsMock,
|
||||
'../media/file-upload': {
|
||||
FileUpload: {
|
||||
copy: async (fileId: string, _options: any) => {
|
||||
return `copied-${fileId}`;
|
||||
},
|
||||
},
|
||||
},
|
||||
'../../settings': {
|
||||
settings: {
|
||||
get: (_key: string) => {
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
},
|
||||
'../utils/getURL': {
|
||||
getURL: (path: string) => `https://example.com${path}`,
|
||||
},
|
||||
'../i18n': {
|
||||
i18n: {
|
||||
t: (key: string) => key,
|
||||
},
|
||||
},
|
||||
'./copyFileUpload': {
|
||||
copyFileUpload: (_attachmentData: { _id: string; name: string }, _assetsPath: string) => {
|
||||
return Promise.resolve();
|
||||
},
|
||||
},
|
||||
'./exportRoomMessagesToFile': {
|
||||
exportRoomMessagesToFile,
|
||||
},
|
||||
'./getRoomData': {
|
||||
getRoomData: Sinon.stub().resolves({
|
||||
roomId: 'GENERAL',
|
||||
roomName: 'general',
|
||||
type: 'c',
|
||||
exportedCount: 0,
|
||||
status: 'pending',
|
||||
userId: 'user1',
|
||||
targetFile: 'general.json',
|
||||
}),
|
||||
},
|
||||
'./sendEmail': {
|
||||
sendEmail: Sinon.stub().resolves(),
|
||||
},
|
||||
'./uploadZipFile': {
|
||||
uploadZipFile: Sinon.stub().resolves({ _id: 'file1' }),
|
||||
},
|
||||
}) as {
|
||||
processDataDownloads: () => Promise<void>;
|
||||
};
|
||||
|
||||
const userData = { _id: 'user1', username: 'userone' };
|
||||
|
||||
describe('requestDataDownload', () => {
|
||||
beforeEach(() => {
|
||||
exportOperation = null;
|
||||
});
|
||||
|
||||
it('should create a new export operation if none exists', async () => {
|
||||
const result = await requestDataDownload({ userData, fullExport: false });
|
||||
|
||||
expect(result.requested).to.be.true;
|
||||
expect(result.exportOperation).to.exist;
|
||||
expect(result.exportOperation.userId).to.equal('user1');
|
||||
expect(result.exportOperation.fullExport).to.be.false;
|
||||
expect(result.url).to.be.null;
|
||||
expect(result.pendingOperationsBeforeMyRequest).to.equal(0);
|
||||
expect(result.exportOperation.status).to.equal('pending');
|
||||
});
|
||||
});
|
||||
|
||||
describe('export user data', async () => {
|
||||
beforeEach(() => {
|
||||
exportOperation = null;
|
||||
});
|
||||
it('should process data download for pending export operations', async () => {
|
||||
await requestDataDownload({ userData, fullExport: true });
|
||||
|
||||
expect(exportOperation).to.not.be.null;
|
||||
expect(exportOperation?.userId).to.equal('user1');
|
||||
expect(exportOperation?.fullExport).to.be.true;
|
||||
expect(exportOperation?.status).to.equal('pending');
|
||||
|
||||
await processDataDownloads();
|
||||
|
||||
expect(exportOperation?.status).to.equal('completed');
|
||||
expect(exportOperation?.fileId).to.equal('file1');
|
||||
expect(exportOperation?.generatedUserFile).to.be.true;
|
||||
expect(exportOperation?.roomList).to.have.lengthOf(1);
|
||||
expect(exportOperation?.roomList?.[0].roomId).to.equal('GENERAL');
|
||||
expect(exportOperation?.roomList?.[0].exportedCount).to.equal(2);
|
||||
expect(exportOperation?.exportPath).to.be.string;
|
||||
|
||||
expect(fs.readFileSync(`${exportOperation?.exportPath}/${exportOperation?.roomList?.[0].targetFile}`, 'utf-8')).to.contain(
|
||||
'Hello World',
|
||||
);
|
||||
expect(exportOperation?.generatedFile).to.be.string;
|
||||
expect(fs.existsSync(exportOperation?.generatedFile as string)).to.be.true;
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user