Skip to content

Commit

Permalink
Merge pull request #197 from tipi-tapi/develop
Browse files Browse the repository at this point in the history
Release 1.1.1
  • Loading branch information
akalswl14 authored Aug 20, 2023
2 parents 705997b + 688b69d commit 53e4289
Show file tree
Hide file tree
Showing 10 changed files with 290 additions and 116 deletions.
201 changes: 106 additions & 95 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -1,113 +1,124 @@
name: main branch cd

on:
push:
branches: [ "main" ]
push:
branches: [ "main" ]

env:
APPLICATION_PATH: ./src/main/resources/application.yml
PROD_PATH: ./src/main/resources/application-prod.yml
OAUTH_PATH: ./src/main/resources/application-oauth.yml
AWS_PATH: ./src/main/resources/application-aws.yml
OPENAI_PATH: ./src/main/resources/application-openai.yml
APPLICATION_PATH: ./src/main/resources/application.yml
PROD_PATH: ./src/main/resources/application-prod.yml
OAUTH_PATH: ./src/main/resources/application-oauth.yml
AWS_PATH: ./src/main/resources/application-aws.yml
OPENAI_PATH: ./src/main/resources/application-openai.yml
R2_PATH: ./src/main/resources/application-r2.yml

jobs:
deploy:
runs-on: ubuntu-latest
environment: prod
steps:
- name: checkout
uses: actions/checkout@v3
deploy:
runs-on: ubuntu-latest
environment: prod
steps:
- name: checkout
uses: actions/checkout@v3

- name: application.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.APPLICATION_PATH }}
env:
encryptor.secret.key: ${{ secrets.ENCRYPTOR_SECRET_KEY }}
presigned-image.expiration.admin-diaries: ${{ secrets.PRESIGNED_IMAGE_EXPIRATION_ADMIN_DIARIES }}
- name: application.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.APPLICATION_PATH }}
env:
encryptor.secret.key: ${{ secrets.ENCRYPTOR_SECRET_KEY }}
presigned-image.expiration.admin-diaries: ${{ secrets.PRESIGNED_IMAGE_EXPIRATION_ADMIN_DIARIES }}

- name: application-prod.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.PROD_PATH }}
env:
spring.datasource.url: ${{ secrets.RDS_URL }}
spring.datasource.username: ${{ secrets.RDS_USERNAME }}
spring.datasource.password: ${{ secrets.RDS_PASSWORD }}
- name: application-prod.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.PROD_PATH }}
env:
spring.datasource.url: ${{ secrets.RDS_URL }}
spring.datasource.username: ${{ secrets.RDS_USERNAME }}
spring.datasource.password: ${{ secrets.RDS_PASSWORD }}

