Skip to content

Commit

Permalink
Merge branch 'develop' into feat/friends_fundingProgress
Browse files Browse the repository at this point in the history
  • Loading branch information
YeaChan05 authored Jun 6, 2024
2 parents 0c4f3dd + 131e7ee commit baad1fa
Show file tree
Hide file tree
Showing 33 changed files with 708 additions and 464 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ dependencies {

implementation 'p6spy:p6spy:3.9.1'
implementation 'com.github.gavlyukovskiy:datasource-decorator-spring-boot-autoconfigure:1.9.0'

implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'io.micrometer:micrometer-registry-prometheus'
}

tasks.named('test') {
Expand Down
30 changes: 30 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,33 @@ services:
restart: always
ports:
- "6379:6379"
prometheus:
image: prom/prometheus
container_name: prometheus
restart: always
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"

grafana:
image: grafana/grafana
container_name: grafana
restart: always
ports:
- "3009:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
volumes:
- grafana-storage:/var/lib/grafana

mysqld_exporter:
image: prom/mysqld_exporter
restart: always
environment:
- DATA_SOURCE_NAME=${MYSQL_USERNAME}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST})/
ports:
- "9104:9104"

volumes:
grafana-storage:
24 changes: 24 additions & 0 deletions nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,30 @@ http {
ssl_dhparam /etc/ssl/certs/ssl-dhparams.pem;
}

