From 831b82ccf7e095b59b2c712d10bccbf685ad614d Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sat, 22 Feb 2025 18:39:12 -0500 Subject: [PATCH 01/23] not finished create app rev --- constants/general.constant.js | 17 +++++ constants/routes.constant.js | 10 +++ docs/api/api_data.js | 60 +++++++++++++++ docs/api/api_data.json | 13 ++-- middlewares/hacker.middleware.js | 2 + middlewares/validators/hacker.validator.js | 8 ++ models/hacker.model.js | 6 ++ routes/api/hacker.js | 30 ++++++++ scripts/accept_script.py | 86 +++++++++++++++++----- scripts/batch_scripts.py | 54 +++++++++++++- tests/hacker.test.js | 1 + tests/util/hacker.test.util.js | 7 ++ 12 files changed, 270 insertions(+), 24 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index 5e23d2fe..cffbc967 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -25,6 +25,18 @@ const HACKER_STATUSES = [ HACKER_STATUS_CHECKED_IN, HACKER_STATUS_DECLINED ]; + +const HACKER_REVIEWER_STATUS_NONE = "None"; +const HACKER_REVIEWER_STATUS_YES = "Yes"; +const HACKER_REVIEWER_STATUS_NO = "No"; +const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +const HACKER_REVIEWER_STATUSES = [ + HACKER_REVIEWER_STATUS_NONE, + HACKER_REVIEWER_STATUS_YES, + HACKER_REVIEWER_STATUS_NO, + HACKER_REVIEWER_STATUS_MAYBE, +]; + // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -185,7 +197,12 @@ 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_YES: HACKER_REVIEWER_STATUS_YES, + HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, + HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, HACKER_STATUSES: HACKER_STATUSES, + HACKER_REVIEWER_STATUSES: HACKER_REVIEWER_STATUSES, 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 e880674d..fc54a92b 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,6 +153,16 @@ 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) + // }, 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 25e0c5a6..b0f50926 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,6 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" + // } + // ] + // } + // }, + // "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": "post", "url": "/hacker/resume/:id", diff --git a/docs/api/api_data.json b/docs/api/api_data.json index cfc8a3ab..4e281765 100644 --- a/docs/api/api_data.json +++ b/docs/api/api_data.json @@ -1501,7 +1501,7 @@ "examples": [ { "title": "application: ", - "content": "{\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 \"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}", + "content": "{\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}", "type": "Json" } ] @@ -1528,7 +1528,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\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 \"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}", + "content": "{\n \"message\": \"Hacker creation successful\", \n \"data\": {\n \"id\":\"5bff4d736f86be0a41badb91\",\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}", "type": "object" } ] @@ -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 \"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" } ] @@ -1692,7 +1692,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 \"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\": 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 }", "type": "object" } ] @@ -1927,7 +1927,7 @@ "examples": [ { "title": "application: ", - "content": "{\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 \"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 }", + "content": "{\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 }", "type": "Json" } ] @@ -1954,7 +1954,7 @@ "examples": [ { "title": "Success-Response: ", - "content": "{\n \"message\": \"Changed 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 \"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\": \"Changed 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}", "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..57bee7f5 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,6 +102,7 @@ function parseConfirmation(req, res, next) { return next(); } +// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req @@ -112,6 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; + // req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 50078261..74e5db9f 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -291,6 +291,14 @@ module.exports = { false ) ], + // updateReviewerStatusValidator: [ + // VALIDATOR.enumValidator( + // "body", + // "reviewerStatus", + // Constants.HACKER_REVIEWER_STATUSES, + // false + // ) + // ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/models/hacker.model.js b/models/hacker.model.js index 291964e3..a13e5e39 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -15,6 +15,12 @@ const HackerSchema = new mongoose.Schema({ required: true, default: "None" }, + reviewerStatus: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: true, + default: "None" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 77cb1d43..0cff635c 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -293,6 +293,36 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") + // * @apiSuccess {string} message Success message + // * @apiSuccess {object} data Hacker object + // * @apiSuccessExample {object} Success-Response: + // * { + // * "message": "Changed hacker information", + // * "data": { + // * "reviewerStatus": "Yes" + // * } + // * } + // * @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/accept/:id accept a Hacker * @apiName acceptHacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index f76f445e..228b25a0 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -21,6 +21,12 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe', +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', @@ -28,7 +34,8 @@ '4': 'downloadResume', '5': 'inviteUsers', '6': 'getHackers', - '7': 'acceptHackers' + '7': 'acceptHackers', + '8': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -202,6 +209,17 @@ 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 batchAction() -> str: status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] @@ -230,6 +248,13 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) expand = 'true' if expand else 'false' @@ -309,32 +334,57 @@ def updateStatus(): _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) - -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() +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) - 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)) + 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('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 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') HACKER_IDs = loadIDs() @@ -464,6 +514,8 @@ def getHackers(): getHackers() elif BATCH_ACTION == 'acceptHackers': acceptFromEmails() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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..ffad8393 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -21,13 +21,20 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe' +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', '3': 'weekOf', '4': 'downloadResume', '5': 'inviteUsers', - '6': 'getHackers' + '6': 'getHackers', + '7': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -212,6 +219,18 @@ 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 getHacker(ID): r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) @@ -228,6 +247,12 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) @@ -268,6 +293,31 @@ 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 sendDayOfEmail(): INITIAL_STATUS = status('initial') @@ -421,6 +471,8 @@ def getHackers(): inviteUsers() elif BATCH_ACTION == 'getHackers': getHackers() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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 6bd7bc69..97ec3790 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1734,6 +1734,7 @@ 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("school"); res.body.data.stats.should.have.property("degree"); res.body.data.stats.should.have.property("gender"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 1eb310cb..a1c928b3 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,6 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -56,6 +57,7 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -98,6 +100,7 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", + reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -140,6 +143,7 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -182,6 +186,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", + reviewerStatus: "Maybe", application: { general: { school: "University of Blah", @@ -224,6 +229,7 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -628,6 +634,7 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 46a2e8e117c36e235e51688de67374c756acc4b2 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 30 Mar 2025 22:36:08 -0400 Subject: [PATCH 02/23] Reviewer status: 1/2 works (needs to enter twice??) --- constants/routes.constant.js | 20 ++-- docs/api/api_data.js | 120 ++++++++++----------- middlewares/hacker.middleware.js | 4 +- middlewares/validators/hacker.validator.js | 16 +-- routes/api/hacker.js | 58 +++++----- scripts/accept_script.py | 9 +- scripts/batch_scripts.py | 11 +- tests/util/hacker.test.util.js | 4 +- 8 files changed, 124 insertions(+), 118 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index fc54a92b..0adfef71 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,16 +153,16 @@ 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) - // }, + 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) + }, 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 b0f50926..c12265d3 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,66 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" - // } - // ] - // } - // }, - // "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"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index 57bee7f5..c993f1bc 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,10 +102,10 @@ function parseConfirmation(req, res, next) { return next(); } -// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -113,7 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; - // req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 74e5db9f..991245c8 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -291,14 +291,14 @@ module.exports = { false ) ], - // updateReviewerStatusValidator: [ - // VALIDATOR.enumValidator( - // "body", - // "reviewerStatus", - // Constants.HACKER_REVIEWER_STATUSES, - // false - // ) - // ], + updateReviewerStatusValidator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0cff635c..9862195c 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -293,35 +293,35 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") - // * @apiSuccess {string} message Success message - // * @apiSuccess {object} data Hacker object - // * @apiSuccessExample {object} Success-Response: - // * { - // * "message": "Changed hacker information", - // * "data": { - // * "reviewerStatus": "Yes" - // * } - // * } - // * @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/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": "Yes" + * } + * } + * @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/accept/:id accept a Hacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 228b25a0..950e5c92 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe', + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/scripts/batch_scripts.py b/scripts/batch_scripts.py index ffad8393..9f5be703 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 @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe' + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index a1c928b3..f2bb9839 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Yes", + reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -186,7 +186,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "Maybe", + reviewerStatus: "", application: { general: { school: "University of Blah", From e0ee561a3ca278fcbf32d06964d0491c7603df74 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 31 Mar 2025 20:48:48 -0400 Subject: [PATCH 03/23] Hacker Reviewer Feature --- constants/general.constant.js | 29 +- constants/routes.constant.js | 20 ++ docs/api/api_data.js | 300 +++++++++++++++++++++ middlewares/hacker.middleware.js | 10 + middlewares/validators/hacker.validator.js | 36 +++ models/hacker.model.js | 32 ++- routes/api/hacker.js | 154 ++++++++++- scripts/accept_script.py | 225 +++++++++++++++- scripts/batch_scripts.py | 219 +++++++++++++++ tests/hacker.test.js | 5 + tests/util/hacker.test.util.js | 7 - 11 files changed, 1013 insertions(+), 24 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index cffbc967..8eba3108 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -26,15 +26,21 @@ const HACKER_STATUSES = [ HACKER_STATUS_DECLINED ]; -const HACKER_REVIEWER_STATUS_NONE = "None"; -const HACKER_REVIEWER_STATUS_YES = "Yes"; -const HACKER_REVIEWER_STATUS_NO = "No"; -const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +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_YES, - HACKER_REVIEWER_STATUS_NO, - HACKER_REVIEWER_STATUS_MAYBE, + HACKER_REVIEWER_STATUS_POOR, + HACKER_REVIEWER_STATUS_WEAK, + HACKER_REVIEWER_STATUS_AVERAGE, + HACKER_REVIEWER_STATUS_STRONG, + HACKER_REVIEWER_STATUS_OUTSTANDING, + HACKER_REVIEWER_STATUS_WHITELIST, ]; // This date is Jan 6, 2020 00:00:00 GMT -0500 @@ -198,9 +204,12 @@ module.exports = { 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_YES: HACKER_REVIEWER_STATUS_YES, - HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, - HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, + 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, TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE, diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 0adfef71..a4b68b46 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -163,6 +163,26 @@ const hackerRoutes = { 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(168) + }, + patchSelfReviewerStatus2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(169) + }, + // patchAnyReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, + // _id: mongoose.Types.ObjectId.createFromTime(168) + // }, + // patchSelfReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, + // _id: mongoose.Types.ObjectId.createFromTime(169) + // }, 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 c12265d3..959de392 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2177,6 +2177,306 @@ define({ "api": [ } ] }, + { + "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 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/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 name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerName2/:id", + "title": "update a hacker's reviewer name", + "name": "patchHackerReviewerName2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerName2", + "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName2/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments/:id", + "title": "update a hacker's reviewer comments", + "name": "patchHackerReviewerComments", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments", + "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments2/:id", + "title": "update a hacker's reviewer comments 2", + "name": "patchHackerReviewerComments2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments2", + "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments2/:id" + } + ] + }, { "type": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index c993f1bc..d5cf893b 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -106,6 +106,11 @@ function parseConfirmation(req, res, next) { * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus2: String}}}} req + * @param {{body: {hackerDetails: {reviewerName: String}}}} req + * @param {{body: {hackerDetails: {reviewerName2: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments2: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -114,6 +119,11 @@ function parseConfirmation(req, res, next) { function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus2 = "none"; + req.body.hackerDetails.reviewerName = ""; + req.body.hackerDetails.reviewerName2 = ""; + 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 991245c8..ffd07dd1 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -299,6 +299,42 @@ module.exports = { false ) ], + updateReviewerStatus2Validator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus2", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], + updateReviewerNameValidator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName", + false + ) + ], + updateReviewerName2Validator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName2", + 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 a13e5e39..38465898 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -18,9 +18,39 @@ const HackerSchema = new mongoose.Schema({ reviewerStatus: { type: String, enum: Constants.HACKER_REVIEWER_STATUSES, - required: true, + required: false, default: "None" }, + reviewerStatus2: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: false, + default: "None" + }, + reviewerName: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerName2: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments2: { + type: String, + enum: String, + required: false, + default: "" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 9862195c..8e1434ec 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -306,23 +306,167 @@ module.exports = { * { * "message": "Changed hacker information", * "data": { - * "reviewerStatus": "Yes" + * "reviewerStatus": "Outstanding" * } * } * @apiPermission Administrator */ hackerRouter.route("/reviewerStatus/:id").patch( - // Middleware.Validator.RouteParam.idValidator, + Middleware.Validator.RouteParam.idValidator, // Middleware.Auth.ensureAuthenticated(), // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - // Middleware.Validator.Hacker.updateReviewerStatusValidator, + Middleware.Validator.Hacker.updateReviewerStatusValidator, // Middleware.parseBody.middleware, - // Middleware.Hacker.parsePatch, - + 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 diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 950e5c92..b7bb455e 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -38,7 +38,7 @@ '5': 'inviteUsers', '6': 'getHackers', '7': 'acceptHackers', - '8': 'updateReviewerStatus' + '8': 'updateReviewerStatus', } LOG_VERBOSITIES = { '0': 'None', @@ -223,6 +223,60 @@ def reviewerStatus(prefixStr) -> str: ) 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 str] + 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 str] + 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()] @@ -258,6 +312,41 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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' @@ -362,7 +451,131 @@ def updateReviewerStatus(): _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 = getIdList() + 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 = 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 sendDayOfEmail(): # INITIAL_STATUS = status('initial') # HACKER_IDs = loadIDs() @@ -519,6 +732,16 @@ def getHackers(): 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 9f5be703..518e483b 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -233,6 +233,60 @@ def reviewerStatus(prefixStr) -> str: ) 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): @@ -256,6 +310,36 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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) @@ -321,6 +405,131 @@ def updateReviewerStatus(): _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') @@ -476,6 +685,16 @@ def 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 97ec3790..70817732 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1735,6 +1735,11 @@ describe("GET Hacker stats", function() { 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"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index f2bb9839..1eb310cb 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,6 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -57,7 +56,6 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -100,7 +98,6 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", - reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -143,7 +140,6 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -186,7 +182,6 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "", application: { general: { school: "University of Blah", @@ -229,7 +224,6 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -634,7 +628,6 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 6c77c84659c79ea880ba623e7cc9bbb9fc0bac2a Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Fri, 4 Apr 2025 12:43:10 -0400 Subject: [PATCH 04/23] Cleaner code --- docs/api/api_data.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index 959de392..105d21e3 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2132,7 +2132,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus", - "description": "

