diff --git a/src/core/app.module.ts b/src/core/app.module.ts index 3baaae2..2274a5d 100644 --- a/src/core/app.module.ts +++ b/src/core/app.module.ts @@ -5,8 +5,10 @@ import { PassportModule } from '@teacinema/passport' import { AccountModule } from '../modules/account/account.module' import { AuthModule } from '../modules/auth/auth.module' import { CategoryModule } from '../modules/category/category.module' +import { HallModule } from '../modules/hall/hall.module' import { MediaModule } from '../modules/media/media.module' import { MovieModule } from '../modules/movie/movie.module' +import { SeatModule } from '../modules/seat/seat.module' import { TheaterModule } from '../modules/theater/theater.module' import { UsersModule } from '../modules/users/users.module' import { ObservabilityModule } from '../observability/observability.module' @@ -33,6 +35,8 @@ import { getPassportConfig } from './config' MovieModule, CategoryModule, TheaterModule, + HallModule, + SeatModule, PassportModule.registerAsync({ useFactory: getPassportConfig, inject: [ConfigService] diff --git a/src/modules/hall/dto/index.ts b/src/modules/hall/dto/index.ts new file mode 100644 index 0000000..66d0236 --- /dev/null +++ b/src/modules/hall/dto/index.ts @@ -0,0 +1 @@ +export * from './rq' diff --git a/src/modules/hall/dto/rq/create-hall.request.dto.ts b/src/modules/hall/dto/rq/create-hall.request.dto.ts new file mode 100644 index 0000000..12143b9 --- /dev/null +++ b/src/modules/hall/dto/rq/create-hall.request.dto.ts @@ -0,0 +1,67 @@ +import { Body, Controller, Get, HttpCode, HttpStatus } from '@nestjs/common' +import { ApiProperty } from '@nestjs/swagger' +import type { ListHallsByTheaterRequest } from '@teacinema/contracts/gen/ts/hall' +import { Type } from 'class-transformer' +import { + IsArray, + IsEnum, + IsInt, + IsNotEmpty, + IsNumber, + IsString, + ValidateNested +} from 'class-validator' + +enum SeatType { + CHAIR = 'chair', + SOFA2 = 'sofa2', + SOFA3 = 'sofa3' +} + +class RowConfig { + @ApiProperty({ + example: 1 + }) + @IsNumber() + public row: number + + @ApiProperty({ + example: 15 + }) + @IsNumber() + public columns: number + + @ApiProperty({ + example: SeatType.CHAIR, + enum: SeatType + }) + @IsEnum(SeatType) + public type: SeatType + + @ApiProperty({ + example: 500 + }) + @IsInt() + public price: number +} + +export class CreateHallRequestDto { + @ApiProperty({ + example: 'Зал 1' + }) + @IsString() + @IsNotEmpty() + public name: string + + @ApiProperty({ + example: '123456' + }) + @IsString() + @IsNotEmpty() + public theaterId: string + + @IsArray() + @ValidateNested({ each: true }) + @Type(() => RowConfig) + public layout: RowConfig[] +} diff --git a/src/modules/hall/dto/rq/index.ts b/src/modules/hall/dto/rq/index.ts new file mode 100644 index 0000000..3f75e70 --- /dev/null +++ b/src/modules/hall/dto/rq/index.ts @@ -0,0 +1 @@ +export * from './create-hall.request.dto' diff --git a/src/modules/hall/hall.controller.ts b/src/modules/hall/hall.controller.ts new file mode 100644 index 0000000..b7cfe0f --- /dev/null +++ b/src/modules/hall/hall.controller.ts @@ -0,0 +1,44 @@ +import { + Body, + Controller, + Get, + HttpCode, + HttpStatus, + Param, + Post +} from '@nestjs/common' +import type { ListHallsByTheaterRequest } from '@teacinema/contracts/gen/ts/hall' +import { Role } from 'src/shared/guards' + +import { Protected } from '../../shared/decorators' + +import { CreateHallRequestDto } from './dto' +import { HallClientGrpc } from './hall.grpc' + +@Controller('halls') +export class HallController { + constructor(private readonly client: HallClientGrpc) {} + + @Get() + @HttpCode(HttpStatus.OK) + public async getAll(@Body() data: ListHallsByTheaterRequest) { + const { halls } = await this.client.call('listHallsByTheater', data) + return halls + } + + @Get(':id') + @HttpCode(HttpStatus.OK) + public async getById(@Param('id') id: string) { + const { hall } = await this.client.call('getHall', { id }) + + return hall + } + + // @Protected(Role.ADMIN) + @Post() + @HttpCode(HttpStatus.CREATED) + public async create(@Body() dto: CreateHallRequestDto) { + const { hall } = await this.client.call('createHall', dto) + return hall + } +} diff --git a/src/modules/hall/hall.grpc.ts b/src/modules/hall/hall.grpc.ts new file mode 100644 index 0000000..32041f2 --- /dev/null +++ b/src/modules/hall/hall.grpc.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common' +import type { ClientGrpc } from '@nestjs/microservices' +import { InjectGrpc } from '@teacinema/common' +import { HallServiceClient } from '@teacinema/contracts/gen/ts/hall' + +import { AbstractGrpcClient } from '../../shared/grpc/abstract-grpc.client' + +@Injectable() +export class HallClientGrpc extends AbstractGrpcClient { + constructor(@InjectGrpc('HALL_PACKAGE') client: ClientGrpc) { + super(client, 'HallService') + } +} diff --git a/src/modules/hall/hall.module.ts b/src/modules/hall/hall.module.ts new file mode 100644 index 0000000..5659551 --- /dev/null +++ b/src/modules/hall/hall.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common' +import { GrpcModule } from '@teacinema/common' + +import { HallController } from './hall.controller' +import { HallClientGrpc } from './hall.grpc' + +@Module({ + imports: [GrpcModule.register(['HALL_PACKAGE'])], + controllers: [HallController], + providers: [HallClientGrpc] +}) +export class HallModule {} diff --git a/src/modules/seat/seat.controller.ts b/src/modules/seat/seat.controller.ts new file mode 100644 index 0000000..3c006b3 --- /dev/null +++ b/src/modules/seat/seat.controller.ts @@ -0,0 +1,36 @@ +import { + Body, + Controller, + Get, + HttpCode, + HttpStatus, + Param +} from '@nestjs/common' + +import { SeatClientGrpc } from './seat.grpc' + +@Controller('seats') +export class SeatController { + constructor(private readonly client: SeatClientGrpc) {} + + @Get(':hallId/:screeningId') + @HttpCode(HttpStatus.OK) + public async getAll( + @Param('hallId') hallId: string, + @Param('screeningId') screeningId: string + ) { + const { seats } = await this.client.call('listSeatsByHall', { + hallId, + screeningId + }) + return seats + } + + @Get(':id') + @HttpCode(HttpStatus.OK) + public async getById(@Param('id') id: string) { + const { seat } = await this.client.call('getSeat', { id }) + + return seat + } +} diff --git a/src/modules/seat/seat.grpc.ts b/src/modules/seat/seat.grpc.ts new file mode 100644 index 0000000..2dc323b --- /dev/null +++ b/src/modules/seat/seat.grpc.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common' +import type { ClientGrpc } from '@nestjs/microservices' +import { InjectGrpc } from '@teacinema/common' +import { SeatServiceClient } from '@teacinema/contracts/gen/ts/seat' + +import { AbstractGrpcClient } from '../../shared/grpc/abstract-grpc.client' + +@Injectable() +export class SeatClientGrpc extends AbstractGrpcClient { + constructor(@InjectGrpc('SEAT_PACKAGE') client: ClientGrpc) { + super(client, 'SeatService') + } +} diff --git a/src/modules/seat/seat.module.ts b/src/modules/seat/seat.module.ts new file mode 100644 index 0000000..40bcff5 --- /dev/null +++ b/src/modules/seat/seat.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common' +import { GrpcModule } from '@teacinema/common' + +import { SeatController } from './seat.controller' +import { SeatClientGrpc } from './seat.grpc' + +@Module({ + imports: [GrpcModule.register(['SEAT_PACKAGE'])], + controllers: [SeatController], + providers: [SeatClientGrpc] +}) +export class SeatModule {} diff --git a/yarn.lock b/yarn.lock index 3011e55..1d0e139 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1997,9 +1997,9 @@ "@sinonjs/commons" "^3.0.1" "@teacinema/common@^1.0.0": - version "1.4.0" - resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.4.0/common-1.4.0.tgz#9523c8a5a54c54b4756f2bc4db5d2cabb60504f2" - integrity sha512-M2c95xPg/lSG5Vz9tkqheuKzrd5m0HDtZdBEpPVehkTjk81GmSywyZr/HMBEl4GU/cQG93Xza//l3yCP7JnaZg== + version "1.5.0" + resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.5.0/common-1.5.0.tgz#236c1aba248b31773297bf17aad9053116483e93" + integrity sha512-GqGx8jFaMP6ADcZP18ariJtAHbJqLhT9Up80SLwU1fInKUthQb5MzLrTc4ce8jAxbczLVMGmikphIQNYNpvCGg== dependencies: "@nestjs/common" "^11.1.16" "@nestjs/config" "^4.0.3" @@ -2007,9 +2007,9 @@ "@teacinema/contracts" "^1.1.3" "@teacinema/contracts@^1.0.0", "@teacinema/contracts@^1.1.3": - version "1.3.2" - resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.3.2/contracts-1.3.2.tgz#4abd896c2af5030ec049b34f978aa52554e6b03d" - integrity sha512-myXVPXPDOzSxixIAh8LuIMg84ftBHSKht9sySLnztrQfssutg4Hz5590aQIMlgUooHBiC/Gu/6sCUEkfeFOofQ== + version "1.4.1" + resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.4.1/contracts-1.4.1.tgz#20feccf1784a41ad6b4b0ebfcc035f991a7473c9" + integrity sha512-CcYU/cUQfBw+KJp8d14RONIZahkbUAYxiLqudHhx/kpEPuoQDO8VMJy6SbUqBM1HKZ1VTtyQWfxm/79PBPMe0g== dependencies: "@nestjs/microservices" "^11.1.12" protoc "33.4.0"