favorite
This commit is contained in:
@@ -16,7 +16,9 @@ import {
|
||||
ApiHeader,
|
||||
} from '@nestjs/swagger';
|
||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||
import { RestId } from 'src/common/decorators';
|
||||
import { RestId, UserId } from 'src/common/decorators';
|
||||
import { AuthGuard } from 'src/modules/auth/guards/auth.guard';
|
||||
import { OptionalAuthGuard } from 'src/modules/auth/guards/optinalAuth.guard';
|
||||
|
||||
@ApiTags('foods')
|
||||
@Controller()
|
||||
@@ -39,18 +41,62 @@ export class FoodController {
|
||||
return this.foodsService.findAllByRestaurant(slug);
|
||||
}
|
||||
|
||||
|
||||
@Get('public/foods/:foodId')
|
||||
@UseGuards(OptionalAuthGuard)
|
||||
@ApiHeader({
|
||||
name: 'X-Slug',
|
||||
required: true,
|
||||
schema: {
|
||||
type: 'string',
|
||||
default: 'zhivan',
|
||||
},
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Get a food by id' })
|
||||
@ApiParam({ name: 'foodId', required: true })
|
||||
@ApiOkResponse({ description: 'The food', type: CreateFoodDto })
|
||||
@ApiNotFoundResponse({ description: 'Food not found' })
|
||||
findPublicFoodById(@Param('foodId') foodId: string) {
|
||||
return this.foodsService.findPublicById(foodId);
|
||||
findPublicFoodById(@Param('foodId') foodId: string, @UserId() userId?: string):Promise<any> {
|
||||
const a= this.foodsService.findPublicById(foodId, userId);
|
||||
return a
|
||||
}
|
||||
|
||||
@Post('public/foods/favorite/:foodId')
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiHeader({
|
||||
name: 'X-Slug',
|
||||
required: true,
|
||||
schema: {
|
||||
type: 'string',
|
||||
default: 'zhivan',
|
||||
},
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Set a food as favorite' })
|
||||
@ApiParam({ name: 'foodId', required: true })
|
||||
setAsFavorute(@Param('foodId') foodId: string, @UserId() userId: string) {
|
||||
return this.foodsService.addFavorite(userId, foodId);
|
||||
}
|
||||
|
||||
@Delete('public/foods/favorite/:foodId')
|
||||
@UseGuards(AuthGuard)
|
||||
@ApiHeader({
|
||||
name: 'X-Slug',
|
||||
required: true,
|
||||
schema: {
|
||||
type: 'string',
|
||||
default: 'zhivan',
|
||||
},
|
||||
})
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Remove a food favorite' })
|
||||
@ApiParam({ name: 'foodId', required: true })
|
||||
removeFavorite(@Param('foodId') foodId: string, @UserId() userId: string) {
|
||||
return this.foodsService.removeFavorite(userId, foodId);
|
||||
}
|
||||
|
||||
@UseGuards(AdminAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@Post('admin/foods')
|
||||
@Post('admin/foods')
|
||||
@ApiOperation({ summary: 'Create a new food' })
|
||||
@ApiCreatedResponse({ description: 'The food has been successfully created.', type: CreateFoodDto })
|
||||
@ApiBody({ type: CreateFoodDto })
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { Entity, ManyToOne, Unique } from '@mikro-orm/core';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
import { Food } from '../../foods/entities/food.entity';
|
||||
|
||||
@Entity({ tableName: 'favorites' })
|
||||
@Unique({ properties: ['user', 'food'] })
|
||||
export class Favorite extends BaseEntity {
|
||||
@ManyToOne(() => User)
|
||||
user: User;
|
||||
|
||||
@ManyToOne(() => Food)
|
||||
food: Food;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { Restaurant } from '../../../modules/restaurants/entities/restaurant.ent
|
||||
import { Review } from 'src/modules/review/entities/review.entity';
|
||||
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
||||
import { MealType } from '../interface/food.interface';
|
||||
import { Favorite } from './favorite.entity';
|
||||
|
||||
@Entity({ tableName: 'foods' })
|
||||
@Index({ properties: ['restaurant', 'isActive'] })
|
||||
@@ -26,6 +27,9 @@ export class Food extends BaseEntity {
|
||||
})
|
||||
inventory?: Inventory;
|
||||
|
||||
@OneToMany(() => Favorite, favorite => favorite.food)
|
||||
favorites = new Collection<Favorite>(this);
|
||||
|
||||
@Property({ nullable: true })
|
||||
title?: string;
|
||||
|
||||
|
||||
@@ -12,11 +12,12 @@ import { RestaurantsModule } from '../restaurants/restaurants.module';
|
||||
import { AuthModule } from '../auth/auth.module';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { UtilsModule } from '../utils/utils.module';
|
||||
import { Favorite } from './entities/favorite.entity';
|
||||
|
||||
@Module({
|
||||
imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule, UtilsModule],
|
||||
imports: [MikroOrmModule.forFeature([Food, Category, Favorite]), RestaurantsModule, AuthModule, JwtModule, UtilsModule],
|
||||
controllers: [FoodController, CategoryController],
|
||||
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
||||
exports: [FoodRepository, CategoryRepository],
|
||||
})
|
||||
export class FoodModule {}
|
||||
export class FoodModule { }
|
||||
|
||||
@@ -9,6 +9,7 @@ import { Food } from '../entities/food.entity';
|
||||
import { CategoryMessage, FoodMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
||||
import { CacheService } from '../../utils/cache.service';
|
||||
import { Favorite } from '../entities/favorite.entity';
|
||||
|
||||
@Injectable()
|
||||
export class FoodService {
|
||||
@@ -76,10 +77,17 @@ export class FoodService {
|
||||
/**
|
||||
* 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'] });
|
||||
async findPublicById(foodId: string, userId?: string):Promise<any> {
|
||||
const food = await this.foodRepository.findOne({ id: foodId, isActive: true }, { populate: ['category'] });
|
||||
if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||
return food;
|
||||
let isFavorite = false
|
||||
if (userId) {
|
||||
isFavorite = await this.em.count(Favorite, { user: { id: userId }, food: { id: foodId } }) > 0
|
||||
}
|
||||
return {
|
||||
...food,
|
||||
isFavorite,
|
||||
};;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,6 +95,7 @@ export class FoodService {
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -164,6 +173,23 @@ export class FoodService {
|
||||
await this.invalidateRestaurantFoodsCache(restaurantSlug);
|
||||
}
|
||||
|
||||
async removeFavorite(userId: string, foodId: string) {
|
||||
return this.em.nativeDelete(Favorite, {
|
||||
user: userId,
|
||||
food: foodId,
|
||||
});
|
||||
}
|
||||
|
||||
async addFavorite(userId: string, foodId: string) {
|
||||
const favorite = this.em.create(Favorite, {
|
||||
user: userId,
|
||||
food: foodId,
|
||||
});
|
||||
|
||||
await this.em.persistAndFlush(favorite);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invalidate cache for restaurant foods
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user