Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rooms.hide endpoint #34208

Merged
merged 26 commits into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7e1c022
chore: added types for rooms.close endpoint
aleksandernsilva Dec 17, 2024
0013cdd
feat: added rooms.close endpoint
aleksandernsilva Dec 17, 2024
4615d04
feat: added checks
aleksandernsilva Jan 3, 2025
bb86b9e
test: added e2e api tests
aleksandernsilva Jan 3, 2025
0242718
refactor: adjusted error response
aleksandernsilva Feb 4, 2025
6ef6a5d
test: added more test cases
aleksandernsilva Feb 4, 2025
ca8f84c
test: changed to use promisses
aleksandernsilva Feb 4, 2025
86e48fa
refactor: changed error messages to follow error-xxxx pattern
aleksandernsilva Feb 4, 2025
d716f93
refactor: added a projection to subscription find
aleksandernsilva Feb 4, 2025
7a78061
fix: adjusted projection
aleksandernsilva Feb 4, 2025
b2fee10
test: adjusted error messages
aleksandernsilva Feb 4, 2025
3df5f6b
chore: changeset
aleksandernsilva Feb 10, 2025
526abdf
refactor: renamed `rooms.close` to `rooms.hide`
aleksandernsilva Feb 10, 2025
9bec9ce
refactor: adjusted error message
aleksandernsilva Feb 10, 2025
c13c2ba
refactor: changed user query projection
aleksandernsilva Feb 10, 2025
7c74480
test: updated error message
aleksandernsilva Feb 11, 2025
1009b2a
feat: added method findOneOpenByRoomIdAndUserId
aleksandernsilva Feb 11, 2025
f18a2ae
chore: updated changeset
aleksandernsilva Feb 11, 2025
4965533
refactor: removed method findOneOpenByRoomIdAndUserId
aleksandernsilva Feb 12, 2025
7d30b3b
fix: hideByRoomAndUserId to update only when sub is closed
aleksandernsilva Feb 12, 2025
000dd77
refactor: removed find added count check
aleksandernsilva Feb 12, 2025
bcaac55
test: cleanup users after tests
aleksandernsilva Feb 12, 2025
c7166bd
refactor: removed findOneOpenByRoomIdAndUserId type
aleksandernsilva Feb 12, 2025
8625bce
chore: updated changeset
aleksandernsilva Feb 12, 2025
79b2c70
test: added clean up for roomB
aleksandernsilva Feb 13, 2025
856ea60
Merge branch 'develop' into feat/rooms-close-endpoint
kodiakhq[bot] Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/chilly-sheep-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'@rocket.chat/rest-typings': minor
'@rocket.chat/models': minor
'@rocket.chat/i18n': minor
'@rocket.chat/meteor': minor
---

Adds a new endpoint `rooms.hide` to hide rooms of any type when provided with the room's ID
30 changes: 30 additions & 0 deletions apps/meteor/app/api/server/v1/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
isRoomsCleanHistoryProps,
isRoomsOpenProps,
isRoomsMembersOrderedByRoleProps,
isRoomsHideProps,
} from '@rocket.chat/rest-typings';
import { Meteor } from 'meteor/meteor';

Expand All @@ -21,6 +22,7 @@ import * as dataExport from '../../../../server/lib/dataExport';
import { eraseRoom } from '../../../../server/lib/eraseRoom';
import { findUsersOfRoomOrderedByRole } from '../../../../server/lib/findUsersOfRoomOrderedByRole';
import { openRoom } from '../../../../server/lib/openRoom';
import { hideRoomMethod } from '../../../../server/methods/hideRoom';
import { muteUserInRoom } from '../../../../server/methods/muteUserInRoom';
import { unmuteUserInRoom } from '../../../../server/methods/unmuteUserInRoom';
import { canAccessRoomAsync, canAccessRoomIdAsync } from '../../../authorization/server/functions/canAccessRoom';
Expand Down Expand Up @@ -962,3 +964,31 @@ API.v1.addRoute(
},
},
);

API.v1.addRoute(
'rooms.hide',
{ authRequired: true, validateParams: isRoomsHideProps },
{
async post() {
const { roomId } = this.bodyParams;

if (!(await canAccessRoomIdAsync(roomId, this.userId))) {
return API.v1.unauthorized();
}

const user = await Users.findOneById(this.userId, { projections: { _id: 1 } });

if (!user) {
return API.v1.failure('error-invalid-user');
}

const modCount = await hideRoomMethod(this.userId, roomId);

if (!modCount) {
return API.v1.failure('error-room-already-hidden');
}

return API.v1.success();
},
},
);
90 changes: 90 additions & 0 deletions apps/meteor/tests/end-to-end/api/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4204,4 +4204,94 @@ describe('[Rooms]', () => {
});
});
});

