61fd639faf
- Updated CORS settings for frontend compatibility. - Integrated Redis URL configuration. - Improved login response structure in account service. - Added role-based authorization for order and plan management. - Enhanced error handling and logging in profile and plan services. - Updated Swagger documentation for clarity on order statuses. - Configured Redis connection for better performance.
372 lines
11 KiB
JavaScript
372 lines
11 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"
|
|
}, {
|
|
attempts: 1,
|
|
removeOnComplete: true,
|
|
removeOnFail: true,
|
|
});
|
|
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,
|
|
},
|
|
select: {
|
|
id: true,
|
|
email: true,
|
|
role: true,
|
|
isAccountVerified: true,
|
|
isDeleted: true,
|
|
password: true,
|
|
profile: true,
|
|
},
|
|
});
|
|
// 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);
|
|
const finalOutputData = {
|
|
id: account.id,
|
|
email: account.email,
|
|
role: account.role,
|
|
shopName: account?.profile?.shopName,
|
|
shopLogo: account?.profile?.shopLogo,
|
|
};
|
|
return {
|
|
accessToken,
|
|
profile: finalOutputData
|
|
};
|
|
};
|
|
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
|
|
};
|