-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
66 changed files
with
3,480 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
name: 'sports_echo_ci' | ||
on: | ||
push: | ||
branches: [ "feature/*", "hotfix" ] | ||
pull_request: | ||
branches: [ "dev1" ] | ||
permissions: | ||
contents: read | ||
pull-requests: read | ||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Git Checkout | ||
uses: actions/checkout@v4 | ||
|
||
# .properties file 생성 | ||
- name: application.properties 생성 | ||
run: | | ||
touch ./src/main/resources/application-prod.yml | ||
touch ./src/main/resources/application-test.yml | ||
echo "${{ secrets.PROD_YML }}" > ./application-prod.yml | ||
echo "${{ secrets.TEST_PROD_YML }}" > ./application-test.yml | ||
- name: Java Setup | ||
uses: actions/setup-java@v3 | ||
with: | ||
java-version: '17' | ||
distribution: 'oracle' | ||
cache: gradle | ||
|
||
- name: Build with Gradle | ||
env: | ||
SPRING_PROFILES_ACTIVE: test | ||
run: | | ||
./gradlew clean build | ||
- name: Publish Unit Test Results | ||
uses: EnricoMi/publish-unit-test-result-action@v1 | ||
if: ${{ always() }} | ||
with: | ||
files: build/test-results/**/*.xml | ||
|
||
- name: Upload Jacoco Report | ||
if: ${{ failure() }} | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
name: jacoco-report | ||
path: build/reports/jacoco/test/html |
158 changes: 158 additions & 0 deletions
158
src/main/java/com/sportsecho/common/oauth/OAuthUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package com.sportsecho.common.oauth; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.sportsecho.common.oauth.exception.OAuthErrorCode; | ||
import com.sportsecho.global.exception.GlobalException; | ||
import com.sportsecho.member.entity.Member; | ||
import com.sportsecho.member.entity.MemberRole; | ||
import com.sportsecho.member.repository.MemberRepository; | ||
import java.net.URI; | ||
import java.util.UUID; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.RequestEntity; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.util.LinkedMultiValueMap; | ||
import org.springframework.util.MultiValueMap; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
/** | ||
* kakaoOAuthDocs: https://developers.kakao.com/docs/latest/ko/kakaologin/rest-api#request-token | ||
* naverOAuthDocs: https://developers.naver.com/docs/login/devguide/devguide.md | ||
* googleOAuthDocs: https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko | ||
* */ | ||
|
||
@Service | ||
@Slf4j(topic = "OAUthUtil") | ||
@RequiredArgsConstructor | ||
public class OAuthUtil { | ||
|
||
@Value("${oauth.api.key.kakao}") | ||
private String kakaoApiKey; | ||
|
||
@Value("${oauth.api.key.naver}") | ||
private String naverApiKey; | ||
|
||
@Value("${oauth.api.secret.naver}") | ||
private String naverApiSecret; | ||
|
||
@Value("${oauth.api.key.google}") | ||
private String googleApiKey; | ||
|
||
@Value("${oauth.api.secret.google}") | ||
private String googleApiSecret; | ||
|
||
private final MemberRepository memberRepository; | ||
|
||
private final RestTemplate restTemplate; | ||
private final PasswordEncoder passwordEncoder; | ||
|
||
public JsonNode getToken(URI uri, SocialType socialType, String code) { | ||
try { | ||
// HTTP Header 생성 | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); | ||
|
||
RequestEntity<MultiValueMap<String, String>> requestEntity = RequestEntity | ||
.post(uri) | ||
.headers(headers) | ||
.body(generateBody(socialType, code)); | ||
|
||
// HTTP 요청 보내기 | ||
ResponseEntity<String> response = restTemplate.exchange( | ||
requestEntity, | ||
String.class | ||
); | ||
|
||
// HTTP 응답 (JSON) -> 액세스 토큰 파싱 | ||
return new ObjectMapper().readTree(response.getBody()); | ||
} catch (JsonProcessingException e) { | ||
throw new GlobalException(OAuthErrorCode.ILLEGAL_REQUEST); | ||
} | ||
} | ||
|
||
public JsonNode getMemberInfo(URI uri, String accessToken) { | ||
try { | ||
// HTTP Header 생성 | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.add("Authorization", "Bearer " + accessToken); | ||
headers.add("Content-type", "application/x-www-form-urlencoded;charset=utf-8"); | ||
|
||
RequestEntity<MultiValueMap<String, String>> requestEntity = RequestEntity | ||
.post(uri) | ||
.headers(headers) | ||
.body(new LinkedMultiValueMap<>()); | ||
|
||
//HTTP 요청 보내기 | ||
ResponseEntity<String> response = restTemplate.exchange( | ||
requestEntity, | ||
String.class | ||
); | ||
|
||
return new ObjectMapper().readTree(response.getBody()); | ||
} catch(JsonProcessingException e) { | ||
throw new GlobalException(OAuthErrorCode.ILLEGAL_REQUEST); | ||
} | ||
} | ||
|
||
public Member registerSocialMemberIfNeeded(Long socialId, String memberName, String email, SocialType socialType) { | ||
Member socialMember = memberRepository.findBySocialIdAndSocialType(socialId, socialType).orElse(null); | ||
|
||
if (socialMember == null) { | ||
// 소셜 사용자 email과 동일한 email 가진 회원이 있는지 확인 | ||
Member sameEmailMember = memberRepository.findByEmail(email).orElse(null); | ||
|
||
if (sameEmailMember != null) { | ||
socialMember = sameEmailMember; | ||
} else { | ||
String encodedPassword = passwordEncoder.encode(UUID.randomUUID().toString()); | ||
|
||
socialMember = Member.builder() | ||
.memberName(memberName) | ||
.email(email) | ||
.password(encodedPassword) | ||
.role(MemberRole.CUSTOMER) | ||
.build(); | ||
} | ||
|
||
//socialId update 및 저장 | ||
socialMember = socialMember.updateSocialIdAndType(socialId, socialType); | ||
memberRepository.save(socialMember); | ||
} | ||
|
||
return socialMember; | ||
} | ||
|
||
private MultiValueMap<String, String> generateBody(SocialType socialType, String code) { | ||
MultiValueMap<String, String> body = new LinkedMultiValueMap<>(); | ||
|
||
if(SocialType.KAKAO.equals(socialType)) { | ||
body.add("grant_type", "authorization_code"); | ||
body.add("client_id", kakaoApiKey); | ||
body.add("redirect_uri", "http://localhost:8080/api/members/kakao/callback"); | ||
body.add("code", code); | ||
} | ||
if(SocialType.NAVER.equals(socialType)) { | ||
body.add("grant_type", "authorization_code"); | ||
body.add("client_id", naverApiKey); | ||
body.add("client_secret", naverApiSecret); | ||
body.add("code", code); | ||
body.add("state", "9kgsGTfH4j7IyAkg"); | ||
} | ||
if(SocialType.GOOGLE.equals(socialType)) { | ||
body.add("grant_type", "authorization_code"); | ||
body.add("client_id", googleApiKey); | ||
body.add("client_secret", googleApiSecret); | ||
body.add("code", code); | ||
body.add("redirect_uri", "http://localhost:8080/api/members/google/callback"); | ||
} | ||
|
||
return body; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.sportsecho.common.oauth; | ||
|
||
public enum SocialType { | ||
KAKAO, NAVER, GOOGLE | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/com/sportsecho/common/oauth/exception/OAuthErrorCode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.sportsecho.common.oauth.exception; | ||
|
||
import com.sportsecho.global.exception.BaseErrorCode; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import org.springframework.http.HttpStatus; | ||
|
||
@Getter | ||
@AllArgsConstructor | ||
public enum OAuthErrorCode implements BaseErrorCode { | ||
|
||
ILLEGAL_REQUEST(HttpStatus.BAD_REQUEST, "잘못된 OAuth 로그인 요청입니다."), | ||
; | ||
|
||
private final HttpStatus status; | ||
private final String msg; | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/sportsecho/global/util/s3/AWSConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.sportsecho.global.util.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 AWSConfig { | ||
|
||
@Value("${cloud.aws.credentials.accessKey}") | ||
private String iamAccessKey; // IAM Access Key | ||
|
||
@Value("${cloud.aws.credentials.secretKey}") | ||
private String iamSecretKey; // IAM Secret Key | ||
|
||
private String region = "ap-northeast-2"; // Bucket Region (서울) | ||
|
||
@Bean | ||
public AmazonS3Client amazonS3Client() { | ||
BasicAWSCredentials basicAWSCredentials = new BasicAWSCredentials(iamAccessKey, iamSecretKey); | ||
return (AmazonS3Client) AmazonS3ClientBuilder.standard() | ||
.withRegion(region) | ||
.withCredentials(new AWSStaticCredentialsProvider(basicAWSCredentials)) | ||
.build(); | ||
} | ||
|
||
|
||
} |
51 changes: 51 additions & 0 deletions
51
src/main/java/com/sportsecho/global/util/s3/S3Uploader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.sportsecho.global.util.s3; | ||
|
||
import com.amazonaws.services.s3.AmazonS3Client; | ||
import com.amazonaws.services.s3.model.PutObjectRequest; | ||
import java.io.File; | ||
import java.io.FileOutputStream; | ||
import java.io.IOException; | ||
import java.util.Objects; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Slf4j | ||
@RequiredArgsConstructor | ||
@Service | ||
public class S3Uploader { | ||
|
||
private final AmazonS3Client amazonS3Client; | ||
|
||
@Value("${cloud.aws.s3.bucket}") | ||
private String bucket; | ||
|
||
@Value("${cloud.aws.region.static}") | ||
private String region; | ||
|
||
public String upload(MultipartFile file, String filename) { | ||
File fileObj = converMultiPartFileToFile(file); | ||
amazonS3Client.putObject(new PutObjectRequest(bucket, filename, fileObj)); | ||
fileObj.delete(); | ||
|
||
String fileurl = amazonS3Client.getUrl(bucket, filename).toString(); | ||
|
||
return fileurl; | ||
} | ||
|
||
private File converMultiPartFileToFile(MultipartFile file) { | ||
File convertedFile = new File(Objects.requireNonNull(file.getOriginalFilename())); | ||
try (FileOutputStream fileOutputStream = new FileOutputStream(convertedFile)) { | ||
fileOutputStream.write(file.getBytes()); | ||
} catch (IOException e) { | ||
log.error("파일 변환 실패 : ", e); | ||
} | ||
return convertedFile; | ||
} | ||
|
||
public void deleteFile(String filename) { | ||
amazonS3Client.deleteObject(bucket, filename); | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
src/main/java/com/sportsecho/global/util/s3/controller/FileUploadController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.sportsecho.global.util.s3.controller; | ||
|
||
import com.sportsecho.global.util.s3.service.FileUploadService; | ||
import com.sportsecho.member.entity.MemberDetailsImpl; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
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; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api") | ||
public class FileUploadController { | ||
|
||
private final FileUploadService fileUploadService; | ||
|
||
@PostMapping("/image") | ||
public String uploadProductImage( | ||
@RequestParam(value = "file")MultipartFile file, | ||
@RequestParam(value = "identifier") String identifier, | ||
@AuthenticationPrincipal MemberDetailsImpl memberDetails | ||
) { | ||
return fileUploadService.uploadFile(memberDetails.getMember(), file, identifier); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/java/com/sportsecho/global/util/s3/service/FileUploadService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package com.sportsecho.global.util.s3.service; | ||
|
||
import com.sportsecho.global.exception.GlobalException; | ||
import com.sportsecho.global.util.s3.S3Uploader; | ||
import com.sportsecho.member.entity.Member; | ||
import com.sportsecho.member.entity.MemberRole; | ||
import com.sportsecho.product.exception.ProductErrorCode; | ||
import com.sportsecho.product.repository.ProductRepository; | ||
import java.util.UUID; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class FileUploadService { | ||
|
||
private final S3Uploader s3Uploader; | ||
|
||
public String uploadFile(Member member, MultipartFile file, String identifier) { | ||
|
||
// if (member.getRole().equals(MemberRole.CUSTOMER)) { | ||
// throw new GlobalException(ProductErrorCode.NO_AUTHORIZATION); | ||
// } | ||
|
||
UUID uuid = UUID.randomUUID(); | ||
String fileName = identifier + uuid; | ||
|
||
return s3Uploader.upload(file, fileName); | ||
} | ||
} |
Oops, something went wrong.