diff --git a/nestjs-BE/server/package-lock.json b/nestjs-BE/server/package-lock.json index a161dbd3..ab081798 100644 --- a/nestjs-BE/server/package-lock.json +++ b/nestjs-BE/server/package-lock.json @@ -41,6 +41,7 @@ "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", "@types/supertest": "^2.0.12", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.42.0", @@ -4020,6 +4021,13 @@ "@types/superagent": "*" } }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/validator": { "version": "13.11.7", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.7.tgz", diff --git a/nestjs-BE/server/package.json b/nestjs-BE/server/package.json index 70d9ad39..bd6f68fd 100644 --- a/nestjs-BE/server/package.json +++ b/nestjs-BE/server/package.json @@ -52,6 +52,7 @@ "@types/node": "^20.3.1", "@types/passport-jwt": "^3.0.13", "@types/supertest": "^2.0.12", + "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "eslint": "^8.42.0", diff --git a/nestjs-BE/server/src/auth/auth.controller.spec.ts b/nestjs-BE/server/src/auth/auth.controller.spec.ts index 07cc7907..a1f2a77a 100644 --- a/nestjs-BE/server/src/auth/auth.controller.spec.ts +++ b/nestjs-BE/server/src/auth/auth.controller.spec.ts @@ -29,13 +29,13 @@ describe('AuthController', () => { provide: UsersService, useValue: { findUserByEmailAndProvider: jest.fn(), - createUser: jest.fn(), + getOrCreateUser: jest.fn(), }, }, { provide: ProfilesService, useValue: { - createProfile: jest.fn(), + getOrCreateProfile: jest.fn(), }, }, { @@ -62,7 +62,7 @@ describe('AuthController', () => { jest .spyOn(authService, 'getKakaoAccount') .mockResolvedValue(kakaoUserAccountMock); - jest.spyOn(usersService, 'findUserByEmailAndProvider').mockResolvedValue({ + jest.spyOn(usersService, 'getOrCreateUser').mockResolvedValue({ uuid: 'user uuid', } as User); jest.spyOn(authService, 'login').mockResolvedValue(tokenMock); @@ -74,32 +74,6 @@ describe('AuthController', () => { message: 'Success', data: tokenMock, }); - expect(usersService.createUser).not.toHaveBeenCalled(); - }); - - it('kakaoLogin user login first time', async () => { - const requestMock = { kakaoUserId: 0 }; - const kakaoUserAccountMock = { email: 'kakao email' }; - const tokenMock = { - refresh_token: 'refresh token', - access_token: 'access token', - }; - jest - .spyOn(authService, 'getKakaoAccount') - .mockResolvedValue(kakaoUserAccountMock); - jest - .spyOn(usersService, 'createUser') - .mockResolvedValue({ uuid: 'user uuid' } as User); - jest.spyOn(authService, 'login').mockResolvedValue(tokenMock); - - const response = controller.kakaoLogin(requestMock); - - await expect(response).resolves.toEqual({ - statusCode: 200, - message: 'Success', - data: tokenMock, - }); - expect(usersService.createUser).toHaveBeenCalled(); }); it('kakaoLogin kakao login fail', async () => { diff --git a/nestjs-BE/server/src/auth/auth.controller.ts b/nestjs-BE/server/src/auth/auth.controller.ts index c31533fd..38bcc293 100644 --- a/nestjs-BE/server/src/auth/auth.controller.ts +++ b/nestjs-BE/server/src/auth/auth.controller.ts @@ -41,24 +41,15 @@ export class AuthController { kakaoUserDto.kakaoUserId, ); if (!kakaoUserAccount) throw new NotFoundException(); - const email = kakaoUserAccount.email; - const user = await this.usersService.findUserByEmailAndProvider( - email, - 'kakao', - ); - let userUuid = user?.uuid; - if (!userUuid) { - const data = { email, provider: 'kakao' }; - const createdUser = await this.usersService.createUser(data); - userUuid = createdUser.uuid; - const profileData = { - user_id: createdUser.uuid, - image: customEnv.BASE_IMAGE_URL, - nickname: '익명의 사용자', - }; - await this.profilesService.createProfile(profileData); - } - const tokenData = await this.authService.login(userUuid); + const userData = { email: kakaoUserAccount.email, provider: 'kakao' }; + const user = await this.usersService.getOrCreateUser(userData); + const profileData = { + user_id: user.uuid, + image: customEnv.BASE_IMAGE_URL, + nickname: '익명의 사용자', + }; + await this.profilesService.getOrCreateProfile(profileData); + const tokenData = await this.authService.login(user.uuid); return { statusCode: 200, message: 'Success', data: tokenData }; } diff --git a/nestjs-BE/server/src/auth/auth.service.ts b/nestjs-BE/server/src/auth/auth.service.ts index 57543bfb..cbc32a75 100644 --- a/nestjs-BE/server/src/auth/auth.service.ts +++ b/nestjs-BE/server/src/auth/auth.service.ts @@ -2,7 +2,6 @@ import { Injectable, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { jwtConstants, kakaoOauthConstants } from './constants'; import { stringify } from 'qs'; -import { PrismaService } from '../prisma/prisma.service'; import { RefreshTokensService } from './refresh-tokens.service'; @Injectable() @@ -10,7 +9,6 @@ export class AuthService { constructor( private jwtService: JwtService, private refreshTokensService: RefreshTokensService, - protected prisma: PrismaService, ) {} async getKakaoAccount(kakaoUserId: number) { diff --git a/nestjs-BE/server/src/profiles/profiles.service.spec.ts b/nestjs-BE/server/src/profiles/profiles.service.spec.ts index eed7adf2..8afc4e06 100644 --- a/nestjs-BE/server/src/profiles/profiles.service.spec.ts +++ b/nestjs-BE/server/src/profiles/profiles.service.spec.ts @@ -18,7 +18,7 @@ describe('ProfilesService', () => { profile: { findUnique: jest.fn(), findMany: jest.fn(), - create: jest.fn(), + upsert: jest.fn(), update: jest.fn(), }, }, @@ -83,38 +83,18 @@ describe('ProfilesService', () => { await expect(profiles).resolves.toEqual([]); }); - it('createProfile created', async () => { + it('getOrCreateProfile', async () => { const data = { user_id: generateUuid(), image: 'www.test.com/image', nickname: 'test nickname', }; - const testProfile = { uuid: generateUuid(), ...data }; - jest.spyOn(prisma.profile, 'create').mockResolvedValue(testProfile); + const profileMock = { uuid: generateUuid(), ...data }; + jest.spyOn(prisma.profile, 'upsert').mockResolvedValue(profileMock); - const profile = profilesService.createProfile(data); + const profile = profilesService.getOrCreateProfile(data); - await expect(profile).resolves.toEqual(testProfile); - }); - - it("createProfile user_id doesn't exists", async () => { - const data = { - user_id: generateUuid(), - image: 'www.test.com/image', - nickname: 'test nickname', - }; - jest - .spyOn(prisma.profile, 'create') - .mockRejectedValue( - new PrismaClientKnownRequestError( - 'Foreign key constraint failed on the field: `user_id`', - { code: 'P2003', clientVersion: '' }, - ), - ); - - const profile = profilesService.createProfile(data); - - await expect(profile).rejects.toThrow(PrismaClientKnownRequestError); + await expect(profile).resolves.toEqual(profileMock); }); it('updateProfile updated', async () => { diff --git a/nestjs-BE/server/src/profiles/profiles.service.ts b/nestjs-BE/server/src/profiles/profiles.service.ts index 5fdc1483..b0226221 100644 --- a/nestjs-BE/server/src/profiles/profiles.service.ts +++ b/nestjs-BE/server/src/profiles/profiles.service.ts @@ -19,9 +19,11 @@ export class ProfilesService { }); } - async createProfile(data: CreateProfileDto): Promise { - return this.prisma.profile.create({ - data: { + async getOrCreateProfile(data: CreateProfileDto): Promise { + return this.prisma.profile.upsert({ + where: { user_id: data.user_id }, + update: {}, + create: { uuid: generateUuid(), user_id: data.user_id, image: data.image, diff --git a/nestjs-BE/server/src/users/dto/update-user.dto.ts b/nestjs-BE/server/src/users/dto/update-user.dto.ts deleted file mode 100644 index fc59078e..00000000 --- a/nestjs-BE/server/src/users/dto/update-user.dto.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PartialType } from '@nestjs/mapped-types'; -import { CreateUserDto } from './create-user.dto'; -import { ApiProperty } from '@nestjs/swagger'; - -export class UpdateUserDto extends PartialType(CreateUserDto) { - @ApiProperty({ - example: 'newpassword', - description: 'The new password of the user', - }) - password?: string; - uuid?: string; -} diff --git a/nestjs-BE/server/src/users/users.service.spec.ts b/nestjs-BE/server/src/users/users.service.spec.ts index f6154742..c2771936 100644 --- a/nestjs-BE/server/src/users/users.service.spec.ts +++ b/nestjs-BE/server/src/users/users.service.spec.ts @@ -2,7 +2,6 @@ import { Test, TestingModule } from '@nestjs/testing'; import { UsersService } from './users.service'; import { PrismaService } from '../prisma/prisma.service'; import generateUuid from '../utils/uuid'; -import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library'; describe('UsersService', () => { let usersService: UsersService; @@ -17,7 +16,7 @@ describe('UsersService', () => { useValue: { user: { findUnique: jest.fn(), - create: jest.fn(), + upsert: jest.fn(), }, }, }, @@ -55,37 +54,19 @@ describe('UsersService', () => { await expect(user).resolves.toBeNull(); }); - it('createUser created', async () => { + it('getOrCreateUser', async () => { const testUser = { uuid: generateUuid(), email: 'test@test.com', provider: 'kakao', }; - jest.spyOn(prisma.user, 'create').mockResolvedValue(testUser); + jest.spyOn(prisma.user, 'upsert').mockResolvedValue(testUser); - const user = usersService.createUser({ + const user = usersService.getOrCreateUser({ email: 'test@test.com', provider: 'kakao', }); await expect(user).resolves.toEqual(testUser); }); - - it('createUser user already exists', async () => { - jest - .spyOn(prisma.user, 'create') - .mockRejectedValue( - new PrismaClientKnownRequestError( - 'Unique constraint failed on the constraint: `User_email_provider_key`', - { code: 'P2025', clientVersion: '' }, - ), - ); - - const user = usersService.createUser({ - email: 'test@test.com', - provider: 'kakao', - }); - - await expect(user).rejects.toThrow(PrismaClientKnownRequestError); - }); }); diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts index eb2f1f16..4d65e639 100644 --- a/nestjs-BE/server/src/users/users.service.ts +++ b/nestjs-BE/server/src/users/users.service.ts @@ -17,9 +17,11 @@ export class UsersService { }); } - async createUser(data: CreateUserDto): Promise { - return this.prisma.user.create({ - data: { + async getOrCreateUser(data: CreateUserDto): Promise { + return this.prisma.user.upsert({ + where: { email_provider: { email: data.email, provider: data.provider } }, + update: {}, + create: { uuid: generateUuid(), email: data.email, provider: data.provider,