From eac8e6391297a34b2cde2be4d4bf06bd4c745d43 Mon Sep 17 00:00:00 2001 From: Jihyun3478 Date: Sun, 4 May 2025 20:48:53 +0900 Subject: [PATCH 1/2] =?UTF-8?q?hotfix:=20QR=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20UUID=20=ED=83=80=EC=9E=85=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/user.controller.ts | 4 +-- src/services/__test__/qr.service.test.ts | 37 +++++++++++++++++++----- src/services/user.service.ts | 9 ++++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/controllers/user.controller.ts b/src/controllers/user.controller.ts index dab0d9b..937927f 100644 --- a/src/controllers/user.controller.ts +++ b/src/controllers/user.controller.ts @@ -118,7 +118,7 @@ export class UserController { const ip = typeof req.headers['x-forwarded-for'] === 'string' ? req.headers['x-forwarded-for'].split(',')[0].trim() : req.ip ?? ''; const userAgent = req.headers['user-agent'] || ''; - const token = await this.userService.create(user.id, ip, userAgent); + const token = await this.userService.create(user.velog_uuid, ip, userAgent); const typedToken = token as Token10; const response = new QRLoginTokenResponseDto( @@ -147,7 +147,7 @@ export class UserController { } const { decryptedAccessToken, decryptedRefreshToken } = - await this.userService.findUserAndTokensByVelogUUID(found.user.toString()); + await this.userService.findUserAndTokensByVelogUUID(String(found.user)); res.clearCookie('access_token', this.cookieOption()); res.clearCookie('refresh_token', this.cookieOption()); diff --git a/src/services/__test__/qr.service.test.ts b/src/services/__test__/qr.service.test.ts index 9315fac..ca0bed4 100644 --- a/src/services/__test__/qr.service.test.ts +++ b/src/services/__test__/qr.service.test.ts @@ -33,23 +33,44 @@ describe('UserService 의 QRService', () => { }); describe('create', () => { + const velogUUID = 'uuid-1234'; + const ip = '127.0.0.1'; + const userAgent = 'Chrome'; + + const mockUser = { + id: 1, + velog_uuid: velogUUID, + access_token: 'token', + refresh_token: 'token', + group_id: 1, + email: 'test@example.com', + is_active: true, + created_at: new Date(), + updated_at: new Date(), + }; + it('QR 토큰을 생성하고 반환해야 한다', async () => { - const userId = 1; - const ip = '127.0.0.1'; - const userAgent = 'Chrome'; - - const token = await service.create(userId, ip, userAgent); - + repo.findByUserVelogUUID.mockResolvedValueOnce(mockUser); + + const token = await service.create(velogUUID, ip, userAgent); + expect(typeof token).toBe('string'); expect(token.length).toBe(10); expect(/^[A-Za-z0-9\-_.~!]{10}$/.test(token)).toBe(true); - expect(repo.createQRLoginToken).toHaveBeenCalledWith(token, userId, ip, userAgent); + expect(repo.createQRLoginToken).toHaveBeenCalledWith(token, mockUser.id, ip, userAgent); + }); + + it('유저 조회 실패 시 예외 발생', async () => { + repo.findByUserVelogUUID.mockResolvedValueOnce(null as any); + + await expect(service.create(velogUUID, ip, userAgent)).rejects.toThrow('QR 토큰 생성 실패: 유저 없음'); }); it('QR 토큰 생성 중 오류 발생 시 예외 발생', async () => { + repo.findByUserVelogUUID.mockResolvedValueOnce(mockUser); repo.createQRLoginToken.mockRejectedValueOnce(new DBError('생성 실패')); - await expect(service.create(1, 'ip', 'agent')).rejects.toThrow('생성 실패'); + await expect(service.create('uuid-1234', 'ip', 'agent')).rejects.toThrow('생성 실패'); }); }); diff --git a/src/services/user.service.ts b/src/services/user.service.ts index 13e4073..732a613 100644 --- a/src/services/user.service.ts +++ b/src/services/user.service.ts @@ -136,9 +136,14 @@ export class UserService { return { user, decryptedAccessToken, decryptedRefreshToken }; } - async create(userId: number, ip: string, userAgent: string): Promise { + async create(velogUUID: string, ip: string, userAgent: string): Promise { + const user = await this.userRepo.findByUserVelogUUID(velogUUID); + if (!user) { + throw new NotFoundError('QR 토큰 생성 실패: 유저 없음'); + } + const token = generateRandomToken(10); - await this.userRepo.createQRLoginToken(token, userId, ip, userAgent); + await this.userRepo.createQRLoginToken(token, user.id, ip, userAgent); return token; } From cb934edca477a9252dd3daf6a45933e91ec75cc7 Mon Sep 17 00:00:00 2001 From: Jihyun3478 Date: Sun, 4 May 2025 20:56:22 +0900 Subject: [PATCH 2/2] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=EB=9E=98?= =?UTF-8?q?=EB=B9=97=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/__test__/qr.service.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/__test__/qr.service.test.ts b/src/services/__test__/qr.service.test.ts index ca0bed4..d5d3fdd 100644 --- a/src/services/__test__/qr.service.test.ts +++ b/src/services/__test__/qr.service.test.ts @@ -61,7 +61,7 @@ describe('UserService 의 QRService', () => { }); it('유저 조회 실패 시 예외 발생', async () => { - repo.findByUserVelogUUID.mockResolvedValueOnce(null as any); + repo.findByUserVelogUUID.mockResolvedValueOnce(null as unknown as typeof mockUser); await expect(service.create(velogUUID, ip, userAgent)).rejects.toThrow('QR 토큰 생성 실패: 유저 없음'); }); @@ -70,7 +70,7 @@ describe('UserService 의 QRService', () => { repo.findByUserVelogUUID.mockResolvedValueOnce(mockUser); repo.createQRLoginToken.mockRejectedValueOnce(new DBError('생성 실패')); - await expect(service.create('uuid-1234', 'ip', 'agent')).rejects.toThrow('생성 실패'); + await expect(service.create(velogUUID, ip, userAgent)).rejects.toThrow('생성 실패'); }); });