Skip to content
Merged
5 changes: 5 additions & 0 deletions constants/error.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@ const TEAM_MEMBER_422_MESSAGE = "Duplicate team member in input";
const VALIDATION_422_MESSAGE = "Validation failed";
const ACCOUNT_DUPLICATE_422_MESSAGE = "Account already exists";
const ROLE_DUPLICATE_422_MESSAGE = "Role already exists";
const SETTINGS_422_MESSAGE =
"openTime must be before closeTime, and closeTime must be before confirmTime";

const ACCOUNT_TOKEN_401_MESSAGE = "Invalid token for account";
const AUTH_401_MESSAGE = "Invalid Authentication";

const AUTH_403_MESSAGE = "Invalid Authorization";
const ACCOUNT_403_MESSAGE = "Account not verified";
const SETTINGS_403_MESSAGE = "Applications are not open right now";

const TEAM_READ_500_MESSAGE = "Error while retrieving team";
const TEAM_UPDATE_500_MESSAGE = "Error while updating team";
Expand Down Expand Up @@ -79,13 +82,15 @@ module.exports = {
HACKER_STATUS_409_MESSAGE: HACKER_STATUS_409_MESSAGE,
TEAM_SIZE_409_MESSAGE: TEAM_SIZE_409_MESSAGE,
ROLE_DUPLICATE_422_MESSAGE: ROLE_DUPLICATE_422_MESSAGE,
SETTINGS_422_MESSAGE: SETTINGS_422_MESSAGE,
ROLE_CREATE_500_MESSAGE: ROLE_CREATE_500_MESSAGE,
TEAM_NAME_409_MESSAGE: TEAM_NAME_409_MESSAGE,
TEAM_JOIN_SAME_409_MESSAGE: TEAM_JOIN_SAME_409_MESSAGE,
TEAM_READ_500_MESSAGE: TEAM_READ_500_MESSAGE,
VOLUNTEER_404_MESSAGE: VOLUNTEER_404_MESSAGE,
SPONSOR_UPDATE_500_MESSAGE: SPONSOR_UPDATE_500_MESSAGE,
SETTINGS_404_MESSAGE: SETTINGS_404_MESSAGE,
SETTINGS_403_MESSAGE: SETTINGS_403_MESSAGE,
TRAVEL_404_MESSAGE: TRAVEL_404_MESSAGE,
TRAVEL_CREATE_500_MESSAGE: TRAVEL_CREATE_500_MESSAGE
};
52 changes: 52 additions & 0 deletions middlewares/settings.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,28 @@ async function updateSettings(req, res, next) {
}
}

/**
* @function confirmValidPatch
* @param {{body:{settingsDetails:{openTime:Date, closeTime:Date, confirmTime:Date}}}} req
* @param {*} res
* @param {*} next
* @return {void}
* @description Confirms that openTime < closeTime < confirmTime
*/
function confirmValidPatch(req, res, next) {
const openTime = new Date(req.body.settingsDetails.openTime);
const closeTime = new Date(req.body.settingsDetails.closeTime);
const confirmTime = new Date(req.body.settingsDetails.confirmTime);
if (openTime < closeTime && closeTime < confirmTime) {
return next();
}
return next({
status: 422,
message: Constants.Error.SETTINGS_422_MESSAGE,
error: req.body.settingsDetails
});
}

/**
* @function updateSettings
* @param {*} req
Expand All @@ -76,8 +98,38 @@ async function getSettings(req, res, next) {
}
}

/**
* @function confirmAppsOpen
* @param {*} req
* @param {*} res
* @param {*} next
* @description Only succeeds if the currentTime > openTime, and currentTime < closeTime
*/
async function confirmAppsOpen(req, res, next) {
const settings = await Services.Settings.getSettings();
if (!settings) {
return next({
status: 500,
message: Constants.Error.GENERIC_500_MESSAGE
});
} else {
const now = Date.now();
const openTime = new Date(settings.openTime);
const closeTime = new Date(settings.closeTime);
if (openTime < now && closeTime > now) {
return next();
}
return next({
status: 403,
message: Constants.Error.SETTINGS_403_MESSAGE
});
}
}

module.exports = {
parsePatch: parsePatch,
confirmValidPatch: confirmValidPatch,
confirmAppsOpen: Middleware.Util.asyncMiddleware(confirmAppsOpen),
updateSettings: Middleware.Util.asyncMiddleware(updateSettings),
getSettings: Middleware.Util.asyncMiddleware(getSettings)
};
6 changes: 4 additions & 2 deletions routes/api/hacker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const Middleware = {
Util: require("../../middlewares/util.middleware"),
Hacker: require("../../middlewares/hacker.middleware"),
Auth: require("../../middlewares/auth.middleware"),
Search: require("../../middlewares/search.middleware")
Search: require("../../middlewares/search.middleware"),
Settings: require("../../middlewares/settings.middleware")
};
const Services = {
Hacker: require("../../services/hacker.service"),
Expand Down Expand Up @@ -180,8 +181,9 @@ module.exports = {
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.Validator.Hacker.newHackerValidator,

Middleware.parseBody.middleware,
Middleware.Settings.confirmAppsOpen,

// validate type
Middleware.Hacker.validateConfirmedStatusFromAccountId,
// validate that the accountId is not being used for any other thing
Expand Down
1 change: 1 addition & 0 deletions routes/api/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ module.exports = {
Middleware.Validator.Settings.createSettingsValidator,
Middleware.parseBody.middleware,
Middleware.Settings.parsePatch,
Middleware.Settings.confirmValidPatch,
Middleware.Settings.updateSettings,
Controllers.Settings.patchedSettings
);
Expand Down
51 changes: 51 additions & 0 deletions tests/hacker.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const util = {
auth: require("./util/auth.test.util"),
hacker: require("./util/hacker.test.util"),
account: require("./util/account.test.util"),
settings: require("./util/settings.test.util"),
accountConfirmation: require("./util/accountConfirmation.test.util")
};
const StorageService = require("../services/storage.service");
Expand Down Expand Up @@ -459,6 +460,56 @@ describe("POST create hacker", function() {
});
});

