diff --git a/constants/general.constant.js b/constants/general.constant.js index 5e23d2fe..e1cc8502 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -25,6 +25,68 @@ const HACKER_STATUSES = [ HACKER_STATUS_CHECKED_IN, HACKER_STATUS_DECLINED ]; + +const HACKER_REVIEWER_STATUS_NONE = 'None'; +const HACKER_REVIEWER_STATUS_POOR = 'Poor'; +const HACKER_REVIEWER_STATUS_WEAK = 'Weak'; +const HACKER_REVIEWER_STATUS_AVERAGE = 'Average'; +const HACKER_REVIEWER_STATUS_STRONG = 'Strong'; +const HACKER_REVIEWER_STATUS_OUTSTANDING = 'Outstanding'; +const HACKER_REVIEWER_STATUS_WHITELIST = 'Whitelist'; +const HACKER_REVIEWER_STATUSES = [ + HACKER_REVIEWER_STATUS_NONE, + HACKER_REVIEWER_STATUS_POOR, + HACKER_REVIEWER_STATUS_WEAK, + HACKER_REVIEWER_STATUS_AVERAGE, + HACKER_REVIEWER_STATUS_STRONG, + HACKER_REVIEWER_STATUS_OUTSTANDING, + HACKER_REVIEWER_STATUS_WHITELIST, +]; + +const HACKER_REVIEWER_NAMES = [ + '', + 'Amy', + 'Carolyn', + 'Clara', + 'Debo', + 'Deon', + 'Doaa', + 'Emily', + 'Emma', + 'Ethan', + 'Evan', + 'Finnley', + 'Gabriel', + 'Ian', + 'Inaya', + 'Jake', + 'Jamie', + 'Jane J.', + 'Jane K.', + 'Jeffrey', + 'Joshua', + 'Jyothsna', + 'Khyati', + 'Michael', + 'Mika', + 'Mubeen', + 'Mira', + 'Oishika', + 'Olivia', + 'Qi', + 'Rémi', + 'Sebastian', + 'Shirley', + 'Sihan', + 'Siva', + 'Snigdha', + 'Stephanie', + 'Tavi', + 'Tina', + 'Vipul', + 'Yue Qian', +]; + // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -185,7 +247,16 @@ module.exports = { HACKER_STATUS_CONFIRMED: HACKER_STATUS_CONFIRMED, HACKER_STATUS_WITHDRAWN: HACKER_STATUS_WITHDRAWN, HACKER_STATUS_CHECKED_IN: HACKER_STATUS_CHECKED_IN, + HACKER_REVIEWER_STATUS_NONE: HACKER_REVIEWER_STATUS_NONE, + HACKER_REVIEWER_STATUS_POOR: HACKER_REVIEWER_STATUS_POOR, + HACKER_REVIEWER_STATUS_WEAK: HACKER_REVIEWER_STATUS_WEAK, + HACKER_REVIEWER_STATUS_AVERAGE: HACKER_REVIEWER_STATUS_AVERAGE, + HACKER_REVIEWER_STATUS_STRONG: HACKER_REVIEWER_STATUS_STRONG, + HACKER_REVIEWER_STATUS_OUTSTANDING: HACKER_REVIEWER_STATUS_OUTSTANDING, + HACKER_REVIEWER_STATUS_WHITELIST: HACKER_REVIEWER_STATUS_WHITELIST, HACKER_STATUSES: HACKER_STATUSES, + HACKER_REVIEWER_STATUSES: HACKER_REVIEWER_STATUSES, + HACKER_REVIEWER_NAMES: HACKER_REVIEWER_NAMES, TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE, TRAVEL_STATUS_BUS: TRAVEL_STATUS_BUS, TRAVEL_STATUS_POLICY: TRAVEL_STATUS_POLICY, diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 0a246fe8..37e61fd6 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -6,7 +6,7 @@ * ===***===***===***===***===***===***===***===***=== * * If you are adding a route to this list, update this number - * next avaiable createFromTime value: 170 + * next avaiable createFromTime value: 180 * * If you are deleting a route from this list, please add the ID to the list of 'reserved' IDs, * so that we don't accidentally assign someone to a given ID. @@ -153,6 +153,66 @@ const hackerRoutes = { uri: "/api/hacker/status/" + Constants.ROLE_CATEGORIES.SELF, _id: mongoose.Types.ObjectId.createFromTime(125), }, + patchAnyReviewerStatusById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(168) + }, + patchSelfReviewerStatusById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(169) + }, + patchAnyReviewerStatus2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(170) + }, + patchSelfReviewerStatus2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(171) + }, + patchAnyReviewerNameById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(172) + }, + patchSelfReviewerNameById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(173) + }, + patchAnyReviewerName2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerName2/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(174) + }, + patchSelfReviewerName2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerName2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(175) + }, + patchAnyReviewerCommentsById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerComments/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(176) + }, + patchSelfReviewerCommentsById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerComments/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(177) + }, + patchAnyReviewerComments2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerComments2/" + Constants.ROLE_CATEGORIES.ALL, + _id: mongoose.Types.ObjectId.createFromTime(178) + }, + patchSelfReviewerComments2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerComments2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(179) + }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, diff --git a/docs/api/api_data.js b/docs/api/api_data.js index df439b86..c2fa3ded 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,6 +2117,426 @@ define({ "api": [ } ] }, + { + "type": "patch", + "url": "/hacker/reviewerStatus/:id", + "title": "update a hacker's reviewer status", + "name": "patchHackerReviewerStatus", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerStatus", + "description": "
Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerStatus/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerStatus/:id", + "title": "update a hacker's reviewer status", + "name": "patchHackerReviewerStatus", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerStatus", + "description": "Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus\": \"Poor\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerStatus/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerStatus2/:id", + "title": "update a hacker's reviewer status (2)", + "name": "patchHackerReviewerStatus2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerStatus2", + "description": "Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus2\": \"Outstanding\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerStatus2/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerName/:id", + "title": "update a hacker's reviewer name", + "name": "patchHackerReviewerName", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerName", + "description": "Reviewer's name of the hacker's application
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName\": \"Jane Doe\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerName/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerName2/:id", + "title": "update a hacker's reviewer name (2)", + "name": "patchHackerReviewerName2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerName2", + "description": "Reviewer's name (2) of the hacker's application
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName2\": \"John Doe\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerName2/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments/:id", + "title": "update a hacker's reviewer's comments", + "name": "patchHackerReviewerComments", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments", + "description": "Reviewer's comments of the hacker's application
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerComments\": \"The application was good and expressed a strong desire and aspiration of joining the team.\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerComments/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments2/:id", + "title": "update a hacker's reviewer's comments (2)", + "name": "patchHackerReviewerComments2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments2", + "description": "Reviewer's comments (2) of the hacker's application
" + } + ] + } + }, + "success": { + "fields": { + "Success 200": [ + { + "group": "Success 200", + "type": "string", + "optional": false, + "field": "message", + "description": "Success message
" + }, + { + "group": "Success 200", + "type": "object", + "optional": false, + "field": "data", + "description": "Hacker object
" + } + ] + }, + "examples": [ + { + "title": "Success-Response:", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerComments2\": \"The application was good and expressed a strong desire and aspiration of joining the team.\"\n }\n}", + "type": "object" + } + ] + }, + "permission": [ + { + "name": "Administrator" + } + ], + "filename": "routes/api/hacker.js", + "groupTitle": "Hacker", + "sampleRequest": [ + { + "url": "https://api.mchacks.ca/api/hacker/reviewerComments2/:id" + } + ] + }, { "type": "post", "url": "/hacker/resume/:id", diff --git a/docs/api/api_data.json b/docs/api/api_data.json index 6c9d27c7..c32148c9 100644 --- a/docs/api/api_data.json +++ b/docs/api/api_data.json @@ -1610,7 +1610,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"sendEmail\": true,\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", + "content": "{\n \"message\": \"Successfully retrieved hacker information\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\n \"status\": \"Applied\",\n \"application\":{\n \"general\":{\n \"school\": \"McGill University\",\n \"degree\": \"Undergraduate\",\n \"fieldOfStudy\": \"Computer Science\",\n \"graduationYear\": \"2021\",\n \"jobInterest\":\"Internship\",\n \"URL\":{\n \"resume\":\"resumes/1543458163426-5bff4d736f86be0a41badb91\",\n \"github\":\"https://github.com/abcd\",\n \"dropler\":\"https://dribbble.com/abcd\",\n \"personal\":\"https://www.hi.com/\",\n \"linkedIn\":\"https://linkedin.com/in/abcd\",\n \"other\":\"https://github.com/hackmcgill/hackerAPI/issues/168\"\n },\n },\n \"shortAnswer\": {\n \"skills\":[\"Javascript\",\"Typescript\"],\n \"question1\": \"I love McHacks\",\n \"question2\":\"Pls accept me\",\n \"previousHackathons\": \"5\",\n \"comments\":\"hi!\",\n },\n \"other:\" {\n \"gender\": \"male\",\n \"ethnicity\": \"Asian or Pacific Islander\",\n \"sendEmail\": false,\n \"privacyPolicy\": true,\n \"codeOfConduct\": true,\n }\n \"accommodation\": {\n \"travel\": 0\n },\n \"location:\" {\n \"timeZone\": \"GMT-5\",\n \"country\": \"Canada\",\n \"city\": \"Montreal\",\n }\n }\n }\n }", "type": "object" } ] @@ -2117,6 +2117,7 @@ } ] }, + { "type": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index f23a346a..ba540f99 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -3,6 +3,10 @@ const TAG = `[ HACKER.MIDDLEWARE.js ]`; const mongoose = require("mongoose"); +const { HACKER_REVIEWER_STATUS_NONE } = require("../constants/general.constant"); +const { HACKER_REVIEWER_STATUSES } = require("../constants/general.constant"); +const { HACKER_REVIEWER_NAMES } = require("../constants/general.constant"); +const { HACKER_DEFAULT_REVIEWER } = HACKER_REVIEWER_NAMES.find(r => r === ''); // shim to allow us to use Promise.allSettled require("promise.allsettled").shim(); @@ -105,6 +109,12 @@ function parseConfirmation(req, res, next) { /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus: HACKER_REVIEWER_STATUSES}}}} req + * @param {{body: {hackerDetails: {reviewerStatus2: HACKER_REVIEWER_STATUSES}}}} req + * @param {{body: {hackerDetails: {reviewerName: HACKER_REVIEWER_NAMES}}}} req + * @param {{body: {hackerDetails: {reviewerName2: HACKER_REVIEWER_NAMES}}}} req + * @param {{body: {hackerDetails: {reviewerComments: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments2: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -112,6 +122,12 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; + req.body.hackerDetails.reviewerStatus = HACKER_REVIEWER_STATUS_NONE; + req.body.hackerDetails.reviewerStatus2 = HACKER_REVIEWER_STATUS_NONE; + req.body.hackerDetails.reviewerName = HACKER_DEFAULT_REVIEWER; + req.body.hackerDetails.reviewerName2 = HACKER_DEFAULT_REVIEWER; + req.body.hackerDetails.reviewerComments = ""; + req.body.hackerDetails.reviewerComments2 = ""; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 05a3b413..fc1283f3 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -306,6 +306,52 @@ module.exports = { false ) ], + updateReviewerStatusValidator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], + updateReviewerStatus2Validator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus2", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], + updateReviewerNameValidator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName", + Constants.HACKER_REVIEWER_NAMES, + false + ) + ], + updateReviewerName2Validator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName2", + Constants.HACKER_REVIEWER_NAMES, + false + ) + ], + updateReviewerCommentsValidator: [ + VALIDATOR.stringValidator( + "body", + "reviewerComments", + false + ) + ], + updateReviewerComments2Validator: [ + VALIDATOR.stringValidator( + "body", + "reviewerComments2", + false + ) + ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/models/hacker.model.js b/models/hacker.model.js index 51171616..38e399f2 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -15,6 +15,40 @@ const HackerSchema = new mongoose.Schema({ required: true, default: "None" }, + reviewerStatus: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: false, + default: Constants.HACKER_REVIEWER_STATUS_NONE + }, + reviewerStatus2: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: false, + default: Constants.HACKER_REVIEWER_STATUS_NONE + }, + reviewerName: { + type: String, + enum: Constants.HACKER_REVIEWER_NAMES, + required: false, + default: Constants.HACKER_REVIEWER_NAMES.find(r => r === '') + }, + reviewerName2: { + type: String, + enum: Constants.HACKER_REVIEWER_NAMES, + required: false, + default: Constants.HACKER_REVIEWER_NAMES.find(r => r === '') + }, + reviewerComments: { + type: String, + required: false, + default: "" + }, + reviewerComments2: { + type: String, + required: false, + default: "" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0fe125a6..58f57d8b 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -268,7 +268,7 @@ module.exports = { ); /** - * @api {patch} /hacker/status/:id update a hacker's status + * @api {patch} /hacker/status/:id update a hacker's status - DOES NOT trigger an email to the hacker * @apiName patchHackerStatus * @apiGroup Hacker * @apiVersion 0.0.9 @@ -293,12 +293,184 @@ module.exports = { Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.updateHacker, - Middleware.Hacker.sendStatusUpdateEmail, Controllers.Hacker.updatedHacker ); + /** + * @api {patch} /hacker/reviewerStatus/:id update a hacker's reviewer status + * @apiName patchHackerReviewerStatus + * @apiGroup Hacker + * @apiVersion 0.0.9 + * + * @apiParam (body) {string} [reviewerStatus] Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") + * @apiSuccess {string} message Success message + * @apiSuccess {object} data Hacker object + * @apiSuccessExample {object} Success-Response: + * { + * "message": "Changed hacker information", + * "data": { + * "reviewerStatus": "Outstanding" + * } + * } + * @apiPermission Administrator + */ + hackerRouter.route("/reviewerStatus/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerStatusValidator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker + ); + + /** + * @api {patch} /hacker/reviewerStatus2/:id update a hacker's reviewer status 2 + * @apiName patchHackerReviewerStatus2 + * @apiGroup Hacker + * @apiVersion 0.0.9 + * + * @apiParam (body) {string} [reviewerStatus2] Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") + * @apiSuccess {string} message Success message + * @apiSuccess {object} data Hacker object + * @apiSuccessExample {object} Success-Response: + * { + * "message": "Changed hacker information", + * "data": { + * "reviewerStatus2": "Outstanding" + * } + * } + * @apiPermission Administrator + */ + hackerRouter.route("/reviewerStatus2/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerStatus2Validator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker + ); + + /** + * @api {patch} /hacker/reviewerName/:id update a hacker's reviewer name + * @apiName patchHackerReviewerName + * @apiGroup Hacker + * @apiVersion 0.0.9 + * + * @apiParam (body) {string} [reviewerName] Reviewer name of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") + * @apiSuccess {string} message Success message + * @apiSuccess {string} data name + * @apiSuccessExample {object} Success-Response: + * { + * "message": "Changed hacker information", + * "data": { + * "reviewerName": "John Doe" + * } + * } + * @apiPermission Administrator + */ + hackerRouter.route("/reviewerName/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerNameValidator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker +); + +/** +* @api {patch} /hacker/reviewerName2/:id update a hacker's reviewer name +* @apiName patchHackerReviewerName2 +* @apiGroup Hacker +* @apiVersion 0.0.9 +* +* @apiParam (body) {string} [reviewerName2] Reviewer name of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") +* @apiSuccess {string} message Success message +* @apiSuccess {string} data name +* @apiSuccessExample {object} Success-Response: +* { +* "message": "Changed hacker information", +* "data": { +* "reviewerName2": "John Doe" +* } +* } +* @apiPermission Administrator +*/ +hackerRouter.route("/reviewerName2/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerName2Validator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker +); + +/** +* @api {patch} /hacker/reviewerComments/:id update a hacker's reviewer comments +* @apiName patchHackerReviewerComments +* @apiGroup Hacker +* @apiVersion 0.0.9 +* +* @apiParam (body) {string} [reviewerComments] Reviewer comments of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") +* @apiSuccess {string} message Success message +* @apiSuccess {string} data name +* @apiSuccessExample {object} Success-Response: +* { +* "message": "Changed hacker information", +* "data": { +* "reviewerComments": "John Doe" +* } +* } +* @apiPermission Administrator +*/ +hackerRouter.route("/reviewerComments/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerCommentsValidator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker +); + +/** +* @api {patch} /hacker/reviewerComments/:id update a hacker's reviewer comments +* @apiName patchHackerReviewerComments +* @apiGroup Hacker +* @apiVersion 0.0.9 +* +* @apiParam (body) {string} [reviewerComments] Reviewer comments of the hacker's application ("None"|"Poor"|"Weak"|"Average"|"Strong"|"Outstanding"|"Whitelist") +* @apiSuccess {string} message Success message +* @apiSuccess {string} data name +* @apiSuccessExample {object} Success-Response: +* { +* "message": "Changed hacker information", +* "data": { +* "reviewerComments": "John Doe" +* } +* } +* @apiPermission Administrator +*/ +hackerRouter.route("/reviewerComments2/:id").patch( + Middleware.Validator.RouteParam.idValidator, + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Validator.Hacker.updateReviewerComments2Validator, + Middleware.parseBody.middleware, + Middleware.Hacker.parsePatch, + Middleware.Hacker.updateHacker, + Controllers.Hacker.updatedHacker +); + /** * @api {patch} /hacker/accept/:id accept a Hacker * @apiName acceptHacker @@ -394,7 +566,7 @@ module.exports = { Controllers.Hacker.updatedHackerBatch ); /** - * @api {patch} /hacker/checkin/:id update a hacker's status to be 'Checked-in'. Note that the Hacker must eitehr be Accepted or Confirmed. + * @api {patch} /hacker/checkin/:id update a hacker's status to be 'Checked-in'. Note that the Hacker must eitehr be Accepted or Confirmed. Emails the hacker that they have been checked in. * @apiName checkinHacker * @apiGroup Hacker * @apiVersion 0.0.9 @@ -782,7 +954,7 @@ module.exports = { /** * @api {patch} /hacker/confirmation/:id - * Allows confirmation of hacker attendence if they are accepted. Also allows change from 'confirmed' to 'withdrawn'. + * Allows confirmation of hacker attendence if they are accepted. Also allows change from 'confirmed' to 'withdrawn'. Sends email confirmation of status change. * @apiName patchHackerConfirmed * @apiGroup Hacker * @apiVersion 0.0.9 diff --git a/scripts/accept_script.py b/scripts/accept_script.py index f76f445e..7fc71334 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -21,6 +21,59 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' +} +VALID_REVIEWER_NAME = { + '0': '', + '1': 'Amy', + '2': 'Carolyn', + '3': 'Clara', + '4': 'Debo', + '5': 'Deon', + '6': 'Doaa', + '7': 'Emily', + '8': 'Emma', + '9': 'Ethan', + '10': 'Evan', + '11': 'Finnley', + '12': 'Gabriel', + '13': 'Ian', + '14': 'Inaya', + '15': 'Jake', + '16': 'Jamie', + '17': 'Jane J.', + '18': 'Jane K.', + '19': 'Jeffrey', + '20': 'Joshua', + '21': 'Jyothsna', + '22': 'Khyati', + '23': 'Michael', + '24': 'Mika', + '25': 'Mubeen', + '26': 'Mira', + '27': 'Oishika', + '28': 'Olivia', + '29': 'Qi', + '30': 'Rémi', + '31': 'Sebastian', + '32': 'Shirley', + '33': 'Sihan', + '34': 'Siva', + '35': 'Snigdha', + '36': 'Stephanie', + '37': 'Tavi', + '38': 'Tina', + '39': 'Vipul', + '40': 'Yue Qian', +} + BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', @@ -28,7 +81,8 @@ '4': 'downloadResume', '5': 'inviteUsers', '6': 'getHackers', - '7': 'acceptHackers' + '7': 'acceptHackers', + '8': 'updateReviewerStatus', } LOG_VERBOSITIES = { '0': 'None', @@ -202,6 +256,71 @@ def status(prefixStr) -> str: ) return initial_status +def reviewerStatus(prefixStr) -> str: + reviewerStatus_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_STATUSES.items()] + initial_reviewerStatus = requestUntilSuccess( + 'Input {0} reviewerStatus:\n{1}'.format(prefixStr, ''.join(reviewerStatus_list)), + 'Invalid {0} reviewerStatus'.format(prefixStr), + lambda x: x in VALID_REVIEWER_STATUSES.keys(), + lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerStatus + +def reviewerStatus2(prefixStr) -> str: + reviewerStatus2_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_STATUSES.items()] + initial_reviewerStatus2 = requestUntilSuccess( + 'Input {0} reviewerStatus2:\n{1}'.format(prefixStr, ''.join(reviewerStatus2_list)), + 'Invalid {0} reviewerStatus2'.format(prefixStr), + lambda x: x in VALID_REVIEWER_STATUSES.keys(), + lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerStatus2 + +def reviewerName(prefixStr) -> str: + reviewerName_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_NAME.items()] + initial_reviewerName = requestUntilSuccess( + 'Input {0} reviewerName:\n{1}'.format(prefixStr, ''.join(reviewerName_list)), + 'Invalid {0} reviewerName'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerName + +def reviewerName2(prefixStr) -> str: + reviewerName2_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_NAME.items()] + initial_reviewerName2 = requestUntilSuccess( + 'Input {0} reviewerName2:\n{1}'.format(prefixStr, ''.join(reviewerName2_list)), + 'Invalid {0} reviewerName2'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerName2 + +def reviewerComments(prefixStr) -> str: + reviewerComments_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerComments = requestUntilSuccess( + 'Input {0} reviewerComments:\n{1}'.format(prefixStr, ''.join(reviewerComments_list)), + 'Invalid {0} reviewerComments'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerComments + +def reviewerComments2(prefixStr) -> str: + reviewerComments2_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerComments2 = requestUntilSuccess( + 'Input {0} reviewerComments2:\n{1}'.format(prefixStr, ''.join(reviewerComments2_list)), + 'Invalid {0} reviewerComments2'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerComments2 def batchAction() -> str: status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] @@ -230,6 +349,48 @@ def hasValidStatus(status, hackerInfo): return False +def hasValidReviewerStatus(reviewerStatus, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerStatus'] == reviewerStatus: + return True + else: + return False + + +def hasValidReviewerStatus2(reviewerStatus2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerStatus2'] == reviewerStatus2: + return True + else: + return False + + +def hasValidReviewerName(reviewerName, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerName'] == reviewerName: + return True + else: + return False + + +def hasValidReviewerName2(reviewerName2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerName2'] == reviewerName2: + return True + else: + return False + + +def hasValidReviewerComments(reviewerComments, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerComments'] == reviewerComments: + return True + else: + return False + + +def hasValidReviewerComments2(reviewerComments2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerComments2'] == reviewerComments2: + return True + else: + return False + + def search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) expand = 'true' if expand else 'false' @@ -309,31 +470,185 @@ def updateStatus(): _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) +def updateReviewerStatus(): + INITIAL_REVIEWER_STATUS = reviewerStatus('initial') + NEW_REVIEWER_STATUS = reviewerStatus('new') + HACKER_IDs = getIdList() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerStatus = hasValidReviewerStatus(INITIAL_REVIEWER_STATUS, hacker) + if validReviewerStatus: + r = s.patch('{0}/api/hacker/reviewerStatus/{1}'.format(API_URL, ID), + {"reviewerStatus": NEW_REVIEWER_STATUS}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_STATUS, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() +def updateReviewerStatus2(): + INITIAL_REVIEWER_STATUS2 = reviewerStatus2('initial') + NEW_REVIEWER_STATUS2 = reviewerStatus2('new') + HACKER_IDs = getIdList() for index, ID in enumerate(HACKER_IDs): # so that we aren't 0-based index index = index + 1 hacker = getHacker(ID) - validStatus = hasValidStatus(INITIAL_STATUS, hacker) - if validStatus: - r = s.post( - '{0}/api/hacker/email/dayOf/{1}'.format(API_URL, ID)) - if r.status_code != 200: - _print('cannot send email to {0}'.format( - ID), 1, index, len(HACKER_IDs)) - else: - _print('Sent email to {0}'.format( - ID), 3, index, len(HACKER_IDs)) + validReviewerStatus2 = hasValidReviewerStatus2(INITIAL_REVIEWER_STATUS2, hacker) + if validReviewerStatus2: + r = s.patch('{0}/api/hacker/reviewerStatus2/{1}'.format(API_URL, ID), + {"reviewerStatus2": NEW_REVIEWER_STATUS2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_STATUS2, ID), 3, index, len(HACKER_IDs)) elif hacker is not None: - _print('Sent invalid status for {0}'.format( + _print('invalid status for {0}'.format( ID), 1, index, len(HACKER_IDs)) else: - _print('Could not find {0}'.format( + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerName(): + INITIAL_REVIEWER_NAME = reviewerName('initial') + NEW_REVIEWER_NAME = reviewerName('new') + HACKER_IDs = getIdList() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerName = hasValidReviewerName(INITIAL_REVIEWER_NAME, hacker) + if validReviewerName: + r = s.patch('{0}/api/hacker/reviewerName/{1}'.format(API_URL, ID), + {"reviewerName": NEW_REVIEWER_NAME}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_NAME, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerName2(): + INITIAL_REVIEWER_NAME2 = reviewerName2('initial') + NEW_REVIEWER_NAME2 = reviewerName2('new') + HACKER_IDs = getIdList() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerName2 = hasValidReviewerName2(INITIAL_REVIEWER_NAME2, hacker) + if validReviewerName2: + r = s.patch('{0}/api/hacker/reviewerName2/{1}'.format(API_URL, ID), + {"reviewerName2": NEW_REVIEWER_NAME2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_NAME2, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerComments(): + INITIAL_REVIEWER_COMMENTS = reviewerComments('initial') + NEW_REVIEWER_COMMENTS = reviewerComments('new') + HACKER_IDs = getIdList() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerComments = hasValidReviewerComments(INITIAL_REVIEWER_COMMENTS, hacker) + if validReviewerComments: + r = s.patch('{0}/api/hacker/reviewerComments/{1}'.format(API_URL, ID), + {"reviewerComments": NEW_REVIEWER_COMMENTS}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_COMMENTS, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) +def updateReviewerComments2(): + INITIAL_REVIEWER_COMMENTS2 = reviewerComments2('initial') + NEW_REVIEWER_COMMENTS2 = reviewerComments2('new') + HACKER_IDs = getIdList() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerComments2 = hasValidReviewerComments2(INITIAL_REVIEWER_COMMENTS2, hacker) + if validReviewerComments2: + r = s.patch('{0}/api/hacker/reviewerComments/{1}'.format(API_URL, ID), + {"reviewerComments": NEW_REVIEWER_COMMENTS2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_COMMENTS2, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def assignReviewers(): + HACKER_IDs = getIdList() + numHackers = HACKER_IDs.count + + +# def sendDayOfEmail(): +# INITIAL_STATUS = status('initial') +# HACKER_IDs = loadIDs() +# for index, ID in enumerate(HACKER_IDs): +# # so that we aren't 0-based index +# index = index + 1 +# hacker = getHacker(ID) +# validStatus = hasValidStatus(INITIAL_STATUS, hacker) +# if validStatus: +# r = s.post( +# '{0}/api/hacker/email/dayOf/{1}'.format(API_URL, ID)) +# if r.status_code != 200: +# _print('cannot send email to {0}'.format( +# ID), 1, index, len(HACKER_IDs)) +# else: +# _print('Sent email to {0}'.format( +# ID), 3, index, len(HACKER_IDs)) +# elif hacker is not None: +# _print('Sent invalid status for {0}'.format( +# ID), 1, index, len(HACKER_IDs)) +# else: +# _print('Could not find {0}'.format( +# ID), 1, index, len(HACKER_IDs)) + def sendWeekOfEmail(): INITIAL_STATUS = status('initial') @@ -464,6 +779,18 @@ def getHackers(): getHackers() elif BATCH_ACTION == 'acceptHackers': acceptFromEmails() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() + elif BATCH_ACTION == 'updateReviewerStatus2': + updateReviewerStatus2() + elif BATCH_ACTION == 'updateReviewerName': + updateReviewerName() + elif BATCH_ACTION == 'updateReviewerName2': + updateReviewerName2() + elif BATCH_ACTION == 'updateReviewerComments': + updateReviewerComments() + elif BATCH_ACTION == 'updateReviewerComments2': + updateReviewerComments2() print('Finished {0}'.format(BATCH_ACTION)) except Exception as e: _print('Failed to perform action {0}: {1}'.format( diff --git a/scripts/batch_scripts.py b/scripts/batch_scripts.py index 387aa51b..518e483b 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -1,6 +1,6 @@ #!/bin/bash/python3 import base64 -from bson import ObjectId +from json import ObjectId import csv import getpass import json @@ -21,13 +21,23 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', '3': 'weekOf', '4': 'downloadResume', '5': 'inviteUsers', - '6': 'getHackers' + '6': 'getHackers', + '7': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -212,6 +222,72 @@ def batchAction() -> str: ) return batch_action +def reviewerStatus(prefixStr) -> str: + reviewerStatus_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_STATUSES.items()] + initial_reviewerStatus = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerStatus_list)), + 'Invalid {0} status'.format(prefixStr), + lambda x: x in VALID_REVIEWER_STATUSES.keys(), + lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerStatus + +def reviewerStatus2(prefixStr) -> str: + reviewerStatus2_list = ['{0}: {1}\n'.format(k, v) + for k, v in VALID_REVIEWER_STATUSES.items()] + initial_reviewerStatus2 = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerStatus2_list)), + 'Invalid {0} status'.format(prefixStr), + lambda x: x in VALID_REVIEWER_STATUSES.keys(), + lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerStatus2 + +def reviewerName(prefixStr) -> str: + reviewerName_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerName = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerName_list)), + 'Invalid {0} status'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerName + +def reviewerName2(prefixStr) -> str: + reviewerName2_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerName2 = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerName2_list)), + 'Invalid {0} status'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerName2 + +def reviewerComments(prefixStr) -> str: + reviewerComments_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerComments = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerComments_list)), + 'Invalid {0} status'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerComments + +def reviewerComments2(prefixStr) -> str: + reviewerComments2_list = ['{0}: {1}\n'.format(k, v) + for k, v in str] + initial_reviewerComments2 = requestUntilSuccess( + 'Input {0} status:\n{1}'.format(prefixStr, ''.join(reviewerComments2_list)), + 'Invalid {0} status'.format(prefixStr), + # lambda x: x in VALID_REVIEWER_STATUSES.keys(), + # lambda x: VALID_REVIEWER_STATUSES[x] + ) + return initial_reviewerComments2 + def getHacker(ID): r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) @@ -228,6 +304,42 @@ def hasValidStatus(status, hackerInfo): else: return False +def hasValidReviewerStatus(reviewerStatus, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerStatus'] == reviewerStatus: + return True + else: + return False + +def hasValidReviewerStatus2(reviewerStatus2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerStatus2'] == reviewerStatus2: + return True + else: + return False + +def hasValidReviewerName(reviewerName, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerName'] == reviewerName: + return True + else: + return False + +def hasValidReviewerName2(reviewerName2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerName2'] == reviewerName2: + return True + else: + return False + +def hasValidReviewerComments(reviewerComments, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerComments'] == reviewerComments: + return True + else: + return False + +def hasValidReviewerComments2(reviewerComments2, hackerInfo): + if hackerInfo is not None and hackerInfo['reviewerComments2'] == reviewerComments2: + return True + else: + return False + def search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) @@ -268,6 +380,156 @@ def updateStatus(): _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) +def updateReviewerStatus(): + INITIAL_REVIEWER_STATUS = reviewerStatus('initial') + NEW_REVIEWER_STATUS = reviewerStatus('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerStatus = hasValidReviewerStatus(INITIAL_REVIEWER_STATUS, hacker) + if validReviewerStatus: + r = s.patch('{0}/api/hacker/reviewerStatus/{1}'.format(API_URL, ID), + {"reviewerStatus": NEW_REVIEWER_STATUS}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_STATUS, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerStatus2(): + INITIAL_REVIEWER_STATUS2 = reviewerStatus2('initial') + NEW_REVIEWER_STATUS2 = reviewerStatus2('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerStatus2 = hasValidReviewerStatus2(INITIAL_REVIEWER_STATUS2, hacker) + if validReviewerStatus2: + r = s.patch('{0}/api/hacker/reviewerStatus2/{1}'.format(API_URL, ID), + {"reviewerStatus2": NEW_REVIEWER_STATUS2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_STATUS2, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerName(): + INITIAL_REVIEWER_NAME = reviewerName('initial') + NEW_REVIEWER_NAME = reviewerName('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerName = hasValidReviewerName(INITIAL_REVIEWER_NAME, hacker) + if validReviewerName: + r = s.patch('{0}/api/hacker/reviewerName/{1}'.format(API_URL, ID), + {"reviewerName": NEW_REVIEWER_NAME}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_NAME, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerName2(): + INITIAL_REVIEWER_NAME2 = reviewerName2('initial') + NEW_REVIEWER_NAME2 = reviewerName2('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerName2 = hasValidReviewerName2(INITIAL_REVIEWER_NAME2, hacker) + if validReviewerName2: + r = s.patch('{0}/api/hacker/reviewerName2/{1}'.format(API_URL, ID), + {"reviewerName2": NEW_REVIEWER_NAME2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_NAME2, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerComments(): + INITIAL_REVIEWER_COMMENTS = reviewerComments('initial') + NEW_REVIEWER_COMMENTS = reviewerComments('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerComments = hasValidReviewerComments(INITIAL_REVIEWER_COMMENTS, hacker) + if validReviewerComments: + r = s.patch('{0}/api/hacker/reviewerComments/{1}'.format(API_URL, ID), + {"reviewerComments": NEW_REVIEWER_COMMENTS}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_COMMENTS, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + +def updateReviewerComments2(): + INITIAL_REVIEWER_COMMENTS2 = reviewerComments2('initial') + NEW_REVIEWER_COMMENTS2 = reviewerComments2('new') + HACKER_IDs = loadIDs() + for index, ID in enumerate(HACKER_IDs): + # so that we aren't 0-based index + index = index + 1 + hacker = getHacker(ID) + validReviewerComments2 = hasValidReviewerComments2(INITIAL_REVIEWER_COMMENTS2, hacker) + if validReviewerComments2: + r = s.patch('{0}/api/hacker/reviewerComments2/{1}'.format(API_URL, ID), + {"reviewerComments2": NEW_REVIEWER_COMMENTS2}) + # if r.status_code != 200: + # _print('cannot update status for {0}'.format( + # ID), 1, index, len(HACKER_IDs)) + # else: + _print('{0} {1}'.format( + NEW_REVIEWER_COMMENTS2, ID), 3, index, len(HACKER_IDs)) + elif hacker is not None: + _print('invalid status for {0}'.format( + ID), 1, index, len(HACKER_IDs)) + else: + _print('could not find {0}'.format( + ID), 1, index, len(HACKER_IDs)) + def sendDayOfEmail(): INITIAL_STATUS = status('initial') @@ -421,6 +683,18 @@ def getHackers(): inviteUsers() elif BATCH_ACTION == 'getHackers': getHackers() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() + elif BATCH_ACTION == 'updateReviewerStatus2': + updateReviewerStatus2() + elif BATCH_ACTION == 'updateReviewerName': + updateReviewerName() + elif BATCH_ACTION == 'updateReviewerName2': + updateReviewerName2() + elif BATCH_ACTION == 'updateReviewerComments': + updateReviewerComments() + elif BATCH_ACTION == 'updateReviewerComments2': + updateReviewerComments2() print('Finished {0}'.format(BATCH_ACTION)) except Exception as e: _print('Failed to perform action {0}: {1}'.format( diff --git a/tests/hacker.test.js b/tests/hacker.test.js index b344e86d..08b59fdb 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1734,6 +1734,12 @@ describe("GET Hacker stats", function() { res.body.data.should.have.property("stats"); res.body.data.stats.should.have.property("total"); res.body.data.stats.should.have.property("status"); + res.body.data.stats.should.have.property("reviewerStatus"); + res.body.data.stats.should.have.property("reviewerStatus2"); + res.body.data.stats.should.have.property("reviewerName"); + res.body.data.stats.should.have.property("reviewerName2"); + res.body.data.stats.should.have.property("reviewerComments"); + res.body.data.stats.should.have.property("reviewerComments2"); res.body.data.stats.should.have.property("school"); res.body.data.stats.should.have.property("degree"); res.body.data.stats.should.have.property("gender");