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

Commit ecc72aa

Browse files
authored
Merge pull request #20 from topcoder-platform/Issue_19
Issue 19
2 parents aa87b47 + 0831b14 commit ecc72aa

File tree

13 files changed

+120
-129
lines changed

13 files changed

+120
-129
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Dependencies
44

5-
- nodejs (v10)
5+
- Nodejs (v10)
66
- Mongodb (v4)
77

88
## Configuration
@@ -54,6 +54,7 @@ npm start
5454
```
5555

5656
## Mock API
57+
5758
For verification purpose, we need a mock app for Topcoder Challenge API and Topcoder Member API. You can run command `npm run mock-api` to start the mock app.
5859

5960
## Heroku Deployment

config/default.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ module.exports = {
77
PORT: process.env.PORT || 3000,
88

99
MONGODB_URL: process.env.MONGODB_URL || 'mongodb://localhost:27017/leaderboardDB',
10-
CHALLENGE_API_URL: process.env.CHALLENGE_API_URL || 'https://api.topcoder-dev.com/v3/challenges',
10+
CHALLENGE_API_URL: process.env.CHALLENGE_API_URL || 'https://api.topcoder-dev.com/v4/challenges',
1111
MEMBER_API_URL: process.env.MEMBER_API_URL || 'https://api.topcoder-dev.com/v3/users',
1212

1313
GROUP_IDS: process.env.GROUP_IDS || '202343,20000000', // Comma separated string of Group IDs

config/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
module.exports = {
6-
CHALLENGE_API_URL: 'https://api.topcoder-dev.com/v3/challenges',
6+
CHALLENGE_API_URL: 'https://api.topcoder-dev.com/v4/challenges',
77
MEMBER_API_URL: 'https://api.topcoder-dev.com/v3/users',
88
MOCK_API_PORT: 3001
99
}

docs/Leaderboard API.postman_collection.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"info": {
3-
"_postman_id": "85361413-4f1c-4fb2-9433-01dc999d7e4b",
3+
"_postman_id": "adfe8d84-410e-4628-9a1c-f74e16e89c83",
44
"name": "Leaderboard API",
55
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
66
},
@@ -180,7 +180,7 @@
180180
],
181181
"body": {
182182
"mode": "raw",
183-
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"metadata\": {\n \"assertions\": {\n \"pending\": 0,\n \"failed\": 1,\n \"total\": 10\n },\n \"tests\": {\n \"total\": 10\n }\n },\n \"aggregateScore\": 90\n}",
183+
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"metadata\": {\n \"tests\": {\n \"pending\": 0,\n \"failed\": 1,\n \"total\": 10\n }\n },\n \"score\": 90\n}",
184184
"options": {
185185
"raw": {
186186
"language": "json"
@@ -217,7 +217,7 @@
217217
],
218218
"body": {
219219
"mode": "raw",
220-
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"aggregateScore\": 0\n}",
220+
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"score\": 0\n}",
221221
"options": {
222222
"raw": {
223223
"language": "json"
@@ -254,7 +254,7 @@
254254
],
255255
"body": {
256256
"mode": "raw",
257-
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"aggregateScore\": 0\n}",
257+
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"submissionId\": \"261d3655-9c80-4f90-8051-e209e8c21701\",\n \"score\": 0\n}",
258258
"options": {
259259
"raw": {
260260
"language": "json"
@@ -296,7 +296,7 @@
296296
],
297297
"body": {
298298
"mode": "raw",
299-
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"metadata\": {\n \"assertions\": {\n \"pending\": 0,\n \"failed\": 1,\n \"total\": 5\n },\n \"tests\": {\n \"total\": 5\n }\n },\n \"aggregateScore\": 80\n}"
299+
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"metadata\": {\n \"test\": {\n \"pending\": 0,\n \"failed\": 1,\n \"total\": 5\n }\n },\n \"score\": 80\n}"
300300
},
301301
"url": {
302302
"raw": "{{URL}}/leaderboard/challenge/30051825/member/8547899",
@@ -327,7 +327,7 @@
327327
],
328328
"body": {
329329
"mode": "raw",
330-
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"aggregateScore\": 80\n}"
330+
"raw": "{\n\t\"id\": \"161d3655-9c80-4f90-8051-e209e8c21701\",\n \"score\": 80\n}"
331331
},
332332
"url": {
333333
"raw": "{{URL}}/leaderboard/challenge/30051825/member/5547899",
@@ -388,13 +388,13 @@
388388
"method": "DELETE",
389389
"header": [],
390390
"url": {
391-
"raw": "{{URL}}/leaderboard/reviewSummation/661d3655-9c80-4f90-8051-e209e8c21704",
391+
"raw": "{{URL}}/leaderboard/review/661d3655-9c80-4f90-8051-e209e8c21704",
392392
"host": [
393393
"{{URL}}"
394394
],
395395
"path": [
396396
"leaderboard",
397-
"reviewSummation",
397+
"review",
398398
"661d3655-9c80-4f90-8051-e209e8c21704"
399399
]
400400
}
@@ -407,13 +407,13 @@
407407
"method": "DELETE",
408408
"header": [],
409409
"url": {
410-
"raw": "{{URL}}/leaderboard/reviewSummation/231d3655-9c80-4f90-8051-e209e8c21704",
410+
"raw": "{{URL}}/leaderboard/review/231d3655-9c80-4f90-8051-e209e8c21704",
411411
"host": [
412412
"{{URL}}"
413413
],
414414
"path": [
415415
"leaderboard",
416-
"reviewSummation",
416+
"review",
417417
"231d3655-9c80-4f90-8051-e209e8c21704"
418418
]
419419
}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"mock-api": "NODE_ENV=test node test/common/mock.js",
1111
"lint": "standard",
1212
"lint:fix": "standard --fix",
13-
"test": "nyc --reporter=html --reporter=text mocha test/unit/test.js --require test/common/prepare.js --exit",
14-
"e2e": "nyc --reporter=html --reporter=text mocha test/e2e/test.js --require test/common/prepare.js --exit"
13+
"test": "nyc --reporter=html --reporter=text mocha test/unit/test.js --timeout=20000 --require test/common/prepare.js --exit",
14+
"e2e": "nyc --reporter=html --reporter=text mocha test/e2e/test.js --timeout=20000 --require test/common/prepare.js --exit"
1515
},
1616
"author": "TCSCODER",
1717
"license": "none",

src/controllers/LeaderboardController.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@ async function updateLeaderboard (req, res) {
2828
}
2929

3030
/**
31-
* Delete leaderboard detail by review summation id
31+
* Delete leaderboard detail by review id
3232
* @param req the request
3333
* @param res the response
3434
*/
3535
async function deleteLeaderboard (req, res) {
36-
await LeaderboardService.deleteLeaderboard(req.params.reviewSummationId)
36+
await LeaderboardService.deleteLeaderboard(req.params.reviewId)
3737
res.status(204).end()
3838
}
3939

src/models/Leaderboard.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
const Schema = require('mongoose').Schema
66

77
const LeaderboardSchema = new Schema({
8-
reviewSummationId: { type: String },
8+
reviewId: { type: String },
99
submissionId: { type: String },
1010
challengeId: { type: String },
1111
memberId: { type: String },

src/routes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module.exports = {
1919
method: 'updateLeaderboard'
2020
}
2121
},
22-
'/leaderboard/reviewSummation/:reviewSummationId': {
22+
'/leaderboard/review/:reviewId': {
2323
delete: {
2424
controller: 'LeaderboardController',
2525
method: 'deleteLeaderboard'

src/services/LeaderboardService.js

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ async function getLeaderboard (challengeId, memberId) {
2828
* @returns {Number} the test passed number
2929
*/
3030
function getTestsPassed (metadata) {
31-
const tests = metadata.tests || { total: 0, pending: 0, failed: 0}
31+
const tests = metadata.tests || { total: 0, pending: 0, failed: 0 }
3232

3333
let testsPassed = tests.total - tests.pending - tests.failed
3434

@@ -42,35 +42,35 @@ function getTestsPassed (metadata) {
4242
/**
4343
* Calculate test passed number and total test cases
4444
*
45-
* @param {Object} reviewSummation the review summation
45+
* @param {Object} review the review
4646
* @return {Object} testsPassed and totalTestCases
4747
*/
48-
function calculateResult (reviewSummation) {
48+
function calculateResult (review) {
4949
let testsPassed = 0
5050
let totalTestCases = 0
5151

52-
if (reviewSummation.metadata) {
53-
testsPassed = getTestsPassed(reviewSummation.metadata)
54-
totalTestCases = _.get(reviewSummation, 'metadata.tests.total', 0)
52+
if (review.metadata) {
53+
testsPassed = getTestsPassed(review.metadata)
54+
totalTestCases = _.get(review, 'metadata.tests.total', 0)
5555
}
5656
return { testsPassed, totalTestCases }
5757
}
5858

5959
/**
60-
* Create leaderboard using review summation data
60+
* Create leaderboard using review data
6161
*
6262
* @param {String} challengeId the challenge id
6363
* @param {String} memberId the member id
64-
* @param {Object} reviewSummation the review summation data
64+
* @param {Object} review the review data
6565
* @returns {Object} the created leaderboard
6666
*/
67-
async function createLeaderboard (challengeId, memberId, reviewSummation) {
67+
async function createLeaderboard (challengeId, memberId, review) {
6868
const existRecords = await getLeaderboard(challengeId, memberId)
6969
if (existRecords.length > 0) {
7070
throw new errors.ConflictError(`Leaderboard record with challenge # ${challengeId} and member # ${memberId} already exists.`)
7171
}
7272

