0f7af70b90
Updated Docker configuration, refactored middleware for improved error handling, and restructured account, order, plan, profile, and support modules, including their routes, services, and validations. Enhanced email processing queues and utilities for token generation, pagination, and response management to streamline the application architecture and enhance maintainability.
349 lines
10 KiB
JavaScript
349 lines
10 KiB
JavaScript
import bcrypt from "bcrypt";
|
|
import { configs } from "../../configs/index.js";
|
|
import { prisma } from "../../lib/prisma.js";
|
|
import { emailQueue } from "../../queues/email/email.queue.js";
|
|
import { AppError } from "../../utils/app_error.js";
|
|
import { jwtHelpers } from "../../utils/JWT.js";
|
|
import sendMail from "../../utils/mail_sender.js";
|
|
import { otpGenerator } from "../../utils/otpGenerator.js";
|
|
const create_account_into_db = async (req) => {
|
|
const payload = req?.body;
|
|
// check account exist or not
|
|
const existingAccount = await prisma.account.findUnique({
|
|
where: { email: payload.email },
|
|
});
|
|
if (existingAccount) {
|
|
throw new AppError("Email already exists", 403);
|
|
}
|
|
// hash password
|
|
const hashPassword = bcrypt.hashSync(payload.password, 10);
|
|
// create account and profile
|
|
const result = await prisma.$transaction(async (tx) => {
|
|
const account = await tx.account.create({
|
|
data: {
|
|
email: payload.email,
|
|
password: hashPassword,
|
|
},
|
|
});
|
|
const profile = await tx.profile.create({
|
|
data: {
|
|
shopName: payload.shopName,
|
|
accountId: account.id,
|
|
},
|
|
});
|
|
return {
|
|
account,
|
|
profile,
|
|
};
|
|
});
|
|
// sending otp and verification link
|
|
const newOtp = otpGenerator();
|
|
const verificationToken = jwtHelpers.generateToken({
|
|
email: payload.email,
|
|
accountId: result.account.id,
|
|
}, configs.jwt.verified_token, "5m");
|
|
const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`;
|
|
// save otp into db
|
|
await prisma.account.update({
|
|
where: {
|
|
email: payload.email,
|
|
},
|
|
data: {
|
|
lastOtp: newOtp,
|
|
lastOtpSendingTime: new Date(),
|
|
},
|
|
});
|
|
await emailQueue.add("email-queue", {
|
|
name: payload.shopName,
|
|
otp: newOtp,
|
|
verificationLink: verificationLink,
|
|
subject: "Welcome to Quick Launch - Verification OTP",
|
|
email: payload.email,
|
|
textBody: "You can use otp or verification link for verifying your account"
|
|
});
|
|
return null;
|
|
};
|
|
const verify_account_using_otp_into_db = async (req) => {
|
|
const payload = req?.body;
|
|
// check account
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email: payload.email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// match with last otp
|
|
const isOtpMatch = payload.otp === account.lastOtp;
|
|
if (!isOtpMatch) {
|
|
throw new AppError("Invalid OTP, Please try again!!", 401);
|
|
}
|
|
// check otp timing
|
|
const OTP_EXPIRY_TIME = 5 * 60 * 1000; // 5 minutes in ms
|
|
const isOtpExpired = account.lastOtpSendingTime
|
|
? new Date().getTime() - new Date(account.lastOtpSendingTime).getTime() >
|
|
OTP_EXPIRY_TIME
|
|
: true;
|
|
if (isOtpExpired) {
|
|
throw new AppError("OTP Expired, Please try again!!", 401);
|
|
}
|
|
// change account status
|
|
await prisma.account.update({
|
|
where: {
|
|
id: account.id,
|
|
},
|
|
data: {
|
|
isAccountVerified: true,
|
|
},
|
|
});
|
|
// infuter user welcome email
|
|
return "";
|
|
};
|
|
const verify_account_using_link_into_db = async (req) => {
|
|
const token = req?.body?.token;
|
|
let decoadeToken;
|
|
try {
|
|
decoadeToken = jwtHelpers.verifyToken(token, configs.jwt.verified_token);
|
|
}
|
|
catch (error) {
|
|
if (error?.message == "invalid signature") {
|
|
throw new AppError("Invalid Token", 403);
|
|
}
|
|
else if (error?.message == "jwt expired") {
|
|
throw new AppError("Token expired, please reset again", 403);
|
|
}
|
|
}
|
|
// check account
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email: decoadeToken.email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// change account status
|
|
await prisma.account.update({
|
|
where: {
|
|
id: account.id,
|
|
},
|
|
data: {
|
|
isAccountVerified: true,
|
|
},
|
|
});
|
|
// infuter user welcome email
|
|
return "";
|
|
};
|
|
const login_user_into_db = async (req) => {
|
|
const payload = req?.body;
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email: payload.email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// checking password
|
|
const isPasswordMatch = bcrypt.compareSync(payload.password, account.password);
|
|
if (!isPasswordMatch) {
|
|
throw new AppError("Invalid password", 401);
|
|
}
|
|
// check if account is deleted
|
|
if (account.isDeleted) {
|
|
throw new AppError("Account is deleted", 401);
|
|
}
|
|
// check if account is verified
|
|
if (!account.isAccountVerified) {
|
|
throw new AppError("Account is not verified", 401);
|
|
}
|
|
// generate access
|
|
const accessToken = jwtHelpers.generateToken({
|
|
email: account.email,
|
|
role: account.role,
|
|
accountId: account.id,
|
|
}, configs.jwt.access_token, configs.jwt.access_expires);
|
|
return accessToken;
|
|
};
|
|
const get_user_account_from_db = async (req) => {
|
|
const user = req?.user;
|
|
const result = await prisma.account.findUnique({
|
|
where: {
|
|
id: user?.accountId,
|
|
},
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
isAccountVerified: true,
|
|
isDeleted: true,
|
|
profile: true,
|
|
},
|
|
});
|
|
return result;
|
|
};
|
|
const change_password_into_db = async (req) => {
|
|
const user = req?.user;
|
|
// payload
|
|
const payload = req?.body;
|
|
// check old and new password is not same
|
|
const isSamePassword = payload.oldPassword === payload.newPassword;
|
|
if (isSamePassword) {
|
|
throw new AppError("Old and new password are same, Please provide deffirent password", 404);
|
|
}
|
|
// check user validity
|
|
const isUserExist = await prisma.account.findFirst({
|
|
where: {
|
|
email: user?.email,
|
|
},
|
|
});
|
|
// if account not exists
|
|
if (!isUserExist) {
|
|
throw new AppError("Account not found!!", 404);
|
|
}
|
|
// check old password
|
|
const isPasswordMatch = bcrypt.compareSync(payload.oldPassword, isUserExist.password);
|
|
if (!isPasswordMatch) {
|
|
throw new AppError("Incorrect password", 401);
|
|
}
|
|
// change password logic
|
|
const newHashPassword = bcrypt.hashSync(payload.newPassword, 10);
|
|
await prisma.account.update({
|
|
where: {
|
|
id: isUserExist.id,
|
|
},
|
|
data: {
|
|
password: newHashPassword,
|
|
},
|
|
});
|
|
// in future email notification for more sucurity
|
|
return "";
|
|
};
|
|
const resend_otp_and_verification_link_from_db = async (req) => {
|
|
const email = req?.body?.email;
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// if already verified
|
|
if (account.isAccountVerified) {
|
|
throw new AppError("Account already verified", 403);
|
|
}
|
|
// make new otp and verification link
|
|
const newOtp = otpGenerator();
|
|
const verificationToken = jwtHelpers.generateToken({
|
|
email,
|
|
accountId: account.id,
|
|
}, configs.jwt.verified_token, "5m");
|
|
const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`;
|
|
// save otp into db
|
|
await prisma.account.update({
|
|
where: {
|
|
email,
|
|
},
|
|
data: {
|
|
lastOtp: newOtp,
|
|
lastOtpSendingTime: new Date(),
|
|
},
|
|
});
|
|
await sendMail({
|
|
to: email,
|
|
subject: "New Verification otp and link",
|
|
htmlBody: `
|
|
<p><strong>OTP</strong> ${newOtp}</p>
|
|
<small>Otp will be expire in 5 minutes</small>
|
|
|
|
<br/> <br/>
|
|
|
|
<p>Or you can use Verification link </p>
|
|
<p>${verificationLink}</p>
|
|
`,
|
|
textBody: "You can use otp or direct link",
|
|
});
|
|
};
|
|
const forget_password_generate_reset_token_from_db = async (req) => {
|
|
const email = req?.body?.email;
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// generate forget token
|
|
const verificationToken = jwtHelpers.generateToken({
|
|
email: email,
|
|
accountId: account.id,
|
|
}, configs.jwt.verified_token, "5m");
|
|
const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`;
|
|
await sendMail({
|
|
to: email,
|
|
subject: "Forget Password- Use this link for new password ",
|
|
htmlBody: `
|
|
<p>Your Reset Link: </p>
|
|
<p>${verificationLink}</p>
|
|
`,
|
|
textBody: "",
|
|
});
|
|
};
|
|
const reset_password_using_token_into_db = async (req) => {
|
|
const token = req?.body?.token;
|
|
const newPass = req?.body?.newPass;
|
|
let decoadeToken;
|
|
try {
|
|
decoadeToken = jwtHelpers.verifyToken(token, configs.jwt.verified_token);
|
|
}
|
|
catch (error) {
|
|
if (error?.message == "invalid signature") {
|
|
throw new AppError("Invalid Token", 403);
|
|
}
|
|
else if (error?.message == "jwt expired") {
|
|
throw new AppError("Link expired, please reset again", 403);
|
|
}
|
|
}
|
|
// check account
|
|
const account = await prisma.account.findUnique({
|
|
where: {
|
|
email: decoadeToken.email,
|
|
},
|
|
});
|
|
// check if account exists
|
|
if (!account) {
|
|
throw new AppError("Account not found", 404);
|
|
}
|
|
// change account password
|
|
const newHash = bcrypt.hashSync(newPass, 10);
|
|
await prisma.account.update({
|
|
where: {
|
|
id: account.id,
|
|
},
|
|
data: {
|
|
password: newHash,
|
|
},
|
|
});
|
|
// infuter user alart for changing password
|
|
return "";
|
|
};
|
|
export const account_services = {
|
|
create_account_into_db,
|
|
login_user_into_db,
|
|
get_user_account_from_db,
|
|
change_password_into_db,
|
|
verify_account_using_otp_into_db,
|
|
resend_otp_and_verification_link_from_db,
|
|
verify_account_using_link_into_db,
|
|
forget_password_generate_reset_token_from_db,
|
|
reset_password_using_token_into_db
|
|
};
|