11import { Team , isMeteorError } from '@rocket.chat/core-services' ;
22import type { IIntegration , IUser , IRoom , RoomType , UserStatus } from '@rocket.chat/core-typings' ;
33import { Integrations , Messages , Rooms , Subscriptions , Uploads , Users } from '@rocket.chat/models' ;
4- import { isGroupsOnlineProps , isGroupsMessagesProps , isGroupsFilesProps } from '@rocket.chat/rest-typings' ;
4+ import {
5+ isGroupsOnlineProps ,
6+ isGroupsMessagesProps ,
7+ isGroupsFilesProps ,
8+ ajv ,
9+ validateBadRequestErrorResponse ,
10+ validateUnauthorizedErrorResponse ,
11+ validateForbiddenErrorResponse ,
12+ } from '@rocket.chat/rest-typings' ;
513import { isTruthy } from '@rocket.chat/tools' ;
614import { check , Match } from 'meteor/check' ;
7- import { Meteor } from 'meteor/meteor' ;
815import type { Filter } from 'mongodb' ;
916
1017import { eraseRoom } from '../../../../server/lib/eraseRoom' ;
@@ -31,12 +38,136 @@ import { executeGetRoomRoles } from '../../../lib/server/methods/getRoomRoles';
3138import { leaveRoomMethod } from '../../../lib/server/methods/leaveRoom' ;
3239import { executeUnarchiveRoom } from '../../../lib/server/methods/unarchiveRoom' ;
3340import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser' ;
41+ import type { ExtractRoutesFromAPI } from '../ApiClass' ;
3442import { API } from '../api' ;
3543import { addUserToFileObj } from '../helpers/addUserToFileObj' ;
3644import { composeRoomWithLastMessage } from '../helpers/composeRoomWithLastMessage' ;
3745import { getPaginationItems } from '../helpers/getPaginationItems' ;
3846import { getUserFromParams , getUserListFromParams } from '../helpers/getUserFromParams' ;
3947
48+ type GroupsCreateProps = {
49+ name : string ;
50+ members ?: string [ ] ;
51+ customFields ?: Record < string , any > ;
52+ readOnly ?: boolean ;
53+ extraData ?: {
54+ broadcast : boolean ;
55+ encrypted : boolean ;
56+ federated ?: boolean ;
57+ topic ?: string ;
58+ teamId ?: string ;
59+ } ;
60+ excludeSelf ?: boolean ;
61+ } ;
62+
63+ const GroupsCreatePropsSchema = {
64+ type : 'object' ,
65+ properties : {
66+ name : {
67+ type : 'string' ,
68+ } ,
69+ members : {
70+ type : 'array' ,
71+ items : { type : 'string' } ,
72+ } ,
73+ readOnly : {
74+ type : 'boolean' ,
75+ } ,
76+ customFields : {
77+ type : 'object' ,
78+ additionalProperties : true ,
79+ } ,
80+ extraData : {
81+ type : 'object' ,
82+ properties : {
83+ broadcast : {
84+ type : 'boolean' ,
85+ } ,
86+ encrypted : {
87+ type : 'boolean' ,
88+ } ,
89+ federated : {
90+ type : 'boolean' ,
91+ } ,
92+ teamId : {
93+ type : 'string' ,
94+ } ,
95+ topic : {
96+ type : 'string' ,
97+ } ,
98+ } ,
99+ additionalProperties : false ,
100+ } ,
101+ excludeSelf : {
102+ type : 'boolean' ,
103+ } ,
104+ } ,
105+ required : [ 'name' ] ,
106+ additionalProperties : false ,
107+ } ;
108+
109+ const isGroupsCreateProps = ajv . compile < GroupsCreateProps > ( GroupsCreatePropsSchema ) ;
110+
111+ const isGroupsCreateResponseSchema = ajv . compile ( {
112+ type : 'object' ,
113+ properties : {
114+ success : {
115+ type : 'boolean' ,
116+ enum : [ true ] ,
117+ } ,
118+ group : {
119+ $ref : '#/components/schemas/IRoom' ,
120+ } ,
121+ } ,
122+ required : [ 'success' , 'group' ] ,
123+ additionalProperties : false ,
124+ } ) ;
125+
126+ const groupsEndpoints = API . v1
127+ //Creates private group
128+ . post (
129+ 'groups.create' ,
130+ {
131+ authRequired : true ,
132+ body : isGroupsCreateProps ,
133+ response : {
134+ 200 : isGroupsCreateResponseSchema ,
135+ 400 : validateBadRequestErrorResponse ,
136+ 401 : validateUnauthorizedErrorResponse ,
137+ 403 : validateForbiddenErrorResponse ,
138+ } ,
139+ } ,
140+ async function action ( ) {
141+ const readOnly = this . bodyParams . readOnly ?? false ;
142+
143+ try {
144+ const result = await createPrivateGroupMethod (
145+ this . user ,
146+ this . bodyParams . name ,
147+ this . bodyParams . members ? this . bodyParams . members : [ ] ,
148+ readOnly ,
149+ this . bodyParams . customFields ,
150+ this . bodyParams . extraData ,
151+ this . bodyParams . excludeSelf ?? false ,
152+ ) ;
153+
154+ const room = await Rooms . findOneById ( result . rid , { projection : API . v1 . defaultFieldsToExclude } ) ;
155+ if ( ! room ) {
156+ throw new Meteor . Error ( 'error-room-not-found' , 'The required "roomId" or "roomName" param provided does not match any group' ) ;
157+ }
158+
159+ return API . v1 . success ( {
160+ group : await composeRoomWithLastMessage ( room , this . userId ) ,
161+ } ) ;
162+ } catch ( error : unknown ) {
163+ if ( isMeteorError ( error ) && error . reason === 'error-not-allowed' ) {
164+ throw new Meteor . Error ( 'error-not-allowed' , 'Not allowed' ) ;
165+ }
166+ throw error ;
167+ }
168+ } ,
169+ ) ;
170+
40171async function getRoomFromParams ( params : { roomId ?: string } | { roomName ?: string } ) : Promise < IRoom > {
41172 if (
42173 ( ! ( 'roomId' in params ) && ! ( 'roomName' in params ) ) ||
@@ -316,58 +447,6 @@ API.v1.addRoute(
316447 } ,
317448) ;
318449
319- // Create Private Group
320- API . v1 . addRoute (
321- 'groups.create' ,
322- { authRequired : true } ,
323- {
324- async post ( ) {
325- if ( ! this . bodyParams . name ) {
326- return API . v1 . failure ( 'Body param "name" is required' ) ;
327- }
328-
329- if ( this . bodyParams . members && ! Array . isArray ( this . bodyParams . members ) ) {
330- return API . v1 . failure ( 'Body param "members" must be an array if provided' ) ;
331- }
332-
333- if ( this . bodyParams . customFields && ! ( typeof this . bodyParams . customFields === 'object' ) ) {
334- return API . v1 . failure ( 'Body param "customFields" must be an object if provided' ) ;
335- }
336- if ( this . bodyParams . extraData && ! ( typeof this . bodyParams . extraData === 'object' ) ) {
337- return API . v1 . failure ( 'Body param "extraData" must be an object if provided' ) ;
338- }
339-
340- const readOnly = typeof this . bodyParams . readOnly !== 'undefined' ? this . bodyParams . readOnly : false ;
341-
342- try {
343- const result = await createPrivateGroupMethod (
344- this . user ,
345- this . bodyParams . name ,
346- this . bodyParams . members ? this . bodyParams . members : [ ] ,
347- readOnly ,
348- this . bodyParams . customFields ,
349- this . bodyParams . extraData ,
350- this . bodyParams . excludeSelf ?? false ,
351- ) ;
352-
353- const room = await Rooms . findOneById ( result . rid , { projection : API . v1 . defaultFieldsToExclude } ) ;
354- if ( ! room ) {
355- throw new Meteor . Error ( 'error-room-not-found' , 'The required "roomId" or "roomName" param provided does not match any group' ) ;
356- }
357-
358- return API . v1 . success ( {
359- group : await composeRoomWithLastMessage ( room , this . userId ) ,
360- } ) ;
361- } catch ( error : unknown ) {
362- if ( isMeteorError ( error ) && error . reason === 'error-not-allowed' ) {
363- return API . v1 . forbidden ( ) ;
364- }
365- throw error ;
366- }
367- } ,
368- } ,
369- ) ;
370-
371450API . v1 . addRoute (
372451 'groups.delete' ,
373452 { authRequired : true } ,
@@ -1300,3 +1379,10 @@ API.v1.addRoute(
13001379 } ,
13011380 } ,
13021381) ;
1382+
1383+ export type GroupsEndpoints = ExtractRoutesFromAPI < typeof groupsEndpoints > ;
1384+
1385+ declare module '@rocket.chat/rest-typings' {
1386+ // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
1387+ interface Endpoints extends GroupsEndpoints { }
1388+ }
0 commit comments