Reviewer status of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2159,7 +2159,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus\": \"Poor\"\n }\n}", "type": "object" } ] @@ -2180,7 +2180,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerStatus2/:id", - "title": "update a hacker's reviewer status 2", + "title": "update a hacker's reviewer status (2)", "name": "patchHackerReviewerStatus2", "group": "Hacker", "version": "0.0.9", @@ -2192,7 +2192,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus2", - "description": "

Reviewer status 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2219,7 +2219,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus2\": \"Outstanding\"\n }\n}", "type": "object" } ] @@ -2252,7 +2252,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name of the hacker's application

" } ] } @@ -2279,7 +2279,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName\": \"Jane Doe\"\n }\n}", "type": "object" } ] @@ -2300,7 +2300,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerName2/:id", - "title": "update a hacker's reviewer name", + "title": "update a hacker's reviewer name (2)", "name": "patchHackerReviewerName2", "group": "Hacker", "version": "0.0.9", @@ -2312,7 +2312,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName2", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name (2) of the hacker's application

" } ] } @@ -2339,7 +2339,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName2\": \"John Doe\"\n }\n}", "type": "object" } ] @@ -2360,7 +2360,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments/:id", - "title": "update a hacker's reviewer comments", + "title": "update a hacker's reviewer's comments", "name": "patchHackerReviewerComments", "group": "Hacker", "version": "0.0.9", @@ -2372,7 +2372,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments", - "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments of the hacker's application

" } ] } @@ -2399,7 +2399,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] @@ -2420,7 +2420,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments2/:id", - "title": "update a hacker's reviewer comments 2", + "title": "update a hacker's reviewer's comments (2)", "name": "patchHackerReviewerComments2", "group": "Hacker", "version": "0.0.9", @@ -2432,7 +2432,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments2", - "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments (2) of the hacker's application