- name: application-oauth.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.OAUTH_PATH }}
env:
oauth2.google.client-id: ${{ secrets.GOOGLE_CLIENT_ID }}
oauth2.google.client-secret: ${{ secrets.GOOGLE_CLIENT_SECRET }}
oauth2.google.token-url: ${{ secrets.GOOGLE_TOKEN_URL }}
oauth2.google.user-info-url: ${{ secrets.GOOGLE_USER_INFO_URL }}
oauth2.google.redirect-uri: ${{ secrets.GOOGLE_REDIRECT_URI }}
oauth2.google.delete-account-url: ${{ secrets.GOOGLE_DELETE_ACCOUNT_URL }}
oauth2.apple.ios.client-id: ${{ secrets.APPLE_IOS_CLIENT_ID }}
oauth2.apple.ios.team-id: ${{ secrets.APPLE_IOS_TEAM_ID }}
oauth2.apple.ios.key-id: ${{ secrets.APPLE_IOS_KEY_ID }}
oauth2.apple.ios.private-key: ${{ secrets.APPLE_IOS_PRIVATE_KEY }}
oauth2.apple.ios.token-url: ${{ secrets.APPLE_IOS_TOKEN_URL }}
oauth2.apple.ios.delete-account-url: ${{ secrets.APPLE_IOS_DELETE_ACCOUNT_URL }}
jwt.secret: ${{ secrets.JWT_SECRET }}
- name: application-oauth.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.OAUTH_PATH }}
env:
oauth2.google.client-id: ${{ secrets.GOOGLE_CLIENT_ID }}
oauth2.google.client-secret: ${{ secrets.GOOGLE_CLIENT_SECRET }}
oauth2.google.token-url: ${{ secrets.GOOGLE_TOKEN_URL }}
oauth2.google.user-info-url: ${{ secrets.GOOGLE_USER_INFO_URL }}
oauth2.google.redirect-uri: ${{ secrets.GOOGLE_REDIRECT_URI }}
oauth2.google.delete-account-url: ${{ secrets.GOOGLE_DELETE_ACCOUNT_URL }}
oauth2.apple.ios.client-id: ${{ secrets.APPLE_IOS_CLIENT_ID }}
oauth2.apple.ios.team-id: ${{ secrets.APPLE_IOS_TEAM_ID }}
oauth2.apple.ios.key-id: ${{ secrets.APPLE_IOS_KEY_ID }}
oauth2.apple.ios.private-key: ${{ secrets.APPLE_IOS_PRIVATE_KEY }}
oauth2.apple.ios.token-url: ${{ secrets.APPLE_IOS_TOKEN_URL }}
oauth2.apple.ios.delete-account-url: ${{ secrets.APPLE_IOS_DELETE_ACCOUNT_URL }}
jwt.secret: ${{ secrets.JWT_SECRET }}

- name: application-aws.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.AWS_PATH }}
env:
cloud.aws.credentials.secret-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
cloud.aws.credentials.access-key: ${{ secrets.AWS_ACCESS_KEY_ID }}
cloud.aws.s3.bucket: ${{ secrets.AWS_S3_BUCKET }}
- name: application-aws.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.AWS_PATH }}
env:
cloud.aws.credentials.secret-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
cloud.aws.credentials.access-key: ${{ secrets.AWS_ACCESS_KEY_ID }}
cloud.aws.s3.bucket: ${{ secrets.AWS_S3_BUCKET }}

- name: application-openai.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.OPENAI_PATH }}
env:
openai.api.key: ${{ secrets.OPENAI_API_KEY }}
openai.dalle.url: ${{ secrets.DALLE_API_URL }}
- name: application-openai.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.OPENAI_PATH }}
env:
openai.api.key: ${{ secrets.OPENAI_API_KEY }}
openai.dalle.url: ${{ secrets.DALLE_API_URL }}

- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
- name: application-r2.yml setting
uses: microsoft/variable-substitution@v1
with:
files: ${{ env.R2_PATH }}
env:
r2.credentials.secret-key: ${{ secrets.R2_SECRET_ACCESS_KEY }}
r2.credentials.access-key: ${{ secrets.R2_ACCESS_KEY_ID }}
r2.bucket: ${{ secrets.R2_BUCKET_NAME }}
r2.account-id: ${{ secrets.R2_ACCOUNT_ID }}

- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'

- name: Clean and Build with Gradle
run: ./gradlew clean build
- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Cache Gradle packages
uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
- name: Clean and Build with Gradle
run: ./gradlew clean build

- name: Copy JAR file to EC2
uses: appleboy/scp-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
port: 22
source: build/libs/draw-my-today-0.0.1-SNAPSHOT.jar
target: /home/ubuntu/SpringServer
- name: Cache Gradle packages
uses: actions/cache@v1
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle

- name: Deploy EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
port: 22
script: |
cd SpringServer
./start.sh
- name: Copy JAR file to EC2
uses: appleboy/scp-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
port: 22
source: build/libs/draw-my-today-0.0.1-SNAPSHOT.jar
target: /home/ubuntu/SpringServer

- name: Deploy EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
port: 22
script: |
cd SpringServer
./start.sh
47 changes: 47 additions & 0 deletions src/main/java/tipitapi/drawmytoday/common/config/R2Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package tipitapi.drawmytoday.common.config;

import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;

