Skip to content

Commit

Permalink
feat: v2.1.0 영수증 첨부 기능 추가 (#728)
Browse files Browse the repository at this point in the history
* fix: CI/CD 스크립트 정상화 (#706)

* feat: workflow 복구

* test: dev 워크플로우 테스트

* test: 잘못된 yaml 형식 수정

* test: 설정 서브모듈 추가

* fix: eof 추가

* feat: 이미지 업로드 경로 업데이트

* feat: 은행 이름 수정 (#712)

* feat: BaseEntity 적용 (#700)

* feat: 영수증 이미지 업로드 기능 추가 (#714)

* feat: gitignore 추가

* feat: 이미지 업로드/다운로드 기능 추가

* feat: 이미지 업로드/다운로드 기능 추가

* feat: 운영, 개발 image 설정 분리

* feat: 서브모듈 삭제

* test: imageUploadService 추가

* test: 행사 이미지 저장 및 조회 기능 테스트

* feat: 이미지 삭제 기능 구현

* test: 이미지 삭제 테스트 추가

---------

Co-authored-by: juha <[email protected]>

* docs: adoc 수정 (#722)

* chore: 테스트용 트리거 브랜치 삭제 (#726)

---------

Co-authored-by: juha <[email protected]>
Co-authored-by: Arachne <[email protected]>
Co-authored-by: juha <[email protected]>
  • Loading branch information
4 people authored Oct 10, 2024
1 parent 410c306 commit 4e3763f
Show file tree
Hide file tree
Showing 53 changed files with 788 additions and 56 deletions.
72 changes: 72 additions & 0 deletions .github/workflows/backend-dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: backend-push

on:
push:
branches: [ "be-dev" ]

jobs:
build:
runs-on: ubuntu-latest

defaults:
run:
shell: bash
working-directory: ./server

permissions:
contents: read

steps:
- name: CheckOut
uses: actions/checkout@v4
with:
token: ${{secrets.CONFIG_SUBMODULE_TOKEN}}
submodules: true

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

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

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

- name: Test with Gradle Wrapper
run: ./gradlew clean build

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v3

- name: Build and push
run: |
docker buildx build --platform linux/arm64 -t \
${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }} --push .
deploy:
needs: build
runs-on: [ self-hosted, backend-dev ]
steps:
- name: Docker remove
run: |
CONTAINER_IDS=$(sudo docker ps -qa)
if [ -n "$CONTAINER_IDS" ]; then
sudo docker rm -f $CONTAINER_IDS
else
echo "No running containers found."
fi
- name: Docker Image pull
run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}

- name: Docker run
run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=dev -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}
77 changes: 77 additions & 0 deletions .github/workflows/backend-prod.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: backend-push

on:
push:
branches: [ "main" ]
paths:
- 'server/**'

jobs:
build:
runs-on: ubuntu-latest

defaults:
run:
shell: bash
working-directory: ./server

permissions:
contents: read

steps:
- name: CheckOut
uses: actions/checkout@v4
with:
token: ${{secrets.CONFIG_SUBMODULE_TOKEN}}
submodules: true

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

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

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

- name: Test with Gradle Wrapper
run: ./gradlew clean build

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Set up Docker BuildX
uses: docker/setup-buildx-action@v3

- name: Build and push
run: |
docker buildx build --platform linux/arm64 -t \
${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push .
deploy:
needs: build
strategy:
matrix:
runner: [ prod-1, prod-2 ]
runs-on: [ self-hosted, '${{ matrix.runner }}' ]
steps:
- name: Docker remove
run: |
CONTAINER_IDS=$(sudo docker ps -qa)
if [ -n "$CONTAINER_IDS" ]; then
sudo docker rm -f $CONTAINER_IDS
else
echo "No running containers found."
fi
- name: Docker Image pull
run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }}

- name: Docker run
run: sudo docker run -d -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }}
44 changes: 44 additions & 0 deletions .github/workflows/backend-pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: backend-pull-request

on:
pull_request:
branches: [ "main", "be-dev" ]

jobs:
build:
runs-on: [ ubuntu-latest ]

defaults:
run:
working-directory: ./server

steps:
- name: CheckOut
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

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

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

- name: Test with Gradle Wrapper
run: ./gradlew clean build

- name: publish unit test results
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
files: server/build/test-results/test/TEST-*.xml

- name: add comments to a pull request
uses: mikepenz/action-junit-report@v3
if: always()
with:
report_paths: server/build/test-results/test/TEST-*.xml
2 changes: 1 addition & 1 deletion server/.gitignore → .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ $RECYCLE.BIN/
*.lnk

### Gradle ###
.gradle
server/.gradle
**/build/
!src/**/build/

Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "server/src/main/resources/config"]
path = server/src/main/resources/config
url = https://github.com/woowacourse-teams/2024-haeng-dong-config
2 changes: 2 additions & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ dependencies {
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'

implementation 'software.amazon.awssdk:s3:2.25.27'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

Expand Down
63 changes: 63 additions & 0 deletions server/src/docs/asciidoc/event.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,66 @@ operation::authenticateEvent[snippets="http-request,http-response,request-cookie
}
]
----