" } ] } @@ -2459,7 +2459,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] From eae9218e4ea13b46fb45b49ef76b7185d9cc5084 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 29 Sep 2025 21:26:24 -0400 Subject: [PATCH 05/23] remove uneccessary comments --- constants/routes.constant.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index a4b68b46..3d35faa8 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -173,16 +173,6 @@ const hackerRoutes = { uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, _id: mongoose.Types.ObjectId.createFromTime(169) }, - // patchAnyReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, - // _id: mongoose.Types.ObjectId.createFromTime(168) - // }, - // patchSelfReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, - // _id: mongoose.Types.ObjectId.createFromTime(169) - // }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, From f3a89570922ab8587d3c8c4bdd10908463da6ff5 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sat, 22 Feb 2025 18:39:12 -0500 Subject: [PATCH 06/23] not finished create app rev --- constants/general.constant.js | 17 +++++ constants/routes.constant.js | 10 +++ docs/api/api_data.js | 60 +++++++++++++++ docs/api/api_data.json | 3 +- middlewares/hacker.middleware.js | 2 + middlewares/validators/hacker.validator.js | 8 ++ models/hacker.model.js | 6 ++ routes/api/hacker.js | 30 ++++++++ scripts/accept_script.py | 86 +++++++++++++++++----- scripts/batch_scripts.py | 54 +++++++++++++- tests/hacker.test.js | 1 + tests/util/hacker.test.util.js | 7 ++ 12 files changed, 265 insertions(+), 19 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index 5e23d2fe..cffbc967 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -25,6 +25,18 @@ const HACKER_STATUSES = [ HACKER_STATUS_CHECKED_IN, HACKER_STATUS_DECLINED ]; + +const HACKER_REVIEWER_STATUS_NONE = "None"; +const HACKER_REVIEWER_STATUS_YES = "Yes"; +const HACKER_REVIEWER_STATUS_NO = "No"; +const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +const HACKER_REVIEWER_STATUSES = [ + HACKER_REVIEWER_STATUS_NONE, + HACKER_REVIEWER_STATUS_YES, + HACKER_REVIEWER_STATUS_NO, + HACKER_REVIEWER_STATUS_MAYBE, +]; + // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -185,7 +197,12 @@ 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_YES: HACKER_REVIEWER_STATUS_YES, + HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, + HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, HACKER_STATUSES: HACKER_STATUSES, + HACKER_REVIEWER_STATUSES: HACKER_REVIEWER_STATUSES, 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 e880674d..fc54a92b 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,6 +153,16 @@ 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) + // }, 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..0a4ba50b 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,6 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" + // } + // ] + // } + // }, + // "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": "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..57bee7f5 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,6 +102,7 @@ function parseConfirmation(req, res, next) { return next(); } +// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req @@ -112,6 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; + // req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 05a3b413..fa92c080 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -306,6 +306,14 @@ module.exports = { false ) ], + // updateReviewerStatusValidator: [ + // VALIDATOR.enumValidator( + // "body", + // "reviewerStatus", + // Constants.HACKER_REVIEWER_STATUSES, + // false + // ) + // ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/models/hacker.model.js b/models/hacker.model.js index 51171616..8ee13f5b 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -15,6 +15,12 @@ const HackerSchema = new mongoose.Schema({ required: true, default: "None" }, + reviewerStatus: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: true, + default: "None" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0fe125a6..08f4677e 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -299,6 +299,36 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") + // * @apiSuccess {string} message Success message + // * @apiSuccess {object} data Hacker object + // * @apiSuccessExample {object} Success-Response: + // * { + // * "message": "Changed hacker information", + // * "data": { + // * "reviewerStatus": "Yes" + // * } + // * } + // * @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/accept/:id accept a Hacker * @apiName acceptHacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index f76f445e..228b25a0 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -21,6 +21,12 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe', +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', @@ -28,7 +34,8 @@ '4': 'downloadResume', '5': 'inviteUsers', '6': 'getHackers', - '7': 'acceptHackers' + '7': 'acceptHackers', + '8': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -202,6 +209,17 @@ 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 batchAction() -> str: status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] @@ -230,6 +248,13 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) expand = 'true' if expand else 'false' @@ -309,32 +334,57 @@ def updateStatus(): _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) - -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() +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) - 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)) + 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('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 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') HACKER_IDs = loadIDs() @@ -464,6 +514,8 @@ def getHackers(): getHackers() elif BATCH_ACTION == 'acceptHackers': acceptFromEmails() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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..ffad8393 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -21,13 +21,20 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe' +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', '3': 'weekOf', '4': 'downloadResume', '5': 'inviteUsers', - '6': 'getHackers' + '6': 'getHackers', + '7': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -212,6 +219,18 @@ 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 getHacker(ID): r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) @@ -228,6 +247,12 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) @@ -268,6 +293,31 @@ 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 sendDayOfEmail(): INITIAL_STATUS = status('initial') @@ -421,6 +471,8 @@ def getHackers(): inviteUsers() elif BATCH_ACTION == 'getHackers': getHackers() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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..19c61f74 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1734,6 +1734,7 @@ 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("school"); res.body.data.stats.should.have.property("degree"); res.body.data.stats.should.have.property("gender"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 3dd62cbe..fe760603 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,6 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -58,6 +59,7 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -102,6 +104,7 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", + reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -146,6 +149,7 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -190,6 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", + reviewerStatus: "Maybe", application: { general: { school: "University of Blah", @@ -234,6 +239,7 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -658,6 +664,7 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 659cd9e4faceac70f5a557b699d60abf436579f0 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 30 Mar 2025 22:36:08 -0400 Subject: [PATCH 07/23] Reviewer status: 1/2 works (needs to enter twice??) --- constants/routes.constant.js | 20 ++-- docs/api/api_data.js | 120 ++++++++++----------- middlewares/hacker.middleware.js | 4 +- middlewares/validators/hacker.validator.js | 16 +-- routes/api/hacker.js | 58 +++++----- scripts/accept_script.py | 9 +- scripts/batch_scripts.py | 11 +- tests/util/hacker.test.util.js | 4 +- 8 files changed, 124 insertions(+), 118 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index fc54a92b..0adfef71 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,16 +153,16 @@ 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) - // }, + 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) + }, 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 0a4ba50b..e14e0c7c 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,66 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" - // } - // ] - // } - // }, - // "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"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index 57bee7f5..c993f1bc 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,10 +102,10 @@ function parseConfirmation(req, res, next) { return next(); } -// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -113,7 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; - // req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index fa92c080..fae08e33 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -306,14 +306,14 @@ module.exports = { false ) ], - // updateReviewerStatusValidator: [ - // VALIDATOR.enumValidator( - // "body", - // "reviewerStatus", - // Constants.HACKER_REVIEWER_STATUSES, - // false - // ) - // ], + updateReviewerStatusValidator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 08f4677e..0f0f2d55 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -299,35 +299,35 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") - // * @apiSuccess {string} message Success message - // * @apiSuccess {object} data Hacker object - // * @apiSuccessExample {object} Success-Response: - // * { - // * "message": "Changed hacker information", - // * "data": { - // * "reviewerStatus": "Yes" - // * } - // * } - // * @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/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": "Yes" + * } + * } + * @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/accept/:id accept a Hacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 228b25a0..950e5c92 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe', + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/scripts/batch_scripts.py b/scripts/batch_scripts.py index ffad8393..9f5be703 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 @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe' + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index fe760603..4ffffa3d 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Yes", + reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -194,7 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "Maybe", + reviewerStatus: "", application: { general: { school: "University of Blah", From 61de1a32a0eee8d296292e04d989b7bd2d06dcc8 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 31 Mar 2025 20:48:48 -0400 Subject: [PATCH 08/23] Hacker Reviewer Feature --- constants/general.constant.js | 29 +- constants/routes.constant.js | 20 ++ docs/api/api_data.js | 300 +++++++++++++++++++++ middlewares/hacker.middleware.js | 10 + middlewares/validators/hacker.validator.js | 36 +++ models/hacker.model.js | 32 ++- routes/api/hacker.js | 154 ++++++++++- scripts/accept_script.py | 225 +++++++++++++++- scripts/batch_scripts.py | 219 +++++++++++++++ tests/hacker.test.js | 5 + tests/util/hacker.test.util.js | 7 - 11 files changed, 1013 insertions(+), 24 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index cffbc967..8eba3108 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -26,15 +26,21 @@ const HACKER_STATUSES = [ HACKER_STATUS_DECLINED ]; -const HACKER_REVIEWER_STATUS_NONE = "None"; -const HACKER_REVIEWER_STATUS_YES = "Yes"; -const HACKER_REVIEWER_STATUS_NO = "No"; -const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +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_YES, - HACKER_REVIEWER_STATUS_NO, - HACKER_REVIEWER_STATUS_MAYBE, + HACKER_REVIEWER_STATUS_POOR, + HACKER_REVIEWER_STATUS_WEAK, + HACKER_REVIEWER_STATUS_AVERAGE, + HACKER_REVIEWER_STATUS_STRONG, + HACKER_REVIEWER_STATUS_OUTSTANDING, + HACKER_REVIEWER_STATUS_WHITELIST, ]; // This date is Jan 6, 2020 00:00:00 GMT -0500 @@ -198,9 +204,12 @@ module.exports = { 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_YES: HACKER_REVIEWER_STATUS_YES, - HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, - HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, + 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, TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE, diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 0adfef71..a4b68b46 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -163,6 +163,26 @@ const hackerRoutes = { 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(168) + }, + patchSelfReviewerStatus2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(169) + }, + // patchAnyReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, + // _id: mongoose.Types.ObjectId.createFromTime(168) + // }, + // patchSelfReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, + // _id: mongoose.Types.ObjectId.createFromTime(169) + // }, 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 e14e0c7c..8b051d68 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2177,6 +2177,306 @@ define({ "api": [ } ] }, + { + "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 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/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 name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerName2/:id", + "title": "update a hacker's reviewer name", + "name": "patchHackerReviewerName2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerName2", + "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName2/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments/:id", + "title": "update a hacker's reviewer comments", + "name": "patchHackerReviewerComments", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments", + "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments2/:id", + "title": "update a hacker's reviewer comments 2", + "name": "patchHackerReviewerComments2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments2", + "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments2/:id" + } + ] + }, { "type": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index c993f1bc..d5cf893b 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -106,6 +106,11 @@ function parseConfirmation(req, res, next) { * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus2: String}}}} req + * @param {{body: {hackerDetails: {reviewerName: String}}}} req + * @param {{body: {hackerDetails: {reviewerName2: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments2: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -114,6 +119,11 @@ function parseConfirmation(req, res, next) { function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus2 = "none"; + req.body.hackerDetails.reviewerName = ""; + req.body.hackerDetails.reviewerName2 = ""; + 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 fae08e33..0ded318a 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -314,6 +314,42 @@ module.exports = { false ) ], + updateReviewerStatus2Validator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus2", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], + updateReviewerNameValidator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName", + false + ) + ], + updateReviewerName2Validator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName2", + 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 8ee13f5b..76bc809a 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -18,9 +18,39 @@ const HackerSchema = new mongoose.Schema({ reviewerStatus: { type: String, enum: Constants.HACKER_REVIEWER_STATUSES, - required: true, + required: false, default: "None" }, + reviewerStatus2: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: false, + default: "None" + }, + reviewerName: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerName2: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments2: { + type: String, + enum: String, + required: false, + default: "" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0f0f2d55..cac08a8c 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -312,23 +312,167 @@ module.exports = { * { * "message": "Changed hacker information", * "data": { - * "reviewerStatus": "Yes" + * "reviewerStatus": "Outstanding" * } * } * @apiPermission Administrator */ hackerRouter.route("/reviewerStatus/:id").patch( - // Middleware.Validator.RouteParam.idValidator, + Middleware.Validator.RouteParam.idValidator, // Middleware.Auth.ensureAuthenticated(), // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - // Middleware.Validator.Hacker.updateReviewerStatusValidator, + Middleware.Validator.Hacker.updateReviewerStatusValidator, // Middleware.parseBody.middleware, - // Middleware.Hacker.parsePatch, - + 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 diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 950e5c92..b7bb455e 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -38,7 +38,7 @@ '5': 'inviteUsers', '6': 'getHackers', '7': 'acceptHackers', - '8': 'updateReviewerStatus' + '8': 'updateReviewerStatus', } LOG_VERBOSITIES = { '0': 'None', @@ -223,6 +223,60 @@ def reviewerStatus(prefixStr) -> str: ) 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 str] + 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 str] + 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()] @@ -258,6 +312,41 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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' @@ -362,7 +451,131 @@ def updateReviewerStatus(): _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 = getIdList() + 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 = 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 sendDayOfEmail(): # INITIAL_STATUS = status('initial') # HACKER_IDs = loadIDs() @@ -519,6 +732,16 @@ def getHackers(): 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 9f5be703..518e483b 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -233,6 +233,60 @@ def reviewerStatus(prefixStr) -> str: ) 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): @@ -256,6 +310,36 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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) @@ -321,6 +405,131 @@ def updateReviewerStatus(): _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') @@ -476,6 +685,16 @@ def 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 19c61f74..08b59fdb 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1735,6 +1735,11 @@ describe("GET Hacker stats", function() { 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"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 4ffffa3d..3dd62cbe 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,6 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -59,7 +58,6 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -104,7 +102,6 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", - reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -149,7 +146,6 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -194,7 +190,6 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "", application: { general: { school: "University of Blah", @@ -239,7 +234,6 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -664,7 +658,6 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From b9e15fbda33083ce90bd57eafb1b7544d564c754 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Fri, 4 Apr 2025 12:43:10 -0400 Subject: [PATCH 09/23] Cleaner code --- docs/api/api_data.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index 8b051d68..4a6a37f6 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2132,7 +2132,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus", - "description": "

