feat: add references to room.info endpoint (#33011)

Co-authored-by: Júlia Jaeger Foresti <60678893+juliajforesti@users.noreply.github.com>
Co-authored-by: Kevin Aleman <11577696+KevLehman@users.noreply.github.com>
pull/33216/head^2
Diego Sampaio 1 year ago committed by GitHub
parent e4e8541c91
commit 532f08819e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 7
      .changeset/quiet-cherries-punch.md
  2. 16
      apps/meteor/app/api/server/v1/rooms.ts
  3. 25
      apps/meteor/server/services/team/service.ts
  4. 158
      apps/meteor/tests/end-to-end/api/rooms.ts
  5. 4
      packages/core-services/src/types/ITeamService.ts
  6. 4
      packages/rest-typings/src/v1/rooms.ts

@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/core-services": minor
"@rocket.chat/rest-typings": minor
---
Return `parent` and `team` information when calling `rooms.info` endpoint

@ -1,4 +1,4 @@
import { Media } from '@rocket.chat/core-services';
import { Media, Team } from '@rocket.chat/core-services';
import type { IRoom, IUpload } from '@rocket.chat/core-typings';
import { Messages, Rooms, Users, Uploads, Subscriptions } from '@rocket.chat/models';
import type { Notifications } from '@rocket.chat/rest-typings';
@ -417,7 +417,19 @@ API.v1.addRoute(
return API.v1.failure('not-allowed', 'Not Allowed');
}
return API.v1.success({ room: (await Rooms.findOneByIdOrName(room._id, { projection: fields })) ?? undefined });
const discussionParent =
room.prid &&
(await Rooms.findOneById<Pick<IRoom, 'name' | 'fname' | 't' | 'prid' | 'u'>>(room.prid, {
projection: { name: 1, fname: 1, t: 1, prid: 1, u: 1 },
}));
const { team, parentRoom } = await Team.getRoomInfo(room);
const parent = discussionParent || parentRoom;
return API.v1.success({
room: (await Rooms.findOneByIdOrName(room._id, { projection: fields })) ?? undefined,
...(team && { team }),
...(parent && { parent }),
});
},
},
);

@ -20,6 +20,7 @@ import type {
ITeam,
ITeamMember,
ITeamStats,
AtLeast,
} from '@rocket.chat/core-typings';
import type { InsertionModel } from '@rocket.chat/model-typings';
import { Team, Rooms, Subscriptions, Users, TeamMember } from '@rocket.chat/models';
@ -1053,4 +1054,28 @@ export class TeamService extends ServiceClassInternal implements ITeamService {
return rooms;
}
private getParentRoom(team: AtLeast<ITeam, 'roomId'>): Promise<Pick<IRoom, 'name' | 'fname' | 't' | '_id'> | null> {
return Rooms.findOneById<Pick<IRoom, 'name' | 'fname' | 't' | '_id'>>(team.roomId, { projection: { name: 1, fname: 1, t: 1 } });
}
async getRoomInfo(
room: AtLeast<IRoom, 'teamId' | 'teamMain' | '_id'>,
): Promise<{ team?: Pick<ITeam, 'name' | 'roomId' | 'type'>; parentRoom?: Pick<IRoom, 'name' | 'fname' | 't' | '_id'> }> {
if (!room.teamId) {
return {};
}
const team = await Team.findOneById(room.teamId, { projection: { _id: 1, name: 1, roomId: 1, type: 1 } });
if (!team) {
return {};
}
if (room.teamMain) {
return { team };
}
const parentRoom = await this.getParentRoom(team);
return { team, ...(parentRoom && { parentRoom }) };
}
}

