diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index e1c3968..9f0778b 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -2,7 +2,7 @@ name: ModernFarmer CI/CD on: push: - branches: ["feature_13/카카오,-구글-로그인-수정"] + branches: ["feature_14/-유저-관련-API-구현"] pull_request: branches: ["dev"] diff --git a/build.gradle b/build.gradle index a8fb8ae..0fe7026 100644 --- a/build.gradle +++ b/build.gradle @@ -39,6 +39,8 @@ dependencies { implementation group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.2' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.2' runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.2' + + implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE' } tasks.named('test') { diff --git a/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Config.java b/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Config.java new file mode 100644 index 0000000..9d58626 --- /dev/null +++ b/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Config.java @@ -0,0 +1,28 @@ +package modernfarmer.server.farmususer.global.config.s3; + +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class S3Config { + @Value("${cloud.aws.credentials.access-key}") + private String accessKey; + @Value("${cloud.aws.credentials.secret-key}") + private String secretKey; + @Value("${cloud.aws.region.static}") + private String region; + + @Bean + public AmazonS3Client amazonS3Client() { + BasicAWSCredentials awsCredentials= new BasicAWSCredentials(accessKey, secretKey); + return (AmazonS3Client) AmazonS3ClientBuilder.standard() + .withRegion(region) + .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Uploader.java b/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Uploader.java new file mode 100644 index 0000000..f020922 --- /dev/null +++ b/src/main/java/modernfarmer/server/farmususer/global/config/s3/S3Uploader.java @@ -0,0 +1,68 @@ +package modernfarmer.server.farmususer.global.config.s3; + +import com.amazonaws.services.s3.AmazonS3Client; +import com.amazonaws.services.s3.model.CannedAccessControlList; +import com.amazonaws.services.s3.model.PutObjectRequest; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Optional; +import java.util.UUID; + +@Slf4j +@Component +public class S3Uploader { + private final AmazonS3Client amazonS3Client; + + @Value("${cloud.aws.s3.bucket}") + private String bucket; + + public S3Uploader(AmazonS3Client amazonS3Client) { + this.amazonS3Client = amazonS3Client; + } + + public String uploadFiles( + MultipartFile multipartFile, String dirName) throws IOException { + File uploadFile = convert(multipartFile).orElseThrow(() -> + new IllegalArgumentException("error: MultipartFile -> File convert fail")); + return upload(uploadFile, dirName); + } + + public String upload(File uploadFile, String filePath) { + String fileName = filePath + "/" + UUID.randomUUID() + uploadFile.getName(); + String uploadImageUrl = putS3(uploadFile, fileName); + removeNewFile(uploadFile); + return uploadImageUrl; + } + + private String putS3(File uploadFile, String fileName) { + amazonS3Client.putObject( + new PutObjectRequest(bucket, fileName, uploadFile) + .withCannedAcl(CannedAccessControlList.PublicRead)); + return amazonS3Client.getUrl(bucket, fileName).toString(); + } + + private void removeNewFile(File targetFile) { + if (targetFile.delete()) { + System.out.println("File delete success"); + return; + } + System.out.println("File delete fail"); + } + + private Optional convert(MultipartFile file) throws IOException { + File convertFile = new File(System.getProperty("user.dir") + "/" + file.getOriginalFilename()); + if (convertFile.createNewFile()) { + try (FileOutputStream fileOutputStream = new FileOutputStream(convertFile)) { + fileOutputStream.write(file.getBytes()); + } + return Optional.of(convertFile); + } + return Optional.empty(); + } +} \ No newline at end of file diff --git a/src/main/java/modernfarmer/server/farmususer/user/controller/UserController.java b/src/main/java/modernfarmer/server/farmususer/user/controller/UserController.java index 60eed70..f5587cf 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/controller/UserController.java +++ b/src/main/java/modernfarmer/server/farmususer/user/controller/UserController.java @@ -2,18 +2,19 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import modernfarmer.server.farmususer.user.dto.request.ProduceNicknameRequest; +import modernfarmer.server.farmususer.user.dto.response.ProfileImageResponseDto; import modernfarmer.server.farmususer.user.dto.response.ResponseDto; import modernfarmer.server.farmususer.user.dto.response.TokenResponseDto; -import modernfarmer.server.farmususer.user.service.AuthService; import modernfarmer.server.farmususer.user.service.UserService; import modernfarmer.server.farmususer.user.util.JwtTokenProvider; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletRequest; +import java.io.IOException; @Slf4j @RestController @@ -24,6 +25,51 @@ public class UserController { private final UserService userService; private final JwtTokenProvider jwtTokenProvider; + @PostMapping(value = "/profileImage", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseDto produceProfileImage(HttpServletRequest request, @RequestPart("file") MultipartFile multipartFile) throws IOException { + + String userId = jwtTokenProvider.getUserId(request); + log.info(userId); + ResponseDto responseDto = userService.emitProfileImage(Long.valueOf(userId), multipartFile); + + return responseDto; + + } + + @GetMapping(value = "/profileImage") + public ProfileImageResponseDto selectProfileImage(HttpServletRequest request){ + + String userId = jwtTokenProvider.getUserId(request); + + + ProfileImageResponseDto profileImageResponseDto = userService.selectProfileImage(Long.valueOf(userId)); + + return profileImageResponseDto; + } + + + @DeleteMapping(value = "/delete") + public ResponseDto deleteUser(HttpServletRequest request){ + + String userId = jwtTokenProvider.getUserId(request); + + ResponseDto responseDto = userService.deleteUser(Long.valueOf(userId)); + + return responseDto; + } + + + + @PostMapping(value = "/nickname") + public ResponseDto emitNickname(HttpServletRequest request, @RequestBody ProduceNicknameRequest produceNicknameRequest){ + + String userId = jwtTokenProvider.getUserId(request); + + ResponseDto responseDto = userService.emitNickname(Long.valueOf(userId), produceNicknameRequest.getNickName()); + + return responseDto; + } + @DeleteMapping("/logout") public ResponseDto logout(HttpServletRequest request) { @@ -50,4 +96,6 @@ public TokenResponseDto reissueToken(HttpServletRequest request) { return reissueTokenResponseDto; } + + } diff --git a/src/main/java/modernfarmer/server/farmususer/user/dto/request/ProduceNicknameRequest.java b/src/main/java/modernfarmer/server/farmususer/user/dto/request/ProduceNicknameRequest.java new file mode 100644 index 0000000..a71b618 --- /dev/null +++ b/src/main/java/modernfarmer/server/farmususer/user/dto/request/ProduceNicknameRequest.java @@ -0,0 +1,14 @@ +package modernfarmer.server.farmususer.user.dto.request; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class ProduceNicknameRequest { + + private String nickName; +} diff --git a/src/main/java/modernfarmer/server/farmususer/user/dto/response/ProfileImageResponseDto.java b/src/main/java/modernfarmer/server/farmususer/user/dto/response/ProfileImageResponseDto.java new file mode 100644 index 0000000..1ae6158 --- /dev/null +++ b/src/main/java/modernfarmer/server/farmususer/user/dto/response/ProfileImageResponseDto.java @@ -0,0 +1,14 @@ +package modernfarmer.server.farmususer.user.dto.response; + + +import lombok.*; +import lombok.experimental.SuperBuilder; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@SuperBuilder +public class ProfileImageResponseDto extends ResponseDto{ + + private String profileImage; +} diff --git a/src/main/java/modernfarmer/server/farmususer/user/dto/response/ResponseDto.java b/src/main/java/modernfarmer/server/farmususer/user/dto/response/ResponseDto.java index 49a0746..d4169cb 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/dto/response/ResponseDto.java +++ b/src/main/java/modernfarmer/server/farmususer/user/dto/response/ResponseDto.java @@ -6,8 +6,8 @@ @NoArgsConstructor @AllArgsConstructor -@Data @SuperBuilder +@Getter public class ResponseDto { private int code; private String message; diff --git a/src/main/java/modernfarmer/server/farmususer/user/dto/response/TokenResponseDto.java b/src/main/java/modernfarmer/server/farmususer/user/dto/response/TokenResponseDto.java index d992472..beba6e7 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/dto/response/TokenResponseDto.java +++ b/src/main/java/modernfarmer/server/farmususer/user/dto/response/TokenResponseDto.java @@ -2,17 +2,14 @@ import lombok.*; +import lombok.experimental.SuperBuilder; @NoArgsConstructor @AllArgsConstructor @ToString -@Builder +@SuperBuilder @Getter -public class TokenResponseDto { - - private int code; - - private String message; +public class TokenResponseDto extends ResponseDto{ private String accessToken; diff --git a/src/main/java/modernfarmer/server/farmususer/user/repository/UserRepository.java b/src/main/java/modernfarmer/server/farmususer/user/repository/UserRepository.java index cacff0b..33c6fc2 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/repository/UserRepository.java +++ b/src/main/java/modernfarmer/server/farmususer/user/repository/UserRepository.java @@ -3,6 +3,7 @@ import io.lettuce.core.dynamic.annotation.Param; import modernfarmer.server.farmususer.user.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -11,12 +12,23 @@ @Repository public interface UserRepository extends JpaRepository { - - Optional findByUsernumber(String usernumber); @Query("SELECT a.role FROM User AS a WHERE a.id = :userId") String findUserRole(@Param("userId") Long userId); + @Modifying + @Query("update User as u set u.nickname = :nickName where u.id = :userId") + void updateUserNickname(@Param("nickName") String nickName, @Param("userId") Long userId); + @Modifying + @Query("delete from User as u where u.id = :userId") + void deleteUser(@Param("userId") Long userId); + + @Query("select u.profileImage from User as u where u.id = :userId") + String selectUserProfileImage(@Param("userId") Long userId); + @Modifying + @Query("update User as u set u.profileImage = :profileImage where u.id = :userId") + void emitUserProfileImage(@Param("userId") Long userId, @Param("profileImage") String profileImage); + diff --git a/src/main/java/modernfarmer/server/farmususer/user/service/AuthService.java b/src/main/java/modernfarmer/server/farmususer/user/service/AuthService.java index 1b73a5c..9978c2a 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/service/AuthService.java +++ b/src/main/java/modernfarmer/server/farmususer/user/service/AuthService.java @@ -28,7 +28,7 @@ public class AuthService{ public UserRepository userRepository; private final WebClient webClient; - private boolean early = false; + @Autowired public AuthService(WebClient webClient, UserRepository userRepository, JwtTokenProvider jwtTokenProvider, RedisTemplate redisTemplate) { @@ -41,6 +41,7 @@ public AuthService(WebClient webClient, UserRepository userRepository, JwtTokenP public TokenResponseDto googleLogin(String accessToken) { User user; + boolean early = false; Mono userInfoMono = getUserGoogleInfo(accessToken); GoogleUserResponseDto userInfo = userInfoMono.block(); @@ -88,6 +89,7 @@ public TokenResponseDto googleLogin(String accessToken) { public TokenResponseDto kakaoLogin(String accessToken) { User user; + boolean early = false; Mono userInfoMono = getUserKakaoInfo(accessToken); KakaoUserResponseDto userInfo = userInfoMono.block(); diff --git a/src/main/java/modernfarmer/server/farmususer/user/service/UserService.java b/src/main/java/modernfarmer/server/farmususer/user/service/UserService.java index b3cc99f..6cec29c 100644 --- a/src/main/java/modernfarmer/server/farmususer/user/service/UserService.java +++ b/src/main/java/modernfarmer/server/farmususer/user/service/UserService.java @@ -1,6 +1,9 @@ package modernfarmer.server.farmususer.user.service; +import lombok.extern.slf4j.Slf4j; +import modernfarmer.server.farmususer.global.config.s3.S3Uploader; import modernfarmer.server.farmususer.global.exception.notfound.NotFoundRefreshTokenException; +import modernfarmer.server.farmususer.user.dto.response.ProfileImageResponseDto; import modernfarmer.server.farmususer.user.dto.response.ResponseDto; import modernfarmer.server.farmususer.user.dto.response.TokenResponseDto; import modernfarmer.server.farmususer.user.repository.UserRepository; @@ -8,27 +11,93 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; import org.springframework.web.reactive.function.client.WebClient; -import java.util.Objects; +import java.io.IOException; +@Slf4j @Service public class UserService { public JwtTokenProvider jwtTokenProvider; public RedisTemplate redisTemplate; - public UserRepository userRepository; + public final S3Uploader s3Uploader; - private final WebClient webClient; @Autowired - public UserService(WebClient webClient, UserRepository userRepository, JwtTokenProvider jwtTokenProvider, RedisTemplate redisTemplate) { - this.webClient = webClient; + public UserService(UserRepository userRepository, JwtTokenProvider jwtTokenProvider, RedisTemplate redisTemplate, + S3Uploader s3Uploader + ) { + this.userRepository = userRepository; this.jwtTokenProvider = jwtTokenProvider; this.redisTemplate = redisTemplate; + this.s3Uploader = s3Uploader; + + } + @Transactional + public ResponseDto emitProfileImage(Long userId, MultipartFile multipartFile) throws IOException { + + String imageUrl = s3Uploader.uploadFiles(multipartFile, "userprofileimage"); + log.info(imageUrl); + + userRepository.emitUserProfileImage(userId, imageUrl); + + ResponseDto responseDto = ResponseDto + .builder() + .code(200) + .message("OK") + .build(); + + return responseDto; + } + + public ProfileImageResponseDto selectProfileImage(Long userId){ + + String userProfileImage = userRepository.selectUserProfileImage(userId); + + + ProfileImageResponseDto profileImageResponseDto = ProfileImageResponseDto + .builder() + .code(200) + .message("OK") + .profileImage(userProfileImage) + .build(); + + + return profileImageResponseDto; + } + + @Transactional + public ResponseDto deleteUser(Long userId){ + + userRepository.deleteUser(userId); + + ResponseDto responseDto = ResponseDto + .builder() + .code(200) + .message("OK") + .build(); + + return responseDto; + } + + + @Transactional + public ResponseDto emitNickname(Long userId, String nickName){ + + userRepository.updateUserNickname(nickName, userId); + + ResponseDto responseDto = ResponseDto.builder() + .code(200) + .message("OK") + .build(); + + return responseDto; }