Reviewer status of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2159,7 +2159,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus\": \"Poor\"\n }\n}", "type": "object" } ] @@ -2180,7 +2180,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerStatus2/:id", - "title": "update a hacker's reviewer status 2", + "title": "update a hacker's reviewer status (2)", "name": "patchHackerReviewerStatus2", "group": "Hacker", "version": "0.0.9", @@ -2192,7 +2192,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus2", - "description": "

Reviewer status 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2219,7 +2219,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus2\": \"Outstanding\"\n }\n}", "type": "object" } ] @@ -2252,7 +2252,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name of the hacker's application

" } ] } @@ -2279,7 +2279,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName\": \"Jane Doe\"\n }\n}", "type": "object" } ] @@ -2300,7 +2300,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerName2/:id", - "title": "update a hacker's reviewer name", + "title": "update a hacker's reviewer name (2)", "name": "patchHackerReviewerName2", "group": "Hacker", "version": "0.0.9", @@ -2312,7 +2312,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName2", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name (2) of the hacker's application

" } ] } @@ -2339,7 +2339,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName2\": \"John Doe\"\n }\n}", "type": "object" } ] @@ -2360,7 +2360,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments/:id", - "title": "update a hacker's reviewer comments", + "title": "update a hacker's reviewer's comments", "name": "patchHackerReviewerComments", "group": "Hacker", "version": "0.0.9", @@ -2372,7 +2372,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments", - "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments of the hacker's application

" } ] } @@ -2399,7 +2399,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] @@ -2420,7 +2420,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments2/:id", - "title": "update a hacker's reviewer comments 2", + "title": "update a hacker's reviewer's comments (2)", "name": "patchHackerReviewerComments2", "group": "Hacker", "version": "0.0.9", @@ -2432,7 +2432,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments2", - "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments (2) of the hacker's application