@Configuration
public class R2Config {

@Value("${r2.credentials.access-key}")
private String accessKey;

@Value("${r2.credentials.secret-key}")
private String secretKey;

@Value("${r2.account-id}")
private String accountId;

@Bean
@Qualifier("r2Client")
public S3Client r2Client() throws URISyntaxException {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
return S3Client.builder()
.credentialsProvider(() -> credentials)
.region(Region.of("auto"))
.endpointOverride(new URI("https://" + accountId + ".r2.cloudflarestorage.com"))
.build();
}

@Bean
@Qualifier("r2Presigner")
public S3Presigner r2Presigner() throws URISyntaxException {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
return S3Presigner.builder()
.credentialsProvider(() -> credentials)
.region(Region.of("auto"))
.endpointOverride(new URI("https://" + accountId + ".r2.cloudflarestorage.com"))
.build();
}
}
13 changes: 13 additions & 0 deletions src/main/java/tipitapi/drawmytoday/common/config/S3Config.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package tipitapi.drawmytoday.common.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;

@Configuration
public class S3Config {
Expand All @@ -20,11 +22,22 @@ public class S3Config {
private String region;

@Bean
@Qualifier("awsS3Client")
public S3Client amazonS3() {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
return S3Client.builder()
.credentialsProvider(() -> credentials)
.region(Region.of(region))
.build();
}

@Bean
@Qualifier("awsS3Presigner")
public S3Presigner s3Presigner() {
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
return S3Presigner.builder()
.credentialsProvider(() -> credentials)
.region(Region.of(region))
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import java.util.Date;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tipitapi.drawmytoday.diary.domain.Diary;
import tipitapi.drawmytoday.diary.domain.Image;
import tipitapi.drawmytoday.diary.exception.ImageNotFoundException;
import tipitapi.drawmytoday.diary.repository.ImageRepository;
import tipitapi.drawmytoday.r2.service.R2Service;
import tipitapi.drawmytoday.s3.service.S3Service;

@Service
Expand All @@ -17,6 +19,10 @@ public class ImageService {

private final ImageRepository imageRepository;
private final S3Service s3Service;
private final R2Service r2Service;

@Value("${spring.profiles.active:Unknown}")
private String profile;

public Image getImage(Diary diary) {
return imageRepository.findByIsSelectedTrueAndDiary(diary)
Expand All @@ -28,9 +34,10 @@ public Image createImage(Diary diary, String imagePath, boolean isSelected) {
}

public Image uploadAndCreateImage(Diary diary, byte[] dallEImage, boolean isSelected) {
String imagePath = String.format("post/%d/%s_%d.png", diary.getDiaryId(),
String imagePath = String.format(profile + "/post/%d/%s_%d.png", diary.getDiaryId(),
new Date().getTime(), 1);
s3Service.uploadImage(dallEImage, imagePath);
r2Service.uploadImage(dallEImage, imagePath);
return createImage(diary, imagePath, isSelected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tipitapi.drawmytoday.r2.service;

import static java.time.Duration.ofMinutes;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.S3Exception;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import tipitapi.drawmytoday.s3.exception.S3FailedException;

@Service
public class R2PreSignedService {

private final S3Presigner s3Presigner;
private final String bucketName;

public R2PreSignedService(@Qualifier("r2Presigner") S3Presigner s3Presigner,
@Value("${r2.bucket}") String bucketName) {
this.s3Presigner = s3Presigner;
this.bucketName = bucketName;
}

/*
* S3 이미지 조회용 pre-signed URL 발급 메서드
*/
public String getPreSignedUrlForShare(String objectKey, long expirationMin) {
try {
GetObjectRequest getObjectRequest = GetObjectRequest.builder()
.bucket(bucketName)
.key(objectKey)
.build();

GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
.signatureDuration(ofMinutes(expirationMin))
.getObjectRequest(getObjectRequest).build();

return s3Presigner.presignGetObject(getObjectPresignRequest).url().toString();
} catch (SdkClientException | S3Exception e) {
throw e;
} catch (Exception e) {
throw new S3FailedException(e);
}
}
}
Loading

0 comments on commit 53e4289

Please sign in to comment.