diff --git a/docs/api/api_data.js b/docs/api/api_data.js index b6d9a872..beef9127 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -1383,6 +1383,25 @@ define({ "name": "getHackerStats", "group": "Hacker", "version": "0.0.9", + "parameter": { + "fields": { + "query": [{ + "group": "query", + "type": "String", + "optional": false, + "field": "model", + "description": "
the model to be searched (Only hacker supported)
" + }, + { + "group": "query", + "type": "Array", + "optional": false, + "field": "q", + "description": "the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/
" + } + ] + } + }, "success": { "fields": { "Success 200": [{ diff --git a/docs/api/api_data.json b/docs/api/api_data.json index cc112aa3..82c5e35e 100644 --- a/docs/api/api_data.json +++ b/docs/api/api_data.json @@ -1382,6 +1382,25 @@ "name": "getHackerStats", "group": "Hacker", "version": "0.0.9", + "parameter": { + "fields": { + "query": [{ + "group": "query", + "type": "String", + "optional": false, + "field": "model", + "description": "the model to be searched (Only hacker supported)
" + }, + { + "group": "query", + "type": "Array", + "optional": false, + "field": "q", + "description": "the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/
" + } + ] + } + }, "success": { "fields": { "Success 200": [{ diff --git a/docs/api/api_project.js b/docs/api/api_project.js index 0e8c6e6d..45ecedd3 100644 --- a/docs/api/api_project.js +++ b/docs/api/api_project.js @@ -1,16 +1,16 @@ -define({ - "name": "hackerAPI", - "version": "0.0.8", - "description": "Documentation for the API used for mchacks", - "defaultVersion": "0.0.8", - "title": "hackerAPI documentation", - "url": "https://api.mchacks.ca/api", - "sampleUrl": "https://api.mchacks.ca/api", - "apidoc": "0.3.0", - "generator": { - "name": "apidoc", - "time": "2019-01-05T01:35:07.317Z", - "url": "http://apidocjs.com", - "version": "0.17.7" - } +define({ + "name": "hackerAPI", + "version": "0.0.8", + "description": "Documentation for the API used for mchacks", + "defaultVersion": "0.0.8", + "title": "hackerAPI documentation", + "url": "https://api.mchacks.ca/api", + "sampleUrl": "https://api.mchacks.ca/api", + "apidoc": "0.3.0", + "generator": { + "name": "apidoc", + "time": "2019-01-07T03:26:47.443Z", + "url": "http://apidocjs.com", + "version": "0.17.7" + } }); \ No newline at end of file diff --git a/docs/api/api_project.json b/docs/api/api_project.json index 6f2d6d2e..5aff4cd2 100644 --- a/docs/api/api_project.json +++ b/docs/api/api_project.json @@ -1,16 +1,16 @@ -{ - "name": "hackerAPI", - "version": "0.0.8", - "description": "Documentation for the API used for mchacks", - "defaultVersion": "0.0.8", - "title": "hackerAPI documentation", - "url": "https://api.mchacks.ca/api", - "sampleUrl": "https://api.mchacks.ca/api", - "apidoc": "0.3.0", - "generator": { - "name": "apidoc", - "time": "2019-01-05T01:35:07.317Z", - "url": "http://apidocjs.com", - "version": "0.17.7" - } +{ + "name": "hackerAPI", + "version": "0.0.8", + "description": "Documentation for the API used for mchacks", + "defaultVersion": "0.0.8", + "title": "hackerAPI documentation", + "url": "https://api.mchacks.ca/api", + "sampleUrl": "https://api.mchacks.ca/api", + "apidoc": "0.3.0", + "generator": { + "name": "apidoc", + "time": "2019-01-07T03:26:47.443Z", + "url": "http://apidocjs.com", + "version": "0.17.7" + } } \ No newline at end of file diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index d277e790..7d55d466 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -487,7 +487,7 @@ async function findSelf(req, res, next) { } async function getStats(req, res, next) { - const stats = await Services.Hacker.getStats(); + const stats = await Services.Hacker.getStats(req.body.results); req.body.stats = stats; next(); } diff --git a/middlewares/search.middleware.js b/middlewares/search.middleware.js index e33a966d..b6707568 100644 --- a/middlewares/search.middleware.js +++ b/middlewares/search.middleware.js @@ -26,7 +26,7 @@ function parseQuery(req, res, next) { } //Default limit if (!req.body.hasOwnProperty("limit")) { - req.body.limit = 25; + req.body.limit = 10000; } else { req.body.limit = parseInt(req.body.limit); } @@ -62,8 +62,14 @@ async function executeQuery(req, res, next) { return next(); } +function setExpandTrue(req, res, next) { + req.body.expand = true; + next(); +} + module.exports = { parseQuery: parseQuery, - executeQuery: Middleware.Util.asyncMiddleware(executeQuery) + executeQuery: Middleware.Util.asyncMiddleware(executeQuery), + setExpandTrue: setExpandTrue, }; \ No newline at end of file diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 2b98e8d4..0170fce6 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -44,4 +44,8 @@ module.exports = { downloadResumeValidator: [ VALIDATOR.mongoIdValidator("param", "id", false) ], + statsValidator: [ + VALIDATOR.searchModelValidator("query", "model", false), + VALIDATOR.searchValidator("query", "q") + ] }; \ No newline at end of file diff --git a/routes/api/hacker.js b/routes/api/hacker.js index efef35cb..548e1317 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -13,7 +13,8 @@ const Middleware = { parseBody: require("../../middlewares/parse-body.middleware"), Util: require("../../middlewares/util.middleware"), Hacker: require("../../middlewares/hacker.middleware"), - Auth: require("../../middlewares/auth.middleware") + Auth: require("../../middlewares/auth.middleware"), + Search: require("../../middlewares/search.middleware") }; const Services = { Hacker: require("../../services/hacker.service"), @@ -173,6 +174,10 @@ module.exports = { * @apiName getHackerStats * @apiGroup Hacker * @apiVersion 0.0.9 + * + * @apiParam (query) {String} model the model to be searched (Only hacker supported) + * @apiParam (query) {Array} q the query to be executed. For more information on how to format this, please see https://docs.mchacks.ca/architecture/ + * * @apiSuccess {string} message Success message * @apiSuccess {object} data Hacker object * @apiSuccessExample {object} Success-Response: @@ -201,6 +206,11 @@ module.exports = { hackerRouter.route("/stats").get( Middleware.Auth.ensureAuthenticated(), Middleware.Auth.ensureAuthorized(), + Middleware.Validator.Hacker.statsValidator, + Middleware.parseBody.middleware, + Middleware.Search.setExpandTrue, + Middleware.Search.parseQuery, + Middleware.Search.executeQuery, Middleware.Hacker.getStats, Controllers.Hacker.gotStats ); diff --git a/services/hacker.service.js b/services/hacker.service.js index 48f8f74f..ff0adb60 100644 --- a/services/hacker.service.js +++ b/services/hacker.service.js @@ -81,8 +81,8 @@ function findByAccountId(accountId) { return Hacker.findOne(query, logger.updateCallbackFactory(TAG, "hacker")); } -async function getStats() { - const TAG = `[ hacker Service # getHackerStats ]`; +async function getStatsAllHackersCached() { + const TAG = `[ hacker Service # getStatsAll ]`; if (cache.get(Constants.CACHE_KEY_STATS) !== null) { logger.info(`${TAG} Getting cached stats`); return cache.get(Constants.CACHE_KEY_STATS); @@ -90,6 +90,12 @@ async function getStats() { const allHackers = await Hacker.find({}, logger.updateCallbackFactory(TAG, "hacker")).populate({ path: "accountId", }); + cache.put(Constants.CACHE_KEY_STATS, stats, Constants.CACHE_TIMEOUT_STATS); //set a time-out of 5 minutes + return getStats(allHackers); +} + +function getStats(hackers) { + const TAG = `[ hacker Service # getStats ]`; const stats = { total: 0, status: {}, @@ -106,7 +112,7 @@ async function getStats() { age: {} }; - allHackers.forEach((hacker) => { + hackers.forEach((hacker) => { if (!hacker.accountId) { // user is no longer with us for some reason :( return; @@ -133,7 +139,6 @@ async function getStats() { const age = hacker.accountId.getAge(); stats.age[age] = (stats.age[age]) ? stats.age[age] + 1 : 1; }); - cache.put(Constants.CACHE_KEY_STATS, stats, Constants.CACHE_TIMEOUT_STATS); //set a time-out of 5 minutes return stats; } @@ -144,5 +149,6 @@ module.exports = { updateOne: updateOne, findIds: findIds, findByAccountId: findByAccountId, - getStats: getStats + getStats: getStats, + getStatsAllHackersCached: getStatsAllHackersCached, }; \ No newline at end of file diff --git a/services/search.service.js b/services/search.service.js index 4f1225f3..7d0f3b3e 100644 --- a/services/search.service.js +++ b/services/search.service.js @@ -65,10 +65,9 @@ function executeQuery(model, queryArray, page, limit, sort, sort_by, shouldExpan } else if (sort == "asc") { query.sort(sort_by); } - return query.lean() - .limit(limit) + return query.limit(limit) .skip(limit * page) - .exec() + .exec(); } module.exports = { diff --git a/tests/hacker.test.js b/tests/hacker.test.js index 911fd95d..0204e5f8 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -750,6 +750,22 @@ describe("POST add a hacker resume", function () { }); describe("GET Hacker stats", function () { + it("It should FAIL and get hacker stats (invalid validation)", function (done) { + //this takes a lot of time for some reason + util.auth.login(agent, Admin1, (error) => { + if (error) { + return done(error); + } + return agent + .get(`/api/hacker/stats`) + .end(function (err, res) { + res.should.have.status(422); + res.should.have.property("body"); + res.body.should.have.property("message"); + done(); + }); + }); + }); it("It should SUCCEED and get hacker stats", function (done) { //this takes a lot of time for some reason util.auth.login(agent, Admin1, (error) => { @@ -758,6 +774,10 @@ describe("GET Hacker stats", function () { } return agent .get(`/api/hacker/stats`) + .query({ + model: "hacker", + q: JSON.stringify([]) + }) .end(function (err, res) { res.should.have.status(200); res.should.have.property("body");