11import { Users } from '@rocket.chat/models' ;
2- import { isLivechatUsersManagerGETProps , isPOSTLivechatUsersTypeProps } from '@rocket.chat/rest-typings' ;
3- import { check } from 'meteor/check' ;
2+ import { ajv , validateBadRequestErrorResponse , validateUnauthorizedErrorResponse , validateForbiddenErrorResponse } from '@rocket.chat/rest-typings' ;
43
54import { API } from '../../../../api/server' ;
65import { getPaginationItems } from '../../../../api/server/helpers/getPaginationItems' ;
76import { hasAtLeastOnePermissionAsync } from '../../../../authorization/server/functions/hasPermission' ;
87import { findAgents , findManagers } from '../../../server/api/lib/users' ;
98import { addManager , addAgent , removeAgent , removeManager } from '../../../server/lib/omni-users' ;
109
10+ // --- Local types and AJV schemas (moved from rest-typings) ---
11+
12+ type LivechatUsersManagerGETLocal = {
13+ text ?: string ;
14+ fields ?: string ;
15+ onlyAvailable ?: boolean ;
16+ excludeId ?: string ;
17+ showIdleAgents ?: boolean ;
18+ count ?: number ;
19+ offset ?: number ;
20+ sort ?: string ;
21+ query ?: string ;
22+ } ;
23+
24+ const LivechatUsersManagerGETLocalSchema = {
25+ type : 'object' ,
26+ properties : {
27+ text : { type : 'string' , nullable : true } ,
28+ onlyAvailable : { type : 'boolean' , nullable : true } ,
29+ excludeId : { type : 'string' , nullable : true } ,
30+ showIdleAgents : { type : 'boolean' , nullable : true } ,
31+ count : { type : 'number' , nullable : true } ,
32+ offset : { type : 'number' , nullable : true } ,
33+ sort : { type : 'string' , nullable : true } ,
34+ query : { type : 'string' , nullable : true } ,
35+ fields : { type : 'string' , nullable : true } ,
36+ } ,
37+ required : [ ] ,
38+ additionalProperties : false ,
39+ } ;
40+
41+ const isLivechatUsersManagerGETLocal = ajv . compile < LivechatUsersManagerGETLocal > ( LivechatUsersManagerGETLocalSchema ) ;
42+
43+ type POSTLivechatUsersTypeLocal = {
44+ username : string ;
45+ } ;
46+
47+ const POSTLivechatUsersTypeLocalSchema = {
48+ type : 'object' ,
49+ properties : {
50+ username : { type : 'string' } ,
51+ } ,
52+ required : [ 'username' ] ,
53+ additionalProperties : false ,
54+ } ;
55+
56+ const isPOSTLivechatUsersTypeLocal = ajv . compile < POSTLivechatUsersTypeLocal > ( POSTLivechatUsersTypeLocalSchema ) ;
57+
58+ // --- Response schemas ---
59+
60+ const paginatedUsersResponseSchema = ajv . compile < {
61+ users : object [ ] ;
62+ count : number ;
63+ offset : number ;
64+ total : number ;
65+ } > ( {
66+ type : 'object' ,
67+ properties : {
68+ // ILivechatAgent is not registered in typia (extends IUser with livechat-specific fields),
69+ // so we use { type: 'object' } as a fallback.
70+ users : { type : 'array' , items : { type : 'object' } } ,
71+ count : { type : 'number' } ,
72+ offset : { type : 'number' } ,
73+ total : { type : 'number' } ,
74+ success : { type : 'boolean' , enum : [ true ] } ,
75+ } ,
76+ required : [ 'users' , 'count' , 'offset' , 'total' , 'success' ] ,
77+ additionalProperties : false ,
78+ } ) ;
79+
80+ const postUserResponseSchema = ajv . compile < { user : object } > ( {
81+ type : 'object' ,
82+ properties : {
83+ user : { type : 'object' } ,
84+ success : { type : 'boolean' , enum : [ true ] } ,
85+ } ,
86+ required : [ 'user' , 'success' ] ,
87+ additionalProperties : false ,
88+ } ) ;
89+
90+ const successOnlyResponseSchema = ajv . compile < void > ( {
91+ type : 'object' ,
92+ properties : {
93+ success : { type : 'boolean' , enum : [ true ] } ,
94+ } ,
95+ required : [ 'success' ] ,
96+ additionalProperties : false ,
97+ } ) ;
98+
99+ const getUserByIdResponseSchema = ajv . compile < { user : object | null } > ( {
100+ type : 'object' ,
101+ properties : {
102+ user : { type : [ 'object' , 'null' ] } ,
103+ success : { type : 'boolean' , enum : [ true ] } ,
104+ } ,
105+ required : [ 'user' , 'success' ] ,
106+ additionalProperties : false ,
107+ } ) ;
108+
11109const emptyStringArray : string [ ] = [ ] ;
12110
13- API . v1 . addRoute (
14- 'livechat/users/:type' ,
15- {
16- authRequired : true ,
17- permissionsRequired : {
18- 'POST' : [ 'view-livechat-manager' ] ,
19- '*' : emptyStringArray ,
20- } ,
21- validateParams : {
22- GET : isLivechatUsersManagerGETProps ,
23- POST : isPOSTLivechatUsersTypeProps ,
111+ API . v1
112+ . get (
113+ 'livechat/users/:type' ,
114+ {
115+ authRequired : true ,
116+ permissionsRequired : emptyStringArray ,
117+ query : isLivechatUsersManagerGETLocal ,
118+ response : {
119+ 200 : paginatedUsersResponseSchema ,
120+ 400 : validateBadRequestErrorResponse ,
121+ 401 : validateUnauthorizedErrorResponse ,
122+ 403 : validateForbiddenErrorResponse ,
123+ } ,
24124 } ,
25- } ,
26- {
27- async get ( ) {
28- check ( this . urlParams , {
29- type : String ,
30- } ) ;
125+ async function action ( ) {
31126 const { offset, count } = await getPaginationItems ( this . queryParams ) ;
32127 const { sort } = await this . parseJsonQuery ( ) ;
33128 const { text } = this . queryParams ;
34129
35130 if ( this . urlParams . type === 'agent' ) {
36131 if ( ! ( await hasAtLeastOnePermissionAsync ( this . userId , [ 'transfer-livechat-guest' , 'edit-omnichannel-contact' ] ) ) ) {
37- return API . v1 . forbidden ( ) ;
132+ return API . v1 . forbidden ( 'error-not-authorized' ) ;
38133 }
39134
40- const { onlyAvailable, excludeId, showIdleAgents } = this . queryParams ;
135+ const { onlyAvailable = false , excludeId, showIdleAgents } = this . queryParams ;
41136 return API . v1 . success (
42137 await findAgents ( {
43138 text,
@@ -54,7 +149,7 @@ API.v1.addRoute(
54149 }
55150 if ( this . urlParams . type === 'manager' ) {
56151 if ( ! ( await hasAtLeastOnePermissionAsync ( this . userId , [ 'view-livechat-manager' ] ) ) ) {
57- return API . v1 . forbidden ( ) ;
152+ return API . v1 . forbidden ( 'error-not-authorized' ) ;
58153 }
59154
60155 return API . v1 . success (
@@ -70,7 +165,21 @@ API.v1.addRoute(
70165 }
71166 throw new Error ( 'Invalid type' ) ;
72167 } ,
73- async post ( ) {
168+ )
169+ . post (
170+ 'livechat/users/:type' ,
171+ {
172+ authRequired : true ,
173+ permissionsRequired : [ 'view-livechat-manager' ] ,
174+ body : isPOSTLivechatUsersTypeLocal ,
175+ response : {
176+ 200 : postUserResponseSchema ,
177+ 400 : validateBadRequestErrorResponse ,
178+ 401 : validateUnauthorizedErrorResponse ,
179+ 403 : validateForbiddenErrorResponse ,
180+ } ,
181+ } ,
182+ async function action ( ) {
74183 if ( this . urlParams . type === 'agent' ) {
75184 const user = await addAgent ( this . bodyParams . username ) ;
76185 if ( user ) {
@@ -87,14 +196,21 @@ API.v1.addRoute(
87196
88197 return API . v1 . failure ( ) ;
89198 } ,
90- } ,
91- ) ;
92-
93- API . v1 . addRoute (
94- 'livechat/users/:type/:_id' ,
95- { authRequired : true , permissionsRequired : [ 'view-livechat-manager' ] } ,
96- {
97- async get ( ) {
199+ )
200+ . get (
201+ 'livechat/users/:type/:_id' ,
202+ {
203+ authRequired : true ,
204+ permissionsRequired : [ 'view-livechat-manager' ] ,
205+ query : undefined ,
206+ response : {
207+ 200 : getUserByIdResponseSchema ,
208+ 400 : validateBadRequestErrorResponse ,
209+ 401 : validateUnauthorizedErrorResponse ,
210+ 403 : validateForbiddenErrorResponse ,
211+ } ,
212+ } ,
213+ async function action ( ) {
98214 if ( ! [ 'agent' , 'manager' ] . includes ( this . urlParams . type ) ) {
99215 throw new Error ( 'Invalid type' ) ;
100216 }
@@ -107,7 +223,21 @@ API.v1.addRoute(
107223 // TODO: throw error instead of returning null
108224 return API . v1 . success ( { user } ) ;
109225 } ,
110- async delete ( ) {
226+ )
227+ . delete (
228+ 'livechat/users/:type/:_id' ,
229+ {
230+ authRequired : true ,
231+ permissionsRequired : [ 'view-livechat-manager' ] ,
232+ query : undefined ,
233+ response : {
234+ 200 : successOnlyResponseSchema ,
235+ 400 : validateBadRequestErrorResponse ,
236+ 401 : validateUnauthorizedErrorResponse ,
237+ 403 : validateForbiddenErrorResponse ,
238+ } ,
239+ } ,
240+ async function action ( ) {
111241 if ( this . urlParams . type === 'agent' ) {
112242 if ( await removeAgent ( this . urlParams . _id ) ) {
113243 return API . v1 . success ( ) ;
@@ -120,7 +250,7 @@ API.v1.addRoute(
120250 throw new Error ( 'Invalid type' ) ;
121251 }
122252
123- return API . v1 . failure ( ) ;
253+ return API . v1 . failure ( 'error-removing-user' ) ;
124254 } ,
125- } ,
126- ) ;
255+ ) ;
256+
0 commit comments