=== 행사 이미지 업로드
operation::uploadImages[snippets="http-request,http-response"]

==== [.red]#Exceptions#

[source,json,options="nowrap"]
----
[
{
"code": "EVENT_NOT_FOUND",
"message": "존재하지 않는 행사입니다."
},
{
"code": "IMAGE_UPLOAD_FAIL",
"message": "이미지 업로드에 실패했습니다."
},
{
"code":"TOKEN_NOT_FOUND",
"message":"토큰이 존재하지 않습니다."
},
{
"code":"TOKEN_EXPIRED",
"message":"만료된 토큰입니다."
},
{
"code":"TOKEN_INVALID",
"message":"유효하지 않은 토큰입니다."
}
]
----

=== 행사 이미지 목록 조회

operation::findImages[snippets="http-request,response-body,response-fields,http-response"]

==== [.red]#Exceptions#

[source,json,options="nowrap"]
----
[
{
"code": "EVENT_NOT_FOUND",
"message": "존재하지 않는 행사입니다."
}
]
----

=== 행사 이미지 삭제

operation::deleteImage[snippets="http-request,http-response"]

==== [.red]#Exceptions#

[source,json,options="nowrap"]
----
[
{
"code": "EVENT_NOT_FOUND",
"message": "존재하지 않는 행사입니다."
}
]
----
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Slf4j
@SpringBootApplication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@
import java.util.List;
import java.util.Map.Entry;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import server.haengdong.application.request.EventAppRequest;
import server.haengdong.application.request.EventLoginAppRequest;
import server.haengdong.application.request.EventUpdateAppRequest;
import server.haengdong.application.response.EventAppResponse;
import server.haengdong.application.response.EventDetailAppResponse;
import server.haengdong.application.response.EventImageAppResponse;
import server.haengdong.application.response.MemberBillReportAppResponse;
import server.haengdong.domain.bill.Bill;
import server.haengdong.domain.bill.BillRepository;
import server.haengdong.domain.member.Member;
import server.haengdong.domain.bill.MemberBillReport;
import server.haengdong.domain.event.Event;
import server.haengdong.domain.event.EventImage;
import server.haengdong.domain.event.EventImageRepository;
import server.haengdong.domain.event.EventRepository;
import server.haengdong.domain.event.EventTokenProvider;
import server.haengdong.domain.member.Member;
import server.haengdong.exception.AuthenticationException;
import server.haengdong.exception.HaengdongErrorCode;
import server.haengdong.exception.HaengdongException;
Expand All @@ -30,6 +34,10 @@ public class EventService {
private final EventRepository eventRepository;
private final EventTokenProvider eventTokenProvider;
private final BillRepository billRepository;
private final EventImageRepository eventImageRepository;

@Value("${image.base-url}")
private String baseUrl;

@Transactional
public EventAppResponse saveEvent(EventAppRequest request) {
Expand Down Expand Up @@ -92,4 +100,41 @@ public void updateEvent(String token, EventUpdateAppRequest request) {
event.changeAccount(request.bankName(), request.accountNumber());
}
}

@Transactional
public void saveImages(String token, List<String> imageNames) {
Event event = getEvent(token);

List<EventImage> images = imageNames.stream()
.map(imageName -> new EventImage(event, imageName))
.toList();

eventImageRepository.saveAll(images);
}

public List<EventImageAppResponse> findImages(String token) {
Event event = getEvent(token);

return eventImageRepository.findAllByEvent(event)
.stream()
.map(image -> new EventImageAppResponse(image.getId(), createUrl(image)))
.toList();
}

private String createUrl(EventImage image) {
return baseUrl + image.getName();
}

@Transactional
public String deleteImage(String token, Long imageId) {
EventImage eventImage = eventImageRepository.findById(imageId)
.orElseThrow(() -> new HaengdongException(HaengdongErrorCode.IMAGE_NOT_FOUND));

Event event = eventImage.getEvent();
if (event.isTokenMismatch(token)) {
throw new AuthenticationException(HaengdongErrorCode.PASSWORD_INVALID);
}
eventImageRepository.delete(eventImage);
return eventImage.getName();
}
}
Loading

0 comments on commit 4e3763f

Please sign in to comment.