diff --git a/actions/srmRoundComponentsAndTerms.js b/actions/srmRoundComponentsAndTerms.js index b0808503a..b4ce5d32a 100644 --- a/actions/srmRoundComponentsAndTerms.js +++ b/actions/srmRoundComponentsAndTerms.js @@ -300,6 +300,47 @@ var setRoundTerms = function (api, connection, dbConnectionMap, next) { }); }; +/** + * Gets round terms. + * + * @param api the api instance. + * @param connection the connection instance + * @param dbConnectionMap the database connection map + * @param next the callback method + */ +var getRoundTerms = function (api, connection, dbConnectionMap, next) { + var helper = api.helper, + sqlParams = {}, + roundId = Number(connection.params.roundId), + roundTermsContent = ''; + + async.waterfall([ + function (cb) { + cb(helper.checkAdmin(connection, 'Authorized information needed.', 'Admin access only.')); + }, function (cb) { + cb(helper.checkIdParameter(roundId, "roundId")); + }, function (cb) { + sqlParams.round_id = roundId; + api.dataAccess.executeQuery("get_round_terms", sqlParams, dbConnectionMap, cb); + }, function (results, cb) { + if (!results || results.length === 0) { + var error = new IllegalArgumentError("The round terms can't be found with such roundId = " + roundId); + cb(error); + } else { + roundTermsContent = results[0].terms_content; + cb(); + } + } + ], function (err) { + if (err) { + helper.handleError(api, connection, err); + } else { + connection.response = {"roundTermsContent": roundTermsContent}; + } + next(connection, true); + }); +}; + /** * The API for Set Round Components. */ @@ -349,3 +390,28 @@ exports.setRoundTerms = { } } }; + +/** + * The API for Get Round Terms. + */ +exports.getRoundTerms = { + name: "getRoundTerms", + description: "Get Round Terms", + inputs: { + required: ['roundId'], + optional: [] + }, + blockedConnectionTypes: [], + outputExample: {}, + version: 'v2', + transaction: 'read', + databases: ["informixoltp"], + run: function (api, connection, next) { + if (connection.dbConnectionMap) { + api.log("Execute getRoundTerms#run", 'debug'); + getRoundTerms(api, connection, connection.dbConnectionMap, next); + } else { + api.helper.handleNoConnection(api, connection, next); + } + } +}; diff --git a/apiary.apib b/apiary.apib index feff00bbf..75b35db27 100644 --- a/apiary.apib +++ b/apiary.apib @@ -9107,6 +9107,57 @@ Request "description":"Servers are up but overloaded. Try again later." } +## Get round terms of use [/data/srm/rounds/:roundId/terms] +### Get round terms of use by round id [GET] + +- Only when jwt passed can we get the round terms of use. + ++ Parameters + + roundId (required, number, `13672`) ... The id of round + ++ Request + + + Headers + + Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZHwxMzI0NTYiLCJleHAiOjEzOTM3MDM1NzEsImF1ZCI6InRvcGNvZGVyIiwiaWF0IjoxMzkzNjQzNTcxfQ.F2iohKp2nwjQeGqrBD1wn42GJUD0r28aGjhDle7KujA + ++ Response 200 (application/json) + + { + "roundTermsContent": "The round terms content..." + } ++ Response 401 (application/json) + + { + "name":"Unauthorized", + "value":"401", + "description":"Authentication credentials were missing or incorrect." + } + ++ Response 404 (application/json) + + { + "name":"Not Found", + "value":"404", + "description":"This message will explain why the URI requested is invalid or the resource 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." + } + ## Agree terms of use [/terms/{termsOfUseId}/agree] ### Agree terms of use by id [POST] diff --git a/get_round_terms.patch b/get_round_terms.patch new file mode 100644 index 000000000..ffe87acdc --- /dev/null +++ b/get_round_terms.patch @@ -0,0 +1,302 @@ +diff --git a/actions/srmRoundComponentsAndTerms.js b/actions/srmRoundComponentsAndTerms.js +index c653f11..765c0be 100644 +--- a/actions/srmRoundComponentsAndTerms.js ++++ b/actions/srmRoundComponentsAndTerms.js +@@ -99,7 +99,7 @@ function checkComponents(api, dbConnectionMap, components, callback) { + }, function (results, cb) { + if (!error) { + if (results.length === 0) { +- error = new IllegalArgumentError("The componentId "+ component.componentId + " does not exist in database."); ++ error = new IllegalArgumentError("The componentId " + component.componentId + " does not exist in database."); + } + } + +@@ -301,6 +301,47 @@ var setRoundTerms = function (api, connection, dbConnectionMap, next) { + }; + + /** ++ * Gets round terms. ++ * ++ * @param api the api instance. ++ * @param connection the connection instance ++ * @param dbConnectionMap the database connection map ++ * @param next the callback method ++ */ ++var getRoundTerms = function (api, connection, dbConnectionMap, next) { ++ var helper = api.helper, ++ sqlParams = {}, ++ roundId = Number(connection.params.roundId), ++ roundTermsContent = ''; ++ ++ async.waterfall([ ++ function (cb) { ++ cb(helper.checkAdmin(connection, 'Authorized information needed.', 'Admin access only.')); ++ }, function (cb) { ++ cb(helper.checkIdParameter(roundId, "roundId")); ++ }, function (cb) { ++ sqlParams.round_id = roundId; ++ api.dataAccess.executeQuery("get_round_terms", sqlParams, dbConnectionMap, cb); ++ }, function (results, cb) { ++ if (!results || results.length === 0) { ++ var error = new IllegalArgumentError("The round terms can't be found with such roundId = " + roundId); ++ cb(error); ++ } else { ++ roundTermsContent = results[0].terms_content; ++ cb(); ++ } ++ } ++ ], function (err) { ++ if (err) { ++ helper.handleError(api, connection, err); ++ } else { ++ connection.response = {"roundTermsContent": roundTermsContent}; ++ } ++ next(connection, true); ++ }); ++}; ++ ++/** + * The API for Set Round Components. + */ + exports.setRoundComponents = { +@@ -348,4 +389,29 @@ exports.setRoundTerms = { + api.helper.handleNoConnection(api, connection, next); + } + } ++}; ++ ++/** ++ * The API for Get Round Terms. ++ */ ++exports.getRoundTerms = { ++ name: "getRoundTerms", ++ description: "Get Round Terms", ++ inputs: { ++ required: ['roundId'], ++ optional: [] ++ }, ++ blockedConnectionTypes: [], ++ outputExample: {}, ++ version: 'v2', ++ transaction: 'read', ++ databases: ["informixoltp"], ++ run: function (api, connection, next) { ++ if (connection.dbConnectionMap) { ++ api.log("Execute getRoundTerms#run", 'debug'); ++ getRoundTerms(api, connection, connection.dbConnectionMap, next); ++ } else { ++ api.helper.handleNoConnection(api, connection, next); ++ } ++ } + }; +\ No newline at end of file +diff --git a/apiary.apib b/apiary.apib +index feff00b..75b35db 100644 +--- a/apiary.apib ++++ b/apiary.apib +@@ -9107,6 +9107,57 @@ Request + "description":"Servers are up but overloaded. Try again later." + } + ++## Get round terms of use [/data/srm/rounds/:roundId/terms] ++### Get round terms of use by round id [GET] ++ ++- Only when jwt passed can we get the round terms of use. ++ +++ Parameters ++ + roundId (required, number, `13672`) ... The id of round ++ +++ Request ++ ++ + Headers ++ ++ Authorization : Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZHwxMzI0NTYiLCJleHAiOjEzOTM3MDM1NzEsImF1ZCI6InRvcGNvZGVyIiwiaWF0IjoxMzkzNjQzNTcxfQ.F2iohKp2nwjQeGqrBD1wn42GJUD0r28aGjhDle7KujA ++ +++ Response 200 (application/json) ++ ++ { ++ "roundTermsContent": "The round terms content..." ++ } +++ Response 401 (application/json) ++ ++ { ++ "name":"Unauthorized", ++ "value":"401", ++ "description":"Authentication credentials were missing or incorrect." ++ } ++ +++ Response 404 (application/json) ++ ++ { ++ "name":"Not Found", ++ "value":"404", ++ "description":"This message will explain why the URI requested is invalid or the resource 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." ++ } ++ + ## Agree terms of use [/terms/{termsOfUseId}/agree] + ### Agree terms of use by id [POST] + +diff --git a/queries/get_round_terms b/queries/get_round_terms +new file mode 100644 +index 0000000..bd5329a +--- /dev/null ++++ b/queries/get_round_terms +@@ -0,0 +1 @@ ++SELECT skip 0 FIRST 1 terms_content FROM round_terms WHERE round_id = @round_id@; +\ No newline at end of file +diff --git a/queries/get_round_terms.json b/queries/get_round_terms.json +new file mode 100644 +index 0000000..d2ce81a +--- /dev/null ++++ b/queries/get_round_terms.json +@@ -0,0 +1,5 @@ ++{ ++ "name" : "get_round_terms", ++ "db" : "informixoltp", ++ "sqlfile" : "get_round_terms" ++} +diff --git a/routes.js b/routes.js +index 9723cf1..8d8efbc 100755 +--- a/routes.js ++++ b/routes.js +@@ -330,8 +330,9 @@ exports.routes = { + { path: "/:apiVersion/data/srm/problems", action: "listSRMProblems" }, + { path: "/:apiVersion/data/srm/rounds/:roundId/problems", action: "listRoundProblems" }, + { path: "/:apiVersion/data/srm/rounds/:roundId/:problemId/:divisionId/components", action: "listRoundProblemComponents" }, +- { path: "/:apiVersion/data/srm/rounds/:roundId/components", action: "listRoundProblemComponents" }, +- { path: "/:apiVersion/data/srm/rounds/:contestId", action: "listSRMContestRounds" }, ++ { path: "/:apiVersion/data/srm/rounds/:roundId/components", action: "listRoundProblemComponents" }, ++ { path: "/:apiVersion/data/srm/rounds/:roundId/terms", action: "getRoundTerms" }, ++ { path: "/:apiVersion/data/srm/rounds/:contestId", action: "listSRMContestRounds" }, + { path: "/:apiVersion/auth0/callback", action: "auth0Callback" }, + + //Stubs APIs +diff --git a/test/test.srmRoundComponentsAndTerms.js b/test/test.srmRoundComponentsAndTerms.js +index 6b32e80..1282943 100644 +--- a/test/test.srmRoundComponentsAndTerms.js ++++ b/test/test.srmRoundComponentsAndTerms.js +@@ -61,6 +61,25 @@ function createPostRequest(queryString, user) { + } + + /** ++ * Create get request and return it. ++ * ++ * @param queryString - the query string ++ * @param user - the user handle ++ * @returns {*} request ++ */ ++function createGetRequest(queryString, user) { ++ var req = request(API_ENDPOINT) ++ .get(queryString) ++ .set("Accept", "application/json") ++ .expect("Content-Type", /json/); ++ if (user) { ++ req.set('Authorization', generateAuthHeader(user)); ++ } ++ ++ return req; ++} ++ ++/** + * Assert post response detail. + * + * @param queryString - the query string +@@ -85,6 +104,31 @@ function assertPostError(queryString, user, obj, statusCode, errorDetail, done) + }); + } + ++/** ++ * Assert Get response detail. ++ * ++ * @param queryString - the query string ++ * @param user - the user handle ++ * @param obj - the JSON object ++ * @param statusCode - the expected status code ++ * @param errorDetail - the error detail. ++ * @param done the callback function ++ */ ++function assertGetError(queryString, user, obj, statusCode, errorDetail, done) { ++ createGetRequest(queryString, user).expect(statusCode).send(obj).end(function (err, res) { ++ if (err) { ++ done(err); ++ return; ++ } ++ if (statusCode === 200) { ++ assert.equal(res.body.error, errorDetail, "Invalid error detail"); ++ } else { ++ assert.equal(res.body.error.details, errorDetail, "Invalid error detail"); ++ } ++ done(); ++ }); ++} ++ + describe('SRM Round Components And Terms APIs', function () { + this.timeout(120000); // Wait 2 minutes, remote db might be slow. + +@@ -367,5 +411,49 @@ describe('SRM Round Components And Terms APIs', function () { + done(); + }); + }); ++ ++ describe('Get Round Terms API invalid test', function () { ++ it("No anonymous access.", function (done) { ++ assertGetError("/v2/data/srm/rounds/13673/terms", null, null, 401, "Authorized information needed.", done); ++ }); ++ ++ it("Admin access only.", function (done) { ++ assertGetError("/v2/data/srm/rounds/13673/terms", 'user', null, 403, "Admin access only.", done); ++ }); ++ ++ it("roundId should be number.", function (done) { ++ assertGetError("/v2/data/srm/rounds/13673a/terms", 'heffan', null, 400, "roundId should be number.", done); ++ }); ++ ++ it("roundId should be Integer.", function (done) { ++ assertGetError("/v2/data/srm/rounds/13673.01/terms", 'heffan', null, 400, "roundId should be Integer.", done); ++ }); ++ ++ it("roundId should be positive.", function (done) { ++ assertGetError("/v2/data/srm/rounds/-13673/terms", 'heffan', null, 400, "roundId should be positive.", done); ++ }); ++ ++ it("roundId should be less or equal to 2147483647.", function (done) { ++ assertGetError("/v2/data/srm/rounds/1111111111111111111/terms", 'heffan', null, 400, ++ "roundId should be less or equal to 2147483647.", done); ++ }); ++ ++ it("The round terms should not be empty.", function (done) { ++ var notFoundRoundId = 136733; ++ assertGetError("/v2/data/srm/rounds/" + notFoundRoundId + "/terms", 'heffan', null, 400, ++ "The round terms can't be found with such roundId = " + notFoundRoundId, done); ++ }); ++ ++ it("Valid get round terms.", function (done) { ++ createGetRequest("/v2/data/srm/rounds/13673/terms", 'heffan').expect(200).send(null).end(function (err, res) { ++ if (err) { ++ done(err); ++ return; ++ } ++ assert.equal(res.body.roundTermsContent, "term text", "Invalid response detail"); ++ done(); ++ }); ++ }); ++ }); + }); + }); +\ No newline at end of file diff --git a/queries/get_round_terms b/queries/get_round_terms new file mode 100644 index 000000000..bd5329aa2 --- /dev/null +++ b/queries/get_round_terms @@ -0,0 +1 @@ +SELECT skip 0 FIRST 1 terms_content FROM round_terms WHERE round_id = @round_id@; \ No newline at end of file diff --git a/queries/get_round_terms.json b/queries/get_round_terms.json new file mode 100644 index 000000000..d2ce81a5c --- /dev/null +++ b/queries/get_round_terms.json @@ -0,0 +1,5 @@ +{ + "name" : "get_round_terms", + "db" : "informixoltp", + "sqlfile" : "get_round_terms" +} diff --git a/routes.js b/routes.js index 89ffd8881..6d69b2424 100755 --- a/routes.js +++ b/routes.js @@ -330,8 +330,9 @@ exports.routes = { { path: "/:apiVersion/data/srm/problems", action: "listSRMProblems" }, { path: "/:apiVersion/data/srm/rounds/:roundId/problems", action: "listRoundProblems" }, { path: "/:apiVersion/data/srm/rounds/:roundId/:problemId/:divisionId/components", action: "listRoundProblemComponents" }, - { path: "/:apiVersion/data/srm/rounds/:roundId/components", action: "listRoundProblemComponents" }, - { path: "/:apiVersion/data/srm/rounds/:contestId", action: "listSRMContestRounds" }, + { path: "/:apiVersion/data/srm/rounds/:roundId/components", action: "listRoundProblemComponents" }, + { path: "/:apiVersion/data/srm/rounds/:roundId/terms", action: "getRoundTerms" }, + { path: "/:apiVersion/data/srm/rounds/:contestId", action: "listSRMContestRounds" }, { path: "/:apiVersion/auth0/callback", action: "auth0Callback" }, //Stubs APIs diff --git a/test/test.srmRoundComponentsAndTerms.js b/test/test.srmRoundComponentsAndTerms.js index 6b32e8016..128294341 100644 --- a/test/test.srmRoundComponentsAndTerms.js +++ b/test/test.srmRoundComponentsAndTerms.js @@ -60,6 +60,25 @@ function createPostRequest(queryString, user) { return req; } +/** + * Create get request and return it. + * + * @param queryString - the query string + * @param user - the user handle + * @returns {*} request + */ +function createGetRequest(queryString, user) { + var req = request(API_ENDPOINT) + .get(queryString) + .set("Accept", "application/json") + .expect("Content-Type", /json/); + if (user) { + req.set('Authorization', generateAuthHeader(user)); + } + + return req; +} + /** * Assert post response detail. * @@ -85,6 +104,31 @@ function assertPostError(queryString, user, obj, statusCode, errorDetail, done) }); } +/** + * Assert Get response detail. + * + * @param queryString - the query string + * @param user - the user handle + * @param obj - the JSON object + * @param statusCode - the expected status code + * @param errorDetail - the error detail. + * @param done the callback function + */ +function assertGetError(queryString, user, obj, statusCode, errorDetail, done) { + createGetRequest(queryString, user).expect(statusCode).send(obj).end(function (err, res) { + if (err) { + done(err); + return; + } + if (statusCode === 200) { + assert.equal(res.body.error, errorDetail, "Invalid error detail"); + } else { + assert.equal(res.body.error.details, errorDetail, "Invalid error detail"); + } + done(); + }); +} + describe('SRM Round Components And Terms APIs', function () { this.timeout(120000); // Wait 2 minutes, remote db might be slow. @@ -367,5 +411,49 @@ describe('SRM Round Components And Terms APIs', function () { done(); }); }); + + describe('Get Round Terms API invalid test', function () { + it("No anonymous access.", function (done) { + assertGetError("/v2/data/srm/rounds/13673/terms", null, null, 401, "Authorized information needed.", done); + }); + + it("Admin access only.", function (done) { + assertGetError("/v2/data/srm/rounds/13673/terms", 'user', null, 403, "Admin access only.", done); + }); + + it("roundId should be number.", function (done) { + assertGetError("/v2/data/srm/rounds/13673a/terms", 'heffan', null, 400, "roundId should be number.", done); + }); + + it("roundId should be Integer.", function (done) { + assertGetError("/v2/data/srm/rounds/13673.01/terms", 'heffan', null, 400, "roundId should be Integer.", done); + }); + + it("roundId should be positive.", function (done) { + assertGetError("/v2/data/srm/rounds/-13673/terms", 'heffan', null, 400, "roundId should be positive.", done); + }); + + it("roundId should be less or equal to 2147483647.", function (done) { + assertGetError("/v2/data/srm/rounds/1111111111111111111/terms", 'heffan', null, 400, + "roundId should be less or equal to 2147483647.", done); + }); + + it("The round terms should not be empty.", function (done) { + var notFoundRoundId = 136733; + assertGetError("/v2/data/srm/rounds/" + notFoundRoundId + "/terms", 'heffan', null, 400, + "The round terms can't be found with such roundId = " + notFoundRoundId, done); + }); + + it("Valid get round terms.", function (done) { + createGetRequest("/v2/data/srm/rounds/13673/terms", 'heffan').expect(200).send(null).end(function (err, res) { + if (err) { + done(err); + return; + } + assert.equal(res.body.roundTermsContent, "term text", "Invalid response detail"); + done(); + }); + }); + }); }); }); \ No newline at end of file