Skip to content

Commit

Permalink
Finished email
Browse files Browse the repository at this point in the history
  • Loading branch information
Harsh Patel committed Oct 31, 2019
1 parent d8b634a commit b135286
Show file tree
Hide file tree
Showing 9 changed files with 200 additions and 102 deletions.
8 changes: 6 additions & 2 deletions constants/routes.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,13 @@ const searchRoutes = {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/search/"
},
"bactchAction": {
"updateStatus": {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/search/action",
uri: "/api/search/updateStatus",
},
"sendEmails": {
requestType: Constants.REQUEST_TYPES.GET,
uri: "/api/search/sendEmails",
},
};

Expand Down
2 changes: 2 additions & 0 deletions constants/success.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const HACKER_GET_BY_ID = "Hacker found by id.";
const HACKER_READ = "Hacker retrieval successful.";
const HACKER_CREATE = "Hacker creation successful.";
const HACKER_UPDATE = "Hacker update successful.";
const HACKER_UPDATE_EMAILS = "Hacker update emails sent."
const HACKER_SENT_WEEK_OF = "Hacker week-of email sent."

const RESUME_UPLOAD = "Resume upload successful.";
Expand Down Expand Up @@ -67,6 +68,7 @@ module.exports = {
HACKER_READ: HACKER_READ,
HACKER_CREATE: HACKER_CREATE,
HACKER_UPDATE: HACKER_UPDATE,
HACKER_UPDATE_EMAILS: HACKER_UPDATE_EMAILS,

HACKER_SENT_WEEK_OF: HACKER_SENT_WEEK_OF,

Expand Down
19 changes: 18 additions & 1 deletion controllers/search.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const Services = {
};
const Util = require("../middlewares/util.middleware");
const Success = require("../constants/success.constant");
const ErrorMessages = require("../constants/error.constant")

async function searchResults(req, res) {
let results = req.body.results;
Expand All @@ -21,6 +22,22 @@ async function searchResults(req, res) {
});
}

async function emailResults(req, res) {
let results = req.body.results;
let message;
if (results == undefined) {

This comment has been minimized.

Copy link
@pierreTklein

pierreTklein Nov 2, 2019

Member

Consider === over ==

message = Success.HACKER_UPDATE_EMAILS;
results = {}
} else {
message = ErrorMessages.EMAIL_500_MESSAGE;
}
return res.status(200).json({
message: message,
data: results
});
}

