diff --git a/constants/routes.constant.js b/constants/routes.constant.js index d5aec255..1bcf1da8 100644 --- a/constants/routes.constant.js +++ b/constants/routes.constant.js @@ -213,6 +213,16 @@ const hackerRoutes = { uri: "/api/hacker/reviewerComments2/" + Constants.ROLE_CATEGORIES.SELF, _id: mongoose.Types.ObjectId.createFromTime(179) }, + // 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/controllers/hacker.controller.js b/controllers/hacker.controller.js index 25b2a635..326c45bd 100644 --- a/controllers/hacker.controller.js +++ b/controllers/hacker.controller.js @@ -102,9 +102,27 @@ function updatedHackerBatch(req, res) { }); } +/** + * @function assignReviewers + * @param {{body: {names: string[]}}} req + * @param {*} res + * @return {JSON} Success or error status + * @description + * Assign reviewers to hackers who've not yet been assigned reviewers and submitted applications before the deadline. + * Returns a 200 status after bulk assignment reviewers. + * The assignments are located in req.body. + */ +function assignedReviewers(req, res) { + return res.status(200).json({ + message: 'Successfully assigned reviewers to hackers', + data: req.body + }); +} + module.exports = { updatedHacker: updatedHacker, updatedHackerBatch: updatedHackerBatch, + assignedReviewers: assignedReviewers, createdHacker: createdHacker, uploadedResume: uploadedResume, downloadedResume: downloadedResume, diff --git a/middlewares/hacker.middleware.js b/middlewares/hacker.middleware.js index ba540f99..6b357275 100644 --- a/middlewares/hacker.middleware.js +++ b/middlewares/hacker.middleware.js @@ -3,6 +3,7 @@ const TAG = `[ HACKER.MIDDLEWARE.js ]`; const mongoose = require("mongoose"); +const ObjectId = mongoose.Types.ObjectId; 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"); @@ -740,6 +741,97 @@ async function updateBatchHacker(req, res, next) { next(); } + +/** + * Updates a hacker that is specified by req.params.id, and then sets req.email + * to the email of the hacker, found in Account. + * Assigns reviewers to hackers in a batch process. + * @param {*} req + * @param {*} res + * @param {*} next + */ +async function assignReviewers(req, res, next) { + try { + console.log('Starting assignReviewers'); + + // const REVIEWER_NAMES = HACKER_REVIEWER_NAMES.filter(name => name !== ''); // get all non-empty reviewer names + const REVIEWER_NAMES = req.body.names; + console.log('Reviewer names:', REVIEWER_NAMES); + + const cutoff = new Date('2025-11-27T17:23:59.000Z'); // EDIT: set your desired cutoff date here + const cutoffObjectId = new ObjectId(Math.floor(cutoff.getTime() / 1000).toString(16) + "0000000000000000"); + + const hackerModel = require('../models/hacker.model'); + + // find all hackers created before the cutoff date + const hackers = await hackerModel.find({ + _id: { $lte: cutoffObjectId } + }).select('_id'); + + console.log('Found hackers:', hackers.length); + + // get counts + const hackerCount = hackers.length; + const revwiewerCount = REVIEWER_NAMES.length; + + if (hackerCount === 0) { + console.log('No hackers found for reviewer assignment.'); + + req.body = { + success: true, + assigned: 0, + reviewers: revwiewerCount, + assignments: [] + } + + return next(); + } + + console.log(`Found ${hackerCount} assignable reviewers.`); + + let assignments = []; + let hackerIndex = 0; + let updatePromises = []; + + // assign reviewers to hackers + for (const hacker of hackers) { + const assignedReviewer1 = REVIEWER_NAMES[hackerIndex % revwiewerCount]; + const assignedReviewer2 = REVIEWER_NAMES[(hackerIndex + 1) % revwiewerCount]; + + assignments.push({ hackerId: hacker._id, reviewer: assignedReviewer1, reviewer2: assignedReviewer2 }); + + updatePromises.push( + Services.Hacker.updateOne(hacker._id, { reviewerName: assignedReviewer1, reviewerName2: assignedReviewer2 }) + ); + + hackerIndex++; + } + + // exec all updates + await Promise.all(updatePromises); + + console.log(`Completed reviewer assignment at ${new Date().toISOString()}`); + console.log(`Assignments:`, assignments); + + req.body = { + success: true, + assigned: hackerCount, + reviewers: revwiewerCount, + assignments: assignments + } + + return next(); + + } catch (error) { + console.error('Error during reviewer assignment:', error); + return next({ + status: 500, + message: Constants.Error.GENERIC_500_MESSAGE, + data: { error: error } + }); + } +} + /** * Sets req.body.status to Accepted for next middleware, and store req.params.id as req.hackerId * @param {{params:{id: string}, body: *}} req @@ -911,6 +1003,7 @@ module.exports = { ), updateHacker: Middleware.Util.asyncMiddleware(updateHacker), updateBatchHacker: Middleware.Util.asyncMiddleware(updateBatchHacker), + assignReviewers: Middleware.Util.asyncMiddleware(assignReviewers), parseAccept: parseAccept, parseAcceptBatch: parseAcceptBatch, parseAcceptEmail: parseAcceptEmail, diff --git a/routes/api/hacker.js b/routes/api/hacker.js index bfc7a5bf..c69fe2a7 100644 --- a/routes/api/hacker.js +++ b/routes/api/hacker.js @@ -299,6 +299,32 @@ module.exports = { Controllers.Hacker.updatedHacker ); + /** + * @api {post} /hacker/assignReviewers update a hacker's reviewer status + * @apiName patchAssignReviewers + * @apiGroup Hacker + * @apiVersion 0.0.9 + * + * @apiParam (body) None + * @apiSuccess {string} message Success message + * @apiSuccess {object} data Hacker object + * @apiSuccessExample {object} Success-Response: + * { + * "message": "Assigned reviewers to hackers", + * } + * @apiPermission Administrator + */ + hackerRouter.route("/assignReviewers").post( + // 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.assignReviewers, + Controllers.Hacker.assignedReviewers + ); + /** * @api {patch} /hacker/reviewerStatus/:id update a hacker's reviewer status * @apiName patchHackerReviewerStatus diff --git a/scripts/accept_script.py b/scripts/accept_script.py index 7fc71334..2e3e47b1 100644 --- a/scripts/accept_script.py +++ b/scripts/accept_script.py @@ -619,10 +619,6 @@ 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():