" } ] } @@ -2459,7 +2459,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] From 5c0b4d1bed613c476fea44c0024202b046940283 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 29 Sep 2025 21:26:24 -0400 Subject: [PATCH 10/23] remove uneccessary comments --- constants/routes.constant.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index a4b68b46..3d35faa8 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -173,16 +173,6 @@ const hackerRoutes = { uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, _id: mongoose.Types.ObjectId.createFromTime(169) }, - // patchAnyReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, - // _id: mongoose.Types.ObjectId.createFromTime(168) - // }, - // patchSelfReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, - // _id: mongoose.Types.ObjectId.createFromTime(169) - // }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, From c69b1c9e5c52af7ef01b079dd13cc6a4741a3bac Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sat, 22 Feb 2025 18:39:12 -0500 Subject: [PATCH 11/23] not finished create app rev --- constants/general.constant.js | 17 +++++ constants/routes.constant.js | 10 +++ docs/api/api_data.js | 60 +++++++++++++++ docs/api/api_data.json | 3 +- middlewares/hacker.middleware.js | 2 + middlewares/validators/hacker.validator.js | 8 ++ models/hacker.model.js | 6 ++ routes/api/hacker.js | 30 ++++++++ scripts/accept_script.py | 86 +++++++++++++++++----- scripts/batch_scripts.py | 54 +++++++++++++- tests/hacker.test.js | 1 + tests/util/hacker.test.util.js | 7 ++ 12 files changed, 265 insertions(+), 19 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index 5e23d2fe..cffbc967 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -25,6 +25,18 @@ const HACKER_STATUSES = [ HACKER_STATUS_CHECKED_IN, HACKER_STATUS_DECLINED ]; + +const HACKER_REVIEWER_STATUS_NONE = "None"; +const HACKER_REVIEWER_STATUS_YES = "Yes"; +const HACKER_REVIEWER_STATUS_NO = "No"; +const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +const HACKER_REVIEWER_STATUSES = [ + HACKER_REVIEWER_STATUS_NONE, + HACKER_REVIEWER_STATUS_YES, + HACKER_REVIEWER_STATUS_NO, + HACKER_REVIEWER_STATUS_MAYBE, +]; + // This date is Jan 6, 2020 00:00:00 GMT -0500 const APPLICATION_CLOSE_TIME = 1578286800000; @@ -185,7 +197,12 @@ 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_YES: HACKER_REVIEWER_STATUS_YES, + HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, + HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, HACKER_STATUSES: HACKER_STATUSES, + HACKER_REVIEWER_STATUSES: HACKER_REVIEWER_STATUSES, 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 e880674d..fc54a92b 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,6 +153,16 @@ 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) + // }, 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..0a4ba50b 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,6 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" + // } + // ] + // } + // }, + // "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": "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..57bee7f5 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,6 +102,7 @@ function parseConfirmation(req, res, next) { return next(); } +// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req @@ -112,6 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; + // req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index 05a3b413..fa92c080 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -306,6 +306,14 @@ module.exports = { false ) ], + // updateReviewerStatusValidator: [ + // VALIDATOR.enumValidator( + // "body", + // "reviewerStatus", + // Constants.HACKER_REVIEWER_STATUSES, + // false + // ) + // ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/models/hacker.model.js b/models/hacker.model.js index 51171616..8ee13f5b 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -15,6 +15,12 @@ const HackerSchema = new mongoose.Schema({ required: true, default: "None" }, + reviewerStatus: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: true, + default: "None" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0fe125a6..08f4677e 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -299,6 +299,36 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") + // * @apiSuccess {string} message Success message + // * @apiSuccess {object} data Hacker object + // * @apiSuccessExample {object} Success-Response: + // * { + // * "message": "Changed hacker information", + // * "data": { + // * "reviewerStatus": "Yes" + // * } + // * } + // * @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/accept/:id accept a Hacker * @apiName acceptHacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index f76f445e..228b25a0 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -21,6 +21,12 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe', +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', @@ -28,7 +34,8 @@ '4': 'downloadResume', '5': 'inviteUsers', '6': 'getHackers', - '7': 'acceptHackers' + '7': 'acceptHackers', + '8': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -202,6 +209,17 @@ 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 batchAction() -> str: status_list = ['{0}: {1}\n'.format(k, v) for k, v in BATCH_ACTIONS.items()] @@ -230,6 +248,13 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) expand = 'true' if expand else 'false' @@ -309,32 +334,57 @@ def updateStatus(): _print('could not find {0}'.format( ID), 1, index, len(HACKER_IDs)) - -def sendDayOfEmail(): - INITIAL_STATUS = status('initial') - HACKER_IDs = loadIDs() +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) - 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)) + 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('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 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') HACKER_IDs = loadIDs() @@ -464,6 +514,8 @@ def getHackers(): getHackers() elif BATCH_ACTION == 'acceptHackers': acceptFromEmails() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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..ffad8393 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -21,13 +21,20 @@ '6': 'Withdrawn', '7': 'Checked-in' } +VALID_REVIEWER_STATUSES = { + '1': 'None', + '2': 'Yes', + '3': 'No', + '4': 'Maybe' +} BATCH_ACTIONS = { '1': 'updateStatus', '2': 'dayOf', '3': 'weekOf', '4': 'downloadResume', '5': 'inviteUsers', - '6': 'getHackers' + '6': 'getHackers', + '7': 'updateReviewerStatus' } LOG_VERBOSITIES = { '0': 'None', @@ -212,6 +219,18 @@ 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 getHacker(ID): r = s.get('{0}/api/hacker/{1}'.format(API_URL, ID)) @@ -228,6 +247,12 @@ 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 search(model: str = 'hacker', query=[], expand: bool = True): q = json.dumps(query) @@ -268,6 +293,31 @@ 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 sendDayOfEmail(): INITIAL_STATUS = status('initial') @@ -421,6 +471,8 @@ def getHackers(): inviteUsers() elif BATCH_ACTION == 'getHackers': getHackers() + elif BATCH_ACTION == 'updateReviewerStatus': + updateReviewerStatus() 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..19c61f74 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1734,6 +1734,7 @@ 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("school"); res.body.data.stats.should.have.property("degree"); res.body.data.stats.should.have.property("gender"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 3dd62cbe..fe760603 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,6 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -58,6 +59,7 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -102,6 +104,7 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", + reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -146,6 +149,7 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -190,6 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", + reviewerStatus: "Maybe", application: { general: { school: "University of Blah", @@ -234,6 +239,7 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -658,6 +664,7 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 726100fa562d7a0042cc40dabc901f91fd59e4ab Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 30 Mar 2025 22:36:08 -0400 Subject: [PATCH 12/23] Reviewer status: 1/2 works (needs to enter twice??) --- constants/routes.constant.js | 20 ++-- docs/api/api_data.js | 120 ++++++++++----------- middlewares/hacker.middleware.js | 4 +- middlewares/validators/hacker.validator.js | 16 +-- routes/api/hacker.js | 58 +++++----- scripts/accept_script.py | 9 +- scripts/batch_scripts.py | 11 +- tests/util/hacker.test.util.js | 4 +- 8 files changed, 124 insertions(+), 118 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index fc54a92b..0adfef71 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -153,16 +153,16 @@ 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) - // }, + 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) + }, 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 0a4ba50b..e14e0c7c 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,66 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" - // } - // ] - // } - // }, - // "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"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index 57bee7f5..c993f1bc 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,10 +102,10 @@ function parseConfirmation(req, res, next) { return next(); } -// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -113,7 +113,7 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; - // req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus = "none"; return next(); } diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index fa92c080..fae08e33 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -306,14 +306,14 @@ module.exports = { false ) ], - // updateReviewerStatusValidator: [ - // VALIDATOR.enumValidator( - // "body", - // "reviewerStatus", - // Constants.HACKER_REVIEWER_STATUSES, - // false - // ) - // ], + updateReviewerStatusValidator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], checkInStatusValidator: [ VALIDATOR.enumValidator( "body", diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 08f4677e..0f0f2d55 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -299,35 +299,35 @@ module.exports = { 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"|"Yes"|"No"|"Maybe") - // * @apiSuccess {string} message Success message - // * @apiSuccess {object} data Hacker object - // * @apiSuccessExample {object} Success-Response: - // * { - // * "message": "Changed hacker information", - // * "data": { - // * "reviewerStatus": "Yes" - // * } - // * } - // * @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/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": "Yes" + * } + * } + * @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/accept/:id accept a Hacker diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 228b25a0..950e5c92 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe', + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/scripts/batch_scripts.py b/scripts/batch_scripts.py index ffad8393..9f5be703 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 @@ -23,9 +23,12 @@ } VALID_REVIEWER_STATUSES = { '1': 'None', - '2': 'Yes', - '3': 'No', - '4': 'Maybe' + '2': 'Poor', + '3': 'Weak', + '4': 'Average', + '5': 'Strong', + '6': 'Outstanding', + '7': 'Whitelist' } BATCH_ACTIONS = { '1': 'updateStatus', diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index fe760603..4ffffa3d 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Yes", + reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -194,7 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "Maybe", + reviewerStatus: "", application: { general: { school: "University of Blah", From 733a48782eaacb5252460fe2c0ee65cc88bcbdda Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 31 Mar 2025 20:48:48 -0400 Subject: [PATCH 13/23] Hacker Reviewer Feature --- constants/general.constant.js | 29 +- constants/routes.constant.js | 20 ++ docs/api/api_data.js | 300 +++++++++++++++++++++ middlewares/hacker.middleware.js | 10 + middlewares/validators/hacker.validator.js | 36 +++ models/hacker.model.js | 32 ++- routes/api/hacker.js | 154 ++++++++++- scripts/accept_script.py | 225 +++++++++++++++- scripts/batch_scripts.py | 219 +++++++++++++++ tests/hacker.test.js | 5 + tests/util/hacker.test.util.js | 7 - 11 files changed, 1013 insertions(+), 24 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index cffbc967..8eba3108 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -26,15 +26,21 @@ const HACKER_STATUSES = [ HACKER_STATUS_DECLINED ]; -const HACKER_REVIEWER_STATUS_NONE = "None"; -const HACKER_REVIEWER_STATUS_YES = "Yes"; -const HACKER_REVIEWER_STATUS_NO = "No"; -const HACKER_REVIEWER_STATUS_MAYBE = "Maybe"; +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_YES, - HACKER_REVIEWER_STATUS_NO, - HACKER_REVIEWER_STATUS_MAYBE, + HACKER_REVIEWER_STATUS_POOR, + HACKER_REVIEWER_STATUS_WEAK, + HACKER_REVIEWER_STATUS_AVERAGE, + HACKER_REVIEWER_STATUS_STRONG, + HACKER_REVIEWER_STATUS_OUTSTANDING, + HACKER_REVIEWER_STATUS_WHITELIST, ]; // This date is Jan 6, 2020 00:00:00 GMT -0500 @@ -198,9 +204,12 @@ module.exports = { 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_YES: HACKER_REVIEWER_STATUS_YES, - HACKER_REVIWER_STATUS_NO: HACKER_REVIEWER_STATUS_NO, - HACKER_REVIWER_STATUS_MAYBE: HACKER_REVIEWER_STATUS_MAYBE, + 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, TRAVEL_STATUS_NONE: TRAVEL_STATUS_NONE, diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 0adfef71..a4b68b46 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -163,6 +163,26 @@ const hackerRoutes = { 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(168) + }, + patchSelfReviewerStatus2ById: { + requestType: Constants.REQUEST_TYPES.PATCH, + uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, + _id: mongoose.Types.ObjectId.createFromTime(169) + }, + // patchAnyReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, + // _id: mongoose.Types.ObjectId.createFromTime(168) + // }, + // patchSelfReviewerNameById: { + // requestType: Constants.REQUEST_TYPES.PATCH, + // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, + // _id: mongoose.Types.ObjectId.createFromTime(169) + // }, 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 e14e0c7c..8b051d68 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2177,6 +2177,306 @@ define({ "api": [ } ] }, + { + "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 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/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 name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerName2/:id", + "title": "update a hacker's reviewer name", + "name": "patchHackerReviewerName2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerName2", + "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerName2/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments/:id", + "title": "update a hacker's reviewer comments", + "name": "patchHackerReviewerComments", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments", + "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments/:id" + } + ] + }, + { + "type": "patch", + "url": "/hacker/reviewerComments2/:id", + "title": "update a hacker's reviewer comments 2", + "name": "patchHackerReviewerComments2", + "group": "Hacker", + "version": "0.0.9", + "parameter": { + "fields": { + "body": [ + { + "group": "body", + "type": "string", + "optional": true, + "field": "reviewerComments2", + "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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/reviewerComments2/:id" + } + ] + }, { "type": "post", "url": "/hacker/resume/:id", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index c993f1bc..d5cf893b 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -106,6 +106,11 @@ function parseConfirmation(req, res, next) { * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req + * @param {{body: {hackerDetails: {reviewerStatus2: String}}}} req + * @param {{body: {hackerDetails: {reviewerName: String}}}} req + * @param {{body: {hackerDetails: {reviewerName2: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments: String}}}} req + * @param {{body: {hackerDetails: {reviewerComments2: String}}}} req * @param {JSON} res * @param {(err?)=>void} next * @return {void} @@ -114,6 +119,11 @@ function parseConfirmation(req, res, next) { function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; req.body.hackerDetails.reviewerStatus = "none"; + req.body.hackerDetails.reviewerStatus2 = "none"; + req.body.hackerDetails.reviewerName = ""; + req.body.hackerDetails.reviewerName2 = ""; + 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 fae08e33..0ded318a 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -314,6 +314,42 @@ module.exports = { false ) ], + updateReviewerStatus2Validator: [ + VALIDATOR.enumValidator( + "body", + "reviewerStatus2", + Constants.HACKER_REVIEWER_STATUSES, + false + ) + ], + updateReviewerNameValidator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName", + false + ) + ], + updateReviewerName2Validator: [ + VALIDATOR.stringValidator( + "body", + "reviewerName2", + 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 8ee13f5b..76bc809a 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -18,9 +18,39 @@ const HackerSchema = new mongoose.Schema({ reviewerStatus: { type: String, enum: Constants.HACKER_REVIEWER_STATUSES, - required: true, + required: false, default: "None" }, + reviewerStatus2: { + type: String, + enum: Constants.HACKER_REVIEWER_STATUSES, + required: false, + default: "None" + }, + reviewerName: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerName2: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments: { + type: String, + enum: String, + required: false, + default: "" + }, + reviewerComments2: { + type: String, + enum: String, + required: false, + default: "" + }, application: { general: { school: { diff --git a/routes/api/hacker.js b/routes/api/hacker.js index 0f0f2d55..cac08a8c 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -312,23 +312,167 @@ module.exports = { * { * "message": "Changed hacker information", * "data": { - * "reviewerStatus": "Yes" + * "reviewerStatus": "Outstanding" * } * } * @apiPermission Administrator */ hackerRouter.route("/reviewerStatus/:id").patch( - // Middleware.Validator.RouteParam.idValidator, + Middleware.Validator.RouteParam.idValidator, // Middleware.Auth.ensureAuthenticated(), // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), - // Middleware.Validator.Hacker.updateReviewerStatusValidator, + Middleware.Validator.Hacker.updateReviewerStatusValidator, // Middleware.parseBody.middleware, - // Middleware.Hacker.parsePatch, - + 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 diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 950e5c92..b7bb455e 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -38,7 +38,7 @@ '5': 'inviteUsers', '6': 'getHackers', '7': 'acceptHackers', - '8': 'updateReviewerStatus' + '8': 'updateReviewerStatus', } LOG_VERBOSITIES = { '0': 'None', @@ -223,6 +223,60 @@ def reviewerStatus(prefixStr) -> str: ) 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 str] + 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 str] + 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()] @@ -258,6 +312,41 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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' @@ -362,7 +451,131 @@ def updateReviewerStatus(): _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 = getIdList() + 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 = 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 sendDayOfEmail(): # INITIAL_STATUS = status('initial') # HACKER_IDs = loadIDs() @@ -519,6 +732,16 @@ def getHackers(): 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 9f5be703..518e483b 100644 --- a/scripts/batch_scripts.py +++ b/scripts/batch_scripts.py @@ -233,6 +233,60 @@ def reviewerStatus(prefixStr) -> str: ) 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): @@ -256,6 +310,36 @@ def hasValidReviewerStatus(reviewerStatus, hackerInfo): 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) @@ -321,6 +405,131 @@ def updateReviewerStatus(): _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') @@ -476,6 +685,16 @@ def 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 19c61f74..08b59fdb 100644 --- a/tests/hacker.test.js +++ b/tests/hacker.test.js @@ -1735,6 +1735,11 @@ describe("GET Hacker stats", function() { 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"); diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 4ffffa3d..3dd62cbe 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,6 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -59,7 +58,6 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -104,7 +102,6 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", - reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -149,7 +146,6 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -194,7 +190,6 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "", application: { general: { school: "University of Blah", @@ -239,7 +234,6 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -664,7 +658,6 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 99665255ec38c827be4b9e122727811d4f79e9b4 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Fri, 4 Apr 2025 12:43:10 -0400 Subject: [PATCH 14/23] Cleaner code --- docs/api/api_data.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index 8b051d68..4a6a37f6 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2132,7 +2132,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus", - "description": "