describe('/rooms.hide', () => {
let roomA: IRoom;
let roomB: IRoom;
const roomName = `rooms.hide.test.${Date.now()}`;
let memberA: TestUser<IUser>;
let memberB: TestUser<IUser>;
let nonMember: TestUser<IUser>;
let nonMemberCredentials: Credentials;

before(async () => {
memberA = await createUser();
memberB = await createUser();
nonMember = await createUser();
nonMemberCredentials = await login(nonMember.username, password);
});

before(async () => {
roomA = (await createRoom({ type: 'c', name: roomName, members: [memberA.username, memberB.username] })).body.channel;
roomB = (await createRoom({ type: 'd', username: memberB.username })).body.room;
aleksandernsilva marked this conversation as resolved.
Show resolved Hide resolved
});

after(async () => {
await deleteRoom({ type: 'c', roomId: roomA._id });
await deleteRoom({ type: 'd', roomId: roomB._id });
await deleteUser(memberA);
await deleteUser(memberB);
await deleteUser(nonMember);
});

it('should hide the room', async () => {
await request
.post(api('rooms.hide'))
.set(credentials)
.send({ roomId: roomA._id })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});

it('should be already hidden', async () => {
await request
.post(api('rooms.hide'))
.set(credentials)
.send({ roomId: roomA._id })
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', `error-room-already-hidden`);
});
});

it('should fail if roomId is not provided', async () => {
await request
.post(api('rooms.hide'))
.set(credentials)
.send()
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res: Response) => {
expect(res.body).to.have.property('success', false);
});
});

it('should return 401 if user is not logged in', async () => {
await request
.post(api('rooms.hide'))
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('status', 'error');
expect(res.body).to.have.property('message');
});
});

it('should return forbidden if user does not have access to the room', async () => {
await request
.post(api('rooms.hide'))
.set(nonMemberCredentials)
.send({ roomId: roomB._id })
.expect('Content-Type', 'application/json')
.expect(401)
.expect((res) => {
expect(res.body).to.have.property('success', false);
});
});
});
});
1 change: 1 addition & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -2245,6 +2245,7 @@
"error-room-does-not-exist": "This room does not exist",
"error-role-already-present": "A role with this name already exists",
"error-room-already-closed": "Room is already closed",
"error-room-already-hidden": "Room is already hidden",
"error-room-is-not-closed": "Room is not closed",
"error-room-onHold": "Error! Room is On Hold",
"error-room-is-already-on-hold": "Error! Room is already On Hold",
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/locales/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,7 @@
"error-role-name-required": "Nome do papel é obrigatório",
"error-room-does-not-exist": "Essa sala não existe",
"error-role-already-present": "Já existe uma função com este nome",
"error-room-already-hidden": "A sala já está oculta",
"error-room-is-not-closed": "Sala não está fechada",
"error-room-onHold": "Erro! Sala está em espera",
"error-selected-agent-room-agent-are-same": "O agente selecionado e o agente da sala são iguais",
Expand Down
1 change: 1 addition & 0 deletions packages/models/src/models/Subscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,7 @@ export class SubscriptionsRaw extends BaseRaw<ISubscription> implements ISubscri
const query = {
'rid': roomId,
'u._id': userId,
'open': true,
};

const update: UpdateFilter<ISubscription> = {
Expand Down
22 changes: 22 additions & 0 deletions packages/rest-typings/src/v1/rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,24 @@ const membersOrderedByRoleRolePropsSchema = {

export const isRoomsMembersOrderedByRoleProps = ajv.compile<RoomsMembersOrderedByRoleProps>(membersOrderedByRoleRolePropsSchema);

type RoomsHideProps = {
roomId: string;
};

const roomsHideSchema = {
type: 'object',
properties: {
roomId: {
type: 'string',
minLength: 1,
},
},
required: ['roomId'],
additionalProperties: false,
};

export const isRoomsHideProps = ajv.compile<RoomsHideProps>(roomsHideSchema);

export type RoomsEndpoints = {
'/v1/rooms.autocomplete.channelAndPrivate': {
GET: (params: RoomsAutoCompleteChannelAndPrivateProps) => {
Expand Down Expand Up @@ -846,4 +864,8 @@ export type RoomsEndpoints = {
members: (IUser & { roles?: IRole['_id'][] })[];
}>;
};

'/v1/rooms.hide': {
POST: (params: RoomsHideProps) => void;
};
};
Loading