module.exports = {
searchResults: Util.asyncMiddleware(searchResults)
searchResults: Util.asyncMiddleware(searchResults),
emailResults: Util.asyncMiddleware(emailResults)
};
27 changes: 23 additions & 4 deletions middlewares/search.middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const Services = {
const Middleware = {
Util: require("../middlewares/util.middleware")
}
const Constants = require("../../constants/general.constant");

/**
* @function parseQuery
Expand Down Expand Up @@ -71,9 +70,28 @@ async function executeQuery(req, res, next) {
* @returns
*/
async function executeStatusAction(req, res, next) {
// NOW HAVE req.body.results as an array of "hackers potentially"
console.log("GETS IN EXECUTE STATUS ACTION BRO!")
req.body.results = await Services.Search.executeAction(req.body.model,
req.body.results = await Services.Search.executeStatusAction(req.body.model,
req.body.q,
req.body.page,
req.body.limit,
req.body.sort,
req.body.sort_by,
req.body.expand,
req.body.update
);
return next();
}

/**
*
* @param {} req
* @param {*} res
* @param {*} next
*
* @returns
*/
async function executeEmailAction(req, res, next) {
req.body.results = await Services.Search.executeEmailAction(req.body.model,
req.body.q,
req.body.page,
req.body.limit,
Expand All @@ -95,5 +113,6 @@ module.exports = {
parseQuery: parseQuery,
executeQuery: Middleware.Util.asyncMiddleware(executeQuery),
executeStatusAction: Middleware.Util.asyncMiddleware(executeStatusAction),
executeEmailAction: Middleware.Util.asyncMiddleware(executeEmailAction),
setExpandTrue: setExpandTrue,
};
16 changes: 12 additions & 4 deletions middlewares/validators/search.validator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,24 @@ module.exports = {
VALIDATOR.booleanValidator("query", "expand", true),
VALIDATOR.searchValidator("query", "q")
],
searchActionValidator: [
statusValidator: [
VALIDATOR.searchModelValidator("query", "model", false),
VALIDATOR.alphaValidator("query", "sort", true),
VALIDATOR.integerValidator("query", "page", true, 0),
VALIDATOR.integerValidator("query", "limit", true, 0, 1000),
VALIDATOR.searchSortValidator("query", "sort_by"),
VALIDATOR.booleanValidator("query", "expand", true),
VALIDATOR.searchValidator("query", "q"),
/* ACTION VALIDATOR NEED TO MAKE WORK! */
VALIDATOR.actionValidator("query", "action"),
VALIDATOR.statusValidator("query", "status")
VALIDATOR.updateObjectValidator("query", "update")
],
emailValidator: [
VALIDATOR.searchModelValidator("query", "model", false),
VALIDATOR.alphaValidator("query", "sort", true),
VALIDATOR.integerValidator("query", "page", true, 0),
VALIDATOR.integerValidator("query", "limit", true, 0, 1000),
VALIDATOR.searchSortValidator("query", "sort_by"),
VALIDATOR.booleanValidator("query", "expand", true),
VALIDATOR.searchValidator("query", "q"),
VALIDATOR.statusValidator("query", "status")
]
};
36 changes: 34 additions & 2 deletions middlewares/validators/validator.helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,12 +566,43 @@ function actionValidator(fieldLocation, actionFieldName) {
}


/**
* Validates that action field is a valid action from constants passed, and checks if corresponding new status is valid.
* @param {"query" | "body" | "header" | "param"} fieldLocation The location where the field should be found.
* @param {string} actionFieldName The name of the action that needs to be performed.
* @param {string} statusFieldName The name of the action that needs to be performed.
*/
function updateObjectValidator(fieldLocation, actionFieldName) {
const updateObjectValue = setProperValidationChainBuilder(fieldLocation, actionFieldName, "Invalid update object string.");

return updateObjectValue.exists()
.withMessage("The update object string must exist.")
.custom(updateObjectValidatorHelper).withMessage("The value must be a valid update object.");
}

function updateObjectValidatorHelper(update) {
try {
var updateObject = JSON.parse(update);

if (updateObject && typeof updateObject === "object" && !("password" in updateObject)) {

This comment has been minimized.

Copy link
@pierreTklein

pierreTklein Nov 2, 2019

Member

Since this function is generic (not just for account schemas), I would recommend making the validation more generic too, i.e. do not hardcode password into the validation.

for (var key in updateObject) {
var schemaPath = Models.Hacker.searchableField(key);

This comment has been minimized.

Copy link
@pierreTklein

pierreTklein Nov 2, 2019

Member

This line makes the function not generic too. So we should choose whether this should be an updateObjectValidatorHelper or a updateHackerValidatorHelper

if (!schemaPath) return false;
}
return true;
}
}
catch (e) {
return false;
}
}

function statusValidator(fieldLocation, statusFieldName) {
const statusValue = setProperValidationChainBuilder(fieldLocation, statusFieldName, "Invalid status.");
return statusValue.exists().withMessage("The status must exist!").custom((val, {
req
}) => {
return Constants.CORRESPONDING_STATUSES[req.query.action].includes(val);
return Constants.HACKER_STATUSES.includes(val);
}).withMessage("The value must be a proper status.")
}

Expand Down Expand Up @@ -647,5 +678,6 @@ module.exports = {
enumValidator: enumValidator,
routesValidator: routesValidator,
actionValidator: actionValidator,
statusValidator: statusValidator
statusValidator: statusValidator,
updateObjectValidator: updateObjectValidator,
};
19 changes: 14 additions & 5 deletions routes/api/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ module.exports = {
);

/**
* @api {get} /search/action execute an action on a specific query for any defined model
* @api {get} /search/updateStatus execute an action on a specific query for any defined model
* @apiName search
* @apiGroup Search
* @apiVersion 0.0.8
Expand All @@ -81,8 +81,7 @@ module.exports = {
* @apiParam (query) {number} limit the maximum number of results that you would like returned
* @apiParam (query) {any} sort_by any parameter you want to sort the results by
* @apiParam (query) {boolean} expand whether you want to expand sub documents within the results
* @apiParam (query) {String} action type of action either Status or Email
* @apiParam (query) {String} status new status or type of email
* @apiParam (query) {String} update new status or type of email
*
* @apiSuccess {String} message Success message
* @apiSuccess {Object} data Results
Expand All @@ -107,16 +106,26 @@ module.exports = {
* @apiErrorExample {object} Error-Response:
* {"message": "Validation failed", "data": {}}
*/
searchRouter.route("/action").get(
searchRouter.route("/updateStatus").get(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.Validator.Search.searchActionValidator,
Middleware.Validator.Search.statusValidator,
Middleware.parseBody.middleware,
Middleware.Search.parseQuery,
Middleware.Search.executeStatusAction,
Controllers.Search.searchResults
);

searchRouter.route("/sendEmails").get(
Middleware.Auth.ensureAuthenticated(),
Middleware.Auth.ensureAuthorized(),
Middleware.Validator.Search.emailValidator,
Middleware.parseBody.middleware,
Middleware.Search.parseQuery,
Middleware.Search.executeEmailAction,
Controllers.Search.emailResults
);

apiRouter.use("/search", searchRouter);
}
};
25 changes: 23 additions & 2 deletions services/email.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class EmailService {
* @param {*} mailData
* @param {(err?)=>void} callback
*/
send(mailData, callback = () => {}) {
send(mailData, callback = () => { }) {
if (env.isTest()) {
//Silence all actual emails if we're testing
mailData.mailSettings = {
Expand All @@ -41,7 +41,7 @@ class EmailService {
* @param {*} mailData
* @param {(err?)=>void} callback
*/
sendMultiple(mailData, callback = () => {}) {
sendMultiple(mailData, callback = () => { }) {
return client.sendMultiple(mailData, (error) => {
if (error) {
logger.error(`${TAG} ` + JSON.stringify(error));
Expand Down Expand Up @@ -100,6 +100,27 @@ class EmailService {
}
}, callback);
}

async sendStatusUpdateAsync(firstName, recipient, status) {
const handlebarsPath = path.join(__dirname, `../assets/email/statusEmail/${status}.hbs`);
const mailData = {
to: recipient,
from: process.env.NO_REPLY_EMAIL,
subject: Constants.EMAIL_SUBJECTS[status],
html: this.renderEmail(handlebarsPath, {
firstName: firstName
})
};
return this.send(mailData).then(
(response) => {
if (response[0].statusCode >= 200 && response[0].statusCode < 300) {
return undefined;
} else {
return response[0];
}
});
}

/**
* Generates the HTML from the handlebars template file found at the given path.
* @param {string} path the absolute path to the handlebars template file
Expand Down
Loading

0 comments on commit b135286

Please sign in to comment.