Skip to content

Commit

Permalink
Merge pull request #181 from agiledev-students-fall2023/charlotte
Browse files Browse the repository at this point in the history
SendRecoveryEmail done
  • Loading branch information
lunnnnnn authored Dec 6, 2023
2 parents 2c1e591 + ab16176 commit 3523854
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 122 deletions.
2 changes: 2 additions & 0 deletions back-end/.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ SESSION_SECRET = 'myKey123!'
JWT_SECRET = 'myKey123!'
CLIENT_URL = "http://localhost:5173"
MONGODB_URI = "mongodb+srv://yz5835:[email protected]/bakerdb"
EMAIL_USER='[email protected]'
EMAIL_PASS='Goodoldmap123'
2 changes: 1 addition & 1 deletion back-end/src/app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const passwordValidationRules = [
// Account routes
app.patch("/changeusername", usernameValidationRules, changeusernameRouter); //Finished
app.patch("/resetemail", emailValidationRules, resetemailRouter); //Finished
app.post("/forgetpassword", forgetpasswordRouter);
app.post("/forget", forgetpasswordRouter);
app.patch("/resetpassword", passwordValidationRules, resetpasswordRouter); //Finished
app.delete("/delaccount", delaccountRouter); //Finished

Expand Down
33 changes: 14 additions & 19 deletions back-end/src/routes/forgetpasswordRouter.mjs
Original file line number Diff line number Diff line change
@@ -1,44 +1,39 @@
//to-do add recovery page, now we only send token to client's email
import User from '../models/User.mjs';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import sendRecoveryEmail from './sendEmail.mjs'; // Your email sending function
import sendRecoveryEmail from './sendEmail.mjs';

const forgetpasswordRouter = async (req, res) => {
const { email } = req.body;

console.log("Received forgot password request for email:", email);

try {
const user = await User.findOne({ email: email.toLowerCase() });
console.log("User found:", user);

if (!user) {
console.log("User not found for email:", email);
return res.status(404).json({ message: "User not found." });
}

// Generate a token for password reset
const resetToken = jwt.sign({ id: user.id, email: user.email }, process.env.JWT_SECRET, { expiresIn: "1h" });

// Store the token in the database (you'll need to implement this logic)
// E.g., user.resetToken = resetToken; await user.save();

// Send the token to the user's email
// Store the reset token in the user's record in the database
user.resetToken = resetToken;
await user.save();

await sendRecoveryEmail(email, resetToken);
console.log("Password reset email sent to:", email);

return res.status(200).json({ message: "Password reset email sent." });
} catch (error) {
console.error(error);
console.error("Error in /forgotpassword route:", error);
return res.status(500).json({ message: "Internal server error." });
}


};

export default forgetpasswordRouter;

// const forgetpasswordRouter = async (req, res) => {
// // req.body: email, userID
// // TODO: compare email to see if that match,
// // if match, send recovery data to email
// try {
// return res.sendStatus(200)
// } catch (error) {
// }
// }

// export default forgetpasswordRouter
9 changes: 4 additions & 5 deletions back-end/src/routes/sendEmail.mjs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import nodemailer from 'nodemailer';

const sendRecoveryEmail = async (email, token) => {
// Create a transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: 'smtp.example.com',
host: 'smtp.gmail.com', // Gmail SMTP server
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: 'your-email@example.com', // Your email
pass: 'your-password', // Your email password or app-specific password
user: 'goodoldmap@gmail.com',
pass: 'ebro wnec snzf fcqt',
},
});

let mailOptions = {
from: '"Your App Name" <your-email@example.com>', // Sender address
from: '"The GoodOldMap" <goodoldmap@gmail.com>', // Your verified sender email address
to: email, // Receiver email
subject: 'Password Recovery', // Subject line
text: `Please use the following token to recover your password in 1h: ${token}`, // Plain text body
Expand Down
32 changes: 32 additions & 0 deletions back-end/tests/routes/testsendemail.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import nodemailer from 'nodemailer';
import dotenv from 'dotenv';

dotenv.config();

const testEmailSending = async () => {
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'ebro wnec snzf fcqt', // Use environment variables to keep this secure
},
});

let mailOptions = {
from: `"The GoodOldMap" <${process.env.EMAIL_USER}>`,
to: '[email protected]', // Replace with your test recipient email
subject: 'Test Email',
text: 'This is a test email from my Node.js application.',
};

try {
let info = await transporter.sendMail(mailOptions);
console.log('Message sent: %s', info.messageId);
} catch (error) {
console.error('Error sending email:', error);
}
};

testEmailSending();
23 changes: 0 additions & 23 deletions front-end/src/pages/Account/Account.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,6 @@ const AccountEdit = (props) => {
}
}

// route /forgetpassword
// TODO: user id
const sentForgetPwEmail = async (evt) => {
try {
const requestData = getFormData()
requestData["userID"] = "1234"
const response = await axiosProvider.post(
"/forgetpassword",
requestData,
)
closePopup()
} catch (error) {
const errorMessage = error?.requestMessage || error.response?.data?.message || 'Change failed, please try again.';
setMessage(errorMessage);
}
}

// Finished: route /resetpassword
const confirmResetPassword = async (evt) => {
Expand Down Expand Up @@ -207,13 +191,6 @@ const AccountEdit = (props) => {
buttons: [{value:"Discard", handleClick: closePopup},
{value:"Confirm", handleClick: confirmResetEmail}],
},
"forgotPassword": {
link: "Forget Password",
title: "Forget Password",
inputs: [{id:"email", name:"email", type:"text", placeholder:"email"}],
buttons: [{value:"Discard", handleClick: closePopup},
{value: "Send Email", handleClick: sentForgetPwEmail}],
},
"changePassword": {
link: "Change Password",
title: "Change Password",
Expand Down
27 changes: 13 additions & 14 deletions front-end/src/pages/Account/popupContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,33 @@ import { FormInputsPopup } from "../../components/form/formInput";
import { FormBtns } from "../../components/form/formBtn";
import { forwardRef } from "react";


const PopupContent = forwardRef((props, ref) => {
// props: title(str), inputs(array of object), buttons:(array of object)
// optional: message
// Function to stop propagation for clicks inside the popup content
const handleContentClick = (e) => {
e.stopPropagation(); // Prevents clicks within the content from closing the popup
};

return (
// dark background
// Overlay: Closes the popup when clicked
<div
className="popupBackground fixed top-0 left-0 z-[1700] w-full h-full bg-black bg-opacity-50 flex items-center justify-center"
className="popupBackground fixed top-0 left-0 z-[1700] w-full h-full bg-black bg-opacity-50 flex items-center justify-center"
onClick={props.handleClick}>
{/* white popup container: */}
<div className="bg-white rounded-lg shadow-xl w-[80%] max-w-[30rem]">

{/* Content Area: Does not propagate clicks to the overlay */}
<div className="bg-white rounded-lg shadow-xl w-[80%] max-w-[30rem]" onClick={handleContentClick}>
<div className="p-8 text-center">
{/* content area */}
<h3 className="text-lg font-bold mb-4 text-center">{props?.title}</h3>
<p>{props?.message}</p>
<div className="space-y-4" >
<div className="space-y-4">
<FormInputsPopup inputs={props?.inputs}/>
<div className="flex flex-row gap-2 justify-end"> {/* Adjust button positioning as needed */}
<div className="flex flex-row gap-2 justify-end">
<FormBtns buttons={props?.buttons}/>
</div>
</div>
</div>

</div>
</div>
);
});


export default PopupContent
export default PopupContent;
Loading

0 comments on commit 3523854

Please sign in to comment.