Node.js callback from one controller method to other - node.js

I have created a emailHelper in my project for sending emails.
I wan to get a callback once the email sent successfully
//emailHelper.js
module.exports = {
sendMail: (options) => {
var transporter = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: keys.sendGridUsername,
pass: keys.sendGridPassword
}
});
const mailOptions = {
from: options.from,
to: options.to,
subject: options.subject,
html: options.content
};
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
return false;
}
else {
console.log('mail sent');
return true;
}
});
}
}
I want to save data to database only if the email is sent
const { sendMail } = require('../helpers/emailHelper');
mail: (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}
thank you

Wrap your sendMail in promise and return it:
return new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
reject();
}
else {
console.log('mail sent');
resolve();
}
});
});
Than you would be able to do this:
sendMail(emailOptions).then(() => {
// success save data
}).catch(() => {
// failure trrow error
});
Using async/await you would need to change promise to return some identifier in any case, boolean in this case, and than tweak mail function:
return new Promise((resolve) => {
transporter.sendMail(mailOptions, (err, info) => {
if(err) {
console.log(err);
resolve(false);
}
else {
console.log('mail sent');
resolve(true);
}
});
});
mail: async (req, res, next) => {
const emailOptions = {
from: 'from#email.com',
to: 'to#email.com',
subject: 'subject',
content: 'text'
};
const mailResetLink = await sendMail(emailOptions);
if(mailResetLink) {
//success save data
} else {
//failure trrow error
}
}

Related

Nodemailer is not working in live but locally working fine

function sendEmail(num, email, customerName) {
var readHTMLFile = function (path, callback) {
fs.readFile(path, { encoding: 'utf-8' }, function (err, html) {
if (err) {
throw err;
callback(err);
}
else {
callback(null, html);
}
});
};
let transporter = nodemailer.createTransport({
host: "smtp.gmail.com",
secure: true,
port: 465,
auth: {
user:process.env.USEREMAIL,
pass:process.env.USERPASS
},
});
readHTMLFile(__dirname + '/views/layouts/first.html', function (err, html) {
var template = handlebars.compile(html);
var replacements = {
otp: `${num}`,
customerName: `${customerName}`
};
var htmlToSend = template(replacements);
var mailOptions = {
from: process.env.USEREMAIL,
to: email,
subject: "Hello ✔",
html: htmlToSend
};
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Email sent");
}
});
});
}
All this is working fine with my localhost:8000 but after I upload(hosted) with my cyclic.sh account, my app works and getting success message, but did not get any mail with my box. sendEmail function not working in live but working locally. what is issues of the sendEmail function
I had a same problem and fixed it by wrapping sendmail with a promise
new Promise((resolve, reject) => {
transporter.sendMail(mailOptions, function (error, response) {
if (error) {
reject(error)
} else {
resolve("email sent")
}
});
})

requires a callback function but got a [object Undefined]

