From 17a6f9c525097cd7ec1160603c3f52fcd7be4264 Mon Sep 17 00:00:00 2001 From: Ghost141 Date: Tue, 9 Dec 2014 15:13:23 +0800 Subject: [PATCH 1/3] TC API - User Algo Challenges API --- actions/user.js | 171 +++++++++++- apiary.apib | 170 ++++++++++++ initializers/helper.js | 11 +- queries/get_user_algo_challenges | 40 +++ queries/get_user_algo_challenges.json | 5 + queries/get_user_algo_challenges_count | 9 + queries/get_user_algo_challenges_count.json | 5 + routes.js | 5 +- .../getUserAlgoChallenges/common_oltp__clean | 1 + .../common_oltp__insert_test_data | 1 + .../getUserAlgoChallenges/topcoder_dw__clean | 14 + .../topcoder_dw__insert_test_data | 179 ++++++++++++ test/test.getUserAlgoChallenges.js | 261 ++++++++++++++++++ ...et_user_algo_challenges_error_message.json | 22 ++ .../expected_response_1.json | 44 +++ .../expected_response_2.json | 6 + .../expected_response_3.json | 6 + .../expected_response_4.json | 20 ++ .../expected_response_5.json | 44 +++ .../expected_response_6.json | 44 +++ .../expected_response_7.json | 44 +++ 21 files changed, 1083 insertions(+), 19 deletions(-) create mode 100644 queries/get_user_algo_challenges create mode 100644 queries/get_user_algo_challenges.json create mode 100644 queries/get_user_algo_challenges_count create mode 100644 queries/get_user_algo_challenges_count.json create mode 100644 test/sqls/getUserAlgoChallenges/common_oltp__clean create mode 100644 test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data create mode 100644 test/sqls/getUserAlgoChallenges/topcoder_dw__clean create mode 100644 test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data create mode 100644 test/test.getUserAlgoChallenges.js create mode 100644 test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_1.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_2.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_3.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_4.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_5.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_6.json create mode 100644 test/test_files/getUserAlgoChallenges/expected_response_7.json diff --git a/actions/user.js b/actions/user.js index c7c4d960b..3e39ec50f 100644 --- a/actions/user.js +++ b/actions/user.js @@ -1,12 +1,14 @@ /* * Copyright (C) 2014 TopCoder Inc., All Rights Reserved. * - * @version 1.2 + * @version 1.3 * @author muzehyun, Ghost_141 * Changes in 1.1: * - Implement user activation email api. * Changes in 1.2: * - Implement get user identity api. + * Changes in 1.3: + * - Implement get user algorithm challenges api. */ 'use strict'; var async = require('async'); @@ -29,6 +31,13 @@ var activationEmailSubject = "Topcoder User Registration Activation"; */ var activationEmailSenderName = "Topcoder API"; +/** + * The valid sort column values for get user algo challenges api. + * @since 1.3 + */ +var VALID_SORT_COLUMN_ALGO_CHALLENGES = ['id', 'type', 'codingDuration', 'placement', 'numContestants', + 'numSubmitters']; + /** * It validates activation code and retrieves user id from activation code * @param {String} activationCode - activation code string @@ -332,7 +341,7 @@ exports.getUserIdentity = { * @since 1.2 */ function getUserIdentityByAuth0Id(api, connection, next) { - var helper = api.helper, + var helper = api.helper, auth0id = connection.params.id, userid = 0, dbConnectionMap = connection.dbConnectionMap, @@ -343,24 +352,23 @@ function getUserIdentityByAuth0Id(api, connection, next) { function (cb) { try { var splits = auth0id.split('|'); - if (splits[0] == 'ad') { + if (splits[0] === 'ad') { cb(null, [{ user_id: Number(splits[1]) }]); } else { - api.helper.getProviderId(splits[0], function(err, provider) { + api.helper.getProviderId(splits[0], function (err, provider) { if (err) { cb(notfound); } else { api.dataAccess.executeQuery("get_user_by_social_login", - { - social_user_id: splits[1], - provider_id: provider - }, - dbConnectionMap, cb); + { + social_user_id: splits[1], + provider_id: provider + }, + dbConnectionMap, cb); } }); } - } - catch (exc) { + } catch (exc) { cb(notfound); } }, @@ -368,10 +376,10 @@ function getUserIdentityByAuth0Id(api, connection, next) { if (!result[0]) { cb(notfound); } else { - userid = result[0].user_id - api.dataAccess.executeQuery('get_user_email_and_handle', - { userId: userid }, - dbConnectionMap, cb); + userid = result[0].user_id; + api.dataAccess.executeQuery('get_user_email_and_handle', + { userId: userid }, + dbConnectionMap, cb); } }, function (rs, cb) { @@ -422,3 +430,136 @@ exports.getUserIdentityByAuth0Id = { } } }; + +/** + * Handle the get algorithm challenges that user participated to. + * @param {Object} api - The api object. + * @param {Object} connection - The connection object. + * @param {Function} next - The callback function. + * @since 1.3 + */ +function getUserAlgorithmChallenges(api, connection, next) { + var helper = api.helper, dbConnectionMap = connection.dbConnectionMap, response, sqlParams, sortOrder, sortColumn, + exeQuery = function (name) { + return function (cbx) { + api.dataAccess.executeQuery(name, sqlParams, dbConnectionMap, cbx); + }; + }, + handle = connection.params.handle, + pageIndex = Number(connection.params.pageIndex || 1), + pageSize = Number(connection.params.pageSize || 10); + + // If the sortOrder is set and sortColumn is missing. + if (connection.params.sortOrder && !connection.params.sortColumn) { + helper.handleError(api, connection, new BadRequestError('The sortColumn is missing.')); + next(connection, true); + return; + } + + sortOrder = (connection.params.sortOrder || "asc").toLowerCase(); + sortColumn = connection.params.sortColumn || "id"; + + if (pageIndex === -1) { + pageSize = helper.MAX_INT; + pageIndex = 1; + } + + if (sortColumn.toLowerCase() === 'placement') { + //reverse the sortOrder value because for placement 1 is the best so the descending order should be like 1, 2, 3. + sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'; + } + + async.waterfall([ + function (cb) { + var error = helper.checkPageIndex(pageIndex, "pageIndex") + || helper.checkStringParameter(handle, "handle", 30) + || helper.checkPositiveInteger(pageSize, "pageSize") + || helper.checkMaxInt(pageSize, "pageSize") + || helper.checkContains(['asc', 'desc'], sortOrder, "sortOrder") + || helper.checkSortColumn(VALID_SORT_COLUMN_ALGO_CHALLENGES, sortColumn.toLowerCase()); + cb(error); + }, + function (cb) { + helper.checkUserExists(handle, api, dbConnectionMap, cb); + }, + function (err, cb) { + if (err) { + cb(err); + return; + } + helper.checkUserActivated(handle, api, dbConnectionMap, cb); + }, + function (err, cb) { + if (err) { + cb(err); + return; + } + sqlParams = { + first_row_index: (pageIndex - 1) * pageSize, + page_size: pageSize, + sort_order: sortOrder, + sort_column: helper.getSortColumnDBName(sortColumn.toLowerCase()), + handle: handle.toLowerCase() + }; + async.parallel({ + data: exeQuery('get_user_algo_challenges'), + count: exeQuery('get_user_algo_challenges_count') + }, cb); + }, + function (queryResult, cb) { + var total = queryResult.count[0].total_count; + response = { + pageIndex: pageIndex, + pageSize: pageIndex === -1 ? total : pageSize, + total: total, + data: queryResult.data.map(function (row) { + return { + id: row.id, + type: row.type, + prize: row.paid > 0, + codingDuration: row.coding_duration, + placement: row.placement, + numContestants: row.num_contestants, + numSubmitters: row.num_submitters, + platforms: [], + technologies: row.technologies.split(',').map(function (s) { return s.trim(); }) + }; + }) + }; + cb(); + } + ], function (err) { + if (err) { + helper.handleError(api, connection, err); + } else { + connection.response = response; + } + next(connection, true); + }); +} + +/** + * The API for get user algorithm challenges. + * @since 1.3 + */ +exports.getUserAlgorithmChallenges = { + name: 'getUserAlgorithmChallenges', + description: 'Get user algorithm challenges related information', + inputs: { + required: ['handle'], + optional: ["sortOrder", "pageIndex", "pageSize", "sortColumn"] + }, + blockedConnectionTypes: [], + outputExample: {}, + version: 'v2', + transaction: 'read', + databases: ['topcoder_dw', 'common_oltp'], + run: function (api, connection, next) { + if (connection.dbConnectionMap) { + api.log('getUserAlgorithmChallenges#run', 'debug'); + getUserAlgorithmChallenges(api, connection, next); + } else { + api.helper.handleNoConnection(api, connection, next); + } + } +}; diff --git a/apiary.apib b/apiary.apib index 235aef0c5..548542195 100644 --- a/apiary.apib +++ b/apiary.apib @@ -2342,6 +2342,176 @@ Request "description":"Servers are up but overloaded. Try again later." } +## Get User Algo Challenges [/user/{handle}/challenges/algo?pageIndex={pageIndex}&pageSize={pageSize}&sortOrder={sortOrder}&sortColumn={sortColumn}] +### Get User Algo Challenges [GET] + ++ Parameters + + handle (required, string, `heffan`) ... the user handle that to search + + pageIndex (optional, number, `1`) ... The page index of the returned resources. 1-based. It can be null. The default value will be 1 + + pageSize (optional, number, `10`) ... The page size of the returned resources. 1-based. It can be null. The default value will be 10. + + sortColumn (optional, string, `id`) ... The column name to sort, can be null. + + sortOrder (optional, string, `asc`) ... The sorting order, can be null. If it's set, it can only be 'asc' or 'desc'. + ++ Response 200 (application/json) + + { + "total": 1, + "pageIndex": 1, + "pageSize": 10, + "data": [ + { + "id": 2001, + "type": "Single Round Match", + "placement": 1, + "prize": true, + "numContestants": 14, + "numSubmitters": 6, + "codingDuration": 30000000, + "platforms": [], + "technologies": [ + "Java", + "C++" + ] + } + ] + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be number." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be equal to -1 or greater than 0" + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be Integer." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be less or equal to 2147483647." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be number." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be positive." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be Integer." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be less or equal to 2147483647." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "" + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "handle exceeds 30 characters." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "sortOrder should be an element of asc,desc." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "The sort column 'abc' is invalid, it should be element of id,type,prize,codingDuration,placement,numContestants,numSubmitters." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "The sortColumn is missing." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "User is not activated." + } + ++ Response 404 (application/json) + { + "name": "Not Found", + "value": 404, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "User does not exist." + } + ++ Response 500 (application/json) + + { + "name":"Internal Server Error", + "value":"500", + "description":"Unknown server error. Please contact support." + } + ++ Response 503 (application/json) + + { + "name":"Service Unavailable", + "value":"503", + "description":"Servers are up but overloaded. Try again later." + } + ## Validate Handle [/users/validate/{handle}] ### Validate Handle [GET] diff --git a/initializers/helper.js b/initializers/helper.js index b75eb804f..ad0e9072c 100644 --- a/initializers/helper.js +++ b/initializers/helper.js @@ -5,8 +5,8 @@ /** * This module contains helper functions. - * @author Sky_, Ghost_141, muzehyun, kurtrips, isv, LazyChild, hesibo, panoptimum, flytoj2ee - * @version 1.38 + * @author Sky_, Ghost_141, muzehyun, kurtrips, isv, LazyChild, hesibo, panoptimum, flytoj2ee, TCSASSEMBLER + * @version 1.39 * changes in 1.1: * - add mapProperties * changes in 1.2: @@ -101,6 +101,8 @@ * - Updated checkDates function to accept optional 'errorMessage' parameter. * Changes in 1.38: * - Add method editSql, readQuery and constant QUERY_PATH. + * Changes in 1.39: + * - Update apiName2dbNameMap to add entries for coding_duration, num_contestants and num_submitters. */ "use strict"; @@ -256,7 +258,10 @@ var apiName2dbNameMap = { problemid: 'problem_id', problemname: 'problem_name', problemtype: 'problem_type', - mypoints: 'my_points' + mypoints: 'my_points', + codingduration: 'coding_duration', + numcontestants: 'num_contestants', + numsubmitters: 'num_submitters' }; /** diff --git a/queries/get_user_algo_challenges b/queries/get_user_algo_challenges new file mode 100644 index 000000000..791dacf10 --- /dev/null +++ b/queries/get_user_algo_challenges @@ -0,0 +1,40 @@ +SELECT +SKIP @first_row_index@ +FIRST @page_size@ + r.round_id AS id +, r.round_type_desc AS type +, rr.division_placed AS placement +, NVL(reg_info.count, 0) AS num_contestants +, NVL(sub_info.count, 0) AS num_submitters +, NVL(rr.paid, 0) AS paid +, (((extend(dbinfo("UTC_TO_DATETIME", + (SELECT MAX(submit_time) FROM problem_submission ps WHERE ps.round_id = r.round_id AND ps.problem_id = p.problem_id AND ps.coder_id = co.coder_id)/1000) + , YEAR TO fraction) - c.start_date)::INTERVAL SECOND(9) to second) * 1000)::char(10)::INT8 AS coding_duration +, user_algo_challenges_language(co.coder_id, p.problem_id, r.round_id) AS technologies +FROM contest c +INNER JOIN round r ON r.contest_id = c.contest_id +INNER JOIN problem p ON p.round_id = r.round_id +INNER JOIN room_result rr ON rr.round_id = r.round_id +INNER JOIN coder co ON co.coder_id = rr.coder_id AND co.handle_lower = '@handle@' +INNER JOIN coder_rank_history rkh ON rkh.coder_id = rr.coder_id AND rkh.round_id = rr.round_id +LEFT JOIN ( + SELECT + rr.round_id + , COUNT(*) AS count + FROM room_result rr + INNER JOIN room ON room.room_id = rr.room_id AND room.division_id IN (1, 2) + WHERE rr.problems_submitted > 0 + GROUP BY rr.round_id +) sub_info ON sub_info.round_id = r.round_id +LEFT JOIN ( + SELECT + rr.round_id + , COUNT(*) AS count + FROM room_result rr + INNER JOIN room ON room.room_id = rr.room_id AND room.division_id IN (1, 2) + GROUP BY rr.round_id +) reg_info ON reg_info.round_id = r.round_id +WHERE r.round_type_id IN (1,2,10,20) +AND rkh.coder_rank_type_id = 2 +AND rr.problems_submitted > 0 -- has submitted +ORDER BY @sort_column@ @sort_order@ diff --git a/queries/get_user_algo_challenges.json b/queries/get_user_algo_challenges.json new file mode 100644 index 000000000..73e801786 --- /dev/null +++ b/queries/get_user_algo_challenges.json @@ -0,0 +1,5 @@ +{ + "name" : "get_user_algo_challenges", + "db" : "topcoder_dw", + "sqlfile" : "get_user_algo_challenges" +} diff --git a/queries/get_user_algo_challenges_count b/queries/get_user_algo_challenges_count new file mode 100644 index 000000000..bb4fe724d --- /dev/null +++ b/queries/get_user_algo_challenges_count @@ -0,0 +1,9 @@ +SELECT COUNT(*) AS total_count +FROM contest c +INNER JOIN round r ON r.contest_id = c.contest_id +INNER JOIN room_result rr ON rr.round_id = r.round_id +INNER JOIN coder co ON co.coder_id = rr.coder_id AND co.handle_lower = '@handle@' +INNER JOIN coder_rank_history rkh ON rkh.coder_id = rr.coder_id AND rkh.round_id = rr.round_id +WHERE r.round_type_id IN (1,2,10,20) +AND rkh.coder_rank_type_id = 2 +AND rr.problems_submitted > 0 diff --git a/queries/get_user_algo_challenges_count.json b/queries/get_user_algo_challenges_count.json new file mode 100644 index 000000000..490537c33 --- /dev/null +++ b/queries/get_user_algo_challenges_count.json @@ -0,0 +1,5 @@ +{ + "name" : "get_user_algo_challenges_count", + "db" : "topcoder_dw", + "sqlfile" : "get_user_algo_challenges_count" +} diff --git a/routes.js b/routes.js index 24fd7090f..e03b0abfd 100755 --- a/routes.js +++ b/routes.js @@ -1,7 +1,7 @@ /* * Copyright (C) 2013 - 2014 TopCoder Inc., All Rights Reserved. * - * @version 1.62 + * @version 1.63 * @author vangavroche, Sky_, muzehyun, kurtrips, Ghost_141, ecnu_haozi, hesibo, LazyChild, isv, flytoj2ee, * @author panoptimum, bugbuka, Easyhard, TCASSEMBLER * @@ -144,6 +144,8 @@ * - Added routes for modifying/deleting round question answers. * Changes in 1.62: * - Added route for src2image api. + * Changes in 1.63: + * - Add route for get user algorithm challenges api. */ /*jslint node:true, nomen: true */ "use strict"; @@ -262,6 +264,7 @@ exports.routes = { { path: "/:apiVersion/user/activation-email", action: "userActivationEmail" }, { path: "/:apiVersion/user/tcid/:id", action: "getUserIdentityByAuth0Id" }, { path: "/:apiVersion/user/identity", action: "getUserIdentity" }, + { path: "/:apiVersion/user/:handle/challenges/algo", action: "getUserAlgorithmChallenges" }, { path: "/:apiVersion/users/tops/:trackType", action: "getTopTrackMembers" }, { path: "/:apiVersion/users/resetToken", action: "generateResetToken" }, diff --git a/test/sqls/getUserAlgoChallenges/common_oltp__clean b/test/sqls/getUserAlgoChallenges/common_oltp__clean new file mode 100644 index 000000000..e22883b6e --- /dev/null +++ b/test/sqls/getUserAlgoChallenges/common_oltp__clean @@ -0,0 +1 @@ +DELETE FROM user WHERE user_id = 300002; diff --git a/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data b/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data new file mode 100644 index 000000000..b07af6097 --- /dev/null +++ b/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data @@ -0,0 +1 @@ +INSERT INTO user(user_id, handle, status) VALUES(300002, 'user2', 'U'); diff --git a/test/sqls/getUserAlgoChallenges/topcoder_dw__clean b/test/sqls/getUserAlgoChallenges/topcoder_dw__clean new file mode 100644 index 000000000..57c325a50 --- /dev/null +++ b/test/sqls/getUserAlgoChallenges/topcoder_dw__clean @@ -0,0 +1,14 @@ +DELETE FROM coder_rank_history WHERE round_id IN (2001, 2002, 2003, 2004); +DELETE FROM problem_submission; +DELETE FROM room_result WHERE round_id IN (2001, 2002, 2003, 2004); +DELETE FROM room WHERE room_id IN (2001, 2002, 2003, 2004); +DELETE FROM problem; +DELETE FROM round WHERE round_id IN (2001, 2002, 2003, 2004); +DELETE FROM contest WHERE contest_id IN (2001, 2002, 2003, 2004); +DELETE FROM coder_rank_type_lu; +DELETE FROM coder; +DELETE FROM division_lu; +DELETE FROM round_type_lu; +DELETE FROM algo_rating_type_lu; +DELETE FROM room_type_lu; +DELETE FROM language_lu; diff --git a/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data b/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data new file mode 100644 index 000000000..947689a8b --- /dev/null +++ b/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data @@ -0,0 +1,179 @@ +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (1, 'Admin'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (2, 'Contest'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (3, 'Practice'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (5, 'Lobby'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (4, 'Moderated Chat Room'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (6, 'Team Contest'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (7, 'Team Practice'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (8, 'Team Admin'); + +INSERT INTO division_lu(division_id,division_desc) VALUES (-1, 'No Division Applicable'); +INSERT INTO division_lu(division_id,division_desc) VALUES (0, 'Unrated Division'); +INSERT INTO division_lu(division_id,division_desc) VALUES (1, 'Division-I'); +INSERT INTO division_lu(division_id,division_desc) VALUES (2, 'Division-II'); + +INSERT INTO language_lu(language_id,language_name,status) VALUES (7,'R','Y'); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (1, 'Java', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (3, 'C++', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (2, 'XML', 'N', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (4, 'C#', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (5, 'VB', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (6, 'Python', 'Y', ''); + +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (1, 'TopCoder Rating'); +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (2, 'TopCoder High School Rating'); +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (3, 'Marathon Match Rating'); + +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (1, 'Single Round Match', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (2, 'Tournament Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (3, 'Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (4, 'Moderated Chat Session', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (10, 'Long Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (6, 'Screening Tool Problem Sets', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (11, 'Weakest Link Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (7, 'Team Single Round Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (8, 'Team Tournament Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (9, 'Team Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (12, 'Private Label Tournament', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (13, 'Marathon Match', 3); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (14, 'Marathon Match Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (15, 'Intel Marathon Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (16, 'Intel Marathon Match Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (17, 'HS Single Round Match', 2); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (18, 'HS Tournament Round', 2); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (19, 'Marathon Match Tournament Round', 3); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (20, 'Intro Event Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (21, 'Education Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (22, 'AMD Marathon Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (23, 'AMD Marathon Match Practice', NULL); + +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(132456, 'heffan', 'heffan'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300001, 'user1', 'user1'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300002, 'user2', 'user2'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300003, 'user3', 'user3'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300004, 'user4', 'user4'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300005, 'user5', 'user5'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300006, 'user6', 'user6'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300007, 'user7', 'user7'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300008, 'user8', 'user8'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300009, 'user9', 'user9'); +INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300010, 'user10', 'user10'); + +INSERT INTO coder_rank_type_lu(coder_rank_type_id, coder_rank_type_desc) VALUES(2, 'Test'); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2001, 'Contest 2001', "2014-12-11 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id) VALUES(2001, 2001, 'Round 2001', 10); +INSERT INTO room(room_id, round_id, room_type_id, division_id) VALUES(2001, 2001, 2, 1); +INSERT INTO problem(problem_id, round_id, result_type_id, method_name, class_name, division_id) VALUES(2001, 2001, 1, 'test', 'Main', 1); + +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 132456, 1, 1, 500); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300002, 2, 1, 300); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300003, 3, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300004, 4, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300006, 6, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300007, 7, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300009, 9, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2001, 2001, 300001, 10, 0, 0); + +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(132456, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300001, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300002, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300003, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300004, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300006, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300007, 2001, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300009, 2001, 2, 1); + +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2001, 132456, 2001, 1, 1, 1418285967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2001, 132456, 2001, 4, 2, 1418295967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2001, 300002, 2001, 1, 1, 1418285967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2001, 300003, 2001, 1, 1, 1418285967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2001, 300007, 2001, 1, 1, 1418285967481); + +INSERT INTO round(round_id, contest_id, name, round_type_id) VALUES(2002, 2001, 'Round 2002', 10); +INSERT INTO room(room_id, round_id, room_type_id, division_id) VALUES(2002, 2002, 2, 1); +INSERT INTO problem(problem_id, round_id, result_type_id, method_name, class_name, division_id) VALUES(2002, 2002, 1, 'test', 'Main', 1); + +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 132456, 1, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300002, 2, 1, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300003, 3, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300004, 4, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300005, 5, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300006, 6, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300007, 7, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300008, 8, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2002, 2002, 300009, 9, 1, 0); + +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(132456, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300001, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300002, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300003, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300004, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300005, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300006, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300007, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300008, 2002, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300009, 2002, 2, 1); + +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 132456, 2002, 3, 1, 1418275767481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300002, 2002, 1, 1, 1418245967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300003, 2002, 1, 1, 1418255967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300005, 2002, 1, 1, 1418295967481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300007, 2002, 1, 1, 1418285867481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300008, 2002, 1, 1, 1418285767481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2002, 300009, 2002, 1, 1, 1418285467481); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2002, 'Contest 2002', "2014-12-10 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id) VALUES(2003, 2002, 'Round 2003', 10); +INSERT INTO room(room_id, round_id, room_type_id, division_id) VALUES(2003, 2003, 2, 1); +INSERT INTO problem(problem_id, round_id, result_type_id, method_name, class_name, division_id) VALUES(2003, 2003, 1, 'test', 'Main', 1); + +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 132456, 1, 1, 100); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300002, 2, 1, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300003, 3, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300004, 4, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300005, 5, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300006, 6, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300008, 8, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300009, 9, 0, 0); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2003, 2003, 300001, 1, 0, 0); + +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(132456, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300001, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300002, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300003, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300004, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300005, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300006, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300008, 2003, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300009, 2003, 2, 1); + +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2003, 132456, 2003, 2, 1, 1418285767481); +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2003, 300002, 2003, 1, 1, 1418285967481); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2003, 'Contest 2003', "2014-12-10 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id) VALUES(2004, 2003, 'Round 2004', 10); +INSERT INTO room(room_id, round_id, room_type_id, division_id) VALUES(2004, 2004, 2, 1); +INSERT INTO problem(problem_id, round_id, result_type_id, method_name, class_name, division_id) VALUES(2004, 2004, 1, 'test', 'Main', 1); + +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 132456, 1, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300002, 2, 1, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300003, 3, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300004, 4, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300005, 5, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300006, 6, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300008, 8, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300009, 9, 0, 200); +INSERT INTO room_result(round_id, room_id, coder_id, division_placed, problems_submitted, paid) VALUES(2004, 2004, 300001, 1, 0, 200); + +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(132456, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300001, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300002, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300003, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300004, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300005, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300006, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300008, 2004, 2, 1); +INSERT INTO coder_rank_history(coder_id, round_id, coder_rank_type_id, algo_rating_type_id) VALUES(300009, 2004, 2, 1); + +INSERT INTO problem_submission(round_id, coder_id, problem_id, language_id, submission_number, submit_time) VALUES(2004, 300002, 2004, 7, 1, 1418285967481); diff --git a/test/test.getUserAlgoChallenges.js b/test/test.getUserAlgoChallenges.js new file mode 100644 index 000000000..c8a3d7a2f --- /dev/null +++ b/test/test.getUserAlgoChallenges.js @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2014 TopCoder Inc., All Rights Reserved. + * + * @version 1.0 + * @author TCSASSEMBLER + */ +'use strict'; +/*global describe, it, before, beforeEach, after, afterEach */ +/*jslint node: true, stupid: true, unparam: true */ + +/** + * Module dependencies. + */ +var request = require('supertest'); +var assert = require('chai').assert; +var async = require('async'); + +var testHelper = require('./helpers/testHelper'); +var SQL_DIR = __dirname + '/sqls/getUserAlgoChallenges/'; +var API_ENDPOINT = process.env.API_ENDPOINT || 'http://localhost:8080'; + +describe('Get User Algo Challenges API', function () { + this.timeout(180000); // The api with testing remote db could be quit slow + + var msgObj = require('../test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message'); + + /** + * Clear database + * @param {Function} done the callback + */ + function clearDb(done) { + testHelper.runSqlFile(SQL_DIR + "topcoder_dw__clean", "topcoder_dw", done); + } + + /** + * This function is run before all tests. + * Generate tests data. + * @param {Function} done the callback + */ + before(function (done) { + async.waterfall([ + clearDb, + function (cb) { + testHelper.runSqlFile(SQL_DIR + 'topcoder_dw__insert_test_data', 'topcoder_dw', cb); + } + ], done); + }); + + /** + * This function is run after all tests. + * Clean up all data. + * @param {Function} done the callback + */ + after(function (done) { + clearDb(done); + }); + + /** + * create a http request and test it. + * @param {String} userId - the request userId. + * @param {Number} expectStatus - the expected response status code. + * @param {String} query - The query used in http request. + * @param {Function} cb - the call back function. + */ + function createGetRequest(userId, expectStatus, query, cb) { + request(API_ENDPOINT) + .get('/v2/user/' + userId + '/challenges/algo' + query) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(expectStatus) + .end(cb); + } + + /** + * assert the bad response. + * @param {String} url - the request url + * @param {Number} expectStatus - the expect status. + * @param {String} errorMessage - the expected error message. + * @param {String} query - The query used in http request. + * @param {Function} cb - the callback function. + */ + function assertBadResponse(url, query, expectStatus, errorMessage, cb) { + createGetRequest(url, expectStatus, query, function (err, result) { + if (!err) { + assert.equal(result.body.error.details, errorMessage, 'invalid error message'); + } else { + cb(err); + return; + } + cb(); + }); + } + + function assertSuccessResponse(url, query, expectedResponse, cb) { + createGetRequest(url, 200, query, function (err, result) { + testHelper.assertResponse(err, result, expectedResponse, cb); + }); + } + + /** + * Test when user handle is too long. + */ + it('should return bad request. The user handle is too long.', function (done) { + assertBadResponse('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', '', 400, msgObj.handle.tooLong, done); + }); + + /** + * Test when user handle is not existed. + */ + it('should return bad request. The user handle is not existed.', function (done) { + assertBadResponse('abc', '', 404, msgObj.handle.notExisted, done); + }); + + /** + * Test when pageIndex is not integer. + */ + it('should return bad request. The pageIndex is not integer.', function (done) { + assertBadResponse('heffan', '?pageIndex=1.2345', 400, msgObj.pageIndex.notInteger, done); + }); + + /** + * Test when pageIndex is not number. + */ + it('should return bad request. The pageIndex is not number.', function (done) { + assertBadResponse('heffan', '?pageIndex=abc', 400, msgObj.pageIndex.notNumber, done); + }); + + /** + * Test when pageIndex is zero. + */ + it('should return bad request. The pageIndex is zero.', function (done) { + assertBadResponse('heffan', '?pageIndex=0', 400, msgObj.pageIndex.notPositive, done); + }); + + /** + * Test when pageIndex is too big. + */ + it('should return bad request. The pageIndex is too big.', function (done) { + assertBadResponse('heffan', '?pageIndex=2147483648', 400, msgObj.pageIndex.tooBig, done); + }); + + /** + * Test when pageIndex is not positive and not -1. + */ + it('should return bad request. The pageIndex is not positive and not -1.', function (done) { + assertBadResponse('heffan', '?pageIndex=-2', 400, msgObj.pageIndex.notPositive, done); + }); + + /** + * Test when pageSize is not integer. + */ + it('should return bad request. The pageSize is not integer.', function (done) { + assertBadResponse('heffan', '?pageSize=1.2345', 400, msgObj.pageSize.notInteger, done); + }); + + /** + * Test when pageSize is not number. + */ + it('should return bad request. The pageSize is not number.', function (done) { + assertBadResponse('heffan', '?pageSize=abc', 400, msgObj.pageSize.notNumber, done); + }); + + /** + * Test when pageSize is not positive. + */ + it('should return bad request. The pageSize is not positive.', function (done) { + assertBadResponse('heffan', '?pageSize=-1', 400, msgObj.pageSize.notPositive, done); + }); + + /** + * Test when pageSize is zero. + */ + it('should return bad request. The pageSize is zero.', function (done) { + assertBadResponse('heffan', '?pageSize=0', 400, msgObj.pageSize.notPositive, done); + }); + + /** + * Test when pageSize is too big. + */ + it('should return bad request. The pageSize is too big.', function (done) { + assertBadResponse('heffan', '?pageSize=2147483648', 400, msgObj.pageSize.tooBig, done); + }); + + /** + * Test when sortOrder is invalid. + */ + it('should return bad request. The sortOrder is invalid.', function (done) { + assertBadResponse('heffan', '?sortOrder=abc&sortColumn=type', 400, msgObj.invalidSortOrder, done); + }); + + /** + * Test when sortColumn is invalid. + */ + it('should return bad request. The sortColumn is invalid.', function (done) { + assertBadResponse('heffan', '?sortColumn=abc', 400, msgObj.invalidSortColumn, done); + }); + + /** + * The sortColumn is missing. + */ + it('should return bad request. The sortColumn is missing.', function (done) { + assertBadResponse('heffan', '?sortOrder=asc', 400, msgObj.missingSortColumn, done); + }); + + /** + * Test success results. + */ + it('should return success results.', function (done) { + assertSuccessResponse('heffan', '', 'test_files/getUserAlgoChallenges/expected_response_1', done); + }); + + /** + * The given user hasn't do any marathon matches. + */ + it('should return success results. The given user have no marathon matches.', function (done) { + assertSuccessResponse('user10', '', 'test_files/getUserAlgoChallenges/expected_response_2', done); + }); + + /** + * The given user is not activated. + */ + it('should return bad request. The given user is not activated.', function (done) { + assertBadResponse('user2', '', 400, msgObj.inActivatedUser, done); + }); + + /** + * Test pageIndex filter. + */ + it('should return success results. Test pageIndex filter.', function (done) { + assertSuccessResponse('heffan', '?pageIndex=2', 'test_files/getUserAlgoChallenges/expected_response_3', done); + }); + + /** + * Test when pageIndex = -1 + */ + it('should return success results. Test pageIndex=-1.', function (done) { + assertSuccessResponse('heffan', '?pageIndex=-1', 'test_files/getUserAlgoChallenges/expected_response_7', done); + }); + + /** + * Test pageSize filter. + */ + it('should return success results. Test pageSize filter.', function (done) { + assertSuccessResponse('heffan', '?pageSize=1', 'test_files/getUserAlgoChallenges/expected_response_4', done); + }); + + /** + * Test sortOrder filter. + */ + it('should return success results. Test sortOrder filter.', function (done) { + assertSuccessResponse('heffan', '?sortOrder=desc&sortColumn=id', 'test_files/getUserAlgoChallenges/expected_response_5', done); + }); + + /** + * Test sortColumn filter. + */ + it('should return success results. Test sortColumn filter.', function (done) { + assertSuccessResponse('heffan', '?sortColumn=numSubmitters', 'test_files/getUserAlgoChallenges/expected_response_6', done); + }); + +}); diff --git a/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json b/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json new file mode 100644 index 000000000..81e694828 --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json @@ -0,0 +1,22 @@ +{ + "pageIndex" : { + "notNumber": "pageIndex should be number.", + "notPositive": "pageIndex should be equal to -1 or greater than 0", + "notInteger": "pageIndex should be Integer.", + "tooBig": "pageIndex should be less or equal to 2147483647." + }, + "pageSize" : { + "notNumber": "pageSize should be number.", + "notPositive": "pageSize should be positive.", + "notInteger": "pageSize should be Integer.", + "tooBig": "pageSize should be less or equal to 2147483647." + }, + "handle": { + "tooLong": "handle exceeds 30 characters.", + "notExisted": "User does not exist." + }, + "invalidSortOrder": "sortOrder should be an element of asc,desc.", + "invalidSortColumn": "The sort column 'abc' is invalid, it should be element of id,type,prize,codingDuration,placement,numContestants,numSubmitters.", + "missingSortColumn": "The sortColumn is missing.", + "inActivatedUser": "User is not activated." +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_1.json b/test/test_files/getUserAlgoChallenges/expected_response_1.json new file mode 100644 index 000000000..e61a52a5a --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_1.json @@ -0,0 +1,44 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 3, + "data": [ + { + "id": 2001, + "prize": true, + "codingDuration": 21967000, + "placement": 1, + "numContestants": 8, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C#", + "Java" + ] + }, + { + "id": 2002, + "prize": false, + "codingDuration": 1767000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 7, + "platforms": [], + "technologies": [ + "C++" + ] + }, + { + "id": 2003, + "prize": true, + "codingDuration": 98167000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 2, + "platforms": [], + "technologies": [ + "XML" + ] + } + ] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_2.json b/test/test_files/getUserAlgoChallenges/expected_response_2.json new file mode 100644 index 000000000..f9400219a --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_2.json @@ -0,0 +1,6 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 0, + "data": [] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_3.json b/test/test_files/getUserAlgoChallenges/expected_response_3.json new file mode 100644 index 000000000..13b43744c --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_3.json @@ -0,0 +1,6 @@ +{ + "pageIndex": 2, + "pageSize": 10, + "total": 3, + "data": [] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_4.json b/test/test_files/getUserAlgoChallenges/expected_response_4.json new file mode 100644 index 000000000..f6acc80e4 --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_4.json @@ -0,0 +1,20 @@ +{ + "pageIndex": 1, + "pageSize": 1, + "total": 3, + "data": [ + { + "id": 2001, + "prize": true, + "codingDuration": 21967000, + "placement": 1, + "numContestants": 8, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C#", + "Java" + ] + } + ] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_5.json b/test/test_files/getUserAlgoChallenges/expected_response_5.json new file mode 100644 index 000000000..6157129eb --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_5.json @@ -0,0 +1,44 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 3, + "data": [ + { + "id": 2003, + "prize": true, + "codingDuration": 98167000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 2, + "platforms": [], + "technologies": [ + "XML" + ] + }, + { + "id": 2002, + "prize": false, + "codingDuration": 1767000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 7, + "platforms": [], + "technologies": [ + "C++" + ] + }, + { + "id": 2001, + "prize": true, + "codingDuration": 21967000, + "placement": 1, + "numContestants": 8, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C#", + "Java" + ] + } + ] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_6.json b/test/test_files/getUserAlgoChallenges/expected_response_6.json new file mode 100644 index 000000000..c344b7a3e --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_6.json @@ -0,0 +1,44 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 3, + "data": [ + { + "id": 2003, + "prize": true, + "codingDuration": 98167000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 2, + "platforms": [], + "technologies": [ + "XML" + ] + }, + { + "id": 2001, + "prize": true, + "codingDuration": 21967000, + "placement": 1, + "numContestants": 8, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C#", + "Java" + ] + }, + { + "id": 2002, + "prize": false, + "codingDuration": 1767000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 7, + "platforms": [], + "technologies": [ + "C++" + ] + } + ] +} diff --git a/test/test_files/getUserAlgoChallenges/expected_response_7.json b/test/test_files/getUserAlgoChallenges/expected_response_7.json new file mode 100644 index 000000000..54c95517b --- /dev/null +++ b/test/test_files/getUserAlgoChallenges/expected_response_7.json @@ -0,0 +1,44 @@ +{ + "pageIndex": 1, + "pageSize": 2147483647, + "total": 3, + "data": [ + { + "id": 2001, + "prize": true, + "codingDuration": 21967000, + "placement": 1, + "numContestants": 8, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C#", + "Java" + ] + }, + { + "id": 2002, + "prize": false, + "codingDuration": 1767000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 7, + "platforms": [], + "technologies": [ + "C++" + ] + }, + { + "id": 2003, + "prize": true, + "codingDuration": 98167000, + "placement": 1, + "numContestants": 9, + "numSubmitters": 2, + "platforms": [], + "technologies": [ + "XML" + ] + } + ] +} From 83f7601f6460ea8d8c86b66d2601ea928892ce4d Mon Sep 17 00:00:00 2001 From: Ghost141 Date: Mon, 8 Dec 2014 20:07:57 +0800 Subject: [PATCH 2/3] TC API - User Marathon Matches API --- actions/memberStatistics.js | 90 +----- actions/user.js | 161 ++++++++++- apiary.apib | 157 +++++++++++ initializers/helper.js | 72 ++++- queries/get_user_marathon_matches | 33 +++ queries/get_user_marathon_matches.json | 5 + queries/get_user_marathon_matches_count | 20 ++ queries/get_user_marathon_matches_count.json | 5 + routes.js | 5 +- .../getUserMarathonMatches/topcoder_dw__clean | 13 + .../topcoder_dw__insert_test_data | 113 ++++++++ test/test.getUserMarathonMatches.js | 261 ++++++++++++++++++ ...t_user_marathon_matches_error_message.json | 22 ++ .../expected_response_1.json | 37 +++ .../expected_response_2.json | 6 + .../expected_response_3.json | 6 + .../expected_response_4.json | 22 ++ .../expected_response_5.json | 37 +++ .../expected_response_6.json | 37 +++ .../expected_response_7.json | 37 +++ 20 files changed, 1036 insertions(+), 103 deletions(-) create mode 100644 queries/get_user_marathon_matches create mode 100644 queries/get_user_marathon_matches.json create mode 100644 queries/get_user_marathon_matches_count create mode 100644 queries/get_user_marathon_matches_count.json create mode 100644 test/sqls/getUserMarathonMatches/topcoder_dw__clean create mode 100644 test/sqls/getUserMarathonMatches/topcoder_dw__insert_test_data create mode 100644 test/test.getUserMarathonMatches.js create mode 100644 test/test_files/getUserMarathonMatches/expected_get_user_marathon_matches_error_message.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_1.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_2.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_3.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_4.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_5.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_6.json create mode 100644 test/test_files/getUserMarathonMatches/expected_response_7.json diff --git a/actions/memberStatistics.js b/actions/memberStatistics.js index be9a125d7..e17ad55e0 100644 --- a/actions/memberStatistics.js +++ b/actions/memberStatistics.js @@ -63,48 +63,6 @@ var STUDIO_ID = 6; var OPENAIM_ID = 8; var HIGH_SCHOOL_ID = 3; -/** - * check whether given user is activated. - * @param {String} handle - the handle to check. - * @param {Object} api - the action hero api object - * @param {Object} dbConnectionMap - the database connection map - * @param {Function} callback - the callback function - */ -function checkCoderActivated(handle, api, dbConnectionMap, callback) { - api.dataAccess.executeQuery('check_coder_activated', { handle: handle }, dbConnectionMap, function (err, result) { - if (err) { - callback(err, null); - return; - } - if (result && result[0] && result[0].status === 'A') { - callback(err, null); - } else { - callback(err, new BadRequestError('User is not activated.')); - } - }); -} - -///** -// * Check whether given user is activated. -// * @param {String} handle - the handle to check. -// * @param {Object} api - the action hero api object -// * @param {Object} dbConnectionMap - the database connection map -// * @param {Function} callback - the callback function -// */ -//function checkUserActivated(handle, api, dbConnectionMap, callback) { -// api.dataAccess.executeQuery('check_user_activated', { handle: handle }, dbConnectionMap, function (err, result) { -// if (err) { -// callback(err, null); -// return; -// } -// if (result && result[0] && result[0].status === 'A') { -// callback(err, null); -// } else { -// callback(err, new BadRequestError('User is not activated.')); -// } -// }); -//} - /** * Update user preference. * @@ -183,42 +141,6 @@ function updateDemographicResponse(key, value, questionId, userId, api, dbConnec } -/** - * Check if the user exist and activated. - * @param {String} handle - the user handle. - * @param {Object} api - the api object. - * @param {Object} dbConnectionMap - the database connection map object. - * @param {Function} callback - the callback function. - * @since 1.10 - */ -function checkUserExistAndActivate(handle, api, dbConnectionMap, callback) { - async.waterfall([ - function (cb) { - // check user existence and activated status. - async.parallel({ - exist: function (cb) { - api.helper.checkUserExists(handle, api, dbConnectionMap, cb); - }, - activate: function (cb) { - checkCoderActivated(handle, api, dbConnectionMap, cb); - } - }, cb); - }, - function (results, cb) { - // handle the error situation. - if (results.exist) { - cb(results.exist); - return; - } - if (results.activate) { - cb(results.activate); - return; - } - cb(); - } - ], callback); -} - /** * Get the user basic profile information. * @param {Object} api - the api object. @@ -270,7 +192,7 @@ function getBasicUserProfile(api, handle, privateInfoEligibility, dbConnectionMa } }); } else { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); } }, function (cb) { var execQuery = function (name) { @@ -785,7 +707,7 @@ exports.getMarathonStatistics = { } async.waterfall([ function (cb) { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var executeQuery = function (sqlName, cbx) { api.dataAccess.executeQuery(sqlName, sqlParams, dbConnectionMap, cbx); @@ -899,7 +821,7 @@ exports.getSoftwareStatistics = { cb(); } }, function (cb) { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name, cbx) { api.dataAccess.executeQuery(name, @@ -1036,7 +958,7 @@ exports.getStudioStatistics = { async.waterfall([ function (cb) { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { api.dataAccess.executeQuery('get_studio_member_statistics_track', sqlParams, dbConnectionMap, cb); }, function (results, cb) { @@ -1105,7 +1027,7 @@ exports.getAlgorithmStatistics = { } async.waterfall([ function (cb) { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name) { return function (cbx) { @@ -1498,7 +1420,7 @@ exports.getCopilotStatistics = { cb(); } }, function (cb) { - checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name, cbx) { api.dataAccess.executeQuery(name, diff --git a/actions/user.js b/actions/user.js index c7c4d960b..70e958556 100644 --- a/actions/user.js +++ b/actions/user.js @@ -1,12 +1,14 @@ /* * Copyright (C) 2014 TopCoder Inc., All Rights Reserved. * - * @version 1.2 + * @version 1.3 * @author muzehyun, Ghost_141 * Changes in 1.1: * - Implement user activation email api. * Changes in 1.2: * - Implement get user identity api. + * Changes in 1.3: + * - Implement get user marathon match api. */ 'use strict'; var async = require('async'); @@ -29,6 +31,13 @@ var activationEmailSubject = "Topcoder User Registration Activation"; */ var activationEmailSenderName = "Topcoder API"; +/** + * The valid sort column for get user marathon matches api. + * @since 1.3 + */ +var VALID_SORT_COLUMN_MARATHON_MATCH = ['id', 'type', 'codingDuration', 'placement', 'numContestants', + 'numSubmitters']; + /** * It validates activation code and retrieves user id from activation code * @param {String} activationCode - activation code string @@ -332,7 +341,7 @@ exports.getUserIdentity = { * @since 1.2 */ function getUserIdentityByAuth0Id(api, connection, next) { - var helper = api.helper, + var helper = api.helper, auth0id = connection.params.id, userid = 0, dbConnectionMap = connection.dbConnectionMap, @@ -343,24 +352,23 @@ function getUserIdentityByAuth0Id(api, connection, next) { function (cb) { try { var splits = auth0id.split('|'); - if (splits[0] == 'ad') { + if (splits[0] === 'ad') { cb(null, [{ user_id: Number(splits[1]) }]); } else { - api.helper.getProviderId(splits[0], function(err, provider) { + api.helper.getProviderId(splits[0], function (err, provider) { if (err) { cb(notfound); } else { api.dataAccess.executeQuery("get_user_by_social_login", - { - social_user_id: splits[1], - provider_id: provider - }, - dbConnectionMap, cb); + { + social_user_id: splits[1], + provider_id: provider + }, + dbConnectionMap, cb); } }); } - } - catch (exc) { + } catch (exc) { cb(notfound); } }, @@ -368,10 +376,10 @@ function getUserIdentityByAuth0Id(api, connection, next) { if (!result[0]) { cb(notfound); } else { - userid = result[0].user_id - api.dataAccess.executeQuery('get_user_email_and_handle', - { userId: userid }, - dbConnectionMap, cb); + userid = result[0].user_id; + api.dataAccess.executeQuery('get_user_email_and_handle', + { userId: userid }, + dbConnectionMap, cb); } }, function (rs, cb) { @@ -422,3 +430,126 @@ exports.getUserIdentityByAuth0Id = { } } }; + +/** + * Handle the get marathon matches that user participated to. + * @param {Object} api - The api object. + * @param {Object} connection - The connection object. + * @param {Function} next - The callback function. + * @since 1.3 + */ +function getUserMarathonMatches(api, connection, next) { + var helper = api.helper, dbConnectionMap = connection.dbConnectionMap, response, sqlParams, sortOrder, sortColumn, + exeQuery = function (name) { + return function (cbx) { + api.dataAccess.executeQuery(name, sqlParams, dbConnectionMap, cbx); + }; + }, + handle = connection.params.handle, + pageIndex = Number(connection.params.pageIndex || 1), + pageSize = Number(connection.params.pageSize || 10); + + sortOrder = (connection.params.sortOrder || "asc").toLowerCase(); + sortColumn = connection.params.sortColumn || "id"; + + // If the sortOrder is set and sortColumn is missing. + if (connection.params.sortOrder && !connection.params.sortColumn) { + helper.handleError(api, connection, new BadRequestError('The sortColumn is missing.')); + next(connection, true); + return; + } + + if (pageIndex === -1) { + pageSize = helper.MAX_INT; + pageIndex = 1; + } + + //reverse the sorting direction value because for placement 1 is the best so the descending order should be like 1, 2, 3. + if (sortColumn.toLowerCase() === 'placement') { + sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'; + } + + async.waterfall([ + function (cb) { + var error = helper.checkPageIndex(pageIndex, "pageIndex") + || helper.checkStringParameter(handle, "handle", 30) + || helper.checkPositiveInteger(pageSize, "pageSize") + || helper.checkMaxInt(pageSize, "pageSize") + || helper.checkContains(['asc', 'desc'], sortOrder, "sortOrder") + || helper.checkSortColumn(VALID_SORT_COLUMN_MARATHON_MATCH, sortColumn.toLowerCase()); + cb(error); + }, + function (cb) { + helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + }, + function (cb) { + sqlParams = { + first_row_index: (pageIndex - 1) * pageSize, + page_size: pageSize, + sort_order: sortOrder, + sort_column: helper.getSortColumnDBName(sortColumn), + handle: handle.toLowerCase() + }; + async.parallel({ + data: exeQuery('get_user_marathon_matches'), + count: exeQuery('get_user_marathon_matches_count') + }, cb); + }, + function (queryResult, cb) { + var total = queryResult.count[0].total_count; + response = { + pageIndex: pageIndex, + pageSize: pageSize, + total: total, + data: queryResult.data.map(function (row) { + return { + id: row.id, + type: row.type, + prize: row.paid > 0, + codingDuration: row.coding_duration, + placement: row.placement, + numContestants: row.num_contestants, + numSubmitters: row.num_submitters, + platforms: [], + technologies: row.technologies.length === 0 + ? [] : row.technologies.split(',').map(function (s) { return s.trim(); }) + }; + }) + }; + cb(); + } + ], function (err) { + if (err) { + helper.handleError(api, connection, err); + } else { + connection.response = response; + } + next(connection, true); + }); +} + +/** + * The api for get user marathon matches. + * @since 1.3 + */ +exports.getUserMarathonMatches = { + name: 'getUserMarathonMatches', + description: 'Get marathon match related info that member has participated to', + inputs: { + required: ['handle'], + optional: ["sortOrder", "pageIndex", "pageSize", "sortColumn"] + }, + blockedConnectionTypes: [], + outputExample: {}, + version: 'v2', + transaction: 'read', + databases: ['topcoder_dw'], + run: function (api, connection, next) { + if (connection.dbConnectionMap) { + api.log('getUserMarathonMatches#run', 'debug'); + getUserMarathonMatches(api, connection, next); + } else { + api.helper.handleNoConnection(api, connection, next); + } + } +}; diff --git a/apiary.apib b/apiary.apib index 235aef0c5..6bb17182b 100644 --- a/apiary.apib +++ b/apiary.apib @@ -2343,6 +2343,163 @@ Request } +## Get User Marathon Matches Information [/user/{handle}/challenges/marathon?pageIndex={pageIndex}&pageSize={pageSize}&sortColumn={sortColumn}&sortOrder={sortOrder}] +### Get User Marathon Matches Information [GET] + ++ Parameters + + handle (required, string, `heffan`) ... the user handle that to search + + pageIndex (optional, number, `1`) ... The page index of the returned resources. 1-based. It can be null. The default value will be 1 + + pageSize (optional, number, `10`) ... The page size of the returned resources. 1-based. It can be null. The default value will be 10. + + sortColumn (optional, string, `id`) ... The column name to sort, can be null. The valid value are 'id', 'type', 'placement', 'numContestants', 'numSubmitters', 'codingDuration'. + + sortOrder (optional, string, `asc`) ... The sorting order, can be null. If it's set, it can only be 'asc' or 'desc'. + + ++ Response 200 (application/json) + + { + "total": 1, + "pageIndex": 1, + "pageSize": 10, + "data": [ + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "placement": 1, + "prize": true, + "numContestants": 14, + "numSubmitters": 6, + "codingDuration": 30000000, + "platforms": [], + "technologies": [ + "Java", + "C++" + ] + } + ] + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be number." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be equal to -1 or greater than 0" + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be Integer." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageIndex should be less or equal to 2147483647." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be number." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be positive." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be Integer." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "pageSize should be less or equal to 2147483647." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "" + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "handle exceeds 30 characters." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "User does not exist." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "sortOrder should be an element of asc,desc." + } + ++ Response 400 (application/json) + { + "name": "Bad Request", + "value": 400, + "description": "The request was invalid. An accompanying message will explain why.", + "details": "The sort column 'abc' is invalid, it should be element of id,type,prize,codingDuration,placement,numContestants,numSubmitters." + } + ++ Response 500 (application/json) + + { + "name":"Internal Server Error", + "value":"500", + "description":"Unknown server error. Please contact support." + } + ++ Response 503 (application/json) + + { + "name":"Service Unavailable", + "value":"503", + "description":"Servers are up but overloaded. Try again later." + } + + + ## Validate Handle [/users/validate/{handle}] ### Validate Handle [GET] diff --git a/initializers/helper.js b/initializers/helper.js index b75eb804f..9f8907557 100644 --- a/initializers/helper.js +++ b/initializers/helper.js @@ -5,8 +5,8 @@ /** * This module contains helper functions. - * @author Sky_, Ghost_141, muzehyun, kurtrips, isv, LazyChild, hesibo, panoptimum, flytoj2ee - * @version 1.38 + * @author Sky_, Ghost_141, muzehyun, kurtrips, isv, LazyChild, hesibo, panoptimum, flytoj2ee, TCSASSEMBLER + * @version 1.39 * changes in 1.1: * - add mapProperties * changes in 1.2: @@ -101,6 +101,9 @@ * - Updated checkDates function to accept optional 'errorMessage' parameter. * Changes in 1.38: * - Add method editSql, readQuery and constant QUERY_PATH. + * Changes in 1.39: + * - Update apiName2dbNameMap to add entries for coding_duration, num_contestants and num_submitters. + * - Move checkUserExistAndActivated method from actions/memberStatistics.js to this file. */ "use strict"; @@ -256,7 +259,10 @@ var apiName2dbNameMap = { problemid: 'problem_id', problemname: 'problem_name', problemtype: 'problem_type', - mypoints: 'my_points' + mypoints: 'my_points', + codingduration: 'coding_duration', + numcontestants: 'num_contestants', + numsubmitters: 'num_submitters' }; /** @@ -1584,6 +1590,7 @@ helper.checkUserExists = function (handle, api, dbConnectionMap, callback) { /** * Check whether given user is activated. + * The method will fetch data from common_oltp.user table and check status field. * @param {String} handle - the handle to check. * @param {Object} api - the action hero api object * @param {Object} dbConnectionMap - the database connection map @@ -1603,6 +1610,65 @@ helper.checkUserActivated = function (handle, api, dbConnectionMap, callback) { }); }; +/** + * check whether given coder is activated. + * The method will fetch data from topcoder_dw.coder table and check status field. + * @param {String} handle - the handle to check. + * @param {Object} api - the action hero api object + * @param {Object} dbConnectionMap - the database connection map + * @param {Function} callback - the callback function + * @since 1.39 + */ +helper.checkCoderActivated = function (handle, api, dbConnectionMap, callback) { + api.dataAccess.executeQuery('check_coder_activated', { handle: handle }, dbConnectionMap, function (err, result) { + if (err) { + callback(err, null); + return; + } + if (result && result[0] && result[0].status === 'A') { + callback(err, null); + } else { + callback(err, new BadRequestError('User is not activated.')); + } + }); +}; + +/** + * Check if the user exist and activated. + * @param {String} handle - the user handle. + * @param {Object} api - the api object. + * @param {Object} dbConnectionMap - the database connection map object. + * @param {Function} callback - the callback function. + * @since 1.39 + */ +helper.checkUserExistAndActivate = function (handle, api, dbConnectionMap, callback) { + async.waterfall([ + function (cb) { + // check user existence and activated status. + async.parallel({ + exist: function (cb) { + api.helper.checkUserExists(handle, api, dbConnectionMap, cb); + }, + activate: function (cb) { + api.helper.checkCoderActivated(handle, api, dbConnectionMap, cb); + } + }, cb); + }, + function (results, cb) { + // handle the error situation. + if (results.exist) { + cb(results.exist); + return; + } + if (results.activate) { + cb(results.activate); + return; + } + cb(); + } + ], callback); +}; + /** * Validate the given password value. * @param {String} password - the password value. diff --git a/queries/get_user_marathon_matches b/queries/get_user_marathon_matches new file mode 100644 index 000000000..d777d9081 --- /dev/null +++ b/queries/get_user_marathon_matches @@ -0,0 +1,33 @@ +SELECT +SKIP @first_row_index@ +FIRST @page_size@ + lcr.round_id AS id +, lcr.placed AS placement +, NVL(rr.paid, 0) AS paid +, (SELECT count(*) FROM long_comp_result WHERE round_id = r.round_id AND attended = 'Y') AS num_contestants +, (SELECT count(*) FROM long_comp_result WHERE round_id = r.round_id AND attended = 'Y' AND num_submissions > 0) AS num_submitters +, r.round_type_desc AS type +, user_marathon_match_language(lcr.coder_id, p.problem_id, r.round_id) AS technologies +, (((extend(dbinfo("UTC_TO_DATETIME", + (SELECT MAX(submit_time) FROM long_problem_submission lps WHERE lps.round_id = r.round_id AND lps.problem_id = p.problem_id AND lps.coder_id = co.coder_id)/1000) + , YEAR TO fraction) - c.start_date)::INTERVAL SECOND(9) to second) * 1000)::char(10)::INT8 AS coding_duration +FROM long_comp_result lcr +, round r +, contest c +, room ro +, room_result rr +, problem p +, coder co +WHERE lcr.round_id = r.round_id +AND c.contest_id = r.contest_id +AND lcr.coder_id = co.coder_id +AND co.handle_lower = '@handle@' +AND ro.round_id = r.round_id +AND rr.room_id = ro.room_id +AND rr.round_id = r.round_id +AND rr.coder_id = co.coder_id +AND p.round_id = r.round_id +AND lcr.attended = 'Y' +AND rr.problems_submitted > 0 -- Has submitted. +AND r.round_type_id IN (10,13,15,19,22,24,25,27) +ORDER BY @sort_column@ @sort_order@ diff --git a/queries/get_user_marathon_matches.json b/queries/get_user_marathon_matches.json new file mode 100644 index 000000000..5628df9ab --- /dev/null +++ b/queries/get_user_marathon_matches.json @@ -0,0 +1,5 @@ +{ + "name" : "get_user_marathon_matches", + "db" : "topcoder_dw", + "sqlfile" : "get_user_marathon_matches" +} diff --git a/queries/get_user_marathon_matches_count b/queries/get_user_marathon_matches_count new file mode 100644 index 000000000..f74c7e621 --- /dev/null +++ b/queries/get_user_marathon_matches_count @@ -0,0 +1,20 @@ +SELECT COUNT(*) AS total_count +FROM long_comp_result lcr +, round r +, contest c +, room ro +, room_result rr +, problem p +, coder co +WHERE lcr.round_id = r.round_id +AND c.contest_id = r.contest_id +AND lcr.coder_id = co.coder_id +AND co.handle_lower = '@handle@' +AND ro.round_id = r.round_id +AND rr.room_id = ro.room_id +AND rr.round_id = r.round_id +AND rr.coder_id = co.coder_id +AND p.round_id = r.round_id +AND lcr.attended = 'Y' +AND rr.problems_submitted > 0 -- Has submitted. +AND r.round_type_id IN (10,13,15,19,22,24,25,27) diff --git a/queries/get_user_marathon_matches_count.json b/queries/get_user_marathon_matches_count.json new file mode 100644 index 000000000..6042d732d --- /dev/null +++ b/queries/get_user_marathon_matches_count.json @@ -0,0 +1,5 @@ +{ + "name" : "get_user_marathon_matches_count", + "db" : "topcoder_dw", + "sqlfile" : "get_user_marathon_matches_count" +} diff --git a/routes.js b/routes.js index 24fd7090f..d6c9f226d 100755 --- a/routes.js +++ b/routes.js @@ -1,7 +1,7 @@ /* * Copyright (C) 2013 - 2014 TopCoder Inc., All Rights Reserved. * - * @version 1.62 + * @version 1.63 * @author vangavroche, Sky_, muzehyun, kurtrips, Ghost_141, ecnu_haozi, hesibo, LazyChild, isv, flytoj2ee, * @author panoptimum, bugbuka, Easyhard, TCASSEMBLER * @@ -144,6 +144,8 @@ * - Added routes for modifying/deleting round question answers. * Changes in 1.62: * - Added route for src2image api. + * Changes in 1.63: + * - Add route for get user marathon matches api. */ /*jslint node:true, nomen: true */ "use strict"; @@ -262,6 +264,7 @@ exports.routes = { { path: "/:apiVersion/user/activation-email", action: "userActivationEmail" }, { path: "/:apiVersion/user/tcid/:id", action: "getUserIdentityByAuth0Id" }, { path: "/:apiVersion/user/identity", action: "getUserIdentity" }, + { path: "/:apiVersion/user/:handle/challenges/marathon", action: "getUserMarathonMatches" }, { path: "/:apiVersion/users/tops/:trackType", action: "getTopTrackMembers" }, { path: "/:apiVersion/users/resetToken", action: "generateResetToken" }, diff --git a/test/sqls/getUserMarathonMatches/topcoder_dw__clean b/test/sqls/getUserMarathonMatches/topcoder_dw__clean new file mode 100644 index 000000000..90f55b9e2 --- /dev/null +++ b/test/sqls/getUserMarathonMatches/topcoder_dw__clean @@ -0,0 +1,13 @@ +DELETE FROM long_comp_result WHERE round_id IN (2001, 2002, 2003); +DELETE FROM room_result; +DELETE FROM problem WHERE round_id IN (2001, 2002, 2003); +DELETE FROM room; +DELETE FROM round WHERE round_id IN (2001, 2002, 2003); +DELETE FROM contest WHERE contest_id IN (2001, 2002, 2003); +DELETE FROM round_type_lu; +DELETE FROM algo_rating_type_lu; +DELETE FROM division_lu; +DELETE FROM room_type_lu; +DELETE FROM language_lu; +DELETE FROM long_problem_submission; +DELETE FROM coder; diff --git a/test/sqls/getUserMarathonMatches/topcoder_dw__insert_test_data b/test/sqls/getUserMarathonMatches/topcoder_dw__insert_test_data new file mode 100644 index 000000000..df112b104 --- /dev/null +++ b/test/sqls/getUserMarathonMatches/topcoder_dw__insert_test_data @@ -0,0 +1,113 @@ +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (1, 'TopCoder Rating'); +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (2, 'TopCoder High School Rating'); +INSERT INTO algo_rating_type_lu(algo_rating_type_id,algo_rating_type_desc) VALUES (3, 'Marathon Match Rating'); + +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (1, 'Admin'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (2, 'Contest'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (3, 'Practice'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (5, 'Lobby'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (4, 'Moderated Chat Room'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (6, 'Team Contest'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (7, 'Team Practice'); +INSERT INTO room_type_lu(room_type_id,room_type_desc) VALUES (8, 'Team Admin'); + +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (1, 'Single Round Match', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (2, 'Tournament Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (3, 'Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (4, 'Moderated Chat Session', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (10, 'Long Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (6, 'Screening Tool Problem Sets', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (11, 'Weakest Link Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (7, 'Team Single Round Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (8, 'Team Tournament Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (9, 'Team Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (12, 'Private Label Tournament', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (13, 'Marathon Match', 3); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (14, 'Marathon Match Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (15, 'Intel Marathon Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (16, 'Intel Marathon Match Practice Round', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (17, 'HS Single Round Match', 2); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (18, 'HS Tournament Round', 2); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (19, 'Marathon Match Tournament Round', 3); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (20, 'Intro Event Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (21, 'Education Round', 1); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (22, 'AMD Marathon Match', NULL); +INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (23, 'AMD Marathon Match Practice', NULL); + +INSERT INTO division_lu(division_id,division_desc) VALUES (-1, 'No Division Applicable'); +INSERT INTO division_lu(division_id,division_desc) VALUES (0, 'Unrated Division'); +INSERT INTO division_lu(division_id,division_desc) VALUES (1, 'Division-I'); +INSERT INTO division_lu(division_id,division_desc) VALUES (2, 'Division-II'); + +INSERT INTO language_lu(language_id,language_name,status) VALUES (7,'R','Y'); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (1, 'Java', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (3, 'C++', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (2, 'XML', 'N', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (4, 'C#', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (5, 'VB', 'Y', ''); +INSERT INTO language_lu(language_id,language_name,status,language_desc) VALUES (6, 'Python', 'Y', ''); + +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(132456, 'heffan', 'heffan', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300001, 'user1', 'user1', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300002, 'user2', 'user2', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300003, 'user3', 'user3', 'U'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300004, 'user4', 'user4', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300005, 'user5', 'user5', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300006, 'user6', 'user6', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300007, 'user7', 'user7', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300008, 'user8', 'user8', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300009, 'user9', 'user9', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300010, 'user10', 'user10', 'A'); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2001, 'Contest 2001', "2014-12-10 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id, round_type_desc) VALUES(2001, 2001, 'Round 2001', 19, 'Marathon Match Tournament Round'); +INSERT INTO room(round_id, room_id, name, room_type_id, division_id) VALUES(2001, 2001, 'Room 2001', 2, 1); + +INSERT INTO problem(problem_id, round_id, division_id, result_type_id, method_name, class_name) VALUES(2001, 2001, 1, 1, 'abc', 'Main'); + +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2001, 132456, 'Y', 1, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2001, 300001, 'Y', 2, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2001, 300002, 'Y', 3, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, num_submissions) VALUES(2001, 300003, 'Y', 0); +INSERT INTO long_comp_result(round_id, coder_id, attended, num_submissions) VALUES(2001, 300004, 'Y', 0); +INSERT INTO long_comp_result(round_id, coder_id, attended, num_submissions) VALUES(2001, 300005, 'Y', 0); + +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2001, 132456, 2001, 1, 1418205404618, 1, 1); +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2001, 132456, 2001, 5, 1418205576592, 2, 1); +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2001, 132456, 2001, 2, 1418204576592, 3, 1); + +INSERT INTO room_result(round_id, room_id, coder_id, problems_submitted, paid) VALUES(2001, 2001, 132456, 1, 100); +INSERT INTO room_result(round_id, room_id, coder_id, problems_submitted) VALUES(2001, 2001, 300001, 1); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2002, 'Contest 2002', "2014-12-10 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id, round_type_desc) VALUES(2002, 2002, 'Round 2002', 19, 'Marathon Match Tournament Round'); +INSERT INTO room(round_id, room_id, name, room_type_id, division_id) VALUES(2002, 2002, 'Room 2002', 2, 1); + +INSERT INTO problem(problem_id, round_id, division_id, result_type_id, method_name, class_name) VALUES(2002, 2002, 1, 1, 'abc', 'Main'); + +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2002, 132456, 'Y', 1, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2002, 300001, 'Y', 2, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2002, 300002, 'Y', 3, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2002, 300003, 'Y', 4, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, num_submissions) VALUES(2002, 300005, 'Y', 0); + + +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2002, 132456, 2002, 1, 1418205576592, 1, 1); +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2002, 132456, 2002, 6, 1418205576592, 2, 1); +INSERT INTO long_problem_submission(round_id, coder_id, problem_id, language_id, submit_time, submission_number, example) VALUES(2002, 132456, 2002, 3, 1418215576592, 3, 1); + +INSERT INTO room_result(round_id, room_id, coder_id, problems_submitted) VALUES(2002, 2002, 132456, 1); +INSERT INTO room_result(round_id, room_id, coder_id, problems_submitted) VALUES(2002, 2002, 300001, 1); + +INSERT INTO contest(contest_id, name, start_date) VALUES(2003, 'Contest 2003', "2014-12-10 00:00:00"); +INSERT INTO round(round_id, contest_id, name, round_type_id, round_type_desc) VALUES(2003, 2003, 'Round 2003', 19, 'Marathon Match Tournament Round'); +INSERT INTO room(round_id, room_id, name, room_type_id, division_id) VALUES(2003, 2003, 'Room 2003', 2, 1); + +INSERT INTO problem(problem_id, round_id, division_id, result_type_id, method_name, class_name) VALUES(2003, 2003, 1, 1, 'abc', 'Main'); + +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2003, 300001, 'Y', 2, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2003, 300002, 'Y', 3, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, placed, num_submissions) VALUES(2003, 300003, 'Y', 4, 5); +INSERT INTO long_comp_result(round_id, coder_id, attended, num_submissions) VALUES(2003, 300005, 'Y', 0); + +INSERT INTO room_result(round_id, room_id, coder_id, problems_submitted) VALUES(2003, 2003, 300001, 1); diff --git a/test/test.getUserMarathonMatches.js b/test/test.getUserMarathonMatches.js new file mode 100644 index 000000000..0998a2169 --- /dev/null +++ b/test/test.getUserMarathonMatches.js @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2014 TopCoder Inc., All Rights Reserved. + * + * @version 1.0 + * @author Ghost_141 + */ +'use strict'; +/*global describe, it, before, beforeEach, after, afterEach */ +/*jslint node: true, stupid: true, unparam: true */ + +/** + * Module dependencies. + */ +var request = require('supertest'); +var assert = require('chai').assert; +var async = require('async'); + +var testHelper = require('./helpers/testHelper'); +var SQL_DIR = __dirname + '/sqls/getUserMarathonMatches/'; +var API_ENDPOINT = process.env.API_ENDPOINT || 'http://localhost:8080'; + +describe('Get User Marathon Matches API', function () { + this.timeout(180000); // The api with testing remote db could be quit slow + + var msgObj = require('../test/test_files/getUserMarathonMatches/expected_get_user_marathon_matches_error_message'); + + /** + * Clear database + * @param {Function} done the callback + */ + function clearDb(done) { + testHelper.runSqlFile(SQL_DIR + "topcoder_dw__clean", "topcoder_dw", done); + } + + /** + * This function is run before all tests. + * Generate tests data. + * @param {Function} done the callback + */ + before(function (done) { + async.waterfall([ + clearDb, + function (cb) { + testHelper.runSqlFile(SQL_DIR + 'topcoder_dw__insert_test_data', 'topcoder_dw', cb); + } + ], done); + }); + + /** + * This function is run after all tests. + * Clean up all data. + * @param {Function} done the callback + */ + after(function (done) { + clearDb(done); + }); + + /** + * create a http request and test it. + * @param {String} handle - the request user handle. + * @param {Number} expectStatus - the expected response status code. + * @param {String} query - The query used in http request. + * @param {Function} cb - the call back function. + */ + function createGetRequest(handle, expectStatus, query, cb) { + request(API_ENDPOINT) + .get('/v2/user/' + handle + '/challenges/marathon' + query) + .set('Accept', 'application/json') + .expect('Content-Type', /json/) + .expect(expectStatus) + .end(cb); + } + + /** + * assert the bad response. + * @param {String} handle - the request handle + * @param {Number} expectStatus - the expect status. + * @param {String} errorMessage - the expected error message. + * @param {String} query - The query used in http request. + * @param {Function} cb - the callback function. + */ + function assertBadResponse(handle, query, expectStatus, errorMessage, cb) { + createGetRequest(handle, expectStatus, query, function (err, result) { + if (!err) { + assert.equal(result.body.error.details, errorMessage, 'invalid error message'); + } else { + cb(err); + return; + } + cb(); + }); + } + + function assertSuccessResponse(handle, query, expectedResponse, cb) { + createGetRequest(handle, 200, query, function (err, result) { + testHelper.assertResponse(err, result, expectedResponse, cb); + }); + } + + /** + * Test when user handle is too long. + */ + it('should return bad request. The user handle is too long.', function (done) { + assertBadResponse('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', '', 400, msgObj.handle.tooLong, done); + }); + + /** + * Test when user handle is not existed. + */ + it('should return bad request. The user handle is not existed.', function (done) { + assertBadResponse('abc', '', 404, msgObj.handle.notExisted, done); + }); + + /** + * Test when pageIndex is not integer. + */ + it('should return bad request. The pageIndex is not integer.', function (done) { + assertBadResponse('heffan', '?pageIndex=1.2345', 400, msgObj.pageIndex.notInteger, done); + }); + + /** + * Test when pageIndex is not number. + */ + it('should return bad request. The pageIndex is not number.', function (done) { + assertBadResponse('heffan', '?pageIndex=abc', 400, msgObj.pageIndex.notNumber, done); + }); + + /** + * Test when pageIndex is zero. + */ + it('should return bad request. The pageIndex is zero.', function (done) { + assertBadResponse('heffan', '?pageIndex=0', 400, msgObj.pageIndex.notPositive, done); + }); + + /** + * Test when pageIndex is too big. + */ + it('should return bad request. The pageIndex is too big.', function (done) { + assertBadResponse('heffan', '?pageIndex=2147483648', 400, msgObj.pageIndex.tooBig, done); + }); + + /** + * Test when pageIndex is not positive and not -1. + */ + it('should return bad request. The pageIndex is not positive and not -1.', function (done) { + assertBadResponse('heffan', '?pageIndex=-2', 400, msgObj.pageIndex.notPositive, done); + }); + + /** + * Test when pageSize is not integer. + */ + it('should return bad request. The pageSize is not integer.', function (done) { + assertBadResponse('heffan', '?pageSize=1.2345', 400, msgObj.pageSize.notInteger, done); + }); + + /** + * Test when pageSize is not number. + */ + it('should return bad request. The pageSize is not number.', function (done) { + assertBadResponse('heffan', '?pageSize=abc', 400, msgObj.pageSize.notNumber, done); + }); + + /** + * Test when pageSize is not positive. + */ + it('should return bad request. The pageSize is not positive.', function (done) { + assertBadResponse('heffan', '?pageSize=-1', 400, msgObj.pageSize.notPositive, done); + }); + + /** + * Test when pageSize is zero. + */ + it('should return bad request. The pageSize is zero.', function (done) { + assertBadResponse('heffan', '?pageSize=0', 400, msgObj.pageSize.notPositive, done); + }); + + /** + * Test when pageSize is too big. + */ + it('should return bad request. The pageSize is too big.', function (done) { + assertBadResponse('heffan', '?pageSize=2147483648', 400, msgObj.pageSize.tooBig, done); + }); + + /** + * Test when sortOrder is invalid. + */ + it('should return bad request. The sortOrder is invalid.', function (done) { + assertBadResponse('heffan', '?sortOrder=abc&sortColumn=id', 400, msgObj.invalidSortOrder, done); + }); + + /** + * Test when sortColumn is invalid. + */ + it('should return bad request. The sortColumn is invalid.', function (done) { + assertBadResponse('heffan', '?sortColumn=abc', 400, msgObj.invalidSortColumn, done); + }); + + /** + * Test when sortColumn is missing. + */ + it('should return bad request. The sortColumn is missing.', function (done) { + assertBadResponse('heffan', '?sortOrder=abc', 400, msgObj.missingSortColumn, done); + }); + + /** + * Test when user is not activated. + */ + it('should return bad request. The user is unactivated.', function (done) { + assertBadResponse('user3', '', 400, msgObj.notActivatedUser, done); + }); + + /** + * Test success results. + */ + it('should return success results.', function (done) { + assertSuccessResponse('heffan', '', 'test_files/getUserMarathonMatches/expected_response_1', done); + }); + + /** + * The given user hasn't do any marathon matches. + */ + it('should return success results. The given user have no marathon matches.', function (done) { + assertSuccessResponse('user10', '', 'test_files/getUserMarathonMatches/expected_response_2', done); + }); + + /** + * Test pageIndex filter. + */ + it('should return success results. Test pageIndex filter.', function (done) { + assertSuccessResponse('heffan', '?pageIndex=2', 'test_files/getUserMarathonMatches/expected_response_3', done); + }); + + /** + * Test pageIndex = -1. + */ + it('should return success results. Test pageIndex = -1.', function (done) { + assertSuccessResponse('heffan', '?pageIndex=-1', 'test_files/getUserMarathonMatches/expected_response_7', done); + }); + + /** + * Test pageSize filter. + */ + it('should return success results. Test pageSize filter.', function (done) { + assertSuccessResponse('heffan', '?pageSize=1', 'test_files/getUserMarathonMatches/expected_response_4', done); + }); + + /** + * Test sortOrder filter. + */ + it('should return success results. Test sortOrder filter.', function (done) { + assertSuccessResponse('heffan', '?sortOrder=desc&sortColumn=id', 'test_files/getUserMarathonMatches/expected_response_5', done); + }); + + /** + * Test sortColumn filter. + */ + it('should return success results. Test sortColumn filter.', function (done) { + assertSuccessResponse('heffan', '?sortColumn=numContestants', 'test_files/getUserMarathonMatches/expected_response_6', done); + }); + +}); diff --git a/test/test_files/getUserMarathonMatches/expected_get_user_marathon_matches_error_message.json b/test/test_files/getUserMarathonMatches/expected_get_user_marathon_matches_error_message.json new file mode 100644 index 000000000..bdd159ece --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_get_user_marathon_matches_error_message.json @@ -0,0 +1,22 @@ +{ + "pageIndex" : { + "notNumber": "pageIndex should be number.", + "notPositive": "pageIndex should be equal to -1 or greater than 0", + "notInteger": "pageIndex should be Integer.", + "tooBig": "pageIndex should be less or equal to 2147483647." + }, + "pageSize" : { + "notNumber": "pageSize should be number.", + "notPositive": "pageSize should be positive.", + "notInteger": "pageSize should be Integer.", + "tooBig": "pageSize should be less or equal to 2147483647." + }, + "handle": { + "tooLong": "handle exceeds 30 characters.", + "notExisted": "User does not exist." + }, + "invalidSortOrder": "sortOrder should be an element of asc,desc.", + "invalidSortColumn": "The sort column 'abc' is invalid, it should be element of id,type,codingDuration,placement,numContestants,numSubmitters.", + "notActivatedUser": "User is not activated.", + "missingSortColumn": "The sortColumn is missing." +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_1.json b/test/test_files/getUserMarathonMatches/expected_response_1.json new file mode 100644 index 000000000..056ede084 --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_1.json @@ -0,0 +1,37 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 2, + "data": [ + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "prize": true, + "codingDuration": 17976000, + "placement": 1, + "numContestants": 6, + "numSubmitters": 3, + "platforms": [], + "technologies": [ + "Java", + "VB", + "XML" + ] + }, + { + "id": 2002, + "type": "Marathon Match Tournament Round", + "prize": false, + "codingDuration": 27976000, + "placement": 1, + "numContestants": 5, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C++", + "Java", + "Python" + ] + } + ] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_2.json b/test/test_files/getUserMarathonMatches/expected_response_2.json new file mode 100644 index 000000000..f9400219a --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_2.json @@ -0,0 +1,6 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 0, + "data": [] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_3.json b/test/test_files/getUserMarathonMatches/expected_response_3.json new file mode 100644 index 000000000..7c7410309 --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_3.json @@ -0,0 +1,6 @@ +{ + "pageIndex": 2, + "pageSize": 10, + "total": 2, + "data": [] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_4.json b/test/test_files/getUserMarathonMatches/expected_response_4.json new file mode 100644 index 000000000..11e5280ec --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_4.json @@ -0,0 +1,22 @@ +{ + "pageIndex": 1, + "pageSize": 1, + "total": 2, + "data": [ + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "prize": true, + "codingDuration": 17976000, + "placement": 1, + "numContestants": 6, + "numSubmitters": 3, + "platforms": [], + "technologies": [ + "Java", + "VB", + "XML" + ] + } + ] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_5.json b/test/test_files/getUserMarathonMatches/expected_response_5.json new file mode 100644 index 000000000..4c919eca5 --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_5.json @@ -0,0 +1,37 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 2, + "data": [ + { + "id": 2002, + "type": "Marathon Match Tournament Round", + "prize": false, + "codingDuration": 27976000, + "placement": 1, + "numContestants": 5, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C++", + "Java", + "Python" + ] + }, + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "prize": true, + "codingDuration": 17976000, + "placement": 1, + "numContestants": 6, + "numSubmitters": 3, + "platforms": [], + "technologies": [ + "Java", + "VB", + "XML" + ] + } + ] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_6.json b/test/test_files/getUserMarathonMatches/expected_response_6.json new file mode 100644 index 000000000..4c919eca5 --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_6.json @@ -0,0 +1,37 @@ +{ + "pageIndex": 1, + "pageSize": 10, + "total": 2, + "data": [ + { + "id": 2002, + "type": "Marathon Match Tournament Round", + "prize": false, + "codingDuration": 27976000, + "placement": 1, + "numContestants": 5, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C++", + "Java", + "Python" + ] + }, + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "prize": true, + "codingDuration": 17976000, + "placement": 1, + "numContestants": 6, + "numSubmitters": 3, + "platforms": [], + "technologies": [ + "Java", + "VB", + "XML" + ] + } + ] +} diff --git a/test/test_files/getUserMarathonMatches/expected_response_7.json b/test/test_files/getUserMarathonMatches/expected_response_7.json new file mode 100644 index 000000000..f770ba3f2 --- /dev/null +++ b/test/test_files/getUserMarathonMatches/expected_response_7.json @@ -0,0 +1,37 @@ +{ + "pageIndex": 1, + "pageSize": 2147483647, + "total": 2, + "data": [ + { + "id": 2001, + "type": "Marathon Match Tournament Round", + "prize": true, + "codingDuration": 17976000, + "placement": 1, + "numContestants": 6, + "numSubmitters": 3, + "platforms": [], + "technologies": [ + "Java", + "VB", + "XML" + ] + }, + { + "id": 2002, + "type": "Marathon Match Tournament Round", + "prize": false, + "codingDuration": 27976000, + "placement": 1, + "numContestants": 5, + "numSubmitters": 4, + "platforms": [], + "technologies": [ + "C++", + "Java", + "Python" + ] + } + ] +} From 34afb00067456e39c16641e02ea4a4ffcb699c70 Mon Sep 17 00:00:00 2001 From: Ghost141 Date: Fri, 19 Dec 2014 18:21:41 +0800 Subject: [PATCH 3/3] Few updates to improve helper.js and fix bug in user algo challenges api. --- actions/challenges.js | 4 ++-- actions/memberStatistics.js | 12 +++++----- actions/srmChallenges.js | 2 +- actions/user.js | 23 +++++-------------- initializers/helper.js | 13 +++++------ .../getUserAlgoChallenges/common_oltp__clean | 1 - .../common_oltp__insert_test_data | 1 - .../topcoder_dw__insert_test_data | 22 +++++++++--------- ...et_user_algo_challenges_error_message.json | 2 +- 9 files changed, 33 insertions(+), 47 deletions(-) delete mode 100644 test/sqls/getUserAlgoChallenges/common_oltp__clean delete mode 100644 test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data diff --git a/actions/challenges.js b/actions/challenges.js index 605aaf9d9..293f1caa1 100755 --- a/actions/challenges.js +++ b/actions/challenges.js @@ -933,7 +933,7 @@ var searchChallenges = function (api, connection, dbConnectionMap, community, ne sqlParams.firstRowIndex = (pageIndex - 1) * pageSize; sqlParams.pageSize = pageSize; sqlParams.sortColumn = sortColumn.toLowerCase(); - sqlParams.sortColumn = helper.getSortColumnDBName(sortColumn.toLowerCase()); + sqlParams.sortColumn = helper.getSortColumnDBName(sortColumn); sqlParams.sortOrder = sortOrder.toLowerCase(); // Set the project type id sqlParams.project_type_id = challengeType.category; @@ -3684,7 +3684,7 @@ var getChallenges = function (api, connection, listType, isMyChallenges, next) { sqlParams = _.extend(sqlParams, { first_row_index: (pageIndex - 1) * pageSize, page_size: pageSize, - sort_column: helper.getSortColumnDBName(sortColumn.toLowerCase()), + sort_column: helper.getSortColumnDBName(sortColumn), sort_order: sortOrder.toLowerCase(), track: type.category, // Set the submission phase status id. diff --git a/actions/memberStatistics.js b/actions/memberStatistics.js index e17ad55e0..8b7bf3b2c 100644 --- a/actions/memberStatistics.js +++ b/actions/memberStatistics.js @@ -192,7 +192,7 @@ function getBasicUserProfile(api, handle, privateInfoEligibility, dbConnectionMa } }); } else { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); } }, function (cb) { var execQuery = function (name) { @@ -707,7 +707,7 @@ exports.getMarathonStatistics = { } async.waterfall([ function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var executeQuery = function (sqlName, cbx) { api.dataAccess.executeQuery(sqlName, sqlParams, dbConnectionMap, cbx); @@ -821,7 +821,7 @@ exports.getSoftwareStatistics = { cb(); } }, function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name, cbx) { api.dataAccess.executeQuery(name, @@ -958,7 +958,7 @@ exports.getStudioStatistics = { async.waterfall([ function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { api.dataAccess.executeQuery('get_studio_member_statistics_track', sqlParams, dbConnectionMap, cb); }, function (results, cb) { @@ -1027,7 +1027,7 @@ exports.getAlgorithmStatistics = { } async.waterfall([ function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name) { return function (cbx) { @@ -1420,7 +1420,7 @@ exports.getCopilotStatistics = { cb(); } }, function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { var execQuery = function (name, cbx) { api.dataAccess.executeQuery(name, diff --git a/actions/srmChallenges.js b/actions/srmChallenges.js index aea27fb23..ca12fb11a 100644 --- a/actions/srmChallenges.js +++ b/actions/srmChallenges.js @@ -2079,7 +2079,7 @@ function getPracticeProblems(api, connection, next) { sqlParams = { firstRowIndex: (pageIndex - 1) * pageSize, pageSize: pageSize, - sortColumn: helper.getSortColumnDBName(sortColumn.toLowerCase()), + sortColumn: helper.getSortColumnDBName(sortColumn), sortOrder: sortOrder.toLowerCase(), userId: caller.userId }; diff --git a/actions/user.js b/actions/user.js index 046d39dfd..6b14bbda2 100644 --- a/actions/user.js +++ b/actions/user.js @@ -489,7 +489,7 @@ function getUserMarathonMatches(api, connection, next) { cb(error); }, function (cb) { - helper.checkUserExistAndActivate(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, function (cb) { sqlParams = { @@ -612,25 +612,14 @@ function getUserAlgorithmChallenges(api, connection, next) { cb(error); }, function (cb) { - helper.checkUserExists(handle, api, dbConnectionMap, cb); + helper.checkCoderExistAndActivate(handle, api, dbConnectionMap, cb); }, - function (err, cb) { - if (err) { - cb(err); - return; - } - helper.checkUserActivated(handle, api, dbConnectionMap, cb); - }, - function (err, cb) { - if (err) { - cb(err); - return; - } + function (cb) { sqlParams = { first_row_index: (pageIndex - 1) * pageSize, page_size: pageSize, sort_order: sortOrder, - sort_column: helper.getSortColumnDBName(sortColumn.toLowerCase()), + sort_column: helper.getSortColumnDBName(sortColumn), handle: handle.toLowerCase() }; async.parallel({ @@ -642,7 +631,7 @@ function getUserAlgorithmChallenges(api, connection, next) { var total = queryResult.count[0].total_count; response = { pageIndex: pageIndex, - pageSize: pageIndex === -1 ? total : pageSize, + pageSize: pageSize, total: total, data: queryResult.data.map(function (row) { return { @@ -685,7 +674,7 @@ exports.getUserAlgorithmChallenges = { outputExample: {}, version: 'v2', transaction: 'read', - databases: ['topcoder_dw', 'common_oltp'], + databases: ['topcoder_dw'], run: function (api, connection, next) { if (connection.dbConnectionMap) { api.log('getUserAlgorithmChallenges#run', 'debug'); diff --git a/initializers/helper.js b/initializers/helper.js index 779c55a0e..e698fe106 100644 --- a/initializers/helper.js +++ b/initializers/helper.js @@ -106,6 +106,8 @@ * - Move checkUserExistAndActivated method from actions/memberStatistics.js to this file. * Changes in 1.40: * - Update apiName2dbNameMap to add entries for coding_duration, num_contestants and num_submitters. + * - Update getSortColumnDBName method to return column name in lower case. + * - Update getLowerCaseList method to use map method. */ "use strict"; @@ -861,11 +863,7 @@ helper.checkFilterDate = function (date, dateName, dateFormat) { * @return {Array} the array with lowercase strings */ helper.getLowerCaseList = function (arr) { - var ret = []; - arr.forEach(function (s) { - ret.push(s.toLowerCase()); - }); - return ret; + return arr.map(function (s) { return s.toLowerCase(); }); }; /** @@ -1162,7 +1160,7 @@ helper.getSortColumnDBName = function (apiName) { if (_.isDefined(apiName2dbNameMap[apiName.toLowerCase()])) { return apiName2dbNameMap[apiName.toLowerCase()]; } - return apiName; + return apiName.toLowerCase(); }; @@ -1637,13 +1635,14 @@ helper.checkCoderActivated = function (handle, api, dbConnectionMap, callback) { /** * Check if the user exist and activated. + * The method name coder indicate that this is checking topcoder_dw.coder instead of common_oltp.user table. * @param {String} handle - the user handle. * @param {Object} api - the api object. * @param {Object} dbConnectionMap - the database connection map object. * @param {Function} callback - the callback function. * @since 1.39 */ -helper.checkUserExistAndActivate = function (handle, api, dbConnectionMap, callback) { +helper.checkCoderExistAndActivate = function (handle, api, dbConnectionMap, callback) { async.waterfall([ function (cb) { // check user existence and activated status. diff --git a/test/sqls/getUserAlgoChallenges/common_oltp__clean b/test/sqls/getUserAlgoChallenges/common_oltp__clean deleted file mode 100644 index e22883b6e..000000000 --- a/test/sqls/getUserAlgoChallenges/common_oltp__clean +++ /dev/null @@ -1 +0,0 @@ -DELETE FROM user WHERE user_id = 300002; diff --git a/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data b/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data deleted file mode 100644 index b07af6097..000000000 --- a/test/sqls/getUserAlgoChallenges/common_oltp__insert_test_data +++ /dev/null @@ -1 +0,0 @@ -INSERT INTO user(user_id, handle, status) VALUES(300002, 'user2', 'U'); diff --git a/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data b/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data index 947689a8b..f34423d20 100644 --- a/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data +++ b/test/sqls/getUserAlgoChallenges/topcoder_dw__insert_test_data @@ -47,17 +47,17 @@ INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VAL INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (22, 'AMD Marathon Match', NULL); INSERT INTO round_type_lu(round_type_id,round_type_desc,algo_rating_type_id) VALUES (23, 'AMD Marathon Match Practice', NULL); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(132456, 'heffan', 'heffan'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300001, 'user1', 'user1'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300002, 'user2', 'user2'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300003, 'user3', 'user3'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300004, 'user4', 'user4'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300005, 'user5', 'user5'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300006, 'user6', 'user6'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300007, 'user7', 'user7'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300008, 'user8', 'user8'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300009, 'user9', 'user9'); -INSERT INTO coder(coder_id, handle, handle_lower) VALUES(300010, 'user10', 'user10'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(132456, 'heffan', 'heffan', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300001, 'user1', 'user1', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300002, 'user2', 'user2', 'U'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300003, 'user3', 'user3', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300004, 'user4', 'user4', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300005, 'user5', 'user5', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300006, 'user6', 'user6', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300007, 'user7', 'user7', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300008, 'user8', 'user8', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300009, 'user9', 'user9', 'A'); +INSERT INTO coder(coder_id, handle, handle_lower, status) VALUES(300010, 'user10', 'user10', 'A'); INSERT INTO coder_rank_type_lu(coder_rank_type_id, coder_rank_type_desc) VALUES(2, 'Test'); diff --git a/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json b/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json index 81e694828..3235a433e 100644 --- a/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json +++ b/test/test_files/getUserAlgoChallenges/expected_get_user_algo_challenges_error_message.json @@ -16,7 +16,7 @@ "notExisted": "User does not exist." }, "invalidSortOrder": "sortOrder should be an element of asc,desc.", - "invalidSortColumn": "The sort column 'abc' is invalid, it should be element of id,type,prize,codingDuration,placement,numContestants,numSubmitters.", + "invalidSortColumn": "The sort column 'abc' is invalid, it should be element of id,type,codingDuration,placement,numContestants,numSubmitters.", "missingSortColumn": "The sortColumn is missing.", "inActivatedUser": "User is not activated." }