Files
quicklanch-server/src/app/modules/account/account.service.ts
T

404 lines
9.9 KiB
TypeScript
Raw Normal View History

2026-04-02 21:27:09 +06:00
import bcrypt from "bcrypt";
import { Request } from "express";
import { configs } from "../../configs";
import { prisma } from "../../lib/prisma";
import { emailQueue } from "../../queues/email/email.queue";
2026-04-02 21:27:09 +06:00
import { AppError } from "../../utils/app_error";
import { jwtHelpers } from "../../utils/JWT";
import sendMail from "../../utils/mail_sender";
import { otpGenerator } from "../../utils/otpGenerator";
2026-04-02 21:27:09 +06:00
const create_account_into_db = async (req: Request) => {
const payload = req?.body;
// check account exist or not
const existingAccount = await prisma.account.findUnique({
where: { email: payload.email },
});
2026-04-02 21:27:09 +06:00
if (existingAccount) {
throw new AppError("Email already exists", 403);
}
2026-04-02 21:27:09 +06:00
// 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,
2026-04-02 21:27:09 +06:00
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 as string,
"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"
})
2026-04-02 21:27:09 +06:00
return result;
};
const verify_account_using_otp_into_db = async (req: Request) => {
const payload: { email: string; otp: string } = 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
2026-04-02 21:27:09 +06:00
: 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: Request) => {
const token = req?.body?.token as string;
let decoadeToken: any;
try {
decoadeToken = jwtHelpers.verifyToken(
token,
configs.jwt.verified_token as string,
);
} catch (error: any) {
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: Request) => {
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 as string,
configs.jwt.access_expires as string,
);
return accessToken;
};
const get_user_account_from_db = async (req: Request) => {
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: Request) => {
const user = req?.user;
// payload
const payload: { oldPassword: string; newPassword: string } = 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: Request) => {
const email = req?.body?.email as string;
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 as string,
"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 as string,
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: Request) => {
2026-04-02 21:27:09 +06:00
const email = req?.body?.email as string;
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 as string,
"5m",
);
const verificationLink = `${configs.jwt.front_end_url}/verify/token?=${verificationToken}`;
await sendMail({
to: email as string,
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: Request) => {
const token = req?.body?.token as string;
const newPass = req?.body?.newPass as string;
let decoadeToken: any;
try {
decoadeToken = jwtHelpers.verifyToken(
token,
configs.jwt.verified_token as string,
);
} catch (error: any) {
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 "";
};
2026-04-02 21:27:09 +06:00
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,
2026-04-02 21:27:09 +06:00
reset_password_using_token_into_db
};