From fae765e05a8f7383ce45eed4227b9fb840c936ca Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Sun, 16 Nov 2025 10:37:03 +0330 Subject: [PATCH] auth --- src/app.module.ts | 2 +- src/modules/auth/auth.module.ts | 4 ++- src/modules/auth/guards/adminAuth.guard.ts | 16 ++++++------ .../foods/controllers/food.controller.ts | 13 ++++++---- src/modules/foods/entities/food.entity.ts | 6 ++++- src/modules/foods/food.module.ts | 5 +++- src/modules/foods/providers/food.service.ts | 25 ++++++++++--------- .../foods/repositories/food.repository.ts | 4 +-- 8 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index b80b22e..278aca0 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -47,7 +47,7 @@ import { FoodModule } from './modules/foods/food.module'; FoodModule, ], controllers: [], - // providers: [CacheService], + providers: [], // exports: [CacheService], }) export class AppModule {} diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts index 0126c1e..da232c4 100644 --- a/src/modules/auth/auth.module.ts +++ b/src/modules/auth/auth.module.ts @@ -11,6 +11,7 @@ import { RestaurantsModule } from '../restaurants/restaurants.module'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { User } from '../users/entities/user.entity'; import { AdminAuthController } from './controllers/admin-auth.controller'; +import { AdminAuthGuard } from './guards/adminAuth.guard'; @Module({ imports: [ @@ -31,6 +32,7 @@ import { AdminAuthController } from './controllers/admin-auth.controller'; MikroOrmModule.forFeature([User]), ], controllers: [AuthController, AdminAuthController], - providers: [AuthService, TokensService], + providers: [AuthService, TokensService, AdminAuthGuard], + exports: [AdminAuthGuard], }) export class AuthModule {} diff --git a/src/modules/auth/guards/adminAuth.guard.ts b/src/modules/auth/guards/adminAuth.guard.ts index 23da293..6719f24 100644 --- a/src/modules/auth/guards/adminAuth.guard.ts +++ b/src/modules/auth/guards/adminAuth.guard.ts @@ -1,23 +1,25 @@ -import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common'; +import { CanActivate, ExecutionContext, Injectable, UnauthorizedException, Inject } from '@nestjs/common'; import { Request } from 'express'; import { JwtService } from '@nestjs/jwt'; import { ConfigService } from '@nestjs/config'; -import { ITokenPayload } from '../interfaces/IToken-payload'; +import { IAdminTokenPayload } from '../interfaces/IToken-payload'; -export interface AuthRequest extends Request { - userId: string; +export interface AdminAuthRequest extends Request { + adminId: string; restId: string; } @Injectable() export class AdminAuthGuard implements CanActivate { constructor( + @Inject(JwtService) private readonly jwtService: JwtService, + @Inject(ConfigService) private readonly configService: ConfigService, ) {} async canActivate(context: ExecutionContext) { - const request = context.switchToHttp().getRequest(); + const request = context.switchToHttp().getRequest(); try { const secret = this.configService.get('JWT_SECRET'); @@ -27,10 +29,10 @@ export class AdminAuthGuard implements CanActivate { } try { - const payload = await this.jwtService.verifyAsync(token, { + const payload = await this.jwtService.verifyAsync(token, { secret, }); - request['userId'] = payload.userId; + request['adminId'] = payload.adminId; request['restId'] = payload.restId; } catch { throw new UnauthorizedException(); diff --git a/src/modules/foods/controllers/food.controller.ts b/src/modules/foods/controllers/food.controller.ts index 633a4be..e1d1454 100644 --- a/src/modules/foods/controllers/food.controller.ts +++ b/src/modules/foods/controllers/food.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common'; +import { Controller, Get, Post, Body, Patch, Param, Delete, Query, UseGuards } from '@nestjs/common'; import { FoodService } from '../providers/food.service'; import { CreateFoodDto } from '../dto/create-food.dto'; import { UpdateFoodDto } from '../dto/update-food.dto'; @@ -14,7 +14,10 @@ import { ApiBody, ApiParam, } from '@nestjs/swagger'; +import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard'; +import { RestId } from 'src/common/decorators'; +@UseGuards(AdminAuthGuard) @ApiTags('foods') @Controller('foods') export class FoodController { @@ -24,8 +27,8 @@ export class FoodController { @ApiOperation({ summary: 'Create a new food' }) @ApiCreatedResponse({ description: 'The food has been successfully created.', type: CreateFoodDto }) @ApiBody({ type: CreateFoodDto }) - create(@Body() createFoodDto: CreateFoodDto) { - return this.foodsService.create(createFoodDto); + create(@Body() createFoodDto: CreateFoodDto, @RestId() restId: string) { + return this.foodsService.create(restId, createFoodDto); } @Get() @@ -38,8 +41,8 @@ export class FoodController { @ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] }) @ApiQuery({ name: 'categoryId', required: false, type: String }) @ApiQuery({ name: 'isActive', required: false, type: Boolean }) - findAll(@Query() dto: FindFoodsDto) { - return this.foodsService.findAll(dto); + findAll(@Query() dto: FindFoodsDto,@RestId() restId: string) { + return this.foodsService.findAll(restId, dto); } @Get(':id') diff --git a/src/modules/foods/entities/food.entity.ts b/src/modules/foods/entities/food.entity.ts index ae82dc7..a44e0a5 100644 --- a/src/modules/foods/entities/food.entity.ts +++ b/src/modules/foods/entities/food.entity.ts @@ -1,9 +1,13 @@ -import { Collection, Entity, ManyToMany, Property } from '@mikro-orm/core'; +import { Collection, Entity, ManyToMany, OneToOne, Property } from '@mikro-orm/core'; import { Category } from './category.entity'; import { BaseEntity } from '../../../common/entities/base.entity'; +import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity'; @Entity({ tableName: 'foods' }) export class Food extends BaseEntity { + @OneToOne(() => Restaurant) + restaurant: Restaurant; + @ManyToMany(() => Category) categories = new Collection(this); diff --git a/src/modules/foods/food.module.ts b/src/modules/foods/food.module.ts index acaa49c..f602212 100644 --- a/src/modules/foods/food.module.ts +++ b/src/modules/foods/food.module.ts @@ -8,9 +8,12 @@ import { CategoryRepository } from './repositories/category.repository'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { Category } from './entities/category.entity'; import { Food } from './entities/food.entity'; +import { RestaurantsModule } from '../restaurants/restaurants.module'; +import { AuthModule } from '../auth/auth.module'; +import { JwtModule } from '@nestjs/jwt'; @Module({ - imports: [MikroOrmModule.forFeature([Food, Category])], + imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule], controllers: [FoodController, CategoryController], providers: [FoodService, CategoryService, FoodRepository, CategoryRepository], exports: [FoodRepository, CategoryRepository], diff --git a/src/modules/foods/providers/food.service.ts b/src/modules/foods/providers/food.service.ts index 4891fc9..7d53f9d 100644 --- a/src/modules/foods/providers/food.service.ts +++ b/src/modules/foods/providers/food.service.ts @@ -6,24 +6,24 @@ import { CategoryRepository } from '../repositories/category.repository'; import { EntityManager } from '@mikro-orm/postgresql'; import { RequiredEntityData } from '@mikro-orm/core'; import { Food } from '../entities/food.entity'; -import { FoodMessage } from 'src/common/enums/message.enum'; -// import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository'; +import { FoodMessage, RestMessage } from 'src/common/enums/message.enum'; +import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository'; @Injectable() export class FoodService { constructor( private readonly foodRepository: FoodRepository, private readonly categoryRepository: CategoryRepository, - // private readonly restRepository: RestRepository, + private readonly restRepository: RestRepository, private readonly em: EntityManager, ) {} - async create(createFoodDto: CreateFoodDto): Promise { + async create(restId: string, createFoodDto: CreateFoodDto): Promise { const { categoryIds, ...rest } = createFoodDto; - // const restaurant = await this.restRepository.findOne({ id: createFoodDto.restId }); - // if (!restaurant) { - // throw new NotFoundException(RestMessage.NOT_FOUND); - // } + const restaurant = await this.restRepository.findOne({ id: restId }); + if (!restaurant) { + throw new NotFoundException(RestMessage.NOT_FOUND); + } // prepare data with defaults for required fields so repository.create typing is satisfied const data: RequiredEntityData = { // boolean/day flags @@ -48,9 +48,10 @@ export class FoodService { points: rest.points ?? 0, prepareTime: rest.prepareTime ?? 0, images: rest.images ?? undefined, - } as RequiredEntityData; + restaurant: restaurant, + }; - const food = this.foodRepository.create(data) as Food; + const food = this.foodRepository.create(data); if (!food) { throw new Error('Failed to create food entity'); } @@ -65,8 +66,8 @@ export class FoodService { return food; } - findAll(dto: FindFoodsDto) { - return this.foodRepository.findAllPaginated(dto); + findAll(restId: string, dto: FindFoodsDto) { + return this.foodRepository.findAllPaginated(restId, dto); } findOne(id: string) { diff --git a/src/modules/foods/repositories/food.repository.ts b/src/modules/foods/repositories/food.repository.ts index aaf556e..57dcaeb 100644 --- a/src/modules/foods/repositories/food.repository.ts +++ b/src/modules/foods/repositories/food.repository.ts @@ -23,12 +23,12 @@ export class FoodRepository extends EntityRepository { * Find foods with pagination and optional filters. * Supports: search (title/content), categoryId, isActive, ordering. */ - async findAllPaginated(opts: FindFoodsOpts = {}): Promise> { + async findAllPaginated(restId: string, opts: FindFoodsOpts = {}): Promise> { const { page = 1, limit = 10, search, orderBy = 'createdAt', order = 'desc', categoryId, isActive } = opts; const offset = (page - 1) * limit; - const where: FilterQuery = {}; + const where: FilterQuery = { restaurant: { id: restId } }; if (typeof isActive === 'boolean') { where.isActive = isActive;