@@ -35,12 +35,12 @@ const addMemberValidations = {
3535 * @param {Object } invite invite to process
3636 * @param {Array } invites existent invites from DB
3737 * @param {Object } data template for new invites to be put in DB
38+ * @param {Array } failed failed invites error message
3839 *
3940 * @returns {Promise<Promise[]> } list of promises
4041 */
41- const buildCreateInvitePromises = ( req , invite , invites , data ) => {
42+ const buildCreateInvitePromises = ( req , invite , invites , data , failed ) => {
4243 const invitePromises = [ ] ;
43-
4444 if ( invite . userIds ) {
4545 // remove invites for users that are invited already
4646 _ . remove ( invite . userIds , u => _ . some ( invites , i => i . userId === u ) ) ;
@@ -91,15 +91,15 @@ const buildCreateInvitePromises = (req, invite, invites, data) => {
9191
9292 invitePromises . push ( models . ProjectMemberInvite . create ( dataNew ) ) ;
9393 } ) ;
94-
95- return Promise . resolve ( invitePromises ) ;
94+ return invitePromises ;
9695 } ) . catch ( ( error ) => {
9796 req . log . error ( error ) ;
98- return Promise . reject ( invitePromises ) ;
97+ _ . forEach ( invite . emails , email => failed . push ( _ . assign ( { } , { email, message : error . statusText } ) ) ) ;
98+ return invitePromises ;
9999 } ) ;
100100 }
101101
102- return Promise . resolve ( invitePromises ) ;
102+ return invitePromises ;
103103} ;
104104
105105const sendInviteEmail = ( req , projectId , invite ) => {
@@ -157,6 +157,7 @@ module.exports = [
157157 validate ( addMemberValidations ) ,
158158 permissions ( 'projectMemberInvite.create' ) ,
159159 ( req , res , next ) => {
160+ let failed = [ ] ;
160161 const invite = req . body . param ;
161162
162163 if ( ! invite . userIds && ! invite . emails ) {
@@ -192,80 +193,80 @@ module.exports = [
192193 if ( invite . emails ) {
193194 // email invites can only be used for CUSTOMER role
194195 if ( invite . role !== PROJECT_MEMBER_ROLE . CUSTOMER ) { // eslint-disable-line no-lonely-if
195- const err = new Error ( `Emails can only be used for ${ PROJECT_MEMBER_ROLE . CUSTOMER } ` ) ;
196- err . status = 400 ;
197- return next ( err ) ;
196+ const message = `Emails can only be used for ${ PROJECT_MEMBER_ROLE . CUSTOMER } ` ;
197+ failed = _ . concat ( failed , _ . map ( invite . emails , email => _ . assign ( { } , { email , message } ) ) ) ;
198+ delete invite . emails ;
198199 }
199200 }
200-
201201 if ( promises . length === 0 ) {
202202 promises . push ( Promise . resolve ( ) ) ;
203203 }
204204 return Promise . all ( promises ) . then ( ( rolesList ) => {
205+ const updatedInvite = invite ;
205206 if ( ! ! invite . userIds && _ . includes ( PROJECT_MEMBER_MANAGER_ROLES , invite . role ) ) {
206207 req . log . debug ( 'Chekcing if userId is allowed as manager' ) ;
207208 const forbidUserList = [ ] ;
208209 _ . zip ( invite . userIds , rolesList ) . forEach ( ( data ) => {
209210 const [ userId , roles ] = data ;
210211 req . log . debug ( roles ) ;
211212
212- if ( ! util . hasIntersection ( MANAGER_ROLES , roles ) ) {
213+ if ( roles && ! util . hasIntersection ( MANAGER_ROLES , roles ) ) {
213214 forbidUserList . push ( userId ) ;
214215 }
215216 } ) ;
216217 if ( forbidUserList . length > 0 ) {
217- const err = new Error ( ` ${ forbidUserList . join ( ) } cannot be added with a Manager role to the project` ) ;
218- err . status = 403 ;
219- return next ( err ) ;
218+ const message = ' cannot be added with a Manager role to the project' ;
219+ failed = _ . concat ( failed , _ . map ( forbidUserList , id => _ . assign ( { } , { id , message } ) ) ) ;
220+ updatedInvite . userIds = _ . filter ( invite . userIds , userId => ! _ . includes ( forbidUserList , userId ) ) ;
220221 }
221222 }
222223 return models . ProjectMemberInvite . getPendingInvitesForProject ( projectId )
223224 . then ( ( invites ) => {
224225 const data = {
225226 projectId,
226- role : invite . role ,
227+ role : updatedInvite . role ,
227228 // invite directly if user is admin or copilot manager
228- status : ( invite . role !== PROJECT_MEMBER_ROLE . COPILOT ||
229+ status : ( updatedInvite . role !== PROJECT_MEMBER_ROLE . COPILOT ||
229230 util . hasRoles ( req , [ USER_ROLE . CONNECT_ADMIN , USER_ROLE . COPILOT_MANAGER ] ) )
230231 ? INVITE_STATUS . PENDING
231232 : INVITE_STATUS . REQUESTED ,
232233 createdBy : req . authUser . userId ,
233234 updatedBy : req . authUser . userId ,
234235 } ;
235236
236- return buildCreateInvitePromises ( req , invite , invites , data )
237- . then ( ( invitePromises ) => {
238- if ( invitePromises . length === 0 ) {
239- return [ ] ;
240- }
241-
242- req . log . debug ( 'Creating invites' ) ;
243- return models . sequelize . Promise . all ( invitePromises )
244- . then ( ( values ) => {
245- values . forEach ( ( v ) => {
246- req . app . emit ( EVENT . ROUTING_KEY . PROJECT_MEMBER_INVITE_CREATED , {
247- req,
248- userId : v . userId ,
249- email : v . email ,
250- status : v . status ,
251- role : v . role ,
252- } ) ;
253- req . app . services . pubsub . publish (
254- EVENT . ROUTING_KEY . PROJECT_MEMBER_INVITE_CREATED ,
255- v ,
256- { correlationId : req . id } ,
257- ) ;
258- // send email invite (async)
259- if ( v . email && ! v . userId && v . status === INVITE_STATUS . PENDING ) {
260- sendInviteEmail ( req , projectId , v ) ;
261- }
262- } ) ;
263- return values ;
264- } ) ; // models.sequelize.Promise.all
265- } ) ; // buildCreateInvitePromises
237+ req . log . debug ( 'Creating invites' ) ;
238+ return models . sequelize . Promise . all ( buildCreateInvitePromises ( req , updatedInvite , invites , data , failed ) )
239+ . then ( ( values ) => {
240+ values . forEach ( ( v ) => {
241+ req . app . emit ( EVENT . ROUTING_KEY . PROJECT_MEMBER_INVITE_CREATED , {
242+ req,
243+ userId : v . userId ,
244+ email : v . email ,
245+ status : v . status ,
246+ role : v . role ,
247+ } ) ;
248+ req . app . services . pubsub . publish (
249+ EVENT . ROUTING_KEY . PROJECT_MEMBER_INVITE_CREATED ,
250+ v ,
251+ { correlationId : req . id } ,
252+ ) ;
253+ // send email invite (async)
254+ if ( v . email && ! v . userId && v . status === INVITE_STATUS . PENDING ) {
255+ sendInviteEmail ( req , projectId , v ) ;
256+ }
257+ } ) ;
258+ return values ;
259+ } ) ; // models.sequelize.Promise.all
266260 } ) ; // models.ProjectMemberInvite.getPendingInvitesForProject
267261 } )
268- . then ( values => res . status ( 201 ) . json ( util . wrapResponse ( req . id , values , null , 201 ) ) )
262+ . then ( ( values ) => {
263+ const success = _ . assign ( { } , { success : values } ) ;
264+ if ( failed . length ) {
265+ res . status ( 403 ) . json ( util . wrapResponse ( req . id , _ . assign ( { } , success , { failed } ) , null , 403 ) ) ;
266+ } else {
267+ res . status ( 201 ) . json ( util . wrapResponse ( req . id , success , null , 201 ) ) ;
268+ }
269+ } )
269270 . catch ( err => next ( err ) ) ;
270271 } ,
271272] ;
0 commit comments