auth
This commit is contained in:
+1
-1
@@ -47,7 +47,7 @@ import { FoodModule } from './modules/foods/food.module';
|
|||||||
FoodModule,
|
FoodModule,
|
||||||
],
|
],
|
||||||
controllers: [],
|
controllers: [],
|
||||||
// providers: [CacheService],
|
providers: [],
|
||||||
// exports: [CacheService],
|
// exports: [CacheService],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { RestaurantsModule } from '../restaurants/restaurants.module';
|
|||||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||||
import { User } from '../users/entities/user.entity';
|
import { User } from '../users/entities/user.entity';
|
||||||
import { AdminAuthController } from './controllers/admin-auth.controller';
|
import { AdminAuthController } from './controllers/admin-auth.controller';
|
||||||
|
import { AdminAuthGuard } from './guards/adminAuth.guard';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -31,6 +32,7 @@ import { AdminAuthController } from './controllers/admin-auth.controller';
|
|||||||
MikroOrmModule.forFeature([User]),
|
MikroOrmModule.forFeature([User]),
|
||||||
],
|
],
|
||||||
controllers: [AuthController, AdminAuthController],
|
controllers: [AuthController, AdminAuthController],
|
||||||
providers: [AuthService, TokensService],
|
providers: [AuthService, TokensService, AdminAuthGuard],
|
||||||
|
exports: [AdminAuthGuard],
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
export class AuthModule {}
|
||||||
|
|||||||
@@ -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 { Request } from 'express';
|
||||||
import { JwtService } from '@nestjs/jwt';
|
import { JwtService } from '@nestjs/jwt';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { ITokenPayload } from '../interfaces/IToken-payload';
|
import { IAdminTokenPayload } from '../interfaces/IToken-payload';
|
||||||
|
|
||||||
export interface AuthRequest extends Request {
|
export interface AdminAuthRequest extends Request {
|
||||||
userId: string;
|
adminId: string;
|
||||||
restId: string;
|
restId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdminAuthGuard implements CanActivate {
|
export class AdminAuthGuard implements CanActivate {
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(JwtService)
|
||||||
private readonly jwtService: JwtService,
|
private readonly jwtService: JwtService,
|
||||||
|
@Inject(ConfigService)
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext) {
|
async canActivate(context: ExecutionContext) {
|
||||||
const request = context.switchToHttp().getRequest<AuthRequest>();
|
const request = context.switchToHttp().getRequest<AdminAuthRequest>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const secret = this.configService.get<string>('JWT_SECRET');
|
const secret = this.configService.get<string>('JWT_SECRET');
|
||||||
@@ -27,10 +29,10 @@ export class AdminAuthGuard implements CanActivate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const payload = await this.jwtService.verifyAsync<ITokenPayload>(token, {
|
const payload = await this.jwtService.verifyAsync<IAdminTokenPayload>(token, {
|
||||||
secret,
|
secret,
|
||||||
});
|
});
|
||||||
request['userId'] = payload.userId;
|
request['adminId'] = payload.adminId;
|
||||||
request['restId'] = payload.restId;
|
request['restId'] = payload.restId;
|
||||||
} catch {
|
} catch {
|
||||||
throw new UnauthorizedException();
|
throw new UnauthorizedException();
|
||||||
|
|||||||
@@ -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 { FoodService } from '../providers/food.service';
|
||||||
import { CreateFoodDto } from '../dto/create-food.dto';
|
import { CreateFoodDto } from '../dto/create-food.dto';
|
||||||
import { UpdateFoodDto } from '../dto/update-food.dto';
|
import { UpdateFoodDto } from '../dto/update-food.dto';
|
||||||
@@ -14,7 +14,10 @@ import {
|
|||||||
ApiBody,
|
ApiBody,
|
||||||
ApiParam,
|
ApiParam,
|
||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
|
import { AdminAuthGuard } from 'src/modules/auth/guards/adminAuth.guard';
|
||||||
|
import { RestId } from 'src/common/decorators';
|
||||||
|
|
||||||
|
@UseGuards(AdminAuthGuard)
|
||||||
@ApiTags('foods')
|
@ApiTags('foods')
|
||||||
@Controller('foods')
|
@Controller('foods')
|
||||||
export class FoodController {
|
export class FoodController {
|
||||||
@@ -24,8 +27,8 @@ export class FoodController {
|
|||||||
@ApiOperation({ summary: 'Create a new food' })
|
@ApiOperation({ summary: 'Create a new food' })
|
||||||
@ApiCreatedResponse({ description: 'The food has been successfully created.', type: CreateFoodDto })
|
@ApiCreatedResponse({ description: 'The food has been successfully created.', type: CreateFoodDto })
|
||||||
@ApiBody({ type: CreateFoodDto })
|
@ApiBody({ type: CreateFoodDto })
|
||||||
create(@Body() createFoodDto: CreateFoodDto) {
|
create(@Body() createFoodDto: CreateFoodDto, @RestId() restId: string) {
|
||||||
return this.foodsService.create(createFoodDto);
|
return this.foodsService.create(restId, createFoodDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@@ -38,8 +41,8 @@ export class FoodController {
|
|||||||
@ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] })
|
@ApiQuery({ name: 'order', required: false, enum: ['asc', 'desc'] })
|
||||||
@ApiQuery({ name: 'categoryId', required: false, type: String })
|
@ApiQuery({ name: 'categoryId', required: false, type: String })
|
||||||
@ApiQuery({ name: 'isActive', required: false, type: Boolean })
|
@ApiQuery({ name: 'isActive', required: false, type: Boolean })
|
||||||
findAll(@Query() dto: FindFoodsDto) {
|
findAll(@Query() dto: FindFoodsDto,@RestId() restId: string) {
|
||||||
return this.foodsService.findAll(dto);
|
return this.foodsService.findAll(restId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
|
|||||||
@@ -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 { Category } from './category.entity';
|
||||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||||
|
import { Restaurant } from 'src/modules/restaurants/entities/restaurant.entity';
|
||||||
|
|
||||||
@Entity({ tableName: 'foods' })
|
@Entity({ tableName: 'foods' })
|
||||||
export class Food extends BaseEntity {
|
export class Food extends BaseEntity {
|
||||||
|
@OneToOne(() => Restaurant)
|
||||||
|
restaurant: Restaurant;
|
||||||
|
|
||||||
@ManyToMany(() => Category)
|
@ManyToMany(() => Category)
|
||||||
categories = new Collection<Category>(this);
|
categories = new Collection<Category>(this);
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,12 @@ import { CategoryRepository } from './repositories/category.repository';
|
|||||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||||
import { Category } from './entities/category.entity';
|
import { Category } from './entities/category.entity';
|
||||||
import { Food } from './entities/food.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({
|
@Module({
|
||||||
imports: [MikroOrmModule.forFeature([Food, Category])],
|
imports: [MikroOrmModule.forFeature([Food, Category]), RestaurantsModule, AuthModule, JwtModule],
|
||||||
controllers: [FoodController, CategoryController],
|
controllers: [FoodController, CategoryController],
|
||||||
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
providers: [FoodService, CategoryService, FoodRepository, CategoryRepository],
|
||||||
exports: [FoodRepository, CategoryRepository],
|
exports: [FoodRepository, CategoryRepository],
|
||||||
|
|||||||
@@ -6,24 +6,24 @@ import { CategoryRepository } from '../repositories/category.repository';
|
|||||||
import { EntityManager } from '@mikro-orm/postgresql';
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
import { RequiredEntityData } from '@mikro-orm/core';
|
import { RequiredEntityData } from '@mikro-orm/core';
|
||||||
import { Food } from '../entities/food.entity';
|
import { Food } from '../entities/food.entity';
|
||||||
import { FoodMessage } from 'src/common/enums/message.enum';
|
import { 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';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FoodService {
|
export class FoodService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly foodRepository: FoodRepository,
|
private readonly foodRepository: FoodRepository,
|
||||||
private readonly categoryRepository: CategoryRepository,
|
private readonly categoryRepository: CategoryRepository,
|
||||||
// private readonly restRepository: RestRepository,
|
private readonly restRepository: RestRepository,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(createFoodDto: CreateFoodDto): Promise<Food> {
|
async create(restId: string, createFoodDto: CreateFoodDto): Promise<Food> {
|
||||||
const { categoryIds, ...rest } = createFoodDto;
|
const { categoryIds, ...rest } = createFoodDto;
|
||||||
// const restaurant = await this.restRepository.findOne({ id: createFoodDto.restId });
|
const restaurant = await this.restRepository.findOne({ id: restId });
|
||||||
// if (!restaurant) {
|
if (!restaurant) {
|
||||||
// throw new NotFoundException(RestMessage.NOT_FOUND);
|
throw new NotFoundException(RestMessage.NOT_FOUND);
|
||||||
// }
|
}
|
||||||
// prepare data with defaults for required fields so repository.create typing is satisfied
|
// prepare data with defaults for required fields so repository.create typing is satisfied
|
||||||
const data: RequiredEntityData<Food> = {
|
const data: RequiredEntityData<Food> = {
|
||||||
// boolean/day flags
|
// boolean/day flags
|
||||||
@@ -48,9 +48,10 @@ export class FoodService {
|
|||||||
points: rest.points ?? 0,
|
points: rest.points ?? 0,
|
||||||
prepareTime: rest.prepareTime ?? 0,
|
prepareTime: rest.prepareTime ?? 0,
|
||||||
images: rest.images ?? undefined,
|
images: rest.images ?? undefined,
|
||||||
} as RequiredEntityData<Food>;
|
restaurant: restaurant,
|
||||||
|
};
|
||||||
|
|
||||||
const food = this.foodRepository.create(data) as Food;
|
const food = this.foodRepository.create(data);
|
||||||
if (!food) {
|
if (!food) {
|
||||||
throw new Error('Failed to create food entity');
|
throw new Error('Failed to create food entity');
|
||||||
}
|
}
|
||||||
@@ -65,8 +66,8 @@ export class FoodService {
|
|||||||
return food;
|
return food;
|
||||||
}
|
}
|
||||||
|
|
||||||
findAll(dto: FindFoodsDto) {
|
findAll(restId: string, dto: FindFoodsDto) {
|
||||||
return this.foodRepository.findAllPaginated(dto);
|
return this.foodRepository.findAllPaginated(restId, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
findOne(id: string) {
|
findOne(id: string) {
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ export class FoodRepository extends EntityRepository<Food> {
|
|||||||
* Find foods with pagination and optional filters.
|
* Find foods with pagination and optional filters.
|
||||||
* Supports: search (title/content), categoryId, isActive, ordering.
|
* Supports: search (title/content), categoryId, isActive, ordering.
|
||||||
*/
|
*/
|
||||||
async findAllPaginated(opts: FindFoodsOpts = {}): Promise<PaginatedResult<Food>> {
|
async findAllPaginated(restId: string, opts: FindFoodsOpts = {}): Promise<PaginatedResult<Food>> {
|
||||||
const { page = 1, limit = 10, search, orderBy = 'createdAt', order = 'desc', categoryId, isActive } = opts;
|
const { page = 1, limit = 10, search, orderBy = 'createdAt', order = 'desc', categoryId, isActive } = opts;
|
||||||
|
|
||||||
const offset = (page - 1) * limit;
|
const offset = (page - 1) * limit;
|
||||||
|
|
||||||
const where: FilterQuery<Food> = {};
|
const where: FilterQuery<Food> = { restaurant: { id: restId } };
|
||||||
|
|
||||||
if (typeof isActive === 'boolean') {
|
if (typeof isActive === 'boolean') {
|
||||||
where.isActive = isActive;
|
where.isActive = isActive;
|
||||||
|
|||||||
Reference in New Issue
Block a user