server {
listen 9090;

location / {
proxy_pass http://prometheus:9090;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

server {
listen 3009;

location / {
proxy_pass http://grafana:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

server {
if ($host = www.fundina.shop) {
return 301 https://$host$request_uri;
Expand Down
15 changes: 15 additions & 0 deletions prometheus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
global:
scrape_interval: 15s

scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

- job_name: 'spring-boot-apps'
static_configs:
- targets: ['app1:8080', 'app2:8080', 'app3:8080']

- job_name: 'mysql'
static_configs:
- targets: ['mysqld_exporter:9104']
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,13 @@
public class SecurityConfig {
private static final List<String> ORIGIN_PATTERN = List.of("https://www.kakaofunding.kro.kr/");
private static final String CORS_CONFIGURATION_PATTERN = "/**";
private static final String API_V_1 = "/api/v1/";
public static final String API_V_1 = "/api/v1/";
private static final String ACTUATOR = "/actuator/**";

private static final List<String> ALLOWED_HEADERS = Arrays.asList("Origin", "Content-Type", "Accept", "Authorization", "X-Requested-With");
private static final List<String> ALLOWED_METHODS = Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS");

private static final String METRICS = "/metrics";

private final AuthenticationAccessDeniedHandler authenticationAccessDeniedHandler;
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
private final JwtAuthenticationFilter jwtAuthenticationFilter;
Expand All @@ -39,6 +42,8 @@ public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception
return http.authorizeHttpRequests(
authorizationManagerRequestMatcherRegistry -> authorizationManagerRequestMatcherRegistry
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.requestMatchers(ACTUATOR).permitAll()
.requestMatchers(METRICS).permitAll()
.requestMatchers(API_V_1 + "oauth/login").permitAll()
.requestMatchers(API_V_1 + "oauth/logout").authenticated()
.requestMatchers(API_V_1 + "oauth/reissue").permitAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@Getter
public enum KakaoApiErrorCode implements ErrorCode {
INVALID_ACCESS_TOKEN(-401, CODE_PREFIX + "007", HttpStatus.BAD_REQUEST, "유효하지 않은 소셜 엑세스 토큰입니다.");
INVALID_ACCESS_TOKEN(-401, CODE_PREFIX + "008", HttpStatus.BAD_REQUEST, "유효하지 않은 소셜 엑세스 토큰입니다.");

private final int serverErrorCode;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

@Getter
public enum KakaoAuthErrorCode implements ErrorCode {
NOT_FOUND_REFRESH_TOKEN("KOE319", CODE_PREFIX + "008", HttpStatus.NOT_FOUND, "소셜 리프레시 토큰을 찾을 수 없습니다."),
INVALID_REFRESH_TOKEN("KOE322", CODE_PREFIX + "009", HttpStatus.NOT_FOUND, "이미 만료되었거나 유효하지 않은 소셜 리프레시 토큰입니다.");
NOT_FOUND_REFRESH_TOKEN("KOE319", CODE_PREFIX + "009", HttpStatus.NOT_FOUND, "소셜 리프레시 토큰을 찾을 수 없습니다."),
INVALID_REFRESH_TOKEN("KOE322", CODE_PREFIX + "010", HttpStatus.NOT_FOUND, "이미 만료되었거나 유효하지 않은 소셜 리프레시 토큰입니다.");

private final String serverErrorCode;
private final String code;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

@Getter
public enum RefreshTokenErrorCode implements ErrorCode {
NOT_FOUND(CODE_PREFIX + "004", HttpStatus.NOT_FOUND, "리프레시 토큰을 찾을 수 없습니다."),
INVALID(CODE_PREFIX + "005", HttpStatus.NOT_FOUND, "유효하지 않은 리프레시 토큰입니다."),
EXPIRED(CODE_PREFIX + "006", HttpStatus.NOT_FOUND, "만료된 리프레시 토큰입니다.");
NOT_FOUND(CODE_PREFIX + "005", HttpStatus.NOT_FOUND, "리프레시 토큰을 찾을 수 없습니다."),
INVALID(CODE_PREFIX + "006", HttpStatus.BAD_REQUEST, "유효하지 않은 리프레시 토큰입니다."),
EXPIRED(CODE_PREFIX + "007", HttpStatus.BAD_REQUEST, "만료된 리프레시 토큰입니다.");

private final String code;
private final HttpStatus httpStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,52 @@
package org.kakaoshare.backend.domain.order.repository.query;


import static org.kakaoshare.backend.common.util.RepositoryUtils.priceExpression;
import static org.kakaoshare.backend.domain.member.entity.QMember.member;
import static org.kakaoshare.backend.domain.order.entity.QOrder.order;
import static org.kakaoshare.backend.domain.product.entity.QProduct.product;
import static org.kakaoshare.backend.domain.receipt.entity.QReceipt.receipt;
import static org.kakaoshare.backend.domain.wish.entity.QWish.wish;

import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Projections;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.JPAExpressions;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;

import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.kakaoshare.backend.common.util.RepositoryUtils;
import org.kakaoshare.backend.common.vo.PriceRange;
import org.kakaoshare.backend.domain.member.entity.Gender;
import org.kakaoshare.backend.domain.rank.dto.RankPriceRange;

import lombok.RequiredArgsConstructor;
import org.kakaoshare.backend.common.util.RepositoryUtils;
import org.kakaoshare.backend.domain.member.entity.QMember;
import org.kakaoshare.backend.domain.option.dto.QOptionSummaryResponse;
import org.kakaoshare.backend.domain.order.dto.inquiry.OrderHistoryDetailDto;
import org.kakaoshare.backend.domain.order.dto.inquiry.OrderProductDto;
import org.kakaoshare.backend.domain.order.dto.inquiry.QOrderProductDto;
import org.kakaoshare.backend.domain.order.vo.OrderHistoryDate;
import org.kakaoshare.backend.domain.product.dto.QProductDto;
import org.kakaoshare.backend.domain.rank.dto.RankPriceRange;
import org.kakaoshare.backend.domain.rank.dto.RankResponse;
import org.kakaoshare.backend.domain.rank.util.TargetType;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static org.kakaoshare.backend.common.util.RepositoryUtils.*;
import static org.kakaoshare.backend.common.util.RepositoryUtils.createOrderSpecifiers;
import static org.kakaoshare.backend.common.util.RepositoryUtils.eqExpression;
import static org.kakaoshare.backend.common.util.RepositoryUtils.periodExpression;
import static org.kakaoshare.backend.common.util.RepositoryUtils.priceExpression;
import static org.kakaoshare.backend.common.util.RepositoryUtils.toPage;
import static org.kakaoshare.backend.domain.member.entity.QMember.member;
import static org.kakaoshare.backend.domain.order.entity.QOrder.order;
import static org.kakaoshare.backend.domain.product.entity.QProduct.product;
import static org.kakaoshare.backend.domain.receipt.entity.QReceipt.receipt;
import static org.kakaoshare.backend.domain.receipt.entity.QReceiptOption.receiptOption;
import static org.kakaoshare.backend.domain.wish.entity.QWish.wish;

@Component
@RequiredArgsConstructor
public class OrderRepositoryCustomImpl implements OrderRepositoryCustom {
private static final QMember receiver = new QMember("receiver");
private static final QMember recipient = new QMember("recipient");

private final JPAQueryFactory queryFactory;

public Page<RankResponse> findTopRankedProductsByOrders(LocalDateTime term, Pageable pageable) {
Expand Down Expand Up @@ -162,10 +159,11 @@ private JPAQuery<?> createOrderProductDtoBaseQuery(final String providerId, fina
return queryFactory.from(order)
.innerJoin(order.receipt, receipt)
.innerJoin(receipt.product, product)
.innerJoin(receipt.receiver, member)
.innerJoin(receipt.recipient, recipient)
.innerJoin(receipt.receiver, receiver)
.where(
periodExpression(receipt.createdAt, date),
eqExpression(member.providerId, providerId)
eqExpression(recipient.providerId, providerId)
)
.offset(pageable.getOffset())
.limit(pageable.getPageSize());
Expand All @@ -186,7 +184,7 @@ private QOrderProductDto getOrderProductDto() {
return new QOrderProductDto(
order.ordersId,
receipt.orderNumber,
member.name,
receiver.name,
getProductDto(),
receipt.quantity,
order.createdAt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,22 @@
public class ProductController {
public static final int PAGE_DEFAULT_SIZE = 20;
private final ProductService productService;

@GetMapping("/{productId}")
public ResponseEntity<?> getProductDetail(@PathVariable Long productId,
@Nullable @LoggedInMember String providerId,
@RequestParam(name = "tab", required = false, defaultValue = "description") String tab) {
if ("description".equals(tab)) {
DescriptionResponse response = productService.getProductDescription(productId);
DescriptionResponse response = productService.getProductDescription(productId, providerId);
return ResponseEntity.ok(response);
}
if ("detail".equals(tab)) {
DetailResponse response = productService.getProductDetail(productId);
DetailResponse response = productService.getProductDetail(productId, providerId);
return ResponseEntity.ok(response);
}
return ResponseEntity.badRequest().body("Invalid tab value");
}

@GetMapping
public ResponseEntity<?> getSimpleProductsInPage(
@Nullable @LoggedInMember String providerId,
Expand All @@ -52,24 +53,24 @@ public ResponseEntity<?> getSimpleProductsInPage(
PageResponse<?> simpleProductsPage = productService.getSimpleProductsPage(categoryId, pageable, providerId);
return ResponseEntity.ok(simpleProductsPage);
}

@GetMapping("/brands/{brandId}")
public ResponseEntity<?> getBrandsProducts(@PathVariable("brandId") Long brandId,
@PageableDefault(size = PAGE_DEFAULT_SIZE) Pageable pageable) {
PageResponse<?> simpleProductPage = productService.getSimpleProductsByBrandId(brandId, pageable);
return ResponseEntity.ok(simpleProductPage);
}


@PostMapping("/{productId}/wishes")
public ResponseEntity<?> resistWishingProduct(@LoggedInMember String providerId,
@PathVariable("productId") Long productId,
@RequestParam(name = "type") WishType type) {
WishResponse response = productService.resisterProductInWishList(providerId, productId, type);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}


@DeleteMapping("/{productId}/wishes")
public ResponseEntity<?> cancelWisingProduct(@LoggedInMember String providerId,
@PathVariable("productId") Long productId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.kakaoshare.backend.domain.product.entity.ProductThumbnail;

import java.util.List;
import org.kakaoshare.backend.domain.wish.entity.Wish;

@Getter
@Builder
Expand All @@ -25,9 +26,11 @@ public class DescriptionResponse {
private final String brandName;
private final Long brandId;
private final String brandThumbnail;
private final int wishCount;
private final boolean isWish;

public static DescriptionResponse of(final Product product, List<String> descriptionPhotosUrls,
List<OptionResponse> optionsResponses, List<String> productThumbnailsUrls) {
List<OptionResponse> optionsResponses, List<String> productThumbnailsUrls, Boolean isWished) {

List<String> thumbnails;
if (product.getProductThumbnails().isEmpty() && product.getPhoto() != null) {
Expand All @@ -51,6 +54,8 @@ public static DescriptionResponse of(final Product product, List<String> descrip
.brandName(product.getBrand().getName())
.brandId(product.getBrand().getBrandId())
.brandThumbnail(product.getBrand().getIconPhoto())
.wishCount(product.getWishCount())
.isWish(isWished)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.kakaoshare.backend.domain.product.dto;

import java.util.Optional;
import lombok.Builder;
import lombok.Getter;
import org.kakaoshare.backend.domain.option.dto.OptionResponse;
import org.kakaoshare.backend.domain.product.entity.Product;
import org.kakaoshare.backend.domain.product.entity.ProductDetail;
import org.kakaoshare.backend.domain.product.entity.ProductThumbnail;
import java.util.List;

Expand All @@ -26,13 +28,18 @@ public class DetailResponse {
private final String billingNotice;
private final String caution;
private final List<String> productThumbnails;
public static DetailResponse of(final Product product,List<OptionResponse> optionsResponses) {
String origin = product.getProductDetail() != null ? product.getProductDetail().getOrigin() : "정보 없음";
String manufacturer = product.getProductDetail() != null ? product.getProductDetail().getManufacturer() : "정보 없음";
String tel = product.getProductDetail() != null ? product.getProductDetail().getTel() : "정보 없음";
String deliverDescription = product.getProductDetail() != null ? product.getProductDetail().getDeliverDescription() : "정보 없음";
String billingNotice = product.getProductDetail() != null ? product.getProductDetail().getBillingNotice() : "정보 없음";
String caution = product.getProductDetail() != null ? product.getProductDetail().getCaution() : "정보 없음";
private final int wishCount;
private final boolean isWish;

public static DetailResponse of(final Product product, List<OptionResponse> optionsResponses, Boolean isWished) {
ProductDetail detail = product.getProductDetail();

String origin = Optional.ofNullable(detail).map(ProductDetail::getOrigin).orElse(null);
String manufacturer = Optional.ofNullable(detail).map(ProductDetail::getManufacturer).orElse(null);
String tel = Optional.ofNullable(detail).map(ProductDetail::getTel).orElse(null);
String deliverDescription = Optional.ofNullable(detail).map(ProductDetail::getDeliverDescription).orElse(null);
String billingNotice = Optional.ofNullable(detail).map(ProductDetail::getBillingNotice).orElse(null);
String caution = Optional.ofNullable(detail).map(ProductDetail::getCaution).orElse(null);

return DetailResponse.builder()
.productId(product.getProductId())
Expand All @@ -51,6 +58,8 @@ public static DetailResponse of(final Product product,List<OptionResponse> optio
.brandName(product.getBrandName())
.brandId(product.getBrand().getBrandId())
.brandThumbnail(product.getBrand().getIconPhoto())
.wishCount(product.getWishCount())
.isWish(isWished)
.build();
}
}
Loading

0 comments on commit baad1fa

Please sign in to comment.