diff --git a/package-lock.json b/package-lock.json index b85c8b9..a27fad9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,8 @@ "prisma": "^5.4.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", - "swagger-ui-express": "^5.0.0" + "swagger-ui-express": "^5.0.0", + "ws": "^8.14.2" }, "devDependencies": { "@nestjs/cli": "^10.0.0", @@ -11217,6 +11218,26 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", diff --git a/package.json b/package.json index 5daec02..d43f97a 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "prisma": "^5.4.2", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", - "swagger-ui-express": "^5.0.0" + "swagger-ui-express": "^5.0.0", + "ws": "^8.14.2" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 7120b42..a8826a8 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -58,19 +58,9 @@ export class AuthController { // 엑세스 토큰을 HTTP 응답 헤더에 추가 res.header('accessToken', accessToken); - // 리프레시 토큰을 쿠키로 설정하여 클라이언트에게 전달 - // httpOnly : javascript 로 쿠키에 접근 할 수 없는 옵션 - // secure : true 일 시 https 연결에서만 전송된다. - - // 리프레시 토큰을 HTTP 응답 헤더에 추가 res.header('refreshToken', refreshToken); res.status(200).json({ userId }); // 클라이언트에게 JSON 응답을 보냄 - - //res.cookie('refreshToken', refreshToken, { httpOnly: true, secure: false }); - - // 액세스 토큰을 클라이언트에게 JSON 응답으로 반환 (Response body 에 전송) - //res.status(200).json({ accessToken }); // 클라이언트에게 JSON 응답을 보냄 } // 리프레시 토큰을 사용하여 엑세스 토큰 재발급을 위한 엔드포인트 추가 diff --git a/src/auth/auth.module.ts b/src/auth/auth.module.ts index 68a6a55..833d08c 100644 --- a/src/auth/auth.module.ts +++ b/src/auth/auth.module.ts @@ -10,16 +10,16 @@ import { JwtAccessStrategy } from './strategies/jwt-access.strategy'; import { UsersService } from 'src/users/users.service'; import { JwtKakaoStrategy } from './strategies/jwt-social-kakao.strategy'; import { JwtGoogleStrategy } from './strategies/jwt-social-google.strategy'; -//import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy'; +export const jwtSecret = process.env.JWT_SECRET; @Module({ imports: [PrismaModule, PassportModule, UsersModule, JwtModule.register({})], controllers: [AuthController], providers: [ AuthService, - JwtAccessStrategy, AuthService, UsersService, + JwtAccessStrategy, JwtKakaoStrategy, JwtNaverStrategy, JwtGoogleStrategy, diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index cd368c4..833574a 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -21,8 +21,6 @@ export class AuthService { // 리팩토링 시 res 빼도 작동하는지 테스트 accessToken: string; refreshToken: string; - - //user: User; // User 정보를 반환하기 위한 타입 userId: number; // userId만 반환 }> { // 1. 이메일이 일치하는 유저를 DB에서 찾기 @@ -31,12 +29,16 @@ export class AuthService { // 2. 일치하는 유저가 없으면 에러 if (!user) throw new NotFoundException('이메일이 없습니다.'); + // 2-1. 사용자가 삭제되지 않았는지 확인 (deletedAt가 null이어야 함) + if (user.deletedAt !== null) { + throw new UnauthorizedException('사용자가 삭제되었습니다.'); + } + // 3. 일치하는 유저는 있지만 비밀번호가 틀렸다면 에러 const isAuth = await bcrypt.compare(password, user.password); if (!isAuth) throw new UnauthorizedException('비밀번호가 일치하지 않습니다.'); - // const isdeletedAt // 4. 리프레시 토큰 생성 const refreshToken = this.setRefreshToken({ user, res }); @@ -51,11 +53,6 @@ export class AuthService { }, }); - //Authorization로 보내도록 결정되면 이렇게 수정(피드백 받으면 좋을 내용) - // res.header('Authorization', `Bearer ${accessToken}`); - // res.header('RefreshToken', refreshToken); - - //TODO : user값 대신 userId값만 넘어가게 수정해야함 () return { accessToken, refreshToken, userId: user.userId }; //리턴값 } @@ -65,11 +62,7 @@ export class AuthService { { secret: process.env.JWT_ACCESS_KEY, expiresIn: '36000s' } ); - res.header('accessToken', accessToken); // 클라이언트로 액세스 토큰을 반환 - //res.header('Authorization', `Bearer ${accessToken}`); // 클라이언트로 액세스토큰을 Authorization 에 Bearer 로 반환 - //console.log('엑세스 토큰 확인용 로그', user); return accessToken; - // return res.header(accessToken); } setRefreshToken({ user, res }): string { @@ -79,10 +72,7 @@ export class AuthService { { secret: process.env.JWT_REFRESH_KEY, expiresIn: '2w' } ); - res.header('refreshToken', refreshToken); // 클라이언트로 리프레시 토큰을 반환 - //console.log('리프레시 토큰 확인용 로그', user); return refreshToken; - // return res.header(refreshToken); } async refreshAccessToken(refreshToken: string): Promise { @@ -92,8 +82,10 @@ export class AuthService { }); // 리프레시 토큰이 유효하다면 새로운 액세스 토큰을 발급 + const userId = decodedToken.sub; // 추출된 사용자 ID + const newAccessToken = await this.getAccessToken({ - user: decodedToken, + user: { userId }, // 사용자 ID를 전달 res: null, }); @@ -117,7 +109,6 @@ export class AuthService { confirmPassword: req.user.password, // 비밀번호를 해싱하여 저장 intro: req.user.intro, profileImg: req.user.profileImg, - // 다른 필드도 설정해야 할 수 있음 }; // console.log('소셜 로그인 회원가입 : ', createUser); // createUser 정보를 콘솔에 출력 user = await this.usersService.create(createUser); @@ -134,19 +125,40 @@ export class AuthService { }, }); - //Authorization로 보내도록 결정되면 이렇게 수정(피드백 받으면 좋을 내용) - //res.header('Authorization', `Bearer ${accessToken}`); - //res.header('RefreshToken', refreshToken); - - // res.header(accessToken); - // res.header(refreshToken); + //토큰 요청헤더로 보내는 코드 + // res.header('accessToken', accessToken); + // res.header('refreshToken', refreshToken); res.header('userId', user.userId); + + //토큰 쿠키로 보내는 코드드 + // res.cookie('accessToken', accessToken, { + // httpOnly: false, // 배포시에 true + // sameSite: 'none', + // secure: false, // 배포시에 true + // }); + + // res.cookie('refreshToken', refreshToken, { + // httpOnly: false, // 배포시에 true + // sameSite: 'none', + // secure: false, // 배포시에 true + // }); + console.log('로컬 엑세스 토큰', accessToken); console.log('로컬 리프레시 토큰', refreshToken); console.log(user.userId); // 리다이렉션 - res.redirect('https://www.totobon6125.store'); // 메인페이지 url 을 입력해야합니다. + res.redirect( + `http://localhost:5500?accessToken=${encodeURIComponent( + accessToken + )}&refreshToken=${encodeURIComponent( + refreshToken + )}&userId=${encodeURIComponent(user.userId)}` + ); + // 현재 : 파람스로 AT,RT userId전달 // https 로 배포되면 cookie로 바꿔야함 + // `http://localhost:5500?userId=${user.userId}` + //https://www.totobon6125.store/ + // https://www.totobon6125.store?userId=${user.userId} //http://localhost:5173/ //http://127.0.0.1:5500 return { accessToken, refreshToken, userId: user.userId }; diff --git a/src/auth/guards/jwt-auth.guard.ts b/src/auth/guards/jwt-auth.guard.ts index c52787e..ed7c445 100644 --- a/src/auth/guards/jwt-auth.guard.ts +++ b/src/auth/guards/jwt-auth.guard.ts @@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() -export class JwtAuthGuard extends AuthGuard('jwt') {} - +// export class JwtAuthGuard extends AuthGuard('jwt') {} export class JwtAccessAuthGuard extends AuthGuard('access') {} export class JwtRefreshAuthGuard extends AuthGuard('refresh') {} diff --git a/src/auth/strategies/jwt-access.strategy.ts b/src/auth/strategies/jwt-access.strategy.ts index 4b25886..a9a4879 100644 --- a/src/auth/strategies/jwt-access.strategy.ts +++ b/src/auth/strategies/jwt-access.strategy.ts @@ -8,7 +8,7 @@ import { UsersService } from 'src/users/users.service'; //1. 비밀번호 검증 //2. 만료시간 검증 -export class JwtAccessStrategy extends PassportStrategy(Strategy, 'jwt') { +export class JwtAccessStrategy extends PassportStrategy(Strategy, 'access') { constructor(private usersService: UsersService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), //엑세스 토큰 diff --git a/src/auth/strategies/jwt-refresh.strategy.ts b/src/auth/strategies/jwt-refresh.strategy.ts index ac94a37..760233e 100644 --- a/src/auth/strategies/jwt-refresh.strategy.ts +++ b/src/auth/strategies/jwt-refresh.strategy.ts @@ -1,22 +1,46 @@ // import { PassportStrategy } from '@nestjs/passport'; -// import { Strategy } from 'passport-jwt'; +// import { Strategy, ExtractJwt } from 'passport-jwt'; +// import { Injectable, UnauthorizedException, Request } from '@nestjs/common'; +// import { JwtService } from '@nestjs/jwt'; +// import { UsersService } from '../../users/users.service'; +// @Injectable() // export class JwtRefreshStrategy extends PassportStrategy(Strategy, 'refresh') { -// constructor() { +// constructor( +// private jwtService: JwtService, +// private usersService: UsersService +// ) { // super({ -// jwtFromRequest: (req) => { -// const cookie = req.headers.cookie; -// const refreshToken = cookie.replace('refreshToken=', ''); -// return refreshToken; -// }, +// jwtFromRequest: ExtractJwt.fromHeader('refreshtoken'), // 헤더에서 리프레시 토큰을 추출 // secretOrKey: process.env.JWT_REFRESH_KEY, // }); // } -// validate(payload) { -// return { -// email: payload.email, -// id: payload.sub, -// }; +// async validate(payload: any, @Request() req: any) { +// // 'refreshtoken' 헤더에서 refreshToken을 추출 +// const refreshToken = req.headers.refreshtoken as string; +// console.log('리프레시토큰 확인', refreshToken); +// if (!refreshToken) { +// throw new UnauthorizedException('Refresh token not provided'); +// } + +// try { +// // 리프레시 토큰의 유효성을 검증 +// const decodedToken = this.jwtService.verify(refreshToken, { +// secret: process.env.JWT_REFRESH_KEY, +// }); + +// // 유효한 사용자를 찾을 때 사용자 서비스를 활용 +// const user = await this.usersService.findById(decodedToken.sub); + +// if (!user) { +// throw new UnauthorizedException('Invalid token'); +// } + +// // 사용자 정보를 반환 +// return { email: user.email, id: user.userId }; +// } catch (error) { +// throw new UnauthorizedException('Invalid token'); +// } // } // } diff --git a/src/auth/strategies/jwt-social-kakao.strategy.ts b/src/auth/strategies/jwt-social-kakao.strategy.ts index ce18d91..555b579 100644 --- a/src/auth/strategies/jwt-social-kakao.strategy.ts +++ b/src/auth/strategies/jwt-social-kakao.strategy.ts @@ -21,7 +21,7 @@ export class JwtKakaoStrategy extends PassportStrategy(Strategy, 'kakao') { console.log('카카오에서 주는 accessToken:' + accessToken); console.log('카카오에서 주는 refreshToken:' + refreshToken); console.log('카카오 프로필', profile); - //console.log(profile._json.kakao_account.email); + console.log(profile._json.kakao_account.email); // 비밀번호 암호화 const hashedPassword = await bcrypt.hash(profile.id.toString(), 10); diff --git a/src/events/events.controller.ts b/src/events/events.controller.ts index d763eac..4d9d2fc 100644 --- a/src/events/events.controller.ts +++ b/src/events/events.controller.ts @@ -27,7 +27,7 @@ import { ApiBody, } from '@nestjs/swagger'; import { EventEntity } from './entities/event.entity'; -import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; +import { JwtAccessAuthGuard } from 'src/auth/guards/jwt-auth.guard'; import { User } from '@prisma/client'; import { FileInterceptor } from '@nestjs/platform-express'; import { AwsS3Service } from 'src/aws/aws.s3'; @@ -47,7 +47,7 @@ export class EventsController { // 이벤트 생성 @Post() - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '호스트로 Event 생성' }) @ApiCreatedResponse({ type: EventEntity }) @@ -59,7 +59,7 @@ export class EventsController { // 이벤트 이미지 업로드 @Post('upload') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: 'Event 이미지 업로드' }) @ApiConsumes('multipart/form-data') @@ -133,7 +133,7 @@ export class EventsController { // 이벤트 참가 신청 @Put(':eventId/join') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: 'Guest로서 Event 참가신청' }) @ApiCreatedResponse({ description: `모임 참석 신청 / 취소` }) @@ -186,7 +186,7 @@ export class EventsController { // 관심있는 이벤트 북마크 추가 @Post(':eventId/bookmark') - @UseGuards(JwtAuthGuard) + @UseGuards(JwtAccessAuthGuard) @ApiBearerAuth() @ApiOperation({ summary: 'Event 북마크 추가' }) async addBookmark( @@ -199,7 +199,7 @@ export class EventsController { // 관심있는 이벤트 북마크 제거 @Delete(':eventId/bookmark') - @UseGuards(JwtAuthGuard) + @UseGuards(JwtAccessAuthGuard) @ApiBearerAuth() @ApiOperation({ summary: 'Event 북마크 제거' }) async removeBookmark( diff --git a/src/events/events.service.ts b/src/events/events.service.ts index b3d174f..e331651 100644 --- a/src/events/events.service.ts +++ b/src/events/events.service.ts @@ -31,6 +31,8 @@ export class EventsService { }, }); + + return event; } diff --git a/src/mails/dto/verify-code.dto.ts b/src/mails/dto/verify-code.dto.ts new file mode 100644 index 0000000..0e5e571 --- /dev/null +++ b/src/mails/dto/verify-code.dto.ts @@ -0,0 +1,12 @@ +import { IsInt } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class VerifyCodeDto { + @ApiProperty() + @IsInt() + @ApiProperty({ + description: 'code', + example: '12345', + }) + code: number; +} diff --git a/src/mails/mail.controller.ts b/src/mails/mail.controller.ts index ca3efba..3c5cc2a 100644 --- a/src/mails/mail.controller.ts +++ b/src/mails/mail.controller.ts @@ -4,6 +4,7 @@ import { MailService } from './mail.service'; import { ApiBody, ApiTags } from '@nestjs/swagger'; import { SendMailDto } from './dto/sendmail.dto'; import { Request } from 'express'; // Request 객체를 가져오도록 수정 +import { VerifyCodeDto } from './dto/verify-code.dto'; @Controller('mail') @ApiTags('Mail') @@ -22,4 +23,19 @@ export class MailController { ) { await this.mailService.sendMail(to, subject, req); } + + @Post('verify') + @ApiBody({ + type: VerifyCodeDto, // VerifyCodeDto는 인증 코드를 받는 DTO입니다. + }) + async verifyCode(@Body() verifyCodeDto: VerifyCodeDto) { + const { code } = verifyCodeDto; + const isVerified = this.mailService.verifyVerificationCode(code); + + if (isVerified) { + return { message: '인증 성공' }; + } else { + return { message: '인증 실패' }; + } + } } diff --git a/src/mails/mail.service.ts b/src/mails/mail.service.ts index aece483..281f24e 100644 --- a/src/mails/mail.service.ts +++ b/src/mails/mail.service.ts @@ -1,15 +1,16 @@ -import { Injectable } from '@nestjs/common'; +// mail.service.ts +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { Request } from 'express'; import * as nodemailer from 'nodemailer'; -import { Request } from 'express'; // Express의 Request 객체를 사용하기 위해 추가 @Injectable() export class MailService { private transporter; + private verificationCodes = new Map(); // 숫자를 사용하여 인증 번호 관리 constructor() { this.transporter = nodemailer.createTransport({ - // SMTP 설정 - host: 'smtp.gmail.com', //smtp 호스트 + host: 'smtp.gmail.com', port: 587, secure: false, auth: { @@ -19,7 +20,6 @@ export class MailService { }); } - // 랜덤한 인증 번호 생성 함수 generateRandomNumber = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; @@ -32,7 +32,6 @@ export class MailService { const verificationCode = this.generateRandomNumber(10000, 99999); // 5자리 랜덤 인증 번호 생성 console.log('인증 번호 확인 샌드 메일:', verificationCode); - // 이메일 내용에 인증 번호 포함 await this.transporter.sendMail({ from: process.env.EMAIL_USER, to: email, @@ -40,9 +39,25 @@ export class MailService { text: `인증 번호: ${verificationCode}`, }); + this.verificationCodes.set(verificationCode, verificationCode); + console.log('메일이 전송되었습니다'); } catch (error) { console.error('메일 전송 중 오류가 발생했습니다:', error); + // throw new Error('메일 전송 중 오류가 발생했습니다'); + throw new HttpException( + '메일 전송 중 오류가 발생했습니다', + HttpStatus.INTERNAL_SERVER_ERROR + ); + } + } + + //인증번호 검증 + verifyVerificationCode(code: number): boolean { + if (this.verificationCodes.has(code)) { + this.verificationCodes.delete(code); + return true; } + return false; } } diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 1f9d403..ebb51e6 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -7,7 +7,7 @@ import { UpdateUserDto } from './dto/update-user.dto'; import { DeleteUserDto } from './dto/delete-user.dto'; import { ApiBearerAuth, ApiCreatedResponse, ApiOkResponse, ApiOperation, ApiResponse, ApiTags, ApiBody, ApiConsumes, ApiProperty } from '@nestjs/swagger'; import { UserEntity } from './entities/user.entity'; -import { JwtAuthGuard } from 'src/auth/guards/jwt-auth.guard'; +import { JwtAccessAuthGuard } from 'src/auth/guards/jwt-auth.guard'; import { User } from '@prisma/client'; import { AwsS3Service } from 'src/aws/aws.s3'; import { UploadedFile, UseInterceptors } from '@nestjs/common'; @@ -64,7 +64,7 @@ export class UsersController { // 2. 전체 유저 리스트를 조회한다. @Get() - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '회원 조회' }) @ApiOkResponse({ type: UserEntity, isArray: true }) @@ -82,7 +82,7 @@ export class UsersController { // 유저 자신의 정보를 조회한다. @Get('me') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '유저 본인 조회' }) async findMe(@Req() req: RequestWithUser) { @@ -96,7 +96,7 @@ export class UsersController { // 3. userId를 통한 유저 조회 @Get(':id') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: 'ID로 회원 조회' }) @ApiResponse({ status: 200, description: '유저 정보 조회 성공' }) @@ -111,7 +111,7 @@ export class UsersController { // 5. user 정보 수정한다. @Patch(':id') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '회원 정보 수정' }) @ApiResponse({ status: 200, description: '회원 정보가 수정되었습니다' }) @@ -131,7 +131,7 @@ export class UsersController { // 6. 회원 탈퇴를 한다. @Delete('withdrawal') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '회원 탈퇴' }) async remove(@Req() req: RequestWithUser, @Body() DeleteUserDto: DeleteUserDto) { @@ -170,7 +170,7 @@ export class UsersController { // 10. 사용자 유저 프로필 이미지를 업로드 한다. @Post('upload') - @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 + @UseGuards(JwtAccessAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '프로필 이미지 업로드' }) @ApiConsumes('multipart/form-data') diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 05022d8..9f49bc6 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -37,6 +37,19 @@ export class UsersService { const hashedPassword = await bcrypt.hash(password, 10); + // Default 프로필 이미지 리스트 + // 순서: 회색, 하늘색, 주황색, 남색, 네온색, 녹색 + const profileImgList = + ['https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698025763231', + 'https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698029706605', + 'https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698029779728', + 'https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698029799098', + 'https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698029815362', + 'https://s3-image-local-mingle.s3.ap-northeast-2.amazonaws.com/profileImg/1698029828369' + ] + // Default 프로필 이미지 리스트 랜덤으로 하나 선택 + const randomProfileImg = profileImgList[Math.floor(Math.random() * profileImgList.length)]; + // 트랜잭션을 사용하여 user와 UserDetail 생성 const [user] = await this.prisma.$transaction([ this.prisma.user.create({ @@ -47,7 +60,7 @@ export class UsersService { create: { nickname, intro, - profileImg: '기본 이미지 URL', + profileImg: randomProfileImg, // default 프로필 이미지 업로드 }, }, }, @@ -68,6 +81,12 @@ export class UsersService { return this.prisma.userDetail.findUnique({ where: { nickname } }); } + // 사용자 ID로 사용자를 찾는 메서드 추가 + async findById(userId: number): Promise { + return this.prisma.user.findUnique({ + where: { userId }, + }); + } // 2. 전체 유저 리스트를 조회한다. async findAll() { diff --git a/src/views/index.html b/src/views/index.html index 57c424f..d35a7cb 100644 --- a/src/views/index.html +++ b/src/views/index.html @@ -1,11 +1,46 @@ - + 소셜로그인 - 구글로그인 - 카카오로그인 - 네이버로그인 +

소셜로그인

+ + + + + + +
+ 구글로그인 + 카카오로그인 + 네이버로그인 +
+ +
+

채팅

+
+ + +
+
    + +
+