basicaly i am writing code setup here only for me. Because i am facing lots of dificulty in development and geting a good job
This setup i usfe in code
import UserModel from "../model/User.js";
import bcrypt from 'bcrypt';
import dotenv from 'dotenv';
import sendEmailVerificationByOTP from "../utils/sendEmailVerificationByOTP.js";
import EmailVerificationModel from "../model/EmailVerificaion.js";
import transporter from "../config/emailConfig.js";
import jwt from "jsonwebtoken"
dotenv.config();
// signup user
const signup = async (req, res) => {
try {
const { name, email, password } = req.body;
// all field is require
if (!name || !email || !password ){
return res.status(400).json({ status: "failed", message: "All fields are required" })
}
// user already exist
const existingUser = await UserModel.findOne({ email });
if (existingUser) {
return res.status(400).json({ status: "Fail", message: "User already exist" })
}
// salt
const salt = await bcrypt.genSalt(Number(process.env.SALT));
// hasspassword
const hasspassword = await bcrypt.hash(password, salt)
const newUser = await new UserModel({
name,
email,
password: hasspassword
}).save();
//CALL send otp to user
sendEmailVerificationByOTP(req, newUser)
res.status(200).json({
status: "sucess",
message: "your accoount is sucessfuly created",
user: { id: newUser._id, email: newUser.email }
})
} catch (error) {
console.error(error)
return res.status(400).json({ status: "failed", message: "Unable to Register, please try again later" })
}
}
// Verify email
const verifyEmail = async (req, res) => {
try {
const { email, otp } = req.body;
// Check if all required fields are provided
if (!email || !otp) {
return res.status(400).json({ status: "failed", message: "All fields are required" });
}
// Check if the email exists
const userEmail = await UserModel.findOne({ email });
if (!userEmail) {
return res.status(400).json({ status: "failed", message: "Email does not exist" });
}
// Check if the email is already verified
if (userEmail.is_verified) {
return res.status(400).json({ status: "failed", message: "This email is already verified" });
}
// Check if there is a matching email verification OTP
const emailVerification = await EmailVerificationModel.findOne({ userId: userEmail._id, otp });
if (!emailVerification) {
// Resend OTP if not verified
await sendEmailVerificationByOTP(req, userEmail);
return res.status(400).json({ status: "failed", message: "Invalid OTP. A new OTP has been sent to your email." });
}
// Check if OTP is expired
const currentTime = new Date();
const expirationTime = new Date(emailVerification.createdAt.getTime() + 15 * 60 * 1000); // 15 minutes
if (currentTime > expirationTime) {
// OTP expired, send new OTP
await sendEmailVerificationByOTP(req, userEmail);
return res.status(400).json({ status: "failed", message: "OTP expired. A new OTP has been sent to your email." });
}
// Mark the user's email as verified
userEmail.is_verified = true;
await userEmail.save();
// Remove all OTP entries for the user
await EmailVerificationModel.deleteMany({ userId: userEmail._id });
return res.status(200).json({ status: "success", message: "Email verified successfully" });
} catch (error) {
console.error(error);
return res.status(500).json({ status: "failed", message: "An error occurred while verifying the email." });
}
};
// User Login
const Login = async (req, res) => {
try {
const { email, password } = req.body
// All field is require
if (!email || !password) {
return res.status(400).json({ status: "fail to login", message: "All field is required" })
}
// Email is exist or not
const user = await UserModel.findOne({ email })
if (!user) {
return res.status(400).json({ status: "Fail to login", message: "Email or password is not exist" })
}
// is user is verified or not
if (!user.is_verified) {
return res.status(400).json({ status: "fail to login", message: "Account is not active" })
}
// Check the user password is match or not
const isMatch = await bcrypt.compare(password, user.password)
//if password is not match
if (!isMatch) {
return res.status(400).json({ status: "Fail to login", message: "password is not same" })
}
// Generate single long-lived token (30 days)
console.log("JWT Secret Key:", process.env.JWT_SECRET_KEY);
const tokenExp = Math.floor(Date.now() / 1000) + (30 * 24 * 60 * 60);
const token = jwt.sign(
{
id: user._id,
roles: user.role[0],
exp: tokenExp
},
process.env.JWT_SECRET_KEY
);
// Send response
res.status(200).json({
user: { id: user._id, email: user.email, name: user.name, roles: user.role[0] },
status: "success",
message: "Login successful",
token,
token_exp: tokenExp,
is_auth: true
});
} catch (error) {
console.log(error)
res.status(400).json({ status: "Fail to login", message: "" })
}
}
// profile
const userProfile = async (req, res) => {
res.send({ "user": req.user })
}
// Change Password
const changePassword = async (req, res) => {
try {
const { password, confirm_password } = req.body
if (!password || !confirm_password) {
res.status(400).json({ statu: "Fail", message: "all filed is require" })
}
if (password !== confirm_password) {
res.statu(400).json({ status: "Fail", message: "Password is not match" })
}
const salt = await bcrypt.genSalt(Number(process.env.SALT))
const hashPassword = await bcrypt.hash(password, salt)
await UserModel.findByIdAndUpdate(req.user._id, { $set: { password: hashPassword } })
// Send success response
res.status(200).json({ status: "success", message: "Password changed successfully" });
} catch (error) {
console.error(error);
res.status(500).json({ status: "failed", message: "Unable to change password, please try again later" });
}
}
// Send Password Reset Link via Email
const sendUserPasswordResetEmail = async (req, res) => {
try {
// Extract email from req.body
const { email } = req.body;
// Check if email is provided
if (!email) {
return res.status(400).json({ status: "failed", message: "Email field is required" });
}
// Find user by email
const user = await UserModel.findOne({ email: email });
if (!user) {
return res.status(404).json({ status: "failed", message: "Email doesn't exist" });
}
// Create a secret and token for password reset
const secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
const token = jwt.sign({ userId: user._id }, secret, { expiresIn: '15m' });
// Construct the reset password link
const resetLink = `${process.env.FRONTEND_HOST}/account/reset-password-confirm/${user._id}/${token}`;
console.log(resetLink)
// Send password reset email
await transporter.sendMail({
from: process.env.EMAIL_FROM,
to: user.email,
subject: "Reset your password",
html: `<p>Hello ${user.name},</p><p>Please <a href="${resetLink}">click here</a> to reset your password.</p>`,
});
// Respond with success
res.status(200).json({ status: "success", message: "Password reset email sent. Please check your email." });
} catch (error) {
console.error(error);
res.status(500).json({ status: "failed", message: "Unable to send password reset email. Please try again later." });
}
};
// reset password
const resetPassword = async (req, res) => {
try {
const { password, confirm_password } = req.body;
const { id, token } = req.params;
// Find user by ID
const user = await UserModel.findById(id);
if (!user) {
return res.status(404).json({ status: "failed", message: "User not found" });
}
// Validate token
const new_secret = user._id + process.env.JWT_ACCESS_TOKEN_SECRET_KEY;
jwt.verify(token, new_secret);
// Check if password and password_confirmation are provided
if (!password || !confirm_password) {
return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password are required" });
}
// Check if password and password_confirmation match
if (password !== confirm_password) {
return res.status(400).json({ status: "failed", message: "New Password and Confirm New Password don't match" });
}
// Generate salt and hash new password
const salt = await bcrypt.genSalt(10);
const newHashPassword = await bcrypt.hash(password, salt);
// Update user's password
await UserModel.findByIdAndUpdate(user._id, { $set: { password: newHashPassword } });
// Send success response
res.status(200).json({ status: "success", message: "Password reset successfully" });
} catch (error) {
console.log(error);
if (error.name === "TokenExpiredError") {
return res.status(400).json({ status: "failed", message: "Token expired. Please request a new password reset link." });
}
return res.status(500).json({ status: "failed", message: "Unable to reset password. Please try again later." });
}
}
// Logout
const Logout = async (req, res) => {
try {
res.clearCookie('accessToken');
res.clearCookie('refreshToken');
res.clearCookie('is_auth');
res.status(200).json({ status: "success", message: "Logout successfully done" });
} catch (error) {
console.error(error);
res.status(500).json({ status: "failed", message: "Unable to logout, please try again later" });
}
};
export { signup, verifyEmail, Login, userProfile, Logout, changePassword, resetPassword, sendUserPasswordResetEmail };
Author Of article : Harendra Read full article