Skip to content
Draft
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
5 changes: 5 additions & 0 deletions services/registration/src/common/adjustScores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type CriteriaScores = {
score: number;
}[];

// distinguishable referral bonus (points should never be this high for any other reason)
// can we make a separate field for this? yes, however that requires handling a bunch of
// edge cases so surely its okay to be lazy for now
export const REFERRAL_BONUS = 100;

/** The minimum grading score an essay can get. */
const MIN_GRADING_SCORE = 1;
/** The maximum grading score an essay can get. */
Expand Down
21 changes: 19 additions & 2 deletions services/registration/src/routes/grading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,31 @@ import { Types } from "mongoose";
import _ from "lodash";

import { ApplicationModel, Essay, StatusType } from "../models/application";
import { ReferralModel, ReferralStatusType } from "../models/referral";
import { GraderModel } from "../models/grader";
import { Review, ReviewModel } from "../models/review";
import { BranchModel, BranchType, GradingGroupType } from "../models/branch";
import { calibrationQuestionMapping, rubricMapping } from "../config";
import { getCalibrationMapping } from "../common/adjustScores";
import { getCalibrationMapping, REFERRAL_BONUS } from "../common/adjustScores";

const MAX_REVIEWS_PER_ESSAY = 2;
// NOTE: No. of essays for each application. As such, will need to be updated whenever we add/remove essays.
const ESSAY_COUNT = 4;

async function checkForReferralBonus(email?: string, hexathon?: Types.ObjectId) {
if (!email || !hexathon) {
return 0;
}

const referral = await ReferralModel.exists({
hexathon,
"status": ReferralStatusType.SUBMITTED,
"referralData.email": new RegExp(`^${_.escapeRegExp(email.trim())}$`, "i"),
});

return referral ? REFERRAL_BONUS : 0;
}

type AggregatedEssay = {
applicationId: string;
applicationBranch: string;
Expand Down Expand Up @@ -304,7 +319,9 @@ gradingRouter.route("/actions/submit-review").post(
if (allEssayReviews.length >= MAX_REVIEWS_PER_ESSAY * ESSAY_COUNT) {
application.gradingComplete = true;
const sumScores = allEssayReviews.reduce((prev, review) => prev + review.adjustedScore, 0);
application.finalScore = sumScores / allEssayReviews.length;
const baseScore = sumScores / allEssayReviews.length;
const referralBonus = await checkForReferralBonus(application.email, application.hexathon);
application.finalScore = baseScore + referralBonus;
await application.save();
}

Expand Down
51 changes: 51 additions & 0 deletions services/registration/src/routes/referrals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,50 @@ import { FilterQuery, isValidObjectId, Types } from "mongoose";

import { validateReferralData } from "../common/util";
import { Referral, ReferralModel, ReferralStatusType } from "../models/referral";
import { ApplicationModel, StatusType } from "../models/application";
import { REFERRAL_BONUS } from "../common/adjustScores";

export const referralRouter = express.Router();

/*
The referral bonus gets applied after the last grader's review is submitted,
this handles the cases where someone is referred after their application is graded
*/
async function applyReferralBonus(
email?: string,
hexathon?: Types.ObjectId,
referralId?: Types.ObjectId
) {
if (!email || !hexathon || !referralId) {
return;
}

const emailRegex = new RegExp(`^${_.escapeRegExp(email.trim())}$`, "i");

const application = await ApplicationModel.findOne({
hexathon,
email: emailRegex,
status: { $ne: StatusType.DRAFT },
});

if (!application || !application.gradingComplete) {
return;
}

const alreadyHasBonus = await ReferralModel.exists({
hexathon,
"referralData.email": emailRegex,
"status": ReferralStatusType.SUBMITTED,
"_id": { $ne: referralId },
});
if (alreadyHasBonus) {
return;
}

application.finalScore += REFERRAL_BONUS;
await application.save();
}

referralRouter.route("/actions/create-referral").post(
checkAbility("create", "Referral"),
asyncHandler(async (req, res) => {
Expand Down Expand Up @@ -255,6 +296,10 @@ referralRouter.route("/:id/actions/submit-referral").post(
throw new BadRequestError("No referral exists with this id or you do not have permission.");
}

if (existingReferral.status !== ReferralStatusType.DRAFT) {
throw new BadRequestError("This referral has already been submitted.");
}

let resume;
if (existingReferral.referralData.resume) {
resume = await apiCall(
Expand All @@ -281,6 +326,12 @@ referralRouter.route("/:id/actions/submit-referral").post(
{ new: true, runValidators: true }
);

await applyReferralBonus(
existingReferral.referralData.email,
existingReferral.hexathon,
existingReferral._id
);

return res.sendStatus(204);
})
);