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.2
7
+ * @author ecnu_haozi, xjtufreeman, TCSASSEMBLER
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)
11
14
*/
12
15
"use strict" ;
13
16
14
17
var async = require ( 'async' ) ;
15
18
var _ = require ( 'underscore' ) ;
16
19
var moment = require ( 'moment' ) ;
20
+ var ForumWrapper = require ( "forum-connector" ) . ForumWrapper ;
17
21
var NotFoundError = require ( '../errors/NotFoundError' ) ;
18
22
var ForbiddenError = require ( '../errors/ForbiddenError' ) ;
19
23
24
+ /**
25
+ * The forum wrapper instance
26
+ */
27
+ var forumWrapper = null ;
28
+
29
+ /**
30
+ * Get forum wrapper. It is initialized only once.
31
+ * @param {Object } api The api object that is used to access the infrastructure.
32
+ * @param {Function<err, forumWrapper> } callback the callback function
33
+ */
34
+ var getForumWrapper = function ( api , callback ) {
35
+ if ( forumWrapper ) {
36
+ callback ( null , forumWrapper ) ;
37
+ } else {
38
+ try {
39
+ forumWrapper = new ForumWrapper ( api . config . general . devForumJNDI ) ;
40
+ callback ( null , forumWrapper ) ;
41
+ } catch ( ex ) {
42
+ api . log ( 'Failed to connect to forum: ' + ex + " " + ( ex . stack || '' ) , 'error' ) ;
43
+ callback ( new Error ( 'Failed to connect to forum' ) ) ;
44
+ }
45
+ }
46
+ } ;
47
+
20
48
//constants
21
49
var DESIGN_PROJECT_TYPE = 1 ,
22
50
DEVELOPMENT_PROJECT_TYPE = 2 ,
@@ -120,11 +148,12 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
120
148
api . dataAccess . executeQuery ( "insert_resource" , {
121
149
resourceId : resourceId ,
122
150
projectId : challengeId ,
151
+ userId : userId ,
123
152
createUser : '"' + userId + '"' ,
124
153
modifyUser : '"' + userId + '"'
125
154
} ,
126
155
dbConnectionMap ,
127
- function ( err , result ) {
156
+ function ( err ) {
128
157
if ( err ) {
129
158
next ( err ) ;
130
159
} else {
@@ -137,7 +166,6 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
137
166
* Audit the challenge registration on table 'tcs_catalog.project_user_audit'.
138
167
*
139
168
* @param {Object } api The api object that is used to access the infrastructure.
140
- * @param {Number } resourceId The resource id.
141
169
* @param {Number } userId The current logged-in user's id.
142
170
* @param {Number } challengeId The id of the challenge to register.
143
171
* @param {Object } dbConnectionMap The database connection map for the current request.
@@ -211,8 +239,9 @@ var prepareProjectResult = function (api, rating, userId, challengeId, phaseId,
211
239
*
212
240
* @param {Object } api The api object that is used to access the infrastructure.
213
241
* @param {Number } resourceId The resource id.
214
- * @param {Number } userId The current logged-in user's id.
215
- * @param {Number } challengeId The id of the challenge to register.
242
+ * @param {Number } propertyId The property id.
243
+ * @param {String } propertyValue The property value.
244
+ * @param {Number } userId The user id.
216
245
* @param {Object } dbConnectionMap The database connection map for the current request.
217
246
* @param {Function<err, data> } next The callback to be called after this function is done..
218
247
*/
@@ -345,12 +374,13 @@ var projectTrack = function (api, userId, challengeId, componentInfo, dbConnecti
345
374
* Send email to notify the user registration succeeded.
346
375
*
347
376
* @param {Object } api The api object that is used to access the infrastructure.
348
- * @param {Number } userId The current logged-in user's id.
349
377
* @param {Object } componentInfo The component info object generated from method <code>registerComponentInquiry</code>.
378
+ * @param {Number } userId The current logged-in user's id.
379
+ * @param {Number } activeForumCategoryId The active forum category id.
350
380
* @param {Object } dbConnectionMap The database connection map for the current request.
351
381
* @param {Function<err, data> } next The callback to be called after this function is done.
352
382
*/
353
- var sendNotificationEmail = function ( api , componentInfo , userId , dbConnectionMap , next ) {
383
+ var sendNotificationEmail = function ( api , componentInfo , userId , activeForumCategoryId , dbConnectionMap , next ) {
354
384
async . waterfall ( [
355
385
function ( cb ) {
356
386
api . dataAccess . executeQuery ( "get_user_email_and_handle" , {
@@ -362,7 +392,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
362
392
cb ( new NotFoundError ( "user's email and handle not found" ) ) ;
363
393
return ;
364
394
}
365
- var user , projectName , documentationDetails , submitURL , activeForumCategoryId , forumURL , umlToolInfo ;
395
+ var user , projectName , documentationDetails , submitURL , forumURL , umlToolInfo ;
366
396
367
397
user = result [ 0 ] ;
368
398
projectName = componentInfo . project_name + api . helper . getPhaseName ( componentInfo . phase_id ) + ' Contest' ;
@@ -377,7 +407,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
377
407
378
408
if ( componentInfo . phase_id === 112 || componentInfo . phase_id === 113 ) {
379
409
umlToolInfo = "You can read more about our UML tool and download it at\n" +
380
- "http://www.topcoder.com/tc?module=Static&d1=dev&d2=umltool&d3=description\n\n" ;
410
+ "http://www.topcoder.com/tc?module=Static&d1=dev&d2=umltool&d3=description\n\n" ;
381
411
}
382
412
383
413
//NOTE : forumURL is out of scope, here use a mock value instead. See http://apps.topcoder.com/forums/?module=Thread&threadID=811696&start=0
@@ -402,6 +432,80 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
402
432
] , next ) ;
403
433
} ;
404
434
435
+ /*
436
+ * Get the active forum category id of the specified challenge.
437
+ *
438
+ * @param {Object } api The api object that is used to access the infrastructure.
439
+ * @param {Object } componentInfo The component info object generated from method <code>registerComponentInquiry</code>.
440
+ * @param {Number } challengeId The challenge id.
441
+ * @param {Object } dbConnectionMap The database connection map for the current request.
442
+ * @param {Function<err, data> } next The callback to be called after this function is done.
443
+ */
444
+ var getActiveForumCategoryId = function ( api , componentInfo , challengeId , dbConnectionMap , next ) {
445
+ async . waterfall ( [
446
+ function ( cb ) {
447
+ if ( componentInfo . component_id === null ) {
448
+ api . log ( 'Could not find component for challenge ' + challengeId , 'error' ) ;
449
+ next ( new Error ( 'Could not find component for challenge ' + challengeId ) ) ;
450
+ return ;
451
+ }
452
+ api . dataAccess . executeQuery ( "get_active_forum_category" , { componentId : componentInfo . component_id } , dbConnectionMap , cb ) ;
453
+ } ,
454
+ function ( result , cb ) {
455
+ if ( result . length === 0 ) {
456
+ api . log ( 'Could not find forum for challenge ' + challengeId , 'debug' ) ;
457
+ cb ( null , null ) ;
458
+ return ;
459
+ }
460
+
461
+ cb ( null , result [ 0 ] . jive_category_id ) ;
462
+ }
463
+ ] , next ) ;
464
+ } ;
465
+
466
+ /*
467
+ * Grant user forum access
468
+ *
469
+ * @param {Object } api The api object that is used to access the infrastructure.
470
+ * @param {Number } userId The current logged-in user's id.
471
+ * @param {Number } challengeId The challenge id.
472
+ * @param {Function<err, data> } next The callback to be called after this function is done.
473
+ */
474
+ var grantForumAccess = function ( api , userId , activeForumCategoryId , next ) {
475
+
476
+ if ( api . config . general . grantForumAccess !== true ) {
477
+ next ( ) ;
478
+ return ;
479
+ }
480
+
481
+ if ( activeForumCategoryId === null ) {
482
+ api . log ( 'Could not find forum category ' + activeForumCategoryId , 'error' ) ;
483
+ next ( new Error ( 'Could not find forum category ' + activeForumCategoryId ) ) ;
484
+ return ;
485
+ }
486
+
487
+ api . log ( 'start to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access.' ) ;
488
+ async . waterfall ( [
489
+ function ( cb ) {
490
+ getForumWrapper ( api , cb ) ;
491
+ } , function ( forumWrapper , cb ) {
492
+ forumWrapper . assignRole ( userId , "Software_Users_" + activeForumCategoryId , function ( err ) {
493
+ if ( err ) {
494
+ api . log ( 'Failed to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access:' + err + " " + ( err . stack || '' ) , 'error' ) ;
495
+ cb ( new Error ( 'Failed to grant user ' + userId + ' forum category ' + activeForumCategoryId + ' access' ) ) ;
496
+ }
497
+ cb ( ) ;
498
+ } ) ;
499
+ }
500
+ ] , function ( err ) {
501
+ if ( err ) {
502
+ next ( err ) ;
503
+ return ;
504
+ }
505
+ next ( ) ;
506
+ } ) ;
507
+ } ;
508
+
405
509
/**
406
510
* Register a development (software) challenge for the current logged-in user.
407
511
*
@@ -429,10 +533,24 @@ var registerSoftwareChallenge = function (api, userId, challengeId, dbConnection
429
533
cb ( err ) ;
430
534
} ) ;
431
535
} ,
536
+
432
537
function ( cb ) {
433
- //Send notification mail
434
- sendNotificationEmail ( api , componentInfo , userId , dbConnectionMap , cb ) ;
538
+ getActiveForumCategoryId ( api , componentInfo , challengeId , dbConnectionMap , cb ) ;
539
+ } ,
540
+
541
+ function ( activeForumCategoryId , cb ) {
542
+ async . waterfall ( [
543
+ function ( cbx ) {
544
+ // Grant forum access
545
+ grantForumAccess ( api , userId , activeForumCategoryId , cbx ) ;
546
+ } ,
547
+ function ( cbx ) {
548
+ // Send notification mail
549
+ sendNotificationEmail ( api , componentInfo , userId , activeForumCategoryId , dbConnectionMap , cbx ) ;
550
+ }
551
+ ] , cb ) ;
435
552
}
553
+
436
554
] , next ) ;
437
555
} ;
438
556
@@ -483,7 +601,7 @@ var persistStudioChallengeResouce = function (api, userId, challengeId, dbConnec
483
601
} ,
484
602
function ( cb ) {
485
603
//Registration time
486
- persistResourceInfo ( api , resourceId , 6 , moment ( ) . format ( "MM.dd.yyyy hh:mm aa " ) , userId , dbConnectionMap , cb ) ;
604
+ persistResourceInfo ( api , resourceId , 6 , moment ( ) . format ( "MM.DD.YYYY hh:mm A " ) , userId , dbConnectionMap , cb ) ;
487
605
} ,
488
606
function ( cb ) {
489
607
//payments.
@@ -527,6 +645,8 @@ var timelineNotification = function (api, userId, challengeId, dbConnectionMap,
527
645
} ,
528
646
dbConnectionMap ,
529
647
cb ) ;
648
+ } else {
649
+ cb ( null ) ;
530
650
}
531
651
}
532
652
] , next ) ;
@@ -565,10 +685,30 @@ var registerSoftwareChallengeAction = function (api, connection, next) {
565
685
if ( connection . dbConnectionMap ) {
566
686
api . log ( "Execute registerSoftwareChallengeAction#run" , 'debug' ) ;
567
687
568
- var challengeId = Number ( connection . params . challengeId ) ;
688
+ var challengeId = Number ( connection . params . challengeId ) ,
689
+ sqlParams = {
690
+ challengeId : challengeId ,
691
+ user_id : connection . caller . userId
692
+ } ,
693
+ execQuery = function ( name ) {
694
+ return function ( cbx ) {
695
+ api . dataAccess . executeQuery ( name , sqlParams , connection . dbConnectionMap , cbx ) ;
696
+ } ;
697
+ } ;
569
698
async . waterfall ( [
570
-
571
699
function ( cb ) {
700
+ async . parallel ( {
701
+ isCopilotPosting : execQuery ( 'check_challenge_is_copilot_posting' ) ,
702
+ isCopilot : execQuery ( 'check_is_copilot' )
703
+ } , cb ) ;
704
+ } , function ( res , cb ) {
705
+ if ( res . isCopilotPosting . length > 0 && res . isCopilotPosting [ 0 ] . challenge_is_copilot ) {
706
+ if ( res . isCopilot . length === 0 || ! res . isCopilot [ 0 ] . user_is_copilot ) {
707
+ cb ( new ForbiddenError ( 'You should be a copilot before register a copilot posting.' ) ) ;
708
+ }
709
+ }
710
+ cb ( null ) ;
711
+ } , function ( cb ) {
572
712
api . challengeHelper . getChallengeTerms (
573
713
connection ,
574
714
challengeId ,
0 commit comments