From 4a2c479879c503493b7a6c64d3b089a3bc829885 Mon Sep 17 00:00:00 2001 From: nicekid1 <86746988+nicekid1@users.noreply.github.com> Date: Wed, 1 Jan 2025 10:39:49 +0330 Subject: [PATCH] Add login functionality for admin in admin module --- src/admin/admin.controller.ts | 23 +++++++------ src/admin/admin.module.ts | 17 +++++++++- src/admin/admin.service.ts | 57 ++++++++++++++++++++++++-------- src/products/products.service.ts | 2 +- 4 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/admin/admin.controller.ts b/src/admin/admin.controller.ts index 075bbe2..36e1b43 100644 --- a/src/admin/admin.controller.ts +++ b/src/admin/admin.controller.ts @@ -1,17 +1,18 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; -import { AdminService } from './admin.service'; -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { InjectModel } from '@nestjs/sequelize'; -import { Admin } from './entities/admin.entity'; -import * as bcrypt from 'bcrypt'; -import { JwtService } from '@nestjs/jwt'; +import { Controller, Get, Post, Body, Patch, Param, Delete } from "@nestjs/common"; +import { AdminService } from "./admin.service"; +import { Admin } from "./entities/admin.entity"; -@Controller('admin') +@Controller("admin") export class AdminController { constructor(private readonly adminService: AdminService) {} - @Post('register') - async register(@Body() body:{email: string, password: string}):Promise{ - const {email, password} = body + @Post("register") + async register(@Body() body: { email: string; password: string }): Promise { + const { email, password } = body; return this.adminService.register(email, password); } + @Post("login") + async login(@Body() body: { email: string; password: string }): Promise<{ token: string }> { + const { email, password } = body; + return this.adminService.login(email, password); + } } diff --git a/src/admin/admin.module.ts b/src/admin/admin.module.ts index 8f141d0..9b9ac62 100644 --- a/src/admin/admin.module.ts +++ b/src/admin/admin.module.ts @@ -3,9 +3,24 @@ import { AdminService } from './admin.service'; import { AdminController } from './admin.controller'; import { SequelizeModule } from '@nestjs/sequelize'; import { Admin } from './entities/admin.entity'; +import { JwtModule } from '@nestjs/jwt'; +import { ConfigModule, ConfigService } from '@nestjs/config'; @Module({ - imports:[SequelizeModule.forFeature([Admin])], + imports:[SequelizeModule.forFeature([Admin]), + JwtModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (config: ConfigService) => { + return { + secret: config.get('JWT_SECRET'), + signOptions: { + expiresIn: config.get('JWT_EXPIRES', '1h'), + }, + }; + }, + }), +], controllers: [AdminController], providers: [AdminService], }) diff --git a/src/admin/admin.service.ts b/src/admin/admin.service.ts index 7340136..58d427c 100644 --- a/src/admin/admin.service.ts +++ b/src/admin/admin.service.ts @@ -1,40 +1,69 @@ -import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; -import { InjectModel } from '@nestjs/sequelize'; -import { Admin } from './entities/admin.entity'; - +import { HttpException, HttpStatus, Injectable } from "@nestjs/common"; +import { InjectModel } from "@nestjs/sequelize"; +import { Admin } from "./entities/admin.entity"; +import * as bcrypt from "bcrypt"; +import { JwtService } from "@nestjs/jwt"; +import { ConfigService } from "@nestjs/config"; @Injectable() export class AdminService { - constructor(@InjectModel(Admin) private readonly adminModel: typeof Admin){} + constructor( + @InjectModel(Admin) private readonly adminModel: typeof Admin, + private readonly jwtService: JwtService, + private readonly configService: ConfigService, + ) {} async register(email: string, password: string): Promise { try { if (!email) { - throw new HttpException('Email should be entered.', HttpStatus.BAD_REQUEST); + throw new HttpException("Email should be entered.", HttpStatus.BAD_REQUEST); } if (!password) { - throw new HttpException('Password should be entered.', HttpStatus.BAD_REQUEST); + throw new HttpException("Password should be entered.", HttpStatus.BAD_REQUEST); } const existingAdmin = await this.adminModel.findOne({ where: { email } }); if (existingAdmin) { - throw new HttpException('Email is already registered.', HttpStatus.CONFLICT); + throw new HttpException("Email is already registered.", HttpStatus.CONFLICT); } + const hashedPassword = await bcrypt.hash(password, 10); + const admin = await this.adminModel.create({ email, - password, - role: 'admin', + password: hashedPassword, + role: "admin", }); return admin; } catch (error) { if (error instanceof HttpException) { - throw error; + throw error; } - throw new HttpException( - 'An error occurred during registration.', - HttpStatus.INTERNAL_SERVER_ERROR, + throw new HttpException("An error occurred during registration.", HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + async login(email: string, password: string): Promise<{ token: string }> { + try { + const admin = await this.adminModel.findOne({ where: { email } }); + if (!admin) { + throw new HttpException("Invalid email or password", HttpStatus.UNAUTHORIZED); + } + const isValidPassword = await bcrypt.compare(password, admin.password); + if (!isValidPassword) { + throw new HttpException("Invalid email or password", HttpStatus.UNAUTHORIZED); + } + const token = this.jwtService.sign( + { id: admin.id, role: admin.role }, + { + secret: this.configService.get("JWT_SECRET"), + expiresIn: this.configService.get("JWT_EXPIRES") || "1h", + }, ); + return { token }; + } catch (error) { + console.log(error); + throw new HttpException("An error occurred during login.", HttpStatus.INTERNAL_SERVER_ERROR); } } } diff --git a/src/products/products.service.ts b/src/products/products.service.ts index 3c3cb54..7d90340 100644 --- a/src/products/products.service.ts +++ b/src/products/products.service.ts @@ -25,7 +25,7 @@ export class ProductsService { try { if (search) { where.name = { - [Op.like]: `%${search}%`, + [Op.iLike]: `%${search}%`, }; }