From 87534e8c6f8b004c3674072cb5ba2834b76195ef Mon Sep 17 00:00:00 2001 From: morteza-mortezai Date: Wed, 17 Dec 2025 09:06:03 +0330 Subject: [PATCH] refactor food --- .../foods/controllers/food.controller.ts | 16 ++++----- .../foods/providers/category.service.ts | 4 +-- src/modules/foods/providers/food.service.ts | 33 ++++++++++++------- .../foods/repositories/food.repository.ts | 4 +-- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/modules/foods/controllers/food.controller.ts b/src/modules/foods/controllers/food.controller.ts index 3611f9c..aa7f21a 100644 --- a/src/modules/foods/controllers/food.controller.ts +++ b/src/modules/foods/controllers/food.controller.ts @@ -21,7 +21,7 @@ import { RestId } from 'src/common/decorators'; @ApiTags('foods') @Controller() export class FoodController { - constructor(private readonly foodsService: FoodService) {} + constructor(private readonly foodsService: FoodService) { } @Get('public/foods/restaurant/:slug') @ApiOperation({ summary: 'Get all foods by restaurant slug' }) @@ -45,7 +45,7 @@ export class FoodController { @ApiOkResponse({ description: 'The food', type: CreateFoodDto }) @ApiNotFoundResponse({ description: 'Food not found' }) findPublicFoodById(@Param('foodId') foodId: string) { - return this.foodsService.findById(foodId); + return this.foodsService.findPublicById(foodId); } @UseGuards(AdminAuthGuard) @@ -81,8 +81,8 @@ export class FoodController { @ApiParam({ name: 'id', required: true }) @ApiOkResponse({ description: 'The food', type: CreateFoodDto }) @ApiNotFoundResponse({ description: 'Food not found' }) - findById(@Param('id') id: string) { - return this.foodsService.findById(id); + findById(@Param('id') id: string, @RestId() restId: string) { + return this.foodsService.findAdminById(restId, id); } @UseGuards(AdminAuthGuard) @@ -92,15 +92,15 @@ export class FoodController { @ApiParam({ name: 'id', required: true }) @ApiBody({ type: UpdateFoodDto }) @ApiOkResponse({ description: 'The updated food', type: UpdateFoodDto }) - update(@Param('id') id: string, @Body() updateFoodDto: UpdateFoodDto) { - return this.foodsService.update(id, updateFoodDto); + update(@Param('id') id: string, @Body() updateFoodDto: UpdateFoodDto, @RestId() restId: string) { + return this.foodsService.update(restId, id, updateFoodDto); } @UseGuards(AdminAuthGuard) @ApiBearerAuth() @Delete('admin/foods/:id') @ApiOperation({ summary: 'Delete (soft) a food' }) @ApiParam({ name: 'id', required: true }) - remove(@Param('id') id: string) { - return this.foodsService.remove(id); + remove(@Param('id') id: string, @RestId() restId: string) { + return this.foodsService.remove(restId, id); } } diff --git a/src/modules/foods/providers/category.service.ts b/src/modules/foods/providers/category.service.ts index 6ab1ca6..cac0809 100644 --- a/src/modules/foods/providers/category.service.ts +++ b/src/modules/foods/providers/category.service.ts @@ -13,7 +13,7 @@ export class CategoryService { constructor( private readonly categoryRepository: CategoryRepository, private readonly em: EntityManager, - ) {} + ) { } async create(restId: string, dto: CreateCategoryDto): Promise { const restaurant = await this.em.findOne(Restaurant, { id: restId }); @@ -37,7 +37,7 @@ export class CategoryService { if (!restaurant || !restaurant.id) { throw new NotFoundException(RestMessage.NOT_FOUND); } - return this.categoryRepository.find({ restaurant: restaurant }); + return this.categoryRepository.find({ restaurant: restaurant, isActive: true }); } async findAllByRestaurantId(restId: string): Promise { diff --git a/src/modules/foods/providers/food.service.ts b/src/modules/foods/providers/food.service.ts index 95fa7af..93d4478 100644 --- a/src/modules/foods/providers/food.service.ts +++ b/src/modules/foods/providers/food.service.ts @@ -29,7 +29,7 @@ export class FoodService { if (!restaurant) { throw new NotFoundException(RestMessage.NOT_FOUND); } - const category = await this.categoryRepository.findOne({ id: categoryId }); + const category = await this.categoryRepository.findOne({ id: categoryId, restaurant: { id: restId } }); if (!category) { throw new NotFoundException(CategoryMessage.NOT_FOUND); } @@ -74,11 +74,21 @@ export class FoodService { return this.foodRepository.findAllPaginated(restId, dto); } - async findById(id: string): Promise { - const food = await this.foodRepository.findOne({ id }, { populate: ['category'] }); - if (!food) { - throw new NotFoundException(FoodMessage.NOT_FOUND); - } + /** + * Public food detail (only active foods are visible). + */ + async findPublicById(id: string): Promise { + const food = await this.foodRepository.findOne({ id, isActive: true }, { populate: ['category'] }); + if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND); + return food; + } + + /** + * Admin food detail (scoped to the authenticated restaurant). + */ + async findAdminById(restId: string, id: string): Promise { + const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['category'] }); + if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND); return food; } @@ -112,14 +122,14 @@ export class FoodService { return foods; } - async update(id: string, dto: Partial): Promise { - const food = await this.foodRepository.findOne({ id }, { populate: ['restaurant'] }); + async update(restId: string, id: string, dto: Partial): Promise { + const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['restaurant'] }); if (!food) { throw new NotFoundException(FoodMessage.NOT_FOUND); } // attach new categories if provided (adds, does not attempt to preserve/remove existing ones) if (dto.categoryId) { - const category = await this.categoryRepository.findOne({ id: dto.categoryId }); + const category = await this.categoryRepository.findOne({ id: dto.categoryId, restaurant: { id: restId } }); if (!category) { throw new NotFoundException(CategoryMessage.NOT_FOUND); @@ -130,6 +140,7 @@ export class FoodService { // assign other fields from DTO const { categoryId, ...rest } = dto; + void categoryId; this.em.assign(food, rest); await this.em.persistAndFlush(food); @@ -140,8 +151,8 @@ export class FoodService { return food; } - async remove(id: string) { - const food = await this.foodRepository.findOne({ id }, { populate: ['restaurant'] }); + async remove(restId: string, id: string): Promise { + const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['restaurant'] }); if (!food) { throw new NotFoundException(FoodMessage.NOT_FOUND); } diff --git a/src/modules/foods/repositories/food.repository.ts b/src/modules/foods/repositories/food.repository.ts index e8fe3e4..d9f0559 100644 --- a/src/modules/foods/repositories/food.repository.ts +++ b/src/modules/foods/repositories/food.repository.ts @@ -40,8 +40,8 @@ export class FoodRepository extends EntityRepository { } if (categoryId) { - // filter by related categories (typed via FilterQuery) - Object.assign(where, { categories: { id: categoryId } } as unknown as FilterQuery); + // filter by related category (Food has a single `category` relation) + Object.assign(where, { category: { id: categoryId } } as unknown as FilterQuery); } const [data, total] = await this.findAndCount(where, {