@@ -140,37 +140,98 @@ const inviteUser = async (
140
140
res : express . Response ,
141
141
next : express . NextFunction ,
142
142
) => {
143
- const { email } = req . body ;
143
+ const { emails } = req . body ;
144
+ if ( ! emails ) {
145
+ next ( ApiError . missingFields ( [ 'email' ] ) ) ;
146
+ return ;
147
+ }
148
+ const emailList = emails . replaceAll ( ' ' , '' ) . split ( ',' ) ;
144
149
const emailRegex =
145
150
/ ^ [ a - z A - Z 0 - 9 . ! # $ % & ' * + / = ? ^ _ ` { | } ~ - ] + @ [ a - z A - Z 0 - 9 ] (?: [ a - z A - Z 0 - 9 - ] { 0 , 61 } [ a - z A - Z 0 - 9 ] ) ? (?: \. [ a - z A - Z 0 - 9 ] (?: [ a - z A - Z 0 - 9 - ] { 0 , 61 } [ a - z A - Z 0 - 9 ] ) ? ) * $ / g;
146
- if ( ! email . match ( emailRegex ) ) {
147
- next ( ApiError . badRequest ( 'Invalid email' ) ) ;
151
+
152
+ function validateEmail ( email : string ) {
153
+ if ( ! email . match ( emailRegex ) ) {
154
+ next ( ApiError . badRequest ( `Invalid email: ${ email } ` ) ) ;
155
+ }
148
156
}
149
- const lowercaseEmail = email . toLowerCase ( ) ;
150
- const existingUser : IUser | null = await getUserByEmail ( lowercaseEmail ) ;
151
- if ( existingUser ) {
152
- next (
153
- ApiError . badRequest (
154
- `An account with email ${ lowercaseEmail } already exists.` ,
155
- ) ,
156
- ) ;
157
- return ;
157
+
158
+ function combineEmailToken ( email : string , invite : IInvite | null ) {
159
+ const verificationToken = crypto . randomBytes ( 32 ) . toString ( 'hex' ) ;
160
+ return [ email , invite , verificationToken ] ;
161
+ }
162
+
163
+ async function makeInvite ( combinedList : any [ ] ) {
164
+ try {
165
+ const email = combinedList [ 0 ] ;
166
+ const existingInvite = combinedList [ 1 ] ;
167
+ const verificationToken = combinedList [ 2 ] ;
168
+ if ( existingInvite ) {
169
+ await updateInvite ( existingInvite , verificationToken ) ;
170
+ } else {
171
+ await createInvite ( email , verificationToken ) ;
172
+ }
173
+ } catch ( err : any ) {
174
+ next ( ApiError . internal ( `Error creating invite: ${ err . message } ` ) ) ;
175
+ }
158
176
}
159
177
160
- const existingInvite : IInvite | null = await getInviteByEmail ( lowercaseEmail ) ;
178
+ function sendInvite ( combinedList : any [ ] ) {
179
+ try {
180
+ const email = combinedList [ 0 ] ;
181
+ const verificationToken = combinedList [ 2 ] ;
182
+
183
+ emailInviteLink ( email , verificationToken ) ;
184
+ return ;
185
+ } catch ( err : any ) {
186
+ next ( ApiError . internal ( `Error sending invite: ${ err . message } ` ) ) ;
187
+ }
188
+ }
161
189
162
190
try {
163
- const verificationToken = crypto . randomBytes ( 32 ) . toString ( 'hex' ) ;
164
- if ( existingInvite ) {
165
- await updateInvite ( existingInvite , verificationToken ) ;
166
- } else {
167
- await createInvite ( lowercaseEmail , verificationToken ) ;
191
+ if ( emailList . length === 0 ) {
192
+ next ( ApiError . missingFields ( [ 'email' ] ) ) ;
193
+ return ;
168
194
}
195
+ emailList . forEach ( validateEmail ) ;
196
+ const lowercaseEmailList : string [ ] = emailList . map ( ( email : string ) =>
197
+ email . toLowerCase ( ) ,
198
+ ) ;
199
+
200
+ const userPromises = lowercaseEmailList . map ( getUserByEmail ) ;
201
+ const existingUserList = await Promise . all ( userPromises ) ;
202
+
203
+ const invitePromises = lowercaseEmailList . map ( getInviteByEmail ) ;
204
+ const existingInviteList = await Promise . all ( invitePromises ) ;
205
+
206
+ const existingUserEmails = existingUserList . map ( ( user ) =>
207
+ user ? user . email : '' ,
208
+ ) ;
209
+ const existingInviteEmails = existingInviteList . map ( ( invite ) =>
210
+ invite ? invite . email : '' ,
211
+ ) ;
212
+
213
+ const emailInviteList = lowercaseEmailList . filter ( ( email ) => {
214
+ if ( existingUserEmails . includes ( email ) ) {
215
+ throw ApiError . badRequest ( `User with email ${ email } already exists` ) ;
216
+ }
217
+ return ! existingUserEmails . includes ( email ) ;
218
+ } ) ;
219
+
220
+ const combinedList = emailInviteList . map ( ( email ) => {
221
+ const existingInvite =
222
+ existingInviteList [ existingInviteEmails . indexOf ( email ) ] ;
223
+ return combineEmailToken ( email , existingInvite ) ;
224
+ } ) ;
225
+
226
+ const makeInvitePromises = combinedList . map ( makeInvite ) ;
227
+ await Promise . all ( makeInvitePromises ) ;
228
+
229
+ const sendInvitePromises = combinedList . map ( sendInvite ) ;
230
+ await Promise . all ( sendInvitePromises ) ;
169
231
170
- await emailInviteLink ( lowercaseEmail , verificationToken ) ;
171
232
res . sendStatus ( StatusCode . CREATED ) ;
172
- } catch ( err ) {
173
- next ( ApiError . internal ( ' Unable to invite user.' ) ) ;
233
+ } catch ( err : any ) {
234
+ next ( ApiError . internal ( ` Unable to invite user: ${ err . message } ` ) ) ;
174
235
}
175
236
} ;
176
237
0 commit comments