3
3
*
4
4
* The APIs to register a challenge (studio category or software category) for the current logged-in user.
5
5
*
6
- * @version 1.1
7
- * @author ecnu_haozi, xjtufreeman
6
+ * @version 1.3
7
+ * @author ecnu_haozi, xjtufreeman, bugbuka
8
8
*
9
9
* changes in 1.1:
10
10
* Combine Challenge Registration API(BUGR-11058)
11
+ *
12
+ * changes in 1.2:
13
+ * Integrate the forums operation(Module Assembly - Integrating Forums Wrapper with Challenge Registration API)
14
+ *
15
+ * changes in 1.3:
16
+ * move common function getForumWrapper, aduitResourceAddition to challengeHelper.js
11
17
*/
12
18
"use strict" ;
13
19
14
20
var async = require ( 'async' ) ;
15
21
var _ = require ( 'underscore' ) ;
16
22
var moment = require ( 'moment' ) ;
23
+ var ForumWrapper = require ( "forum-connector" ) . ForumWrapper ;
17
24
var NotFoundError = require ( '../errors/NotFoundError' ) ;
18
25
var ForbiddenError = require ( '../errors/ForbiddenError' ) ;
19
26
27
+ /**
28
+ * The forum wrapper instance
29
+ */
30
+ var forumWrapper = null ;
31
+
20
32
//constants
21
33
var DESIGN_PROJECT_TYPE = 1 ,
22
34
DEVELOPMENT_PROJECT_TYPE = 2 ,
@@ -125,7 +137,7 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
125
137
modifyUser : '"' + userId + '"'
126
138
} ,
127
139
dbConnectionMap ,
128
- function ( err , result ) {
140
+ function ( err ) {
129
141
if ( err ) {
130
142
next ( err ) ;
131
143
} else {
@@ -134,28 +146,6 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
134
146
} ) ;
135
147
} ;
136
148
137
- /**
138
- * Audit the challenge registration on table 'tcs_catalog.project_user_audit'.
139
- *
140
- * @param {Object } api The api object that is used to access the infrastructure.
141
- * @param {Number } resourceId The resource id.
142
- * @param {Number } userId The current logged-in user's id.
143
- * @param {Number } challengeId The id of the challenge to register.
144
- * @param {Object } dbConnectionMap The database connection map for the current request.
145
- * @param {Function<err, data> } next The callback to be called after this function is done.
146
- */
147
- var aduitResourceAddition = function ( api , userId , challengeId , dbConnectionMap , next ) {
148
- api . dataAccess . executeQuery ( "audit_challenge_registration" , {
149
- projectId : challengeId ,
150
- resourceUserId : userId ,
151
- resourceRoleId : SUBMITTER_RESOURCE_ROLE_ID ,
152
- auditActionTypeId : PROJECT_USER_AUDIT_CREATE_TYPE ,
153
- actionUserId : userId
154
- } ,
155
- dbConnectionMap ,
156
- next ) ;
157
- } ;
158
-
159
149
/**
160
150
* Check if the rating suit for software category contests.
161
151
* The code logic is duplicated from server-side java code.
@@ -212,8 +202,9 @@ var prepareProjectResult = function (api, rating, userId, challengeId, phaseId,
212
202
*
213
203
* @param {Object } api The api object that is used to access the infrastructure.
214
204
* @param {Number } resourceId The resource id.
215
- * @param {Number } userId The current logged-in user's id.
216
- * @param {Number } challengeId The id of the challenge to register.
205
+ * @param {Number } propertyId The property id.
206
+ * @param {String } propertyValue The property value.
207
+ * @param {Number } userId The user id.
217
208
* @param {Object } dbConnectionMap The database connection map for the current request.
218
209
* @param {Function<err, data> } next The callback to be called after this function is done..
219
210
*/
@@ -254,7 +245,7 @@ var projectTrack = function (api, userId, challengeId, componentInfo, dbConnecti
254
245
function ( resourceId , callback ) {
255
246
async . parallel ( [
256
247
function ( cb ) {
257
- aduitResourceAddition ( api , userId , challengeId , dbConnectionMap , cb ) ;
248
+ api . challengeHelper . aduitResourceAddition ( api , userId , challengeId , SUBMITTER_RESOURCE_ROLE_ID , PROJECT_USER_AUDIT_CREATE_TYPE , dbConnectionMap , cb ) ;
258
249
} ,
259
250
function ( cb ) {
260
251
prepareProjectResult (
@@ -346,12 +337,13 @@ var projectTrack = function (api, userId, challengeId, componentInfo, dbConnecti
346
337
* Send email to notify the user registration succeeded.
347
338
*
348
339
* @param {Object } api The api object that is used to access the infrastructure.
349
- * @param {Number } userId The current logged-in user's id.
350
340
* @param {Object } componentInfo The component info object generated from method <code>registerComponentInquiry</code>.
341
+ * @param {Number } userId The current logged-in user's id.
342
+ * @param {Number } activeForumCategoryId The active forum category id.
351
343
* @param {Object } dbConnectionMap The database connection map for the current request.
352
344
* @param {Function<err, data> } next The callback to be called after this function is done.
353
345
*/
354
- var sendNotificationEmail = function ( api , componentInfo , userId , dbConnectionMap , next ) {
346
+ var sendNotificationEmail = function ( api , componentInfo , userId , activeForumCategoryId , dbConnectionMap , next ) {
355
347
async . waterfall ( [
356
348
function ( cb ) {
357
349
api . dataAccess . executeQuery ( "get_user_email_and_handle" , {
@@ -363,7 +355,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
363
355
cb ( new NotFoundError ( "user's email and handle not found" ) ) ;
364
356
return ;
365
357
}
366
- var user , projectName , documentationDetails , submitURL , activeForumCategoryId , forumURL , umlToolInfo ;
358
+ var user , projectName , documentationDetails , submitURL , forumURL , umlToolInfo ;
367
359
368
360
user = result [ 0 ] ;
369
361
projectName = componentInfo . project_name + api . helper . getPhaseName ( componentInfo . phase_id ) + ' Contest' ;
@@ -378,7 +370,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
378
370
379
371
if ( componentInfo . phase_id === 112 || componentInfo . phase_id === 113 ) {
380
372
umlToolInfo = "You can read more about our UML tool and download it at\n" +
381
- "http://www.topcoder.com/tc?module=Static&d1=dev&d2=umltool&d3=description\n\n" ;
373
+ "http://www.topcoder.com/tc?module=Static&d1=dev&d2=umltool&d3=description\n\n" ;
382
374
}
383
375
384
376
//NOTE : forumURL is out of scope, here use a mock value instead. See http://apps.topcoder.com/forums/?module=Thread&threadID=811696&start=0
@@ -403,6 +395,80 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
403
395
] , next ) ;
404
396
} ;
405
397
398
+ /*
399
+ * Get the active forum category id of the specified challenge.
400
+ *
401
+ * @param {Object } api The api object that is used to access the infrastructure.
402
+ * @param {Object } componentInfo The component info object generated from method <code>registerComponentInquiry</code>.
403
+ * @param {Number } challengeId The challenge id.
404
+ * @param {Object } dbConnectionMap The database connection map for the current request.
405
+ * @param {Function<err, data> } next The callback to be called after this function is done.
406
+ */
407
+ var getActiveForumCategoryId = function ( api , componentInfo , challengeId , dbConnectionMap , next ) {
408
+ async . waterfall ( [
409
+ function ( cb ) {
410
+ if ( componentInfo . component_id === null ) {
411
+ api . log ( 'Could not find component for challenge ' + challengeId , 'error' ) ;
412
+ next ( new Error ( 'Could not find component for challenge ' + challengeId ) ) ;
413
+ return ;
414
+ }
415
+ api . dataAccess . executeQuery ( "get_active_forum_category" , { componentId : componentInfo . component_id } , dbConnectionMap , cb ) ;
416
+ } ,
417
+ function ( result , cb ) {
418
+ if ( result . length === 0 ) {
419
+ api . log ( 'Could not find forum for challenge ' + challengeId , 'debug' ) ;
420
+ cb ( null , null ) ;
421
+ return ;
422
+ }
423
+
424
+ cb ( null , result [ 0 ] . jive_category_id ) ;
425
+ }
426
+ ] , next ) ;
427
+ } ;
428
+
429
+ /*
430
+ * Grant user forum access
431
+ *
432
+ * @param {Object } api The api object that is used to access the infrastructure.
433
+ * @param {Number } userId The current logged-in user's id.
434
+ * @param {Number } challengeId The challenge id.
435
+ * @param {Function<err, data> } next The callback to be called after this function is done.
436
+ */
437
+ var grantForumAccess = function ( api , userId , activeForumCategoryId , next ) {
438
+
439
+ if ( api . config . general . grantForumAccess !== true ) {
440
+ next ( ) ;
441
+ return ;
442
+ }
443
+
444
+ if ( activeForumCategoryId === null ) {
445
+ api . log ( 'Could not find forum category ' + activeForumCategoryId , 'error' ) ;
446
+ next ( new Error ( 'Could not find forum category ' + activeForumCategoryId ) ) ;
447
+ return ;
448
+ }
449
+
450
+ api . log ( 'start to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access.' ) ;
451
+ async . waterfall ( [
452
+ function ( cb ) {
453
+ api . challengeHelper . getForumWrapper ( api , cb ) ;
454
+ } , function ( forumWrapper , cb ) {
455
+ forumWrapper . assignRole ( userId , "Software_Users_" + activeForumCategoryId , function ( err ) {
456
+ if ( err ) {
457
+ api . log ( 'Failed to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access:' + err + " " + ( err . stack || '' ) , 'error' ) ;
458
+ cb ( new Error ( 'Failed to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access' ) ) ;
459
+ }
460
+ cb ( ) ;
461
+ } ) ;
462
+ }
463
+ ] , function ( err ) {
464
+ if ( err ) {
465
+ next ( err ) ;
466
+ return ;
467
+ }
468
+ next ( ) ;
469
+ } ) ;
470
+ } ;
471
+
406
472
/**
407
473
* Register a development (software) challenge for the current logged-in user.
408
474
*
@@ -430,10 +496,24 @@ var registerSoftwareChallenge = function (api, userId, challengeId, dbConnection
430
496
cb ( err ) ;
431
497
} ) ;
432
498
} ,
499
+
433
500
function ( cb ) {
434
- //Send notification mail
435
- sendNotificationEmail ( api , componentInfo , userId , dbConnectionMap , cb ) ;
501
+ getActiveForumCategoryId ( api , componentInfo , challengeId , dbConnectionMap , cb ) ;
502
+ } ,
503
+
504
+ function ( activeForumCategoryId , cb ) {
505
+ async . waterfall ( [
506
+ function ( cbx ) {
507
+ // Grant forum access
508
+ grantForumAccess ( api , userId , activeForumCategoryId , cbx ) ;
509
+ } ,
510
+ function ( cbx ) {
511
+ // Send notification mail
512
+ sendNotificationEmail ( api , componentInfo , userId , activeForumCategoryId , dbConnectionMap , cbx ) ;
513
+ }
514
+ ] , cb ) ;
436
515
}
516
+
437
517
] , next ) ;
438
518
} ;
439
519
@@ -484,7 +564,7 @@ var persistStudioChallengeResouce = function (api, userId, challengeId, dbConnec
484
564
} ,
485
565
function ( cb ) {
486
566
//Registration time
487
- persistResourceInfo ( api , resourceId , 6 , moment ( ) . format ( "MM.dd.yyyy hh:mm aa " ) , userId , dbConnectionMap , cb ) ;
567
+ persistResourceInfo ( api , resourceId , 6 , moment ( ) . format ( "MM.DD.YYYY hh:mm A " ) , userId , dbConnectionMap , cb ) ;
488
568
} ,
489
569
function ( cb ) {
490
570
//payments.
@@ -528,6 +608,8 @@ var timelineNotification = function (api, userId, challengeId, dbConnectionMap,
528
608
} ,
529
609
dbConnectionMap ,
530
610
cb ) ;
611
+ } else {
612
+ cb ( null ) ;
531
613
}
532
614
}
533
615
] , next ) ;
@@ -566,23 +648,23 @@ var registerSoftwareChallengeAction = function (api, connection, next) {
566
648
if ( connection . dbConnectionMap ) {
567
649
api . log ( "Execute registerSoftwareChallengeAction#run" , 'debug' ) ;
568
650
569
- var challengeId = Number ( connection . params . challengeId ) ;
570
- var sqlParams = {
571
- challengeId : challengeId ,
572
- user_id : connection . caller . userId
573
- } ;
574
- var execQuery = function ( name ) {
575
- return function ( cbx ) {
576
- api . dataAccess . executeQuery ( name , sqlParams , connection . dbConnectionMap , cbx ) ;
651
+ var challengeId = Number ( connection . params . challengeId ) ,
652
+ sqlParams = {
653
+ challengeId : challengeId ,
654
+ user_id : connection . caller . userId
655
+ } ,
656
+ execQuery = function ( name ) {
657
+ return function ( cbx ) {
658
+ api . dataAccess . executeQuery ( name , sqlParams , connection . dbConnectionMap , cbx ) ;
659
+ } ;
577
660
} ;
578
- } ;
579
661
async . waterfall ( [
580
- function ( cb ) {
662
+ function ( cb ) {
581
663
async . parallel ( {
582
664
isCopilotPosting : execQuery ( 'check_challenge_is_copilot_posting' ) ,
583
665
isCopilot : execQuery ( 'check_is_copilot' )
584
666
} , cb ) ;
585
- } , function ( res , cb ) {
667
+ } , function ( res , cb ) {
586
668
if ( res . isCopilotPosting . length > 0 && res . isCopilotPosting [ 0 ] . challenge_is_copilot ) {
587
669
if ( res . isCopilot . length === 0 || ! res . isCopilot [ 0 ] . user_is_copilot ) {
588
670
cb ( new ForbiddenError ( 'You should be a copilot before register a copilot posting.' ) ) ;
0 commit comments