From e18f88a7153af1c70cdeabdaff144a7829fd1662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=A4=80=EC=88=98?= <99115509+hoheesu@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:42:03 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Rename:=20=ED=8F=B4=EB=8D=94=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/app.module.ts | 2 ++ src/auth/auth.controller.ts | 2 +- src/auth/auth.module.ts | 2 +- src/auth/{ => dto}/auth.dto.ts | 0 src/gameRoom/dto/create-gameroom.dto.ts | 1 + src/gameRoom/dto/update-gameroom.dto.ts | 4 +++ src/gameRoom/entities/gameroom.entity.ts | 1 + src/gameRoom/gameroom.controller.spec.ts | 20 ++++++++++++++ src/gameRoom/gameroom.controller.ts | 34 ++++++++++++++++++++++++ src/gameRoom/gameroom.module.ts | 9 +++++++ src/gameRoom/gameroom.service.spec.ts | 18 +++++++++++++ src/gameRoom/gameroom.service.ts | 26 ++++++++++++++++++ src/user/{ => dto}/user.dto.ts | 0 src/user/{ => entities}/user.entity.ts | 0 src/user/user.controller.ts | 2 +- src/user/user.module.ts | 2 +- src/user/user.service.ts | 2 +- 18 files changed, 121 insertions(+), 5 deletions(-) rename src/auth/{ => dto}/auth.dto.ts (100%) create mode 100644 src/gameRoom/dto/create-gameroom.dto.ts create mode 100644 src/gameRoom/dto/update-gameroom.dto.ts create mode 100644 src/gameRoom/entities/gameroom.entity.ts create mode 100644 src/gameRoom/gameroom.controller.spec.ts create mode 100644 src/gameRoom/gameroom.controller.ts create mode 100644 src/gameRoom/gameroom.module.ts create mode 100644 src/gameRoom/gameroom.service.spec.ts create mode 100644 src/gameRoom/gameroom.service.ts rename src/user/{ => dto}/user.dto.ts (100%) rename src/user/{ => entities}/user.entity.ts (100%) diff --git a/package.json b/package.json index 77d9e5c..02c778d 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.0.0", + "@nestjs/mapped-types": "*", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", diff --git a/src/app.module.ts b/src/app.module.ts index 08e5b02..78df526 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,6 +6,7 @@ import { env } from 'process'; import { UserModule } from 'src/user/user.module'; import { AuthModule } from './auth/auth.module'; import { RedisModule } from './redis/redis.module'; +import { GameroomModule } from './gameroom/gameroom.module'; @Module({ imports: [ @@ -22,6 +23,7 @@ import { RedisModule } from './redis/redis.module'; autoLoadEntities: true, synchronize: true, }), + GameroomModule, ], controllers: [AppController], providers: [AppService], diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 20771c3..3bf0712 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -13,7 +13,7 @@ import { Response } from 'express'; import { Request } from 'express'; import { JwtService } from '@nestjs/jwt'; import { UserService } from '../user/user.service'; -import LoginUserDto from './auth.dto'; +import LoginUserDto from './dto/auth.dto'; import { JwtAuthGuard } from './auth.guard'; import { RedisService } from 'src/redis/redis.service'; diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 81b449d..dd143ba 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -5,7 +5,7 @@ import { PassportModule } from '@nestjs/passport'; import { AuthController } from './auth.controller'; import { JwtStrategy } from './jwt.strategy'; import { UserService } from '../user/user.service'; -import { User } from '../user/user.entity'; +import { User } from '../user/entities/user.entity'; import { RedisModule } from 'src/redis/redis.module'; @Module({ diff --git a/src/auth/auth.dto.ts b/src/auth/dto/auth.dto.ts similarity index 100% rename from src/auth/auth.dto.ts rename to src/auth/dto/auth.dto.ts diff --git a/src/gameRoom/dto/create-gameroom.dto.ts b/src/gameRoom/dto/create-gameroom.dto.ts new file mode 100644 index 0000000..138790d --- /dev/null +++ b/src/gameRoom/dto/create-gameroom.dto.ts @@ -0,0 +1 @@ +export class CreateGameroomDto {} diff --git a/src/gameRoom/dto/update-gameroom.dto.ts b/src/gameRoom/dto/update-gameroom.dto.ts new file mode 100644 index 0000000..0c57072 --- /dev/null +++ b/src/gameRoom/dto/update-gameroom.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateGameroomDto } from './create-gameroom.dto'; + +export class UpdateGameroomDto extends PartialType(CreateGameroomDto) {} diff --git a/src/gameRoom/entities/gameroom.entity.ts b/src/gameRoom/entities/gameroom.entity.ts new file mode 100644 index 0000000..13c1d4a --- /dev/null +++ b/src/gameRoom/entities/gameroom.entity.ts @@ -0,0 +1 @@ +export class Gameroom {} diff --git a/src/gameRoom/gameroom.controller.spec.ts b/src/gameRoom/gameroom.controller.spec.ts new file mode 100644 index 0000000..8311500 --- /dev/null +++ b/src/gameRoom/gameroom.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { GameroomController } from './gameroom.controller'; +import { GameroomService } from './gameroom.service'; + +describe('GameroomController', () => { + let controller: GameroomController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [GameroomController], + providers: [GameroomService], + }).compile(); + + controller = module.get(GameroomController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/src/gameRoom/gameroom.controller.ts b/src/gameRoom/gameroom.controller.ts new file mode 100644 index 0000000..59fcd33 --- /dev/null +++ b/src/gameRoom/gameroom.controller.ts @@ -0,0 +1,34 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; +import { GameroomService } from './gameroom.service'; +import { CreateGameroomDto } from './dto/create-gameroom.dto'; +import { UpdateGameroomDto } from './dto/update-gameroom.dto'; + +@Controller('gameroom') +export class GameroomController { + constructor(private readonly gameroomService: GameroomService) {} + + @Post() + create(@Body() createGameroomDto: CreateGameroomDto) { + return this.gameroomService.create(createGameroomDto); + } + + @Get() + findAll() { + return this.gameroomService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string) { + return this.gameroomService.findOne(+id); + } + + @Patch(':id') + update(@Param('id') id: string, @Body() updateGameroomDto: UpdateGameroomDto) { + return this.gameroomService.update(+id, updateGameroomDto); + } + + @Delete(':id') + remove(@Param('id') id: string) { + return this.gameroomService.remove(+id); + } +} diff --git a/src/gameRoom/gameroom.module.ts b/src/gameRoom/gameroom.module.ts new file mode 100644 index 0000000..9292920 --- /dev/null +++ b/src/gameRoom/gameroom.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { GameroomService } from './gameroom.service'; +import { GameroomController } from './gameroom.controller'; + +@Module({ + controllers: [GameroomController], + providers: [GameroomService], +}) +export class GameroomModule {} diff --git a/src/gameRoom/gameroom.service.spec.ts b/src/gameRoom/gameroom.service.spec.ts new file mode 100644 index 0000000..f207033 --- /dev/null +++ b/src/gameRoom/gameroom.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { GameroomService } from './gameroom.service'; + +describe('GameroomService', () => { + let service: GameroomService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [GameroomService], + }).compile(); + + service = module.get(GameroomService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/gameRoom/gameroom.service.ts b/src/gameRoom/gameroom.service.ts new file mode 100644 index 0000000..1f26e51 --- /dev/null +++ b/src/gameRoom/gameroom.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@nestjs/common'; +import { CreateGameroomDto } from './dto/create-gameroom.dto'; +import { UpdateGameroomDto } from './dto/update-gameroom.dto'; + +@Injectable() +export class GameroomService { + create(createGameroomDto: CreateGameroomDto) { + return 'This action adds a new gameroom'; + } + + findAll() { + return `This action returns all gameroom`; + } + + findOne(id: number) { + return `This action returns a #${id} gameroom`; + } + + update(id: number, updateGameroomDto: UpdateGameroomDto) { + return `This action updates a #${id} gameroom`; + } + + remove(id: number) { + return `This action removes a #${id} gameroom`; + } +} diff --git a/src/user/user.dto.ts b/src/user/dto/user.dto.ts similarity index 100% rename from src/user/user.dto.ts rename to src/user/dto/user.dto.ts diff --git a/src/user/user.entity.ts b/src/user/entities/user.entity.ts similarity index 100% rename from src/user/user.entity.ts rename to src/user/entities/user.entity.ts diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index 2532718..6e6c132 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -1,6 +1,6 @@ import { Body, Controller, Post, BadRequestException } from '@nestjs/common'; import { UserService } from './user.service'; -import SingupUserDto from './user.dto'; +import SingupUserDto from './dto/user.dto'; import { validateOrReject } from 'class-validator'; @Controller('user') diff --git a/src/user/user.module.ts b/src/user/user.module.ts index 105f745..ab1e5c0 100644 --- a/src/user/user.module.ts +++ b/src/user/user.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { User } from './user.entity'; +import { User } from './entities/user.entity'; import { UserService } from './user.service'; import { UserController } from './user.controller'; import { AuthModule } from 'src/auth/auth.module'; diff --git a/src/user/user.service.ts b/src/user/user.service.ts index c295cd6..1e82513 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -1,7 +1,7 @@ import { Injectable, BadRequestException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { User } from './user.entity'; +import { User } from './entities/user.entity'; import * as bcrypt from 'bcryptjs'; @Injectable() From 2bca3ecbb8cf8637fcc99f1933b3117e0d984664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=A4=80=EC=88=98?= <99115509+hoheesu@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:32:07 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Remove:=20gameRoom=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.module.ts | 1 + src/gameRoom/dto/create-gameroom.dto.ts | 1 - src/gameRoom/dto/update-gameroom.dto.ts | 4 --- src/gameRoom/entities/gameroom.entity.ts | 1 - src/gameRoom/gameroom.controller.spec.ts | 20 -------------- src/gameRoom/gameroom.controller.ts | 34 ------------------------ src/gameRoom/gameroom.module.ts | 9 ------- src/gameRoom/gameroom.service.spec.ts | 18 ------------- src/gameRoom/gameroom.service.ts | 26 ------------------ 9 files changed, 1 insertion(+), 113 deletions(-) delete mode 100644 src/gameRoom/dto/create-gameroom.dto.ts delete mode 100644 src/gameRoom/dto/update-gameroom.dto.ts delete mode 100644 src/gameRoom/entities/gameroom.entity.ts delete mode 100644 src/gameRoom/gameroom.controller.spec.ts delete mode 100644 src/gameRoom/gameroom.controller.ts delete mode 100644 src/gameRoom/gameroom.module.ts delete mode 100644 src/gameRoom/gameroom.service.spec.ts delete mode 100644 src/gameRoom/gameroom.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 78df526..d9eb941 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -7,6 +7,7 @@ import { UserModule } from 'src/user/user.module'; import { AuthModule } from './auth/auth.module'; import { RedisModule } from './redis/redis.module'; import { GameroomModule } from './gameroom/gameroom.module'; +import { GameroomModule } from './gameroom/gameroom.module'; @Module({ imports: [ diff --git a/src/gameRoom/dto/create-gameroom.dto.ts b/src/gameRoom/dto/create-gameroom.dto.ts deleted file mode 100644 index 138790d..0000000 --- a/src/gameRoom/dto/create-gameroom.dto.ts +++ /dev/null @@ -1 +0,0 @@ -export class CreateGameroomDto {} diff --git a/src/gameRoom/dto/update-gameroom.dto.ts b/src/gameRoom/dto/update-gameroom.dto.ts deleted file mode 100644 index 0c57072..0000000 --- a/src/gameRoom/dto/update-gameroom.dto.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateGameroomDto } from './create-gameroom.dto'; - -export class UpdateGameroomDto extends PartialType(CreateGameroomDto) {} diff --git a/src/gameRoom/entities/gameroom.entity.ts b/src/gameRoom/entities/gameroom.entity.ts deleted file mode 100644 index 13c1d4a..0000000 --- a/src/gameRoom/entities/gameroom.entity.ts +++ /dev/null @@ -1 +0,0 @@ -export class Gameroom {} diff --git a/src/gameRoom/gameroom.controller.spec.ts b/src/gameRoom/gameroom.controller.spec.ts deleted file mode 100644 index 8311500..0000000 --- a/src/gameRoom/gameroom.controller.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { GameroomController } from './gameroom.controller'; -import { GameroomService } from './gameroom.service'; - -describe('GameroomController', () => { - let controller: GameroomController; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - controllers: [GameroomController], - providers: [GameroomService], - }).compile(); - - controller = module.get(GameroomController); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/src/gameRoom/gameroom.controller.ts b/src/gameRoom/gameroom.controller.ts deleted file mode 100644 index 59fcd33..0000000 --- a/src/gameRoom/gameroom.controller.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common'; -import { GameroomService } from './gameroom.service'; -import { CreateGameroomDto } from './dto/create-gameroom.dto'; -import { UpdateGameroomDto } from './dto/update-gameroom.dto'; - -@Controller('gameroom') -export class GameroomController { - constructor(private readonly gameroomService: GameroomService) {} - - @Post() - create(@Body() createGameroomDto: CreateGameroomDto) { - return this.gameroomService.create(createGameroomDto); - } - - @Get() - findAll() { - return this.gameroomService.findAll(); - } - - @Get(':id') - findOne(@Param('id') id: string) { - return this.gameroomService.findOne(+id); - } - - @Patch(':id') - update(@Param('id') id: string, @Body() updateGameroomDto: UpdateGameroomDto) { - return this.gameroomService.update(+id, updateGameroomDto); - } - - @Delete(':id') - remove(@Param('id') id: string) { - return this.gameroomService.remove(+id); - } -} diff --git a/src/gameRoom/gameroom.module.ts b/src/gameRoom/gameroom.module.ts deleted file mode 100644 index 9292920..0000000 --- a/src/gameRoom/gameroom.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; -import { GameroomService } from './gameroom.service'; -import { GameroomController } from './gameroom.controller'; - -@Module({ - controllers: [GameroomController], - providers: [GameroomService], -}) -export class GameroomModule {} diff --git a/src/gameRoom/gameroom.service.spec.ts b/src/gameRoom/gameroom.service.spec.ts deleted file mode 100644 index f207033..0000000 --- a/src/gameRoom/gameroom.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { GameroomService } from './gameroom.service'; - -describe('GameroomService', () => { - let service: GameroomService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [GameroomService], - }).compile(); - - service = module.get(GameroomService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/src/gameRoom/gameroom.service.ts b/src/gameRoom/gameroom.service.ts deleted file mode 100644 index 1f26e51..0000000 --- a/src/gameRoom/gameroom.service.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { CreateGameroomDto } from './dto/create-gameroom.dto'; -import { UpdateGameroomDto } from './dto/update-gameroom.dto'; - -@Injectable() -export class GameroomService { - create(createGameroomDto: CreateGameroomDto) { - return 'This action adds a new gameroom'; - } - - findAll() { - return `This action returns all gameroom`; - } - - findOne(id: number) { - return `This action returns a #${id} gameroom`; - } - - update(id: number, updateGameroomDto: UpdateGameroomDto) { - return `This action updates a #${id} gameroom`; - } - - remove(id: number) { - return `This action removes a #${id} gameroom`; - } -} From 64d98dbed21f08f2f18f0598a17a26197f1409f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=A4=80=EC=88=98?= <99115509+hoheesu@users.noreply.github.com> Date: Fri, 3 Jan 2025 01:41:00 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Feat:=20=EA=B2=8C=EC=9E=84=EB=B0=A9=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1/=EC=9E=85=EC=9E=A5/=ED=87=B4=EC=9E=A5=20http?= =?UTF-8?q?=20=ED=86=B5=EC=8B=A0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 28 +++- package.json | 4 +- src/app.module.ts | 5 +- src/auth/auth.controller.ts | 6 +- src/auth/auth.guard.ts | 2 +- src/auth/jwt.strategy.ts | 28 +++- src/gameRoom/dto/createGameRoom.dto.ts | 1 + src/gameRoom/dto/updateGameRoom.dto.ts | 4 + src/gameRoom/entities/gameRoom.entity.ts | 24 ++++ src/gameRoom/entities/gameRoomUser.entity.ts | 21 +++ src/gameRoom/gameRoom.controller.ts | 47 +++++++ src/gameRoom/gameRoom.module.ts | 17 +++ src/gameRoom/gameRoom.service.ts | 134 +++++++++++++++++++ 13 files changed, 304 insertions(+), 17 deletions(-) create mode 100644 src/gameRoom/dto/createGameRoom.dto.ts create mode 100644 src/gameRoom/dto/updateGameRoom.dto.ts create mode 100644 src/gameRoom/entities/gameRoom.entity.ts create mode 100644 src/gameRoom/entities/gameRoomUser.entity.ts create mode 100644 src/gameRoom/gameRoom.controller.ts create mode 100644 src/gameRoom/gameRoom.module.ts create mode 100644 src/gameRoom/gameRoom.service.ts diff --git a/package-lock.json b/package-lock.json index c982cdd..83307d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,13 +14,14 @@ "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.0.0", + "@nestjs/mapped-types": "^2.0.6", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.0.0", "bcryptjs": "^2.4.3", - "class-transformer": "^0.1.0-beta.10", + "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cookie-parser": "^1.4.7", "dotenv": "^16.4.7", @@ -1774,6 +1775,25 @@ "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0" } }, + "node_modules/@nestjs/mapped-types": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz", + "integrity": "sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==", + "peerDependencies": { + "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", + "class-transformer": "^0.4.0 || ^0.5.0", + "class-validator": "^0.13.0 || ^0.14.0", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/passport": { "version": "10.0.3", "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-10.0.3.tgz", @@ -3748,9 +3768,9 @@ "license": "MIT" }, "node_modules/class-transformer": { - "version": "0.1.0-beta.10", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.1.0-beta.10.tgz", - "integrity": "sha512-Cq9Xd+0/k4vOHr/c1cCRwWIXqS6V+hFJ5d/delZS4931fch7pLSgv7/PP6iJb0Ka0IO0tSmV+GY3MnvUN1U42A==" + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" }, "node_modules/class-validator": { "version": "0.14.1", diff --git a/package.json b/package.json index 02c778d..9da0f65 100644 --- a/package.json +++ b/package.json @@ -25,14 +25,14 @@ "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.0.0", "@nestjs/jwt": "^10.0.0", - "@nestjs/mapped-types": "*", + "@nestjs/mapped-types": "^2.0.6", "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.0.0", "bcryptjs": "^2.4.3", - "class-transformer": "^0.1.0-beta.10", + "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "cookie-parser": "^1.4.7", "dotenv": "^16.4.7", diff --git a/src/app.module.ts b/src/app.module.ts index d9eb941..7dd9f30 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,14 +6,14 @@ import { env } from 'process'; import { UserModule } from 'src/user/user.module'; import { AuthModule } from './auth/auth.module'; import { RedisModule } from './redis/redis.module'; -import { GameroomModule } from './gameroom/gameroom.module'; -import { GameroomModule } from './gameroom/gameroom.module'; +import { GameRoomModule } from './gameRoom/gameRoom.module'; @Module({ imports: [ UserModule, AuthModule, RedisModule, + GameRoomModule, TypeOrmModule.forRoot({ type: 'mysql', host: process.env.MYSQL_HOST || 'mysql', @@ -24,7 +24,6 @@ import { GameroomModule } from './gameroom/gameroom.module'; autoLoadEntities: true, synchronize: true, }), - GameroomModule, ], controllers: [AppController], providers: [AppService], diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 3bf0712..7d884d7 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -14,7 +14,7 @@ import { Request } from 'express'; import { JwtService } from '@nestjs/jwt'; import { UserService } from '../user/user.service'; import LoginUserDto from './dto/auth.dto'; -import { JwtAuthGuard } from './auth.guard'; +import { RedisAuthGuard } from './auth.guard'; import { RedisService } from 'src/redis/redis.service'; @Controller('auth') @@ -38,7 +38,7 @@ export class AuthController { throw new HttpException('Invalid credentials', HttpStatus.UNAUTHORIZED); } - const payload = { userEmail: user.userEmail, sub: user.id }; + const payload = { userEmail: user.userEmail, userId: user.id }; const accessToken = this.jwtService.sign(payload, { expiresIn: '2h' }); const refreshToken = this.jwtService.sign(payload, { expiresIn: '7d' }); await this.redisService.set(`access:${user.userEmail}`, accessToken, 3600); @@ -60,7 +60,7 @@ export class AuthController { }; } - @UseGuards(JwtAuthGuard) + @UseGuards(RedisAuthGuard) @Get('profile') getProfile() { return { message: 'This is a protected route' }; diff --git a/src/auth/auth.guard.ts b/src/auth/auth.guard.ts index 2155290..9593486 100644 --- a/src/auth/auth.guard.ts +++ b/src/auth/auth.guard.ts @@ -2,4 +2,4 @@ import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() -export class JwtAuthGuard extends AuthGuard('jwt') {} +export class RedisAuthGuard extends AuthGuard('jwt') {} diff --git a/src/auth/jwt.strategy.ts b/src/auth/jwt.strategy.ts index 191b660..53f8321 100644 --- a/src/auth/jwt.strategy.ts +++ b/src/auth/jwt.strategy.ts @@ -1,18 +1,38 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { Strategy, ExtractJwt } from 'passport-jwt'; +import { RedisService } from 'src/redis/redis.service'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { - constructor() { + constructor(private readonly redisService: RedisService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, - secretOrKey: process.env.JWT_SECRET, // 환경변수로 관리 추천 + secretOrKey: process.env.JWT_SECRET, // 환경변수로 관리 }); } async validate(payload: any) { - return { userId: payload.sub, userEmail: payload.userEmail }; + const { userEmail, userId, exp } = payload; + + if (!userEmail || !userId) { + throw new UnauthorizedException('Invalid token payload'); + } + + // Redis에서 토큰 확인 + const storedToken = await this.redisService.get(`access:${userEmail}`); + if (!storedToken) { + throw new UnauthorizedException('Token not found in Redis'); + } + + // 만료 시간 확인 + const currentTime = Math.floor(Date.now() / 1000); + if (exp && currentTime > exp) { + throw new UnauthorizedException('Token has expired'); + } + + // 유효한 유저 정보 반환 + return { userEmail, userId }; } } diff --git a/src/gameRoom/dto/createGameRoom.dto.ts b/src/gameRoom/dto/createGameRoom.dto.ts new file mode 100644 index 0000000..70c508b --- /dev/null +++ b/src/gameRoom/dto/createGameRoom.dto.ts @@ -0,0 +1 @@ +export class CreateGameRoomDto {} diff --git a/src/gameRoom/dto/updateGameRoom.dto.ts b/src/gameRoom/dto/updateGameRoom.dto.ts new file mode 100644 index 0000000..88ccac0 --- /dev/null +++ b/src/gameRoom/dto/updateGameRoom.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateGameRoomDto } from './createGameRoom.dto'; + +export class UpdateGameRoomDto extends PartialType(CreateGameRoomDto) {} diff --git a/src/gameRoom/entities/gameRoom.entity.ts b/src/gameRoom/entities/gameRoom.entity.ts new file mode 100644 index 0000000..6447152 --- /dev/null +++ b/src/gameRoom/entities/gameRoom.entity.ts @@ -0,0 +1,24 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, +} from 'typeorm'; + +@Entity() +export class GameRoom { + @PrimaryGeneratedColumn() + id: number; + + @Column() + roomName: string; + + @Column() + maxPlayers: number; + + @Column({ default: 0 }) // 초기값 설정 + currentCount: number; + + @CreateDateColumn() + createdAt: Date; +} diff --git a/src/gameRoom/entities/gameRoomUser.entity.ts b/src/gameRoom/entities/gameRoomUser.entity.ts new file mode 100644 index 0000000..ecfa46f --- /dev/null +++ b/src/gameRoom/entities/gameRoomUser.entity.ts @@ -0,0 +1,21 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, +} from 'typeorm'; + +@Entity() +export class GameRoomUser { + @PrimaryGeneratedColumn() + id: number; + + @Column() + roomId: number; + + @Column() // 필수 입력값으로 설정 + userId: number; + + @CreateDateColumn() + joinedAt: Date; +} diff --git a/src/gameRoom/gameRoom.controller.ts b/src/gameRoom/gameRoom.controller.ts new file mode 100644 index 0000000..a0eacd7 --- /dev/null +++ b/src/gameRoom/gameRoom.controller.ts @@ -0,0 +1,47 @@ +import { + Controller, + Post, + Get, + Delete, + Body, + Param, + UseGuards, + Req, +} from '@nestjs/common'; +import { GameRoomService } from './gameRoom.service'; +import { RedisAuthGuard } from 'src/auth/auth.guard'; + +@Controller('gameRoom') +@UseGuards(RedisAuthGuard) // 컨트롤러 전체에 Guard 적용 +export class GameRoomController { + constructor(private readonly gameRoomService: GameRoomService) {} + + // 방 생성과 동시에 참가 + @Post('create') + async createRoom(@Body() body: { roomName: string }, @Req() req: any) { + const { roomName } = body; + const userId = await req.user.userId; // JWT에서 추출한 userId 사용 + + return await this.gameRoomService.createRoom(roomName, userId); + } + + // 방 참가 + @Post('join/:roomId') + async joinRoom(@Param('roomId') roomId: number, @Req() req: any) { + const userId = req.user.userId; // JWT에서 추출한 userId 사용 + return await this.gameRoomService.joinRoom(roomId, userId); + } + + // 방 나가기 + @Delete('leave/:roomId') + async leaveRoom(@Param('roomId') roomId: number, @Req() req: any) { + const userId = req.user.userId; // JWT에서 추출한 userId 사용 + return await this.gameRoomService.leaveRoom(roomId, userId); + } + + // 방 상태 조회 + @Get(':roomId') + async getRoomStatus(@Param('roomId') roomId: number) { + return await this.gameRoomService.getRoomStatus(roomId); + } +} diff --git a/src/gameRoom/gameRoom.module.ts b/src/gameRoom/gameRoom.module.ts new file mode 100644 index 0000000..6fa4543 --- /dev/null +++ b/src/gameRoom/gameRoom.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { GameRoomController } from './gameRoom.controller'; +import { GameRoomService } from './gameRoom.service'; +import { GameRoom } from './entities/gameRoom.entity'; +import { GameRoomUser } from './entities/gameRoomUser.entity'; +import { RedisModule } from 'src/redis/redis.module'; // RedisModule 추가 + +@Module({ + imports: [ + TypeOrmModule.forFeature([GameRoom, GameRoomUser]), + RedisModule, // RedisModule 가져오기 + ], + controllers: [GameRoomController], + providers: [GameRoomService], +}) +export class GameRoomModule {} diff --git a/src/gameRoom/gameRoom.service.ts b/src/gameRoom/gameRoom.service.ts new file mode 100644 index 0000000..9788402 --- /dev/null +++ b/src/gameRoom/gameRoom.service.ts @@ -0,0 +1,134 @@ +// gameRoom.service.ts +import { + Injectable, + BadRequestException, + NotFoundException, +} from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { GameRoom } from './entities/gameRoom.entity'; +import { GameRoomUser } from './entities/gameRoomUser.entity'; + +@Injectable() +export class GameRoomService { + constructor( + @InjectRepository(GameRoom) + private readonly gameRoomRepository: Repository, + @InjectRepository(GameRoomUser) + private readonly gameRoomUserRepository: Repository, + ) {} + + // 방 생성과 동시에 유저 참가 + async createRoom(roomName: string, userId: number) { + // 1. 유저가 이미 어떤 방에 속해 있는지 확인 + const existingMembership = await this.gameRoomUserRepository.findOne({ + where: { userId }, + }); + if (existingMembership) { + throw new BadRequestException( + `User ${userId} is already in room ${existingMembership.roomId}. Please leave that room first.`, + ); + } + + // 2. 방 생성 + const newRoom = this.gameRoomRepository.create({ + roomName, + maxPlayers: 2, // 기본값: 2명 + currentCount: 1, // 방 생성과 동시에 1명 참가 + }); + const room = await this.gameRoomRepository.save(newRoom); + + // 3. 유저를 방에 추가 + const newUser = this.gameRoomUserRepository.create({ + roomId: room.id, + userId, + }); + await this.gameRoomUserRepository.save(newUser); + + return { room, user: newUser }; + } + + // 방 참가 + async joinRoom(roomId: number, userId: number) { + // 1. 유저가 이미 다른 방에 속해 있는지 확인 + // - 이미 같은 방에 있다면 "이미 참여 중" 예외를 던지고 + // - 다른 방에 있다면 "다른 방에 참여 중" 예외를 던짐 + const existingMembership = await this.gameRoomUserRepository.findOne({ + where: { userId }, + }); + if (existingMembership) { + if (existingMembership.roomId === roomId) { + throw new BadRequestException( + `User ${userId} already joined this room.`, + ); + } else { + throw new BadRequestException( + `User ${userId} is already in a different room (${existingMembership.roomId}). Leave that room first.`, + ); + } + } + + // 2. 방 존재 여부와 정원 확인 + const room = await this.gameRoomRepository.findOne({ + where: { id: roomId }, + }); + if (!room) { + throw new NotFoundException('Room not found'); + } + if (room.currentCount >= room.maxPlayers) { + throw new BadRequestException('Room is full'); + } + + // 3. 유저를 방에 추가 + const newUser = this.gameRoomUserRepository.create({ roomId, userId }); + room.currentCount += 1; + await this.gameRoomRepository.save(room); + + return await this.gameRoomUserRepository.save(newUser); + } + + // 방에서 나가기 + async leaveRoom(roomId: number, userId: number) { + const room = await this.gameRoomRepository.findOne({ + where: { id: roomId }, + }); + if (!room) { + throw new NotFoundException('Room not found'); + } + + const user = await this.gameRoomUserRepository.findOne({ + where: { roomId, userId }, + }); + if (!user) { + throw new BadRequestException('User not in the room'); + } + + // 유저 삭제 + await this.gameRoomUserRepository.remove(user); + room.currentCount -= 1; // 현재 인원 감소 + + // 방에 더 이상 유저가 없으면 방 삭제 + if (room.currentCount === 0) { + await this.gameRoomRepository.remove(room); + return { + message: `User ${userId} left room ${roomId}. Room has been deleted as it's empty.`, + }; + } + + await this.gameRoomRepository.save(room); + return { message: `User ${userId} left room ${roomId}` }; + } + + // 방 상태 조회 + async getRoomStatus(roomId: number) { + const room = await this.gameRoomRepository.findOne({ + where: { id: roomId }, + }); + if (!room) { + throw new NotFoundException('Room not found'); + } + + const users = await this.gameRoomUserRepository.find({ where: { roomId } }); + return { room, users }; + } +} From 78547312ee4bf9569819209553cf869c2afbec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=EC=A4=80=EC=88=98?= <99115509+hoheesu@users.noreply.github.com> Date: Fri, 3 Jan 2025 02:16:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Docs:=20swagger=ED=8B=80=20=EC=99=84?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 69 +++++++++++++++++++++++++++- package.json | 2 + src/app.controller.ts | 2 + src/auth/auth.controller.ts | 4 ++ src/filters/http-exception.filter.ts | 22 +++++++++ src/gameRoom/dto/gameRoom.dto.ts | 8 ++++ src/gameRoom/gameRoom.controller.ts | 4 ++ src/main.ts | 12 ++++- src/user/dto/user.dto.ts | 7 ++- src/user/user.controller.ts | 2 + 10 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/filters/http-exception.filter.ts create mode 100644 src/gameRoom/dto/gameRoom.dto.ts diff --git a/package-lock.json b/package-lock.json index 83307d5..3d236c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", + "@nestjs/swagger": "^8.1.0", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.0.0", "bcryptjs": "^2.4.3", @@ -33,6 +34,7 @@ "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "socket.io": "^4.7.1", + "swagger-ui-express": "^5.0.1", "typeorm": "^0.3.20" }, "devDependencies": { @@ -1608,6 +1610,11 @@ "node": ">=8" } }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", + "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==" + }, "node_modules/@nestjs-modules/ioredis": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@nestjs-modules/ioredis/-/ioredis-1.2.4.tgz", @@ -1867,6 +1874,38 @@ "dev": true, "license": "MIT" }, + "node_modules/@nestjs/swagger": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-8.1.0.tgz", + "integrity": "sha512-8hzH+r/31XshzXHC9vww4T0xjDAxMzvOaT1xAOvvY1LtXTWyNRCUP2iQsCYJOnnMrR+vydWjvRZiuB3hdvaHxA==", + "dependencies": { + "@microsoft/tsdoc": "^0.15.0", + "@nestjs/mapped-types": "2.0.6", + "js-yaml": "4.1.0", + "lodash": "4.17.21", + "path-to-regexp": "3.3.0", + "swagger-ui-dist": "5.18.2" + }, + "peerDependencies": { + "@fastify/static": "^6.0.0 || ^7.0.0", + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0", + "class-transformer": "*", + "class-validator": "*", + "reflect-metadata": "^0.1.12 || ^0.2.0" + }, + "peerDependenciesMeta": { + "@fastify/static": { + "optional": true + }, + "class-transformer": { + "optional": true + }, + "class-validator": { + "optional": true + } + } + }, "node_modules/@nestjs/terminus": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/@nestjs/terminus/-/terminus-10.2.0.tgz", @@ -2083,6 +2122,12 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -3124,7 +3169,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/array-flatten": { @@ -6912,7 +6956,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -11780,6 +11823,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swagger-ui-dist": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz", + "integrity": "sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==", + "dependencies": { + "@scarf/scarf": "=1.4.0" + } + }, + "node_modules/swagger-ui-express": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz", + "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==", + "dependencies": { + "swagger-ui-dist": ">=5.0.0" + }, + "engines": { + "node": ">= v0.10.32" + }, + "peerDependencies": { + "express": ">=4.0.0 || >=5.0.0-beta" + } + }, "node_modules/symbol-observable": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", diff --git a/package.json b/package.json index 9da0f65..b7b5fd0 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@nestjs/passport": "^10.0.3", "@nestjs/platform-express": "^10.0.0", "@nestjs/platform-socket.io": "^10.0.0", + "@nestjs/swagger": "^8.1.0", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.0.0", "bcryptjs": "^2.4.3", @@ -44,6 +45,7 @@ "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", "socket.io": "^4.7.1", + "swagger-ui-express": "^5.0.1", "typeorm": "^0.3.20" }, "devDependencies": { diff --git a/src/app.controller.ts b/src/app.controller.ts index cce879e..f53aef9 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -1,6 +1,8 @@ import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; +import { ApiTags } from '@nestjs/swagger'; +@ApiTags('healthCheck') @Controller() export class AppController { constructor(private readonly appService: AppService) {} diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 7d884d7..3b73b8c 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -17,6 +17,10 @@ import LoginUserDto from './dto/auth.dto'; import { RedisAuthGuard } from './auth.guard'; import { RedisService } from 'src/redis/redis.service'; + +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; +@ApiTags('auth') + @Controller('auth') export class AuthController { constructor( diff --git a/src/filters/http-exception.filter.ts b/src/filters/http-exception.filter.ts new file mode 100644 index 0000000..6175d03 --- /dev/null +++ b/src/filters/http-exception.filter.ts @@ -0,0 +1,22 @@ + +import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common'; +import { Response } from 'express'; + +@Catch(HttpException) +export class HttpExceptionFilter implements ExceptionFilter { + catch(exception: HttpException, host: ArgumentsHost) { + const ctx = host.switchToHttp(); + const response = ctx.getResponse(); + const status = exception.getStatus(); + const exceptionResponse: any = exception.getResponse(); + + const errorResponse = { + statusCode: status, + timestamp: new Date().toISOString(), + path: ctx.getRequest().url, + ...(typeof exceptionResponse === 'string' ? { message: exceptionResponse } : exceptionResponse), + }; + + response.status(status).json(errorResponse); + } +} diff --git a/src/gameRoom/dto/gameRoom.dto.ts b/src/gameRoom/dto/gameRoom.dto.ts new file mode 100644 index 0000000..71ce3ed --- /dev/null +++ b/src/gameRoom/dto/gameRoom.dto.ts @@ -0,0 +1,8 @@ + +import { IsString, IsNotEmpty } from 'class-validator'; + +export class GameroomDto { + @IsString() + @IsNotEmpty() + name: string; +} diff --git a/src/gameRoom/gameRoom.controller.ts b/src/gameRoom/gameRoom.controller.ts index a0eacd7..b4494f9 100644 --- a/src/gameRoom/gameRoom.controller.ts +++ b/src/gameRoom/gameRoom.controller.ts @@ -11,6 +11,10 @@ import { import { GameRoomService } from './gameRoom.service'; import { RedisAuthGuard } from 'src/auth/auth.guard'; + +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; +@ApiTags('gameRoom') + @Controller('gameRoom') @UseGuards(RedisAuthGuard) // 컨트롤러 전체에 Guard 적용 export class GameRoomController { diff --git a/src/main.ts b/src/main.ts index 89e5663..60c0913 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,6 +2,7 @@ import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe } from '@nestjs/common'; import * as cookieParser from 'cookie-parser'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -10,8 +11,15 @@ async function bootstrap() { app.useGlobalPipes(new ValidationPipe()); // 라우트 디버깅 활성화 - const server = app.getHttpAdapter(); - // console.log('Routes:', server.getHttpServer()._events.request._router.stack); + const config = new DocumentBuilder() + .setTitle('API Documentation') + .setDescription('The API description') + .setVersion('1.0') + .addTag('auth') // 원하는 태그를 추가 + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api', app, document); + await app.listen(process.env.PORT ?? 3000); } bootstrap(); diff --git a/src/user/dto/user.dto.ts b/src/user/dto/user.dto.ts index 33591fd..f8922f7 100644 --- a/src/user/dto/user.dto.ts +++ b/src/user/dto/user.dto.ts @@ -1,13 +1,16 @@ -import { IsString, IsEmail, Matches } from 'class-validator'; +import { IsString, IsEmail, Matches, IsNotEmpty } from 'class-validator'; export default class SingupUserDto { @IsEmail({}, { message: '이메일 형식이 틀렸습니다.' }) + @IsNotEmpty() userEmail: string; @IsString() - readonly userNickname: string; + @IsNotEmpty() + userNickname: string; @IsString() + @IsNotEmpty() @Matches(/^(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/, { message: '비밀번호는 알파벳, 숫자, 특수문자를 포함하여 8글자 이상 작성해주세요', diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index 6e6c132..c115575 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -3,6 +3,8 @@ import { UserService } from './user.service'; import SingupUserDto from './dto/user.dto'; import { validateOrReject } from 'class-validator'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; +@ApiTags('user') @Controller('user') export class UserController { constructor(private readonly userService: UserService) {}