I am creating a RESTful API using Node.js , express and My sql. I have created 2 Services,2Routers, and 2 Controllers
App.js module
require("dotenv").config();
const express = require("express");
const app = express();
const userRouter = require("./api/Routers/user.router");
const categoryRouter=require("./api/Routers/category.router");
app.use(express.json());
app.use("/api/users", userRouter);
app.use("/api/category", categoryRouter);
const port = process.env.PORT ;
app.listen(port, () => {
console.log("server up and running on PORT :", port);
});
Category.service.js
const pool = require("../../config/database");
module.exports = {
create: (data, callBack) => {
pool.query(
`insert into category(name, , branch, state, create_date, modified_date)
values(?,?,?,?,?,?)`,
[
data.name,
data.branch,
data.state,
data.create_date,
data.modified_date,
],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results);
}
);
},
getUserByUserEmail: (email, callBack) => {
pool.query(
`select * from registration where email = ?`,
[email],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results[0]);
}
);
},
getCategoryByCategoryId: (id, callBack) => {
pool.query(
`select id,name,branch,state,create_date,modified_date from category where id = ?`,
[id],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results[0]);
}
);
},
getCategory: callBack => {
pool.query(
`select id,name,branch,state,create_date,modified_date from category`,
[],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results);
}
);
},
updateCategory: (data, callBack) => {
pool.query(
`update category set name=?, branch=?, state=?, create_date=?, modified_date=?, `,
[
data.name,
data.branch,
data.state,
data.create_date,
data.modified_date,
],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results[0]);
}
);
},
deleteCategory: (data, callBack) => {
pool.query(
`delete from category where id = ?`,
[data.id],
(error, results, fields) => {
if (error) {
callBack(error);
}
return callBack(null, results[0]);
}
);
}
};
Category.route.js
const router = require("express").Router();
const { checkToken } = require("../../auth/token_validation");
const {
createCategory,
login,
getCreateByCreateId,
getCategory,
updateCategory,
deleteCategory
} = require("../Controllers/category.controller");
router.get("/", checkToken, getCategory);
router.post("/", checkToken, createCategory);
router.get("/:id", checkToken, getCreateByCreateId);
router.post("/login", login);
router.patch("/", checkToken, updateCategory);
router.delete("/", checkToken, deleteCategory);
module.exports = router;
Category.controll.js
const {
create,
getUserByUserEmail,
getCategoryByCategoryId,
getCategory,
updateCategory,
deleteCategory
} = require("../services/category.service");
const { hashSync, genSaltSync, compareSync } = require("bcrypt");
const { sign } = require("jsonwebtoken");
module.exports = {
createUser: (req, res) => {
const body = req.body;
const salt = genSaltSync(10);
body.password = hashSync(body.password, salt);
create(body, (err, results) => {
if (err) {
console.log(err);
return res.status(500).json({
success: 0,
message: "Database connection error"
});
}
return res.status(200).json({
success: 1,
data: results
});
});
},
login: (req, res) => {
const body = req.body;
getUserByUserEmail(body.email, (err, results) => {
if (err) {
console.log(err);
}
if (!results) {
return res.json({
success: 0,
data: "Invalid email or password"
});
}
const result = compareSync(body.password, results.password);
if (result) {
results.password = undefined;
const jsontoken = sign({ result: results }, process.env.JWT_KEY, {
expiresIn: "1h"
});
return res.json({
success: 1,
message: "login successfully",
token: jsontoken
});
} else {
return res.json({
success: 0,
data: "Invalid email or password"
});
}
});
},
getCategoryByCategoryId: (req, res) => {
const id = req.params.id;
getCategoryByCategoryId(id, (err, results) => {
if (err) {
console.log(err);
return;
}
if (!results) {
return res.json({
success: 0,
message: "Record not Found"
});
}
results.password = undefined;
return res.json({
success: 1,
data: results
});
});
},
getCategory: (req, res) => {
getCategory((err, results) => {
if (err) {
console.log(err);
return;
}
return res.json({
success: 1,
data: results
});
});
},
updateCategory: (req, res) => {
const body = req.body;
const salt = genSaltSync(10);
body.password = hashSync(body.password, salt);
updateCategory(body, (err, results) => {
if (err) {
console.log(err);
return;
}
return res.json({
success: 1,
message: "updated successfully"
});
});
},
deleteCategory: (req, res) => {
const data = req.body;
deleteCategory(data, (err, results) => {
console.log(results);
if (err) {
return;
}
if (!results) {
return res.json({
success: 0,
message: "Record Not Found",
h:results
});
}
return res.json({
success: 1,
message: "category deleted not successful"
});
});
}
};
I am getting Error: Route.post() requires a callback function but got a [object Undefined. how can i sort it out
Error: Route.post() requires a callback function but got a [object Undefined] how can I sort this error
createUser should be renamed in createCategory in Category.controll.js

Axios.get is not returning anything in nodeJS,Express

I have a problem with .get request.
Somehow it is not returning anything? (GET http://localhost:8080/admin net::ERR_EMPTY_RESPONSE)
Any suggestions?
Get Route,With this I'm trying to filter all items by their username:
app.get("/:username", verify, (req, res) => {
console.log("Welcome to roffys server");
Todo.find({ username: req.params.username }).then((err, todo) => {
if (err) {
console.log("Error retrieving todos");
} else {
res.json(todo);
}
});
});
Verify function,here I'm verifying my auth-token,I console logged it and it is working fine:
const jwt = require("jsonwebtoken");
module.exports = function (req, res, next) {
const token = req.header("auth-token");
console.log("-----token", token);
if (!token) return res.status(401).send("Access Denied");
try {
const verified = jwt.verify(token, "secretkey");
req.user = verified;
} catch (err) {
res.status(400).send("Invalid token");
next();
}
};
FE Side with ReactJS :
componentDidMount() {
const { getAll, setPageCount } = this.props.actions;
axios
.get(`http://localhost:8080/${localStorage.getItem("username")}`, {
headers: {
"auth-token": localStorage.getItem("auth-token"),
},
})
.then((res) => {
getAll(res.data);
setPageCount();
console.log("--------res.data", res.data);
})
.catch((err) => {
console.log("err", err);
});
}
app.get("/:username", verify, (req, res, next) => {
console.log("Welcome to roffys server");
Todo.find({ username: req.params.username }).then((err, todo) => {
if (err) {
console.log("Error retrieving todos");
return next(err);
} else {
res.json(todo);
}
});
});
try to add next to your handler and call it when you receive an error.

ejs renderFile condition to check for null

I have a mail route which is using ejs templates to choose different files. Now I want to check for different files and if the files does not exist or null it should choose default "en.ejs" file
inside ejs.renderFile I want to check for if(selectedLanguage !==null{}) but I am not sure how can I do it.
router.post('/mail', (req, res) => {
const subject = 'Test Mail';
const url = process.env.REPORT_URL;
const selectLanguage = req.body.selectedLang
sgMail.setApiKey(SGAPIKEY);
ejs.renderFile(__dirname + `/../ejs/reports/${selectLanguage}.ejs`, {
url: url
},
function (err, data) {
if (err) {
return err;
} else {
const msg = {
to: req.body.sendTo_email,
from: "test#test.com",
subject: subject,
html: data,
cc: req.body.cc,
attachments: [{
content: req.body.pdfBase64,
filename: 'file.pdf',
type: 'application/pdf',
disposition: 'attachment'
}]
};
sgMail.send(msg, error => {
if (error) {
return res.status(400).send({
sent: false
});
} else {
return res.status(200).send({
sent: true
});
}
});
}
});
});
You can check if the template file for the selected language exists (by using fs.access) and fallback to the en.ejs template before calling ejs.renderFile:
const fs = require('fs');
const getTemplateFileName = (lang, callback) => {
const defaultTemplate = __dirname + '/../ejs/reports/en.ejs';
const selectedLangTemplate = __dirname + `/../ejs/reports/${lang}.ejs`;
fs.access(selectedLangTemplate, fs.constants.F_OK, (err) => {
if (err) {
callback(defaultTemplate);
} else {
callback(selectedLangTemplate)
}
})
};
router.post('/mail', (req, res) => {
const subject = 'Test Mail';
const url = process.env.REPORT_URL;
const selectLanguage = req.body.selectedLang
sgMail.setApiKey(SGAPIKEY);
getTemplateFileName(selectLanguage, (filename) => {
ejs.renderFile(filename, { url }, function (err, data) {
if (err) {
return err;
} else {
const msg = {
to: req.body.sendTo_email,
from: "test#test.com",
subject: subject,
html: data,
cc: req.body.cc,
attachments: [{
content: req.body.pdfBase64,
filename: 'file.pdf',
type: 'application/pdf',
disposition: 'attachment'
}]
};
sgMail.send(msg, error => {
if (error) {
return res.status(400).send({
sent: false
});
} else {
return res.status(200).send({
sent: true
});
}
});
}
})
});
});

Not getting correct status code (409) if email exists using Next.js, Mongoose, MongoDb Atlas and Express

I am building a login/Register portion of my app. Right now I'm using express-validator to check if an email exists in my collection.
This is my route:
var router = require('express').Router()
var UserModel = require('../models/UserModel')
var { body } = require('express-validator');
router
.route('/registration')
.get(function(req, res) {
console.log(0)
UserModel.find({}, (err, users) => {
console.log(1);
if (err) return res.status(500).send(err)
console.log(2);
return res.json(users);
})
})
.post(body('username_email').custom(value => {
console.log("value ", value);
console.log(3)
UserModel.findOne({ 'username_email': value }, (err) => {
console.log(4);
if (err) return res.status(409).send(err);
})
}), async(req, res, next) => {
console.log(5)
try {
let newUser = new UserModel(req.body);
let savedUser = await newUser.save();
console.log(6);
if (savedUser) return res.redirect('/users/registration?success=true');
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
module.exports = router
In my component on the front end I have a function in my fetch which will catch the error if there is one.
handleErrors(response) {
if (!response.ok) {
console.log('This email exists!')
throw Error(response.statusText);
}
return response;
}
handleSubmit(event) {
event.preventDefault()
var { username, password } = this.state
var mailFormat = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
var error = false
if (!username.match(mailFormat)) {
this.setState({ usernameError: true })
error = true
} else {
this.setState({ usernameError: false })
}
if (password.length <= 8) {
this.setState({ passwordError: true })
error = true
} else {
this.setState({ passwordError: false })
}
console.log(`error ${error}`)
if (error == false) {
this.setState({ formError: false, formSuccess: true })
}
window.fetch('http://localhost:8016/users/registration', {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
body: JSON.stringify({ username_email: username, password: password })
})
.then(this.handleErrors)
.then(function (response) {
console.log(`response ${response}`)
return response.json()
}).then(function (data) {
console.log('User created:', data)
}).catch(function (error) {
console.log(error);
});
}
The console.log in the fetch, handleErrors is being registered in the console, but why isn't the error status a 409 like I indicated.
Closer excerpt of post route!
.post(body('username_email').custom(value => {
console.log("value ", value);
console.log(3)
Is this the problem? Node style should have a error and callback?
UserModel.findOne({ 'username_email': value }, (err) => {
console.log(4);
if (err) return res.status(409).send(err);
})
}), async(req, res, next) => {
console.log(5)
try {
let newUser = new UserModel(req.body);
let savedUser = await newUser.save();
console.log(6);
if (savedUser) return res.redirect('/users/registration?success=true');
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
UPDATE
I tried Nick's solution but I get this:
MongoError: E11000 duplicate key error collection: development.users index: email_1 dup key: { : null }
at Function.create (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongodb-core/lib/error.js:43:12)
at toError (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongodb/lib/utils.js:149:22)
at coll.s.topology.insert (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongodb/lib/operations/collection_ops.js:859:39)
at handler (/Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongodb-core/lib/topologies/replset.js:1155:22)
at /Users/antoniopavicevac-ortiz/Dropbox/developer_folder/hillfinder/node_modules/mongodb-core/lib/connection/pool.js:397:18
at process._tickCallback (internal/process/next_tick.js:61:11)
POST /users/registration 500 312.485 ms - 51
^C
Two things I am noticing:
I get back MongoError: E11000 duplicate key error collection: development.users index: email_1 dup key: { : null }
which is the error from having a duplicate email, but number one where is E-mail already in use message in the console from the promise? And two how can I pass the error status "res.status(409).send(err);" from the promise?
The issue was that during your validation, you weren't returning the promise since the mongoose call is async. The rest the code ran before your validator was finished. I commented where you were missing the return.
router.route('/registration')
.get(function(req, res) {
UserModel.find({}, (err, users) => {
if (err) res.status(500).send(err)
res.json(users)
})
})
.post(body('username').custom(value => {
return UserModel.findOne({ 'email': value }).then(user => { // Return Promise
if (user) {
return Promise.reject('E-mail already in use');
}
});
}), async(req, res, next) => {
try {
let newUser = new UserModel(req.body)
let savedUser = await newUser.save(err => {
if (err) return res.json({ success: false, error: err })
return res.json({ success: true })
})
if (savedUser) return res.redirect('/users/registration?success=true');
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
module.exports = router
UPDATE
Just read through express-validator docs. I think you would need to validate the errors during the request process
var router = require('express').Router()
var UserModel = require('../models/UserModel')
var { body, validationResult } = require('express-validator');
router.route('/registration')
.get(function(req, res) {
UserModel.find({}, (err, users) => {
if (err) res.status(500).send(err)
res.json(users)
})
})
.post(body('username').custom(value => {
return UserModel.findOne({ 'email': value }).then(user => { // Return Promise
if (user) {
return Promise.reject('E-mail already in use');
}
});
}), async(req, res, next) => {
// Checks for errors in validation
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
try {
let newUser = new UserModel(req.body)
let savedUser = await newUser.save(err => {
if (err) return res.json({ success: false, error: err })
return res.json({ success: true })
})
if (savedUser) return res.redirect('/users/registration?success=true');
return next(new Error('Failed to save user for unknown reasons'))
} catch (err) {
return next(err)
}
})
module.exports = router

Resources