diff --git a/src/canvas/canvas.service.ts b/src/canvas/canvas.service.ts index 07e379a..a383d87 100644 --- a/src/canvas/canvas.service.ts +++ b/src/canvas/canvas.service.ts @@ -420,8 +420,8 @@ export class CanvasService { }): Promise { // 캔버스 타입 조회 const canvasType = await this.getCanvasType(canvas_id); - // 게임 모드면 쿨다운 1초, 그 외는 10초 - const cooldownSeconds = canvasType === 'game_calculation' ? 1 : 10; + // 게임 모드면 쿨다운 1초, 그 외는 3초 + const cooldownSeconds = canvasType === 'game_calculation' ? 1 : 3; console.log( `[CanvasService] 쿨다운 설정: canvasType=${canvasType}, cooldownSeconds=${cooldownSeconds}` ); diff --git a/src/user/dto/create-guest.dto.ts b/src/user/dto/create-guest.dto.ts new file mode 100644 index 0000000..a009d67 --- /dev/null +++ b/src/user/dto/create-guest.dto.ts @@ -0,0 +1,9 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateGuestDto { + @ApiProperty({ + example: 'guest123', + description: '게스트 닉네임', + }) + userName: string; +} \ No newline at end of file diff --git a/src/user/entity/user.entity.ts b/src/user/entity/user.entity.ts index 7f38268..6fe1910 100644 --- a/src/user/entity/user.entity.ts +++ b/src/user/entity/user.entity.ts @@ -14,8 +14,8 @@ export class User { @Column({ name: 'email', unique: true, nullable: false }) email: string; - @Column({ name: 'password', nullable: true }) - password: string; + @Column({ name: 'password', nullable: true, type: 'varchar', length: 100 }) + password: string | null; @Column({ name: 'created_at', type: 'timestamp' }) createdAt: Date; diff --git a/src/user/user.controller.ts b/src/user/user.controller.ts index 44eb9dd..6be7ffd 100644 --- a/src/user/user.controller.ts +++ b/src/user/user.controller.ts @@ -25,6 +25,7 @@ import { OAuthCallbackDto } from './dto/oauth_callback_dto.dto'; import { JwtAuthGuard } from 'src/auth/jwt.guard'; import { AuthRequest } from 'src/interface/AuthRequest.interface'; import { SignedCookies } from 'src/interface/SignedCookies.interface'; +import { CreateGuestDto } from './dto/create-guest.dto'; @ApiTags('api/user') @Controller('api/user') @@ -74,6 +75,27 @@ export class UserController { } } + @Post('signup') + @ApiOperation({ summary: '게스트 회원가입(로그인) API' }) + async guestSignUp( + @Body() createGuestDto: CreateGuestDto, + @Res({ passthrough: true }) res: Response + ) { + const result = await this.userService.guestSignUp(createGuestDto.userName); + // access_token을 헤더로, refresh_token을 쿠키로 내려줌 (OAuth와 동일) + res.setHeader('Authorization', `Bearer ${result.access_token}`); + res.cookie('refresh_token', result.refresh_token, { + httpOnly: true, + secure: true, + sameSite: 'none', + maxAge: 1 * 24 * 60 * 60 * 1000, // 1일 + signed: true, + }); + // 응답 바디에는 토큰 정보 포함하지 않고, 나머지 정보만 반환 + const { access_token, refresh_token, ...rest } = result; + return rest; + } + @Get('info') @ApiOperation({ summary: '마이페이지 API' }) @UseGuards(JwtAuthGuard) diff --git a/src/user/user.service.ts b/src/user/user.service.ts index 41dbf52..c41ac55 100644 --- a/src/user/user.service.ts +++ b/src/user/user.service.ts @@ -11,6 +11,7 @@ import { AuthService } from 'src/auth/auth.service'; import { JwtService } from '@nestjs/jwt'; import Redis from 'ioredis'; import { JwtPayload } from '../interface/JwtPaylod.interface'; +import { v4 as uuidv4 } from 'uuid'; interface CommonTokenResponse { access_token: string; @@ -250,4 +251,34 @@ export class UserService { throw new NotFoundException('로그아웃 실패: 레디스에서 토큰 삭제 실패'); } } + + async guestSignUp(userName: string) { + // uuid로 이메일 생성 + const uuid = uuidv4(); + const email = `${uuid}@guest.local`; + // 이메일 중복 체크 + const exist = await this.userRepository.findOne({ where: { email } }); + if (exist) { + throw new Error('이미 존재하는 이메일입니다.'); + } + const now = new Date(); + const newUser = this.userRepository.create({ + email: email, + password: null, + createdAt: now, + updatedAt: now, + userName: userName, + }); + const saved: User = await this.userRepository.save(newUser); + const token = await this.authService.generateJWT(saved.id, saved.userName); + return { + isSuccess: true, + code: '200', + message: '요청에 성공하였습니다.', + createdAt: now.toISOString(), + data: 'Join Success', + access_token: token.access_token, + refresh_token: token.refresh_token, + }; + } }