diff --git a/.changeset/groups.removeModerator.md b/.changeset/groups.removeModerator.md new file mode 100644 index 0000000000000..426009eebbc66 --- /dev/null +++ b/.changeset/groups.removeModerator.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/rest-typings": minor +--- + +Add OpenAPI support for the Rocket.Chat groups.removeModerator API endpoints by migrating to a modern chained route definition syntax and utilizing shared AJV schemas for validation \ No newline at end of file diff --git a/apps/meteor/app/api/server/v1/groups.ts b/apps/meteor/app/api/server/v1/groups.ts index 2437813860836..d9ce9e6939528 100644 --- a/apps/meteor/app/api/server/v1/groups.ts +++ b/apps/meteor/app/api/server/v1/groups.ts @@ -1,7 +1,16 @@ import { Team, isMeteorError } from '@rocket.chat/core-services'; import type { IIntegration, IUser, IRoom, RoomType, UserStatus } from '@rocket.chat/core-typings'; import { Integrations, Messages, Rooms, Subscriptions, Uploads, Users } from '@rocket.chat/models'; -import { isGroupsOnlineProps, isGroupsMessagesProps, isGroupsFilesProps } from '@rocket.chat/rest-typings'; +import { + isGroupsOnlineProps, + isGroupsMessagesProps, + isGroupsFilesProps, + ajv, + validateBadRequestErrorResponse, + validateUnauthorizedErrorResponse, + withGroupBaseProperties, + GroupsBaseProps +} from '@rocket.chat/rest-typings'; import { isTruthy } from '@rocket.chat/tools'; import { check, Match } from 'meteor/check'; import { Meteor } from 'meteor/meteor'; @@ -31,6 +40,7 @@ import { executeGetRoomRoles } from '../../../lib/server/methods/getRoomRoles'; import { leaveRoomMethod } from '../../../lib/server/methods/leaveRoom'; import { executeUnarchiveRoom } from '../../../lib/server/methods/unarchiveRoom'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; +import type { ExtractRoutesFromAPI } from '../ApiClass'; import { API } from '../api'; import { addUserToFileObj } from '../helpers/addUserToFileObj'; import { composeRoomWithLastMessage } from '../helpers/composeRoomWithLastMessage'; @@ -67,7 +77,7 @@ async function getRoomFromParams(params: { roomId?: string } | { roomName?: stri } })(); - if (!room || room.t !== 'p') { + if (room?.t !== 'p') { throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group'); } @@ -273,7 +283,7 @@ API.v1.addRoute( room = await Rooms.findOneByName(params.roomName || ''); } - if (!room || room.t !== 'p') { + if (room?.t !== 'p') { throw new Meteor.Error('error-room-not-found', 'The required "roomId" or "roomName" param provided does not match any group'); } @@ -791,7 +801,7 @@ API.v1.addRoute( rid: findResult.rid, ...parseIds(mentionIds, 'mentions._id'), ...parseIds(starredIds, 'starred._id'), - ...(pinned && pinned.toLowerCase() === 'true' ? { pinned: true } : {}), + ...(pinned?.toLowerCase() === 'true' ? { pinned: true } : {}), _hidden: { $ne: true }, }; @@ -891,22 +901,47 @@ API.v1.addRoute( }, ); -API.v1.addRoute( +type WithUserId = GroupsBaseProps & { userId: string }; +const withUserIdSchema = withGroupBaseProperties( + { + userId: { + type: 'string', + }, + }, + ['userId'], +); + +const withUserIdProps = ajv.compile(withUserIdSchema); + +const groupsEndpoints = API.v1.post( 'groups.removeModerator', - { authRequired: true }, { - async post() { - const findResult = await findPrivateGroupByIdOrName({ - params: this.bodyParams, - userId: this.userId, - }); + authRequired: true, + body: withUserIdProps, + response: { + 400: validateBadRequestErrorResponse, + 401: validateUnauthorizedErrorResponse, + 200: ajv.compile({ + type: 'object', + properties: { + success: { type: 'boolean', enum: [true] }, + }, + required: ['success'], + additionalProperties: false, + }), + }, + }, + async function action() { + const findResult = await findPrivateGroupByIdOrName({ + params: this.bodyParams, + userId: this.userId, + }); - const user = await getUserFromParams(this.bodyParams); + const user = await getUserFromParams(this.bodyParams); - await removeRoomModerator(this.userId, findResult.rid, user._id); + await removeRoomModerator(this.userId, findResult.rid, user._id); - return API.v1.success(); - }, + return API.v1.success(); }, ); @@ -1300,3 +1335,10 @@ API.v1.addRoute( }, }, ); + +type GroupEndpoints = ExtractRoutesFromAPI; + +declare module '@rocket.chat/rest-typings' { + // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface + interface Endpoints extends GroupEndpoints {} +} diff --git a/packages/rest-typings/src/v1/groups/GroupsRemoveModeratorProps.ts b/packages/rest-typings/src/v1/groups/GroupsRemoveModeratorProps.ts deleted file mode 100644 index c9dbd069094bd..0000000000000 --- a/packages/rest-typings/src/v1/groups/GroupsRemoveModeratorProps.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { WithUserId } from './BaseProps'; -import { withUserIdProps } from './BaseProps'; - -export type GroupsRemoveModeratorProps = WithUserId; -export const isGroupsRemoveModeratorProps = withUserIdProps; diff --git a/packages/rest-typings/src/v1/groups/groups.ts b/packages/rest-typings/src/v1/groups/groups.ts index a7c937b08a9fc..ea4f20d92b94b 100644 --- a/packages/rest-typings/src/v1/groups/groups.ts +++ b/packages/rest-typings/src/v1/groups/groups.ts @@ -24,7 +24,6 @@ import type { GroupsModeratorsProps } from './GroupsModeratorsProps'; import type { GroupsOnlineProps } from './GroupsOnlineProps'; import type { GroupsOpenProps } from './GroupsOpenProps'; import type { GroupsRemoveLeaderProps } from './GroupsRemoveLeaderProps'; -import type { GroupsRemoveModeratorProps } from './GroupsRemoveModeratorProps'; import type { GroupsRemoveOwnerProps } from './GroupsRemoveOwnerProps'; import type { GroupsRenameProps } from './GroupsRenameProps'; import type { GroupsRolesProps } from './GroupsRolesProps'; @@ -107,9 +106,7 @@ export type GroupsEndpoints = { '/v1/groups.addModerator': { POST: (params: GroupsAddModeratorProps) => void; }; - '/v1/groups.removeModerator': { - POST: (params: GroupsRemoveModeratorProps) => void; - }; + '/v1/groups.addOwner': { POST: (params: GroupsAddOwnerProps) => void; }; diff --git a/packages/rest-typings/src/v1/groups/index.ts b/packages/rest-typings/src/v1/groups/index.ts index aad463d285c9d..bb2a080b9b7f9 100644 --- a/packages/rest-typings/src/v1/groups/index.ts +++ b/packages/rest-typings/src/v1/groups/index.ts @@ -25,7 +25,6 @@ export * from './GroupsOnlineProps'; export * from './GroupsOpenProps'; export * from './GroupsRenameProps'; export * from './GroupsRemoveLeaderProps'; -export * from './GroupsRemoveModeratorProps'; export * from './GroupsRemoveOwnerProps'; export * from './GroupsSetAnnouncementProps'; export * from './GroupsSetCustomFieldsProps';