backend_adaptive_learning/controllers/auth/auth.js

1059 lines
31 KiB
JavaScript
Raw Normal View History

2024-09-13 13:03:35 +00:00
import response from "../../response.js";
2024-11-04 04:33:57 +00:00
import bcrypt from "bcryptjs";
2024-09-13 13:03:35 +00:00
import jwt from "jsonwebtoken";
import nodemailer from "nodemailer";
2024-11-20 01:11:01 +00:00
import moment from "moment-timezone";
2024-09-13 13:03:35 +00:00
import models from "../../models/index.js";
const transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS,
},
});
export const registerAdmin = async (req, res) => {
const { NAME_USERS, EMAIL, PASSWORD, CONFIRM_PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!NAME_USERS) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Name is required!", res);
}
if (!EMAIL) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Email is required!", res);
}
if (!PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Password is required!", res);
}
if (!CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Confirm Password is required!", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Passwords do not match!", res);
}
try {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
2024-09-13 13:03:35 +00:00
const newUser = await models.User.create({
NAME_USERS: NAME_USERS,
EMAIL: EMAIL,
2024-09-13 13:03:35 +00:00
PASSWORD: hashedPassword,
ROLE: "admin",
2024-11-20 01:11:01 +00:00
IS_VALIDATED: 1,
2024-09-13 13:03:35 +00:00
});
const adminResponse = {
ID: newUser.ID,
NAME_USERS: newUser.NAME_USERS,
EMAIL: newUser.EMAIL,
ROLE: newUser.ROLE,
2024-11-20 01:11:01 +00:00
IS_VALIDATED: newUser.IS_VALIDATED,
2024-09-13 13:03:35 +00:00
};
response(200, adminResponse, "Admin registration successful", res);
} catch (error) {
console.log(error);
if (error.name === "SequelizeUniqueConstraintError") {
return response(400, null, "Email already registered!", res);
}
response(500, null, "Internal Server Error", res);
}
};
export const registerTeacher = async (req, res) => {
const { NAME_USERS, EMAIL, NIP, PASSWORD, CONFIRM_PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!NAME_USERS) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Name is required!", res);
}
if (!EMAIL) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Email is required!", res);
}
if (!NIP) {
2024-09-13 13:03:35 +00:00
return response(400, null, "NIP is required for teachers!", res);
}
if (!PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Password is required!", res);
}
if (!CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Confirm Password is required!", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Passwords do not match!", res);
}
const transaction = await models.db.transaction();
try {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
2024-09-13 13:03:35 +00:00
const newUser = await models.User.create(
{
NAME_USERS: NAME_USERS,
EMAIL: EMAIL,
2024-09-13 13:03:35 +00:00
PASSWORD: hashedPassword,
ROLE: "teacher",
2024-11-07 02:18:27 +00:00
IS_VALIDATED: 0,
},
{ transaction }
);
await models.Teacher.create(
{
ID: newUser.ID,
NIP: NIP,
},
{ transaction }
);
await transaction.commit();
2024-11-20 01:11:01 +00:00
const now = moment().tz("Asia/Jakarta");
const midnight = now.clone().endOf("day");
const secondsUntilMidnight = midnight.diff(now, "seconds");
2024-11-07 02:18:27 +00:00
const token = jwt.sign(
{ userId: newUser.ID },
process.env.VERIFY_TOKEN_SECRET,
2024-11-20 01:11:01 +00:00
{ expiresIn: secondsUntilMidnight }
2024-11-07 02:18:27 +00:00
);
const validationLink = `${process.env.CLIENT_URL}/validate-email?token=${token}`;
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: EMAIL,
subject: "Email Verification",
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Verification</title>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Arial, sans-serif;
line-height: 1.6;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 20px auto;
padding: 0;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
background-color: #0090FF;
padding: 25px 20px;
text-align: center;
border-radius: 10px 10px 0 0;
}
.header h1 {
color: #ffffff;
margin: 0;
font-size: 32px;
letter-spacing: 2px;
font-weight: bold;
}
.content {
padding: 40px 30px;
background-color: #ffffff;
color: #333333;
}
.content h2 {
color: #0090FF;
margin-top: 0;
font-size: 24px;
margin-bottom: 20px;
}
.content p {
margin-bottom: 15px;
font-size: 16px;
line-height: 1.7;
}
.button {
display: inline-block;
padding: 12px 35px;
background-color: #0090FF;
color: #ffffff !important;
text-decoration: none;
border-radius: 5px;
margin: 25px 0;
font-size: 16px;
font-weight: bold;
text-align: center;
transition: background-color 0.3s ease;
box-shadow: 0 2px 5px rgba(0,144,255,0.3);
}
.button:hover {
background-color: #007acc;
}
.footer {
background-color: #0090FF;
color: #ffffff;
padding: 25px 20px;
text-align: center;
border-radius: 0 0 10px 10px;
font-size: 14px;
}
.signature {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
font-weight: bold;
color: #0090FF;
}
.important-note {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #0090FF;
margin: 20px 0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>SEALS</h1>
</div>
<div class="content">
<h2>Hello, ${NAME_USERS}! 👋</h2>
<p>Welcome to SEALS! We're excited to have you on board.</p>
<p>To get started, please verify your email address by clicking the button below:</p>
<div style="text-align: center;">
<a href="${validationLink}" class="button">Verify Email</a>
</div>
<div class="important-note">
2024-11-20 01:11:01 +00:00
<p style="margin: 0;"><strong>Important:</strong> This verification link will expire at 12:00 AM WIB. If you don't complete the verification by this time, you'll need to register again.</p>
2024-11-07 02:18:27 +00:00
</div>
<p>If you didn't create an account with SEALS, please ignore this email.</p>
<div class="signature">
<p>Thank you for choosing SEALS!</p>
<p style="margin: 5px 0 0 0;">The SEALS Team</p>
</div>
</div>
<div class="footer">
<p style="margin: 0;">&copy; 2024 SEALS. All rights reserved.</p>
</div>
</div>
</body>
</html>
`,
});
response(200, null, "Teacher registered! Please verify your email.", res);
} catch (error) {
console.log(error);
await transaction.rollback();
if (error.name === "SequelizeUniqueConstraintError") {
const field = error.original.sqlMessage.match(/for key '(.+)'/)[1];
if (field === "teacher_unique_nip") {
return response(400, null, "NIP already registered!", res);
}
if (field === "user_unique_email") {
return response(400, null, "Email already registered!", res);
}
}
response(500, null, "Internal Server Error", res);
}
};
export const registerStudent = async (req, res) => {
const { NAME_USERS, EMAIL, NISN, PASSWORD, CONFIRM_PASSWORD } = req.body;
if (!NAME_USERS) {
return response(400, null, "Name is required!", res);
}
if (!EMAIL) {
return response(400, null, "Email is required!", res);
}
if (!NISN) {
return response(400, null, "NISN is required for students!", res);
}
if (!PASSWORD) {
return response(400, null, "Password is required!", res);
}
if (!CONFIRM_PASSWORD) {
return response(400, null, "Confirm Password is required!", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
return response(400, null, "Passwords do not match!", res);
}
const transaction = await models.db.transaction();
try {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
const newUser = await models.User.create(
{
NAME_USERS: NAME_USERS,
EMAIL: EMAIL,
PASSWORD: hashedPassword,
ROLE: "student",
IS_VALIDATED: 0,
},
{ transaction }
);
await models.Student.create(
{
ID: newUser.ID,
NISN: NISN,
},
{ transaction }
);
await transaction.commit();
2024-11-20 01:11:01 +00:00
const now = moment().tz("Asia/Jakarta");
const midnight = now.clone().endOf("day");
const secondsUntilMidnight = midnight.diff(now, "seconds");
2024-11-07 02:18:27 +00:00
const token = jwt.sign(
{ userId: newUser.ID },
process.env.VERIFY_TOKEN_SECRET,
2024-11-20 01:11:01 +00:00
{ expiresIn: secondsUntilMidnight }
2024-11-07 02:18:27 +00:00
);
const validationLink = `${process.env.CLIENT_URL}/validate-email?token=${token}`;
await transporter.sendMail({
from: process.env.EMAIL_USER,
to: EMAIL,
subject: "Email Verification",
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Verification</title>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Arial, sans-serif;
line-height: 1.6;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 20px auto;
padding: 0;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
background-color: #0090FF;
padding: 25px 20px;
text-align: center;
border-radius: 10px 10px 0 0;
}
.header h1 {
color: #ffffff;
margin: 0;
font-size: 32px;
letter-spacing: 2px;
font-weight: bold;
}
.content {
padding: 40px 30px;
background-color: #ffffff;
color: #333333;
}
.content h2 {
color: #0090FF;
margin-top: 0;
font-size: 24px;
margin-bottom: 20px;
}
.content p {
margin-bottom: 15px;
font-size: 16px;
line-height: 1.7;
}
.button {
display: inline-block;
padding: 12px 35px;
background-color: #0090FF;
color: #ffffff !important;
text-decoration: none;
border-radius: 5px;
margin: 25px 0;
font-size: 16px;
font-weight: bold;
text-align: center;
transition: background-color 0.3s ease;
box-shadow: 0 2px 5px rgba(0,144,255,0.3);
}
.button:hover {
background-color: #007acc;
}
.footer {
background-color: #0090FF;
color: #ffffff;
padding: 25px 20px;
text-align: center;
border-radius: 0 0 10px 10px;
font-size: 14px;
}
.signature {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
font-weight: bold;
color: #0090FF;
}
.important-note {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #0090FF;
margin: 20px 0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>SEALS</h1>
</div>
<div class="content">
<h2>Hello, ${NAME_USERS}! 👋</h2>
<p>Welcome to SEALS! We're excited to have you on board.</p>
<p>To get started, please verify your email address by clicking the button below:</p>
<div style="text-align: center;">
<a href="${validationLink}" class="button">Verify Email</a>
</div>
<div class="important-note">
2024-11-20 01:11:01 +00:00
<p style="margin: 0;"><strong>Important:</strong> This verification link will expire at 12:00 AM WIB. If you don't complete the verification by this time, you'll need to register again.</p>
2024-11-07 02:18:27 +00:00
</div>
<p>If you didn't create an account with SEALS, please ignore this email.</p>
<div class="signature">
<p>Thank you for choosing SEALS!</p>
<p style="margin: 5px 0 0 0;">The SEALS Team</p>
</div>
</div>
<div class="footer">
<p style="margin: 0;">&copy; 2024 SEALS. All rights reserved.</p>
</div>
</div>
</body>
</html>
`,
});
response(200, null, "Student registered! Please verify your email.", res);
} catch (error) {
console.log(error);
await transaction.rollback();
if (error.name === "SequelizeUniqueConstraintError") {
const field = error.original.sqlMessage.match(/for key '(.+)'/)[1];
if (field === "student_unique_nisn") {
return response(400, null, "NISN already registered!", res);
}
if (field === "user_unique_email") {
return response(400, null, "Email already registered!", res);
}
}
response(500, null, "Internal Server Error", res);
}
};
export const validateEmail = async (req, res) => {
const { TOKEN } = req.body;
try {
const decoded = jwt.verify(TOKEN, process.env.VERIFY_TOKEN_SECRET);
const userId = decoded.userId;
await models.User.update({ IS_VALIDATED: 1 }, { where: { ID: userId } });
response(200, null, "Email successfully validated!", res);
} catch (error) {
response(400, null, "Invalid or expired token", res);
}
};
export const registerTeacherForAdmin = async (req, res) => {
const { NAME_USERS, EMAIL, NIP, PASSWORD, CONFIRM_PASSWORD } = req.body;
if (!NAME_USERS) {
return response(400, null, "Name is required!", res);
}
if (!EMAIL) {
return response(400, null, "Email is required!", res);
}
if (!NIP) {
return response(400, null, "NIP is required for teachers!", res);
}
if (!PASSWORD) {
return response(400, null, "Password is required!", res);
}
if (!CONFIRM_PASSWORD) {
return response(400, null, "Confirm Password is required!", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
return response(400, null, "Passwords do not match!", res);
}
const transaction = await models.db.transaction();
try {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
const newUser = await models.User.create(
{
NAME_USERS: NAME_USERS,
EMAIL: EMAIL,
PASSWORD: hashedPassword,
ROLE: "teacher",
IS_VALIDATED: 1,
2024-09-13 13:03:35 +00:00
},
{ transaction }
);
await models.Teacher.create(
{
ID: newUser.ID,
NIP: NIP,
2024-09-13 13:03:35 +00:00
},
{ transaction }
);
await transaction.commit();
const teacherResponse = {
ID: newUser.ID,
NAME_USERS: newUser.NAME_USERS,
EMAIL: newUser.EMAIL,
NIP: NIP,
ROLE: newUser.ROLE,
2024-11-07 02:18:27 +00:00
IS_VALIDATED: newUser.IS_VALIDATED,
2024-09-13 13:03:35 +00:00
};
response(200, teacherResponse, "Teacher registration successful", res);
} catch (error) {
console.log(error);
await transaction.rollback();
if (error.name === "SequelizeUniqueConstraintError") {
const field = error.original.sqlMessage.match(/for key '(.+)'/)[1];
if (field === "teacher_unique_nip") {
return response(400, null, "NIP already registered!", res);
}
if (field === "user_unique_email") {
return response(400, null, "Email already registered!", res);
}
}
response(500, null, "Internal Server Error", res);
}
};
2024-11-07 02:18:27 +00:00
export const registerStudentForAdmin = async (req, res) => {
const { NAME_USERS, EMAIL, NISN, PASSWORD, CONFIRM_PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!NAME_USERS) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Name is required!", res);
}
if (!EMAIL) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Email is required!", res);
}
if (!NISN) {
2024-09-13 13:03:35 +00:00
return response(400, null, "NISN is required for students!", res);
}
if (!PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Password is required!", res);
}
if (!CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Confirm Password is required!", res);
}
if (PASSWORD !== CONFIRM_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Passwords do not match!", res);
}
const transaction = await models.db.transaction();
try {
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(PASSWORD, salt);
2024-09-13 13:03:35 +00:00
const newUser = await models.User.create(
{
NAME_USERS: NAME_USERS,
EMAIL: EMAIL,
2024-09-13 13:03:35 +00:00
PASSWORD: hashedPassword,
ROLE: "student",
2024-11-07 02:18:27 +00:00
IS_VALIDATED: 1,
2024-09-13 13:03:35 +00:00
},
{ transaction }
);
await models.Student.create(
{
ID: newUser.ID,
NISN: NISN,
2024-09-13 13:03:35 +00:00
},
{ transaction }
);
await transaction.commit();
const studentResponse = {
ID: newUser.ID,
NAME_USERS: newUser.NAME_USERS,
EMAIL: newUser.EMAIL,
NISN: NISN,
ROLE: newUser.ROLE,
2024-11-07 02:18:27 +00:00
IS_VALIDATED: newUser.IS_VALIDATED,
2024-09-13 13:03:35 +00:00
};
response(200, studentResponse, "Student registration successful", res);
} catch (error) {
console.log(error);
await transaction.rollback();
if (error.name === "SequelizeUniqueConstraintError") {
const field = error.original.sqlMessage.match(/for key '(.+)'/)[1];
if (field === "student_unique_nisn") {
return response(400, null, "NISN already registered!", res);
}
if (field === "user_unique_email") {
return response(400, null, "Email already registered!", res);
}
}
response(500, null, "Internal Server Error", res);
}
};
export const loginUser = async (req, res) => {
const { EMAIL, PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!EMAIL) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Email is required!", res);
}
if (!PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Password is required!", res);
}
try {
const user = await models.User.findOne({ where: { EMAIL } });
2024-09-13 13:03:35 +00:00
if (!user) {
return response(404, null, "User data not found!", res);
}
2024-11-07 02:18:27 +00:00
if (user.IS_VALIDATED !== 1) {
2024-11-20 01:11:01 +00:00
return response(
403,
null,
"User is not validated! Please verify your email first.",
res
);
2024-11-07 02:18:27 +00:00
}
const validPassword = await bcrypt.compare(PASSWORD, user.PASSWORD);
2024-09-13 13:03:35 +00:00
if (!validPassword) {
return response(401, null, "The password you entered is incorrect!", res);
}
const accessToken = jwt.sign(
{ ID: user.ID, ROLE: user.ROLE },
2024-09-13 13:03:35 +00:00
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: "3h" }
);
const refreshToken = jwt.sign(
{ ID: user.ID, ROLE: user.ROLE },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "7d" }
);
await models.User.update(
{ REFRESH_TOKEN: refreshToken },
{ where: { ID: user.ID } }
2024-09-13 13:03:35 +00:00
);
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
2024-11-07 02:18:27 +00:00
maxAge: 7 * 24 * 60 * 60 * 1000,
});
2024-09-13 13:03:35 +00:00
const userResponse = {
ID: user.ID,
NAME_USERS: user.NAME_USERS,
EMAIL: user.EMAIL,
ROLE: user.ROLE,
TOKEN: `Bearer ${accessToken}`,
REFRESH_TOKEN: refreshToken,
2024-09-13 13:03:35 +00:00
};
response(200, userResponse, "Login successful", res);
} catch (error) {
console.log(error);
response(500, null, "Internal Server Error", res);
}
};
export const refreshToken = async (req, res) => {
const refreshToken = req.cookies?.refreshToken || req.body?.REFRESH_TOKEN;
if (!refreshToken) {
return response(400, null, "Refresh token is required!", res);
}
try {
const user = await models.User.findOne({
where: { REFRESH_TOKEN: refreshToken },
});
if (!user) {
return response(403, null, "Invalid refresh token!", res);
}
let decoded;
try {
decoded = jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET);
} catch (err) {
if (err.name === "TokenExpiredError") {
return response(
401,
null,
"Refresh token expired. Please login again.",
res
);
}
return response(403, null, "Invalid refresh token!", res);
}
if (decoded.ID !== user.ID) {
return response(403, null, "Invalid refresh token data!", res);
}
const newAccessToken = jwt.sign(
{ ID: user.ID, ROLE: user.ROLE },
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: "3h" }
);
const newRefreshToken = jwt.sign(
{ ID: user.ID, ROLE: user.ROLE },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: "7d" }
);
await models.User.update(
{ REFRESH_TOKEN: newRefreshToken },
{ where: { ID: user.ID } }
);
res.cookie("refreshToken", newRefreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
2024-11-07 02:18:27 +00:00
maxAge: 7 * 24 * 60 * 60 * 1000,
});
response(
200,
{ TOKEN: `Bearer ${newAccessToken}`, REFRESH_TOKEN: newRefreshToken },
"Token refreshed successfully",
res
);
} catch (error) {
console.log(error);
response(500, null, "Internal Server Error", res);
}
};
2024-09-13 13:03:35 +00:00
export const logoutUser = (req, res) => {
response(200, null, "You have successfully logged out.", res);
};
export const forgotPassword = async (req, res) => {
const { EMAIL } = req.body;
2024-09-13 13:03:35 +00:00
if (!EMAIL) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Email is required!", res);
}
try {
const user = await models.User.findOne({ where: { EMAIL: EMAIL } });
2024-09-13 13:03:35 +00:00
if (!user) {
return response(404, null, "Email is not registered!", res);
}
const resetToken = jwt.sign(
{ id: user.ID },
process.env.RESET_PASSWORD_SECRET,
{
expiresIn: "1h",
}
);
2024-10-28 02:36:05 +00:00
const resetLink = `${process.env.CLIENT_URL}/resetPassword/${resetToken}`;
2024-09-13 13:03:35 +00:00
const mailOptions = {
from: process.env.EMAIL_USER,
to: user.EMAIL,
subject: "Password Reset",
2024-11-07 02:18:27 +00:00
html: `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Reset Password</title>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Arial, sans-serif;
line-height: 1.6;
background-color: #f5f5f5;
}
.container {
max-width: 600px;
margin: 20px auto;
padding: 0;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.header {
background-color: #0090FF;
padding: 25px 20px;
text-align: center;
border-radius: 10px 10px 0 0;
}
.header h1 {
color: #ffffff;
margin: 0;
font-size: 32px;
letter-spacing: 2px;
font-weight: bold;
}
.content {
padding: 40px 30px;
background-color: #ffffff;
color: #333333;
}
.content h2 {
color: #0090FF;
margin-top: 0;
font-size: 24px;
margin-bottom: 20px;
}
.content p {
margin-bottom: 15px;
font-size: 16px;
line-height: 1.7;
}
.button {
display: inline-block;
padding: 12px 35px;
background-color: #0090FF;
color: #ffffff !important;
text-decoration: none;
border-radius: 5px;
margin: 25px 0;
font-size: 16px;
font-weight: bold;
text-align: center;
transition: background-color 0.3s ease;
box-shadow: 0 2px 5px rgba(0,144,255,0.3);
}
.button:hover {
background-color: #007acc;
}
.footer {
background-color: #0090FF;
color: #ffffff;
padding: 25px 20px;
text-align: center;
border-radius: 0 0 10px 10px;
font-size: 14px;
}
.signature {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #eee;
font-weight: bold;
color: #0090FF;
}
.important-note {
background-color: #f8f9fa;
padding: 15px;
border-left: 4px solid #0090FF;
margin: 20px 0;
}
.security-warning {
background-color: #fff3cd;
padding: 15px;
border-left: 4px solid #ffc107;
margin: 20px 0;
font-size: 14px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>SEALS</h1>
</div>
<div class="content">
<h2>Password Reset Request</h2>
<p>Hello!</p>
<p>We received a request to reset the password for your SEALS account. To proceed with the password reset, please click the button below:</p>
<div style="text-align: center;">
<a href="${resetLink}" class="button">Reset Password</a>
</div>
<div class="important-note">
<p style="margin: 0;"><strong>Important:</strong> This reset password link will expire in 1 hour. Please reset your password as soon as possible to maintain access to your account.</p>
</div>
<div class="security-warning">
<p style="margin: 0;"> If you didn't request a password reset, please ignore this email or contact our support team if you have concerns about your account's security.</p>
</div>
<div class="signature">
<p>Thank you for using SEALS!</p>
<p style="margin: 5px 0 0 0;">The SEALS Team</p>
</div>
</div>
<div class="footer">
<p style="margin: 0;">&copy; 2024 SEALS. All rights reserved.</p>
</div>
</div>
</body>
</html>
`,
2024-09-13 13:03:35 +00:00
};
await transporter.sendMail(mailOptions);
response(200, null, "Password reset email sent successfully!", res);
} catch (error) {
console.log(error);
response(500, null, "Internal Server Error", res);
}
};
export const resetPassword = async (req, res) => {
const { TOKEN, NEW_PASSWORD, CONFIRM_NEW_PASSWORD } = req.body;
2024-09-13 13:03:35 +00:00
if (!TOKEN) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Token is required!", res);
}
if (!NEW_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "New password is required!", res);
}
if (!CONFIRM_NEW_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Confirm new password is required!", res);
}
if (NEW_PASSWORD !== CONFIRM_NEW_PASSWORD) {
2024-09-13 13:03:35 +00:00
return response(400, null, "Passwords do not match!", res);
}
try {
const decoded = jwt.verify(TOKEN, process.env.RESET_PASSWORD_SECRET);
2024-09-13 13:03:35 +00:00
const user = await models.User.findOne({ where: { ID: decoded.id } });
if (!user) {
return response(404, null, "User data not found!", res);
}
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(NEW_PASSWORD, salt);
2024-09-13 13:03:35 +00:00
user.PASSWORD = hashedPassword;
await user.save();
response(200, null, "Password has been reset successfully!", res);
} catch (error) {
console.log(error);
if (error.name === "TokenExpiredError") {
return response(400, null, "Reset token has expired!", res);
} else {
return response(500, null, "Internal Server Error", res);
}
}
};