diff --git a/src/controllers/AccountController.js b/src/controllers/AccountController.js index 5209da0..51c91dc 100644 --- a/src/controllers/AccountController.js +++ b/src/controllers/AccountController.js @@ -1,10 +1,12 @@ import AccountModel from '../models/AccountModel'; import AccountValidator from '../validators/AccountValidator'; +import VerificationTokenController from './VerificationTokenController'; import db from '../services/dbService'; import models from '../models/models'; import bcrypt from 'bcryptjs'; -import mailer from '../services/mailer'; import jwt from 'jsonwebtoken'; +import mailer from '../services/mailer'; +import CategoryModel from '../models/CategoryModel'; const AccountController = { async validateAccount(req, res) { @@ -15,12 +17,22 @@ const AccountController = { const { rows } = await db.query(query, [req.query.token]); if (rows && rows.length > 0) { - // update account - // delete verification token - console.log(rows[0]); - res.status(200).send('validate endpoint hittered'); + try { + const updatedAccount = await models.Account.update( + {isVerified: true}, + {where: {id: rows[0].id}} + ); + + models.VerificationToken.destroy({ + where: {account_id: rows[0].id} + }); + return res.status(200).send({message: "email successfully verified"}); + } catch(error) { + console.log('error updating account... '+error); + return res.status(500).send({message: "internal server error"}); + } } else { - return res.status(400).send('Invalid token'); + return res.status(400).send({message: "Unable to resolve email verification."}); } }, @@ -45,13 +57,19 @@ const AccountController = { } }); - const verificationToken = await bcrypt.hash(account.email, 10); - const verificationTokenModel = await models.VerificationToken.create({ - token: verificationToken, - account_id: account.id, - }); + const verificationTokenModel = await VerificationTokenController.create(req, res, account); + mailer.sendVerificationMessage(account.email, verificationTokenModel.token) + .catch(error => { + console.log(`error sending email: ${error}`); + return res.status(500).send({message: "Error sending email."}); + }); - mailer.sendVerificationMessage(account.email, verificationTokenModel.token); + CategoryModel.create({ + body: { + name: "Groceries", + }, + accountId: account.id + }); const tokenExpiration = 24*60*60; const token = jwt.sign({id: account.id}, process.env.SECRET_KEY, {expiresIn: tokenExpiration}); @@ -88,7 +106,7 @@ const AccountController = { try { const result = await AccountModel.delete(req); if(result.rowCount === 0) { - return res.status(404).send({'message': 'category not found'}); + return res.status(404).send({'message': 'account not found'}); } return res.status(204).send({ 'message': 'deleted' }); } catch(error) { diff --git a/src/controllers/VerificationTokenController.js b/src/controllers/VerificationTokenController.js new file mode 100644 index 0000000..a53ea87 --- /dev/null +++ b/src/controllers/VerificationTokenController.js @@ -0,0 +1,44 @@ +import models from '../models/models'; +import mailer from '../services/mailer'; +import bcrypt from 'bcryptjs'; + +const VerificationTokenController = { + async resendEmailVerification(req, res) { + const account = await models.Account.findOne({ + where: {email: req.query.email}, + include: [{ + model: models.VerificationToken, + as: "VerificationToken", + }], + }); + + if (account && account.VerificationToken) { + mailer.sendVerificationMessage(account.email, account.VerificationToken.token) + .then(() => { + return res.status(200).send({message: "Verification email sent."}); + }); + } else if (account) { + const newVerificationToken = await this.create(req, res, account); + mailer.sendVerificationMessage(account.email, newVerificationToken.token) + .then(() => { + return res.status(200).send({message: "Verification email sent."}); + }); + } else { + return res.status(404).send({message: "Account not found for given email."}); + } + }, + + async create(req, res, account) { + const newToken = await bcrypt.hash(account.email, 10); + return models.VerificationToken.create({ + token: newToken, + account_id: account.id + }) + .catch(error => { + console.log(`error creating verification token: ${error}`); + return res.status(500).send({message: "Internal Server error."}); + }); + } +} + +export default VerificationTokenController; \ No newline at end of file diff --git a/src/db/db.sql b/src/db/db.sql index 5a8e688..0fdbc0b 100644 --- a/src/db/db.sql +++ b/src/db/db.sql @@ -4,13 +4,13 @@ CREATE TABLE IF NOT EXISTS users ( email text UNIQUE, password text, created_date timestamptz NOT NULL DEFAULT NOW(), - modified_date timestamptz NOT NULL DEFAULT NOW() + updated_at timestamptz NOT NULL DEFAULT NOW() ); CREATE OR REPLACE FUNCTION trigger_set_timestamp() RETURNS TRIGGER AS $$ BEGIN - NEW.modified_date = NOW(); + NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; diff --git a/src/routes/index.js b/src/routes/index.js index bb9239b..075272f 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -5,6 +5,7 @@ import Report from '../controllers/Report'; import AccountController from '../controllers/AccountController'; import authMiddleware from '../services/authMiddleware'; import { apiRegisterLimiter, apiLoginLimiter } from '../services/rateLimitMiddleware'; +import VerificationTokenController from '../controllers/VerificationTokenController'; const router = express.Router(); @@ -14,9 +15,11 @@ router.get('/', (req, res) => { router.post('/api/v1/register', apiRegisterLimiter, AccountController.create); router.post('/api/v1/login', apiLoginLimiter, AccountController.login); -router.delete('/api/v1/accounts/:id', authMiddleware.validateToken, AccountController.delete); router.get('/api/v1/verification', AccountController.validateAccount); +router.delete('/api/v1/accounts/:id', authMiddleware.validateToken, AccountController.delete); +router.get('/api/v1/registration/email', apiRegisterLimiter, VerificationTokenController.resendEmailVerification); + router.post('/api/v1/expenses', authMiddleware.validateToken, ExpenseController.create); router.get('/api/v1/expenses', authMiddleware.validateToken, ExpenseController.getAll); router.get('/api/v1/expenses/:id', authMiddleware.validateToken, ExpenseController.getOne); @@ -32,6 +35,4 @@ router.delete('/api/v1/categories/:id', authMiddleware.validateToken, CategoryCo router.get('/api/v1/reports/recent', authMiddleware.validateToken, ExpenseController.getRecentExpenses); router.post('/api/v1/reports/monthly', authMiddleware.validateToken, Report.getMonthly); -// router.post('/api/v1/mail', AccountController.mail); - export default router; \ No newline at end of file