import { Model, Types } from "mongoose"; import { HttpStatus } from "../../Helpers/Enums/httpStatus"; import { HttpException } from "../../Helpers/Handlers/commonHandler"; import JWT from "jsonwebtoken"; import User, { IUser } from "../../Models/user.model"; import Customer, { ICustomer } from "../../Models/customer.model"; import GuestUser, { IGuestUser } from "../../Models/guest_user.model"; import Singleton from "../../Helpers/mongodb"; import { Role } from "../../Helpers/Enums/role"; import { generateAndSendOTP } from "../../Helpers/Utils/otp-generator"; import logger from "../../Helpers/logger"; import NotificationService from "./notification.service"; import Common from "../../Helpers/Utils/commonfunction"; export class AuthService { private readonly User: Model; private readonly Customer: Model; private readonly GuestUser: Model; private readonly NotificationService: NotificationService; private _instance: Singleton; constructor() { this.User = User; this.Customer = Customer; this.GuestUser = GuestUser; this._instance = Singleton.getinstance(); this.NotificationService = new NotificationService(); } private signToken(userID: string): string { return JWT.sign( { iss: process.env.PASPORTJS_KEY, sub: userID, }, process.env.PASPORTJS_KEY, { expiresIn: "30 days" } ); } async loginAdmin(data: any) { const user = await this.User.findOne({ $or: [{ email: data.username }, { phone: data.username }], }); if (!user) throw new HttpException("User not found!", HttpStatus.BAD_REQUEST); console.log("user", user); const comparePassword = await Common.comparePassword( data.password, user.password ); if (!comparePassword) throw new HttpException("Invalid Credentials!", HttpStatus.BAD_REQUEST); const { _id, email, username, role, phone, isVerified, isActive, last_login, } = user; // logger.info(`loginUser, ${data}`); const token = this.signToken(_id as string); const userData = { id: _id, email, username, role, token, phone, isVerified, isActive, last_login, }; logger.info("User logged in successfully"); return userData; } async registerUser(data: any) { const { phone, name, email, country_code, device_id, location, country_id, } = data; const isValid = Common.ValidPhoneNumber( phone.toString(), country_code.toString() ); if (isValid !== true) { throw new HttpException( isValid === false ? "Invalid phone number or country code" : isValid, HttpStatus.BAD_REQUEST ); } const user = await this.User.findOne({ phone }); const admin = await this.User.findOne({ role: "1" }); if (user) { throw new HttpException("User already exists", HttpStatus.BAD_REQUEST); } const existGuestUser = await this.GuestUser.findOne({ phone, country_code, }).exec(); const newUserData: any = { phone: phone, role: Role.USER, name: name ? name : "", email: email ? email : "", location: location ? location : "", country_code: country_code ? country_code : "+91", country_id: country_id ? country_id : "in", }; if (existGuestUser) { newUserData.device_id = existGuestUser.device_id; } else { const newGuestUser = await this.GuestUser.create({ phone: phone, device_id: device_id, country_code: country_code ? country_code : "+91", }); newUserData.device_id = device_id; } const newuser = await this.User.create(newUserData); const customer = await this.Customer.create({ phone: phone, user: newuser._id, name: name ? name : "", }); const otp =await generateAndSendOTP(customer.phone); if (!otp) throw new HttpException("Otp not generated!", HttpStatus.BAD_REQUEST); await this._instance.redisClient.setEx(`otp:${phone}`, 600, otp); const userData = { otp, phone }; const notificationData = { from: new Types.ObjectId(newuser?._id?.toString()), to: new Types.ObjectId(admin?._id?.toString()), subject: "New User Registered", message: `New user ${customer?.name} has registered.`, }; await this.NotificationService.createNotification(notificationData); return userData; } async loginUser(phone: string, country_code: string) { const isValid = Common.ValidPhoneNumber( phone.toString(), country_code.toString() ); if (isValid !== true) { throw new HttpException( isValid === false ? "Invalid phone number or country code" : isValid, HttpStatus.BAD_REQUEST ); } const user = await this.User.findOne({ phone: phone, }); console.log("user", user); if (!user) throw new HttpException("User not found!", HttpStatus.BAD_REQUEST); const customer = await this.Customer.findOne({ user: user._id }); // throw error if customer status is blocked if (customer && customer.status === "Blocked") { throw new HttpException( "Your account is blocked", HttpStatus.UNAUTHORIZED ); } const otp =await generateAndSendOTP(phone); if (!otp) throw new HttpException("Otp not generated!", HttpStatus.BAD_REQUEST); await this._instance.redisClient.setEx(`otp:${phone}`, 600, otp); const data = { otp, phone }; return data; } async resendOTP(username: string) { const user = await this.User.findOne( { $or: [{ email: username }, { phone: username }], }, { _id: 1 } ); if (!user) throw new HttpException("User not found!", HttpStatus.BAD_REQUEST); const otp =await generateAndSendOTP(username); if (!otp) throw new HttpException("Otp not generated!", HttpStatus.BAD_REQUEST); await this._instance.redisClient.setEx(`otp:${username}`, 600, otp); const data = { otp, username }; return data; } async forgetPassword(username: string) { const user = await this.User.findOne( { $or: [{ email: username }, { phone: username }], }, { _id: 1 } ); if (!user) throw new HttpException("User not found!", HttpStatus.BAD_REQUEST); const otp =await generateAndSendOTP(username); if (!otp) throw new HttpException("Otp not generated!", HttpStatus.BAD_REQUEST); await this._instance.redisClient.setEx(`otp:${username}`, 600, otp); const data = { otp, username }; return data; } async verifyLoginOTP(otp: string, username: string | undefined) { const otpFromRedis = await this._instance.redisClient.get( `otp:${username}` ); if (!otpFromRedis) { throw new HttpException("Session expired", HttpStatus.BAD_REQUEST); } const isOTPVerified = otp === otpFromRedis; if (isOTPVerified) { const user = await User.findOne({ $or: [{ email: username }, { phone: username }], }); const customer = await Customer.findOne({ user: user._id, }); const lastLogin = new Date(); user.last_login = lastLogin; user.isActive = true; await user.save(); // change if customer login change their status to inactive to active if (customer) { customer.status = "Active"; await customer.save(); } const devideData = await this.GuestUser.findOne({ phone: user.phone, country_code: user.country_code, }).exec(); logger.info(`User logged in successfully, ${customer}`); const token = this.signToken(user._id as string); const userData = { id: user._id, email: user.email, username: user.username, role: user.role, token: token, phone: user.phone, isVerified: user.isVerified, status: customer ? customer.status : undefined, isActive: user.isActive, last_login: user.last_login, name: customer ? customer.name : undefined, country_code: user ? user.country_code : undefined, location: customer ? customer.location : undefined, device_id: devideData ? devideData.device_id : undefined, registration_date: customer ? (customer as unknown as Document & ICustomer & { createdAt: Date }).createdAt : undefined }; logger.info("User logged in successfully"); return userData; } else { // Return a response indicating OTP verification failure throw new HttpException("Invalid OTP", HttpStatus.UNAUTHORIZED); } } async verifyOTP(otp: string, username: string | undefined) { const otpFromRedis = await this._instance.redisClient.get( `otp:${username}` ); const existDevideID = await this.GuestUser.findOne({ phone: username, }).exec(); if (!otpFromRedis) { throw new HttpException("Session expired", HttpStatus.BAD_REQUEST); } const isOTPVerified = otp === otpFromRedis; if (isOTPVerified) { const user = await User.findOne({ $or: [{ email: username }, { phone: username }], }); user.isVerified = true; user.last_login = new Date(); await user.save(); const customer = await Customer.findOne({ user: user._id, }); // change if customer login change their status to inactive to active // if (customer) { // customer.status = "Active"; // await customer.save(); // } // logger.info(`User logged in successfully, ${customer}`); const token = this.signToken(user._id as string); const userData = { id: user._id, email: user.email, username: user.username, role: user.role, token: token, phone: user.phone, country_code: user?.country_code, isVerified: user.isVerified, isActive: user.isActive, last_login: user.last_login, device_id: existDevideID ? existDevideID.device_id : undefined, name: customer ? customer.name : undefined, location: customer ? customer.location : undefined, registration_date: customer ? (customer as unknown as Document & ICustomer & { createdAt: Date }).createdAt : undefined }; logger.info("User Verified successfully"); return userData; } else { // Return a response indicating OTP verification failure throw new HttpException("Invalid OTP", HttpStatus.UNAUTHORIZED); } } async changePassword(id: string, password: string) { // Find the user by email or phone const user: IUser | null = await User.findById(id); if (!user) { // Handle case where user is not found throw new HttpException("User not found", HttpStatus.BAD_REQUEST); } // Update the user's password try { // Update the user's password user.password = password; // Save the updated user document await user.save(); // Return a success message or updated user data return user; } catch (error) { // Handle any errors that occur during password update throw new HttpException( "Failed to update password", HttpStatus.BAD_REQUEST ); } } }