refactor food

This commit is contained in:
2025-12-17 09:06:03 +03:30
parent 1b42a0b4b4
commit 87534e8c6f
4 changed files with 34 additions and 23 deletions
@@ -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);
}
}
@@ -13,7 +13,7 @@ export class CategoryService {
constructor(
private readonly categoryRepository: CategoryRepository,
private readonly em: EntityManager,
) {}
) { }
async create(restId: string, dto: CreateCategoryDto): Promise<Category> {
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<Category[]> {
+22 -11
View File
@@ -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<Food> {
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<Food> {
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<Food> {
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<CreateFoodDto>): Promise<Food> {
const food = await this.foodRepository.findOne({ id }, { populate: ['restaurant'] });
async update(restId: string, id: string, dto: Partial<CreateFoodDto>): Promise<Food> {
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<void> {
const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['restaurant'] });
if (!food) {
throw new NotFoundException(FoodMessage.NOT_FOUND);
}
@@ -40,8 +40,8 @@ export class FoodRepository extends EntityRepository<Food> {
}
if (categoryId) {
// filter by related categories (typed via FilterQuery)
Object.assign(where, { categories: { id: categoryId } } as unknown as FilterQuery<Food>);
// filter by related category (Food has a single `category` relation)
Object.assign(where, { category: { id: categoryId } } as unknown as FilterQuery<Food>);
}
const [data, total] = await this.findAndCount(where, {