it("should FAIL to create a new hacker when applications have not yet opened.", function(done) {
// Upload application not yet open.
util.settings.setApplicationNotYetOpen().then(
util.auth.login(agent, newHackerAccount0, (error) => {
if (error) {
agent.close();
return done(error);
}
return agent
.post(`/api/hacker/`)
.type("application/json")
.send(newHacker0)
.end(function(err, res) {
res.should.have.status(403);
res.should.be.json;
res.body.should.have.property("message");
res.body.message.should.equal(
Constants.Error.SETTINGS_403_MESSAGE
);
done();
});
})
);
});

it("should FAIL to create a new hacker when applications have closed.", function(done) {
// Upload application closed.
util.settings.setApplicationClosed().then(
util.auth.login(agent, newHackerAccount0, (error) => {
if (error) {
agent.close();
return done(error);
}
return agent
.post(`/api/hacker/`)
.type("application/json")
.send(newHacker0)
.end(function(err, res) {
res.should.have.status(403);
res.should.be.json;
res.body.should.have.property("message");
res.body.message.should.equal(
Constants.Error.SETTINGS_403_MESSAGE
);
done();
});
})
);
});

// should fail due to travel request larger than 100
it("should FAIL if the new hacker inputs a value larger than 100 for travel reimbursement", function(done) {
util.auth.login(agent, newHackerAccount0, (error) => {
Expand Down
9 changes: 3 additions & 6 deletions tests/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const agent = chai.request.agent(server.app);
chai.should();
const util = {
account: require("./util/account.test.util"),
auth: require("./util/auth.test.util")
auth: require("./util/auth.test.util"),
settings: require("./util/settings.test.util")
};

const Constants = {
Expand Down Expand Up @@ -84,11 +85,7 @@ describe("PATCH settings", function() {
agent
.patch(`/api/settings/`)
.type("application/json")
.send({
openTime: new Date().toString(),
closeTime: new Date().toString(),
confirmTime: new Date().toString()
})
.send(util.settings.settingConfirmClosed)
// does not have password because of to stripped json
.end(function(err, res) {
res.should.have.status(200);
Expand Down
29 changes: 22 additions & 7 deletions tests/util/settings.test.util.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const Settings = require("../../models/settings.model");
const logger = require("../../services/logger.service");

const settingRegistrationNotYetOpen = {
const settingApplicationNotYetOpen = {
openTime: new Date(Date.now() + 100000000000),
closeTime: new Date(Date.now() + 10000000000000000),
confirmTime: new Date(Date.now() + 100000000000000000)
};

const settingRegistrationOpen = {
const settingApplicationOpen = {
openTime: new Date(Date.now() - 100),
closeTime: new Date(Date.now() + 10000000000),
confirmTime: new Date(Date.now() + 100000000000000)
};

const settingRegistrationClosed = {
const settingApplicationClosed = {
openTime: new Date(Date.now() - 100),
closeTime: new Date(Date.now() - 1000),
confirmTime: new Date(Date.now() + 100000000000000)
Expand All @@ -26,9 +26,22 @@ const settingConfirmClosed = {
};

async function storeAll() {
const toStore = new Settings(settingRegistrationClosed);
const toStore = new Settings(settingApplicationOpen);
Settings.collection.insertOne(toStore);
}

async function setApplicationClosed() {
await dropAll();
const toStore = new Settings(settingApplicationClosed);
Settings.collection.insertOne(toStore);
}

async function setApplicationNotYetOpen() {
await dropAll();
const toStore = new Settings(settingApplicationNotYetOpen);
Settings.collection.insertOne(toStore);
}

async function dropAll() {
try {
await Settings.collection.drop();
Expand All @@ -43,8 +56,10 @@ async function dropAll() {
module.exports = {
storeAll: storeAll,
dropAll: dropAll,
settingRegistrationNotYetOpen: settingRegistrationNotYetOpen,
settingRegistrationOpen: settingRegistrationOpen,
settingRegistrationClosed: settingRegistrationClosed,
setApplicationClosed: setApplicationClosed,
setApplicationNotYetOpen: setApplicationNotYetOpen,
settingApplicationNotYetOpen: settingApplicationNotYetOpen,
settingApplicationOpen: settingApplicationOpen,
settingApplicationClosed: settingApplicationClosed,
settingConfirmClosed: settingConfirmClosed
};