favorite
This commit is contained in:
@@ -16,7 +16,9 @@ import {
|
|||||||
ApiHeader,
|
ApiHeader,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
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')
|
@ApiTags('foods')
|
||||||
@Controller()
|
@Controller()
|
||||||
@@ -39,13 +41,57 @@ export class FoodController {
|
|||||||
return this.foodsService.findAllByRestaurant(slug);
|
return this.foodsService.findAllByRestaurant(slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Get('public/foods/:foodId')
|
@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' })
|
@ApiOperation({ summary: 'Get a food by id' })
|
||||||
@ApiParam({ name: 'foodId', required: true })
|
@ApiParam({ name: 'foodId', required: true })
|
||||||
@ApiOkResponse({ description: 'The food', type: CreateFoodDto })
|
findPublicFoodById(@Param('foodId') foodId: string, @UserId() userId?: string):Promise<any> {
|
||||||
@ApiNotFoundResponse({ description: 'Food not found' })
|
const a= this.foodsService.findPublicById(foodId, userId);
|
||||||
findPublicFoodById(@Param('foodId') foodId: string) {
|
return a
|
||||||
return this.foodsService.findPublicById(foodId);
|
}
|
||||||
|
|
||||||
|
@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)
|
@UseGuards(AdminAuthGuard)
|
||||||
|
|||||||
@@ -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 { Review } from 'src/modules/review/entities/review.entity';
|
||||||
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
import { Inventory } from 'src/modules/inventory/entities/inventory.entity';
|
||||||
import { MealType } from '../interface/food.interface';
|
import { MealType } from '../interface/food.interface';
|
||||||
|
import { Favorite } from './favorite.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'foods' })
|
@Entity({ tableName: 'foods' })
|
||||||
@Index({ properties: ['restaurant', 'isActive'] })
|
@Index({ properties: ['restaurant', 'isActive'] })
|
||||||
@@ -26,6 +27,9 @@ export class Food extends BaseEntity {
|
|||||||
})
|
})
|
||||||
inventory?: Inventory;
|
inventory?: Inventory;
|
||||||
|
|
||||||
|
@OneToMany(() => Favorite, favorite => favorite.food)
|
||||||
|
favorites = new Collection<Favorite>(this);
|
||||||
|
|
||||||
@Property({ nullable: true })
|
@Property({ nullable: true })
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ import { RestaurantsModule } from '../restaurants/restaurants.module';
|
|||||||
import { AuthModule } from '../auth/auth.module';
|
import { AuthModule } from '../auth/auth.module';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { UtilsModule } from '../utils/utils.module';
|
import { UtilsModule } from '../utils/utils.module';
|
||||||
|
import { Favorite } from './entities/favorite.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule, UtilsModule],
|
imports: [MikroOrmModule.forFeature([Food, Category, Favorite]), RestaurantsModule, AuthModule, JwtModule, UtilsModule],
|
||||||
controllers: [FoodController, CategoryController],
|
controllers: [FoodController, CategoryController],
|
||||||
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
||||||
exports: [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 { CategoryMessage, FoodMessage, RestMessage } from 'src/common/enums/message.enum';
|
||||||
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
import { RestRepository } from 'src/modules/restaurants/repositories/rest.repository';
|
||||||
import { CacheService } from '../../utils/cache.service';
|
import { CacheService } from '../../utils/cache.service';
|
||||||
|
import { Favorite } from '../entities/favorite.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FoodService {
|
export class FoodService {
|
||||||
@@ -76,10 +77,17 @@ export class FoodService {
|
|||||||
/**
|
/**
|
||||||
* Public food detail (only active foods are visible).
|
* Public food detail (only active foods are visible).
|
||||||
*/
|
*/
|
||||||
async findPublicById(id: string): Promise<Food> {
|
async findPublicById(foodId: string, userId?: string):Promise<any> {
|
||||||
const food = await this.foodRepository.findOne({ id, isActive: true }, { populate: ['category'] });
|
const food = await this.foodRepository.findOne({ id: foodId, isActive: true }, { populate: ['category'] });
|
||||||
if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
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> {
|
async findAdminById(restId: string, id: string): Promise<Food> {
|
||||||
const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['category'] });
|
const food = await this.foodRepository.findOne({ id, restaurant: { id: restId } }, { populate: ['category'] });
|
||||||
|
|
||||||
if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
if (!food) throw new NotFoundException(FoodMessage.NOT_FOUND);
|
||||||
return food;
|
return food;
|
||||||
}
|
}
|
||||||
@@ -164,6 +173,23 @@ export class FoodService {
|
|||||||
await this.invalidateRestaurantFoodsCache(restaurantSlug);
|
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
|
* Invalidate cache for restaurant foods
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OrdersCrone {
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user