Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions constants/routes.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,16 @@ const hackerRoutes = {
uri: "/api/hacker/reviewerComments2/" + Constants.ROLE_CATEGORIES.SELF,
_id: mongoose.Types.ObjectId.createFromTime(179)
},
// patchAnyReviewerNameById: {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is all commented out, can we just delete it? is there a reason to keep?

// 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,
Expand Down
18 changes: 18 additions & 0 deletions controllers/hacker.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
93 changes: 93 additions & 0 deletions middlewares/hacker.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this comment accurate? i think it's just copy pasted?

* 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
Expand Down Expand Up @@ -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,
Expand Down
26 changes: 26 additions & 0 deletions routes/api/hacker.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's try to enable the auth ones at least

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should also add this route to the Hackboard role "excludes"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait i just realized if we're running this as a script for now we can't have these on

// 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
Expand Down
4 changes: 0 additions & 4 deletions scripts/accept_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
Loading