Skip to content

Commit 859a10c

Browse files
verify
1 parent a50c404 commit 859a10c

File tree

10 files changed

+135
-6
lines changed

10 files changed

+135
-6
lines changed

Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM node
2+
3+
WORKDIR /app
4+
5+
COPY . .
6+
7+
RUN npm install
8+
9+
EXPOSE 3000
10+
11+
CMD ["node", "server"]

controllers/users/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const logout = require('./logout');
44
const getCurrent = require('./getCurrent');
55
const updateSubscription = require('./updateSubscription');
66
const updateAvatar = require('./updateAvatar');
7+
const verifyEmail = require('./verifyEmail');
8+
const resendVerifyEmail = require('./resendVerifyEmail');
79

810
module.exports = {
911
signup,
@@ -12,4 +14,6 @@ module.exports = {
1214
getCurrent,
1315
updateSubscription,
1416
updateAvatar,
17+
verifyEmail,
18+
resendVerifyEmail,
1519
};

controllers/users/login.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const bcrypt = require('bcrypt');
22
const jwt = require('jsonwebtoken');
33
const { User } = require('../../models');
44
const { getErrorMessage } = require('../../utils');
5-
const { joiLoginSchema } = require('../../models/user');
5+
// const { joiLoginSchema } = require('../../models/user');
66
const { SECRET_KEY } = process.env;
77

88
const login = async (req, res) => {
@@ -17,6 +17,9 @@ const login = async (req, res) => {
1717
.status(401)
1818
.json(getErrorMessage(401, 'Email or password is wrong'));
1919
}
20+
if (!user.verify) {
21+
return res.status(401).json(getErrorMessage(401, 'Email not verify'));
22+
}
2023

2124
const comparePassword = bcrypt.compareSync(password, user.password);
2225
if (!comparePassword) {
@@ -25,10 +28,6 @@ const login = async (req, res) => {
2528
.json(getErrorMessage(401, 'Email or password is wrong'));
2629
}
2730

28-
// {
29-
// throw Error(401, 'Email or password is wrong');
30-
// }
31-
3231
const payload = {
3332
id: user._id,
3433
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const { User } = require('../../models');
2+
const { getErrorMessage, sendEmail } = require('../../utils');
3+
4+
const resendVerifyEmail = async (req, res) => {
5+
const { email } = req.body;
6+
7+
if (!email) {
8+
return res
9+
.status(400)
10+
.json(getErrorMessage(400, `Missing required field email`));
11+
}
12+
13+
const user = await User.findOne({ email });
14+
if (!user) {
15+
return res.status(404).json(getErrorMessage(404, `User not found`));
16+
}
17+
if (user.verify) {
18+
return res
19+
.status(400)
20+
.json(getErrorMessage(400, `Verification has already been passed`));
21+
}
22+
const mail = {
23+
to: email,
24+
subject: 'Site registration confirmation',
25+
html: `<a target="_blank" href="http://localhost:3000/api/auth/verify/${user.verificationToken}">Click to confirm registration</a>`,
26+
};
27+
28+
await sendEmail(mail);
29+
30+
res.json({
31+
status: 'success',
32+
code: 200,
33+
message: 'Verification email resent',
34+
});
35+
};
36+
37+
module.exports = resendVerifyEmail;

controllers/users/signup.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
const bcrypt = require('bcrypt');
22
const gravatar = require('gravatar');
33
const { User } = require('../../models');
4-
const { getErrorMessage } = require('../../utils');
4+
const { getErrorMessage, sendEmail } = require('../../utils');
5+
const { v4 } = require('uuid');
56

67
const signup = async (req, res) => {
78
const { email, password, subscription } = req.body;
@@ -12,6 +13,7 @@ const signup = async (req, res) => {
1213
.status(409)
1314
.json(getErrorMessage(409, `Email: '${email}' in use`));
1415
}
16+
const verificationToken = v4();
1517

1618
const avatarURL = gravatar.url(email);
1719
const hashPassword = bcrypt.hashSync(password, bcrypt.genSaltSync(10));
@@ -20,15 +22,25 @@ const signup = async (req, res) => {
2022
email,
2123
password: hashPassword,
2224
avatarURL,
25+
verificationToken,
2326
});
2427

28+
const mail = {
29+
to: email,
30+
subject: 'Site registration confirmation',
31+
html: `<a target="_blank" href="http://localhost:3000/api/auth/verify/${verificationToken}">Click to confirm registration</a>`,
32+
};
33+
34+
await sendEmail(mail);
35+
2536
res.status(201).json({
2637
status: 'success',
2738
code: 201,
2839
user: {
2940
email: result.email,
3041
subscription: result.subscription,
3142
avatarURL: result.avatarURL,
43+
verificationToken: result.verificationToken,
3244
},
3345
});
3446
};

controllers/users/verifyEmail.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const { User } = require('../../models');
2+
const { getErrorMessage } = require('../../utils');
3+
4+
const verifyEmail = async (req, res) => {
5+
const { verificationToken } = req.params;
6+
7+
const user = await User.findOne({ verificationToken });
8+
if (!user) {
9+
return res.status(404).json(getErrorMessage(404, `User not found`));
10+
}
11+
12+
await User.findByIdAndUpdate(user._id, {
13+
verify: true,
14+
verificationToken: '',
15+
});
16+
17+
res.json({
18+
status: 'success',
19+
code: 200,
20+
message: 'Verification successful',
21+
});
22+
};
23+
24+
module.exports = verifyEmail;

models/user.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ const userSchema = Schema({
2525
type: String,
2626
require: true,
2727
},
28+
verify: {
29+
type: Boolean,
30+
default: false,
31+
},
32+
verificationToken: {
33+
type: String,
34+
required: [true, 'Verify token is required'],
35+
},
2836
});
2937

3038
const joiSignupSchema = Joi.object({
@@ -45,6 +53,11 @@ const joiLoginSchema = Joi.object({
4553
const joiSubscriptionSchema = Joi.object({
4654
subscription: Joi.string().valueOf('starter', 'pro', 'business').required(),
4755
});
56+
const joiEmailSchema = Joi.object({
57+
email: Joi.string()
58+
.pattern(/[a-z0-9]+@[a-z]+\.[a-z]{2,3}/)
59+
.required(),
60+
});
4861

4962
const User = model('user', userSchema);
5063

@@ -53,4 +66,5 @@ module.exports = {
5366
joiSignupSchema,
5467
joiLoginSchema,
5568
joiSubscriptionSchema,
69+
joiEmailSchema,
5670
};

routes/api/users.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,17 @@ const {
66
joiSignupSchema,
77
joiLoginSchema,
88
joiSubscriptionSchema,
9+
joiEmailSchema,
910
} = require('../../models/user');
1011

1112
router.post('/signup', validation(joiSignupSchema), ctrlWrapper(ctrl.signup));
1213
router.post('/login', validation(joiLoginSchema), ctrlWrapper(ctrl.login));
14+
router.get('/verify/:verificationToken', ctrlWrapper(ctrl.verifyEmail));
15+
router.post(
16+
'/verify',
17+
validation(joiEmailSchema),
18+
ctrlWrapper(ctrl.resendVerifyEmail),
19+
);
1320
router.post('/logout', auth, ctrlWrapper(ctrl.logout));
1421
router.get('/current', auth, ctrlWrapper(ctrl.getCurrent));
1522
router.patch(

utils/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
const getErrorMessage = require('./getErrorMessage');
2+
const sendEmail = require('./sendEmail');
23

34
module.exports = {
45
getErrorMessage,
6+
sendEmail,
57
};

utils/sendEmail.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const sgMail = require('@sendgrid/mail');
2+
require('dotenv').config();
3+
4+
const { SENDGRID_API_KEY } = process.env;
5+
6+
sgMail.setApiKey(SENDGRID_API_KEY);
7+
8+
const sendEmail = async (data) => {
9+
// eslint-disable-next-line no-useless-catch
10+
try {
11+
const email = { ...data, from: 'diachenkoelena2@gmail.com' };
12+
await sgMail.send(email);
13+
return true;
14+
} catch (error) {
15+
throw error;
16+
}
17+
};
18+
19+
module.exports = sendEmail;

0 commit comments

Comments
 (0)