Reviewer status of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2159,7 +2159,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus\": \"Poor\"\n }\n}", "type": "object" } ] @@ -2180,7 +2180,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerStatus2/:id", - "title": "update a hacker's reviewer status 2", + "title": "update a hacker's reviewer status (2)", "name": "patchHackerReviewerStatus2", "group": "Hacker", "version": "0.0.9", @@ -2192,7 +2192,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus2", - "description": "

Reviewer status 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } @@ -2219,7 +2219,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerStatus2\": \"Outstanding\"\n }\n}", "type": "object" } ] @@ -2252,7 +2252,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name of the hacker's application

" } ] } @@ -2279,7 +2279,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName\": \"Jane Doe\"\n }\n}", "type": "object" } ] @@ -2300,7 +2300,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerName2/:id", - "title": "update a hacker's reviewer name", + "title": "update a hacker's reviewer name (2)", "name": "patchHackerReviewerName2", "group": "Hacker", "version": "0.0.9", @@ -2312,7 +2312,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerName2", - "description": "

Reviewer name of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's name (2) of the hacker's application

" } ] } @@ -2339,7 +2339,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"reviewerName2\": \"John Doe\"\n }\n}", "type": "object" } ] @@ -2360,7 +2360,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments/:id", - "title": "update a hacker's reviewer comments", + "title": "update a hacker's reviewer's comments", "name": "patchHackerReviewerComments", "group": "Hacker", "version": "0.0.9", @@ -2372,7 +2372,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments", - "description": "

