diff --git a/src/core/app.module.ts b/src/core/app.module.ts index 09f0706..3baaae2 100644 --- a/src/core/app.module.ts +++ b/src/core/app.module.ts @@ -7,6 +7,7 @@ import { AuthModule } from '../modules/auth/auth.module' import { CategoryModule } from '../modules/category/category.module' import { MediaModule } from '../modules/media/media.module' import { MovieModule } from '../modules/movie/movie.module' +import { TheaterModule } from '../modules/theater/theater.module' import { UsersModule } from '../modules/users/users.module' import { ObservabilityModule } from '../observability/observability.module' @@ -31,6 +32,7 @@ import { getPassportConfig } from './config' UsersModule, MovieModule, CategoryModule, + TheaterModule, PassportModule.registerAsync({ useFactory: getPassportConfig, inject: [ConfigService] diff --git a/src/modules/account/account.module.ts b/src/modules/account/account.module.ts index 1c9218e..00c43f8 100644 --- a/src/modules/account/account.module.ts +++ b/src/modules/account/account.module.ts @@ -1,9 +1,10 @@ -import { Module } from '@nestjs/common' +import { Global, Module } from '@nestjs/common' import { GrpcModule } from '@teacinema/common' import { AccountController } from './account.controller' import { AccountClientGrpc } from './account.grpc' +@Global() @Module({ imports: [GrpcModule.register(['ACCOUNT_PACKAGE'])], controllers: [AccountController], diff --git a/src/modules/theater/dto/index.ts b/src/modules/theater/dto/index.ts new file mode 100644 index 0000000..66d0236 --- /dev/null +++ b/src/modules/theater/dto/index.ts @@ -0,0 +1 @@ +export * from './rq' diff --git a/src/modules/theater/dto/rq/create-theater.request.dto.ts b/src/modules/theater/dto/rq/create-theater.request.dto.ts new file mode 100644 index 0000000..a9eca30 --- /dev/null +++ b/src/modules/theater/dto/rq/create-theater.request.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsNotEmpty, IsString } from 'class-validator' + +export class CreateTheaterRequestDto { + @ApiProperty({ + example: 'Аврора' + }) + @IsString() + @IsNotEmpty() + public name: string + + @ApiProperty({ + example: 'г. Москва, ул. Ленина, д. 1' + }) + @IsString() + @IsNotEmpty() + public address: string +} diff --git a/src/modules/theater/dto/rq/index.ts b/src/modules/theater/dto/rq/index.ts new file mode 100644 index 0000000..c5311c5 --- /dev/null +++ b/src/modules/theater/dto/rq/index.ts @@ -0,0 +1 @@ +export * from './create-theater.request.dto' diff --git a/src/modules/theater/theater.controller.ts b/src/modules/theater/theater.controller.ts new file mode 100644 index 0000000..c1d3bed --- /dev/null +++ b/src/modules/theater/theater.controller.ts @@ -0,0 +1,34 @@ +import { + Body, + Controller, + Get, + HttpCode, + HttpStatus, + Post +} from '@nestjs/common' +import { Role } from 'src/shared/guards' + +import { Protected } from '../../shared/decorators' + +import { CreateTheaterRequestDto } from './dto' +import { TheaterClientGrpc } from './theater.grpc' + +@Controller('theaters') +export class TheaterController { + constructor(private readonly client: TheaterClientGrpc) {} + + @Get() + @HttpCode(HttpStatus.OK) + public async getAll() { + const { theaters } = await this.client.call('listTheater', {}) + return theaters + } + + @Protected(Role.ADMIN) + @Post() + @HttpCode(HttpStatus.OK) + public async create(@Body() dto: CreateTheaterRequestDto) { + const { theater } = await this.client.call('createTheater', dto) + return theater + } +} diff --git a/src/modules/theater/theater.grpc.ts b/src/modules/theater/theater.grpc.ts new file mode 100644 index 0000000..2808fda --- /dev/null +++ b/src/modules/theater/theater.grpc.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@nestjs/common' +import type { ClientGrpc } from '@nestjs/microservices' +import { InjectGrpc } from '@teacinema/common' +import { TheaterServiceClient } from '@teacinema/contracts/gen/ts/theater' + +import { AbstractGrpcClient } from '../../shared/grpc/abstract-grpc.client' + +@Injectable() +export class TheaterClientGrpc extends AbstractGrpcClient { + constructor(@InjectGrpc('THEATER_PACKAGE') client: ClientGrpc) { + super(client, 'TheaterService') + } +} diff --git a/src/modules/theater/theater.module.ts b/src/modules/theater/theater.module.ts new file mode 100644 index 0000000..a19c593 --- /dev/null +++ b/src/modules/theater/theater.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common' +import { GrpcModule } from '@teacinema/common' + +import { TheaterController } from './theater.controller' +import { TheaterClientGrpc } from './theater.grpc' + +@Module({ + imports: [GrpcModule.register(['THEATER_PACKAGE'])], + controllers: [TheaterController], + providers: [TheaterClientGrpc], + // exports: [TheaterClientGrpc] +}) +export class TheaterModule {} diff --git a/src/shared/decorators/protected.decorator.ts b/src/shared/decorators/protected.decorator.ts index 944eba7..00fe795 100644 --- a/src/shared/decorators/protected.decorator.ts +++ b/src/shared/decorators/protected.decorator.ts @@ -1,7 +1,6 @@ import { applyDecorators, UseGuards } from '@nestjs/common' -import { Role } from '@teacinema/contracts/gen/ts/account' -import { AuthGuard, RolesGuard } from '../guards' +import { AuthGuard, Role, RolesGuard } from '../guards' import { Roles } from './roles.decorator' diff --git a/src/shared/decorators/roles.decorator.ts b/src/shared/decorators/roles.decorator.ts index bfa8007..8e876a6 100644 --- a/src/shared/decorators/roles.decorator.ts +++ b/src/shared/decorators/roles.decorator.ts @@ -1,5 +1,6 @@ import { SetMetadata } from '@nestjs/common' -import { Role } from '@teacinema/contracts/gen/ts/account' + +import { Role } from '../guards' export const ROLES_KEY = 'required_roles' diff --git a/src/shared/guards/roles.guard.ts b/src/shared/guards/roles.guard.ts index c22296c..c939700 100644 --- a/src/shared/guards/roles.guard.ts +++ b/src/shared/guards/roles.guard.ts @@ -6,12 +6,17 @@ import { NotFoundException } from '@nestjs/common' import { Reflector } from '@nestjs/core' -import { Role } from '@teacinema/contracts/gen/ts/account' import { Request } from 'express' import { AccountClientGrpc } from '../../modules/account/account.grpc' import { ROLES_KEY } from '../decorators' +export enum Role { + USER = 0, + ADMIN = 1, + UNRECOGNIZED = -1 +} + @Injectable() export class RolesGuard implements CanActivate { public constructor( diff --git a/yarn.lock b/yarn.lock index 742904a..3011e55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1028,9 +1028,9 @@ tslib "2.8.1" "@nestjs/common@^11.1.16": - version "11.1.18" - resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-11.1.18.tgz#329b214aadea5a4a1b12b4eee61c32b9c5b5082c" - integrity sha512-0sLq8Z+TIjLnz1Tqp0C/x9BpLbqpt1qEu0VcH4/fkE0y3F5JxhfK1AdKQ/SPbKhKgwqVDoY4gS8GQr2G6ujaWg== + version "11.1.19" + resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-11.1.19.tgz#50ba93ae45ebaeda6163554b8e2ecec545a25c92" + integrity sha512-qeiTt2tv+e5QyDKqG8HlVZb2wx64FEaSGFJouqTSRs+kG44iTfl3xlz1XqVped+rihx4hmjWgL5gkhtdK3E6+Q== dependencies: uid "2.0.2" file-type "21.3.4" @@ -1094,9 +1094,9 @@ tslib "2.8.1" "@nestjs/microservices@^11.1.16": - version "11.1.18" - resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-11.1.18.tgz#3f5edd756e32f7c85c1c67c65f8ba3b62a736ebf" - integrity sha512-sodzBqqKAcOv5GctTbb0j3vzgx+X3/IxmJ8pBKL9hEmsarsYPkig6dcOcVFmM2Pknm+o6Cxaqv1YZZETISNi+w== + version "11.1.19" + resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-11.1.19.tgz#0222ca2331a2a702df3b4dd6b7fd2fe7487fb39a" + integrity sha512-3Oja56ydTlSaui19/i7gYM0MMqz/w4UR2aqZeL4K8B+Fq0Ztg3zHb8et76atToJGpSCevJLEsoEMOMaGgzRwfg== dependencies: iterare "1.2.1" tslib "2.8.1" @@ -1997,9 +1997,9 @@ "@sinonjs/commons" "^3.0.1" "@teacinema/common@^1.0.0": - version "1.3.2" - resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcommon/-/1.3.2/common-1.3.2.tgz#51ef68a7a92bb9fbd604052953a10b84846ddd77" - integrity sha512-uD83OWCPZrjDknQNvDGz90WyHDHsRvzn/kE3ofK5oToOOG5f0WXrq0vr1UGi7+DZzTbRfsUe06mgMyahuJ/j4w== + 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== 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.2.3" - resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.2.3/contracts-1.2.3.tgz#d356a9dc7395b304a9d5ab639565fa9bcebb9c74" - integrity sha512-Rvw8DVmIpRD/I2Yk1gQyO8ZmxyOIY3FW+purxwiLBIi22gHQtVAXV27a9xK6sO/XXHx70KhrY/8fU8JH/+ehkw== + 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== dependencies: "@nestjs/microservices" "^11.1.12" protoc "33.4.0"