From 7564cb1aa589c12e62b7e4972eb0536ff22d9182 Mon Sep 17 00:00:00 2001 From: junwon <67488973+wjdwnsdnjs13@users.noreply.github.com> Date: Sat, 3 Aug 2024 18:52:15 +0900 Subject: [PATCH] =?UTF-8?q?[BSVR-180]=20=EB=A0=88=EB=B2=A8=EC=97=85=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=A1=B0=ED=9A=8C=20API=20(#101)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat : level 테이블 내의 모든 정보를 가져오는 기능 추가 * feat : 레벨업 테이블 API 구현 * feat : 레벨업 테이블 API JWT 필터 예외 추가 * refactor : 해당 레벨의 minimum Review는 not null임을 명시하도록 원시타입으로 변경 * refactor : 상수 레벨 테이블을 사용해서 레벨 계산하도록 변경 * refactor : 상수 레벨 테이블을 사용해서 레벨업에 필요한 리뷰 수 계산하도록 변경 * fix : 레벨 계산 오류 수정 * build : ImmutableMap 사용을 위한 의존성 추가 * refactor : ImmutableMap을 사용해 레벨 최소/최대 조건 구현 * refactor : rest api 명명 규칙에 맞도록 복수형으로 변경 * refactor : ResponseStatus, summary 추가 * refactor : 레벨업 조건 테이블 조회 api 변경으로 인한 필터 조건 변경 --- .../common/jwt/JwtAuthenticationFilter.java | 3 +- .../controller/LevelUpTableController.java | 31 +++++++ .../dto/response/LevelUpTableResponse.java | 20 +++++ domain/build.gradle.kts | 3 + .../depromeet/spot/domain/member/Level.java | 81 +++++++++++-------- .../repository/LevelRepositoryImpl.java | 8 ++ .../usecase/port/in/member/LevelUsecase.java | 9 +++ .../port/out/member/LevelRepository.java | 4 + .../usecase/service/level/LevelService.java | 24 ++++++ 9 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 application/src/main/java/org/depromeet/spot/application/member/controller/LevelUpTableController.java create mode 100644 application/src/main/java/org/depromeet/spot/application/member/dto/response/LevelUpTableResponse.java create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/LevelUsecase.java create mode 100644 usecase/src/main/java/org/depromeet/spot/usecase/service/level/LevelService.java diff --git a/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java b/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java index 54f74c5f..247d48ab 100644 --- a/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java +++ b/application/src/main/java/org/depromeet/spot/application/common/jwt/JwtAuthenticationFilter.java @@ -34,7 +34,8 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { "/api-docs", "/swagger-ui.html", "/favicon.ico", - "/api/v1/members" + "/api/v1/members", + "/api/v1/levelUpConditions", }; @Override diff --git a/application/src/main/java/org/depromeet/spot/application/member/controller/LevelUpTableController.java b/application/src/main/java/org/depromeet/spot/application/member/controller/LevelUpTableController.java new file mode 100644 index 00000000..05796f16 --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/member/controller/LevelUpTableController.java @@ -0,0 +1,31 @@ +package org.depromeet.spot.application.member.controller; + +import java.util.List; + +import org.depromeet.spot.application.member.dto.response.LevelUpTableResponse; +import org.depromeet.spot.usecase.port.in.member.LevelUsecase; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@Tag(name = "레벨") +@RequestMapping("/api/v1/levelUpConditions") +public class LevelUpTableController { + + private final LevelUsecase levelUsecase; + + @GetMapping + @ResponseStatus(HttpStatus.OK) + @Operation(summary = "레벨업 조건 테이블 조회 API") + public List getLevelUpTable() { + return levelUsecase.findAllLevels().stream().map(LevelUpTableResponse::from).toList(); + } +} diff --git a/application/src/main/java/org/depromeet/spot/application/member/dto/response/LevelUpTableResponse.java b/application/src/main/java/org/depromeet/spot/application/member/dto/response/LevelUpTableResponse.java new file mode 100644 index 00000000..4914ee57 --- /dev/null +++ b/application/src/main/java/org/depromeet/spot/application/member/dto/response/LevelUpTableResponse.java @@ -0,0 +1,20 @@ +package org.depromeet.spot.application.member.dto.response; + +import org.depromeet.spot.domain.member.Level; + +import lombok.Builder; + +@Builder +public record LevelUpTableResponse(Integer level, String title, int minimum, Integer maximum) { + public static LevelUpTableResponse from(Level level) { + LevelUpTableResponse levelUpTableResponse = + LevelUpTableResponse.builder() + .level(level.getValue()) + .title(level.getTitle()) + .minimum(level.getMinimum()) + .maximum(level.getMaximum()) + .build(); + + return levelUpTableResponse; + } +} diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts index a4997d22..a1f81ae0 100644 --- a/domain/build.gradle.kts +++ b/domain/build.gradle.kts @@ -1,5 +1,8 @@ dependencies { implementation(project(":common")) + + // ImmutableMap을 위한 구아바 사용 + implementation("com.google.guava:guava:31.0.1-jre") } tasks.jar { enabled = true } diff --git a/domain/src/main/java/org/depromeet/spot/domain/member/Level.java b/domain/src/main/java/org/depromeet/spot/domain/member/Level.java index 77f87467..8a8620f8 100644 --- a/domain/src/main/java/org/depromeet/spot/domain/member/Level.java +++ b/domain/src/main/java/org/depromeet/spot/domain/member/Level.java @@ -2,6 +2,8 @@ import java.time.LocalDateTime; +import com.google.common.collect.ImmutableMap; + import lombok.AllArgsConstructor; import lombok.Getter; @@ -9,6 +11,26 @@ @AllArgsConstructor public class Level { + private static final ImmutableMap LEVEL_MINIMUM_CONDITIONS = + ImmutableMap.builder() + .put(0, 0) + .put(1, 1) + .put(2, 3) + .put(3, 5) + .put(4, 8) + .put(5, 14) + .put(6, 21) + .build(); + + private static final ImmutableMap LEVEL_MAXIMUM_CONDITIONS = + ImmutableMap.builder() + .put(0, 0) + .put(1, 2) + .put(2, 4) + .put(3, 7) + .put(4, 13) + .put(5, 20) + .build(); private final Long id; private final int value; private final String title; @@ -18,42 +40,37 @@ public class Level { private final LocalDateTime deletedAt; public static int calculateLevel(final long reviewCnt) { - if (reviewCnt == 0) { - return 0; - } - if (reviewCnt <= 2) { - return 1; - } - if (2 < reviewCnt && reviewCnt <= 4) { - return 2; - } - if (4 < reviewCnt && reviewCnt <= 7) { - return 3; - } - if (7 < reviewCnt && reviewCnt <= 13) { - return 4; - } - if (13 < reviewCnt && reviewCnt <= 20) { + if (reviewCnt > LEVEL_MINIMUM_CONDITIONS.get(6)) { + return 6; + } else if (reviewCnt > LEVEL_MAXIMUM_CONDITIONS.get(5)) { return 5; + } else if (reviewCnt > LEVEL_MAXIMUM_CONDITIONS.get(4)) { + return 4; + } else if (reviewCnt > LEVEL_MAXIMUM_CONDITIONS.get(3)) { + return 3; + } else if (reviewCnt > LEVEL_MAXIMUM_CONDITIONS.get(2)) { + return 2; + } else if (reviewCnt > LEVEL_MAXIMUM_CONDITIONS.get(1)) { + return 1; } - return 6; + return 0; } public static long calculateReviewCntToLevelUp(long reviewCnt) { - int nextLevelMinimumReview; - if (reviewCnt == 0) { - nextLevelMinimumReview = 1; - } else if (reviewCnt <= 2) { - nextLevelMinimumReview = 3; - } else if (2 < reviewCnt && reviewCnt <= 4) { - nextLevelMinimumReview = 5; - } else if (4 < reviewCnt && reviewCnt <= 7) { - nextLevelMinimumReview = 8; - } else if (7 < reviewCnt && reviewCnt <= 13) { - nextLevelMinimumReview = 14; - } else if (13 < reviewCnt && reviewCnt <= 20) { - nextLevelMinimumReview = 21; - } else return 0; - return nextLevelMinimumReview - reviewCnt; + int level = calculateLevel(reviewCnt); + if (level > 5) { + return 0; + } + // (다음 레벨의 최소 리뷰 조건) - (현재 작성한 리뷰 수) + return LEVEL_MINIMUM_CONDITIONS.get(level + 1) - reviewCnt; + } + + public int getMinimum() { + return LEVEL_MINIMUM_CONDITIONS.get(value); + } + + public Integer getMaximum() { + if (value > 5) return null; + return LEVEL_MAXIMUM_CONDITIONS.get(value); } } diff --git a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/LevelRepositoryImpl.java b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/LevelRepositoryImpl.java index 8be4d2c8..3066cfbc 100644 --- a/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/LevelRepositoryImpl.java +++ b/infrastructure/jpa/src/main/java/org/depromeet/spot/jpa/member/repository/LevelRepositoryImpl.java @@ -1,6 +1,9 @@ package org.depromeet.spot.jpa.member.repository; +import java.util.List; + import org.depromeet.spot.domain.member.Level; +import org.depromeet.spot.jpa.member.entity.LevelEntity; import org.depromeet.spot.usecase.port.out.member.LevelRepository; import org.springframework.stereotype.Repository; @@ -16,4 +19,9 @@ public class LevelRepositoryImpl implements LevelRepository { public Level findByValue(final int value) { return levelJpaRepository.findByValue(value).toDomain(); } + + @Override + public List findAll() { + return levelJpaRepository.findAll().stream().map(LevelEntity::toDomain).toList(); + } } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/LevelUsecase.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/LevelUsecase.java new file mode 100644 index 00000000..2a38fb64 --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/in/member/LevelUsecase.java @@ -0,0 +1,9 @@ +package org.depromeet.spot.usecase.port.in.member; + +import java.util.List; + +import org.depromeet.spot.domain.member.Level; + +public interface LevelUsecase { + List findAllLevels(); +} diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/LevelRepository.java b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/LevelRepository.java index ed6a991e..62e9bece 100644 --- a/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/LevelRepository.java +++ b/usecase/src/main/java/org/depromeet/spot/usecase/port/out/member/LevelRepository.java @@ -1,8 +1,12 @@ package org.depromeet.spot.usecase.port.out.member; +import java.util.List; + import org.depromeet.spot.domain.member.Level; public interface LevelRepository { Level findByValue(int value); + + List findAll(); } diff --git a/usecase/src/main/java/org/depromeet/spot/usecase/service/level/LevelService.java b/usecase/src/main/java/org/depromeet/spot/usecase/service/level/LevelService.java new file mode 100644 index 00000000..9f615fba --- /dev/null +++ b/usecase/src/main/java/org/depromeet/spot/usecase/service/level/LevelService.java @@ -0,0 +1,24 @@ +package org.depromeet.spot.usecase.service.level; + +import java.util.List; + +import org.depromeet.spot.domain.member.Level; +import org.depromeet.spot.usecase.port.in.member.LevelUsecase; +import org.depromeet.spot.usecase.port.out.member.LevelRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class LevelService implements LevelUsecase { + + private final LevelRepository levelRepository; + + @Override + public List findAllLevels() { + return levelRepository.findAll(); + } +}