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 { isGroupsOnlineProps
5+ , isGroupsMessagesProps ,
6+ isGroupsFilesProps ,
7+ ajv ,
8+ validateBadRequestErrorResponse ,
9+ validateUnauthorizedErrorResponse ,
10+ validateForbiddenErrorResponse ,
11+ withGroupBaseProperties , } from '@rocket.chat/rest-typings' ;
512import { isTruthy } from '@rocket.chat/tools' ;
613import { check , Match } from 'meteor/check' ;
714import { Meteor } from 'meteor/meteor' ;
815import type { Filter } from 'mongodb' ;
916
17+
18+ import type { ExtractRoutesFromAPI } from '../ApiClass' ;
1019import { eraseRoom } from '../../../../server/lib/eraseRoom' ;
1120import { findUsersOfRoom } from '../../../../server/lib/findUsersOfRoom' ;
1221import { openRoom } from '../../../../server/lib/openRoom' ;
@@ -36,6 +45,111 @@ import { addUserToFileObj } from '../helpers/addUserToFileObj';
3645import { composeRoomWithLastMessage } from '../helpers/composeRoomWithLastMessage' ;
3746import { getPaginationItems } from '../helpers/getPaginationItems' ;
3847import { getUserFromParams , getUserListFromParams } from '../helpers/getUserFromParams' ;
48+ import type { PaginatedRequest , GroupsBaseProps } from '@rocket.chat/rest-typings' ;
49+ import { nullable } from 'zod' ;
50+
51+ type GroupsMembersProps = PaginatedRequest < GroupsBaseProps & { filter ?: string ; status ?: string [ ] } > ;
52+
53+ const GroupsMembersPropsSchema = withGroupBaseProperties ( {
54+ offset : {
55+ type : 'string' ,
56+ } ,
57+ count : {
58+ type : 'string' ,
59+ } ,
60+ filter : {
61+ type : 'string' ,
62+ } ,
63+ query : {
64+ type : 'string' ,
65+ nullable : true
66+ } ,
67+ sort : {
68+ type : 'string' ,
69+ nullable : true
70+ } ,
71+ status : {
72+ type : 'array' ,
73+ items : { type : 'string' } ,
74+ } ,
75+ } ) ;
76+
77+ const isGroupsMembersProps = ajv . compile < GroupsMembersProps > ( GroupsMembersPropsSchema ) ;
78+
79+
80+ const isGroupsMembersResponse = ajv . compile ( {
81+ type : 'object' ,
82+ properties : {
83+ members : {
84+ type : 'array' ,
85+ items : { $ref : '#/components/schemas/IUser' } ,
86+ } ,
87+ count : { type : 'integer' } ,
88+ offset : { type : 'integer' } ,
89+ total : { type : 'integer' } ,
90+ success : { type : 'boolean' , enum : [ true ] } ,
91+ } ,
92+ required : [ 'members' , 'success' ] ,
93+ additionalProperties : false ,
94+ } ) ;
95+
96+ const groupsEndPoints = API . v1
97+ . get (
98+ 'groups.members' ,
99+ {
100+ authRequired : true ,
101+ query : isGroupsMembersProps ,
102+ response : {
103+ 200 : isGroupsMembersResponse ,
104+ 400 : validateBadRequestErrorResponse ,
105+ 401 : validateUnauthorizedErrorResponse ,
106+ 403 : validateForbiddenErrorResponse
107+ }
108+ } ,
109+ async function action ( ) {
110+ const findResult = await findPrivateGroupByIdOrName ( {
111+ params : this . queryParams ,
112+ userId : this . userId ,
113+ } ) ;
114+
115+ if ( findResult . broadcast && ! ( await hasPermissionAsync ( this . userId , 'view-broadcast-member-list' , findResult . rid ) ) ) {
116+ return API . v1 . forbidden ( 'User does not have the permissions required for this action' ) ;
117+ }
118+
119+ const { offset : skip , count : limit } = await getPaginationItems ( this . queryParams ) ;
120+ const { sort = { } } = await this . parseJsonQuery ( ) ;
121+
122+ check (
123+ this . queryParams ,
124+ Match . ObjectIncluding ( {
125+ status : Match . Maybe ( [ String ] ) ,
126+ filter : Match . Maybe ( String ) ,
127+ } ) ,
128+ ) ;
129+
130+ const { status, filter } = this . queryParams ;
131+
132+ const { cursor, totalCount } = await findUsersOfRoom ( {
133+ rid : findResult . rid ,
134+ ...( status && { status : { $in : status as UserStatus [ ] } } ) ,
135+ skip,
136+ limit,
137+ filter,
138+ ...( sort ?. username && { sort : { username : sort . username } } ) ,
139+ } ) ;
140+
141+ const [ members , total ] = await Promise . all ( [ cursor . toArray ( ) , totalCount ] ) ;
142+
143+ return API . v1 . success ( {
144+ members,
145+ count : members . length ,
146+ offset : skip ,
147+ total,
148+ } ) ;
149+ }
150+ )
151+
152+
39153
40154async function getRoomFromParams ( params : { roomId ?: string } | { roomName ?: string } ) : Promise < IRoom > {
41155 if (
@@ -718,54 +832,6 @@ API.v1.addRoute(
718832 } ,
719833) ;
720834
721- API . v1 . addRoute (
722- 'groups.members' ,
723- { authRequired : true } ,
724- {
725- async get ( ) {
726- const findResult = await findPrivateGroupByIdOrName ( {
727- params : this . queryParams ,
728- userId : this . userId ,
729- } ) ;
730-
731- if ( findResult . broadcast && ! ( await hasPermissionAsync ( this . userId , 'view-broadcast-member-list' , findResult . rid ) ) ) {
732- return API . v1 . forbidden ( ) ;
733- }
734-
735- const { offset : skip , count : limit } = await getPaginationItems ( this . queryParams ) ;
736- const { sort = { } } = await this . parseJsonQuery ( ) ;
737-
738- check (
739- this . queryParams ,
740- Match . ObjectIncluding ( {
741- status : Match . Maybe ( [ String ] ) ,
742- filter : Match . Maybe ( String ) ,
743- } ) ,
744- ) ;
745-
746- const { status, filter } = this . queryParams ;
747-
748- const { cursor, totalCount } = await findUsersOfRoom ( {
749- rid : findResult . rid ,
750- ...( status && { status : { $in : status as UserStatus [ ] } } ) ,
751- skip,
752- limit,
753- filter,
754- ...( sort ?. username && { sort : { username : sort . username } } ) ,
755- } ) ;
756-
757- const [ members , total ] = await Promise . all ( [ cursor . toArray ( ) , totalCount ] ) ;
758-
759- return API . v1 . success ( {
760- members,
761- count : members . length ,
762- offset : skip ,
763- total,
764- } ) ;
765- } ,
766- } ,
767- ) ;
768-
769835API . v1 . addRoute (
770836 'groups.messages' ,
771837 { authRequired : true , validateParams : isGroupsMessagesProps } ,
@@ -1300,3 +1366,11 @@ API.v1.addRoute(
13001366 } ,
13011367 } ,
13021368) ;
1369+
1370+
1371+ export type GroupsHistoryEndpoints = ExtractRoutesFromAPI < typeof groupsEndPoints > ;
1372+
1373+ declare module '@rocket.chat/rest-typings' {
1374+ // eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-empty-interface
1375+ interface Endpoints extends GroupsHistoryEndpoints { }
1376+ }
0 commit comments