Skip to content

Commit

Permalink
Merge branch 'main' into loaders
Browse files Browse the repository at this point in the history
  • Loading branch information
AyushSharma72 authored Nov 8, 2024
2 parents 2128ee2 + ed271d3 commit 64ed8a7
Show file tree
Hide file tree
Showing 11 changed files with 465 additions and 221 deletions.
160 changes: 154 additions & 6 deletions backend/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import User from '../models/User.js';
import crypto from 'crypto'; // For generating OTP
import nodemailer from 'nodemailer';
import { hashPassword, comparePassword, generateToken, verifyToken, addCookie, getCookies, removeCookie } from '../utils/authFunctions.js';


const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});

export const registerUser = async (req, res) => {
try {
const { name, email, phoneNumber, password, isGoogle } = req.body;
Expand All @@ -19,45 +30,111 @@ export const registerUser = async (req, res) => {
return res.status(400).json({ error: 'User already exists' });
}

const otp = crypto.randomInt(100000, 999999).toString(); // Generate OTP (6 digits)

if (isGoogle == true) {
const newUser = new User({
name,
email,
phoneNumber: phoneNumber ? phoneNumber : '',
password: ''
password: '',
otp: otp,
otpExpiry: Date.now() + 3600000, // OTP expires in 1 hour
});

await newUser.save();

const token = await generateToken(newUser._id);
await sendOtpEmail(email, otp); // Send OTP to the user's email

const token = await generateToken(newUser._id);
addCookie(res, 'token', token);

return res.status(201).json({ message: 'User registered successfully', userId: newUser._id , token: token });
return res.status(201).json({
message: 'User registered successfully. Please check your email for the OTP to verify your email.',
userId: newUser._id,
token: token,
});
} else {
const hashedPassword = await hashPassword(password);

const newUser = new User({
name,
email,
phoneNumber: phoneNumber ? phoneNumber : '',
password: hashedPassword
password: hashedPassword,
otp: otp,
otpExpiry: Date.now() + 3600000, // OTP expires in 1 hour
});

await newUser.save();

const token = await generateToken(newUser._id);
await sendOtpEmail(email, otp); // Send OTP to the user's email

const token = await generateToken(newUser._id);
addCookie(res, 'token', token);

res.status(201).json({ message: 'User registered successfully', userId: newUser._id, token: token });
res.status(201).json({
message: 'User registered successfully. Please check your email for the OTP to verify your email.',
userId: newUser._id,
token: token,
});
}
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};

const sendOtpEmail = async (userEmail, otp) => {
try {

const mailOptions = {
from: process.env.EMAIL_USER,
to: userEmail,
subject: 'Email Verification - Station Sarthi',
text: `Your OTP for email verification is: ${otp}`,
};

await transporter.sendMail(mailOptions);
} catch (error) {
console.error('Error sending email:', error);
throw new Error('Failed to send OTP');
}
};

export const verifyOtp = async (req, res) => {
try {
const { email, otp } = req.body;

const user = await User.findOne({ email });
if (!user) {
return res.status(404).json({ error: 'User not found' });
}

// Check if OTP has expired
if (Date.now() > user.otpExpiry) {
return res.status(400).json({ error: 'OTP has expired' });
}

// Check if OTP is correct
if (user.otp !== otp) {
return res.status(400).json({ error: 'Invalid OTP' });
}

// OTP is correct, mark user as verified
user.isVerified = true;
user.otp = null; // Clear OTP after verification
user.otpExpiry = null; // Clear OTP expiry after verification
await user.save();

res.status(200).json({ message: 'Email verified successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};


export const loginUser = async (req, res) => {
try {
const { email, password } = req.body;
Expand Down Expand Up @@ -90,6 +167,77 @@ export const loginUser = async (req, res) => {
}
};

async function sendResetOtpEmail(email, otp) {
await transporter.sendMail({
from: 'Station Sarthi <noreply@gmail.com>',
to: email,
subject: 'Password Reset OTP - Station Sarti',
text: `Your OTP for password reset is ${otp}. It will expire in 1 hour.`
});
}

// Route 1: Request Password Reset (Sends OTP)
export const requestPasswordReset = async (req, res) => {
try {
const { email } = req.body;

if (!email) {
return res.status(400).json({ error: 'Email is required' });
}

const user = await User.findOne({ email });

if (!user) {
return res.status(400).json({ error: 'User with this email does not exist' });
}

const otp = crypto.randomInt(100000, 999999).toString(); // Generate OTP
user.otp = otp;
user.otpExpiry = Date.now() + 3600000; // OTP expires in 1 hour
await user.save();

await sendResetOtpEmail(email, otp);

res.status(200).json({ message: 'OTP sent to email for password reset' });
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};

// Route 2: Verify OTP and Reset Password
export const resetPassword = async (req, res) => {
try {
const { email, otp, newPassword } = req.body;

if (!email || !otp || !newPassword) {
return res.status(400).json({ error: 'Email, OTP, and new password are required' });
}

const user = await User.findOne({ email });

if (!user) {
return res.status(400).json({ error: 'User does not exist' });
}

// Check if OTP is valid
if (user.otp !== otp || user.otpExpiry < Date.now()) {
return res.status(400).json({ error: 'Invalid or expired OTP' });
}

// Hash the new password and reset OTP fields
user.password = await hashPassword(newPassword);
user.otp = null;
user.otpExpiry = null;
await user.save();

res.status(200).json({ message: 'Password has been reset successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message || 'Internal Server Error' });
}
};

export const logoutUser = async (req, res) => {
try {
removeCookie(res, 'token');
Expand Down
49 changes: 33 additions & 16 deletions backend/controllers/contactusController.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
import nodemailer from "nodemailer";
import ContactUs from "../models/Contact.js";
import "dotenv/config";


// POST Controller: Handles contact form submission
export const createContactUs = async (req, res) => {
const { mail, subject, message } = req.body;

// Check if required fields are present and valid
if (!mail || !subject || !message) {
return res.status(400).json({
status: "error",
message: "All fields (email, subject, message) are required.",
});
}

// Validate email format using a simple regex
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(mail)) {
return res.status(400).json({
status: "error",
message: "Please provide a valid email address.",
});
}

try {
// Save the contact form data to the database
const newContactRequest = new ContactUs({
mail,
subject,
message,
});
await newContactRequest.save(); // Save the document to the MongoDB database

// Send email using Nodemailer
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 587,
secure: false,
service: 'Gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
tls: {
rejectUnauthorized: false, // Disable strict SSL verification
},
});

const mailOptions = {
Expand All @@ -27,23 +50,17 @@ export const createContactUs = async (req, res) => {
};

// Send mail with defined transport object
transporter.sendMail(mailOptions, (error, mailOptions) => {
if (error) {
console.error("Error occurred: " + error.message);
return;
}
});
await transporter.sendMail(mailOptions);

res.status(200).json({
status: "success",
message: "Your contact request has been successfully received.",
});
} catch (err) {
console.error(`Error at transport : ${err}`);
console.error(`Error during processing contact form: ${err.message}`);
res.status(500).json({
status: "error",
message:
"There was an error sending your message. Please try again later.",
message: "There was an error processing your message. Please try again later.",
});
}
};
29 changes: 29 additions & 0 deletions backend/models/Contact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import mongoose from 'mongoose';
const contactUsSchema = new mongoose.Schema(
{
mail: {
type: String,
required: true,
match: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, // Email format validation
},
subject: {
type: String,
required: true,
},
message: {
type: String,
required: true,
},
dateSubmitted: {
type: Date,
default: Date.now, // Automatically set the current date when the form is submitted
},
},
{ timestamps: true } // Automatically add createdAt and updatedAt fields
);

// Create a model based on the schema
const ContactUs = mongoose.model('Contact', contactUsSchema);


export default ContactUs
4 changes: 4 additions & 0 deletions backend/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ const userSchema = new Schema({
otpExpiry: {
type: Date, // The OTP expiry timestamp
required: false,
},
isVerified: {
type: Boolean,
default: false, // This field will be set to true once the email is verified
}
}, {
timestamps: true
Expand Down
11 changes: 11 additions & 0 deletions backend/routes/authRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
loginUser,
logoutUser,
verifyUser,
verifyOtp,
requestPasswordReset,
resetPassword,
} from "../controllers/authController.js";
import { createCloakroomBooking } from "../controllers/cloakroomController.js";
import { createWheelchairBooking } from "../controllers/WheelchairController.js";
Expand All @@ -24,9 +27,17 @@ const loginLimiter = rateLimit({
// Register route
router.post("/register", registerUser);

router.post("/verify-otp", verifyOtp);

// Login route with rate limiter
router.post("/login", loginLimiter, loginUser);

// Route to request OTP for password reset
router.post('/request-password-reset', requestPasswordReset);

// Route to reset password after OTP verification
router.post('/reset-password', resetPassword);

// Logout route
router.post("/logout", verifyJWT, logoutUser);

Expand Down
3 changes: 1 addition & 2 deletions backend/routes/contactUsRouter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import express from 'express';
const router = express.Router();
import { createContactUs } from "../controllers/contactusController.js";
import { createContactUs} from "../controllers/contactusController.js";

router.post("/contactus", createContactUs);

export default router;
Loading

0 comments on commit 64ed8a7

Please sign in to comment.