diff --git a/src/admin/admin.controller.ts b/src/admin/admin.controller.ts index f289c16..8e0c448 100644 --- a/src/admin/admin.controller.ts +++ b/src/admin/admin.controller.ts @@ -15,7 +15,7 @@ export class AdminController { } //login as admin @Post("login") - async login(@Body() loginAdminDto: LoginAdminDto): Promise<{ accessToken }> { + async login(@Body() loginAdminDto: LoginAdminDto): Promise<{ accessToken; refreshToken }> { return this.adminService.login(loginAdminDto); } //logout user @@ -26,11 +26,9 @@ export class AdminController { return this.adminService.logout(userId); } //get a new access token - @UseGuards(RoleGuard) - @Get("new-token") - async newAccessToken(@Request() req) { - const userId = req.user.id - return this.adminService.refreshToken(userId); + @Post("new-token") + async newAccessToken(@Body("token") token: string) { + return this.adminService.newAccessToken(token); } //edit admin profile @UseGuards(RoleGuard) diff --git a/src/admin/admin.service.ts b/src/admin/admin.service.ts index b13ebc2..5bab251 100644 --- a/src/admin/admin.service.ts +++ b/src/admin/admin.service.ts @@ -17,15 +17,31 @@ export class AdminService { //register method async register(createAdminDto: CreateAdminDto): Promise<{ message }> { try { - const existingAdmin = await this.adminModel.findOne({ + const existingAdminByEmail = await this.adminModel.findOne({ where: { email: createAdminDto.email }, }); - if (existingAdmin) { + if (existingAdminByEmail) { throw new HttpException("The provided email is already registered.", HttpStatus.CONFLICT); } + + const existingAdminByUsername = await this.adminModel.findOne({ + where: { username: createAdminDto.username }, + }); + if (existingAdminByUsername) { + throw new HttpException("The provided username is already taken.", HttpStatus.CONFLICT); + } + + const existingAdminByPhoneNumber = await this.adminModel.findOne({ + where: { phoneNumber: createAdminDto.phoneNumber }, + }); + if (existingAdminByPhoneNumber) { + throw new HttpException("The provided phone number is already registered.", HttpStatus.CONFLICT); + } + createAdminDto.password = await bcrypt.hash(createAdminDto.password, 10); + await this.adminModel.create(createAdminDto); - return { message: "admin register is successful" }; + return { message: "Admin registration is successful." }; } catch (error) { if (error instanceof HttpException) { throw error; @@ -34,14 +50,14 @@ export class AdminService { } } //login method - async login(loginAdminDto: LoginAdminDto): Promise<{ accessToken: string }> { + async login(loginAdminDto: LoginAdminDto): Promise<{ accessToken: string; refreshToken: string }> { try { const admin = await this.adminModel.findOne({ - where: { email: loginAdminDto.email }, + where: { email: loginAdminDto.email,username:loginAdminDto.username }, }); if (!admin) { - throw new HttpException("Invalid email or password.", HttpStatus.UNAUTHORIZED); + throw new HttpException("Invalid email, username or password.", HttpStatus.UNAUTHORIZED); } const isValidPassword = await bcrypt.compare(loginAdminDto.password, admin.password); @@ -69,7 +85,7 @@ export class AdminService { { where: { id: admin.id } }, ); - return { accessToken }; + return { accessToken, refreshToken }; } catch (error) { if (error instanceof HttpException) { throw error; @@ -94,27 +110,25 @@ export class AdminService { } } //getting new access token - async refreshToken(userId: number): Promise<{ accessToken: string }> { - const refreshToken = (await this.adminModel.findOne({ where: { id: userId } })).refreshToken; - + async newAccessToken(refreshToken: string) { if (!refreshToken) { throw new HttpException("Refresh token is required.", HttpStatus.BAD_REQUEST); } let decoded; try { - decoded = this.jwtService.verify(refreshToken, { secret: process.env.JWT_REFRESH_SECRET }); + decoded = this.jwtService.verify(refreshToken, { secret: this.configService.get("JWT_REFRESH_SECRET") }); } catch (error) { throw new HttpException("Invalid or expired token.", HttpStatus.UNAUTHORIZED); } - const user = await this.adminModel.findOne({ where: { id: decoded.id } }); + const user = await this.adminModel.findOne({where:{id:decoded.id}}); if (!user) { throw new HttpException("User not found.", HttpStatus.NOT_FOUND); } - if (user.role !== "admin") { - throw new HttpException("You are not authorized to get an admin token.", HttpStatus.FORBIDDEN); + if (user.refreshToken !== refreshToken) { + throw new HttpException("Invalid refresh token.", HttpStatus.FORBIDDEN); } const accessToken = this.jwtService.sign( diff --git a/src/cart/cart.service.ts b/src/cart/cart.service.ts index 52359cb..1bcf254 100644 --- a/src/cart/cart.service.ts +++ b/src/cart/cart.service.ts @@ -70,36 +70,54 @@ export class CartService { if (!userId) { throw new HttpException("User ID is required.", HttpStatus.BAD_REQUEST); } - + try { const cartItems = await this.cartModel.findAll({ where: { userId, status: "open" }, include: [ { model: Product, - attributes: ["name"], + attributes: ["name", "price"], }, ], }); - + if (!cartItems || cartItems.length === 0) { - throw new HttpException("No cart items found for the specified user.", HttpStatus.NOT_FOUND); + return { cartItems: [], totalPrice: 0 }; } - - const totalPrice = cartItems.reduce((sum, item) => sum + (Number(item.productPrice) * item.quantity || 0), 0); - + + const totalPrice = cartItems.reduce((sum, item) => { + return sum + (Number(item.productPrice) * item.quantity || 0); + }, 0); + return { cartItems, totalPrice }; } catch (error) { - throw new HttpException("An unexpected error occurred while fetching the cart. Please try again later.", HttpStatus.INTERNAL_SERVER_ERROR); + console.error("Error fetching cart items:", error); + throw new HttpException( + "An unexpected error occurred while fetching the cart. Please try again later.", + HttpStatus.INTERNAL_SERVER_ERROR + ); } } - + // Update cart item quantity async updateCart(userId: number, productId: number, quantity: number): Promise { const cartItem = await this.cartModel.findOne({ where: { userId, productId, status: "open" } }); + if (!cartItem) { throw new HttpException("Product not found in the cart.", HttpStatus.NOT_FOUND); } + + const product = await this.productModel.findByPk(productId); + + if (!product) { + throw new HttpException("Product not found.", HttpStatus.NOT_FOUND); + } + + if (product.quantity < quantity) { + throw new HttpException("Insufficient product quantity.", HttpStatus.CONFLICT); + } + try { cartItem.quantity = quantity; await cartItem.save(); @@ -109,7 +127,7 @@ export class CartService { throw new HttpException("An unexpected error occurred while updating the cart. Please try again later.", HttpStatus.INTERNAL_SERVER_ERROR); } } - + // Remove an item from cart async removeFromCart(userId: number, productId: number): Promise<{ message: string; cartItem: Cart }> { const cartItem = await this.cartModel.findOne({ where: { userId, productId, status: "open" } }); @@ -127,11 +145,14 @@ export class CartService { //delete whole cart by user async clearCart(userId: number) { - await this.cartModel.destroy({ where: { userId } }); - return { message: "cart cleared successful" }; + await this.cartModel.destroy({ + where: { userId, status: 'open' }, + }); + return { message: "Cart cleared successfully" }; } - //order(clearCart disable) + + //order async processOrder(userId: number, totalAmount: number): Promise<{ message: string; invoice: Invoice }> { try { const carts = await this.cartModel.findAll({ where: { userId, status: "open" } }); diff --git a/src/invoice/invoice.service.ts b/src/invoice/invoice.service.ts index 8afe856..85949aa 100644 --- a/src/invoice/invoice.service.ts +++ b/src/invoice/invoice.service.ts @@ -17,11 +17,22 @@ export class InvoiceService { if (!user) { throw new HttpException("User not found", HttpStatus.NOT_FOUND); } - const invoice = await this.invoiceModel.create({ - userId, - totalPaymentAmount: 0, - }); - return invoice; + + try { + const invoice = await this.invoiceModel.create({ + userId, + totalPaymentAmount: 0, + }); + + if (!invoice) { + throw new HttpException("Failed to create invoice", HttpStatus.INTERNAL_SERVER_ERROR); + } + + return invoice; + } catch (error) { + console.error("Error during invoice creation:", error); + throw new HttpException("An error occurred while creating the invoice.", HttpStatus.INTERNAL_SERVER_ERROR); + } } async updateTotalPayment(userId: number) { const user = await User.findByPk(userId); @@ -103,7 +114,7 @@ export class InvoiceService { throw new HttpException("An error occurred while retrieving the invoice.", HttpStatus.INTERNAL_SERVER_ERROR); } } - async getUserInvoices(userId: number){ + async getUserInvoices(userId: number) { try { if (!userId) { throw new HttpException("User ID are required.", HttpStatus.BAD_REQUEST); diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index b75b13d..76d08ad 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -17,15 +17,13 @@ export class UsersController { } //login as user @Post("login") - async login(@Body() loginUserDto: LoginUserDto): Promise<{ accessToken }> { + async login(@Body() loginUserDto: LoginUserDto): Promise<{ accessToken; refreshToken }> { return this.usersService.login(loginUserDto); } //get access token - @UseGuards(JwtAuthGuard) - @Get("new-token") - async newAccessToken(@Request() req) { - const userId = req.user.id; - return this.usersService.newAccessToken(userId); + @Post("new-token") + async newAccessToken(@Body("token") token: string) { + return this.usersService.newAccessToken(token); } //logout user @UseGuards(JwtAuthGuard) diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 7d43e3d..4cc60dc 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -20,25 +20,33 @@ export class UsersService { async register(createUserDto: CreateUserDto): Promise<{ message: string }> { try { createUserDto.password = await bcrypt.hash(createUserDto.password, parseInt(process.env.BCRYPT_SALT_ROUNDS || "10", 10)); - + const emailExists = await this.userModel.findOne({ where: { email: createUserDto.email }, }); if (emailExists) { throw new BadRequestException("Email is already registered."); } - + const phoneExists = await this.userModel.findOne({ where: { phoneNumber: createUserDto.phoneNumber }, }); if (phoneExists) { throw new BadRequestException("Phone number is already registered."); } - + + const usernameExists = await this.userModel.findOne({ + where: { username: createUserDto.username }, + }); + if (usernameExists) { + throw new BadRequestException("Username is already registered."); + } + await this.userModel.create(createUserDto); const user = await this.userModel.findOne({ where: { email: createUserDto.email }, }); + const refreshToken = this.jwtService.sign( { id: user.id }, { @@ -46,12 +54,12 @@ export class UsersService { expiresIn: this.configService.get("JWT_REFRESH_EXPIRES") || "7d", }, ); - + await this.userModel.update( - { refreshToken }, // + { refreshToken }, { where: { id: user.id } }, ); - + return { message: "User registered successfully." }; } catch (error) { if (error instanceof HttpException) { @@ -61,14 +69,14 @@ export class UsersService { } } // Login method - async login(loginUserDto: LoginUserDto): Promise<{ accessToken: string }> { + async login(loginUserDto: LoginUserDto): Promise<{ accessToken: string , refreshToken:string}> { try { const user = await this.userModel.findOne({ - where: { email: loginUserDto.email }, + where: { email: loginUserDto.email, username:loginUserDto.username }, }); if (!user) { - throw new UnauthorizedException("Invalid email or password."); + throw new UnauthorizedException("Invalid email , username or password."); } const passwordMatch = await bcrypt.compare(loginUserDto.password, user.password); @@ -97,7 +105,7 @@ export class UsersService { { where: { id: user.id } }, ); - return { accessToken: accessToken }; + return { accessToken, refreshToken }; } catch (error) { if (error instanceof HttpException) { throw error; @@ -106,21 +114,25 @@ export class UsersService { } } // getting access token - async newAccessToken(userId: number) { - const user = await this.userModel.findOne({ where: { id: userId } }); - if (!user || !user.refreshToken) { + async newAccessToken(refreshToken: string) { + if (!refreshToken) { throw new HttpException("Refresh token is required.", HttpStatus.BAD_REQUEST); } let decoded; try { - decoded = this.jwtService.verify(user.refreshToken, { secret: process.env.JWT_REFRESH_SECRET }); + decoded = this.jwtService.verify(refreshToken, { secret: this.configService.get("JWT_REFRESH_SECRET") }); } catch (error) { throw new HttpException("Invalid or expired token.", HttpStatus.UNAUTHORIZED); } - if (user.id !== decoded.id) { - throw new HttpException("User ID mismatch.", HttpStatus.FORBIDDEN); + const user = await this.getProfile(decoded.id); + if (!user) { + throw new HttpException("User not found.", HttpStatus.NOT_FOUND); + } + + if (user.refreshToken !== refreshToken) { + throw new HttpException("Invalid refresh token.", HttpStatus.FORBIDDEN); } const accessToken = this.jwtService.sign( diff --git a/src/wallet/wallet.service.ts b/src/wallet/wallet.service.ts index d9b63b7..9135ae1 100644 --- a/src/wallet/wallet.service.ts +++ b/src/wallet/wallet.service.ts @@ -27,8 +27,7 @@ export class WalletService { const wallet = await this.walletModel.findOne({ where: { userId } }); if (!wallet) { - const newWallet = await this.walletModel.create({ userId, balance: 0 }); - return { walletId: newWallet.id, userId: newWallet.userId, balance: newWallet.balance }; + throw new HttpException('Wallet not found!', HttpStatus.NOT_FOUND) } return { balance: wallet.balance }; @@ -54,28 +53,37 @@ export class WalletService { const wallet = await this.walletModel.findOne({ where: { userId } }); if (!wallet) { - throw new Error("Wallet not found"); + throw new HttpException("Wallet not found", HttpStatus.NOT_FOUND); } if (wallet.balance < amount) { - throw new Error("Insufficient funds"); + throw new HttpException("Insufficient funds", HttpStatus.BAD_REQUEST); } + try { + wallet.balance -= amount; - wallet.balance -= amount; - await this.transactionModel.create({ - walletId: wallet.id, - amount: String(amount).startsWith("-") ? String(amount) : `-${amount}`, - }); - await wallet.save(); + await this.transactionModel.create({ + walletId: wallet.id, + amount: `-${amount}`, + }); + + await wallet.save(); - return "Payment processed successfully"; + return "Payment processed successfully"; + } catch (error) { + console.error("Error processing payment:", error.message); + throw new HttpException("An error occurred while processing the payment.", HttpStatus.INTERNAL_SERVER_ERROR); + } } //getting transaction async getTransactionById(userId: number) { - const wallet = this.getWalletInfo(userId); + const wallet = await this.getWalletInfo(userId); + if (!wallet) { + throw new HttpException("Wallet not found for the user.", HttpStatus.NOT_FOUND); + } return await this.transactionModel.findAll({ - where: { walletId: (await wallet).walletId }, + where: { walletId: wallet.walletId }, }); } }