Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit 24a03f6

Browse files
committed
Merge
2 parents 2cd2a41 + a52843f commit 24a03f6

File tree

169 files changed

+9104
-1141
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

169 files changed

+9104
-1141
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ pids
44
deploy/prod.sh
55
node_modules
66
test/tmp/submissions/*.zip
7+
test/tmp/design_submissions/*.zip
8+
test/tmp/design_tmp_submissions/*.zip
9+

actions/challengeRegistration.js

Lines changed: 155 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,48 @@
33
*
44
* The APIs to register a challenge (studio category or software category) for the current logged-in user.
55
*
6-
* @version 1.1
7-
* @author ecnu_haozi, xjtufreeman
6+
* @version 1.2
7+
* @author ecnu_haozi, xjtufreeman, TCSASSEMBLER
88
*
99
* changes in 1.1:
1010
* 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)
1114
*/
1215
"use strict";
1316

1417
var async = require('async');
1518
var _ = require('underscore');
1619
var moment = require('moment');
20+
var ForumWrapper = require("forum-connector").ForumWrapper;
1721
var NotFoundError = require('../errors/NotFoundError');
1822
var ForbiddenError = require('../errors/ForbiddenError');
1923

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+
2048
//constants
2149
var DESIGN_PROJECT_TYPE = 1,
2250
DEVELOPMENT_PROJECT_TYPE = 2,
@@ -120,11 +148,12 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
120148
api.dataAccess.executeQuery("insert_resource", {
121149
resourceId: resourceId,
122150
projectId: challengeId,
151+
userId: userId,
123152
createUser: '"' + userId + '"',
124153
modifyUser: '"' + userId + '"'
125154
},
126155
dbConnectionMap,
127-
function (err, result) {
156+
function (err) {
128157
if (err) {
129158
next(err);
130159
} else {
@@ -137,7 +166,6 @@ var persistResource = function (api, resourceId, userId, challengeId, dbConnecti
137166
* Audit the challenge registration on table 'tcs_catalog.project_user_audit'.
138167
*
139168
* @param {Object} api The api object that is used to access the infrastructure.
140-
* @param {Number} resourceId The resource id.
141169
* @param {Number} userId The current logged-in user's id.
142170
* @param {Number} challengeId The id of the challenge to register.
143171
* @param {Object} dbConnectionMap The database connection map for the current request.
@@ -211,8 +239,9 @@ var prepareProjectResult = function (api, rating, userId, challengeId, phaseId,
211239
*
212240
* @param {Object} api The api object that is used to access the infrastructure.
213241
* @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.
216245
* @param {Object} dbConnectionMap The database connection map for the current request.
217246
* @param {Function<err, data>} next The callback to be called after this function is done..
218247
*/
@@ -345,12 +374,13 @@ var projectTrack = function (api, userId, challengeId, componentInfo, dbConnecti
345374
* Send email to notify the user registration succeeded.
346375
*
347376
* @param {Object} api The api object that is used to access the infrastructure.
348-
* @param {Number} userId The current logged-in user's id.
349377
* @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.
350380
* @param {Object} dbConnectionMap The database connection map for the current request.
351381
* @param {Function<err, data>} next The callback to be called after this function is done.
352382
*/
353-
var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMap, next) {
383+
var sendNotificationEmail = function (api, componentInfo, userId, activeForumCategoryId, dbConnectionMap, next) {
354384
async.waterfall([
355385
function (cb) {
356386
api.dataAccess.executeQuery("get_user_email_and_handle", {
@@ -362,7 +392,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
362392
cb(new NotFoundError("user's email and handle not found"));
363393
return;
364394
}
365-
var user, projectName, documentationDetails, submitURL, activeForumCategoryId, forumURL, umlToolInfo;
395+
var user, projectName, documentationDetails, submitURL, forumURL, umlToolInfo;
366396

367397
user = result[0];
368398
projectName = componentInfo.project_name + api.helper.getPhaseName(componentInfo.phase_id) + ' Contest';
@@ -377,7 +407,7 @@ var sendNotificationEmail = function (api, componentInfo, userId, dbConnectionMa
377407

378408
if (componentInfo.phase_id === 112 || componentInfo.phase_id === 113) {
379409
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";
381411
}
382412

383413
//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
402432
], next);
403433
};
404434

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+
405509
/**
406510
* Register a development (software) challenge for the current logged-in user.
407511
*
@@ -429,10 +533,24 @@ var registerSoftwareChallenge = function (api, userId, challengeId, dbConnection
429533
cb(err);
430534
});
431535
},
536+
432537
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);
435552
}
553+
436554
], next);
437555
};
438556

@@ -483,7 +601,7 @@ var persistStudioChallengeResouce = function (api, userId, challengeId, dbConnec
483601
},
484602
function (cb) {
485603
//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);
487605
},
488606
function (cb) {
489607
//payments.
@@ -527,6 +645,8 @@ var timelineNotification = function (api, userId, challengeId, dbConnectionMap,
527645
},
528646
dbConnectionMap,
529647
cb);
648+
} else {
649+
cb(null);
530650
}
531651
}
532652
], next);
@@ -565,10 +685,30 @@ var registerSoftwareChallengeAction = function (api, connection, next) {
565685
if (connection.dbConnectionMap) {
566686
api.log("Execute registerSoftwareChallengeAction#run", 'debug');
567687

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+
};
569698
async.waterfall([
570-
571699
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) {
572712
api.challengeHelper.getChallengeTerms(
573713
connection,
574714
challengeId,

0 commit comments

Comments
 (0)