Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
songyi00 committed Mar 1, 2024
2 parents ec79365 + 74b9122 commit e0d5f05
Show file tree
Hide file tree
Showing 132 changed files with 5,188 additions and 282 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ jobs:
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build
run: ./gradlew build
env:
FMP_API_KEY: ${{ secrets.FMP_API_KEY }}
NINJAS_API_KEY: ${{ secrets.NINJAS_API_KEY }}
80 changes: 80 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: Backend CD

on:
push:
branches:
- main
- develop
- fix/#77

jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3

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

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

- name: Execute Gradle build
run: ./gradlew clean build

- name: Set up Docker Build
uses: docker/setup-buildx-action@v2

- name: Docker build and push to NCP container registry and copy docker-compose.yml to server
run: |
cd ./api-server
sudo docker build --build-arg DEPENDENCY=build/dependency -t ${{ secrets.NCP_CONTAINER_REGISTRY_API }}/payout-api --platform linux/amd64 .
sudo docker login ${{ secrets.NCP_CONTAINER_REGISTRY_API }} -u ${{ secrets.NCP_ACCESS_KEY }} -p ${{ secrets.NCP_SECRET_KEY }}
sudo docker push ${{ secrets.NCP_CONTAINER_REGISTRY_API }}/payout-api
cd ../batch
sudo docker build --build-arg DEPENDENCY=build/dependency -t ${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }}/payout-batch --platform linux/amd64 .
sudo docker login ${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }} -u ${{ secrets.NCP_ACCESS_KEY }} -p ${{ secrets.NCP_SECRET_KEY }}
sudo docker push ${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }}/payout-batch
cd ..
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} scp -o StrictHostKeyChecking=no ./docker-compose.yml ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }}:${{ secrets.DOCKER_COMPOSE_PATH }}
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} scp -o StrictHostKeyChecking=no ./nginx/nginx.conf ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }}:${{ secrets.DOCKER_COMPOSE_PATH }}
sshpass -p ${{ secrets.API_SERVER_PASSWORD }} scp -o StrictHostKeyChecking=no ./deploy.sh ${{ secrets.API_SERVER_USERNAME }}@${{ secrets.API_SERVER_HOST }}:${{ secrets.DOCKER_COMPOSE_PATH }}
shell: bash

deploy-to-server:
name: Connect api server ssh and pull from container registry
needs: build-and-push
runs-on: ubuntu-latest
steps:
## docker compose up
- name: Deploy to api server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.API_SERVER_HOST }}
username: ${{ secrets.API_SERVER_USERNAME }}
password: ${{ secrets.API_SERVER_PASSWORD }}
script: |
export DB_HOSTNAME=${{ secrets.DB_HOSTNAME }}
export DB_PORT=${{ secrets.DB_PORT }}
export DB_DATABASE=${{ secrets.DB_DATABASE }}
export DB_USERNAME=${{ secrets.DB_USERNAME }}
export DB_PASSWORD=${{ secrets.DB_PASSWORD }}
export FMP_API_KEY=${{ secrets.FMP_API_KEY }}
export NINJAS_API_KEY=${{ secrets.NINJAS_API_KEY }}
export NCP_CONTAINER_REGISTRY_API=${{ secrets.NCP_CONTAINER_REGISTRY_API }}
export NCP_CONTAINER_REGISTRY_BATCH=${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }}
sudo docker login ${{ secrets.NCP_CONTAINER_REGISTRY_API }} -u ${{ secrets.NCP_ACCESS_KEY }} -p ${{ secrets.NCP_SECRET_KEY }}
sudo docker pull ${{ secrets.NCP_CONTAINER_REGISTRY_API }}/payout-api
sudo docker login ${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }} -u ${{ secrets.NCP_ACCESS_KEY }} -p ${{ secrets.NCP_SECRET_KEY }}
sudo docker pull ${{ secrets.NCP_CONTAINER_REGISTRY_BATCH }}/payout-batch
bash ${{ secrets.DOCKER_COMPOSE_PATH }}/deploy.sh
docker image prune -f
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ out/
.vscode/
.DS_Store

**/logs
**/logs
**/db/data
domain/src/main/generated/nexters/payout/domain/stock/domain/QStock.java
5 changes: 5 additions & 0 deletions api-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM eclipse-temurin:17