73-
const { testsPassed, totalTestCases } = calculateResult(reviewSummation)
73+
const { testsPassed, totalTestCases } = calculateResult(review)
7474

7575
const challengeDetailRes = await helper.reqToAPI(
7676
`${config.CHALLENGE_API_URL}?filter=id=${challengeId}`)
@@ -94,12 +94,12 @@ async function createLeaderboard (challengeId, memberId, reviewSummation) {
9494

9595
// Record to be written into MongoDB
9696
const record = {
97-
reviewSummationId: reviewSummation.id,
98-
submissionId: reviewSummation.submissionId,
97+
reviewId: review.id,
98+
submissionId: review.submissionId,
9999
memberId,
100100
challengeId,
101101
handle: member.handle,
102-
aggregateScore: reviewSummation.aggregateScore,
102+
aggregateScore: review.score, // For TCO scenario, we will only have 1 review - per member and per challenge
103103
testsPassed,
104104
totalTestCases,
105105
groupIds: _.map(groupIds, e => String(e))
@@ -111,40 +111,40 @@ async function createLeaderboard (challengeId, memberId, reviewSummation) {
111111
createLeaderboard.schema = {
112112
challengeId: joi.string().required(),
113113
memberId: joi.string().required(),
114-
reviewSummation: joi.object().keys({
114+
review: joi.object().keys({
115115
id: joi.string().required(),
116116
submissionId: joi.string().required(),
117-
aggregateScore: joi.number().required()
117+
score: joi.number().required()
118118
}).unknown(true).required()
119119
}
120120

121121
/**
122-
* Update leaderboard detail using review summation data
122+
* Update leaderboard detail using review data
123123
*
124124
* @param {String} challengeId the challenge id
125125
* @param {String} memberId the member id
126-
* @param {Object} reviewSummation the review summation data
126+
* @param {Object} review the review data
127127
* @returns the updated leaderboard detail
128128
*/
129-
async function updateLeaderboard (challengeId, memberId, reviewSummation) {
129+
async function updateLeaderboard (challengeId, memberId, review) {
130130
const existRecords = await getLeaderboard(challengeId, memberId)
131131
if (existRecords.length === 0) {
132132
throw new errors.NotFoundError(`Leaderboard record with challenge # ${challengeId} and member # ${memberId} doesn't exist`)
133133
}
134134

135135
let scoreLevel = 'na'
136136

137-
const { testsPassed, totalTestCases } = calculateResult(reviewSummation)
137+
const { testsPassed, totalTestCases } = calculateResult(review)
138138

139-
if (existRecords[0].aggregateScore > reviewSummation.aggregateScore) {
140-
scoreLevel = 'down';
141-
} else if (existRecords[0].aggregateScore < reviewSummation.aggregateScore) {
142-
scoreLevel = 'up';
139+
if (existRecords[0].aggregateScore > review.score) {
140+
scoreLevel = 'down'
141+
} else if (existRecords[0].aggregateScore < review.score) {
142+
scoreLevel = 'up'
143143
}
144144

145145
_.assignIn(existRecords[0], {
146-
aggregateScore: reviewSummation.aggregateScore,
147-
reviewSummationId: reviewSummation.id,
146+
aggregateScore: review.score,
147+
reviewId: review.id,
148148
testsPassed,
149149
totalTestCases,
150150
scoreLevel
@@ -156,9 +156,9 @@ async function updateLeaderboard (challengeId, memberId, reviewSummation) {
156156
updateLeaderboard.schema = {
157157
challengeId: joi.string().required(),
158158
memberId: joi.string().required(),
159-
reviewSummation: joi.object().keys({
159+
review: joi.object().keys({
160160
id: joi.string().required(),
161-
aggregateScore: joi.number().required()
161+
score: joi.number().required()
162162
}).unknown(true).required()
163163
}
164164

@@ -222,20 +222,20 @@ searchLeaderboards.schema = {
222222
}
223223

224224
/**
225-
* Delete leaderboard by review summation id.
225+
* Delete leaderboard by review id.
226226
*
227-
* @param {String} reviewSummationId the review summation id
227+
* @param {String} reviewId the review id
228228
*/
229-
async function deleteLeaderboard (reviewSummationId) {
230-
const entity = await Leaderboard.findOne({ reviewSummationId })
229+
async function deleteLeaderboard (reviewId) {
230+
const entity = await Leaderboard.findOne({ reviewId })
231231
if (!entity) {
232-
throw new errors.NotFoundError(`Leaderboard record with reviewSummation ID: ${reviewSummationId} doesn't exist`)
232+
throw new errors.NotFoundError(`Leaderboard record with review id: ${reviewId} doesn't exist`)
233233
}
234234
await entity.remove()
235235
}
236236

237237
deleteLeaderboard.schema = {
238-
reviewSummationId: joi.string().required()
238+
reviewId: joi.string().required()
239239
}
240240

241241
module.exports = {

src/test-data.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const logger = require('./common/logger')
77

88
const insertData = async () => {
99
await Leaderboard.create({
10-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21704',
10+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21704',
1111
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf4',
1212
challengeId: '30104644',
1313
memberId: '123456',
@@ -18,7 +18,7 @@ const insertData = async () => {
1818
groupIds: ['100', '200']
1919
})
2020
await Leaderboard.create({
21-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21705',
21+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21705',
2222
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf5',
2323
challengeId: '30104644',
2424
memberId: '123457',
@@ -29,7 +29,7 @@ const insertData = async () => {
2929
groupIds: ['100', '200']
3030
})
3131
await Leaderboard.create({
32-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21706',
32+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21706',
3333
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf6',
3434
challengeId: '30104644',
3535
memberId: '123458',
@@ -40,7 +40,7 @@ const insertData = async () => {
4040
groupIds: ['100', '200']
4141
})
4242
await Leaderboard.create({
43-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21701',
43+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21701',
4444
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf1',
4545
challengeId: '30104645',
4646
memberId: '123456',
@@ -51,7 +51,7 @@ const insertData = async () => {
5151
groupIds: ['100', '200']
5252
})
5353
await Leaderboard.create({
54-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21702',
54+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21702',
5555
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf2',
5656
challengeId: '30104645',
5757
memberId: '123457',
@@ -62,7 +62,7 @@ const insertData = async () => {
6262
groupIds: ['100', '200']
6363
})
6464
await Leaderboard.create({
65-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21703',
65+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21703',
6666
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf3',
6767
challengeId: '30104646',
6868
memberId: '123456',
@@ -73,7 +73,7 @@ const insertData = async () => {
7373
groupIds: ['100']
7474
})
7575
await Leaderboard.create({
76-
reviewSummationId: '661d3655-9c80-4f90-8051-e209e8c21709',
76+
reviewId: '661d3655-9c80-4f90-8051-e209e8c21709',
7777
submissionId: '2b5e54b9-f03c-418b-92f3-5f072b0f3bf9',
7878
challengeId: '30104646',
7979
memberId: '123458',

0 commit comments

Comments
 (0)