Reviewer comments of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments of the hacker's application

" } ] } @@ -2399,7 +2399,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] @@ -2420,7 +2420,7 @@ define({ "api": [ { "type": "patch", "url": "/hacker/reviewerComments2/:id", - "title": "update a hacker's reviewer comments 2", + "title": "update a hacker's reviewer's comments (2)", "name": "patchHackerReviewerComments2", "group": "Hacker", "version": "0.0.9", @@ -2432,7 +2432,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerComments2", - "description": "

Reviewer comments 2 of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer's comments (2) of the hacker's application

" } ] } @@ -2459,7 +2459,7 @@ define({ "api": [ "examples": [ { "title": "Success-Response:", - "content": "{\n \"message\": \"Changed hacker information\",\n \"data\": {\n \"status\": \"Yes\"\n }\n}", + "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" } ] From 0a20112ca93e85dd56375a617cc4814a8b9311f1 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 29 Sep 2025 21:26:24 -0400 Subject: [PATCH 15/23] remove uneccessary comments --- constants/routes.constant.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index a4b68b46..3d35faa8 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -173,16 +173,6 @@ const hackerRoutes = { uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.SELF, _id: mongoose.Types.ObjectId.createFromTime(169) }, - // patchAnyReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.ALL, - // _id: mongoose.Types.ObjectId.createFromTime(168) - // }, - // patchSelfReviewerNameById: { - // requestType: Constants.REQUEST_TYPES.PATCH, - // uri: "/api/hacker/reviewerName/" + Constants.ROLE_CATEGORIES.SELF, - // _id: mongoose.Types.ObjectId.createFromTime(169) - // }, patchSelfCheckInById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/checkin/" + Constants.ROLE_CATEGORIES.SELF, From 5098e87aa0eba4cf2a7deafbd1bb20ebbd4cf5ac Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sat, 22 Feb 2025 18:39:12 -0500 Subject: [PATCH 16/23] not finished create app rev --- docs/api/api_data.js | 60 ++++++++++++++++++++++++++++++++ middlewares/hacker.middleware.js | 1 + tests/util/hacker.test.util.js | 7 ++++ 3 files changed, 68 insertions(+) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index 4a6a37f6..ebad81f1 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,6 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" + // } + // ] + // } + // }, + // "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", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index d5cf893b..5ebc6786 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,6 +102,7 @@ function parseConfirmation(req, res, next) { return next(); } +// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 3dd62cbe..fe760603 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,6 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -58,6 +59,7 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -102,6 +104,7 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", + reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -146,6 +149,7 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -190,6 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", + reviewerStatus: "Maybe", application: { general: { school: "University of Blah", @@ -234,6 +239,7 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -658,6 +664,7 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", + reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 58a40c91118ef3826ff1a879d2afadca16554dc4 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 30 Mar 2025 22:36:08 -0400 Subject: [PATCH 17/23] Reviewer status: 1/2 works (needs to enter twice??) --- docs/api/api_data.js | 120 +++++++++++++++---------------- middlewares/hacker.middleware.js | 1 - tests/util/hacker.test.util.js | 4 +- 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index ebad81f1..ae31f9ab 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2117,66 +2117,66 @@ 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"|"Yes"|"No"|"Maybe")

" - // } - // ] - // } - // }, - // "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"|"Yes"|"No"|"Maybe")

