Skip to content

Commit

Permalink
Merge pull request #12 from Leets-Official/feat/#11/프로필-관련-기능-구현
Browse files Browse the repository at this point in the history
[feat] 프로필 관련 기능 구현
  • Loading branch information
ehs208 authored Oct 20, 2024
2 parents 2d5c1e3 + f75f96a commit 1d9386e
Show file tree
Hide file tree
Showing 15 changed files with 367 additions and 30 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/github-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ jobs:
echo "${{ secrets.YML_OAUTH }}" > ./application-oauth.yml
shell: bash

# 환경별 yml 파일 생성(5) - bucket
- name: make application-bucket.yml
if: contains(github.ref, 'develop')
run: |
cd ./src/main/resources
touch ./application-bucket.yml
echo "${{ secrets.YML_BUCKET }}" > ./application-bucket.yml
shell: bash

# gradle build
- name: Build with Gradle
run: ./gradlew build -x test
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ dependencies {
testImplementation 'org.springframework.security:spring-security-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// S3 Bucket
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0'

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,66 @@
package com.leets.xcellentbe.domain.user.controller;

import java.io.IOException;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.leets.xcellentbe.domain.user.domain.User;
import com.leets.xcellentbe.domain.user.dto.UserLoginRequestDto;
import com.leets.xcellentbe.domain.user.dto.UserProfileRequestDto;
import com.leets.xcellentbe.domain.user.dto.UserProfileResponseDto;
import com.leets.xcellentbe.domain.user.dto.UserSignUpRequestDto;
import com.leets.xcellentbe.domain.user.service.S3UploadService;
import com.leets.xcellentbe.domain.user.service.UserService;
import com.leets.xcellentbe.global.auth.email.EmailRequestDto;
import com.leets.xcellentbe.global.response.GlobalResponseDto;

import io.swagger.v3.oas.annotations.Operation;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;

@RestController
@RequestMapping("/api/user")
@RequestMapping("/api/profile")
@RequiredArgsConstructor
public class UserController {
// private final UserService userService;
//
// @PostMapping("/auth/register")
// @Operation(summary = "회원가입", description = "회원가입을 합니다.")
// public ResponseEntity<GlobalResponseDto<String>> register(@RequestBody UserSignUpRequestDto userSignUpRequestDto) {
// return ResponseEntity.status(HttpStatus.CREATED)
// .body(GlobalResponseDto.success(userService.register(userSignUpRequestDto), HttpStatus.CREATED.value()));
// }
//
// @Operation(summary = "로그인", description = "사용자의 이메일과 비밀번호로 로그인합니다.")
// @PostMapping("/auth/login")
// public String login(@RequestBody UserLoginRequestDto userLoginRequestDto) {
// // 로그인 로직 처리
// return "로그인 성공";
// }
}
private final UserService userService;

@GetMapping("/info")
@Operation(summary = "프로필 조회", description = "사용자의 프로필 내용을 조회합니다.")
public ResponseEntity<GlobalResponseDto<UserProfileResponseDto>> getProfile(HttpServletRequest request) {
return ResponseEntity.status(HttpStatus.OK)
.body(GlobalResponseDto.success(userService.getProfile(request)));
}

@PatchMapping("/info")
@Operation(summary = "프로필 수정", description = "사용자의 프로필을 수정합니다.")
public ResponseEntity<GlobalResponseDto<String>> updateProfile(@RequestBody UserProfileRequestDto userProfileRequestDto, HttpServletRequest request) {
userService.updateProfile(request,userProfileRequestDto);
return ResponseEntity.status(HttpStatus.OK).body(GlobalResponseDto.success());
}

@PatchMapping("/profile-image")
@Operation(summary = "프로필 이미지 수정", description = "사용자의 프로필 이미지를 수정합니다.")
public ResponseEntity<GlobalResponseDto<String>> updateProfileImage(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
return ResponseEntity.status(HttpStatus.OK)
.body(GlobalResponseDto.success(userService.updateProfileImage(file, request)));

}

@PatchMapping("/background-image")
@Operation(summary = "배경 이미지 수정", description = "사용자의 배경 이미지를 수정합니다.")
public ResponseEntity<GlobalResponseDto<String>> updateBackgroundImage (@RequestParam("file") MultipartFile file, HttpServletRequest request){
return ResponseEntity.status(HttpStatus.OK)
.body(GlobalResponseDto.success(userService.updateBackgroundProfileImage(file, request)));
}
}
24 changes: 18 additions & 6 deletions src/main/java/com/leets/xcellentbe/domain/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,24 @@ public static User create(String customId, String email, String userName, String
.build();
}

