@@ -30,23 +30,59 @@ const copilotUserSchema = Joi.object().keys({
30
30
accessTokenExpiration : Joi . date ( ) . required ( ) ,
31
31
refreshToken : Joi . string ( ) . required ( ) ,
32
32
userProviderId : Joi . number ( ) . required ( ) ,
33
- topcoderUsername : Joi . string ( )
33
+ topcoderUsername : Joi . string ( ) ,
34
+ username : Joi . string ( ) . optional ( ) ,
35
+ type : Joi . string ( ) . optional ( ) ,
36
+ id : Joi . string ( ) . optional ( ) ,
37
+ role : Joi . string ( ) . optional ( )
34
38
} ) . required ( ) ;
35
39
40
+ /**
41
+ * Refresh the user access token if needed
42
+ * @param {Object } user the copilot
43
+ * @returns {Promise } the promise result of copilot with refreshed token
44
+ */
45
+ async function _refreshAccessToken ( user ) {
46
+ if ( user . accessTokenExpiration && new Date ( ) . getTime ( ) > user . accessTokenExpiration . getTime ( ) -
47
+ ( config . GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION * MS_PER_SECOND ) ) {
48
+ const refreshTokenResult = await request
49
+ . post ( `${ config . GITLAB_API_BASE_URL } /oauth/token` )
50
+ . query ( {
51
+ client_id : config . GITLAB_CLIENT_ID ,
52
+ client_secret : config . GITLAB_CLIENT_SECRET ,
53
+ refresh_token : user . refreshToken ,
54
+ grant_type : 'refresh_token' ,
55
+ redirect_uri : config . GITLAB_OWNER_USER_CALLBACK_URL
56
+ } )
57
+ . end ( ) ;
58
+ // save user token data
59
+ const expiresIn = refreshTokenResult . body . expires_in || config . GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION ;
60
+ const updates = {
61
+ accessToken : refreshTokenResult . body . access_token ,
62
+ accessTokenExpiration : new Date ( new Date ( ) . getTime ( ) + expiresIn * MS_PER_SECOND ) ,
63
+ refreshToken : refreshTokenResult . body . refresh_token
64
+ } ;
65
+ _ . assign ( user , updates ) ;
66
+ await dbHelper . update ( models . User , user . id , updates ) ;
67
+ }
68
+ return user ;
69
+ }
70
+
36
71
/**
37
72
* authenticate the gitlab using access token
38
- * @param {String } accessToken the access token of copilot
73
+ * @param {Object } user the user
39
74
* @private
40
75
*/
41
- async function _authenticate ( accessToken ) {
76
+ async function _getClient ( user ) {
42
77
try {
78
+ const refreshedUser = await _refreshAccessToken ( user ) ;
43
79
const gitlab = new Gitlab ( {
44
80
host : config . GITLAB_API_BASE_URL ,
45
- oauthToken : accessToken
81
+ oauthToken : refreshedUser . accessToken
46
82
} ) ;
47
83
return gitlab ;
48
84
} catch ( err ) {
49
- throw errors . handleGitLabError ( err , 'Failed to during authenticate to Github using access token of copilot.' ) ;
85
+ throw errors . handleGitLabError ( err , 'Failed to authenticate to Gitlab using access token of copilot.' , err ) ;
50
86
}
51
87
}
52
88
@@ -89,8 +125,7 @@ function _getIssueUrl(repoPath, issueId) {
89
125
async function createComment ( copilot , project , issueId , body ) {
90
126
const projectId = project . id ;
91
127
Joi . attempt ( { copilot, projectId, issueId, body} , createComment . schema ) ;
92
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
93
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
128
+ const gitlab = await _getClient ( copilot ) ;
94
129
try {
95
130
body = helper . prepareAutomatedComment ( body , copilot ) ;
96
131
await gitlab . IssueNotes . create ( projectId , issueId , body ) ;
@@ -117,8 +152,7 @@ createComment.schema = {
117
152
async function updateIssue ( copilot , project , issueId , title ) {
118
153
const projectId = project . id ;
119
154
Joi . attempt ( { copilot, projectId, issueId, title} , updateIssue . schema ) ;
120
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
121
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
155
+ const gitlab = await _getClient ( copilot ) ;
122
156
try {
123
157
await gitlab . Issues . edit ( projectId , issueId , { title} ) ;
124
158
} catch ( err ) {
@@ -144,8 +178,7 @@ updateIssue.schema = {
144
178
async function assignUser ( copilot , project , issueId , userId ) {
145
179
const projectId = project . id ;
146
180
Joi . attempt ( { copilot, projectId, issueId, userId} , assignUser . schema ) ;
147
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
148
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
181
+ const gitlab = await _getClient ( copilot ) ;
149
182
try {
150
183
const issue = await gitlab . Issues . show ( issueId , { projectId} ) ;
151
184
const oldAssignees = _ . without ( issue . assignees . map ( ( a ) => a . id ) , userId ) ;
@@ -176,8 +209,7 @@ assignUser.schema = {
176
209
async function removeAssign ( copilot , project , issueId , userId ) {
177
210
const projectId = project . id ;
178
211
Joi . attempt ( { copilot, projectId, issueId, userId} , removeAssign . schema ) ;
179
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
180
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
212
+ const gitlab = await _getClient ( copilot ) ;
181
213
await _removeAssignees ( gitlab , projectId , issueId , [ userId ] ) ;
182
214
logger . debug ( `Gitlab user ${ userId } is unassigned from issue number ${ issueId } ` ) ;
183
215
}
@@ -192,8 +224,7 @@ removeAssign.schema = assignUser.schema;
192
224
*/
193
225
async function getUsernameById ( copilot , userId ) {
194
226
Joi . attempt ( { copilot, userId} , getUsernameById . schema ) ;
195
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
196
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
227
+ const gitlab = await _getClient ( copilot ) ;
197
228
const user = await gitlab . Users . show ( userId ) ;
198
229
return user ? user . username : null ;
199
230
}
@@ -211,8 +242,7 @@ getUsernameById.schema = {
211
242
*/
212
243
async function getUserIdByLogin ( copilot , login ) {
213
244
Joi . attempt ( { copilot, login} , getUserIdByLogin . schema ) ;
214
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
215
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
245
+ const gitlab = await _getClient ( copilot ) ;
216
246
const user = await gitlab . Users . all ( { username : login } ) ;
217
247
return user . length ? user [ 0 ] . id : null ;
218
248
}
@@ -235,8 +265,7 @@ getUserIdByLogin.schema = {
235
265
async function markIssueAsPaid ( copilot , project , issueId , challengeUUID , existLabels , winner , createCopilotPayments ) { // eslint-disable-line max-params
236
266
const projectId = project . id ;
237
267
Joi . attempt ( { copilot, projectId, issueId, challengeUUID, existLabels, winner, createCopilotPayments} , markIssueAsPaid . schema ) ;
238
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
239
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
268
+ const gitlab = await _getClient ( copilot ) ;
240
269
const labels = _ ( existLabels ) . filter ( ( i ) => i !== config . FIX_ACCEPTED_ISSUE_LABEL )
241
270
. push ( config . FIX_ACCEPTED_ISSUE_LABEL , config . PAID_ISSUE_LABEL ) . value ( ) ;
242
271
try {
@@ -279,8 +308,7 @@ markIssueAsPaid.schema = {
279
308
async function changeState ( copilot , project , issueId , state ) {
280
309
const projectId = project . id ;
281
310
Joi . attempt ( { copilot, projectId, issueId, state} , changeState . schema ) ;
282
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
283
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
311
+ const gitlab = await _getClient ( copilot ) ;
284
312
try {
285
313
await gitlab . Issues . edit ( projectId , issueId , { stateEvent : state } ) ;
286
314
} catch ( err ) {
@@ -306,8 +334,7 @@ changeState.schema = {
306
334
async function addLabels ( copilot , project , issueId , labels ) {
307
335
const projectId = project . id ;
308
336
Joi . attempt ( { copilot, projectId, issueId, labels} , addLabels . schema ) ;
309
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
310
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
337
+ const gitlab = await _getClient ( copilot ) ;
311
338
try {
312
339
await gitlab . Issues . edit ( projectId , issueId , { labels : _ . join ( labels , ',' ) } ) ;
313
340
} catch ( err ) {
@@ -329,12 +356,17 @@ addLabels.schema = {
329
356
* @param {Object } repoURL The repository URL
330
357
*/
331
358
async function getRepository ( user , repoURL ) {
332
- const refreshedUser = await _refreshGitlabUserAccessToken ( user ) ;
333
- const gitlab = await _authenticate ( refreshedUser . accessToken ) ;
359
+ Joi . attempt ( { user, repoURL } , getRepository . schema ) ;
360
+ const gitlab = await _getClient ( user ) ;
334
361
const _repoURL = repoURL . replace ( `${ config . GITLAB_API_BASE_URL } /` , '' ) ;
335
362
return await gitlab . Projects . show ( _repoURL ) ;
336
363
}
337
364
365
+ getRepository . schema = {
366
+ user : Joi . object ( ) . required ( ) ,
367
+ repoURL : Joi . string ( ) . required ( )
368
+ } ;
369
+
338
370
/**
339
371
* Add a user to a gitlab repository
340
372
* @param {Object } copilot The copilot
@@ -343,18 +375,19 @@ async function getRepository(user, repoURL) {
343
375
* @param {import('@gitbeaker/rest').AccessLevel } accessLevel The user role
344
376
*/
345
377
async function addUserToRepository ( copilot , repository , user , accessLevel ) {
346
- const refreshedCopilot = await _refreshGitlabUserAccessToken ( copilot ) ;
347
- const gitlab = await _authenticate ( refreshedCopilot . accessToken ) ;
348
- const member = await new Promise ( ( resolve , reject ) => {
349
- gitlab . ProjectMembers . show ( repository . id , user . userProviderId )
350
- . then ( ( result ) => resolve ( result ) )
351
- . catch ( ( err ) => {
352
- // eslint-disable-next-line no-magic-numbers
353
- if ( _ . get ( err , 'cause.response.status' ) === 404 ) {
354
- return resolve ( null ) ;
355
- }
356
- return reject ( err ) ;
357
- } ) ;
378
+ Joi . attempt ( { copilot, repository, user, accessLevel} , addUserToRepository . schema ) ;
379
+ const gitlab = await _getClient ( copilot ) ;
380
+ const member = await new Promise ( async ( resolve , reject ) => {
381
+ try {
382
+ const res = await gitlab . ProjectMembers . show ( repository . id , user . userProviderId ) ;
383
+ resolve ( res ) ;
384
+ } catch ( err ) {
385
+ // eslint-disable-next-line no-magic-numbers
386
+ if ( _ . get ( err , 'cause.response.status' ) === 404 ) {
387
+ resolve ( null ) ;
388
+ }
389
+ reject ( err ) ;
390
+ }
358
391
} ) ;
359
392
if ( ! member ) {
360
393
await gitlab . ProjectMembers . add ( repository . id , user . userProviderId , accessLevel ) ;
@@ -365,47 +398,28 @@ async function addUserToRepository(copilot, repository, user, accessLevel) {
365
398
}
366
399
}
367
400
401
+ addUserToRepository . schema = {
402
+ copilot : copilotUserSchema ,
403
+ repository : Joi . object ( ) . required ( ) ,
404
+ user : Joi . object ( ) . required ( ) ,
405
+ accessLevel : Joi . number ( ) . required ( )
406
+ } ;
407
+
368
408
/**
369
409
* Fork a gitlab repository
370
410
* @param {Object } user The user
371
411
* @param {ProjectSchema } repository The repository
372
412
*/
373
413
async function forkRepository ( user , repository ) {
374
- const refreshedUser = await _refreshGitlabUserAccessToken ( user ) ;
375
- const gitlab = await _authenticate ( refreshedUser . accessToken ) ;
414
+ Joi . attempt ( { user, repository } , forkRepository . schema ) ;
415
+ const gitlab = await _getClient ( user ) ;
376
416
await gitlab . Projects . fork ( repository . id ) ;
377
417
}
378
418
379
- /**
380
- * Refresh the copilot access token if token is needed
381
- * @param {Object } copilot the copilot
382
- * @returns {Promise } the promise result of copilot with refreshed token
383
- */
384
- async function _refreshGitlabUserAccessToken ( copilot ) {
385
- if ( copilot . accessTokenExpiration && new Date ( ) . getTime ( ) > copilot . accessTokenExpiration . getTime ( ) -
386
- ( config . GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION * MS_PER_SECOND ) ) {
387
- const refreshTokenResult = await request
388
- . post ( `${ config . GITLAB_API_BASE_URL } /oauth/token` )
389
- . query ( {
390
- client_id : config . GITLAB_CLIENT_ID ,
391
- client_secret : config . GITLAB_CLIENT_SECRET ,
392
- refresh_token : copilot . refreshToken ,
393
- grant_type : 'refresh_token' ,
394
- redirect_uri : config . GITLAB_OWNER_USER_CALLBACK_URL
395
- } )
396
- . end ( ) ;
397
- // save user token data
398
- const expiresIn = refreshTokenResult . body . expires_in || config . GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION ;
399
- const updates = {
400
- accessToken : refreshTokenResult . body . access_token ,
401
- accessTokenExpiration : new Date ( new Date ( ) . getTime ( ) + expiresIn * MS_PER_SECOND ) ,
402
- refreshToken : refreshTokenResult . body . refresh_token
403
- } ;
404
- copilot = _ . assign ( copilot , updates ) ;
405
- return await dbHelper . update ( models . User , copilot . id , updates ) ;
406
- }
407
- return copilot ;
408
- }
419
+ forkRepository . schema = {
420
+ user : Joi . object ( ) . required ( ) ,
421
+ repository : Joi . object ( ) . required ( )
422
+ } ;
409
423
410
424
module . exports = {
411
425
createComment,
0 commit comments