ARG JAR_FILE=build/libs/api-server.jar
COPY ${JAR_FILE} api-server.jar
ENTRYPOINT ["java","-jar","-Dspring.profiles.active=prod,file-logging","-Duser.timezone=UTC","/api-server.jar"]
11 changes: 11 additions & 0 deletions api-server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ plugins {

dependencies {
implementation(project(":core"))
implementation(project(":domain"))

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.0'

implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0'

testImplementation(testFixtures(project(":domain")))
}

tasks.named('test') {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nexters.payout.apiserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;

@ConfigurationPropertiesScan
@SpringBootApplication(scanBasePackages = {
"nexters.payout.core",
"nexters.payout.domain",
"nexters.payout.apiserver"
})
public class PayoutApiServerApplication {

public static void main(String[] args) {
SpringApplication.run(PayoutApiServerApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package nexters.payout.apiserver.config;

import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.servers.Server;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {

@Bean
public OpenAPI openAPI() {
return new OpenAPI()
.components(new Components())
.addServersItem(new Server().url("/"))
.info(getPayoutServerInfo());
}

private Info getPayoutServerInfo() {
return new Info().title("Payout Server API")
.description("Payout Server API 명세서입니다.")
.version("1.0.0");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nexters.payout.apiserver.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000", "http://localhost:8080")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package nexters.payout.apiserver.dividend.application;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import nexters.payout.apiserver.dividend.application.dto.request.DividendRequest;
import nexters.payout.apiserver.dividend.application.dto.request.TickerShare;
import nexters.payout.apiserver.dividend.application.dto.response.SingleMonthlyDividendResponse;
import nexters.payout.apiserver.dividend.application.dto.response.MonthlyDividendResponse;
import nexters.payout.apiserver.dividend.application.dto.response.SingleYearlyDividendResponse;
import nexters.payout.apiserver.dividend.application.dto.response.YearlyDividendResponse;
import nexters.payout.core.exception.error.NotFoundException;
import nexters.payout.core.time.InstantProvider;
import nexters.payout.domain.dividend.domain.Dividend;
import nexters.payout.domain.dividend.domain.repository.DividendRepository;
import nexters.payout.domain.stock.domain.Stock;
import nexters.payout.domain.stock.domain.repository.StockRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class DividendQueryService {

private final DividendRepository dividendRepository;
private final StockRepository stockRepository;

public List<MonthlyDividendResponse> getMonthlyDividends(final DividendRequest request) {
return InstantProvider.generateNext12Months()
.stream()
.map(yearMonth -> MonthlyDividendResponse.of(
yearMonth.getYear(),
yearMonth.getMonthValue(),
getDividendsOfLastYearAndMonth(request.tickerShares(), yearMonth.getMonthValue())
)
)
.collect(Collectors.toList());
}

public YearlyDividendResponse getYearlyDividends(final DividendRequest request) {
List<SingleYearlyDividendResponse> dividends = request.tickerShares()
.stream()
.map(tickerShare -> {
String ticker = tickerShare.ticker();
return SingleYearlyDividendResponse.of(
getStock(ticker), tickerShare.share(), getYearlyDividend(ticker)
);
})
.filter(response -> response.totalDividend() != 0)
.collect(Collectors.toList());

return YearlyDividendResponse.of(dividends);
}

private double getYearlyDividend(final String ticker) {
return getLastYearDividendsByTicker(ticker)
.stream()
.mapToDouble(Dividend::getDividend)
.sum();
}

private List<Dividend> getLastYearDividendsByTicker(final String ticker) {
return dividendRepository.findAllByTickerAndYear(ticker, InstantProvider.getLastYear());
}

private Stock getStock(final String ticker) {
return stockRepository.findByTicker(ticker)
.orElseThrow(() -> new NotFoundException(String.format("not found ticker [%s]", ticker)));
}

private List<SingleMonthlyDividendResponse> getDividendsOfLastYearAndMonth(
final List<TickerShare> tickerShares, final int month
) {
return tickerShares
.stream()
.flatMap(tickerShare -> stockRepository.findByTicker(tickerShare.ticker())
.map(stock -> getMonthlyDividendResponse(month, tickerShare, stock))
.orElseThrow(() -> new NotFoundException(String.format("not found ticker [%s]", tickerShare.ticker()))))
.toList();
}

private Stream<SingleMonthlyDividendResponse> getMonthlyDividendResponse(
final int month, final TickerShare tickerShare, final Stock stock
) {
return getLastYearDividendsByTickerAndMonth(tickerShare.ticker(), month)
.stream()
.map(dividend -> SingleMonthlyDividendResponse.of(stock, tickerShare.share(), dividend));
}

private List<Dividend> getLastYearDividendsByTickerAndMonth(final String ticker, final int month) {
return dividendRepository.findAllByTickerAndYearAndMonth(ticker, InstantProvider.getLastYear(), month);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package nexters.payout.apiserver.dividend.application.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;

import java.util.List;

public record DividendRequest(
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
@Valid
@Size(min = 1)
List<TickerShare> tickerShares
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package nexters.payout.apiserver.dividend.application.dto.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotEmpty;

public record TickerShare(
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, example = "ticker name")
@NotEmpty
String ticker,
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, example = "share")
@Min(value = 1)
Integer share
) { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package nexters.payout.apiserver.dividend.application.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;

import java.util.Comparator;
import java.util.List;

public record MonthlyDividendResponse(
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
Integer year,
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
Integer month,
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
List<SingleMonthlyDividendResponse> dividends,
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
Double totalDividend
) {
public static MonthlyDividendResponse of(
final int year, final int month, final List<SingleMonthlyDividendResponse> dividends
) {
return new MonthlyDividendResponse(
year,
month,
dividends.stream()
.sorted(Comparator.comparingDouble(SingleMonthlyDividendResponse::totalDividend).reversed())
.toList(),
dividends.stream()
.mapToDouble(SingleMonthlyDividendResponse::totalDividend)
.sum()
);
}
}
Loading

0 comments on commit e0d5f05

Please sign in to comment.