Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
environment: dev
permissions:
contents: read
services:
Expand All @@ -22,29 +23,32 @@ jobs:
--health-interval 10s
--health-timeout 5s
--health-retries 5

redis:
image: redis:6
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'

- name: Run Redis
uses: supercharge/redis-github-action@1.1.0
with:
redis-version: 6

- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
uses: gradle/actions/setup-gradle@v5

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Test with Gradle Wrapper
run: ./gradlew clean spotlessCheck test
- name: Build with Gradle
run: ./gradlew clean build
env:
NEO4J_URI: bolt://localhost:7687
NEO4J_USER: neo4j
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.sillim.recordit.feed.repository;

import com.sillim.recordit.feed.domain.FeedImage;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FeedImageRepository extends JpaRepository<FeedImage, Long> {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
import com.sillim.recordit.global.exception.ErrorCode;
import com.sillim.recordit.global.exception.common.RecordNotFoundException;
import com.sillim.recordit.global.util.FileUtils;
import com.sillim.recordit.rabbitmq.dto.Message;
import com.sillim.recordit.rabbitmq.dto.MessageType;
import com.sillim.recordit.rabbitmq.service.MessagePublisher;
import jakarta.transaction.Transactional;
import java.io.IOException;
import java.util.List;
Expand All @@ -27,31 +24,30 @@ public class FeedCommandService {

private final FeedRepository feedRepository;
private final ImageUploadService imageUploadService;
private final MessagePublisher messagePublisher;
private final FeedImageUploader feedImageUploader;

public Long addFeed(FeedAddRequest request, List<MultipartFile> images, Long memberId) {
Long feedId = feedRepository.save(request.toFeed(memberId)).getId();

if (images == null || images.isEmpty()) {
return feedId;
}
messagePublisher.send(
new Message<>(
MessageType.IMAGES.name(),
images.stream()
.map(
image -> {
try {
return new FeedImageMessage(
feedId,
generateImageName(image),
image.getContentType(),
image.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
}),
MessageType.IMAGES));

feedImageUploader.uploadImages(
images.stream()
.map(
image -> {
try {
return new FeedImageMessage(
feedId,
generateImageName(image),
image.getContentType(),
image.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.toList());
return feedId;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.sillim.recordit.feed.service;

import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.sillim.recordit.feed.domain.Feed;
import com.sillim.recordit.feed.domain.FeedImage;
import com.sillim.recordit.feed.dto.FeedImageMessage;
import com.sillim.recordit.feed.repository.FeedImageRepository;
import com.sillim.recordit.feed.repository.FeedRepository;
import com.sillim.recordit.global.exception.ErrorCode;
import com.sillim.recordit.global.exception.common.ApplicationException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class FeedImageUploader {
private static final String GCS_HOST = "https://storage.googleapis.com/";

@Value("${spring.cloud.gcp.storage.bucket}")
private String bucketName;

private final Storage storage;
private final FeedRepository feedRepository;
private final FeedImageRepository feedImageRepository;

@Async
@Retryable(
retryFor = {ApplicationException.class},
backoff = @Backoff(delay = 2000))
public void uploadImages(List<FeedImageMessage> images) {
for (FeedImageMessage image : images) {
uploadImage(image);
}
}

public void uploadImage(FeedImageMessage image) {
try {
storage.createFrom(
BlobInfo.newBuilder(bucketName, image.fileName())
.setContentType(image.contentType())
.build(),
new ByteArrayInputStream(image.fileBytes()));
} catch (IOException e) {
throw new ApplicationException(ErrorCode.IMAGE_UPLOAD_FAILED);
}

String imageUrl = GCS_HOST + bucketName + "/" + image.fileName();
Feed feed =
feedRepository
.findById(image.feedId())
.orElseThrow(() -> new ApplicationException(ErrorCode.FEED_NOT_FOUND));
feedImageRepository.save(new FeedImage(imageUrl, feed));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public enum ErrorCode {
TOO_MANY_REQUEST("ERR_GLOBAL_004", "너무 많은 요청을 보냈습니다."),
UNHANDLED_EXCEPTION("ERR_GLOBAL_999", "예상치 못한 오류가 발생했습니다."),

IMAGE_UPLOAD_FAILED("ERR_IMAGE_001", "이미지 업로드에 실패했습니다."),

ID_TOKEN_UNSUPPORTED("ERR_OIDC_001", "지원되지 않는 ID Token 입니다."),
ID_TOKEN_EXPIRED("ERR_OIDC_002", "ID Token이 만료되었습니다."),
ID_TOKEN_INVALID_KEY("ERR_OIDC_003", "App Key가 유효하지 않습니다."),
Expand Down
19 changes: 0 additions & 19 deletions src/main/java/com/sillim/recordit/rabbitmq/dto/Message.java

This file was deleted.

This file was deleted.

This file was deleted.

8 changes: 3 additions & 5 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ spring:
cloud:
gcp:
storage:
credentials:
location: ${GCP_KEY_LOCATION}
bucket: ${GCP_BUCKET_NAME}
project-id: ${GCP_PROJECT_ID}

security:
oauth2:
Expand Down Expand Up @@ -77,11 +80,6 @@ spring:
username: ${NEO4J_USERNAME}
password: ${NEO4J_PASSWORD}

rabbitmq:
queue.name: feedimage.queue
exchange.name: direct.exchange
routing.key: feedimage.key

firebase:
credentials:
location: ${FIREBASE_KEY_LOCATION}
Expand Down
9 changes: 3 additions & 6 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ spring:
cloud:
gcp:
storage:
credentials:
location: ${GCP_KEY_LOCATION}
bucket: ${GCP_BUCKET_NAME}
project-id: ${GCP_PROJECT_ID}

security:
oauth2:
Expand Down Expand Up @@ -82,12 +85,6 @@ spring:
username: neo4j
password: verysecret

rabbitmq:
queue.name: sample.queue
exchange.name: sample.exchange
routing.key: sample.key


firebase:
credentials:
location: ${FIREBASE_KEY_LOCATION}
Expand Down
9 changes: 4 additions & 5 deletions src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ spring:
dialect: org.hibernate.dialect.MySQLDialect
hbm2ddl:
auto: validate

cloud:
gcp:
storage:
credentials:
location: ${GCP_KEY_LOCATION}
bucket: ${GCP_BUCKET_NAME}
project-id: ${GCP_PROJECT_ID}

security:
oauth2:
Expand Down Expand Up @@ -76,11 +80,6 @@ spring:
username: ${NEO4J_USERNAME}
password: ${NEO4J_PASSWORD}

rabbitmq:
queue.name: feedimage.queue
exchange.name: direct.exchange
routing.key: feedimage.key

firebase:
credentials:
location: ${FIREBASE_KEY_LOCATION}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.sillim.recordit.feed.fixture.FeedFixture;
import com.sillim.recordit.feed.repository.FeedRepository;
import com.sillim.recordit.member.service.MemberQueryService;
import com.sillim.recordit.rabbitmq.service.MessagePublisher;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
Expand All @@ -30,7 +29,7 @@ class FeedCommandServiceTest {

@Mock FeedRepository feedRepository;
@Mock MemberQueryService memberQueryService;
@Mock MessagePublisher messagePublisher;
@Mock FeedImageUploader feedImageUploader;
@InjectMocks FeedCommandService feedCommandService;

@Test
Expand Down
Loading
Loading