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:
292
apps/meteor/server/api/lib/eraseTeam.spec.ts
Normal file
292
apps/meteor/server/api/lib/eraseTeam.spec.ts
Normal file
@@ -0,0 +1,292 @@
|
||||
import { expect } from 'chai';
|
||||
import proxyquireRaw from 'proxyquire';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
const proxyquire = proxyquireRaw.noCallThru();
|
||||
|
||||
type Stubbed = { [k: string]: any };
|
||||
|
||||
describe('eraseTeam (TypeScript) module', () => {
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
let stubs: Stubbed;
|
||||
let subject: any;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
|
||||
stubs = {
|
||||
'Team': {
|
||||
getMatchingTeamRooms: sandbox.stub().resolves([]),
|
||||
unsetTeamIdOfRooms: sandbox.stub().resolves(),
|
||||
removeAllMembersFromTeam: sandbox.stub().resolves(),
|
||||
deleteById: sandbox.stub().resolves(),
|
||||
},
|
||||
'Users': {
|
||||
findOneById: sandbox.stub().resolves(null),
|
||||
},
|
||||
'Rooms': {
|
||||
findOneById: sandbox.stub().resolves(null),
|
||||
},
|
||||
'eraseRoomStub': sandbox.stub().resolves(true),
|
||||
'deleteRoomStub': sandbox.stub().resolves(),
|
||||
'../../lib/logger/system': {
|
||||
SystemLogger: {
|
||||
error: sandbox.stub(),
|
||||
},
|
||||
},
|
||||
'@rocket.chat/apps': {
|
||||
AppEvents: {
|
||||
IPreRoomDeletePrevent: 'IPreRoomDeletePrevent',
|
||||
IPostRoomDeleted: 'IPostRoomDeleted',
|
||||
},
|
||||
Apps: {
|
||||
self: {
|
||||
isLoaded: () => false,
|
||||
triggerEvent: sandbox.stub().resolves(false),
|
||||
},
|
||||
},
|
||||
},
|
||||
'@rocket.chat/models': {
|
||||
Rooms: {
|
||||
findOneById: (...args: any[]) => stubs.Rooms.findOneById(...args),
|
||||
},
|
||||
Users: {
|
||||
findOneById: (...args: any[]) => stubs.Users.findOneById(...args),
|
||||
},
|
||||
},
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: (function () {
|
||||
class MeteorError extends Error {
|
||||
public error: string | undefined;
|
||||
|
||||
public details: any;
|
||||
|
||||
constructor(message?: string, error?: string, details?: any) {
|
||||
super(message);
|
||||
this.error = error;
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
return MeteorError;
|
||||
})(),
|
||||
},
|
||||
};
|
||||
|
||||
subject = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': stubs['@rocket.chat/apps'],
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('eraseTeamShared', () => {
|
||||
it('throws when user is undefined', async () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
await expect(subject.eraseTeamShared(undefined, { _id: 'team1', roomId: 'teamRoom' }, [], () => {})).to.be.rejected;
|
||||
});
|
||||
|
||||
it('erases provided rooms (excluding team.roomId) and cleans up team', async () => {
|
||||
const team = { _id: 'team-id', roomId: 'team-room' };
|
||||
const user = { _id: 'user-1', username: 'u' };
|
||||
stubs.Team.getMatchingTeamRooms.resolves(['room-1', 'room-2', team.roomId]);
|
||||
stubs.Rooms.findOneById.withArgs(team.roomId).resolves({ _id: team.roomId });
|
||||
|
||||
const erased: Array<{ rid: string; user: any }> = [];
|
||||
const eraseRoomFn = async (rid: string, user: any) => {
|
||||
erased.push({ rid, user });
|
||||
};
|
||||
|
||||
await subject.eraseTeamShared(user, team, ['room-1', 'room-2', team.roomId], eraseRoomFn);
|
||||
|
||||
expect(erased.some((r) => r.rid === 'room-1')).to.be.true;
|
||||
expect(erased.some((r) => r.rid === 'room-2')).to.be.true;
|
||||
sinon.assert.calledOnce(stubs.Team.unsetTeamIdOfRooms);
|
||||
expect(erased.some((r) => r.rid === team.roomId)).to.be.true;
|
||||
sinon.assert.calledOnce(stubs.Team.removeAllMembersFromTeam);
|
||||
sinon.assert.calledOnce(stubs.Team.deleteById);
|
||||
});
|
||||
|
||||
it('skips the main room but still deletes the team when the main room no longer exists', async () => {
|
||||
const team = { _id: 'team-id', roomId: 'team-room' };
|
||||
const user = { _id: 'user-1', username: 'u' };
|
||||
stubs.Team.getMatchingTeamRooms.resolves([]);
|
||||
stubs.Rooms.findOneById.withArgs(team.roomId).resolves(null);
|
||||
|
||||
const eraseRoomFn = sandbox.stub().resolves();
|
||||
|
||||
await subject.eraseTeamShared(user, team, [], eraseRoomFn);
|
||||
|
||||
sinon.assert.notCalled(eraseRoomFn);
|
||||
sinon.assert.calledOnce(stubs.Team.unsetTeamIdOfRooms);
|
||||
sinon.assert.calledOnce(stubs.Team.removeAllMembersFromTeam);
|
||||
sinon.assert.calledOnce(stubs.Team.deleteById);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eraseTeam', () => {
|
||||
it('calls eraseRoom for the team main room (via eraseTeamShared)', async () => {
|
||||
const team = { _id: 't1', roomId: 't-room' };
|
||||
const user = { _id: 'u1', username: 'u', name: 'User' };
|
||||
stubs.Team.getMatchingTeamRooms.resolves([]);
|
||||
stubs.Rooms.findOneById.withArgs(team.roomId).resolves({ _id: team.roomId });
|
||||
const { eraseRoomStub } = stubs;
|
||||
eraseRoomStub.resolves(true);
|
||||
|
||||
await subject.eraseTeam(user, team, []);
|
||||
|
||||
sinon.assert.calledWith(eraseRoomStub, team.roomId, user);
|
||||
});
|
||||
});
|
||||
|
||||
describe('eraseTeamOnRelinquishRoomOwnerships', () => {
|
||||
it('returns successfully deleted room ids only', async () => {
|
||||
const team = { _id: 't1', roomId: 't-room' };
|
||||
stubs.Team.getMatchingTeamRooms.resolves(['r1', 'r2']);
|
||||
|
||||
stubs.Rooms.findOneById.withArgs('r1').resolves({ _id: 'r1', federated: false });
|
||||
stubs.Rooms.findOneById.withArgs('r2').resolves(null);
|
||||
|
||||
stubs.deleteRoomStub.withArgs('r1').resolves();
|
||||
stubs.deleteRoomStub.withArgs('r2').rejects(new Error('boom'));
|
||||
|
||||
const base = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': stubs['@rocket.chat/apps'],
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
|
||||
const result: string[] = await base.eraseTeamOnRelinquishRoomOwnerships(team, ['r1', 'r2']);
|
||||
expect(result).to.be.an('array').that.includes('r1').and.not.includes('r2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('eraseRoomLooseValidation', () => {
|
||||
let baseModule: any;
|
||||
|
||||
beforeEach(() => {
|
||||
baseModule = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': stubs['@rocket.chat/apps'],
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns false when room not found', async () => {
|
||||
stubs.Rooms.findOneById.resolves(null);
|
||||
const res = await baseModule.eraseRoomLooseValidation('does-not-exist');
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false when room.federated is true', async () => {
|
||||
stubs.Rooms.findOneById.resolves({ _id: 'r', federated: true });
|
||||
const res = await baseModule.eraseRoomLooseValidation('r');
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false when app pre-delete prevents deletion', async () => {
|
||||
const listenerStub = sandbox.stub().resolves(true);
|
||||
const AppsStub = {
|
||||
AppEvents: stubs['@rocket.chat/apps'].AppEvents,
|
||||
Apps: {
|
||||
self: {
|
||||
isLoaded: () => true,
|
||||
triggerEvent: listenerStub,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const m = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': AppsStub,
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
|
||||
stubs.Rooms.findOneById.resolves({ _id: 'r', federated: false });
|
||||
|
||||
const res = await m.eraseRoomLooseValidation('r');
|
||||
expect(listenerStub.calledOnce).to.be.true;
|
||||
expect(res).to.be.false;
|
||||
});
|
||||
|
||||
it('logs and returns false when deleteRoom throws', async () => {
|
||||
stubs.Rooms.findOneById.resolves({ _id: 'r', federated: false });
|
||||
stubs.deleteRoomStub.rejects(new Error('boom'));
|
||||
|
||||
const m = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': stubs['@rocket.chat/apps'],
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
|
||||
const res = await m.eraseRoomLooseValidation('r');
|
||||
expect(res).to.be.false;
|
||||
sinon.assert.calledOnce(stubs['../../lib/logger/system'].SystemLogger.error);
|
||||
});
|
||||
|
||||
it('calls post-deleted event and returns true on success', async () => {
|
||||
const roomEventStub = sandbox.stub().onFirstCall().resolves(false).onSecondCall().resolves();
|
||||
const AppsStub = {
|
||||
AppEvents: stubs['@rocket.chat/apps'].AppEvents,
|
||||
Apps: {
|
||||
self: {
|
||||
isLoaded: () => true,
|
||||
triggerEvent: roomEventStub,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
stubs.deleteRoomStub.resolves();
|
||||
const m = proxyquire('./eraseTeam', {
|
||||
'@rocket.chat/apps': AppsStub,
|
||||
'@rocket.chat/models': stubs['@rocket.chat/models'],
|
||||
'../../lib/eraseRoom': { __esModule: true, eraseRoom: stubs.eraseRoomStub },
|
||||
'../../lib/rooms/deleteRoom': { __esModule: true, deleteRoom: stubs.deleteRoomStub },
|
||||
'../../lib/logger/system': stubs['../../lib/logger/system'],
|
||||
'@rocket.chat/core-services': {
|
||||
MeteorError: stubs['@rocket.chat/core-services'].MeteorError,
|
||||
Team: stubs.Team,
|
||||
},
|
||||
});
|
||||
|
||||
stubs.Rooms.findOneById.resolves({ _id: 'r', federated: false });
|
||||
|
||||
const res = await m.eraseRoomLooseValidation('r');
|
||||
expect(res).to.be.true;
|
||||
sinon.assert.calledTwice(roomEventStub);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user