" + } + ] + } + }, + "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", diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index 5ebc6786..d5cf893b 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -102,7 +102,6 @@ function parseConfirmation(req, res, next) { return next(); } -// * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index fe760603..4ffffa3d 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,7 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Yes", + reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -194,7 +194,7 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "Maybe", + reviewerStatus: "", application: { general: { school: "University of Blah", From 597cd006042666bb37f56a7fc469a798f7698d76 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Mon, 31 Mar 2025 20:48:48 -0400 Subject: [PATCH 18/23] Hacker Reviewer Feature --- tests/util/hacker.test.util.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/util/hacker.test.util.js b/tests/util/hacker.test.util.js index 4ffffa3d..3dd62cbe 100644 --- a/tests/util/hacker.test.util.js +++ b/tests/util/hacker.test.util.js @@ -14,7 +14,6 @@ const TeamHacker0 = { _id: Constants.MongoId.hackerAId, accountId: Util.Account.hackerAccounts.stored.team[0]._id, status: "Confirmed", - reviewerStatus: "Outstanding", application: { general: { school: "University of Blah", @@ -59,7 +58,6 @@ const TeamHacker1 = { _id: Constants.MongoId.hackerDId, accountId: Util.Account.hackerAccounts.stored.team[1]._id, status: "Checked-in", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -104,7 +102,6 @@ const TeamHacker2 = { _id: Constants.MongoId.hackerEId, accountId: Util.Account.hackerAccounts.stored.team[2]._id, status: "Waitlisted", - reviewerStatus: "No", application: { general: { school: "University of Blah", @@ -149,7 +146,6 @@ const TeamHacker3 = { _id: Constants.MongoId.hackerFId, accountId: Util.Account.hackerAccounts.stored.team[3]._id, status: "Waitlisted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -194,7 +190,6 @@ const TeamHacker4 = { _id: Constants.MongoId.hackerGId, accountId: Util.Account.hackerAccounts.stored.team[4]._id, status: "Waitlisted", - reviewerStatus: "", application: { general: { school: "University of Blah", @@ -239,7 +234,6 @@ const NoTeamHacker0 = { _id: Constants.MongoId.hackerBId, accountId: Util.Account.hackerAccounts.stored.noTeam[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah", @@ -664,7 +658,6 @@ const unconfirmedAccountHacker1 = { _id: Constants.MongoId.hackerHId, accountId: Util.Account.hackerAccounts.stored.unconfirmed[0]._id, status: "Accepted", - reviewerStatus: "Yes", application: { general: { school: "University of Blah2", From 5bf486746ae05047bdd3f1d7ccb61ace0a0f4842 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Fri, 4 Apr 2025 12:43:10 -0400 Subject: [PATCH 19/23] Cleaner code --- docs/api/api_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/api_data.js b/docs/api/api_data.js index ae31f9ab..c2fa3ded 100644 --- a/docs/api/api_data.js +++ b/docs/api/api_data.js @@ -2132,7 +2132,7 @@ define({ "api": [ "type": "string", "optional": true, "field": "reviewerStatus", - "description": "

Reviewer status of the hacker's application ("None"|"Yes"|"No"|"Maybe")

" + "description": "

Reviewer status of the hacker's application ("None"|"Poor"|"Weak"|"Poor"|"Average"|"Strong"|"Outstanding"|"Whitelist")

" } ] } From 7150e54640f414b9c55ed63918ecd5f998e989ff Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 16 Nov 2025 21:38:42 -0500 Subject: [PATCH 20/23] Fixed Application Error: implemented reviewers values from feat/review_filter and fixed the default value errors for reviewer status, name, and comments --- constants/general.constant.js | 45 ++++++++++++++++++ middlewares/hacker.middleware.js | 20 ++++---- middlewares/validators/hacker.validator.js | 4 ++ models/hacker.model.js | 14 +++--- scripts/accept_script.py | 55 ++++++++++++++++++++-- 5 files changed, 119 insertions(+), 19 deletions(-) diff --git a/constants/general.constant.js b/constants/general.constant.js index 8eba3108..e1cc8502 100644 --- a/constants/general.constant.js +++ b/constants/general.constant.js @@ -43,6 +43,50 @@ const HACKER_REVIEWER_STATUSES = [ 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; @@ -212,6 +256,7 @@ module.exports = { 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/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index d5cf893b..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,10 +109,10 @@ function parseConfirmation(req, res, next) { /** * @function addDefaultStatus * @param {{body: {hackerDetails: {status: String}}}} req - * @param {{body: {hackerDetails: {reviewerStatus: String}}}} req - * @param {{body: {hackerDetails: {reviewerStatus2: String}}}} req - * @param {{body: {hackerDetails: {reviewerName: String}}}} req - * @param {{body: {hackerDetails: {reviewerName2: 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 @@ -118,10 +122,10 @@ function parseConfirmation(req, res, next) { */ function addDefaultStatus(req, res, next) { req.body.hackerDetails.status = "Applied"; - req.body.hackerDetails.reviewerStatus = "none"; - req.body.hackerDetails.reviewerStatus2 = "none"; - req.body.hackerDetails.reviewerName = ""; - req.body.hackerDetails.reviewerName2 = ""; + 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 0ded318a..d2163a10 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -326,6 +326,7 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerName", + Constants.HACKER_REVIEWER_NAMES, false ) ], @@ -333,6 +334,7 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerName2", + Constants.HACKER_REVIEWER_NAMES, false ) ], @@ -340,6 +342,7 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerComments", + String, false ) ], @@ -347,6 +350,7 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerComments2", + String, false ) ], diff --git a/models/hacker.model.js b/models/hacker.model.js index 76bc809a..38e399f2 100644 --- a/models/hacker.model.js +++ b/models/hacker.model.js @@ -19,35 +19,33 @@ const HackerSchema = new mongoose.Schema({ type: String, enum: Constants.HACKER_REVIEWER_STATUSES, required: false, - default: "None" + default: Constants.HACKER_REVIEWER_STATUS_NONE }, reviewerStatus2: { type: String, enum: Constants.HACKER_REVIEWER_STATUSES, required: false, - default: "None" + default: Constants.HACKER_REVIEWER_STATUS_NONE }, reviewerName: { type: String, - enum: String, + enum: Constants.HACKER_REVIEWER_NAMES, required: false, - default: "" + default: Constants.HACKER_REVIEWER_NAMES.find(r => r === '') }, reviewerName2: { type: String, - enum: String, + enum: Constants.HACKER_REVIEWER_NAMES, required: false, - default: "" + default: Constants.HACKER_REVIEWER_NAMES.find(r => r === '') }, reviewerComments: { type: String, - enum: String, required: false, default: "" }, reviewerComments2: { type: String, - enum: String, required: false, default: "" }, diff --git a/scripts/accept_script.py b/scripts/accept_script.py index b7bb455e..7fc71334 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -30,6 +30,50 @@ '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', @@ -236,7 +280,7 @@ def reviewerStatus2(prefixStr) -> str: def reviewerName(prefixStr) -> str: reviewerName_list = ['{0}: {1}\n'.format(k, v) - for k, v in str] + 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), @@ -247,7 +291,7 @@ def reviewerName(prefixStr) -> str: def reviewerName2(prefixStr) -> str: reviewerName2_list = ['{0}: {1}\n'.format(k, v) - for k, v in str] + 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), @@ -575,7 +619,12 @@ def updateReviewerComments2(): 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() From b31238867d4a9081e0dae73c775b7aec246a6bc8 Mon Sep 17 00:00:00 2001 From: JAMIE XIAO Date: Sun, 16 Nov 2025 23:11:01 -0500 Subject: [PATCH 21/23] Fixed Application Error: implemented reviewers values from feat/review_filter and fixed the default value errors for reviewer status, name, and comments --- middlewares/validators/hacker.validator.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/middlewares/validators/hacker.validator.js b/middlewares/validators/hacker.validator.js index d2163a10..fc1283f3 100644 --- a/middlewares/validators/hacker.validator.js +++ b/middlewares/validators/hacker.validator.js @@ -342,7 +342,6 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerComments", - String, false ) ], @@ -350,7 +349,6 @@ module.exports = { VALIDATOR.stringValidator( "body", "reviewerComments2", - String, false ) ], From 3b31298ec6824c4732dcae4f7383c95c641a9cf9 Mon Sep 17 00:00:00 2001 From: Tavi Pollard Date: Mon, 17 Nov 2025 15:55:03 -0500 Subject: [PATCH 22/23] fixed authorization issues by adding all routes to routes.constant.js with unique IDs --- constants/routes.constant.js | 46 +++++++++++++++++++++++++++++++++--- routes/api/hacker.js | 36 ++++++++++++++-------------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/constants/routes.constant.js b/constants/routes.constant.js index 3d35faa8..1ac64a31 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: 168 + * 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. @@ -166,12 +166,52 @@ const hackerRoutes = { patchAnyReviewerStatus2ById: { requestType: Constants.REQUEST_TYPES.PATCH, uri: "/api/hacker/reviewerStatus2/" + Constants.ROLE_CATEGORIES.ALL, - _id: mongoose.Types.ObjectId.createFromTime(168) + _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(169) + _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, diff --git a/routes/api/hacker.js b/routes/api/hacker.js index cac08a8c..eb8edc81 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -319,10 +319,10 @@ module.exports = { */ hackerRouter.route("/reviewerStatus/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerStatusValidator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker @@ -348,10 +348,10 @@ module.exports = { */ hackerRouter.route("/reviewerStatus2/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerStatus2Validator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker @@ -377,10 +377,10 @@ module.exports = { */ hackerRouter.route("/reviewerName/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerNameValidator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker @@ -406,10 +406,10 @@ module.exports = { */ hackerRouter.route("/reviewerName2/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerName2Validator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker @@ -435,10 +435,10 @@ hackerRouter.route("/reviewerName2/:id").patch( */ hackerRouter.route("/reviewerComments/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerCommentsValidator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker @@ -464,10 +464,10 @@ hackerRouter.route("/reviewerComments/:id").patch( */ hackerRouter.route("/reviewerComments2/:id").patch( Middleware.Validator.RouteParam.idValidator, - // Middleware.Auth.ensureAuthenticated(), - // Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), + Middleware.Auth.ensureAuthenticated(), + Middleware.Auth.ensureAuthorized([Services.Hacker.findById]), Middleware.Validator.Hacker.updateReviewerComments2Validator, - // Middleware.parseBody.middleware, + Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.updateHacker, Controllers.Hacker.updatedHacker From 244180b171ad8e6751172b1384388dc7f64277d0 Mon Sep 17 00:00:00 2001 From: Tavi Pollard Date: Mon, 17 Nov 2025 19:18:55 -0500 Subject: [PATCH 23/23] disable emails on status change by admin --- routes/api/hacker.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/routes/api/hacker.js b/routes/api/hacker.js index eb8edc81..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,9 +293,7 @@ module.exports = { Middleware.parseBody.middleware, Middleware.Hacker.parsePatch, Middleware.Hacker.validateConfirmedStatusFromHackerId, - Middleware.Hacker.updateHacker, - Middleware.Hacker.sendStatusUpdateEmail, Controllers.Hacker.updatedHacker ); @@ -568,7 +566,7 @@ hackerRouter.route("/reviewerComments2/:id").patch( 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 @@ -956,7 +954,7 @@ hackerRouter.route("/reviewerComments2/:id").patch( /** * @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