@ -1264,8 +1264,164 @@ describe('[Rooms]', () => {
})
.end(done);
});
});
it('should not return parent & team for room thats not on a team nor is a discussion', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({
roomId: testChannel._id,
})
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('room').and.to.be.an('object');
expect(res.body.room).to.not.have.property('team');
expect(res.body.room).to.not.have.property('prid');
});
});
describe('with team and parent data', () => {
const testChannelName = `channel.test.${Date.now()}-${Math.random()}`;
const teamName = `test-team-${Date.now()}`;
const discussionName = `test-discussion-${Date.now()}`;
const testChannelOutsideTeamname = `channel.test.outside.${Date.now()}-${Math.random()}`;
let testChannel: IRoom;
let testDiscussion: IRoom;
let testDiscussionMainRoom: IRoom;
let testTeam: ITeam;
let testChannelOutside: IRoom;
let testDiscussionOutsideTeam: IRoom;
before(async () => {
testChannel = (await createRoom({ type: 'c', name: testChannelName })).body.channel;
const teamResponse = await request.post(api('teams.create')).set(credentials).send({ name: teamName, type: 1 }).expect(200);
testTeam = teamResponse.body.team;
const resDiscussion = await request.post(api('rooms.createDiscussion')).set(credentials).send({
prid: testChannel._id,
t_name: discussionName,
});
testDiscussion = resDiscussion.body.discussion;
testDiscussionMainRoom = (
await request
.post(api('rooms.createDiscussion'))
.set(credentials)
.send({
prid: testTeam.roomId,
t_name: `test-discussion-${Date.now()}-team`,
})
).body.discussion;
await request
.post(api('teams.addRooms'))
.set(credentials)
.send({ rooms: [testChannel._id], teamId: testTeam._id });
});
before(async () => {
testChannelOutside = (await createRoom({ type: 'c', name: testChannelOutsideTeamname })).body.channel;
testDiscussionOutsideTeam = (
await request
.post(api('rooms.createDiscussion'))
.set(credentials)
.send({
prid: testChannelOutside._id,
t_name: `test-discussion-${Date.now()}`,
})
).body.discussion;
});
after(() =>
Promise.all([
deleteRoom({ type: 'c', roomId: testChannel._id }),
deleteRoom({ type: 'p', roomId: testDiscussion._id }),
deleteRoom({ type: 'c', roomId: testChannelOutside._id }),
deleteRoom({ type: 'p', roomId: testDiscussionOutsideTeam._id }),
deleteRoom({ type: 'p', roomId: testDiscussionMainRoom._id }),
deleteTeam(credentials, teamName),
]),
);
it('should return the channel info, team and parent info', async () => {
const result = await request.get(api('rooms.info')).set(credentials).query({ roomId: testChannel._id }).expect(200);
expect(result.body).to.have.property('success', true);
expect(result.body).to.have.property('team');
expect(result.body).to.have.property('parent');
expect(result.body.parent).to.have.property('_id').and.to.equal(testTeam.roomId);
});
it('should return the dicsussion room info and parent info', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({ roomId: testDiscussion._id })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('parent').and.to.be.an('object');
expect(res.body.parent).to.have.property('_id').and.to.be.equal(testChannel._id);
});
});
it('should not return parent info for the main room of the team', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({ roomId: testTeam.roomId })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.not.have.property('parent');
expect(res.body).to.have.property('team');
});
});
it('should not return team for room outside team', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({ roomId: testChannelOutside._id })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.not.have.property('team');
expect(res.body).to.not.have.property('parent');
});
});
it('should return the parent for discussion outside team', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({ roomId: testDiscussionOutsideTeam._id })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('parent').and.to.be.an('object');
expect(res.body.parent).to.have.property('_id').and.to.be.equal(testChannelOutside._id);
expect(res.body).to.not.have.property('team');
});
});
it('should return the parent for a discussion created from team main room', async () => {
await request
.get(api('rooms.info'))
.set(credentials)
.query({ roomId: testDiscussionMainRoom._id })
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('parent').and.to.be.an('object');
expect(res.body.parent).to.have.property('_id').and.to.be.equal(testTeam.roomId);
expect(res.body).to.not.have.property('team');
});
});
});
});
describe('[/rooms.leave]', () => {
let testChannel: IRoom;
let testGroup: IRoom;

@ -9,6 +9,7 @@ import type {
IRoom,
IUser,
IRole,
AtLeast,
} from '@rocket.chat/core-typings';
import type { Document, Filter, FindOptions } from 'mongodb';
@ -125,4 +126,7 @@ export interface ITeamService {
getStatistics(): Promise<ITeamStats>;
findBySubscribedUserIds(userId: string, callerId?: string): Promise<ITeam[]>;
addRolesToMember(teamId: string, userId: string, roles: Array<string>): Promise<boolean>;
getRoomInfo(
room: AtLeast<IRoom, 'teamId' | 'teamMain' | '_id'>,
): Promise<{ team?: Pick<ITeam, 'name' | 'roomId' | 'type'>; parentRoom?: Pick<IRoom, 'name' | 'fname' | 't' | '_id'> }>;
}

@ -1,4 +1,4 @@
import type { IMessage, IRoom, IUser, RoomAdminFieldsType, IUpload, IE2EEMessage } from '@rocket.chat/core-typings';
import type { IMessage, IRoom, IUser, RoomAdminFieldsType, IUpload, IE2EEMessage, ITeam } from '@rocket.chat/core-typings';
import type { PaginatedRequest } from '../helpers/PaginatedRequest';
import type { PaginatedResult } from '../helpers/PaginatedResult';
@ -626,6 +626,8 @@ export type RoomsEndpoints = {
'/v1/rooms.info': {
GET: (params: RoomsInfoProps) => {
room: IRoom | undefined;
parent?: Pick<IRoom, '_id' | 'name' | 'fname' | 't' | 'prid' | 'u'>;
team?: Pick<ITeam, 'name' | 'roomId' | 'type' | '_id'>;
};
};

Loading…
Cancel
Save