From ee17d938ebafbb339d10fd7b2ebf229218c5dec6 Mon Sep 17 00:00:00 2001 From: erickimme Date: Mon, 16 Oct 2023 23:21:11 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[=EC=99=84=EB=A3=8C]=20=EB=A7=88=EC=9D=B4?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20-=20=EC=9D=B4=EB=AF=B8=EC=A7=80?= =?UTF-8?q?=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/auth/dto/login.dto.ts | 4 +- src/aws/aws.s3.ts | 10 ++-- src/users/dto/create-user-detail.dto.ts | 48 ------------------- src/users/dto/create-user.dto.ts | 63 +++++-------------------- src/users/dto/update-user-detail.dto.ts | 5 -- src/users/dto/update-user.dto.ts | 44 ++++++++++++++++- src/users/users.controller.ts | 31 +++++++----- src/users/users.service.ts | 40 +++++++++++++--- 8 files changed, 116 insertions(+), 129 deletions(-) delete mode 100644 src/users/dto/create-user-detail.dto.ts delete mode 100644 src/users/dto/update-user-detail.dto.ts diff --git a/src/auth/dto/login.dto.ts b/src/auth/dto/login.dto.ts index 6788d79..03612ca 100644 --- a/src/auth/dto/login.dto.ts +++ b/src/auth/dto/login.dto.ts @@ -7,7 +7,7 @@ export class LoginDto { @IsNotEmpty() @ApiProperty({ description: 'Email', - example: 'eric@test.com', + example: 'eric1@test.com', }) email: string; @@ -15,7 +15,7 @@ export class LoginDto { @IsNotEmpty() @ApiProperty({ description: 'Password', - example: '123456!', + example: 'abc123456789!', }) password: string; } diff --git a/src/aws/aws.s3.ts b/src/aws/aws.s3.ts index 5d954e5..023766e 100644 --- a/src/aws/aws.s3.ts +++ b/src/aws/aws.s3.ts @@ -1,6 +1,6 @@ // src/aws/aws.s3.ts import * as AWS from 'aws-sdk'; -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; @Injectable() export class AwsS3Service { @@ -15,9 +15,13 @@ export class AwsS3Service { // S3 업로드 로직 async uploadFile(file) { + if (!file) { + throw new BadRequestException('No file uploaded'); + } + const params = { - Bucket: process.env.AWS_BUCKET_NAME || 'aws-s3-local-mingle', // AWS S3 버킷 이름 - Key: `profileimg/${String(Date.now())}`, // 폴더와 파일 이름 + Bucket: process.env.AWS_BUCKET_NAME || 's3-image-local-mingle', // AWS S3 버킷 이름 + Key: `profileImg/${String(Date.now())}`, // 폴더와 파일 이름 Body: file.buffer, // 파일 내용 ContentType: file.mimetype, // 파일 타입 }; diff --git a/src/users/dto/create-user-detail.dto.ts b/src/users/dto/create-user-detail.dto.ts deleted file mode 100644 index 96356b1..0000000 --- a/src/users/dto/create-user-detail.dto.ts +++ /dev/null @@ -1,48 +0,0 @@ -// src/users/dto/create-user-detail.dto.ts - -import { ApiProperty } from '@nestjs/swagger'; -import { IsNotEmpty, IsString, IsOptional } from 'class-validator'; - -/* -// 사용자 정보 모델 -model UserDetail { - userDetailId Int @id @default(autoincrement()) // Primary Key - UserId Int // Foreign Key - nickname String @unique - intro String? - profileImg String? - - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt - - User User @relation(fields: [UserId], references: [userId]) - - @@map("UserInfo") -} -*/ - -export class CreateUserDetailDto { - @ApiProperty({ - example: 'nickname1', - description: 'The nickname of the user', - }) - @IsNotEmpty() - @IsString() - nickname: string; - - @ApiProperty({ - example: 'Hello, I am user1', - description: 'The introduction of the user', - }) - @IsOptional() - @IsString() - intro?: string; - - @ApiProperty({ - example: 'profile.jpg', - description: 'The profile image of the user', - }) - @IsOptional() - @IsString() - profileImg?: string; -} diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts index ea102ba..331c4b9 100644 --- a/src/users/dto/create-user.dto.ts +++ b/src/users/dto/create-user.dto.ts @@ -10,45 +10,6 @@ import { Matches, } from 'class-validator'; -// model User { -// userId Int @id @default(autoincrement()) // Primary Key -// email String @unique -// password String -// createdAt DateTime @default(now()) -// updatedAt DateTime @updatedAt - -// UserDetail UserDetail[] -// HostEvents HostEvent[] -// GuestEvents GuestEvent[] - -// @@map("User") -// } - -/* Eric's code -export class CreateUserDto { - @ApiProperty({ - example: 'user1@email.com', - description: 'The email of the user', - }) - @IsNotEmpty() - @IsEmail({}, { message: '이메일 형식이 아닙니다.' }) - email: string; - - @ApiProperty({ - example: 'Password1!', - description: 'The password of the user', - }) - @IsNotEmpty() - @IsString() - @MinLength(8, { message: '패스워드는 최소 8자리 이상이어야 합니다.' }) - @MaxLength(15, { message: '패스워드는 최대 15자리까지 가능합니다.' }) - @Matches(/^(?=.*[a-zA-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,15}$/, { - message: '패스워드는 8-15 글자, 영문/숫자/특수문자가 포함되어야 합니다.', - }) - password: string; -} -*/ - export class CreateUserDto { @IsEmail() @IsNotEmpty() @@ -58,18 +19,6 @@ export class CreateUserDto { }) email: string; - @IsString() - @IsNotEmpty() - @MinLength(8) - @MaxLength(15) - //알파벳 포함 , 숫자 포함 , 특수문자 포함 - @Matches(/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/) - @ApiProperty({ - description: 'password', - example: 'abc123456789!', - }) - password: string; - @IsString() @IsNotEmpty() @MinLength(2) @@ -89,6 +38,18 @@ export class CreateUserDto { }) intro: string; + @IsString() + @IsNotEmpty() + @MinLength(8) + @MaxLength(15) + //알파벳 포함 , 숫자 포함 , 특수문자 포함 + @Matches(/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/) + @ApiProperty({ + description: 'password', + example: 'abc123456789!', + }) + password: string; + @IsString() @IsNotEmpty() @ApiProperty({ diff --git a/src/users/dto/update-user-detail.dto.ts b/src/users/dto/update-user-detail.dto.ts deleted file mode 100644 index 787df5b..0000000 --- a/src/users/dto/update-user-detail.dto.ts +++ /dev/null @@ -1,5 +0,0 @@ -// src/users/dto/update-user-detail.dto.ts -import { PartialType } from '@nestjs/swagger'; -import { CreateUserDetailDto } from './create-user-detail.dto'; - -export class UpdateUserDetailDto extends PartialType(CreateUserDetailDto) {} diff --git a/src/users/dto/update-user.dto.ts b/src/users/dto/update-user.dto.ts index 2b846b8..86f4333 100644 --- a/src/users/dto/update-user.dto.ts +++ b/src/users/dto/update-user.dto.ts @@ -1,5 +1,45 @@ // src/users/dto/update-user.dto.ts -import { PartialType } from '@nestjs/swagger'; +import { ApiProperty, PartialType } from '@nestjs/swagger'; import { CreateUserDto } from './create-user.dto'; +import { IsNotEmpty, IsString, Matches, MaxLength, MinLength } from 'class-validator'; -export class UpdateUserDto extends PartialType(CreateUserDto) {} +export class UpdateUserDto { + @IsString() + @IsNotEmpty() + @MinLength(2) + @MaxLength(8) + //영어 또는 한글이 포함 + @Matches(/^(?=.*[A-Za-z가-힣]).*[A-Za-z가-힣0-9]*$/) + @ApiProperty({ + description: 'nickname', + example: '닉네임', + }) + nickname: string; + + @IsString() + @ApiProperty({ + description: 'intro', + example: '안녕하세요', + }) + intro: string; + + @IsString() + @IsNotEmpty() + @MinLength(8) + @MaxLength(15) + //알파벳 포함 , 숫자 포함 , 특수문자 포함 + @Matches(/^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/) + @ApiProperty({ + description: 'password', + example: 'abc123456789!', + }) + password: string; + + @IsString() + @IsNotEmpty() + @ApiProperty({ + description: 'password', + example: 'abc123456789!', + }) + confirmPassword: string; +} diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index d52d873..65308e1 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -5,7 +5,7 @@ import { UsersService } from './users.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { DeleteUserDto } from './dto/delete-user.dto'; -import { ApiBearerAuth, ApiCreatedResponse, ApiOkResponse, ApiOperation, ApiResponse, ApiTags, ApiBody, ApiConsumes } from '@nestjs/swagger'; +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 { User } from '@prisma/client'; @@ -46,7 +46,7 @@ export class UsersController { const users = await this.usersService.findAll(); if (!users) { throw new NotFoundException('Users does not exist'); - } + } // TODO: HEE's code const userEntity = users.map((user) => new UserEntity(user)); @@ -86,12 +86,14 @@ export class UsersController { @UseGuards(JwtAuthGuard) // passport를 사용하여 인증 확인 @ApiBearerAuth() // Swagger 문서에 Bearer 토큰 인증 추가 @ApiOperation({ summary: '회원 정보 수정' }) + @ApiResponse({ status: 200, description: '회원 정보가 수정되었습니다' }) + @ApiResponse({ status: 400, description: '중복된 닉네임입니다' }) + @ApiResponse({ status: 401, description: '패스워드가 일치하지 않습니다' }) + @ApiResponse({ status: 404, description: '유저 정보가 존재하지 않습니다' }) + async update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { - const updatedUser = await this.usersService.update(+id, updateUserDto); - if (!updatedUser) { - throw new NotFoundException('User does not exist'); - } - return updatedUser; + await this.usersService.update(+id, updateUserDto); + return {'message' : '회원 정보가 수정되었습니다'}; } // 6. 회원 탈퇴를 한다. @@ -150,17 +152,22 @@ export class UsersController { async updateProfileImage(@Req() req: RequestWithUser, @UploadedFile() file) { const { userId } = req.user; - console.log('updateProfileImage in users.controller.ts - userId:', userId); - console.log('updateProfileImage in users.controller.ts - file:', file); - const user = await this.usersService.findOne(userId); - console.log('User:', user); + // console.log('User:', user); if (!user) { throw new NotFoundException('User does not exist'); } + // 이미지를 s3에 업로드한다. const uploadedFile = await this.awsS3Service.uploadFile(file) as { Location: string }; - return this.usersService.updateProfileImage(userId, uploadedFile.Location); + + // s3에 업로드된 이미지 URL을 DB에 저장한다. + const s3ProfileImgURL = await this.usersService.updateProfileImage(userId, uploadedFile.Location); + + return { + 'message': '이미지가 업로드되었습니다', + 'profileImgURL' : s3ProfileImgURL, + } } // 사용자가 관심 등록한 모임 리스트를 조회한다. diff --git a/src/users/users.service.ts b/src/users/users.service.ts index 8a8c5fb..d816561 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -88,10 +88,40 @@ export class UsersService { /* FiXME */ // 5. user 정보 수정한다. async update(id: number, updateUserDto: UpdateUserDto) { - return await this.prisma.user.update({ + console.log('updateUserDto in users.service:', updateUserDto) + const { nickname, intro, confirmPassword } = updateUserDto; + + const user = await this.prisma.user.findUnique({ where: { userId: id }, - data: updateUserDto, }); + if (!user) { + throw new BadRequestException('유저 정보가 존재하지 않습니다.'); + } + + // 패스워드, 패스워드 확인 일치 여부 확인 + const isPasswordMatching = await bcrypt.compare(confirmPassword, user.password); + if (!isPasswordMatching) { + throw new BadRequestException('패스워드가 일치하지 않습니다.'); + } + // 중복된 닉네임 확인 + const existingNickname = await this.prisma.userDetail.findUnique({ + where: { nickname }, + }); + if (existingNickname) { + throw new ConflictException('중복된 닉네임입니다.'); + } + + // userdetail page 업데이트 + const updatedUser = await this.prisma.userDetail.update({ + where: { userDetailId: user.userId}, + data: { + intro: intro, + nickname: nickname + }, + }); + + return updatedUser; + } // 6. 회원 탈퇴를 한다. @@ -151,17 +181,15 @@ export class UsersService { where: { UserId: id }, }); - console.log('User Detail:', userDetail); - console.log('User Detail ID:', userDetail.userDetailId); - if (!userDetail) { throw new BadRequestException('회원 상세 정보가 존재하지 않습니다.'); } // userDetailId를 사용하여 프로필 이미지를 업데이트한다. - return await this.prisma.userDetail.update({ + const updatedProfileImage = await this.prisma.userDetail.update({ where: { userDetailId: userDetail.userDetailId }, data: { profileImg: profileImg }, }); + return updatedProfileImage.profileImg; } } From c76373e330b074c346b5dacedd731b919232c8be Mon Sep 17 00:00:00 2001 From: erickimme Date: Mon, 16 Oct 2023 23:43:09 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[=EC=9E=91=EC=97=85=EC=A4=91]=20main=20?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EB=94=94=EB=B2=84=EA=B9=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aws/aws.s3.ts | 1 + src/users/users.controller.ts | 1 + src/users/users.service.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/aws/aws.s3.ts b/src/aws/aws.s3.ts index 023766e..4bb15d0 100644 --- a/src/aws/aws.s3.ts +++ b/src/aws/aws.s3.ts @@ -18,6 +18,7 @@ export class AwsS3Service { if (!file) { throw new BadRequestException('No file uploaded'); } + console.log("2. file in aws.s3.ts: ", file); const params = { Bucket: process.env.AWS_BUCKET_NAME || 's3-image-local-mingle', // AWS S3 버킷 이름 diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 65308e1..f24d8f0 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -152,6 +152,7 @@ export class UsersController { async updateProfileImage(@Req() req: RequestWithUser, @UploadedFile() file) { const { userId } = req.user; + console.log("1. file in users.controller.ts:", file); const user = await this.usersService.findOne(userId); // console.log('User:', user); if (!user) { diff --git a/src/users/users.service.ts b/src/users/users.service.ts index d816561..298f6ba 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -185,6 +185,7 @@ export class UsersService { throw new BadRequestException('회원 상세 정보가 존재하지 않습니다.'); } + console.log("3. profileImg URL in usrs.service", profileImg); // userDetailId를 사용하여 프로필 이미지를 업데이트한다. const updatedProfileImage = await this.prisma.userDetail.update({ where: { userDetailId: userDetail.userDetailId }, From 18a8b34ad3a57b9e133b03fda5554b0343ef4a30 Mon Sep 17 00:00:00 2001 From: erickimme Date: Mon, 16 Oct 2023 23:51:25 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[=EC=9E=91=EC=97=85=EC=A4=91]=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=97=85=EB=A1=9C=EB=93=9C=20=EB=94=94?= =?UTF-8?q?=EB=B2=84=EA=B9=85=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aws/aws.s3.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/aws/aws.s3.ts b/src/aws/aws.s3.ts index 4bb15d0..1801945 100644 --- a/src/aws/aws.s3.ts +++ b/src/aws/aws.s3.ts @@ -32,6 +32,7 @@ export class AwsS3Service { if (err) { return reject(err); } + console.log("2.1. file in aws.s3.ts: ", file); resolve(data); }); });