Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 7ea22c3

Browse files
Merge pull request #1 from Priyankcoder/email-verification
complete local user registration/login and email verification
2 parents 4cc6f58 + a1c382d commit 7ea22c3

File tree

12 files changed

+219
-50
lines changed

12 files changed

+219
-50
lines changed

‎server/controllers/errorController.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"use strict";
22

33
const httpStatus = require("http-status-codes");
4+
const path = require("path")
5+
46

57
exports.logErrors = (error, req, res, next) => {
68
console.error(error.stack);
@@ -11,7 +13,9 @@ exports.respondNoResourceFound = (req, res) => {
1113
let errorCode = httpStatus.NOT_FOUND;
1214
res.status(errorCode);
1315
// res.send(`${errorCode} | The page does not exist!`);
14-
res.sendFile("public/html/Er404.html");
16+
res.sendFile(path.join(__dirname, "../public/html/Er404.html"));
17+
18+
1519
};
1620

1721
exports.respondInternalError = (error, req, res, next) => {

‎server/controllers/usersController.js

Lines changed: 146 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
"use strict";
22

3-
const User = require("../models/user");
3+
const User = require("../models/user"),
4+
Token = require("../models/token"),
5+
crypto = require("crypto"),
6+
passport = require("passport"),
7+
nodemailer = require("nodemailer");
8+
9+
410
const getUserParams = body => {
511
return {
612
name: {
@@ -37,64 +43,125 @@ module.exports = {
3743
req.flash(
3844
"Success",
3945
`${user.name.first}'s account created successfully!`
40-
4146
);
4247
console.log(user);
43-
res.locals.redirect = `/user/${user.name.first}`;
48+
// Create a verification token for this user
49+
var token = new Token({
50+
_userId: user._id,
51+
token: crypto.randomBytes(16).toString("hex"),
52+
});
53+
54+
// Save the verification token
55+
token.save(function (err) {
56+
if (err) {
57+
return res.status(500).send({ msg: err.message });
58+
}
59+
60+
// Send the email
61+
var transporter = nodemailer.createTransport({
62+
service: "SendGrid",
63+
auth: {
64+
user: "apikey",
65+
pass:
66+
"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",
67+
},
68+
});
69+
var mailOptions = {
70+
from: "priyankrastogi14@gmail.com",
71+
to: user.email,
72+
subject: "Account Verification Token",
73+
// text:
74+
// "Hello,\n\n" +
75+
// "Please verify your account by clicking the link \n",
76+
html: `<p>Please verify your Smartier account by clicking the link below</p><a href=http:\/\/${req.headers.host}\/confirmation\/${token.token}>Link</a>`,
77+
};
78+
transporter.sendMail(mailOptions, function (err) {
79+
if (err) {
80+
console.log(err.stack);
81+
res.locals.redirect = "/";
82+
next();
83+
}
84+
// res.status(200).send('A verification email has been sent to Your email address.');
85+
});
86+
});
87+
res.locals.redirect = `/feed`;
4488
next();
4589
} else {
4690
req.flash(
4791
"error",
4892
`Failed to create user account because: ${error.message}.`
4993
);
5094
res.locals.redirect = "/";
51-
next()
95+
next();
5296
}
5397
});
5498
},
5599
userFeed: (req, res) => {
56-
res.render("user", {userName:req.params.user});
57-
100+
res.render("feed");
58101
},
59102
redirectView: (req, res, next) => {
60103
let redirectPath = res.locals.redirect;
61104
if (redirectPath) res.redirect(redirectPath);
62105
},
63-
login: (req, res) => {
64-
res.render("users/login");
65-
},
66-
authenticate: (req, res, next) => {
67-
User.findOne({ email: req.body.email })
68-
.then((user) => {
69-
if (user) {
70-
user.passwordComparison(req.body.password).then((passwordsMatch) => {
71-
if (passwordsMatch) {
72-
res.locals.redirect = `/user/${user._id}`;
73-
req.flash("success", `${user.first}'s logged in successfully!`);
74-
res.locals.user = user;
75-
} else {
76-
req.flash(
77-
"error",
78-
"Failed to log in user account: Incorrect Password."
79-
);
80-
res.locals.redirect = "/login";
81-
}
82-
next();
83-
});
84-
} else {
85-
req.flash(
86-
"error",
87-
"Failed to log in user account: User account not found."
88-
);
89-
res.locals.redirect = "/login";
90-
next();
91-
}
106+
resendToken: function (req, res, next) {
107+
req
108+
.sanitizeBody("email")
109+
.normalizeEmail({
110+
all_lowercase: true,
92111
})
93-
.catch((error) => {
94-
console.log(`Error logging in user: ${error.message}`);
95-
next(error);
96-
});
112+
.trim();
113+
req.check("email", "Email is invalid").isEmail();
114+
// Check for validation errors
115+
116+
var errors = req.validationErrors();
117+
if (errors) return res.status(400).send(errors);
118+
119+
User.findOne({ email: req.body.email }, function (err, user) {
120+
if (!user) return res.status(400).send({ msg: 'We were unable to find a user with that email.' });
121+
if (user.isVerified) return res.status(400).send({ msg: 'This account has already been verified. Please log in.' });
122+
123+
// Create a verification token, save it, and send email
124+
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
125+
126+
// Save the token
127+
token.save(function (err) {
128+
if (err) { return res.status(500).send({ msg: err.message }); }
129+
130+
// Send the email
131+
var transporter = nodemailer.createTransport({
132+
service: "SendGrid",
133+
auth: {
134+
user: "apikey",
135+
pass:
136+
"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",
137+
},
138+
});
139+
var mailOptions = {
140+
from: "priyankrastogi14@gmail.com",
141+
to: user.email,
142+
subject: "Account Verification Token",
143+
// text:
144+
// "Hello,\n\n" +
145+
// "Please verify your account by clicking the link \n",
146+
html: `<p>Please verify your Smartier account by clicking the link below</p><a href=http:\/\/${req.headers.host}\/confirmation\/${token.token}>Link</a>`,
147+
};
148+
transporter.sendMail(mailOptions, function (err) {
149+
if (err) { return res.status(500).send({ msg: err.message }); }
150+
return res.status(200).send('A verification email has been sent to ' + user.email + '.');
151+
});
152+
});
153+
154+
});
155+
},
156+
login: (req, res) => {
157+
res.render("user/login");
97158
},
159+
authenticate: passport.authenticate("local", {
160+
failureRedirect: "/login",
161+
failureFlash: "Failed to login.",
162+
successRedirect: "/feed",
163+
successFlash: "Logged in!",
164+
}),
98165
validate: (req, res, next) => {
99166
req
100167
.sanitizeBody("email")
@@ -107,7 +174,6 @@ module.exports = {
107174
req.check("first", "this cannot be empty").notEmpty();
108175
req.check("last", "this cannot be empty").notEmpty();
109176

110-
111177
req.getValidationResult().then((error) => {
112178
if (!error.isEmpty()) {
113179
let messages = error.array().map((e) => e.msg);
@@ -120,4 +186,44 @@ module.exports = {
120186
}
121187
});
122188
},
189+
/**
190+
* POST /confirmation
191+
*/
192+
confirmationPost: function (req, res, next) {
193+
console.log(req.params.token);
194+
Token.findOne({ token: req.params.token }, function (err, token) {
195+
if (!token)
196+
return res
197+
.status(400)
198+
.send({
199+
type: "not-verified",
200+
msg:
201+
"We were unable to find a valid token. Your token may have expired.",
202+
});
203+
204+
// If we found a token, find a matching user
205+
User.findOne({ _id: token._userId }, function (err, user) {
206+
if (!user)
207+
return res
208+
.status(400)
209+
.send({ msg: "We were unable to find a user for this token." });
210+
if (user.isVerified)
211+
return res
212+
.status(400)
213+
.send({
214+
type: "already-verified",
215+
msg: "This user has already been verified.",
216+
});
217+
218+
// Verify and save the user
219+
user.isVerified = true;
220+
user.save(function (err) {
221+
if (err) {
222+
return res.status(500).send({ msg: err.message });
223+
}
224+
res.status(200).send("The account has been verified. Please log in.");
225+
});
226+
});
227+
});
228+
},
123229
};

‎server/main.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@ const express = require("express"),
99
expressSession = require("express-session"),
1010
cookieParser = require("cookie-parser"),
1111
connectFlash = require("connect-flash"),
12+
path = require("path"),
1213
expressValidator = require("express-validator"),
1314
passport = require("passport"),
1415
errorController = require("./controllers/errorController"),
1516
homeController = require("./controllers/homeController"),
1617
// subscribersController = require("./controllers/subscribersController"),
1718
usersController = require("./controllers/usersController"),
1819
// coursesController = require("./controllers/coursesController"),
19-
User = require("./models/user");
20+
User = require("./models/user"),
21+
Token = require("./models/token")
2022

2123
mongoose.Promise = global.Promise;
2224

@@ -34,7 +36,7 @@ db.once("open", () => {
3436
app.set("port", process.env.PORT || 3000);
3537
app.set("view engine", "ejs");
3638

37-
router.use(express.static("public"));
39+
router.use(express.static(path.join(__dirname,"public")));
3840
router.use(layouts);
3941
router.use(
4042
express.urlencoded({
@@ -79,8 +81,20 @@ router.get("/", homeController.sendHome);
7981
router.get("/register", usersController.new);
8082
router.post("/user/create", usersController.validate, usersController.create, usersController.redirectView);
8183
router.get("/login", usersController.login);
82-
router.post("/login", usersController.authenticate, usersController.redirectView); // app.get("/:name", homeController.sendProfile); app.get("/user", usersController.index, usersController.indexView) //Middlewares
83-
router.get("/user/:user", usersController.userFeed);
84+
router.post("/login", usersController.authenticate); // app.get("/:name", homeController.sendProfile); app.get("/user", usersController.index, usersController.indexView) //Middlewares
85+
router.get("/feed", usersController.userFeed);
86+
// router.get("/user/verification", (req, res)=>{
87+
// res
88+
// .status(200)
89+
// .send("A verification email has been sent to " + user.email + ".");
90+
// })
91+
92+
router.get("/confirmation/:token", usersController.confirmationPost);
93+
// app.post("/resend", usersController.resendTokenPost);
94+
router.post("/resendToken", usersController.resendToken);
95+
96+
97+
8498
router.use(errorController.logErrors);
8599
router.use(errorController.respondNoResourceFound);
86100
router.use(errorController.respondInternalError);

‎server/models/token.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const mongoose = require("mongoose");
2+
const tokenSchema = new mongoose.Schema({
3+
_userId: {
4+
type: mongoose.Schema.Types.ObjectId,
5+
required: true,
6+
ref: "User",
7+
},
8+
token: { type: String, required: true },
9+
createdAt: { type: Date, required: true, default: Date.now, expires: 43200 },
10+
});
11+
12+
module.exports = mongoose.model("token", tokenSchema);

‎server/models/user.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
const mongoose = require("mongoose");
2-
const passportLocalMongoose = require("passport-local-mongoose");
3-
const userSchema = mongoose.Schema(
1+
const mongoose = require("mongoose"),
2+
passportLocalMongoose = require("passport-local-mongoose"),
3+
bcrypt = require("bcrypt"),
4+
passport = require("passport"),
5+
userSchema = mongoose.Schema(
46
{
57
name: {
68
first: {
@@ -19,6 +21,7 @@ const userSchema = mongoose.Schema(
1921
lowercase: true,
2022
unique: true,
2123
},
24+
isVerified: { type: Boolean, default: false },
2225
},
2326
{
2427
timestamps: true,

‎server/package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎server/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"dependencies": {
2727
"connect-flash": "^0.1.1",
2828
"cookie-parser": "^1.4.5",
29+
"crypto": "^1.0.1",
2930
"ejs": "^3.1.3",
3031
"express": "^4.17.1",
3132
"express-ejs-layouts": "^2.5.0",
@@ -35,6 +36,7 @@
3536
"mongodb": "^3.5.9",
3637
"mongoose": "^5.9.24",
3738
"mongoose-type-email": "^1.0.12",
39+
"nodemailer": "^6.4.10",
3840
"nodemon": "^2.0.4",
3941
"passport": "^0.4.1",
4042
"passport-local-mongoose": "^6.0.1"

‎server/public/html/Er404.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
<title>ERROR404</title>
77
</head>
88
<body>
9-
<img src="../images/Er404.svg" alt="ERROR404 Not Found" style = "width: 100vw;">
9+
<img src="/images/Er404.svg" alt="ERROR404 Not Found" style = "width: 100vw;">
1010
</body>
1111
</html>

‎server/views/error404.ejs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>ERROR404</title>
7+
</head>
8+
<body>
9+
<img src="/images/Er404.svg" alt="ERROR404 Not Found" style = "width: 100vw;">
10+
</body>
11+
</html>

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /