From 130b3a8d6a6b9530dc72a035b9f4459a318dd2de Mon Sep 17 00:00:00 2001 From: souravtecken Date: Sat, 20 Jul 2019 21:44:39 +0530 Subject: [PATCH 1/2] Added nodemailer email script. 1. mainMail.js with methods for general email, and password reset email. 2. mailCredentialsSample.s - authentication sample Added email templates. 1. Reused generic send email method in the password reset method. 2. Create a email templates folder with the forgot password template. 3. Password reset method now sends the template within the email. --- server/routes/api/accountManagement.js | 35 +++++++----- .../{ => emailTemplates}/forgotPassword.txt | 0 server/sendEmail/mailCredentialsSample.js | 6 ++ server/sendEmail/mainMail.js | 55 +++++++++++++++++++ 4 files changed, 83 insertions(+), 13 deletions(-) rename server/sendEmail/{ => emailTemplates}/forgotPassword.txt (100%) create mode 100644 server/sendEmail/mailCredentialsSample.js create mode 100644 server/sendEmail/mainMail.js diff --git a/server/routes/api/accountManagement.js b/server/routes/api/accountManagement.js index f20fc8f..8a61375 100644 --- a/server/routes/api/accountManagement.js +++ b/server/routes/api/accountManagement.js @@ -3,10 +3,10 @@ const UserSession = require('../../models/UserSession'); const jwt = require('jsonwebtoken'); var verifyUser = require('../../middleware/Token').verifyUser; const fs = require('fs'); -var nodemailer = require('nodemailer'); var path = require('path'); var privateKey = fs.readFileSync('server/sslcert/server.key', 'utf8'); //privatekey for jwt const config = require('../../../config/config'); +const mail=require("../../sendEmail/mainMail"); // TODO: Limit number of queries to these endpoints // TODO: Async functionality @@ -593,18 +593,27 @@ module.exports = (app) => { } console.log("JWT generated for forgot password."); var link = config.host_url + 'reset/' + token + '/' + user._id.toString(); - var writeData = user.basicInfo.email + "," + user.name.firstName + "," + link + "\n"; - fs.appendFile("./server/sendEmail/emails.csv", writeData, function (err) { - if (err) { - return console.log(err); - } - console.log("Email scheduled"); - }); - return res.status(200).send({ - success: true, - message: 'Email sent' - }); - + // var writeData = user.basicInfo.email + "," + user.name.firstName + "," + link + "\n"; + // fs.appendFile("./server/sendEmail/emails.csv", writeData, function (err) { + // if (err) { + // return console.log(err); + // } + // console.log("Email scheduled"); + // }); + mail.sendPasswordResetMail(user.basicInfo.email, user.name.firstName, link) + .then( () => { + return res.status(200).send({ + success: true, + message: 'Email sent' + }); + }) + .catch( (err) => { + return res.status(500).send({ + success: false, + message: err.message + }) + }) + }); }); }) diff --git a/server/sendEmail/forgotPassword.txt b/server/sendEmail/emailTemplates/forgotPassword.txt similarity index 100% rename from server/sendEmail/forgotPassword.txt rename to server/sendEmail/emailTemplates/forgotPassword.txt diff --git a/server/sendEmail/mailCredentialsSample.js b/server/sendEmail/mailCredentialsSample.js new file mode 100644 index 0000000..463853e --- /dev/null +++ b/server/sendEmail/mailCredentialsSample.js @@ -0,0 +1,6 @@ +auth = { + user: '', + pass: '' +} + +module.exports=auth; diff --git a/server/sendEmail/mainMail.js b/server/sendEmail/mainMail.js new file mode 100644 index 0000000..3eed51a --- /dev/null +++ b/server/sendEmail/mainMail.js @@ -0,0 +1,55 @@ +const nodemailer = require("nodemailer"); +const auth = require("./mailCredentialsSample"); +const fs = require("fs"); + +const transporter = nodemailer.createTransport({ + service: 'gmail', + auth +}); + + +const sendMail = (emailId, subject, text, html = null) => { + // If no template passed, only text shall be used by nodemailer. + const mailOptions = { + from: auth.user, + to: emailId, + subject, + text, + html + }; + return new Promise((resolve, reject) => { + transporter.sendMail(mailOptions, function (error, info) { + if (error) { + console.log(error); + reject({success:false, message:error}); + } else { + console.log('Email sent: ' + info.response); + resolve(); + } + }); + }) +} + +const sendPasswordResetMail = (userEmail, username, resetLink) => { + const subject = '[The Alcoding Club] Password Reset'; + const text = `Hello ${username}, please reset password here: ${resetLink}`; + let mailTemplate = fs.readFileSync("server/sendEmail/emailTemplates/forgotPassword.txt","utf8"); + mailTemplate = mailTemplate.replace("{{username}}", username); + mailTemplate = mailTemplate.replace("{{link}}", resetLink); + + return new Promise((resolve, reject) => { + sendMail(userEmail, subject, text, mailTemplate) + .then(() =>{ + resolve(); + }) + .catch((err) => { + reject(err); + }) + }) +} + +module.exports = { + sendMail, + sendPasswordResetMail +} + From 36e25c3c0bb7c53cdd95cff9c0b510bb24a06a7c Mon Sep 17 00:00:00 2001 From: souravtecken Date: Tue, 30 Jul 2019 20:57:34 +0530 Subject: [PATCH 2/2] Added signup component. 1. Signup option added in navbar dropdown. 2. Component, on submit, provides object with field data in signupData. --- client/app/components/Layout/Navbar.js | 4 ++ client/app/components/Signup/Signup.js | 66 ++++++++++++++++++++++++++ client/app/index.js | 5 +- 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 client/app/components/Signup/Signup.js diff --git a/client/app/components/Layout/Navbar.js b/client/app/components/Layout/Navbar.js index 6687389..8e1880a 100644 --- a/client/app/components/Layout/Navbar.js +++ b/client/app/components/Layout/Navbar.js @@ -160,6 +160,10 @@ class NavbarClass extends Component { Forgot Password + + + Signup + diff --git a/client/app/components/Signup/Signup.js b/client/app/components/Signup/Signup.js new file mode 100644 index 0000000..f4ba130 --- /dev/null +++ b/client/app/components/Signup/Signup.js @@ -0,0 +1,66 @@ +import React, { Component } from 'react' +import axios from "axios"; +import { Link, Redirect } from 'react-router-dom'; +import ReactLoading from '../common/Loading'; +import { ToastContainer, ToastStore } from 'react-toasts'; +import { Button, Label } from 'reactstrap'; + +export default class ForgotPassword extends Component { + constructor(props) { + super(props); + this.state = { + isLoading: false, + isLoading: false + }; + this.onSignup = this.onSignup.bind(this); + } + + renderRedirect() { + if (this.state.redirect) { + return + } + } + + onSignup(event){ + event.preventDefault(); + const formElements = event.target.elements; + const firstName = formElements["firstName"].value; + const emailId = formElements["emailid"].value; + const password = formElements["password"].value; + const confirmPassword = formElements["confirmPassword"].value; + const signupData = { + firstName, + emailId, + password, + confirmPassword + } + //console.log(signupData); + } + + render() { + return ( +
+ {this.renderRedirect()} +

Signup

+
+
+ + +

+ + +

+ + +

+ + +

+ +
+
+ +
+ ) + } +} diff --git a/client/app/index.js b/client/app/index.js index e7e1fb5..edfc6f0 100644 --- a/client/app/index.js +++ b/client/app/index.js @@ -30,7 +30,8 @@ import downloadFile from './components/Pages/Assignments/downloadFile'; import zipFiles from './components/Pages/Assignments/zipFiles'; import updateHandle from './components/Pages/Profile/UpdateHandle'; import contribute from './components/Pages/Contribute'; -import ReactLoading from './components/common/Loading' +import ReactLoading from './components/common/Loading'; +import Signup from './components/Signup/Signup' // import 'bootstrap/dist/css/bootstrap.min.css'; @@ -77,6 +78,8 @@ render(( + +