public static User socialCreate(String email, String socialEmail) {
return User.builder()
.email(email)
.userRole(Role.GUEST)
.socialEmail(socialEmail)
.build();
public void updateProfile(String userName, String phoneNumber, String customId, int userBirthYear, int userBirthDay, int userBirthMonth, String description, String websiteUrl, String location) {
this.userName = userName;
this.customId = customId;
this.description = description;
this.websiteUrl = websiteUrl;
this.location = location;
this.phoneNumber = phoneNumber;
this.userBirthYear = userBirthYear;
this.userBirthDay = userBirthDay;
this.userBirthMonth = userBirthMonth;
}

public void updateProfileImage(String updateProfileImageUrl) {
this.profileImageUrl = updateProfileImageUrl;
}

public void updateBackgroundImage(String updateBackgroundImageUrl) {
this.backgroundProfileImageUrl = updateBackgroundImageUrl;
}

public void updateRefreshToken(String updateRefreshToken) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.leets.xcellentbe.domain.user.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter

public class UserProfileRequestDto {
private String customId;
private String userName;
private String profileImageUrl;
private String backgroundProfileImageUrl;
private String phoneNumber;
private String description;
private String websiteUrl;
private String location;
private int userBirthYear;
private int userBirthMonth;
private int userBirthDay;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.leets.xcellentbe.domain.user.dto;

import com.leets.xcellentbe.domain.user.domain.User;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Getter
public class UserProfileResponseDto {
private String email;
private String customId;
private String userName;
private String profileImageUrl;
private String backgroundProfileImageUrl;
private String phoneNumber;
private String description;
private String websiteUrl;
private String location;
private int userBirthYear;
private int userBirthMonth;
private int userBirthDay;

@Builder
private UserProfileResponseDto(String email, String customId, String userName, String profileImageUrl,
String backgroundProfileImageUrl, String phoneNumber, String description, String websiteUrl, String location,
int userBirthYear, int userBirthMonth, int userBirthDay) {
this.email = email;
this.customId = customId;
this.userName = userName;
this.profileImageUrl = profileImageUrl;
this.backgroundProfileImageUrl = backgroundProfileImageUrl;
this.phoneNumber = phoneNumber;
this.description = description;
this.websiteUrl = websiteUrl;
this.location = location;
this.userBirthYear = userBirthYear;
this.userBirthMonth = userBirthMonth;
this.userBirthDay = userBirthDay;
}

public static UserProfileResponseDto from(User user) {
return UserProfileResponseDto.builder()
.email(user.getEmail())
.customId(user.getCustomId())
.userName(user.getUserName())
.profileImageUrl(user.getProfileImageUrl())
.backgroundProfileImageUrl(user.getBackgroundProfileImageUrl())
.phoneNumber(user.getPhoneNumber())
.description(user.getDescription())
.websiteUrl(user.getWebsiteUrl())
.location(user.getLocation())
.userBirthYear(user.getUserBirthYear())
.userBirthMonth(user.getUserBirthMonth())
.userBirthDay(user.getUserBirthDay())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.leets.xcellentbe.domain.user.exception;

import com.leets.xcellentbe.global.error.ErrorCode;
import com.leets.xcellentbe.global.error.exception.CommonException;

public class InvalidFileFormat extends CommonException {
public InvalidFileFormat() {
super(ErrorCode.INVALID_FILE_FORMAT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.leets.xcellentbe.domain.user.service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.CannedAccessControlList;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.leets.xcellentbe.domain.user.exception.InvalidFileFormat;
import com.leets.xcellentbe.global.error.exception.custom.InternalServerErrorException;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequiredArgsConstructor
@Service
public class S3UploadService {
private final AmazonS3Client amazonS3Client;

@Value("${cloud.aws.s3.bucket}")
private String bucket;

// MultipartFile을 전달받아 File로 전환한 후 S3에 업로드
public String upload(MultipartFile multipartFile, String dirName) { // dirName의 디렉토리가 S3 Bucket 내부에 생성됨
String fileName = multipartFile.getOriginalFilename();
if ((fileName.endsWith(".png") || fileName.endsWith(".jpg"))) {
throw new InvalidFileFormat();
}

try {
File uploadFile = convert(multipartFile).
orElseThrow(() -> new RuntimeException());
return upload(uploadFile, dirName);
} catch(IOException e) {
throw new InternalServerErrorException();
}

}

private String upload(File uploadFile, String dirName) {
String fileName = dirName + "/" + uploadFile.getName();
String uploadImageUrl = putS3(uploadFile, fileName);

removeNewFile(uploadFile); // convert()함수로 인해서 로컬에 생성된 File 삭제 (MultipartFile -> File 전환 하며 로컬에 파일 생성됨)

return uploadImageUrl; // 업로드된 파일의 S3 URL 주소 반환
}

private String putS3(File uploadFile, String fileName) {
amazonS3Client.putObject(
new PutObjectRequest(bucket, fileName, uploadFile)
.withCannedAcl(CannedAccessControlList.PublicRead) // PublicRead 권한으로 업로드 됨
);
return amazonS3Client.getUrl(bucket, fileName).toString();
}

private void removeNewFile(File targetFile) {
if(targetFile.delete()) {
log.info("파일이 삭제되었습니다.");
}else {
log.info("파일이 삭제되지 못했습니다.");
}
}

private Optional<File> convert(MultipartFile file) throws IOException {
File convertFile = new File(file.getOriginalFilename()); // 업로드한 파일의 이름
if(convertFile.createNewFile()) {
try (FileOutputStream fos = new FileOutputStream(convertFile)) {
fos.write(file.getBytes());
}
return Optional.of(convertFile);
}
return Optional.empty();
}

public void removeFile(String fileUrl, String filePath) {
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
amazonS3Client.deleteObject(bucket, filePath + fileName);
}
}
Loading

0 comments on commit 1d9386e

Please sign in to comment.