From 338608c8035ce9a2ec6c8c2d8d9380b8b1d9e0e1 Mon Sep 17 00:00:00 2001 From: MJJ Date: Thu, 10 Oct 2024 13:54:58 +0900 Subject: [PATCH 01/58] =?UTF-8?q?[test]=20=EB=98=90=EB=9E=98=EB=B3=84=20?= =?UTF-8?q?=EA=B0=80=EC=9E=A5=20=EB=86=92=EC=9D=80=20=EC=86=8C=EB=B9=84=20?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EB=B0=8F=20=EA=B0=80=EC=9E=A5=20=EB=86=92?= =?UTF-8?q?=EC=9D=80=20=EB=AA=A9=ED=91=9C=20=EA=B8=88=EC=95=A1=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20repository=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ConsumptionGoalRepositoryTest.java | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java index 25b355f9..49634967 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepositoryTest.java @@ -6,6 +6,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -61,6 +62,7 @@ void setUp() { .name("Peer User 1") .gender(Gender.MALE) .phoneNumber("010-1111-1111") + .mobileCarrier("SK Telecom") .build()); peerUser2 = userRepository.save( @@ -70,6 +72,7 @@ void setUp() { .name("Peer User 2") .gender(Gender.MALE) .phoneNumber("010-2222-2222") + .mobileCarrier("KT") .build()); currentMonth = LocalDate.now(); @@ -345,7 +348,8 @@ void findLatelyGoal_Success() { LocalDate searchDate = LocalDate.of(2024, 9, 1); // when - ConsumptionGoal result = consumptionGoalRepository.findLatelyGoal(user.getId(), category.getId(), searchDate).get(); + ConsumptionGoal result = consumptionGoalRepository.findLatelyGoal(user.getId(), category.getId(), searchDate) + .get(); // then assertEquals(result.getGoalMonth(), targetMonth); @@ -379,9 +383,44 @@ void findLatelyGoal_Success2() { .build()); // when - ConsumptionGoal result = consumptionGoalRepository.findLatelyGoal(user.getId(), category.getId(), targetMonth).get(); + ConsumptionGoal result = consumptionGoalRepository.findLatelyGoal(user.getId(), category.getId(), targetMonth) + .get(); // then assertEquals(result.getGoalMonth(), targetMonth); } + + @Test + @DisplayName("또래 나이, 성별, 카테고리로 최대 소비 금액 조회 성공") + void findMaxConsumeAmountByCategory_Success() { + // when + int peerAgeStart = 23; + int peerAgeEnd = 25; + Gender peerGender = Gender.MALE; + + Optional result = consumptionGoalRepository.findMaxConsumeAmountByCategory( + peerAgeStart, peerAgeEnd, peerGender, currentMonth); + + // then + assertThat(result).isPresent(); + assertThat(result.get().getConsumeAmount()).isEqualTo(150L); + assertThat(result.get().getCategory().getId()).isEqualTo(defaultCategory2.getId()); + } + + @Test + @DisplayName("또래 나이, 성별, 카테고리로 최대 목표 금액 조회 성공") + void findMaxGoalAmountByCategory_Success() { + // when + int peerAgeStart = 23; + int peerAgeEnd = 25; + Gender peerGender = Gender.MALE; + + Optional result = consumptionGoalRepository.findMaxGoalAmountByCategory( + peerAgeStart, peerAgeEnd, peerGender, currentMonth); + + // then + assertThat(result).isPresent(); + assertThat(result.get().getGoalAmount()).isEqualTo(200L); + assertThat(result.get().getCategory().getId()).isEqualTo(defaultCategory2.getId()); + } } \ No newline at end of file From df9fdee97cb4461ea42fb2325e1f5d01962eeb5e Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Fri, 11 Oct 2024 15:56:38 +0900 Subject: [PATCH 02/58] =?UTF-8?q?[feat]=20Querydsl=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 5ae542b7..9a9f417e 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,12 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly('io.jsonwebtoken:jjwt-jackson:0.11.5') // jackson으로 jwt 파싱 + + // querydsl 관련 + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" } tasks.named('test') { From fe81866f30f275f58e7f8c5b1673239ebdf17eba Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Fri, 11 Oct 2024 15:57:12 +0900 Subject: [PATCH 03/58] =?UTF-8?q?[feat]=20=EB=8F=99=EC=A0=81=20=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=EB=A5=BC=20=EB=8B=B4=EB=8B=B9=ED=95=98=EB=8A=94=20Faq?= =?UTF-8?q?SearchRepository=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/faq/repository/FaqRepository.java | 2 +- .../faq/repository/FaqSearchRepository.java | 10 ++++ .../repository/FaqSearchRepositoryImpl.java | 59 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepository.java create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepository.java index 4ab1c63e..d9c6cf4f 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepository.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepository.java @@ -3,7 +3,7 @@ import com.bbteam.budgetbuddies.domain.faq.entity.Faq; import org.springframework.data.jpa.repository.JpaRepository; -public interface FaqRepository extends JpaRepository { +public interface FaqRepository extends JpaRepository, FaqSearchRepository { } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepository.java new file mode 100644 index 00000000..b54ab5be --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepository.java @@ -0,0 +1,10 @@ +package com.bbteam.budgetbuddies.domain.faq.repository; + +import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface FaqSearchRepository { + + Page searchFaq(Pageable pageable, String searchCondition); +} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java new file mode 100644 index 00000000..81205dbf --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java @@ -0,0 +1,59 @@ +package com.bbteam.budgetbuddies.domain.faq.repository; + +import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.JPAExpressions; +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.util.List; + +import static com.bbteam.budgetbuddies.domain.faq.entity.QFaq.*; +import static com.bbteam.budgetbuddies.domain.faqkeyword.domain.QFaqKeyword.*; + +public class FaqSearchRepositoryImpl implements FaqSearchRepository{ + + private final JPAQueryFactory queryFactory; + + public FaqSearchRepositoryImpl(EntityManager em) { + this.queryFactory = new JPAQueryFactory(em); + } + + @Override + public Page searchFaq(Pageable pageable, String searchCondition) { + List result = queryFactory.select(faq) + .from(faq) + .where(faq.in( + JPAExpressions + .select(faqKeyword.faq) + .from(faqKeyword) + .where(keywordMatch(searchCondition)) + )) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + Long total = queryFactory.select(faq.count()) + .from(faq) + .where(faq.in( + JPAExpressions + .select(faqKeyword.faq) + .from(faqKeyword) + .where(keywordMatch(searchCondition)) + )) + .fetchOne(); + + return new PageImpl<>(result, pageable, total); + + } + + private BooleanExpression keywordMatch(String searchCondition) { + return searchCondition != null ? faqKeyword.searchKeyword.keyword.eq(searchCondition) : null; + } + +} + From fccb9ffb407b63114abc767461805cb935dc1110 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Fri, 11 Oct 2024 16:01:09 +0900 Subject: [PATCH 04/58] =?UTF-8?q?[feat]=20FaqService=20searchFaq=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bbteam/budgetbuddies/domain/faq/service/FaqService.java | 2 ++ .../budgetbuddies/domain/faq/service/FaqServiceImpl.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java index eb6a3718..2f276470 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java @@ -11,6 +11,8 @@ public interface FaqService { Page findAllWithPaging(Pageable pageable); + Page searchFaq(Pageable pageable, String searchCondition); + FaqResponseDto.FaqPostResponse postFaq(FaqRequestDto.FaqPostRequest dto, Long userId); FaqResponseDto.FaqModifyResponse modifyFaq(FaqRequestDto.FaqModifyRequest dto, Long faqId); diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java index a28ccba8..70c11286 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java @@ -62,4 +62,9 @@ public String deleteFaq(Long faqId) { private Faq findFaq(Long faqId) { return faqRepository.findById(faqId).orElseThrow(() -> new GeneralException(ErrorStatus._FAQ_NOT_FOUND)); } + + @Override + public Page searchFaq(Pageable pageable, String searchCondition) { + return faqRepository.searchFaq(pageable, searchCondition).map(FaqConverter::entityToFind); + } } From f24d9635ba108b4ee0b10a627e46dce3be8467c8 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Fri, 11 Oct 2024 16:01:59 +0900 Subject: [PATCH 05/58] =?UTF-8?q?[feat]=20FaqApi=20findByPaging=20?= =?UTF-8?q?=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EB=B0=8F=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bbteam/budgetbuddies/domain/faq/controller/FaqApi.java | 3 ++- .../budgetbuddies/domain/faq/controller/FaqController.java | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java index f3e0b134..06bc6e16 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java @@ -17,6 +17,7 @@ import jakarta.validation.Valid; import org.springframework.data.domain.Pageable; import org.springframework.http.MediaType; +import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; @@ -70,7 +71,7 @@ ApiResponse postFaq(@ExistUser @RequestParam Long userId, } ) - ApiResponse findByPaging(Pageable pageable); + ApiResponse findByPaging(Pageable pageable, String SearchCondition); @Operation(summary = "[User] FAQ 수정 API", description = "FAQ를 수정하는 API입니다.", requestBody = @RequestBody( diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java index c8da6681..74a6e41f 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java @@ -7,10 +7,12 @@ import com.bbteam.budgetbuddies.domain.faq.validation.ExistFaq; import com.bbteam.budgetbuddies.domain.user.validation.ExistUser; import jakarta.validation.Valid; +import jakarta.validation.constraints.Null; import lombok.RequiredArgsConstructor; import org.springdoc.core.annotations.ParameterObject; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -37,8 +39,9 @@ public ApiResponse findFaq(@PathVariable @ExistF @Override @GetMapping("/all") - public ApiResponse> findByPaging(@ParameterObject Pageable pageable) { - return ApiResponse.onSuccess(faqService.findAllWithPaging(pageable)); + public ApiResponse> findByPaging(@ParameterObject Pageable pageable, + @RequestParam @Nullable String searchCondition) { + return ApiResponse.onSuccess(faqService.searchFaq(pageable, searchCondition)); } @Override From c48c90718682c9fcf904ede8c6145a3319e2330c Mon Sep 17 00:00:00 2001 From: MJJ Date: Sat, 12 Oct 2024 02:59:41 +0900 Subject: [PATCH 06/58] =?UTF-8?q?[refactor]=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/controller/ConsumptionGoalController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 4a75809d..18508185 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -120,7 +120,7 @@ public ApiResponse getMonthReport(@RequestParam(name = " return ApiResponse.onSuccess(response); } - @GetMapping("/cosnumption-ment") + @GetMapping("/consumption-ment") public ApiResponse getConsumptionMention(@RequestParam(name = "userId") Long userId) { String response = consumptionGoalService.getConsumptionMention(userId); return ApiResponse.onSuccess(response); From 90088a70e80f5ab2109575dd4d20f6dd3ee98411 Mon Sep 17 00:00:00 2001 From: MJJ Date: Sat, 12 Oct 2024 03:59:17 +0900 Subject: [PATCH 07/58] =?UTF-8?q?[refactor]=20AI=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EA=B2=BD=EC=9A=B0=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EB=A9=98=ED=8A=B8=20=EC=9D=91=EB=8B=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalServiceImpl.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 73e1ba13..2eeb306e 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -785,7 +785,7 @@ private String getMainComment(List list) { } } Optional minCategory = categoryRepository.findById(minCategoryId); - + if (minCategory.isEmpty()) { throw new IllegalArgumentException("해당 카테고리를 찾을 수 없습니다."); } @@ -795,8 +795,6 @@ private String getMainComment(List list) { long todayAvailableConsumptionAmount = minDifference / remainDays; long weekAvailableConsumptionAmount = todayAvailableConsumptionAmount * 7; - log.info(String.valueOf(weekAvailableConsumptionAmount)); - NumberFormat nf = NumberFormat.getInstance(Locale.KOREA); // 한국 단위로 locale if (weekAvailableConsumptionAmount < 0) { @@ -817,7 +815,7 @@ public String getConsumptionMention(Long userId) { /** * 가장 큰 소비를 한 카테고리의 소비 목표 데이터 정보와 가장 큰 목표로 세운 카테고리의 소비 목표 데이터를 각각 가져온다. * 위 데이터들을 가지고 프롬프트 진행 - * Gemini AI, Chat GPT + * Chat GPT */ // 유저 아이디로 또래 정보 확인 @@ -835,26 +833,26 @@ public String getConsumptionMention(Long userId) { peerAgeEnd, peerGender, currentMonth); - if (!maxConsumeAmount.isPresent()) { + if (maxConsumeAmount.isEmpty()) { throw new IllegalArgumentException("해당 소비목표 데이터를 찾을 수 없습니다."); } // 유저 이름과 소비 목표 데이터로 카테고리 이름, 소비 금액을 가져 온다. String username = findUserById(userId).getName(); String categoryName = maxConsumeAmount.get().getCategory().getName(); - String consumeAmount = String.valueOf(maxConsumeAmount.get().getConsumeAmount()); + long consumeAmount = maxConsumeAmount.get().getConsumeAmount(); // 또래의 상위 소비 금액에 대한 정보로 프롬프트 작성 String firstPrompt = "00은 " + username + ", 가장 큰 소비 카테고리 이름은 " + categoryName + "," + "해당 카테고리 소비금액은" + consumeAmount + "이야"; - if (!maxGoalAmount.isPresent()) { + if (maxGoalAmount.isEmpty()) { throw new IllegalArgumentException("해당 소비목표 데이터를 찾을 수 없습니다."); } // 가장 큰 목표 소비 금액에 대한 정보로 프롬프트 작성 categoryName = maxGoalAmount.get().getCategory().getName(); - String goalAmount = String.valueOf(maxGoalAmount.get().getGoalAmount()); + long goalAmount = maxGoalAmount.get().getGoalAmount(); // 또래의 상위 목표 소비 금액에 대한 정보로 프롬프트 작성 String secondPrompt = "가장 큰 목표 소비 카테고리 이름은 " + categoryName @@ -868,8 +866,15 @@ public String getConsumptionMention(Long userId) { + "카테고리 목표 금액(ex. 패션에 N만원 소비를 계획해요)같은 트렌드 한 멘트, 인터넷상 바이럴 문구" + "참고하여 만들어줘"; - return openAiService.chat(basePrompt); - // return geminiService.getContents(basePrompt); + String response = openAiService.chat(basePrompt); + + if (response == null) { + NumberFormat nf = NumberFormat.getInstance(Locale.KOREA); + response = "총 " + nf.format(goalAmount - consumeAmount) + "원 더 쓸 수 있어요."; + return response; + } + + return response; } } \ No newline at end of file From 0af3f0c86b3c0d356a7b7b8251d7d7525fd4ca66 Mon Sep 17 00:00:00 2001 From: MJJ Date: Sat, 12 Oct 2024 04:03:56 +0900 Subject: [PATCH 08/58] =?UTF-8?q?[chore]=20gemini=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gemini/controller/GeminiController.java | 29 --------- .../domain/gemini/dto/ChatRequest.java | 57 ----------------- .../domain/gemini/dto/ChatResponse.java | 62 ------------------- .../domain/gemini/service/GeminiService.java | 7 --- .../gemini/service/GeminiServiceImpl.java | 40 ------------ .../config/GeminiRestTemplateConfig.java | 23 ------- 6 files changed, 218 deletions(-) delete mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/gemini/controller/GeminiController.java delete mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatRequest.java delete mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatResponse.java delete mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiService.java delete mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiServiceImpl.java delete mode 100644 src/main/java/com/bbteam/budgetbuddies/global/config/GeminiRestTemplateConfig.java diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/controller/GeminiController.java b/src/main/java/com/bbteam/budgetbuddies/domain/gemini/controller/GeminiController.java deleted file mode 100644 index 1222baa2..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/controller/GeminiController.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.bbteam.budgetbuddies.domain.gemini.controller; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.HttpClientErrorException; - -import com.bbteam.budgetbuddies.domain.gemini.service.GeminiServiceImpl; - -import lombok.RequiredArgsConstructor; - -@RestController -@RequiredArgsConstructor -@RequestMapping("/gemini") -public class GeminiController { - - private final GeminiServiceImpl geminiService; - - @GetMapping("/chat") - public ResponseEntity gemini(@RequestParam(name = "message") String message) { - try { - return ResponseEntity.ok().body(geminiService.getContents(message)); - } catch (HttpClientErrorException e) { - return ResponseEntity.badRequest().body(e.getMessage()); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatRequest.java b/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatRequest.java deleted file mode 100644 index 31dbf2c1..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatRequest.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bbteam.budgetbuddies.domain.gemini.dto; - -import java.util.ArrayList; -import java.util.List; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -public class ChatRequest { - private List contents; - private GenerationConfig generationConfig; - - @Getter - @Setter - public static class Content { - private Parts parts; - } - - @Getter - @Setter - public static class Parts { - private String text; - - } - - @Getter - @Setter - public static class GenerationConfig { - private int candidate_count; - private int max_output_tokens; - private double temperature; - - } - - public ChatRequest(String prompt) { - this.contents = new ArrayList<>(); - Content content = new Content(); - Parts parts = new Parts(); - - parts.setText(prompt); - content.setParts(parts); - - this.contents.add(content); - this.generationConfig = new GenerationConfig(); - this.generationConfig.setCandidate_count(1); - this.generationConfig.setMax_output_tokens(1000); - this.generationConfig.setTemperature(0.7); - } -} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatResponse.java b/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatResponse.java deleted file mode 100644 index 3ff240cb..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/dto/ChatResponse.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.bbteam.budgetbuddies.domain.gemini.dto; - -import java.util.List; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; - -@Data -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class ChatResponse { - - private List candidates; - private PromptFeedback promptFeedback; - - @Getter - @Setter - public static class Candidate { - private Content content; - private String finishReason; - private int index; - private List safetyRatings; - - } - - @Getter - @Setter - @ToString - public static class Content { - private List parts; - private String role; - - } - - @Getter - @Setter - @ToString - public static class Parts { - private String text; - - } - - @Getter - @Setter - public static class SafetyRating { - private String category; - private String probability; - } - - @Getter - @Setter - public static class PromptFeedback { - private List safetyRatings; - - } -} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiService.java b/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiService.java deleted file mode 100644 index eb1f80fb..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiService.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.bbteam.budgetbuddies.domain.gemini.service; - -public interface GeminiService { - - String getContents(String prompt); - -} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiServiceImpl.java deleted file mode 100644 index a1c727a5..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/domain/gemini/service/GeminiServiceImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.bbteam.budgetbuddies.domain.gemini.service; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; - -import com.bbteam.budgetbuddies.domain.gemini.dto.ChatRequest; -import com.bbteam.budgetbuddies.domain.gemini.dto.ChatResponse; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class GeminiServiceImpl implements GeminiService { - - @Qualifier("geminiRestTemplate") - @Autowired - private RestTemplate restTemplate; - - @Value("${spring.gemini.api.url}") - private String apiUrl; - - @Value("${spring.gemini.api.key}") - private String geminiApiKey; - - public String getContents(String prompt) { - - String requestUrl = apiUrl + "?key=" + geminiApiKey; - - ChatRequest request = new ChatRequest(prompt); - ChatResponse response = restTemplate.postForObject(requestUrl, request, ChatResponse.class); - - String message = response.getCandidates().get(0).getContent().getParts().get(0).getText().toString(); - - return message; - } - -} diff --git a/src/main/java/com/bbteam/budgetbuddies/global/config/GeminiRestTemplateConfig.java b/src/main/java/com/bbteam/budgetbuddies/global/config/GeminiRestTemplateConfig.java deleted file mode 100644 index 294ba799..00000000 --- a/src/main/java/com/bbteam/budgetbuddies/global/config/GeminiRestTemplateConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.bbteam.budgetbuddies.global.config; - -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.client.RestTemplate; - -import lombok.RequiredArgsConstructor; - -@Configuration -@RequiredArgsConstructor -public class GeminiRestTemplateConfig { - - @Bean - @Qualifier("geminiRestTemplate") - public RestTemplate geminiRestTemplate() { - RestTemplate restTemplate = new RestTemplate(); - restTemplate.getInterceptors().add((request, body, execution) -> execution.execute(request, body)); - - return restTemplate; - } -} - From c939da46b71e8cc728809bbaa2947e08278f24fb Mon Sep 17 00:00:00 2001 From: MJJ Date: Sat, 12 Oct 2024 04:04:12 +0900 Subject: [PATCH 09/58] =?UTF-8?q?[chore]=20gemini=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/service/ConsumptionGoalServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 2eeb306e..7af006ca 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -45,7 +45,6 @@ import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; -import com.bbteam.budgetbuddies.domain.gemini.service.GeminiService; import com.bbteam.budgetbuddies.domain.openai.service.OpenAiService; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; @@ -63,7 +62,6 @@ public class ConsumptionGoalServiceImpl implements ConsumptionGoalService { private final ExpenseRepository expenseRepository; private final CategoryRepository categoryRepository; private final UserRepository userRepository; - private final GeminiService geminiService; private final OpenAiService openAiService; private final ConsumptionGoalConverter consumptionGoalConverter; From 4167d6101159b46ce214c7911de3a3752c58ea31 Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 15 Oct 2024 14:13:54 +0900 Subject: [PATCH 10/58] =?UTF-8?q?[refactor]=20=20Async=EB=A1=9C=20?= =?UTF-8?q?=EB=B9=84=EB=8F=99=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bbteam/budgetbuddies/BudgetbuddiesApplication.java | 2 ++ .../controller/ConsumptionGoalController.java | 10 +++++++--- .../service/ConsumptionGoalService.java | 3 ++- .../service/ConsumptionGoalServiceImpl.java | 9 ++++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java b/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java index 42ea116f..9443b8db 100644 --- a/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java +++ b/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java @@ -3,9 +3,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableJpaAuditing +@EnableAsync public class BudgetbuddiesApplication { public static void main(String[] args) { diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 18508185..9a85ba0c 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -2,6 +2,8 @@ import java.time.LocalDate; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; @@ -121,8 +123,10 @@ public ApiResponse getMonthReport(@RequestParam(name = " } @GetMapping("/consumption-ment") - public ApiResponse getConsumptionMention(@RequestParam(name = "userId") Long userId) { - String response = consumptionGoalService.getConsumptionMention(userId); - return ApiResponse.onSuccess(response); + public ApiResponse getConsumptionMention(@RequestParam(name = "userId") Long userId) throws + ExecutionException, + InterruptedException { + CompletableFuture response = consumptionGoalService.getConsumptionMention(userId); + return ApiResponse.onSuccess(response.get()); } } \ No newline at end of file diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java index de727f3d..f3bd74dc 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.util.List; +import java.util.concurrent.CompletableFuture; import org.springframework.stereotype.Service; @@ -51,5 +52,5 @@ List getAllConsumptionCategories(Long userId, MonthReportResponseDto getMonthReport(Long userId); - String getConsumptionMention(Long userId); + CompletableFuture getConsumptionMention(Long userId); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 7af006ca..57239627 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -17,9 +17,11 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.stream.Collectors; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -807,8 +809,9 @@ private String getMainComment(List list) { } @Override + @Async @Transactional(readOnly = true) - public String getConsumptionMention(Long userId) { + public CompletableFuture getConsumptionMention(Long userId) { /** * 가장 큰 소비를 한 카테고리의 소비 목표 데이터 정보와 가장 큰 목표로 세운 카테고리의 소비 목표 데이터를 각각 가져온다. @@ -869,10 +872,10 @@ public String getConsumptionMention(Long userId) { if (response == null) { NumberFormat nf = NumberFormat.getInstance(Locale.KOREA); response = "총 " + nf.format(goalAmount - consumeAmount) + "원 더 쓸 수 있어요."; - return response; + return CompletableFuture.completedFuture(response); } - return response; + return CompletableFuture.completedFuture(response); } } \ No newline at end of file From 1ede00dd54c87387ae2da6695999a6120db24872 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Wed, 16 Oct 2024 21:33:09 +0900 Subject: [PATCH 11/58] =?UTF-8?q?[feat]=20=EC=9D=B8=EC=A6=9D=EB=B2=88?= =?UTF-8?q?=ED=98=B8=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bbteam/budgetbuddies/global/security/otp/OtpService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/global/security/otp/OtpService.java b/src/main/java/com/bbteam/budgetbuddies/global/security/otp/OtpService.java index ff76eb7f..40c2eac3 100644 --- a/src/main/java/com/bbteam/budgetbuddies/global/security/otp/OtpService.java +++ b/src/main/java/com/bbteam/budgetbuddies/global/security/otp/OtpService.java @@ -66,7 +66,7 @@ public OtpNumber generateOtp(String phoneNumber) { otpCache.put(phoneNumber, otp); // 실제 메시지 전송 - sendMessage(phoneNumber, otp); + sendMessage(phoneNumber, otp); return otp; } @@ -85,7 +85,7 @@ public void sendMessage(String phoneNumber, OtpNumber otp) { message.setTo(phoneNumber); // 수신 번호 설정 // 메시지 내용 설정 (한글 45자 이하일 경우 자동으로 SMS로 전송) - message.setText("[빈주머니즈]\n인증번호: " + otp.getOtp()); + message.setText("[빈주머니즈]\n인증번호: " + otp.getOtp() + "\n보안을 위해 번호를 타인과 공유하지 마세요."); // 메시지 전송 요청 및 응답 로그 출력 SingleMessageSentResponse response = this.messageService.sendOne(new SingleMessageSendingRequest(message)); From e5a7e1bfa9ea2ad836d6e3d1dbcb0c7a117d6602 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Wed, 16 Oct 2024 21:33:51 +0900 Subject: [PATCH 12/58] =?UTF-8?q?[feat]=20WebConfig=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(AuthArgumentResolver=20=EC=A3=BC=EC=9E=85)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/WebConfig.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/global/config/WebConfig.java diff --git a/src/main/java/com/bbteam/budgetbuddies/global/config/WebConfig.java b/src/main/java/com/bbteam/budgetbuddies/global/config/WebConfig.java new file mode 100644 index 00000000..712fb35a --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/global/config/WebConfig.java @@ -0,0 +1,21 @@ +package com.bbteam.budgetbuddies.global.config; + +import com.bbteam.budgetbuddies.global.security.utils.AuthArgumentResolver; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +@RequiredArgsConstructor +public class WebConfig implements WebMvcConfigurer { + + private final AuthArgumentResolver authArgumentResolver; + + @Override + public void addArgumentResolvers(List argumentResolvers) { + argumentResolvers.add(authArgumentResolver); + } +} \ No newline at end of file From f5212a37372987b55711090644da750a9c752aa0 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Wed, 16 Oct 2024 21:34:36 +0900 Subject: [PATCH 13/58] =?UTF-8?q?[feat]=20AuthUserDto=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20(=EC=9D=B8=EC=A6=9D=EC=9D=84=20=EC=9C=84=ED=95=9C=20id?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=9C=20DTO)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/bbteam/budgetbuddies/domain/user/dto/UserDto.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/user/dto/UserDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/user/dto/UserDto.java index 449178b2..55312f17 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/user/dto/UserDto.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/user/dto/UserDto.java @@ -46,4 +46,10 @@ public static class ModifyUserDto { private String email; private String name; } + + @Getter + @Builder + public static class AuthUserDto { + private Long id; + } } From f987492d894125c7631e7d5ad4a1a7b3c532b898 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Wed, 16 Oct 2024 21:35:12 +0900 Subject: [PATCH 14/58] =?UTF-8?q?[feat]=20AuthUser=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/security/utils/AuthUser.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthUser.java diff --git a/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthUser.java b/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthUser.java new file mode 100644 index 00000000..9fa4a0e1 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthUser.java @@ -0,0 +1,12 @@ +package com.bbteam.budgetbuddies.global.security.utils; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface AuthUser { +} From 8064ce0c28fe58e0932edfb4f4eb6b1c9291e0eb Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Wed, 16 Oct 2024 21:35:45 +0900 Subject: [PATCH 15/58] =?UTF-8?q?[feat]=20AuthArgumentResolver=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/utils/AuthArgumentResolver.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthArgumentResolver.java diff --git a/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthArgumentResolver.java b/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthArgumentResolver.java new file mode 100644 index 00000000..7560b0f2 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/global/security/utils/AuthArgumentResolver.java @@ -0,0 +1,47 @@ +package com.bbteam.budgetbuddies.global.security.utils; + +import com.bbteam.budgetbuddies.apiPayload.code.status.ErrorStatus; +import com.bbteam.budgetbuddies.apiPayload.exception.GeneralException; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.domain.user.entity.User; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.core.MethodParameter; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +@Component +@RequiredArgsConstructor +public class AuthArgumentResolver implements HandlerMethodArgumentResolver { + + // @Auth 존재 여부 확인 + @Override + public boolean supportsParameter(MethodParameter parameter) { + return parameter.hasParameterAnnotation(AuthUser.class); + } + + // @Auth 존재 시, 사용자 정보 확인하여 반환 + @Override + public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer, @NonNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null) { + throw new GeneralException(ErrorStatus._USER_NOT_FOUND); + } + + Object principal = authentication.getPrincipal(); + if (!(principal instanceof User user)) { + throw new GeneralException(ErrorStatus._USER_NOT_FOUND); + } + + UserDto.AuthUserDto authUserDto = UserDto.AuthUserDto.builder() + .id(user.getId()) + .build(); + + return authUserDto; + } +} \ No newline at end of file From a25275ebd31dd61bcdd9683c187d5c5a125d4a17 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Thu, 17 Oct 2024 22:46:49 +0900 Subject: [PATCH 16/58] =?UTF-8?q?[refactor]=20=EC=84=9C=EB=B2=84=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EB=AC=B8=EA=B5=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../budgetbuddies/apiPayload/code/status/ErrorStatus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java index 8c9515b8..fed1aaaa 100644 --- a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java @@ -11,7 +11,7 @@ public enum ErrorStatus implements BaseErrorCode { - _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON5000", "서버에러"), + _INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "COMMON5000", "서버 에러. 관리자에게 문의하세요."), _BAD_REQUEST(HttpStatus.BAD_REQUEST, "COMMON4000", "잘못된 요청"), _USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "USER4001", "사용자가 없습니다."), _COMMENT_NOT_FOUND(HttpStatus.BAD_REQUEST, "COMMENT4001", "해당 댓글이 없습니다.") , From e55dba81fdb2c815d6bf0f7fdb288e8c9ee885d7 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Thu, 17 Oct 2024 22:47:24 +0900 Subject: [PATCH 17/58] =?UTF-8?q?[refactor]=20=ED=95=A0=EC=9D=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=8A=A4?= =?UTF-8?q?=EC=9B=A8=EA=B1=B0=20=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DiscountInfoApi.java | 96 ++++++++++++------- 1 file changed, 60 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoApi.java index a3c880a2..f2e0bf76 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoApi.java @@ -1,12 +1,17 @@ package com.bbteam.budgetbuddies.domain.discountinfo.controller; import com.bbteam.budgetbuddies.apiPayload.ApiResponse; +import com.bbteam.budgetbuddies.apiPayload.code.ErrorReasonDto; import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequest; import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import com.bbteam.budgetbuddies.domain.user.validation.ExistUser; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.PathVariable; @@ -17,10 +22,14 @@ public interface DiscountInfoApi { @Operation(summary = "[User] 특정 년월 할인정보 리스트 가져오기 API", description = "특정 년도와 월에 해당하는 할인정보 목록을 조회하는 API이며, 페이징을 포함합니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "year", description = "데이터를 가져올 연도입니다."), @@ -37,11 +46,13 @@ ApiResponse> getDiscountsByYearAndMonth( @Operation(summary = "[ADMIN] 할인정보 등록하기 API", description = "할인정보를 등록하는 API이며, 추후에는 관리자만 접근 가능하도록 할 예정입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) - }) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ // @Parameter(name = "discountRequestDto", description = "등록할 할인 정보의 전체 내용입니다."), }) @@ -51,27 +62,31 @@ ApiResponse registerDiscountInfo( @Operation(summary = "[User] 특정 할인정보에 좋아요 클릭 API", description = "특정 할인정보에 좋아요 버튼을 클릭하는 API이며, 일단은 사용자 ID를 입력하여 사용합니다. (추후 토큰으로 검증)") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) - }) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ - @Parameter(name = "userId", description = "좋아요를 누른 사용자의 id입니다."), @Parameter(name = "discountInfoId", description = "좋아요를 누를 할인정보의 id입니다."), }) ApiResponse likeDiscountInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @PathVariable Long discountInfoId ); @Operation(summary = "[ADMIN] 특정 할인정보 수정하기 API", description = "특정 할인정보를 수정하는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) - }) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ }) ApiResponse updateDiscountInfo( @@ -80,10 +95,13 @@ ApiResponse updateDiscountInfo( @Operation(summary = "[ADMIN] 특정 할인정보 삭제하기 API", description = "ID를 통해 특정 할인정보를 삭제하는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "discountInfoId", description = "삭제할 할인 정보의 id입니다."), @@ -94,11 +112,14 @@ ApiResponse deleteDiscountInfo( @Operation(summary = "[ADMIN] 특정 할인정보 가져오기 API", description = "ID를 통해 특정 할인정보를 가져오는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) - }) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "discountInfoId", description = "조회할 할인 정보의 id입니다."), }) @@ -108,18 +129,21 @@ ApiResponse getDiscountInfo( @Operation(summary = "[ADMIN] 특정 사용자가 좋아요를 누른 할인정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 할인정보들을 가져오는 API입니다. 페이징을 포함합니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) - }) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "userId", description = "특정 사용자의 id입니다."), @Parameter(name = "page", description = "페이지 번호, 0번이 1 페이지 입니다. (기본값은 0입니다.)"), @Parameter(name = "size", description = "한 페이지에 불러올 데이터 개수입니다. (기본값은 10개입니다.)") }) ApiResponse> getLikedDiscountInfo( - @PathVariable @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer size ); From e697d7c13383463d94fc6f8b2d84cd1a1ceea9ba Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Thu, 17 Oct 2024 22:47:56 +0900 Subject: [PATCH 18/58] =?UTF-8?q?[refactor]=20=ED=95=A0=EC=9D=B8=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EB=90=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DiscountInfoController.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoController.java b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoController.java index 2adb897c..9a29fe89 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/discountinfo/controller/DiscountInfoController.java @@ -4,7 +4,8 @@ import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountRequest; import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto; import com.bbteam.budgetbuddies.domain.discountinfo.service.DiscountInfoService; -import com.bbteam.budgetbuddies.domain.user.validation.ExistUser; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.*; @@ -42,10 +43,10 @@ public ApiResponse registerDiscountInfo( @Override @PostMapping("/likes/{discountInfoId}") public ApiResponse likeDiscountInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @PathVariable Long discountInfoId ) { - DiscountResponseDto discountResponseDto = discountInfoService.toggleLike(userId, discountInfoId); + DiscountResponseDto discountResponseDto = discountInfoService.toggleLike(user.getId(), discountInfoId); return ApiResponse.onSuccess(discountResponseDto); } @@ -84,11 +85,11 @@ public ApiResponse getDiscountInfo( @Override @GetMapping("/liked-all") public ApiResponse> getLikedDiscountInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer size ) { - Page likedDiscountInfoPage = discountInfoService.getLikedDiscountInfo(userId, page, size); + Page likedDiscountInfoPage = discountInfoService.getLikedDiscountInfo(user.getId(), page, size); return ApiResponse.onSuccess(likedDiscountInfoPage); } From 9e991ec1753cbddf19e3afee79338034a831e415 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Thu, 17 Oct 2024 22:56:24 +0900 Subject: [PATCH 19/58] =?UTF-8?q?[refactor]=20=EC=A7=80=EC=9B=90=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=8A=A4?= =?UTF-8?q?=EC=9B=A8=EA=B1=B0=20=EC=A0=95=EB=B3=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SupportInfoApi.java | 91 +++++++++++++------ 1 file changed, 61 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoApi.java index bdbb38e1..b92e9257 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoApi.java @@ -1,13 +1,18 @@ package com.bbteam.budgetbuddies.domain.supportinfo.controller; import com.bbteam.budgetbuddies.apiPayload.ApiResponse; +import com.bbteam.budgetbuddies.apiPayload.code.ErrorReasonDto; import com.bbteam.budgetbuddies.domain.discountinfo.dto.DiscountResponseDto; import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequest; import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import com.bbteam.budgetbuddies.domain.user.validation.ExistUser; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponses; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.PathVariable; @@ -18,10 +23,15 @@ public interface SupportInfoApi { @Operation(summary = "[User] 특정 년월 지원정보 리스트 가져오기 API", description = "특정 년도와 월에 해당하는 지원정보 목록을 조회하는 API이며, 페이징을 포함합니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) + }) @Parameters({ @Parameter(name = "year", description = "데이터를 가져올 연도입니다."), @@ -38,10 +48,13 @@ ApiResponse> getSupportsByYearAndMonth( @Operation(summary = "[ADMIN] 지원정보 등록하기 API", description = "지원정보를 등록하는 API이며, 추후에는 관리자만 접근 가능하도록 할 예정입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) ApiResponse registerSupportInfo( @RequestBody SupportRequest.RegisterSupportDto requestDto @@ -49,26 +62,33 @@ ApiResponse registerSupportInfo( @Operation(summary = "[User] 특정 지원정보에 좋아요 클릭 API", description = "특정 지원정보에 좋아요 버튼을 클릭하는 API이며, 일단은 사용자 ID를 입력하여 사용합니다. (추후 토큰으로 검증)") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "userId", description = "좋아요를 누른 사용자의 id입니다."), @Parameter(name = "supportInfoId", description = "좋아요를 누를 지원정보의 id입니다."), }) ApiResponse likeSupportInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @PathVariable Long supportInfoId ); @Operation(summary = "[ADMIN] 특정 지원정보 수정하기 API", description = "ID를 통해 특정 지원정보를 수정하는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ }) @@ -78,10 +98,13 @@ ApiResponse updateSupportInfo( @Operation(summary = "[ADMIN] 특정 지원정보 삭제하기 API", description = "ID를 통해 특정 지원정보를 삭제하는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "supportInfoId", description = "삭제할 지원 정보의 id입니다."), @@ -92,10 +115,14 @@ ApiResponse deleteSupportInfo( @Operation(summary = "[ADMIN] 특정 지원정보 가져오기 API", description = "ID를 통해 특정 지원정보를 가져오는 API입니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "supportInfoId", description = "조회할 지원 정보의 id입니다."), @@ -106,10 +133,14 @@ ApiResponse getSupportInfo( @Operation(summary = "[ADMIN] 특정 사용자가 좋아요를 누른 지원정보 가져오기 API", description = "특정 사용자가 좋아요를 누른 지원정보들을 가져오는 API입니다. 페이징을 포함합니다.") @ApiResponses({ - @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공"), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), -// @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class))) + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공", content = @Content(schema = @Schema(implementation = ApiResponse.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "PAGE4001", description = "요청된 페이지가 0보다 작습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4001", description = "토큰이 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4002", description = "토큰이 존재하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4003", description = "토큰이 만료되었습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4004", description = "토큰의 페이로드 혹은 시그니처가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "TOKEN4005", description = "토큰 헤더가 유효하지 않습니다.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))), + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON5000", description = "서버 에러. 관리자에게 문의하세요.", content = @Content(schema = @Schema(implementation = ErrorReasonDto.class))) }) @Parameters({ @Parameter(name = "userId", description = "특정 사용자의 id입니다."), @@ -117,7 +148,7 @@ ApiResponse getSupportInfo( @Parameter(name = "size", description = "한 페이지에 불러올 데이터 개수입니다. (기본값은 10개입니다.)") }) ApiResponse> getLikedSupportInfo( - @PathVariable @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer size ); From d3bcf1d7ff7bb8d3468cd0c48ee8a8c0c6fe0a95 Mon Sep 17 00:00:00 2001 From: kangseungmin Date: Thu, 17 Oct 2024 22:56:37 +0900 Subject: [PATCH 20/58] =?UTF-8?q?[refactor]=20=EC=A7=80=EC=9B=90=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=EB=90=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../supportinfo/controller/SupportInfoController.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java index b40f9e81..ca04c776 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/supportinfo/controller/SupportInfoController.java @@ -5,7 +5,9 @@ import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportRequest; import com.bbteam.budgetbuddies.domain.supportinfo.dto.SupportResponseDto; import com.bbteam.budgetbuddies.domain.supportinfo.service.SupportInfoService; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import com.bbteam.budgetbuddies.domain.user.validation.ExistUser; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.web.bind.annotation.*; @@ -43,10 +45,10 @@ public ApiResponse registerSupportInfo( @Override @PostMapping("/likes/{supportInfoId}") public ApiResponse likeSupportInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @PathVariable Long supportInfoId ) { - SupportResponseDto supportResponseDto = supportInfoService.toggleLike(userId, supportInfoId); + SupportResponseDto supportResponseDto = supportInfoService.toggleLike(user.getId(), supportInfoId); return ApiResponse.onSuccess(supportResponseDto); } @@ -84,11 +86,11 @@ public ApiResponse getSupportInfo( @Override @GetMapping("/liked-all") public ApiResponse> getLikedSupportInfo( - @RequestParam @ExistUser Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer size ) { - Page likedSupportInfoPage = supportInfoService.getLikedSupportInfo(userId, page, size); + Page likedSupportInfoPage = supportInfoService.getLikedSupportInfo(user.getId(), page, size); return ApiResponse.onSuccess(likedSupportInfoPage); } From 37726fe27f4dae2a2fa4cd39cd1ef8096005fd52 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 24 Oct 2024 22:13:53 +0900 Subject: [PATCH 21/58] =?UTF-8?q?[refactor]=20ExpenseController=20@AuthUse?= =?UTF-8?q?r=EB=A5=BC=20=ED=86=B5=ED=95=B4=20userId=20=EC=A3=BC=EC=9E=85?= =?UTF-8?q?=EB=B0=9B=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/controller/ExpenseApi.java | 5 +++-- .../domain/expense/controller/ExpenseController.java | 9 +++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java index 50a8cc9a..475ec7f5 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java @@ -16,6 +16,7 @@ import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -43,8 +44,8 @@ ResponseEntity createExpense( @ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))}) ResponseEntity findExpensesForMonth( - @PathVariable @Param("userId") Long userId, - @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date); + UserDto.AuthUserDto user, + LocalDate date); @Operation(summary = "[User] 단일 소비 조회하기", description = "queryParameter를 통해 소비 Id를 전달 받아서 응답값을 조회") @ApiResponses({ diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java index c6499330..979306d2 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java @@ -19,6 +19,8 @@ import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.service.ExpenseService; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import io.swagger.v3.oas.annotations.Parameter; import lombok.RequiredArgsConstructor; @@ -39,12 +41,11 @@ public ResponseEntity createExpense( } @Override - @GetMapping("/{userId}") - public ResponseEntity findExpensesForMonth( - @PathVariable @Param("userId") Long userId, + @GetMapping() + public ResponseEntity findExpensesForMonth(@AuthUser UserDto.AuthUserDto user, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) { - return ResponseEntity.ok(expenseService.getMonthlyExpense(userId, date)); + return ResponseEntity.ok(expenseService.getMonthlyExpense(user.getId(), date)); } @Override From 0cb9cff5e51ee1d7423a593b2c2cb431cb5b7945 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 24 Oct 2024 22:15:24 +0900 Subject: [PATCH 22/58] =?UTF-8?q?[refactor]=20ExpenseServiceImpl=20?= =?UTF-8?q?=EC=9B=94=EB=B3=84=EC=86=8C=EB=B9=84=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=9B=94=EB=A7=90=EC=9D=84=20=EB=8B=A4=EC=9D=8C=EB=8B=AC=2000?= =?UTF-8?q?=EC=8B=9C00=EB=B6=84=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/service/ExpenseServiceImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java index a51df924..9b5b1090 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java @@ -113,12 +113,10 @@ public void deleteExpense(Long expenseId) { @Transactional(readOnly = true) public MonthlyExpenseResponseDto getMonthlyExpense(Long userId, LocalDate localDate) { LocalDate startOfMonth = localDate.withDayOfMonth(1); - LocalDate endOfMonth = localDate.withDayOfMonth(startOfMonth.lengthOfMonth()); + LocalDate nextMonth = startOfMonth.plusMonths(1L); - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Invalid user ID")); - - List expenseSlice = expenseRepository.findAllByUserIdForPeriod(user, - startOfMonth.atStartOfDay(), endOfMonth.atTime(LocalTime.MAX)); + List expenseSlice = expenseRepository.findAllByUserIdForPeriod(userId, + startOfMonth.atStartOfDay(), nextMonth.atStartOfDay()); return expenseConverter.toMonthlyExpenseResponseDto(expenseSlice, startOfMonth); } From 1cec340fb4ced1bec2214409b172f942b1e83e18 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 24 Oct 2024 22:17:08 +0900 Subject: [PATCH 23/58] =?UTF-8?q?[refactor]=20ExpenseRepository=20?= =?UTF-8?q?=EC=9B=94=EB=B3=84=EC=86=8C=EB=B9=84=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=9B=94=EC=B4=88=2000=EC=8B=9C=2000=EB=B6=84=20=EB=B6=80?= =?UTF-8?q?=ED=84=B0=20=EB=8B=A4=EC=9D=8C=EB=8B=AC=201=EC=9D=BC=2000?= =?UTF-8?q?=EC=8B=9C=2000=EB=B6=84=EC=9C=BC=EB=A1=9C=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/repository/ExpenseRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java index b55c55fd..62279b8b 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepository.java @@ -14,8 +14,8 @@ import com.bbteam.budgetbuddies.enums.Gender; public interface ExpenseRepository extends JpaRepository { - @Query("SELECT e FROM Expense e WHERE e.user = :user AND e.expenseDate BETWEEN :startDate AND :endDate ORDER BY e.expenseDate DESC") - List findAllByUserIdForPeriod(@Param("user") User user, @Param("startDate") LocalDateTime startDate, + @Query("SELECT e FROM Expense e WHERE e.user.id = :userId AND e.expenseDate >= :startDate AND e.expenseDate < :endDate ORDER BY e.expenseDate DESC") + List findAllByUserIdForPeriod(@Param("userId") Long userId, @Param("startDate") LocalDateTime startDate, @Param("endDate") LocalDateTime endDate); List findByCategoryIdAndUserIdAndExpenseDateBetweenAndDeletedFalse(Long categoryId, Long userId, From 2c1a39586861e0444c252cbc07a5efd59c05034e Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 24 Oct 2024 22:17:38 +0900 Subject: [PATCH 24/58] =?UTF-8?q?[test]=20ExpenseRepositoryTest=20?= =?UTF-8?q?=EC=9B=94=EB=B3=84=EC=A1=B0=ED=9A=8C=20=EA=B2=BD=EA=B3=97?= =?UTF-8?q?=EA=B0=92=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/ExpenseRepositoryTest.java | 85 ++++++++++--------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepositoryTest.java index c1b34ada..97806cd2 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepositoryTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/expense/repository/ExpenseRepositoryTest.java @@ -3,7 +3,6 @@ import static org.assertj.core.api.Assertions.*; import java.time.LocalDate; -import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.DisplayName; @@ -30,59 +29,63 @@ class ExpenseRepositoryTest { private CategoryRepository categoryRepository; @Test - @DisplayName("findAllByUserIdFOrPeriod 성공") - void findAllByUserIdForPeriod_Success() { + void 월별_소비조회_월초_월말_조회_성공() { // given - User user = userRepository.save( - User.builder().email("email").age(24).name("name").phoneNumber("010-1234-5678").build()); + User user = userRepository.save(User.builder() + .email("email") + .age(24) + .name("test user") + .phoneNumber("010-1234-5678") + .mobileCarrier("TEST") + .build()); Category userCategory = categoryRepository.save( Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); - LocalDate startDate = LocalDate.of(2024, 7, 1); - LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth()); + LocalDate startMonth = LocalDate.of(2024, 7, 1); + LocalDate nextMonth = startMonth.plusMonths(1L); - List expected = setExpense(user, userCategory, startDate); + List expected = getExpectedExpense(user, userCategory); + setUnExpectedExpense(user, userCategory, nextMonth); // when - List result = expenseRepository.findAllByUserIdForPeriod(user, - startDate.atStartOfDay(), endDate.atStartOfDay()); + List result = expenseRepository.findAllByUserIdForPeriod(user.getId(), startMonth.atStartOfDay(), + nextMonth.atStartOfDay()); assertThat(result).usingRecursiveComparison().isEqualTo(expected); } - private List setExpense(User user, Category userCategory, LocalDate startDate) { - setUnexpectedExpense(user, userCategory, startDate); - - return setExpectedExpenseOrderByDateDesc(user, userCategory, startDate); - } - - private List setExpectedExpenseOrderByDateDesc(User user, Category userCategory, LocalDate startDate) { - List expenses = new ArrayList<>(); - - for (int i = startDate.lengthOfMonth(); i > startDate.lengthOfMonth() - 5; i--) { - Expense expense = Expense.builder() - .user(user) - .category(userCategory) - .amount(100000L * i) - .expenseDate(startDate.withDayOfMonth(i).atStartOfDay()) - .build(); - - expenses.add(expenseRepository.save(expense)); - } - return expenses; + private List getExpectedExpense(User user, Category userCategory) { + Expense monthOfStartExpense = Expense.builder() + .user(user) + .category(userCategory) + .amount(100000L) + .expenseDate(LocalDate.of(2024, 7, 1).atStartOfDay()) + .build(); + + Expense monthOfLastExpense = Expense.builder() + .user(user) + .category(userCategory) + .amount(100000L) + .expenseDate(LocalDate.of(2024, 7, 31).atTime(23, 59)) + .build(); + + return List.of(expenseRepository.save(monthOfLastExpense), expenseRepository.save(monthOfStartExpense)); } - private void setUnexpectedExpense(User user, Category userCategory, LocalDate startDate) { - for (int i = 1; i <= 5; i++) { - Expense expense = Expense.builder() - .user(user) - .category(userCategory) - .amount(100000L * i) - .expenseDate(startDate.withMonth(8).atStartOfDay()) - .build(); - - expenseRepository.save(expense); - } + private void setUnExpectedExpense(User user, Category userCategory, LocalDate nextMonth) { + expenseRepository.save(Expense.builder() + .user(user) + .category(userCategory) + .amount(100000L) + .expenseDate(LocalDate.of(2024, 8, 1).atStartOfDay()) + .build()); + + expenseRepository.save(Expense.builder() + .user(user) + .category(userCategory) + .amount(100000L) + .expenseDate(LocalDate.of(2024, 6, 30).atTime(23, 59)) + .build()); } } \ No newline at end of file From 2925e2615f1ad36efce3ff055bb9ddce36ded463 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 24 Oct 2024 22:18:17 +0900 Subject: [PATCH 25/58] =?UTF-8?q?[test]=20ExpenseServiceImplTest=20?= =?UTF-8?q?=EC=9B=94=EB=B3=84=20=EC=86=8C=EB=B9=84=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ExpenseServiceImplTest.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java index 2c7a8484..fd1a8d5f 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java @@ -54,11 +54,8 @@ void setUp() { } @Test - @DisplayName("월별 소비 조회 소비를 DailyExpenseResponseDto로 반환") - void getMonthlyExpense_Success() { + void 월별_소비목록_조회_소비일을_기준으로_소비를_반환_성공() { // given - given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); - Category userCategory = Mockito.spy(Category.builder().build()); given(userCategory.getId()).willReturn(-1L); @@ -66,11 +63,21 @@ void getMonthlyExpense_Success() { List expenses = generateExpenseList(requestMonth, user, userCategory); - given(expenseRepository.findAllByUserIdForPeriod(any(User.class), any(LocalDateTime.class), + given(expenseRepository.findAllByUserIdForPeriod(anyLong(), any(LocalDateTime.class), any(LocalDateTime.class))).willReturn(expenses); - MonthlyExpenseResponseDto expected = MonthlyExpenseResponseDto.builder() - .expenseMonth(LocalDate.of(2024, 07, 01)) + MonthlyExpenseResponseDto expected = getExpectedMonthlyExpense(userCategory); + + // when + MonthlyExpenseResponseDto result = expenseService.getMonthlyExpense(user.getId(), requestMonth); + + // then + assertThat(result).usingRecursiveComparison().isEqualTo(expected); + } + + private MonthlyExpenseResponseDto getExpectedMonthlyExpense(Category userCategory) { + return MonthlyExpenseResponseDto.builder() + .expenseMonth(LocalDate.of(2024, 7, 1)) .totalConsumptionAmount(300_000L) .dailyExpenses(List.of(DailyExpenseResponseDto.builder() .daysOfMonth(2) From 163f03daab9672b0fdc2e67847cb4611de17a405 Mon Sep 17 00:00:00 2001 From: JunRain Date: Fri, 25 Oct 2024 15:42:03 +0900 Subject: [PATCH 26/58] =?UTF-8?q?[refactor]=20=EC=83=81=EC=84=B8=EC=86=8C?= =?UTF-8?q?=EB=B9=84=EC=A1=B0=ED=9A=8C=20DTO=20=EB=AA=85=EC=8B=9C=EC=A0=81?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20userId=20?= =?UTF-8?q?=EC=B9=BC=EB=9F=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/converter/ExpenseConverter.java | 7 +++---- ...penseResponseDto.java => DetailExpenseResponseDto.java} | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) rename src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/{ExpenseResponseDto.java => DetailExpenseResponseDto.java} (91%) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java index 665849d1..ec248bc8 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java @@ -13,7 +13,7 @@ import com.bbteam.budgetbuddies.domain.expense.dto.CompactExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.DailyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.user.entity.User; @@ -31,10 +31,9 @@ public Expense toExpenseEntity(ExpenseRequestDto expenseRequestDto, User user, C .build(); } - public ExpenseResponseDto toExpenseResponseDto(Expense expense) { - return ExpenseResponseDto.builder() + public DetailExpenseResponseDto toExpenseResponseDto(Expense expense) { + return DetailExpenseResponseDto.builder() .expenseId(expense.getId()) - .userId(expense.getUser().getId()) .categoryId(expense.getCategory().getId()) .categoryName(expense.getCategory().getName()) .amount(expense.getAmount()) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/DetailExpenseResponseDto.java similarity index 91% rename from src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java rename to src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/DetailExpenseResponseDto.java index f0996be0..ef0fdef5 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseResponseDto.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/DetailExpenseResponseDto.java @@ -13,9 +13,8 @@ @Builder @NoArgsConstructor @AllArgsConstructor -public class ExpenseResponseDto { +public class DetailExpenseResponseDto { private Long expenseId; - private Long userId; private Long categoryId; private String categoryName; private Long amount; From 456c8e0f0db93c8769ade740a8e6eda5dd9d4f07 Mon Sep 17 00:00:00 2001 From: JunRain Date: Fri, 25 Oct 2024 15:43:36 +0900 Subject: [PATCH 27/58] =?UTF-8?q?[refactor]=20ExpenseController=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=EC=86=8C=EB=B9=84=EC=A1=B0=ED=9A=8C=20@AuthU?= =?UTF-8?q?ser=EB=A5=BC=20=ED=86=B5=ED=95=9C=20userId=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/controller/ExpenseApi.java | 15 +++++-------- .../expense/controller/ExpenseController.java | 22 +++++++++---------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java index 475ec7f5..bd550b32 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java @@ -3,17 +3,15 @@ import java.time.LocalDate; import org.springframework.data.repository.query.Param; -import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.user.dto.UserDto; @@ -32,9 +30,9 @@ public interface ExpenseApi { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))}) - ResponseEntity createExpense( - @Parameter(description = "user_id") @PathVariable Long userId, - @Parameter(description = "category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto + ResponseEntity createExpense( + @Parameter(description = "user_id") @PathVariable Long userId, + @Parameter(description = "category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto ); @Operation(summary = "[User] 월별 소비 조회", description = "무한 스크롤을 통한 조회로 예상하여 Slice를 통해서 조회") @@ -53,8 +51,7 @@ ResponseEntity findExpensesForMonth( @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))}) - @GetMapping("/{userId}/{expenseId}") - ResponseEntity findExpense(@Param("userId") Long userId, @Param("expenseId") Long expenseId); + ResponseEntity findExpense(UserDto.AuthUserDto user, Long expenseId); @Operation(summary = "[User] 단일 소비 업데이트하기", description = "소비 아이디와 카테고리 아이디, amount(소비 금액)을 body에 담아서 소비를 업데이트") @ApiResponses({ @@ -64,7 +61,7 @@ ResponseEntity findExpensesForMonth( @ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))}) @GetMapping("/{userId}/{expenseId}") @PostMapping("/{userId}") - ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, + ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, @RequestBody ExpenseUpdateRequestDto request); @Operation(summary = "[User] 소비 내역 삭제", description = "사용자가 소비 내역을 삭제합니다.") diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java index 979306d2..7382c8b3 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java @@ -33,10 +33,10 @@ public class ExpenseController implements ExpenseApi { @Override @PostMapping("/add/{userId}") - public ResponseEntity createExpense( - @Parameter(description = "user_id") @PathVariable Long userId, - @Parameter(description = "category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto) { - ExpenseResponseDto response = expenseService.createExpense(userId, expenseRequestDto); + public ResponseEntity createExpense( + @Parameter(description = "user_id") @PathVariable Long userId, + @Parameter(description = "category_id, amount, description, expenseDate") @RequestBody ExpenseRequestDto expenseRequestDto) { + DetailExpenseResponseDto response = expenseService.createExpense(userId, expenseRequestDto); return ResponseEntity.ok(response); } @@ -49,24 +49,22 @@ public ResponseEntity findExpensesForMonth(@AuthUser } @Override - @GetMapping("/{userId}/{expenseId}") - public ResponseEntity findExpense(@PathVariable @Param("userId") Long userId, + @GetMapping("/{expenseId}") + public ResponseEntity findExpense(@AuthUser UserDto.AuthUserDto user, @PathVariable @Param("expenseId") Long expenseId) { - return ResponseEntity.ok(expenseService.findExpenseResponseFromUserIdAndExpenseId(userId, expenseId)); + return ResponseEntity.ok(expenseService.findDetailExpenseResponse(user.getId(), expenseId)); } @Override @PostMapping("/{userId}") - public ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, + public ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, @RequestBody ExpenseUpdateRequestDto request) { - ExpenseResponseDto response = expenseService.updateExpense(userId, request); + DetailExpenseResponseDto response = expenseService.updateExpense(userId, request); return ResponseEntity.ok(response); } @DeleteMapping("/delete/{expenseId}") - public ResponseEntity deleteExpense( - @Parameter(description = "expense_id") - @PathVariable Long expenseId) { + public ResponseEntity deleteExpense(@Parameter(description = "expense_id") @PathVariable Long expenseId) { expenseService.deleteExpense(expenseId); return ResponseEntity.ok("Successfully deleted expense!"); } From 3d4a69967b6b500067863e13b4a55cb7f1600b70 Mon Sep 17 00:00:00 2001 From: JunRain Date: Fri, 25 Oct 2024 15:51:28 +0900 Subject: [PATCH 28/58] =?UTF-8?q?[refactor]=20=EC=9C=A0=EC=A0=80=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=B2=B4=ED=81=AC=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F?= =?UTF-8?q?=20Expense=20=EC=A1=B0=ED=9A=8C=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expense/service/ExpenseServiceImpl.java | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java index 9b5b1090..06232ce1 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java @@ -1,7 +1,6 @@ package com.bbteam.budgetbuddies.domain.expense.service; import java.time.LocalDate; -import java.time.LocalTime; import java.util.List; import org.springframework.stereotype.Service; @@ -13,7 +12,7 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; import com.bbteam.budgetbuddies.domain.expense.converter.ExpenseConverter; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; @@ -35,7 +34,7 @@ public class ExpenseServiceImpl implements ExpenseService { private final ConsumptionGoalService consumptionGoalService; @Override - public ExpenseResponseDto createExpense(Long userId, ExpenseRequestDto expenseRequestDto) { + public DetailExpenseResponseDto createExpense(Long userId, ExpenseRequestDto expenseRequestDto) { User user = userRepository.findById(userId) .orElseThrow(() -> new IllegalArgumentException("Invalid user ID")); Category category = categoryRepository.findById(expenseRequestDto.getCategoryId()) @@ -73,12 +72,13 @@ else if (!category.getIsDefault() && category.getUser().getId().equals(userId)) if (expenseDateMonth.equals(currentMonth)) { // 현재 월의 소비 내역일 경우 ConsumptionGoal을 업데이트 - consumptionGoalService.updateConsumeAmount(userId, expenseRequestDto.getCategoryId(), expenseRequestDto.getAmount()); + consumptionGoalService.updateConsumeAmount(userId, expenseRequestDto.getCategoryId(), + expenseRequestDto.getAmount()); } -// else { -// // 과거 월의 소비 내역일 경우 해당 월의 ConsumptionGoal을 업데이트 또는 삭제 상태로 생성 -// consumptionGoalService.updateOrCreateDeletedConsumptionGoal(userId, expenseRequestDto.getCategoryId(), expenseDateMonth, expenseRequestDto.getAmount()); -// } + // else { + // // 과거 월의 소비 내역일 경우 해당 월의 ConsumptionGoal을 업데이트 또는 삭제 상태로 생성 + // consumptionGoalService.updateOrCreateDeletedConsumptionGoal(userId, expenseRequestDto.getCategoryId(), expenseDateMonth, expenseRequestDto.getAmount()); + // } return expenseConverter.toExpenseResponseDto(expense); /* @@ -91,7 +91,7 @@ else if (!category.getIsDefault() && category.getUser().getId().equals(userId)) @Transactional public void deleteExpense(Long expenseId) { Expense expense = expenseRepository.findById(expenseId) - .orElseThrow(() -> new IllegalArgumentException("Not found Expense")); + .orElseThrow(() -> new IllegalArgumentException("Not found Expense")); Long userId = expense.getUser().getId(); Long categoryId = expense.getCategory().getId(); @@ -122,28 +122,22 @@ public MonthlyExpenseResponseDto getMonthlyExpense(Long userId, LocalDate localD } @Override - public ExpenseResponseDto findExpenseResponseFromUserIdAndExpenseId(Long userId, Long expenseId) { - Expense expense = expenseRepository.findById(expenseId) - .orElseThrow(() -> new IllegalArgumentException("Not found expense")); - - checkUserAuthority(userId, expense); - - return expenseConverter.toExpenseResponseDto(expense); + public DetailExpenseResponseDto findDetailExpenseResponse(Long userId, Long expenseId) { + return expenseConverter.toExpenseResponseDto(getExpense(expenseId)); } - private void checkUserAuthority(Long userId, Expense expense) { - if (!expense.getUser().getId().equals(userId)) - throw new IllegalArgumentException("Unauthorized user"); + private Expense getExpense(Long expenseId) { + return expenseRepository.findById(expenseId) + .orElseThrow(() -> new IllegalArgumentException("Not found expense")); } @Override @Transactional - public ExpenseResponseDto updateExpense(Long userId, ExpenseUpdateRequestDto request) { + public DetailExpenseResponseDto updateExpense(Long userId, ExpenseUpdateRequestDto request) { Expense expense = expenseRepository.findById(request.getExpenseId()) .orElseThrow(() -> new IllegalArgumentException("Not found expense")); User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user")); - checkUserAuthority(userId, expense); Category categoryToReplace = categoryService.handleCategoryChange(expense, request, user); From 3f44baef02930ee2392c139f7b3877cc57329b6d Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 16:49:27 +0900 Subject: [PATCH 29/58] =?UTF-8?q?[fix]=20ExpenseController=20=EC=86=8C?= =?UTF-8?q?=EB=B9=84=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20@AuthUser?= =?UTF-8?q?=EB=A5=BC=20=ED=86=B5=ED=95=B4=20User=20=EC=A3=BC=EC=9E=85?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/controller/ExpenseApi.java | 10 ++-------- .../domain/expense/controller/ExpenseController.java | 9 ++++----- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java index bd550b32..45856956 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseApi.java @@ -2,16 +2,13 @@ import java.time.LocalDate; -import org.springframework.data.repository.query.Param; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.user.dto.UserDto; @@ -59,10 +56,7 @@ ResponseEntity findExpensesForMonth( @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "AUTH003", description = "access 토큰을 주세요!", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH004", description = "access 토큰 만료", content = @Content(schema = @Schema(implementation = ApiResponse.class))), @ApiResponse(responseCode = "AUTH006", description = "access 토큰 모양이 이상함", content = @Content(schema = @Schema(implementation = ApiResponse.class)))}) - @GetMapping("/{userId}/{expenseId}") - @PostMapping("/{userId}") - ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, - @RequestBody ExpenseUpdateRequestDto request); + ResponseEntity updateExpense(UserDto.AuthUserDto user, ExpenseUpdateRequestDto request); @Operation(summary = "[User] 소비 내역 삭제", description = "사용자가 소비 내역을 삭제합니다.") @ApiResponses({ diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java index 7382c8b3..75329f71 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/controller/ExpenseController.java @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.RestController; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.service.ExpenseService; @@ -56,11 +56,10 @@ public ResponseEntity findExpense(@AuthUser UserDto.Au } @Override - @PostMapping("/{userId}") - public ResponseEntity updateExpense(@PathVariable @Param("userId") Long userId, + @PostMapping() + public ResponseEntity updateExpense(@AuthUser UserDto.AuthUserDto user, @RequestBody ExpenseUpdateRequestDto request) { - DetailExpenseResponseDto response = expenseService.updateExpense(userId, request); - return ResponseEntity.ok(response); + return ResponseEntity.ok(expenseService.updateExpense(user.getId(), request)); } @DeleteMapping("/delete/{expenseId}") From fee02a78fcd46d71c9a61c4fa4132b13c99bbe63 Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 16:52:33 +0900 Subject: [PATCH 30/58] =?UTF-8?q?[refactor]=20ExpenseUpdateRequestDto=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/expense/converter/ExpenseConverter.java | 2 +- .../domain/expense/dto/ExpenseUpdateRequestDto.java | 2 ++ .../domain/expense/service/ExpenseService.java | 8 ++++---- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java index ec248bc8..3c639164 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/converter/ExpenseConverter.java @@ -31,7 +31,7 @@ public Expense toExpenseEntity(ExpenseRequestDto expenseRequestDto, User user, C .build(); } - public DetailExpenseResponseDto toExpenseResponseDto(Expense expense) { + public DetailExpenseResponseDto toDetailExpenseResponseDto(Expense expense) { return DetailExpenseResponseDto.builder() .expenseId(expense.getId()) .categoryId(expense.getCategory().getId()) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseUpdateRequestDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseUpdateRequestDto.java index 14312ca2..464cd098 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseUpdateRequestDto.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/dto/ExpenseUpdateRequestDto.java @@ -16,9 +16,11 @@ @Builder public class ExpenseUpdateRequestDto { private Long expenseId; + private Long categoryId; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime expenseDate; + private Long amount; } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java index 67df0f7e..b14c8332 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseService.java @@ -3,18 +3,18 @@ import java.time.LocalDate; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; public interface ExpenseService { - ExpenseResponseDto createExpense(Long userId, ExpenseRequestDto expenseRequestDto); + DetailExpenseResponseDto createExpense(Long userId, ExpenseRequestDto expenseRequestDto); MonthlyExpenseResponseDto getMonthlyExpense(Long userId, LocalDate localDate); - ExpenseResponseDto findExpenseResponseFromUserIdAndExpenseId(Long userId, Long expenseId); + DetailExpenseResponseDto findDetailExpenseResponse(Long userId, Long expenseId); - ExpenseResponseDto updateExpense(Long userId, ExpenseUpdateRequestDto request); + DetailExpenseResponseDto updateExpense(Long userId, ExpenseUpdateRequestDto request); void deleteExpense(Long expenseId); } From 3f85a28661f8d4f1c6c46b598b6c06e204d9be7d Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 16:54:03 +0900 Subject: [PATCH 31/58] =?UTF-8?q?[refactor]=20ExpenseServiceImpl=20?= =?UTF-8?q?=EC=86=8C=EB=B9=84=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B5=AC=EC=A1=B0=EB=A5=BC=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expense/service/ExpenseServiceImpl.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java index 06232ce1..5d6bc445 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImpl.java @@ -9,16 +9,18 @@ import com.bbteam.budgetbuddies.domain.category.entity.Category; import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository; import com.bbteam.budgetbuddies.domain.category.service.CategoryService; +import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; import com.bbteam.budgetbuddies.domain.expense.converter.ExpenseConverter; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; +import com.bbteam.budgetbuddies.domain.user.service.UserService; import lombok.RequiredArgsConstructor; @@ -28,6 +30,7 @@ public class ExpenseServiceImpl implements ExpenseService { private final ExpenseRepository expenseRepository; private final UserRepository userRepository; + private final UserService userService; private final CategoryRepository categoryRepository; private final CategoryService categoryService; private final ExpenseConverter expenseConverter; @@ -80,7 +83,7 @@ else if (!category.getIsDefault() && category.getUser().getId().equals(userId)) // consumptionGoalService.updateOrCreateDeletedConsumptionGoal(userId, expenseRequestDto.getCategoryId(), expenseDateMonth, expenseRequestDto.getAmount()); // } - return expenseConverter.toExpenseResponseDto(expense); + return expenseConverter.toDetailExpenseResponseDto(expense); /* Case 1 결과) 해당 유저의 user_id + immutable 필드 중 하나의 조합으로 Expense 테이블에 저장 Case 2 결과) 내가 직접 생성한 카테고리 중 하나로 카테고리를 설정하여 Expense 테이블에 저장 @@ -123,7 +126,7 @@ public MonthlyExpenseResponseDto getMonthlyExpense(Long userId, LocalDate localD @Override public DetailExpenseResponseDto findDetailExpenseResponse(Long userId, Long expenseId) { - return expenseConverter.toExpenseResponseDto(getExpense(expenseId)); + return expenseConverter.toDetailExpenseResponseDto(getExpense(expenseId)); } private Expense getExpense(Long expenseId) { @@ -134,16 +137,21 @@ private Expense getExpense(Long expenseId) { @Override @Transactional public DetailExpenseResponseDto updateExpense(Long userId, ExpenseUpdateRequestDto request) { - Expense expense = expenseRepository.findById(request.getExpenseId()) - .orElseThrow(() -> new IllegalArgumentException("Not found expense")); + User user = userService.getUser(userId); + Expense expense = getExpense(request.getExpenseId()); + Category categoryToReplace = categoryService.getCategory(request.getCategoryId()); - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user")); + expense.updateExpenseFromRequest(request, categoryToReplace); - Category categoryToReplace = categoryService.handleCategoryChange(expense, request, user); + ConsumptionGoal beforeConsumptionGoal = consumptionGoalService.getUserConsumptionGoal( + user, expense.getCategory(), expense.getExpenseDate().toLocalDate().withDayOfMonth(1)); + ConsumptionGoal afterConsumptionGoal = consumptionGoalService.getUserConsumptionGoal( + user, categoryToReplace, request.getExpenseDate().toLocalDate().withDayOfMonth(1)); - expense.updateExpenseFromRequest(request, categoryToReplace); + consumptionGoalService.recalculateConsumptionAmount(beforeConsumptionGoal, expense.getAmount(), + afterConsumptionGoal, request.getAmount()); - return expenseConverter.toExpenseResponseDto(expenseRepository.save(expense)); + return expenseConverter.toDetailExpenseResponseDto(expenseRepository.save(expense)); } } From 19dc666dad171d903ce80e35955fc335edf4b6be Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 18:11:57 +0900 Subject: [PATCH 32/58] =?UTF-8?q?[feature]=20UserService=20userId=EB=A5=BC?= =?UTF-8?q?=20=ED=86=B5=ED=95=9C=20User=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../budgetbuddies/domain/user/service/UserService.java | 3 +++ .../budgetbuddies/domain/user/service/UserServiceImpl.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserService.java b/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserService.java index 0cb29dba..ac0d046b 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserService.java @@ -1,6 +1,7 @@ package com.bbteam.budgetbuddies.domain.user.service; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.UserConsumptionGoalResponse; import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.domain.user.entity.User; import java.util.List; @@ -14,4 +15,6 @@ public interface UserService { UserDto.ResponseUserDto modifyUser(Long userId, UserDto.ModifyUserDto dto); List findAll(); + + User getUser(Long userId); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserServiceImpl.java index 2ce9dbb1..6b9bb191 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/user/service/UserServiceImpl.java @@ -82,4 +82,9 @@ public List findAll() { .map(UserConverter::toDto) .toList(); } + + @Override + public User getUser(Long userId) { + return userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user")); + } } From b612cddbfddd45ee50c21ce7c73fd5cb43cf44b7 Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 18:14:43 +0900 Subject: [PATCH 33/58] =?UTF-8?q?[feat]=20CategoryService=20Category=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../category/service/CategoryService.java | 4 +- .../category/service/CategoryServiceImpl.java | 57 ++++++++----------- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java index 92083193..675d1581 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java @@ -14,8 +14,8 @@ public interface CategoryService { List getUserCategories(Long userId); - Category handleCategoryChange(Expense expense, ExpenseUpdateRequestDto request, User user); - void deleteCategory(Long id, Long userId); + + Category getCategory(Long categoryId); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java index af6ae372..c8dab75f 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java @@ -5,7 +5,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,8 +16,8 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository; import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; +import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; @@ -40,11 +39,11 @@ public class CategoryServiceImpl implements CategoryService { @Transactional public CategoryResponseDto createCategory(Long userId, CategoryRequestDto categoryRequestDto) { User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("Invalid user ID")); + .orElseThrow(() -> new IllegalArgumentException("Invalid user ID")); // 동일한 이름의 삭제된 카테고리가 존재하는지 확인 Optional existingCategory = categoryRepository.findByNameAndUserIdAndDeletedTrue( - categoryRequestDto.getName(), userId); + categoryRequestDto.getName(), userId); if (existingCategory.isPresent()) { // 삭제된 카테고리가 존재하면 복구 (deleted = false) @@ -54,7 +53,7 @@ public CategoryResponseDto createCategory(Long userId, CategoryRequestDto catego // 해당 카테고리의 삭제된 ConsumptionGoal도 복구 Optional existingConsumptionGoal = consumptionGoalRepository.findByUserAndCategoryAndDeletedTrue( - user, categoryToRestore); + user, categoryToRestore); if (existingConsumptionGoal.isPresent()) { ConsumptionGoal consumptionGoalToRestore = existingConsumptionGoal.get(); @@ -65,13 +64,13 @@ public CategoryResponseDto createCategory(Long userId, CategoryRequestDto catego } else { // ConsumptionGoal이 존재하지 않으면 새로 생성 ConsumptionGoal newConsumptionGoal = ConsumptionGoal.builder() - .user(user) - .category(categoryToRestore) - .goalMonth(LocalDate.now().withDayOfMonth(1)) // 현재 달로 목표 설정 - .consumeAmount(0L) - .goalAmount(0L) - .deleted(false) // 생성할 때 삭제 상태가 아니도록 - .build(); + .user(user) + .category(categoryToRestore) + .goalMonth(LocalDate.now().withDayOfMonth(1)) // 현재 달로 목표 설정 + .consumeAmount(0L) + .goalAmount(0L) + .deleted(false) // 생성할 때 삭제 상태가 아니도록 + .build(); consumptionGoalRepository.save(newConsumptionGoal); } @@ -83,13 +82,13 @@ public CategoryResponseDto createCategory(Long userId, CategoryRequestDto catego // 새로운 카테고리에 대한 ConsumptionGoal도 생성 ConsumptionGoal newConsumptionGoal = ConsumptionGoal.builder() - .user(user) - .category(newCategory) - .goalMonth(LocalDate.now().withDayOfMonth(1)) // 현재 달로 목표 설정 - .consumeAmount(0L) - .goalAmount(0L) - .deleted(false) // 생성할 때 삭제 상태가 아니도록 - .build(); + .user(user) + .category(newCategory) + .goalMonth(LocalDate.now().withDayOfMonth(1)) // 현재 달로 목표 설정 + .consumeAmount(0L) + .goalAmount(0L) + .deleted(false) // 생성할 때 삭제 상태가 아니도록 + .build(); consumptionGoalRepository.save(newConsumptionGoal); return categoryConverter.toCategoryResponseDto(newCategory); @@ -100,21 +99,15 @@ public CategoryResponseDto createCategory(Long userId, CategoryRequestDto catego public List getUserCategories(Long userId) { userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found with id: " + userId)); + .orElseThrow(() -> new IllegalArgumentException("User not found with id: " + userId)); List categories = categoryRepository.findUserCategoryByUserId(userId); return categories.stream().map(categoryConverter::toCategoryResponseDto).collect(Collectors.toList()); } @Override - @Transactional(readOnly = true) - public Category handleCategoryChange(Expense expense, ExpenseUpdateRequestDto request, User user) { - Category categoryToReplace = categoryRepository.findById(request.getCategoryId()) - .orElseThrow(() -> new IllegalArgumentException("Not found category")); - - consumptionGoalService.recalculateConsumptionAmount(expense, request, user); - - return categoryToReplace; + public Category getCategory(Long id) { + return categoryRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("Not found category")); } @Override @@ -131,15 +124,15 @@ public void deleteCategory(Long categoryId, Long userId) { // 현재 월에 해당하는 삭제되지 않은 Expense 조회 (deleted = false) List currentMonthExpenses = expenseRepository.findByCategoryIdAndUserIdAndExpenseDateBetweenAndDeletedFalse( - categoryId, userId, startOfMonth.atStartOfDay(), endOfMonth.atTime(23, 59, 59)); + categoryId, userId, startOfMonth.atStartOfDay(), endOfMonth.atTime(23, 59, 59)); long totalAmount = currentMonthExpenses.stream() - .mapToLong(Expense::getAmount) - .sum(); + .mapToLong(Expense::getAmount) + .sum(); // category_id = 10(기타 카테고리)의 소비 목표 업데이트 (custom 카테고리 삭제로 인한 소비 내역은 삭제되지 않고 기타 카테고리로..) ConsumptionGoal goal = consumptionGoalRepository.findByCategoryIdAndUserId(10L, userId) - .orElseThrow(() -> new IllegalArgumentException("No consumption goal found for category_id 10.")); + .orElseThrow(() -> new IllegalArgumentException("No consumption goal found for category_id 10.")); goal.setConsumeAmount(goal.getConsumeAmount() + totalAmount); consumptionGoalRepository.save(goal); From 342b1029fa80b890572000be2fdadcb683e45904 Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 18:16:22 +0900 Subject: [PATCH 34/58] =?UTF-8?q?[refactor]=20ConsumptionGoal=20=EC=86=8C?= =?UTF-8?q?=EB=B9=84=EC=B4=9D=EC=95=A1=20=EC=B6=94=EA=B0=80=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/consumptiongoal/entity/ConsumptionGoal.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java index 71d2accc..229f2df3 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/entity/ConsumptionGoal.java @@ -48,7 +48,7 @@ public class ConsumptionGoal extends BaseEntity { @JoinColumn(name = "category_id") private Category category; - public void updateConsumeAmount(Long amount) { + public void addConsumeAmount(Long amount) { this.consumeAmount += amount; } From 6df37c5e52eeaff68c1e82c9bbf15bef5bece821 Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 18:17:19 +0900 Subject: [PATCH 35/58] =?UTF-8?q?[refactor]=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=EC=97=90=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EB=AA=85=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/repository/ConsumptionGoalRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java index ad52c9c8..72284b9b 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/repository/ConsumptionGoalRepository.java @@ -25,8 +25,7 @@ public interface ConsumptionGoalRepository extends JpaRepository findConsumptionGoalByUserIdAndGoalMonth(Long userId, LocalDate goalMonth); - Optional findConsumptionGoalByUserAndCategoryAndGoalMonth(User user, Category category, - LocalDate goalMonth); + Optional findByUserAndCategoryAndGoalMonth(User user, Category category, LocalDate goalMonth); @Query("SELECT AVG(cg.consumeAmount) FROM ConsumptionGoal cg " + "JOIN cg.category c " + From 57c85a120d788f8bca17438aef1bcefb78a0dbaf Mon Sep 17 00:00:00 2001 From: JunRain Date: Sun, 27 Oct 2024 18:19:42 +0900 Subject: [PATCH 36/58] =?UTF-8?q?[feat]=20ConsumptionGoalService=20?= =?UTF-8?q?=EC=9C=A0=EC=A0=80=EC=9D=98=20=EC=86=8C=EB=B9=84=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20=EB=B0=8F=20=EC=86=8C=EB=B9=84?= =?UTF-8?q?=EA=B8=88=EC=95=A1=20=EC=9E=AC=EA=B3=84=EC=82=B0=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalService.java | 9 +- .../service/ConsumptionGoalServiceImpl.java | 89 ++++++++----------- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java index de727f3d..aecf4416 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalService.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service; +import com.bbteam.budgetbuddies.domain.category.entity.Category; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AllConsumptionCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionAnalysisResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto; @@ -13,8 +14,7 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; -import com.bbteam.budgetbuddies.domain.expense.entity.Expense; +import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.user.entity.User; @Service @@ -35,7 +35,8 @@ ConsumptionGoalResponseListDto updateConsumptionGoals(Long userId, ConsumptionAnalysisResponseDto getTopCategoryAndConsumptionAmount(Long userId); - void recalculateConsumptionAmount(Expense expense, ExpenseUpdateRequestDto request, User user); + void recalculateConsumptionAmount(ConsumptionGoal beforeConsumptionGoal, Long beforeAmount, + ConsumptionGoal afterConsumptionGoal, Long afterAmount); void updateConsumeAmount(Long userId, Long categoryId, Long amount); @@ -52,4 +53,6 @@ List getAllConsumptionCategories(Long userId, MonthReportResponseDto getMonthReport(Long userId); String getConsumptionMention(Long userId); + + ConsumptionGoal getUserConsumptionGoal(User user, Category category, LocalDate goalDate); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 73e1ba13..67d681ce 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -42,8 +42,6 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; -import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.gemini.service.GeminiService; import com.bbteam.budgetbuddies.domain.openai.service.OpenAiService; @@ -556,49 +554,10 @@ private List orderByRemainingBalanceDescending( @Override @Transactional - public void recalculateConsumptionAmount(Expense expense, ExpenseUpdateRequestDto request, User user) { - restorePreviousGoalConsumptionAmount(expense, user); - calculatePresentGoalConsumptionAmount(request, user); - } - - private void restorePreviousGoalConsumptionAmount(Expense expense, User user) { - ConsumptionGoal previousConsumptionGoal = consumptionGoalRepository.findLatelyGoal(user.getId(), - expense.getCategory().getId(), expense.getExpenseDate().toLocalDate().withDayOfMonth(1)) - .orElseThrow(() -> new IllegalArgumentException("Not found consumptionGoal")); - - previousConsumptionGoal.restoreConsumeAmount(expense.getAmount()); - consumptionGoalRepository.save(previousConsumptionGoal); - } - - private void calculatePresentGoalConsumptionAmount(ExpenseUpdateRequestDto request, User user) { - Category categoryToReplace = categoryRepository.findById(request.getCategoryId()) - .orElseThrow(() -> new IllegalArgumentException("Not found category")); - - ConsumptionGoal consumptionGoal = consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth( - user, categoryToReplace, request.getExpenseDate().toLocalDate().withDayOfMonth(1)) - .orElseGet(() -> this.generateGoalByPreviousOrElseNew(user, categoryToReplace, - request.getExpenseDate().toLocalDate().withDayOfMonth(1))); - - consumptionGoal.updateConsumeAmount(request.getAmount()); - consumptionGoalRepository.save(consumptionGoal); - } - - private ConsumptionGoal generateGoalByPreviousOrElseNew(User user, Category category, LocalDate goalMonth) { - LocalDate previousMonth = goalMonth.minusMonths(1); - - return consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, category, previousMonth) - .map(this::generateGoalByPrevious) - .orElseGet(() -> generateNewConsumptionGoal(user, category, goalMonth)); - } - - private ConsumptionGoal generateGoalByPrevious(ConsumptionGoal consumptionGoal) { - return ConsumptionGoal.builder() - .goalMonth(consumptionGoal.getGoalMonth().plusMonths(1)) - .user(consumptionGoal.getUser()) - .category(consumptionGoal.getCategory()) - .consumeAmount(0L) - .goalAmount(consumptionGoal.getGoalAmount()) - .build(); + public void recalculateConsumptionAmount(ConsumptionGoal beforeConsumptionGoal, Long beforeAmount, + ConsumptionGoal afterConsumptionGoal, Long afterAmount) { + beforeConsumptionGoal.restoreConsumeAmount(beforeAmount); + afterConsumptionGoal.addConsumeAmount(afterAmount); } @Override @@ -609,10 +568,10 @@ public void updateConsumeAmount(Long userId, Long categoryId, Long amount) { .orElseThrow(() -> new IllegalArgumentException("Not found Category")); LocalDate thisMonth = LocalDate.now().withDayOfMonth(1); - ConsumptionGoal consumptionGoal = consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth( + ConsumptionGoal consumptionGoal = consumptionGoalRepository.findByUserAndCategoryAndGoalMonth( user, category, thisMonth).orElseGet(() -> generateNewConsumptionGoal(user, category, thisMonth)); - consumptionGoal.updateConsumeAmount(amount); + consumptionGoal.addConsumeAmount(amount); consumptionGoalRepository.save(consumptionGoal); } @@ -624,7 +583,7 @@ public void decreaseConsumeAmount(Long userId, Long categoryId, Long amount, Loc .orElseThrow(() -> new IllegalArgumentException("Not found Category")); LocalDate goalMonth = expenseDate.withDayOfMonth(1); - ConsumptionGoal consumptionGoal = consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth( + ConsumptionGoal consumptionGoal = consumptionGoalRepository.findByUserAndCategoryAndGoalMonth( user, category, goalMonth).orElseThrow(() -> new IllegalArgumentException("Not found ConsumptionGoal")); consumptionGoal.decreaseConsumeAmount(amount); @@ -640,12 +599,12 @@ public void updateOrCreateDeletedConsumptionGoal(Long userId, Long categoryId, L .orElseThrow(() -> new IllegalArgumentException("Invalid category ID")); // 해당 월의 ConsumptionGoal이 존재하는지 확인 - Optional existingGoal = consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth( + Optional existingGoal = consumptionGoalRepository.findByUserAndCategoryAndGoalMonth( user, category, goalMonth); if (existingGoal.isPresent()) { // 존재하는 경우, consumeAmount 업데이트 ConsumptionGoal consumptionGoal = existingGoal.get(); - consumptionGoal.updateConsumeAmount(amount); + consumptionGoal.addConsumeAmount(amount); consumptionGoalRepository.save(consumptionGoal); } else { // 존재하지 않는 경우, 새로운 ConsumptionGoal을 생성 (이 때 목표 금액은 0) ConsumptionGoal newGoal = ConsumptionGoal.builder() @@ -656,7 +615,7 @@ public void updateOrCreateDeletedConsumptionGoal(Long userId, Long categoryId, L .goalAmount(0L) .build(); - newGoal.updateConsumeAmount(amount); // 신규 생성된 목표에 소비 금액 추가 + newGoal.addConsumeAmount(amount); // 신규 생성된 목표에 소비 금액 추가 consumptionGoalRepository.save(newGoal); } } @@ -785,7 +744,7 @@ private String getMainComment(List list) { } } Optional minCategory = categoryRepository.findById(minCategoryId); - + if (minCategory.isEmpty()) { throw new IllegalArgumentException("해당 카테고리를 찾을 수 없습니다."); } @@ -872,4 +831,30 @@ public String getConsumptionMention(Long userId) { // return geminiService.getContents(basePrompt); } + @Override + @Transactional + public ConsumptionGoal getUserConsumptionGoal(User user, Category category, LocalDate goalDate) { + LocalDate goalMonth = goalDate.withDayOfMonth(1); + + return consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth) + .orElseGet(() -> this.generateGoalFromPreviousOrNew(user, category, goalMonth)); + } + + private ConsumptionGoal generateGoalFromPreviousOrNew(User user, Category category, LocalDate goalMonth) { + LocalDate previousMonth = goalMonth.minusMonths(1); + + return consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, previousMonth) + .map(this::generateGoalByPrevious) + .orElseGet(() -> generateNewConsumptionGoal(user, category, goalMonth)); + } + + private ConsumptionGoal generateGoalByPrevious(ConsumptionGoal consumptionGoal) { + return ConsumptionGoal.builder() + .goalMonth(consumptionGoal.getGoalMonth().plusMonths(1)) + .user(consumptionGoal.getUser()) + .category(consumptionGoal.getCategory()) + .consumeAmount(0L) + .goalAmount(consumptionGoal.getGoalAmount()) + .build(); + } } \ No newline at end of file From 65c629a486c6ca82ad0002e061dbb0e5b7306ee0 Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 29 Oct 2024 13:27:32 +0900 Subject: [PATCH 37/58] =?UTF-8?q?[refactor]=20=20Cache=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=97=AC=20AI=20=EB=A9=98=ED=8A=B8=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 84 ++++++++++--------- .../BudgetbuddiesApplication.java | 2 + .../service/ConsumptionGoalServiceImpl.java | 3 + .../global/config/CachingConfig.java | 22 +++++ 4 files changed, 70 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java diff --git a/build.gradle b/build.gradle index 5ae542b7..ff0fc828 100644 --- a/build.gradle +++ b/build.gradle @@ -1,67 +1,69 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.2.7' - id 'io.spring.dependency-management' version '1.1.5' - id 'com.google.cloud.tools.jib' version '3.4.3' + id 'java' + id 'org.springframework.boot' version '3.2.7' + id 'io.spring.dependency-management' version '1.1.5' + id 'com.google.cloud.tools.jib' version '3.4.3' } group = 'com.bbteam' version = '0.0.1-SNAPSHOT' java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) - } + toolchain { + languageVersion = JavaLanguageVersion.of(17) + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-security' // security - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' //Swagger + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-security' // security + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' //Swagger - implementation 'net.nurigo:sdk:4.2.7' // 문자메시지 대행 서비스 + implementation 'net.nurigo:sdk:4.2.7' // 문자메시지 대행 서비스 - compileOnly 'org.projectlombok:lombok' - runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-cache' // cache - implementation 'io.jsonwebtoken:jjwt-api:0.11.5' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' - runtimeOnly('io.jsonwebtoken:jjwt-jackson:0.11.5') // jackson으로 jwt 파싱 + compileOnly 'org.projectlombok:lombok' + runtimeOnly 'com.mysql:mysql-connector-j' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' + runtimeOnly('io.jsonwebtoken:jjwt-jackson:0.11.5') // jackson으로 jwt 파싱 } tasks.named('test') { - useJUnitPlatform() + useJUnitPlatform() } jib { - from { - image = 'openjdk:17-alpine' - platforms { - platform { - architecture = 'amd64' - os = 'linux' - } - } - } - to { - image = 'binjumeoniz1/binjumeoniz:latest' - } - container { - jvmFlags = ['-Dspring.profiles.active=dev'] - } + from { + image = 'openjdk:17-alpine' + platforms { + platform { + architecture = 'amd64' + os = 'linux' + } + } + } + to { + image = 'binjumeoniz1/binjumeoniz:latest' + } + container { + jvmFlags = ['-Dspring.profiles.active=dev'] + } } diff --git a/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java b/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java index 9443b8db..8563c078 100644 --- a/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java +++ b/src/main/java/com/bbteam/budgetbuddies/BudgetbuddiesApplication.java @@ -2,12 +2,14 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.scheduling.annotation.EnableAsync; @SpringBootApplication @EnableJpaAuditing @EnableAsync +@EnableCaching public class BudgetbuddiesApplication { public static void main(String[] args) { diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 57239627..dd40480b 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import org.springframework.cache.annotation.Cacheable; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -811,6 +812,7 @@ private String getMainComment(List list) { @Override @Async @Transactional(readOnly = true) + @Cacheable(value = "openAiResponses", key = "#userId") public CompletableFuture getConsumptionMention(Long userId) { /** @@ -869,6 +871,7 @@ public CompletableFuture getConsumptionMention(Long userId) { String response = openAiService.chat(basePrompt); + // GPT 프롬프트 실패 시 기본 멘트 생성 반환 if (response == null) { NumberFormat nf = NumberFormat.getInstance(Locale.KOREA); response = "총 " + nf.format(goalAmount - consumeAmount) + "원 더 쓸 수 있어요."; diff --git a/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java b/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java new file mode 100644 index 00000000..e916d36b --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java @@ -0,0 +1,22 @@ +package com.bbteam.budgetbuddies.global.config; + +import java.util.List; + +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@EnableCaching +@Configuration +public class CachingConfig { + + @Bean + public CacheManager cacheManager() { + ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); + cacheManager.setAllowNullValues(false); + cacheManager.setCacheNames(List.of("openAiResponses")); + return cacheManager; + } +} From 2fe131cc2170fc1a19bb13bb826f953589dc4b64 Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 29 Oct 2024 14:34:08 +0900 Subject: [PATCH 38/58] =?UTF-8?q?[refactor]=20=20Cache=20value=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/service/ConsumptionGoalServiceImpl.java | 2 +- .../com/bbteam/budgetbuddies/global/config/CachingConfig.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index dd40480b..da24d1ed 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -812,7 +812,7 @@ private String getMainComment(List list) { @Override @Async @Transactional(readOnly = true) - @Cacheable(value = "openAiResponses", key = "#userId") + @Cacheable(value = "consumptionMent", key = "#userId") public CompletableFuture getConsumptionMention(Long userId) { /** diff --git a/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java b/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java index e916d36b..54ad8a20 100644 --- a/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java +++ b/src/main/java/com/bbteam/budgetbuddies/global/config/CachingConfig.java @@ -16,7 +16,7 @@ public class CachingConfig { public CacheManager cacheManager() { ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); cacheManager.setAllowNullValues(false); - cacheManager.setCacheNames(List.of("openAiResponses")); + cacheManager.setCacheNames(List.of("consumptionMent")); return cacheManager; } } From 8c42b49621450152fa293fc30f1065c4e9e36bba Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 29 Oct 2024 15:34:02 +0900 Subject: [PATCH 39/58] =?UTF-8?q?[refactor]=20=20@AuthUser=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=8F=20=EC=8A=A4=EC=9B=A8=EA=B1=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ConsumptionGoalApi.java | 43 ++++++++----- .../controller/ConsumptionGoalController.java | 63 +++++++++++-------- 2 files changed, 67 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java index 69094dbc..304fd7c5 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java @@ -2,18 +2,20 @@ import java.time.LocalDate; import java.util.List; +import java.util.concurrent.ExecutionException; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; import com.bbteam.budgetbuddies.apiPayload.ApiResponse; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AllConsumptionCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionAnalysisResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto; +import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MonthReportResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -25,62 +27,75 @@ public interface ConsumptionGoalApi { @Operation(summary = "[User] 또래들이 가장 큰 계획을 세운 카테고리 조회 Top4", description = "특정 사용자의 소비 목표 카테고리별 소비 목표 금액을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"), + @Parameters({ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"), @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"), @Parameter(name = "peerGender", description = "또래 성별")}) ApiResponse> getTopConsumptionGoalCategories( - Long userId, int peerAgeStart, int peerAgeEnd, String peerGender); + UserDto.AuthUserDto user, int peerAgeStart, int peerAgeEnd, String peerGender); @Operation(summary = "[User] 또래들이 가장 많이 계획한 카테고리와 평균 금액 및 내 목표금액 차이 조회", description = "특정 사용자의 또래 소비 카테고리별 평균 목표 금액을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"), + @Parameters({ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"), @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"), @Parameter(name = "peerGender", description = "또래 성별")}) - ApiResponse> getAllConsumptionGoalCategories(Long userId, int peerAgeStart, + ApiResponse> getAllConsumptionGoalCategories(UserDto.AuthUserDto user, + int peerAgeStart, int peerAgeEnd, String peerGender); @Operation(summary = "[User] 또래나이와 성별 조회", description = "또래나이와 성별을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"), + @Parameters({ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"), @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"), @Parameter(name = "peerGender", description = "또래 성별")}) - ApiResponse getPeerInfo(Long userId, int peerAgeStart, int peerAgeEnd, String peerGender); + ApiResponse getPeerInfo(UserDto.AuthUserDto user, int peerAgeStart, int peerAgeEnd, + String peerGender); @Operation(summary = "[User] 소비 목표 조회", description = "date={yyyy-MM-dd} 형식의 query string을 통해서 사용자의 목표 달을 조회하는 API 입니다.") @Parameters({@Parameter(name = "date", description = "yyyy-MM-dd 형식으로 목표 달의 소비를 조회")}) - ApiResponse findUserConsumptionGoal(LocalDate date, Long userId); + ApiResponse findUserConsumptionGoal(LocalDate date, UserDto.AuthUserDto user); @Operation(summary = "[User] 이번 달 소비 목표 수정", description = "다른 달의 소비 목표를 업데이트하는 것은 불가능하고 오직 이번 달의 소비 목표만 업데이트 하는 API 입니다.") - ResponseEntity updateOrElseGenerateConsumptionGoal(Long userId, + ResponseEntity updateOrElseGenerateConsumptionGoal(UserDto.AuthUserDto user, ConsumptionGoalListRequestDto consumptionGoalListRequestDto); @Operation(summary = "[User] 또래들이 가장 많이한 소비 카테고리 조회 Top3", description = "특정 사용자의 또래 소비 카테고리별 소비 건 수을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"), + @Parameters({ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"), @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"), @Parameter(name = "peerGender", description = "또래 성별")}) - ApiResponse> getTopConsumptionCategories(Long userId, int peerAgeStart, + ApiResponse> getTopConsumptionCategories(UserDto.AuthUserDto user, int peerAgeStart, int peerAgeEnd, String peerGender); @Operation(summary = "[User] 또래들이 가장 많이한 소비 카테고리와 평균 금액 및 내 소비금액 차이 조회", description = "특정 사용자의 또래 소비 카테고리별 평균 소비 금액을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - @Parameters({@Parameter(name = "userId", description = "로그인 한 유저 아이디"), + @Parameters({ @Parameter(name = "peerAgeStart", description = "또래나이 시작 범위"), @Parameter(name = "peerAgeEnd", description = "또래나이 끝 범위"), @Parameter(name = "peerGender", description = "또래 성별")}) - ApiResponse> getAllConsumptionCategories(Long userId, int peerAgeStart, + ApiResponse> getAllConsumptionCategories(UserDto.AuthUserDto user, + int peerAgeStart, int peerAgeEnd, String peerGender); @Operation(summary = "[User] 또래들이 가장 큰 목표로 세운 카테고리와 그 카테고리에서 이번주 사용한 금액 조회", description = "특정 사용자의 또래 소비 카테고리별 이번주 소비 금액을 조회하는 API 입니다.") @ApiResponses(value = { @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) - ApiResponse getTopCategoryAndConsumptionAmount(@PathVariable Long userId); + ApiResponse getTopCategoryAndConsumptionAmount(UserDto.AuthUserDto user); + + @Operation(summary = "[User] 이번 달 레포트 표정, 멘트 조회 ", description = "특정 사용자의 이번 달 레포트 표정, 멘트를 조회하는 API 입니다.") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) + ApiResponse getMonthReport(UserDto.AuthUserDto user); + + @Operation(summary = "[User] 소비 분석 멘트 생성", description = "특정 사용자의 소비 분석 멘트를 생성 하는 API 입니다.") + @ApiResponses(value = { + @io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "COMMON200", description = "OK, 성공")}) + ApiResponse getConsumptionMention(UserDto.AuthUserDto user) throws ExecutionException, InterruptedException; } \ No newline at end of file diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 9a85ba0c..4424cc9a 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -8,7 +8,6 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -25,6 +24,8 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import lombok.RequiredArgsConstructor; @@ -38,95 +39,107 @@ public class ConsumptionGoalController implements ConsumptionGoalApi { @Override @GetMapping("/categories/top-goals/top-4") public ApiResponse> getTopConsumptionGoalCategories( - @RequestParam(name = "userId") Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart, @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd, @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) { List response = consumptionGoalService.getTopConsumptionGoalCategories( - userId, peerAgeStart, peerAgeEnd, peerGender); + user.getId(), peerAgeStart, peerAgeEnd, peerGender); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/categories/top-goals") public ApiResponse> getAllConsumptionGoalCategories( - @RequestParam(name = "userId") Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart, @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd, @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) { List response = consumptionGoalService.getAllConsumptionGoalCategories( - userId, + user.getId(), peerAgeStart, peerAgeEnd, peerGender); return ApiResponse.onSuccess(response); } @Override @GetMapping("/peer-info") - public ApiResponse getPeerInfo(@RequestParam(name = "userId") Long userId, + public ApiResponse getPeerInfo( + @AuthUser UserDto.AuthUserDto user, @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart, @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd, @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) { - PeerInfoResponseDto response = consumptionGoalService.getPeerInfo(userId, peerAgeStart, peerAgeEnd, peerGender); + PeerInfoResponseDto response = consumptionGoalService.getPeerInfo(user.getId(), peerAgeStart, peerAgeEnd, + peerGender); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/{userId}") public ApiResponse findUserConsumptionGoal( - @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, @PathVariable Long userId) { - - ConsumptionGoalResponseListDto response = consumptionGoalService.findUserConsumptionGoalList(userId, date); + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, + @AuthUser UserDto.AuthUserDto user) { + ConsumptionGoalResponseListDto response = consumptionGoalService.findUserConsumptionGoalList(user.getId(), + date); return ApiResponse.onSuccess(response); } @Override @PostMapping("/{userId}") - public ResponseEntity updateOrElseGenerateConsumptionGoal(@PathVariable Long userId, + public ResponseEntity updateOrElseGenerateConsumptionGoal( + @AuthUser UserDto.AuthUserDto user, @RequestBody ConsumptionGoalListRequestDto consumptionGoalListRequestDto) { - return ResponseEntity.ok() - .body(consumptionGoalService.updateConsumptionGoals(userId, consumptionGoalListRequestDto)); + .body(consumptionGoalService.updateConsumptionGoals(user.getId(), consumptionGoalListRequestDto)); } + @Override @GetMapping("/categories/top-consumptions/top-3") public ApiResponse> getTopConsumptionCategories( - @RequestParam(name = "userId") Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart, @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd, @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) { - List response = consumptionGoalService.getTopConsumptionCategories(userId, + List response = consumptionGoalService.getTopConsumptionCategories(user.getId(), peerAgeStart, peerAgeEnd, peerGender); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/categories/top-consumptions") public ApiResponse> getAllConsumptionCategories( - @RequestParam(name = "userId") Long userId, + @AuthUser UserDto.AuthUserDto user, @RequestParam(name = "peerAgeStart", defaultValue = "0") int peerAgeStart, @RequestParam(name = "peerAgeEnd", defaultValue = "0") int peerAgeEnd, @RequestParam(name = "peerGender", defaultValue = "none") String peerGender) { - List response = consumptionGoalService.getAllConsumptionCategories(userId, + List response = consumptionGoalService.getAllConsumptionCategories( + user.getId(), peerAgeStart, peerAgeEnd, peerGender); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/category/top-goals") public ApiResponse getTopCategoryAndConsumptionAmount( - @RequestParam(name = "userId") Long userId) { - ConsumptionAnalysisResponseDto response = consumptionGoalService.getTopCategoryAndConsumptionAmount(userId); + @AuthUser UserDto.AuthUserDto user) { + ConsumptionAnalysisResponseDto response = consumptionGoalService.getTopCategoryAndConsumptionAmount( + user.getId()); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/facialExpressions") - public ApiResponse getMonthReport(@RequestParam(name = "userId") Long userId) { - MonthReportResponseDto response = consumptionGoalService.getMonthReport(userId); + public ApiResponse getMonthReport( + @AuthUser UserDto.AuthUserDto user) { + MonthReportResponseDto response = consumptionGoalService.getMonthReport(user.getId()); return ApiResponse.onSuccess(response); } + @Override @GetMapping("/consumption-ment") - public ApiResponse getConsumptionMention(@RequestParam(name = "userId") Long userId) throws - ExecutionException, - InterruptedException { - CompletableFuture response = consumptionGoalService.getConsumptionMention(userId); + public ApiResponse getConsumptionMention( + @AuthUser UserDto.AuthUserDto user) throws ExecutionException, InterruptedException { + CompletableFuture response = consumptionGoalService.getConsumptionMention(user.getId()); return ApiResponse.onSuccess(response.get()); } } \ No newline at end of file From bce3d383f850fb78580ec0990663b06e0a54b4f5 Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 29 Oct 2024 15:36:40 +0900 Subject: [PATCH 40/58] =?UTF-8?q?[refactor]=20=20=EC=97=94=EB=93=9C?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/controller/ConsumptionGoalController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 4424cc9a..5dbf5e05 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -128,7 +128,7 @@ public ApiResponse getTopCategoryAndConsumptionA } @Override - @GetMapping("/facialExpressions") + @GetMapping("/month-report") public ApiResponse getMonthReport( @AuthUser UserDto.AuthUserDto user) { MonthReportResponseDto response = consumptionGoalService.getMonthReport(user.getId()); From 3afd8d0378f8295da7877d20b53cbe03b9fb1d2e Mon Sep 17 00:00:00 2001 From: MJJ Date: Tue, 29 Oct 2024 15:40:45 +0900 Subject: [PATCH 41/58] =?UTF-8?q?[refactor]=20=EC=86=8C=EB=B9=84=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=20=EC=A1=B0=ED=9A=8C/=20=EC=9D=B4=EB=B2=88=20?= =?UTF-8?q?=EB=8B=AC=20=EC=86=8C=EB=B9=84=20=EB=AA=A9=ED=91=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20userId=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/controller/ConsumptionGoalController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 5dbf5e05..6a18274e 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -74,7 +74,7 @@ public ApiResponse getPeerInfo( } @Override - @GetMapping("/{userId}") + @GetMapping() public ApiResponse findUserConsumptionGoal( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, @AuthUser UserDto.AuthUserDto user) { @@ -85,7 +85,7 @@ public ApiResponse findUserConsumptionGoal( } @Override - @PostMapping("/{userId}") + @PostMapping() public ResponseEntity updateOrElseGenerateConsumptionGoal( @AuthUser UserDto.AuthUserDto user, @RequestBody ConsumptionGoalListRequestDto consumptionGoalListRequestDto) { From 67d98e2cdfce52b03980d6101e401fee70ef4fab Mon Sep 17 00:00:00 2001 From: JunRain Date: Tue, 29 Oct 2024 21:18:09 +0900 Subject: [PATCH 42/58] =?UTF-8?q?[test]=20ConsumptionGoalServiceImplTest?= =?UTF-8?q?=20=EC=86=8C=EB=B9=84=EB=AA=A9=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalServiceTest.java | 179 +++++------------- 1 file changed, 46 insertions(+), 133 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java index 49346396..0b7dcf3d 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java @@ -18,7 +18,6 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -41,8 +40,6 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseUpdateRequestDto; -import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; @@ -230,10 +227,10 @@ void updateConsumptionGoal_Success() { .category(defaultCategory) .goalMonth(thisMonth) .build(); - given(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, defaultCategory, + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, thisMonth)).willReturn(Optional.ofNullable(defaultCategoryGoal)); - given(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, userCategory, + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, thisMonth)).willReturn(Optional.ofNullable(null)); when(consumptionGoalRepository.saveAll(any())).thenAnswer(invocation -> { @@ -515,166 +512,82 @@ void getAllConsumptionCategories_Success() { } @Test - @DisplayName("지난 달, 이번 달 소비 목표가 없는 카테고리에 대한 소비 업데이트를 진행하는 경우 새로운 소비 목표를 생성해 소비 금액을 갱신") - void recalculateConsumptionAmount_notExistPreviousMonthAndThisMonthGoal() { + void 이번달_사용자_소비목표_조회하기() { // given - Category existGoalCategory = Category.builder().name("유저 카테고리").user(user).isDefault(false).build(); - Category notExistGoalCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").isDefault(true).build()); - given(notExistGoalCategory.getId()).willReturn(-1L); - - Expense expense = Mockito.spy( - Expense.builder().category(existGoalCategory).expenseDate(GOAL_MONTH.atStartOfDay()).amount(1000L).build()); - when(expense.getId()).thenReturn(-1L); - - ExpenseUpdateRequestDto request = ExpenseUpdateRequestDto.builder() - .amount(1000L) - .expenseId(expense.getId()) - .expenseDate(LocalDate.of(2024, 8, 7).atStartOfDay()) - .categoryId(notExistGoalCategory.getId()) - .build(); + Category category = Mockito.spy(Category.builder().name("TEST CATEGORY").user(user).isDefault(false).build()); + LocalDate goalMonth = LocalDate.of(2024, 7, 1); - ConsumptionGoal oldGoal = ConsumptionGoal.builder().consumeAmount(1000L).category(existGoalCategory).build(); - ConsumptionGoal expected = ConsumptionGoal.builder() - .goalMonth(LocalDate.of(2024, 8, 1)) - .goalAmount(0L) - .consumeAmount(1000L) - .category(notExistGoalCategory) + ConsumptionGoal userConsumptionGoal = ConsumptionGoal.builder() + .goalAmount(1_000_000L) + .consumeAmount(200_000L) .user(user) + .category(category) + .goalMonth(goalMonth) .build(); - // when - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, expense.getCategory(), - expense.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn(Optional.ofNullable(oldGoal)); - - when(categoryRepository.findById(request.getCategoryId())).thenReturn(Optional.of(notExistGoalCategory)); - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, notExistGoalCategory, - request.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn(Optional.empty()); - - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, notExistGoalCategory, - request.getExpenseDate().minusMonths(1).toLocalDate().withDayOfMonth(1))).thenReturn(Optional.empty()); - - consumptionGoalService.recalculateConsumptionAmount(expense, request, user); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) + .willReturn(Optional.of(userConsumptionGoal)); - ArgumentCaptor consumptionGoalCaptor = ArgumentCaptor.forClass(ConsumptionGoal.class); - verify(consumptionGoalRepository, times(2)).save(consumptionGoalCaptor.capture()); - - List savedConsumptionGoals = consumptionGoalCaptor.getAllValues(); + // when + ConsumptionGoal result = consumptionGoalService.getUserConsumptionGoal(user, category, goalMonth); // then - assertEquals(oldGoal.getConsumeAmount(), 0L); - assertThat(savedConsumptionGoals.get(1)).usingRecursiveComparison().isEqualTo(expected); + assertEquals(result, userConsumptionGoal); } @Test - @DisplayName("이번달 소비 목표가 없는 카테고리에 대한 소비 업데이트를 진행하는 경우 지난 달 소비 목표의 목표 금액을 복사한 이번 달 소비 목표를 생성해 소비 금액을 갱신") - void recalculateConsumptionAmount_notExistThisMonthGoal() { + void 이번달_소비목표가_없는경우_저번달_기준으로_소비목표_생성() { // given - Category existGoalCategory = Category.builder().name("유저 카테고리").user(user).isDefault(false).build(); - Category notExistThisMonthGoalCategory = Mockito.spy( - Category.builder().name("디폴트 카테고리").isDefault(true).build()); - given(notExistThisMonthGoalCategory.getId()).willReturn(-1L); - - Expense expense = Mockito.spy( - Expense.builder().category(existGoalCategory).expenseDate(GOAL_MONTH.atStartOfDay()).amount(1000L).build()); - when(expense.getId()).thenReturn(-1L); - - ExpenseUpdateRequestDto request = ExpenseUpdateRequestDto.builder() - .amount(1000L) - .expenseId(expense.getId()) - .expenseDate(LocalDate.of(2024, 8, 7).atStartOfDay()) - .categoryId(notExistThisMonthGoalCategory.getId()) - .build(); + Category category = Mockito.spy(Category.builder().name("TEST CATEGORY").user(user).isDefault(false).build()); + LocalDate goalMonth = LocalDate.of(2024, 7, 1); - ConsumptionGoal oldGoal = ConsumptionGoal.builder().consumeAmount(1000L).category(existGoalCategory).build(); - - ConsumptionGoal previousMonthGoal = ConsumptionGoal.builder() - .goalMonth(LocalDate.of(2024, 7, 1)) - .goalAmount(3000L) - .consumeAmount(3000L) - .category(notExistThisMonthGoalCategory) + ConsumptionGoal beforeUserConsumptionGoal = ConsumptionGoal.builder() + .goalAmount(1_000_000L) + .consumeAmount(200_000L) .user(user) + .category(category) + .goalMonth(LocalDate.of(2024, 6, 1)) .build(); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) + .willReturn(Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))) + .willReturn(Optional.of(beforeUserConsumptionGoal)); ConsumptionGoal expected = ConsumptionGoal.builder() - .goalMonth(LocalDate.of(2024, 8, 1)) - .goalAmount(3000L) - .consumeAmount(1000L) - .category(notExistThisMonthGoalCategory) + .goalAmount(1_000_000L) + .consumeAmount(0L) .user(user) + .category(category) + .goalMonth(LocalDate.of(2024, 7, 1)) .build(); - // when - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, expense.getCategory(), - expense.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn(Optional.ofNullable(oldGoal)); - - when(categoryRepository.findById(request.getCategoryId())).thenReturn( - Optional.of(notExistThisMonthGoalCategory)); - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, - notExistThisMonthGoalCategory, request.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn( - Optional.empty()); - - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, - notExistThisMonthGoalCategory, - request.getExpenseDate().minusMonths(1).toLocalDate().withDayOfMonth(1))).thenReturn( - Optional.ofNullable(previousMonthGoal)); - - consumptionGoalService.recalculateConsumptionAmount(expense, request, user); - - ArgumentCaptor consumptionGoalCaptor = ArgumentCaptor.forClass(ConsumptionGoal.class); - verify(consumptionGoalRepository, times(2)).save(consumptionGoalCaptor.capture()); - - List savedConsumptionGoals = consumptionGoalCaptor.getAllValues(); + ConsumptionGoal result = consumptionGoalService.getUserConsumptionGoal(user, category, goalMonth); // then - assertEquals(oldGoal.getConsumeAmount(), 0L); - assertThat(savedConsumptionGoals.get(1)).usingRecursiveComparison().isEqualTo(expected); + assertThat(result).usingRecursiveComparison().isEqualTo(expected); } @Test - @DisplayName("이번달 소비 목표가 있는 경우 이번 달 소비 목표의 소비 금액을 갱신") - void recalculateConsumptionAmount_existThisMonthGoal() { + void 이번달_저번달_소비목표가_없는경우_소비목표를_새로_생성() { // given - Category existGoalCategory = Mockito.spy( - Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); - given(existGoalCategory.getId()).willReturn(-1L); - - Expense expense = Mockito.spy( - Expense.builder().category(existGoalCategory).expenseDate(GOAL_MONTH.atStartOfDay()).amount(1000L).build()); - when(expense.getId()).thenReturn(-1L); - - ExpenseUpdateRequestDto request = ExpenseUpdateRequestDto.builder() - .amount(2000L) - .expenseId(expense.getId()) - .expenseDate(LocalDate.of(2024, 8, 7).atStartOfDay()) - .categoryId(existGoalCategory.getId()) - .build(); + Category category = Mockito.spy(Category.builder().name("TEST CATEGORY").user(user).isDefault(false).build()); + LocalDate goalMonth = LocalDate.of(2024, 7, 1); - ConsumptionGoal oldGoal = ConsumptionGoal.builder() - .goalMonth(LocalDate.of(2024, 8, 1)) - .goalAmount(3000L) - .consumeAmount(1000L) - .category(existGoalCategory) - .user(user) - .build(); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) + .willReturn(Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))) + .willReturn(Optional.empty()); ConsumptionGoal expected = ConsumptionGoal.builder() - .goalMonth(LocalDate.of(2024, 8, 1)) - .goalAmount(3000L) - .consumeAmount(2000L) - .category(existGoalCategory) + .goalAmount(0L) + .consumeAmount(0L) .user(user) + .category(category) + .goalMonth(LocalDate.of(2024, 7, 1)) .build(); - // when - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, expense.getCategory(), - expense.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn(Optional.ofNullable(oldGoal)); - - when(categoryRepository.findById(request.getCategoryId())).thenReturn(Optional.of(existGoalCategory)); - when(consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, existGoalCategory, - request.getExpenseDate().toLocalDate().withDayOfMonth(1))).thenReturn(Optional.ofNullable(oldGoal)); - - consumptionGoalService.recalculateConsumptionAmount(expense, request, user); + ConsumptionGoal result = consumptionGoalService.getUserConsumptionGoal(user, category, goalMonth); // then - assertThat(oldGoal).usingRecursiveComparison().isEqualTo(expected); + assertThat(result).usingRecursiveComparison().isEqualTo(expected); } } \ No newline at end of file From d13c04815d5234c4504d8c5de41a1cfe3b157cc4 Mon Sep 17 00:00:00 2001 From: JunRain Date: Tue, 29 Oct 2024 21:25:42 +0900 Subject: [PATCH 43/58] =?UTF-8?q?[test]=20ExpenseServiceImplTest=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ExpenseServiceImplTest.java | 62 +++++++++---------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java index fd1a8d5f..3de8bbed 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/expense/service/ExpenseServiceImplTest.java @@ -24,7 +24,7 @@ import com.bbteam.budgetbuddies.domain.expense.converter.ExpenseConverter; import com.bbteam.budgetbuddies.domain.expense.dto.CompactExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.DailyExpenseResponseDto; -import com.bbteam.budgetbuddies.domain.expense.dto.ExpenseResponseDto; +import com.bbteam.budgetbuddies.domain.expense.dto.DetailExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.dto.MonthlyExpenseResponseDto; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; @@ -79,32 +79,29 @@ private MonthlyExpenseResponseDto getExpectedMonthlyExpense(Category userCategor return MonthlyExpenseResponseDto.builder() .expenseMonth(LocalDate.of(2024, 7, 1)) .totalConsumptionAmount(300_000L) - .dailyExpenses(List.of(DailyExpenseResponseDto.builder() - .daysOfMonth(2) - .daysOfTheWeek("화요일") - .expenses(List.of(CompactExpenseResponseDto.builder() - .amount(200_000L) - .description("User 소비") - .expenseId(-2L) - .categoryId(userCategory.getId()) - .build())) - .build(), DailyExpenseResponseDto.builder() - .daysOfMonth(1) - .daysOfTheWeek("월요일") - .expenses(List.of(CompactExpenseResponseDto.builder() - .amount(100_000L) - .description("User 소비") - .expenseId(-1L) - .categoryId(userCategory.getId()) - .build())) - .build())) + .dailyExpenses( + List.of( + DailyExpenseResponseDto.builder() + .daysOfMonth(2) + .daysOfTheWeek("화요일") + .expenses(List.of(CompactExpenseResponseDto.builder() + .amount(200_000L) + .description("User 소비") + .expenseId(-2L) + .categoryId(userCategory.getId()) + .build())) + .build(), + DailyExpenseResponseDto.builder() + .daysOfMonth(1) + .daysOfTheWeek("월요일") + .expenses(List.of(CompactExpenseResponseDto.builder() + .amount(100_000L) + .description("User 소비") + .expenseId(-1L) + .categoryId(userCategory.getId()) + .build())) + .build())) .build(); - - // when - MonthlyExpenseResponseDto result = expenseService.getMonthlyExpense(user.getId(), requestMonth); - - // then - assertThat(result).usingRecursiveComparison().isEqualTo(expected); } private List generateExpenseList(LocalDate month, User user, Category userCategory) { @@ -130,8 +127,7 @@ private List generateExpenseList(LocalDate month, User user, Category u } @Test - @DisplayName("findExpenseFromUserIdAndExpenseId : 성공") - void findExpenseResponseFromUserIdAndExpenseId_Success() { + void 소비상세조회_성공() { // given final Long expenseId = -1L; @@ -142,8 +138,7 @@ void findExpenseResponseFromUserIdAndExpenseId_Success() { given(expense.getId()).willReturn(expenseId); given(expenseRepository.findById(expense.getId())).willReturn(Optional.of(expense)); - ExpenseResponseDto expected = ExpenseResponseDto.builder() - .userId(user.getId()) + DetailExpenseResponseDto expected = DetailExpenseResponseDto.builder() .expenseId(-1L) .description("유저 소비") .categoryName("유저 카테고리") @@ -151,15 +146,14 @@ void findExpenseResponseFromUserIdAndExpenseId_Success() { .build(); // when - ExpenseResponseDto result = expenseService.findExpenseResponseFromUserIdAndExpenseId(user.getId(), expenseId); + DetailExpenseResponseDto result = expenseService.findDetailExpenseResponse(user.getId(), expenseId); // then assertThat(result).usingRecursiveComparison().isEqualTo(expected); } @Test - @DisplayName("findExpenseFromUserIdAndExpenseId : 소비 유저와 다른 유저로 인한 예외 반환") - void findExpenseResponseFromUserIdAndExpenseId_Fail() { + void 조회_권한이_없는_유저의_소비조회로_인한_예외_반환() { // given final Long expenseId = -1L; @@ -171,6 +165,6 @@ void findExpenseResponseFromUserIdAndExpenseId_Fail() { // then assertThrows(IllegalArgumentException.class, - () -> expenseService.findExpenseResponseFromUserIdAndExpenseId(-2L, expenseId)); + () -> expenseService.findDetailExpenseResponse(-2L, expenseId)); } } \ No newline at end of file From c5e071b3f06072a1a677b6f329794a93b012a3a8 Mon Sep 17 00:00:00 2001 From: JunRain Date: Wed, 30 Oct 2024 22:17:45 +0900 Subject: [PATCH 44/58] =?UTF-8?q?[refactor]=20ConsumptionGoalController=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=86=8C=EB=B9=84=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20@AuthUser=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/controller/ConsumptionGoalApi.java | 3 ++- .../controller/ConsumptionGoalController.java | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java index 69094dbc..abdda415 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java @@ -14,6 +14,7 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.PeerInfoResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -53,7 +54,7 @@ ApiResponse> getAllConsumptionGoalCatego @Operation(summary = "[User] 소비 목표 조회", description = "date={yyyy-MM-dd} 형식의 query string을 통해서 사용자의 목표 달을 조회하는 API 입니다.") @Parameters({@Parameter(name = "date", description = "yyyy-MM-dd 형식으로 목표 달의 소비를 조회")}) - ApiResponse findUserConsumptionGoal(LocalDate date, Long userId); + ApiResponse findUserConsumptionGoal(LocalDate date, UserDto.AuthUserDto user); @Operation(summary = "[User] 이번 달 소비 목표 수정", description = "다른 달의 소비 목표를 업데이트하는 것은 불가능하고 오직 이번 달의 소비 목표만 업데이트 하는 API 입니다.") ResponseEntity updateOrElseGenerateConsumptionGoal(Long userId, diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index 4a75809d..aec1b5a2 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -23,6 +23,8 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopCategoryConsumptionDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.TopGoalCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; +import com.bbteam.budgetbuddies.domain.user.dto.UserDto; +import com.bbteam.budgetbuddies.global.security.utils.AuthUser; import lombok.RequiredArgsConstructor; @@ -67,13 +69,11 @@ public ApiResponse getPeerInfo(@RequestParam(name = "userId return ApiResponse.onSuccess(response); } - @GetMapping("/{userId}") + @GetMapping() public ApiResponse findUserConsumptionGoal( - @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, @PathVariable Long userId) { + @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date, @AuthUser UserDto.AuthUserDto user) { - ConsumptionGoalResponseListDto response = consumptionGoalService.findUserConsumptionGoalList(userId, date); - - return ApiResponse.onSuccess(response); + return ApiResponse.onSuccess(consumptionGoalService.findUserConsumptionGoalList(user.getId(), date)); } @Override From a7dca1017be57ba15b2f519270607259893f11b6 Mon Sep 17 00:00:00 2001 From: JunRain Date: Wed, 30 Oct 2024 22:19:25 +0900 Subject: [PATCH 45/58] =?UTF-8?q?[feat]=20CategoryService=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20Category=20=EC=97=94=ED=8B=B0=ED=8B=B0=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/category/service/CategoryService.java | 2 ++ .../domain/category/service/CategoryServiceImpl.java | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java index 675d1581..0a75b0c9 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryService.java @@ -17,5 +17,7 @@ public interface CategoryService { void deleteCategory(Long id, Long userId); Category getCategory(Long categoryId); + + List getUserCategoryList(Long userId); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java index c8dab75f..49126290 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java @@ -154,4 +154,8 @@ public void deleteCategory(Long categoryId, Long userId) { }); } + @Override + public List getUserCategoryList(Long userId) { + return categoryRepository.findUserCategoryByUserId(userId); + } } \ No newline at end of file From 293c6a64b784591b0651351fc1ed07057a80241a Mon Sep 17 00:00:00 2001 From: JunRain Date: Wed, 30 Oct 2024 22:22:20 +0900 Subject: [PATCH 46/58] =?UTF-8?q?[refactor]=20ConsumptionGoalService=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=86=8C=EB=B9=84=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JPA 쿼리 관련 최적화를 진행해야할 것 같음. 모든 카테고리에 대한 이번달 저번달 소비목표가 없는 경우 2N(카테고리 수)만큼 쿼리문이 나가게 된다. --- .../converter/ConsumptionGoalConverter.java | 34 ++++--------- .../service/ConsumptionGoalServiceImpl.java | 50 ++++--------------- 2 files changed, 22 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java index 5cd7a72a..44c0dd08 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/converter/ConsumptionGoalConverter.java @@ -1,11 +1,11 @@ package com.bbteam.budgetbuddies.domain.consumptiongoal.converter; import java.time.LocalDate; +import java.util.Comparator; import java.util.List; import org.springframework.stereotype.Component; -import com.bbteam.budgetbuddies.domain.category.entity.Category; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionAnalysisResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto; @@ -17,15 +17,6 @@ @Component public class ConsumptionGoalConverter { - public ConsumptionGoalResponseDto toConsumptionGoalResponseDto(Category category) { - return ConsumptionGoalResponseDto.builder() - .categoryName(category.getName()) - .categoryId(category.getId()) - .goalAmount(0L) - .consumeAmount(0L) - .build(); - } - public ConsumptionGoalResponseDto toConsumptionGoalResponseDto(ConsumptionGoal consumptionGoal) { return ConsumptionGoalResponseDto.builder() .categoryName(consumptionGoal.getCategory().getName()) @@ -35,27 +26,24 @@ public ConsumptionGoalResponseDto toConsumptionGoalResponseDto(ConsumptionGoal c .build(); } - public ConsumptionGoalResponseDto toConsumptionGoalResponseDtoFromPreviousGoal(ConsumptionGoal consumptionGoal) { - return ConsumptionGoalResponseDto.builder() - .categoryName(consumptionGoal.getCategory().getName()) - .categoryId(consumptionGoal.getCategory().getId()) - .goalAmount(consumptionGoal.getGoalAmount()) - .consumeAmount(0L) - .build(); + public ConsumptionGoalResponseListDto toConsumptionGoalResponseListDto( + List consumptionGoalList, LocalDate goalMonth) { - } + List consumptionGoalResponseList = consumptionGoalList + .stream() + .map(this::toConsumptionGoalResponseDto) + .sorted(Comparator.comparingLong(ConsumptionGoalResponseDto::getRemainingBalance).reversed()) + .toList(); - public ConsumptionGoalResponseListDto toConsumptionGoalResponseListDto( - List consumptionGoalList, LocalDate goalMonth) { - Long totalGoalAmount = sumTotalGoalAmount(consumptionGoalList); - Long totalConsumptionAmount = sumTotalConsumptionAmount(consumptionGoalList); + Long totalGoalAmount = sumTotalGoalAmount(consumptionGoalResponseList); + Long totalConsumptionAmount = sumTotalConsumptionAmount(consumptionGoalResponseList); return ConsumptionGoalResponseListDto.builder() .goalMonth(goalMonth) .totalGoalAmount(totalGoalAmount) .totalConsumptionAmount(totalConsumptionAmount) .totalRemainingBalance(totalGoalAmount - totalConsumptionAmount) - .consumptionGoalList(consumptionGoalList) + .consumptionGoalList(consumptionGoalResponseList) .build(); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index 67d681ce..c7ff3991 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -25,6 +25,7 @@ import com.bbteam.budgetbuddies.domain.category.entity.Category; import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository; +import com.bbteam.budgetbuddies.domain.category.service.CategoryService; import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.ConsumptionGoalConverter; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AllConsumptionCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto; @@ -47,6 +48,7 @@ import com.bbteam.budgetbuddies.domain.openai.service.OpenAiService; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; +import com.bbteam.budgetbuddies.domain.user.service.UserService; import com.bbteam.budgetbuddies.enums.Gender; import lombok.RequiredArgsConstructor; @@ -60,7 +62,9 @@ public class ConsumptionGoalServiceImpl implements ConsumptionGoalService { private final ConsumptionGoalRepository consumptionGoalRepository; private final ExpenseRepository expenseRepository; private final CategoryRepository categoryRepository; + private final CategoryService categoryService; private final UserRepository userRepository; + private final UserService userService; private final GeminiService geminiService; private final OpenAiService openAiService; @@ -506,50 +510,18 @@ private ConsumptionGoal generateNewConsumptionGoal(User user, Category category, } @Override - @Transactional(readOnly = true) + @Transactional public ConsumptionGoalResponseListDto findUserConsumptionGoalList(Long userId, LocalDate date) { LocalDate goalMonth = date.withDayOfMonth(1); - Map goalMap = initializeGoalMap(userId); - - updateGoalMapWithPrevious(userId, goalMonth, goalMap); - updateGoalMapWithCurrentMonth(userId, goalMonth, goalMap); - - List consumptionGoalList = new ArrayList<>(goalMap.values()); - - return consumptionGoalConverter.toConsumptionGoalResponseListDto( - orderByRemainingBalanceDescending(consumptionGoalList), goalMonth); - } - - private Map initializeGoalMap(Long userId) { - return categoryRepository.findUserCategoryByUserId(userId) - .stream() - .collect(Collectors.toMap(Category::getId, consumptionGoalConverter::toConsumptionGoalResponseDto)); - } - - private void updateGoalMapWithPrevious(Long userId, LocalDate goalMonth, - Map goalMap) { - goalMap.keySet() - .stream() - .map(categoryId -> consumptionGoalRepository.findLatelyGoal(userId, categoryId, goalMonth.minusMonths(1))) - .filter(Optional::isPresent) - .map(Optional::get) - .map(consumptionGoalConverter::toConsumptionGoalResponseDtoFromPreviousGoal) - .forEach(goal -> goalMap.put(goal.getCategoryId(), goal)); - } + User user = userService.getUser(userId); + List categoryList = categoryService.getUserCategoryList(userId); - private void updateGoalMapWithCurrentMonth(Long userId, LocalDate goalMonth, - Map goalMap) { - consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(userId, goalMonth) + List thisMonthUserConsumptionGoal = categoryList .stream() - .map(consumptionGoalConverter::toConsumptionGoalResponseDto) - .forEach(goal -> goalMap.put(goal.getCategoryId(), goal)); - } - - private List orderByRemainingBalanceDescending( - List consumptionGoalList) { - return consumptionGoalList.stream() - .sorted(Comparator.comparingLong(ConsumptionGoalResponseDto::getRemainingBalance).reversed()) + .map(category -> this.getUserConsumptionGoal(user, category, goalMonth)) .toList(); + + return consumptionGoalConverter.toConsumptionGoalResponseListDto(thisMonthUserConsumptionGoal, goalMonth); } @Override From 218a2cfde1c3cc8a0837aefc47348e278c64bbb2 Mon Sep 17 00:00:00 2001 From: JunRain Date: Wed, 30 Oct 2024 22:24:51 +0900 Subject: [PATCH 47/58] =?UTF-8?q?[test]=20ConsumptionGoalServiceTest=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=86=8C=EB=B9=84=EB=AA=A9?= =?UTF-8?q?=ED=91=9C=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalServiceTest.java | 125 ++++++++---------- 1 file changed, 58 insertions(+), 67 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java index 0b7dcf3d..06e585eb 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.NoSuchElementException; import java.util.Optional; -import java.util.Random; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -26,6 +25,7 @@ import com.bbteam.budgetbuddies.domain.category.entity.Category; import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository; +import com.bbteam.budgetbuddies.domain.category.service.CategoryService; import com.bbteam.budgetbuddies.domain.consumptiongoal.converter.ConsumptionGoalConverter; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AllConsumptionCategoryResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.AvgConsumptionGoalDto; @@ -43,15 +43,15 @@ import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; +import com.bbteam.budgetbuddies.domain.user.service.UserService; import com.bbteam.budgetbuddies.enums.Gender; @DisplayName("ConsumptionGoalImpl 서비스 테스트의 ") @ExtendWith(MockitoExtension.class) class ConsumptionGoalServiceTest { - private final LocalDate GOAL_MONTH = LocalDate.of(2024, 07, 01); private final LocalDate currentMonth = LocalDate.now().withDayOfMonth(1); private User user; - private LocalDate goalMonthRandomDay; + private LocalDate requestMonth; @InjectMocks private ConsumptionGoalServiceImpl consumptionGoalService; @Mock @@ -59,17 +59,19 @@ class ConsumptionGoalServiceTest { @Mock private CategoryRepository categoryRepository; @Mock + private CategoryService categoryService; + @Mock private UserRepository userRepository; @Mock + private UserService userService; + @Mock private ExpenseRepository expenseRepository; @Spy private ConsumptionGoalConverter consumptionGoalConverter; @BeforeEach void setUp() { - Random random = new Random(); - int randomDay = random.nextInt(30) + 1; - goalMonthRandomDay = LocalDate.of(GOAL_MONTH.getYear(), GOAL_MONTH.getMonth(), randomDay); + requestMonth = LocalDate.of(2024, 7, 15); user = Mockito.spy(User.builder() .email("email") @@ -81,26 +83,22 @@ void setUp() { } @Test - @DisplayName("findUserConsumptionGoal : 생성된 ConsumptionGoal이 없고 카테고리만 있는 경우 목표 금액, 소비 금액 0으로 초기화") - void findUserConsumptionGoal_onlyCategory() { + void 유저소비목표조회시_이번달_이전달_소비목표가_없는_경우_소비목표를_새로_생성() { // given Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build()); given(defaultCategory.getId()).willReturn(-1L); - Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); given(userCategory.getId()).willReturn(-2L); - List categoryList = List.of(defaultCategory, userCategory); + given(categoryService.getUserCategoryList(user.getId())).willReturn(List.of(defaultCategory, userCategory)); List expected = List.of( new ConsumptionGoalResponseDto(defaultCategory.getName(), defaultCategory.getId(), 0L, 0L), new ConsumptionGoalResponseDto(userCategory.getName(), userCategory.getId(), 0L, 0L)); // when - when(categoryRepository.findUserCategoryByUserId(user.getId())).thenReturn(categoryList); - ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoalList(user.getId(), - goalMonthRandomDay); + requestMonth); // then assertThat(result.getConsumptionGoalList()).usingRecursiveComparison().isEqualTo(expected); @@ -108,94 +106,87 @@ void findUserConsumptionGoal_onlyCategory() { } @Test - @DisplayName("findUserConsumptionGoal : 한달전 ConsumptionGoal만 있을 경우 한달전으로 초기화") - void findUserConsumptionGoal_previousMonth() { + void 소비목표조회시_지난달_소비목표만_존재할시_지난달_기준으로_소비목표를_생성() { // given Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build()); given(defaultCategory.getId()).willReturn(-1L); - Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); given(userCategory.getId()).willReturn(-2L); - given(categoryRepository.findUserCategoryByUserId(user.getId())).willReturn( - List.of(defaultCategory, userCategory)); + given(categoryService.getUserCategoryList(user.getId())).willReturn(List.of(defaultCategory, userCategory)); + given(userService.getUser(user.getId())).willReturn(user); ConsumptionGoal previousMonthDefaultCategoryGoal = ConsumptionGoal.builder() .goalAmount(1_000_000L) .consumeAmount(200_000L) .user(user) .category(defaultCategory) - .goalMonth(goalMonthRandomDay.minusMonths(1)) + .goalMonth(requestMonth.withDayOfMonth(1).minusMonths(1)) .build(); - Long previousMonthDefaultGoalRemainingBalance = - previousMonthDefaultCategoryGoal.getGoalAmount() - previousMonthDefaultCategoryGoal.getConsumeAmount(); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, + requestMonth.withDayOfMonth(1))).willReturn(Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, + requestMonth.withDayOfMonth(1).minusMonths(1))).willReturn(Optional.of(previousMonthDefaultCategoryGoal)); ConsumptionGoal previousMonthUserCategoryGoal = ConsumptionGoal.builder() .goalAmount(1_000_000L) .consumeAmount(20_000L) .user(user) .category(userCategory) - .goalMonth(goalMonthRandomDay.minusMonths(1)) + .goalMonth(requestMonth.withDayOfMonth(1).minusMonths(1)) .build(); - Long previousMonthUseGoalRemainingBalance = - previousMonthUserCategoryGoal.getGoalAmount() - previousMonthUserCategoryGoal.getConsumeAmount(); - - List previousGoalList = List.of(previousMonthDefaultCategoryGoal, - previousMonthUserCategoryGoal); - - List expected = List.of( - consumptionGoalConverter.toConsumptionGoalResponseDto(previousMonthUserCategoryGoal), - consumptionGoalConverter.toConsumptionGoalResponseDto(previousMonthDefaultCategoryGoal)); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, + requestMonth.withDayOfMonth(1))).willReturn(Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, + requestMonth.withDayOfMonth(1).minusMonths(1))).willReturn(Optional.of(previousMonthUserCategoryGoal)); // when - when(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(), - GOAL_MONTH.minusMonths(1))).thenReturn(previousGoalList); - ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoalList(user.getId(), - goalMonthRandomDay); + requestMonth); // then - assertThat(result.getConsumptionGoalList()).usingRecursiveComparison().isEqualTo(expected); - assertEquals(result.getTotalRemainingBalance(), - previousMonthDefaultGoalRemainingBalance + previousMonthUseGoalRemainingBalance); + assertThat(result.getTotalRemainingBalance()).isEqualTo(2_000_000L); + assertThat(result.getTotalConsumptionAmount()).isEqualTo(0L); } @Test - @DisplayName("findUserConsumptionGoal : 한달 전과 목표 달 ConsumptionGoal이 있을 경우 목표 달로 초기화") - void findUserConsumptionGoal_previousMonthAndGoalMonth() { + void 소비목표_조회시_이번달_소비목표가_존재하는_경우_이번달_소비목표를_반환() { // given + Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build()); + given(defaultCategory.getId()).willReturn(-1L); Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); given(userCategory.getId()).willReturn(-2L); - ConsumptionGoal previousMonthUserCategoryGoal = ConsumptionGoal.builder() + given(categoryService.getUserCategoryList(user.getId())).willReturn(List.of(defaultCategory, userCategory)); + given(userService.getUser(user.getId())).willReturn(user); + + ConsumptionGoal thisMonthDefaultCategoryGoal = ConsumptionGoal.builder() .goalAmount(1_000_000L) - .consumeAmount(20_000L) + .consumeAmount(200_000L) .user(user) - .category(userCategory) - .goalMonth(goalMonthRandomDay.minusMonths(1)) + .category(defaultCategory) + .goalMonth(requestMonth.withDayOfMonth(1)) .build(); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, + requestMonth.withDayOfMonth(1))).willReturn(Optional.of(thisMonthDefaultCategoryGoal)); - ConsumptionGoal goalMonthUserCategoryGoal = ConsumptionGoal.builder() - .goalAmount(2_000_000L) - .consumeAmount(30_000L) + ConsumptionGoal thisMonthUserCategoryGoal = ConsumptionGoal.builder() + .goalAmount(1_000_000L) + .consumeAmount(20_000L) .user(user) .category(userCategory) - .goalMonth(goalMonthRandomDay) + .goalMonth(requestMonth.withDayOfMonth(1)) .build(); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, + requestMonth.withDayOfMonth(1))).willReturn(Optional.of(thisMonthUserCategoryGoal)); // when - when(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(), - GOAL_MONTH.minusMonths(1))).thenReturn(List.of(previousMonthUserCategoryGoal)); - - when(consumptionGoalRepository.findConsumptionGoalByUserIdAndGoalMonth(user.getId(), GOAL_MONTH)).thenReturn( - List.of(goalMonthUserCategoryGoal)); - ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoalList(user.getId(), - goalMonthRandomDay); + requestMonth); // then - assertThat(result.getConsumptionGoalList()).usingRecursiveComparison() - .isEqualTo(List.of(consumptionGoalConverter.toConsumptionGoalResponseDto(goalMonthUserCategoryGoal))); + assertThat(result.getTotalRemainingBalance()).isEqualTo(1_780_000L); + assertThat(result.getTotalConsumptionAmount()).isEqualTo(220_000L); } @Test @@ -524,8 +515,8 @@ void getAllConsumptionCategories_Success() { .category(category) .goalMonth(goalMonth) .build(); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) - .willReturn(Optional.of(userConsumptionGoal)); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)).willReturn( + Optional.of(userConsumptionGoal)); // when ConsumptionGoal result = consumptionGoalService.getUserConsumptionGoal(user, category, goalMonth); @@ -547,10 +538,10 @@ void getAllConsumptionCategories_Success() { .category(category) .goalMonth(LocalDate.of(2024, 6, 1)) .build(); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) - .willReturn(Optional.empty()); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))) - .willReturn(Optional.of(beforeUserConsumptionGoal)); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)).willReturn( + Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, + goalMonth.minusMonths(1))).willReturn(Optional.of(beforeUserConsumptionGoal)); ConsumptionGoal expected = ConsumptionGoal.builder() .goalAmount(1_000_000L) @@ -572,10 +563,10 @@ void getAllConsumptionCategories_Success() { Category category = Mockito.spy(Category.builder().name("TEST CATEGORY").user(user).isDefault(false).build()); LocalDate goalMonth = LocalDate.of(2024, 7, 1); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)) - .willReturn(Optional.empty()); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))) - .willReturn(Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth)).willReturn( + Optional.empty()); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, + goalMonth.minusMonths(1))).willReturn(Optional.empty()); ConsumptionGoal expected = ConsumptionGoal.builder() .goalAmount(0L) From 629b8de916efc3c0f6019ba39f8d47b43f369bd7 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 31 Oct 2024 20:49:45 +0900 Subject: [PATCH 48/58] =?UTF-8?q?[fix]=20CategoryService=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20ConsumptionG?= =?UTF-8?q?oalService=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=EB=A1=9C=20=EC=88=9C=ED=99=98=EC=B0=B8=EC=A1=B0=20=EB=B0=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/category/service/CategoryServiceImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java index 49126290..7a010856 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/category/service/CategoryServiceImpl.java @@ -15,7 +15,6 @@ import com.bbteam.budgetbuddies.domain.category.repository.CategoryRepository; import com.bbteam.budgetbuddies.domain.consumptiongoal.entity.ConsumptionGoal; import com.bbteam.budgetbuddies.domain.consumptiongoal.repository.ConsumptionGoalRepository; -import com.bbteam.budgetbuddies.domain.consumptiongoal.service.ConsumptionGoalService; import com.bbteam.budgetbuddies.domain.expense.entity.Expense; import com.bbteam.budgetbuddies.domain.expense.repository.ExpenseRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; @@ -29,7 +28,6 @@ public class CategoryServiceImpl implements CategoryService { private final CategoryRepository categoryRepository; - private final ConsumptionGoalService consumptionGoalService; private final UserRepository userRepository; private final CategoryConverter categoryConverter; private final ConsumptionGoalRepository consumptionGoalRepository; From 4bec92dc9e2c2e4c87217c2a825cc17eb199ff17 Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 31 Oct 2024 20:52:02 +0900 Subject: [PATCH 49/58] =?UTF-8?q?[refactor]=20ConsumptionGoalController=20?= =?UTF-8?q?=EC=86=8C=EB=B9=84=EB=AA=A9=ED=91=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20@AuthUser=EB=A5=BC=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?User=20=EC=A3=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../consumptiongoal/controller/ConsumptionGoalApi.java | 2 +- .../controller/ConsumptionGoalController.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java index abdda415..09d38867 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalApi.java @@ -57,7 +57,7 @@ ApiResponse> getAllConsumptionGoalCatego ApiResponse findUserConsumptionGoal(LocalDate date, UserDto.AuthUserDto user); @Operation(summary = "[User] 이번 달 소비 목표 수정", description = "다른 달의 소비 목표를 업데이트하는 것은 불가능하고 오직 이번 달의 소비 목표만 업데이트 하는 API 입니다.") - ResponseEntity updateOrElseGenerateConsumptionGoal(Long userId, + ResponseEntity updateOrElseGenerateConsumptionGoal(UserDto.AuthUserDto user, ConsumptionGoalListRequestDto consumptionGoalListRequestDto); @Operation(summary = "[User] 또래들이 가장 많이한 소비 카테고리 조회 Top3", description = "특정 사용자의 또래 소비 카테고리별 소비 건 수을 조회하는 API 입니다.") diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java index aec1b5a2..b65b5904 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/controller/ConsumptionGoalController.java @@ -6,7 +6,6 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -77,12 +76,13 @@ public ApiResponse findUserConsumptionGoal( } @Override - @PostMapping("/{userId}") - public ResponseEntity updateOrElseGenerateConsumptionGoal(@PathVariable Long userId, + @PostMapping() + public ResponseEntity updateOrElseGenerateConsumptionGoal( + @AuthUser UserDto.AuthUserDto user, @RequestBody ConsumptionGoalListRequestDto consumptionGoalListRequestDto) { return ResponseEntity.ok() - .body(consumptionGoalService.updateConsumptionGoals(userId, consumptionGoalListRequestDto)); + .body(consumptionGoalService.updateConsumptionGoals(user.getId(), consumptionGoalListRequestDto)); } @GetMapping("/categories/top-consumptions/top-3") From de0f89013ab4bcd6ff08d1549e225dfc0c75213b Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 31 Oct 2024 20:53:41 +0900 Subject: [PATCH 50/58] =?UTF-8?q?[refactor]=20ConsumptionGoalService=20?= =?UTF-8?q?=EC=86=8C=EB=B9=84=EB=AA=A9=ED=91=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EA=B5=AC=EC=A1=B0=20?= =?UTF-8?q?=EB=B3=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalServiceImpl.java | 45 +++++++------------ 1 file changed, 17 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java index c7ff3991..6bc6b4da 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceImpl.java @@ -34,7 +34,6 @@ import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionAnalysisResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalListRequestDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalRequestDto; -import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.ConsumptionGoalResponseListDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MonthReportResponseDto; import com.bbteam.budgetbuddies.domain.consumptiongoal.dto.MyConsumptionGoalDto; @@ -467,48 +466,27 @@ private double calculateMedian(List values) { public ConsumptionGoalResponseListDto updateConsumptionGoals(Long userId, ConsumptionGoalListRequestDto consumptionGoalListRequestDto) { LocalDate thisMonth = LocalDate.now().withDayOfMonth(1); - User user = userRepository.findById(userId).orElseThrow(() -> new IllegalArgumentException("Not found user")); + User user = userService.getUser(userId); List updatedConsumptionGoal = consumptionGoalListRequestDto.getConsumptionGoalList() .stream() .map(c -> updateConsumptionGoalWithRequestDto(user, c, thisMonth)) .toList(); - List response = consumptionGoalRepository.saveAll(updatedConsumptionGoal) - .stream() - .map(consumptionGoalConverter::toConsumptionGoalResponseDto) - .toList(); - - return consumptionGoalConverter.toConsumptionGoalResponseListDto(response, thisMonth); + return consumptionGoalConverter.toConsumptionGoalResponseListDto(updatedConsumptionGoal, thisMonth); } private ConsumptionGoal updateConsumptionGoalWithRequestDto(User user, ConsumptionGoalRequestDto consumptionGoalRequestDto, LocalDate goalMonth) { - Category category = categoryRepository.findById(consumptionGoalRequestDto.getCategoryId()) - .orElseThrow(() -> new IllegalArgumentException("Not found Category")); + Category category = categoryService.getCategory(consumptionGoalRequestDto.getCategoryId()); - ConsumptionGoal consumptionGoal = findOrElseGenerateConsumptionGoal(user, category, goalMonth); + ConsumptionGoal consumptionGoal = this.getUserConsumptionGoal(user, category, goalMonth); consumptionGoal.updateGoalAmount(consumptionGoalRequestDto.getGoalAmount()); return consumptionGoal; } - private ConsumptionGoal findOrElseGenerateConsumptionGoal(User user, Category category, LocalDate goalMonth) { - return consumptionGoalRepository.findConsumptionGoalByUserAndCategoryAndGoalMonth(user, category, goalMonth) - .orElseGet(() -> generateNewConsumptionGoal(user, category, goalMonth)); - } - - private ConsumptionGoal generateNewConsumptionGoal(User user, Category category, LocalDate goalMonth) { - return ConsumptionGoal.builder() - .goalMonth(goalMonth) - .user(user) - .category(category) - .consumeAmount(0L) - .goalAmount(0L) - .build(); - } - @Override @Transactional public ConsumptionGoalResponseListDto findUserConsumptionGoalList(Long userId, LocalDate date) { @@ -821,12 +799,23 @@ private ConsumptionGoal generateGoalFromPreviousOrNew(User user, Category catego } private ConsumptionGoal generateGoalByPrevious(ConsumptionGoal consumptionGoal) { - return ConsumptionGoal.builder() + return consumptionGoalRepository.save(ConsumptionGoal.builder() .goalMonth(consumptionGoal.getGoalMonth().plusMonths(1)) .user(consumptionGoal.getUser()) .category(consumptionGoal.getCategory()) .consumeAmount(0L) .goalAmount(consumptionGoal.getGoalAmount()) - .build(); + .build()); } + + private ConsumptionGoal generateNewConsumptionGoal(User user, Category category, LocalDate goalMonth) { + return consumptionGoalRepository.save(ConsumptionGoal.builder() + .goalMonth(goalMonth) + .user(user) + .category(category) + .consumeAmount(0L) + .goalAmount(0L) + .build()); + } + } \ No newline at end of file From 265c0e5af2cbd5cf35ca072dc210642d2fc0df3b Mon Sep 17 00:00:00 2001 From: JunRain Date: Thu, 31 Oct 2024 20:54:08 +0900 Subject: [PATCH 51/58] =?UTF-8?q?[test]=20ConsumptionGoalServiceTest=20?= =?UTF-8?q?=EC=86=8C=EB=B9=84=EB=AA=A9=ED=91=9C=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ConsumptionGoalServiceTest.java | 113 +++++++----------- 1 file changed, 42 insertions(+), 71 deletions(-) diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java index 06e585eb..a010109f 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/consumptiongoal/service/ConsumptionGoalServiceTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.AdditionalAnswers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; @@ -91,6 +92,7 @@ void setUp() { given(userCategory.getId()).willReturn(-2L); given(categoryService.getUserCategoryList(user.getId())).willReturn(List.of(defaultCategory, userCategory)); + given(consumptionGoalRepository.save(any(ConsumptionGoal.class))).will(AdditionalAnswers.returnsFirstArg()); List expected = List.of( new ConsumptionGoalResponseDto(defaultCategory.getName(), defaultCategory.getId(), 0L, 0L), @@ -140,6 +142,8 @@ void setUp() { given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, requestMonth.withDayOfMonth(1).minusMonths(1))).willReturn(Optional.of(previousMonthUserCategoryGoal)); + given(consumptionGoalRepository.save(any(ConsumptionGoal.class))).will(AdditionalAnswers.returnsFirstArg()); + // when ConsumptionGoalResponseListDto result = consumptionGoalService.findUserConsumptionGoalList(user.getId(), requestMonth); @@ -190,26 +194,19 @@ void setUp() { } @Test - @DisplayName("updateConsumptionGoal : 이번달 목표가 있는 경우(defaultCategory)와 목표가 없는 경우(userCategory)") - void updateConsumptionGoal_Success() { + void 소비목표_업데이트_성공() { // given - Long defaultGoalAmount = 100L; - Long userGoalAmount = 200L; + Long updateAmount = 100L; LocalDate thisMonth = LocalDate.now().withDayOfMonth(1); - given(userRepository.findById(user.getId())).willReturn(Optional.ofNullable(user)); + given(userService.getUser(user.getId())).willReturn(user); ConsumptionGoalListRequestDto request = new ConsumptionGoalListRequestDto( - List.of(new ConsumptionGoalRequestDto(-1L, defaultGoalAmount), - new ConsumptionGoalRequestDto(-2L, userGoalAmount))); + List.of(new ConsumptionGoalRequestDto(-1L, updateAmount))); Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build()); given(defaultCategory.getId()).willReturn(-1L); - given(categoryRepository.findById(defaultCategory.getId())).willReturn(Optional.of(defaultCategory)); - - Category userCategory = Mockito.spy(Category.builder().name("유저 카테고리").user(user).isDefault(false).build()); - given(userCategory.getId()).willReturn(-2L); - given(categoryRepository.findById(userCategory.getId())).willReturn(Optional.of(userCategory)); + given(categoryService.getCategory(defaultCategory.getId())).willReturn(defaultCategory); ConsumptionGoal defaultCategoryGoal = ConsumptionGoal.builder() .goalAmount(1_000_000L) @@ -218,27 +215,14 @@ void updateConsumptionGoal_Success() { .category(defaultCategory) .goalMonth(thisMonth) .build(); - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, - thisMonth)).willReturn(Optional.ofNullable(defaultCategoryGoal)); - - given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, userCategory, - thisMonth)).willReturn(Optional.ofNullable(null)); - - when(consumptionGoalRepository.saveAll(any())).thenAnswer(invocation -> { - List goalsToSave = invocation.getArgument(0); - return goalsToSave; - }); + given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, defaultCategory, thisMonth)).willReturn( + Optional.ofNullable(defaultCategoryGoal)); List expected = List.of(ConsumptionGoalResponseDto.builder() - .goalAmount(defaultGoalAmount) + .goalAmount(updateAmount) .consumeAmount(defaultCategoryGoal.getConsumeAmount()) .categoryName(defaultCategory.getName()) .categoryId(defaultCategory.getId()) - .build(), ConsumptionGoalResponseDto.builder() - .goalAmount(userGoalAmount) - .consumeAmount(0L) - .categoryName(userCategory.getName()) - .categoryId(userCategory.getId()) .build()); // when @@ -290,11 +274,7 @@ void getPeerInfo_UserNotFound() { @DisplayName("getTopCategoryAndConsumptionAmount : 가장 큰 계획 카테고리와 이번 주 소비 금액 조회 성공") void getTopCategoryAndConsumptionAmount_Success() { // given - Category defaultCategory = Mockito.spy(Category.builder() - .name("디폴트 카테고리") - .user(null) - .isDefault(true) - .build()); + Category defaultCategory = Mockito.spy(Category.builder().name("디폴트 카테고리").user(null).isDefault(true).build()); given(defaultCategory.getId()).willReturn(1L); LocalDate goalMonthRandomDay = LocalDate.now(); @@ -321,25 +301,21 @@ void getTopCategoryAndConsumptionAmount_Success() { .build(); List avgConsumptionGoalList = List.of( - new AvgConsumptionGoalDto(defaultCategory.getId(), 5000L) - ); + new AvgConsumptionGoalDto(defaultCategory.getId(), 5000L)); int peerAgeStart = 23; int peerAgeEnd = 25; Gender peerGender = Gender.MALE; given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); - given(consumptionGoalRepository.findAvgGoalAmountByCategory( - peerAgeStart, peerAgeEnd, peerGender, currentMonth)) - .willReturn(avgConsumptionGoalList); + given(consumptionGoalRepository.findAvgGoalAmountByCategory(peerAgeStart, peerAgeEnd, peerGender, + currentMonth)).willReturn(avgConsumptionGoalList); - given(consumptionGoalRepository.findAvgConsumptionByCategoryIdAndCurrentWeek( - defaultCategory.getId(), startOfWeekDateTime, endOfWeekDateTime, - peerAgeStart, peerAgeEnd, peerGender)) - .willReturn(Optional.of(currentWeekConsumptionGoal.getConsumeAmount())); + given(consumptionGoalRepository.findAvgConsumptionByCategoryIdAndCurrentWeek(defaultCategory.getId(), + startOfWeekDateTime, endOfWeekDateTime, peerAgeStart, peerAgeEnd, peerGender)).willReturn( + Optional.of(currentWeekConsumptionGoal.getConsumeAmount())); - given(categoryRepository.findById(defaultCategory.getId())) - .willReturn(Optional.of(defaultCategory)); + given(categoryRepository.findById(defaultCategory.getId())).willReturn(Optional.of(defaultCategory)); // when ConsumptionAnalysisResponseDto result = consumptionGoalService.getTopCategoryAndConsumptionAmount(user.getId()); @@ -374,17 +350,17 @@ void getTopConsumptionCategories_Success() { String peerGender = "MALE"; given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); - given(expenseRepository.findTopCategoriesByConsumptionCount(peerAgeStart, peerAgeEnd, - Gender.valueOf(peerGender), currentMonth.atStartOfDay())) - .willReturn(List.of(topConsumption1, topConsumption2, topConsumption3)); + given( + expenseRepository.findTopCategoriesByConsumptionCount(peerAgeStart, peerAgeEnd, Gender.valueOf(peerGender), + currentMonth.atStartOfDay())).willReturn(List.of(topConsumption1, topConsumption2, topConsumption3)); given(categoryRepository.findById(defaultCategory1.getId())).willReturn(Optional.of(defaultCategory1)); given(categoryRepository.findById(defaultCategory2.getId())).willReturn(Optional.of(defaultCategory2)); given(categoryRepository.findById(defaultCategory3.getId())).willReturn(Optional.of(defaultCategory3)); // when - List result = consumptionGoalService.getTopConsumptionCategories( - user.getId(), peerAgeStart, peerAgeEnd, peerGender); + List result = consumptionGoalService.getTopConsumptionCategories(user.getId(), + peerAgeStart, peerAgeEnd, peerGender); // then assertThat(result).hasSize(3); @@ -414,23 +390,19 @@ void getAllConsumptionGoalCategories_Success() { defaultCategory2.setName("디폴트 카테고리2"); defaultCategory2.setIsDefault(true); - List categoryAvgList = List.of( - new AvgConsumptionGoalDto(1L, 3000L), - new AvgConsumptionGoalDto(2L, 4000L) - ); + List categoryAvgList = List.of(new AvgConsumptionGoalDto(1L, 3000L), + new AvgConsumptionGoalDto(2L, 4000L)); - List myConsumptionAmountList = List.of( - new MyConsumptionGoalDto(1L, 5000L), - new MyConsumptionGoalDto(2L, 2000L) - ); + List myConsumptionAmountList = List.of(new MyConsumptionGoalDto(1L, 5000L), + new MyConsumptionGoalDto(2L, 2000L)); List defaultCategories = List.of(defaultCategory1, defaultCategory2); given(categoryRepository.findAllByIsDefaultTrue()).willReturn(defaultCategories); - given(consumptionGoalRepository.findAvgGoalAmountByCategory( - anyInt(), anyInt(), any(), any())).willReturn(categoryAvgList); - given(consumptionGoalRepository.findAllGoalAmountByUserId(user.getId(), currentMonth)) - .willReturn(myConsumptionAmountList); + given(consumptionGoalRepository.findAvgGoalAmountByCategory(anyInt(), anyInt(), any(), any())).willReturn( + categoryAvgList); + given(consumptionGoalRepository.findAllGoalAmountByUserId(user.getId(), currentMonth)).willReturn( + myConsumptionAmountList); given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); // when @@ -466,21 +438,18 @@ void getAllConsumptionCategories_Success() { defaultCategory2.setName("디폴트 카테고리2"); defaultCategory2.setIsDefault(true); - List categoryAvgList = List.of( - new AvgConsumptionGoalDto(1L, 3000L), - new AvgConsumptionGoalDto(2L, 4000L) - ); + List categoryAvgList = List.of(new AvgConsumptionGoalDto(1L, 3000L), + new AvgConsumptionGoalDto(2L, 4000L)); - List myConsumptionAmountList = List.of( - new MyConsumptionGoalDto(1L, 5000L), - new MyConsumptionGoalDto(2L, 2000L) - ); + List myConsumptionAmountList = List.of(new MyConsumptionGoalDto(1L, 5000L), + new MyConsumptionGoalDto(2L, 2000L)); List defaultCategories = List.of(defaultCategory1, defaultCategory2); given(categoryRepository.findAllByIsDefaultTrue()).willReturn(defaultCategories); - given(consumptionGoalRepository.findAvgConsumptionAmountByCategory( - anyInt(), anyInt(), any(), any())).willReturn(categoryAvgList); + given( + consumptionGoalRepository.findAvgConsumptionAmountByCategory(anyInt(), anyInt(), any(), any())).willReturn( + categoryAvgList); given(userRepository.findById(user.getId())).willReturn(Optional.of(user)); // when @@ -542,6 +511,7 @@ void getAllConsumptionCategories_Success() { Optional.empty()); given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))).willReturn(Optional.of(beforeUserConsumptionGoal)); + given(consumptionGoalRepository.save(any(ConsumptionGoal.class))).will(AdditionalAnswers.returnsFirstArg()); ConsumptionGoal expected = ConsumptionGoal.builder() .goalAmount(1_000_000L) @@ -567,6 +537,7 @@ void getAllConsumptionCategories_Success() { Optional.empty()); given(consumptionGoalRepository.findByUserAndCategoryAndGoalMonth(user, category, goalMonth.minusMonths(1))).willReturn(Optional.empty()); + given(consumptionGoalRepository.save(any(ConsumptionGoal.class))).will(AdditionalAnswers.returnsFirstArg()); ConsumptionGoal expected = ConsumptionGoal.builder() .goalAmount(0L) From 16a3ee7b13151a7b216c2f6478add5ce9838e9b4 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:17:34 +0900 Subject: [PATCH 52/58] =?UTF-8?q?[feat]=20ErrorStatus=20Faq=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20status=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../budgetbuddies/apiPayload/code/status/ErrorStatus.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java index 8c9515b8..e3d44bb8 100644 --- a/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java +++ b/src/main/java/com/bbteam/budgetbuddies/apiPayload/code/status/ErrorStatus.java @@ -27,7 +27,9 @@ public enum ErrorStatus implements BaseErrorCode { _OTP_NOT_VALID(HttpStatus.BAD_REQUEST, "OTP4001", "인증번호가 유효하지 않습니다."), _PHONE_NUMBER_NOT_VALID(HttpStatus.BAD_REQUEST, "AUTH4001", "전화번호 형식이 유효하지 않습니다. (예: 01012341234)"), - _FAQ_NOT_FOUND(HttpStatus.NOT_FOUND, "FAQ4004", "해당 FAQ가 존재하지 않습니다."); + _FAQ_NOT_FOUND(HttpStatus.NOT_FOUND, "FAQ4004", "해당 FAQ가 존재하지 않습니다."), + _SEARCH_KEYWORD_NOT_FOUND(HttpStatus.NOT_FOUND, "SEARCH_KEYWORD4004", "해당 SearchKeyword가 존재하지 않습니다."), + _FAQ_KEYWORD_NOT_FOUND(HttpStatus.NOT_FOUND, "FAQ_KEYWORD4004", "해당 FaqKeyword가 존재하지 않습니다."); private HttpStatus httpStatus; From 9772e0f8146e4e4f3bb19fa3b0dacf75d276a1a7 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:18:09 +0900 Subject: [PATCH 53/58] =?UTF-8?q?[feat]=20FAQ,=20SearchKeyword=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../budgetbuddies/domain/faq/controller/FaqApi.java | 5 +++++ .../domain/faq/controller/FaqController.java | 12 ++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java index 06bc6e16..8485960f 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqApi.java @@ -113,4 +113,9 @@ ApiResponse modifyFaq(@PathVariable @ExistFaq Long faqId, } ) ApiResponse deleteFaq(@ExistFaq Long faqId); + + ApiResponse addKeyword(@ExistFaq Long faqId, Long searchKeywordId); + + ApiResponse deleteKeyword(@ExistFaq Long faqId, Long searchKeywordId); + } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java index 74a6e41f..c15fe5d2 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/controller/FaqController.java @@ -57,4 +57,16 @@ public ApiResponse deleteFaq(@PathVariable @ExistFaq Long faqId) { faqService.deleteFaq(faqId); return ApiResponse.onSuccess("Delete Success"); } + + @Override + @PostMapping("/{faqId}/keyword") + public ApiResponse addKeyword(@PathVariable @ExistFaq Long faqId, @RequestParam Long searchKeywordId) { + return ApiResponse.onSuccess(faqService.addKeyword(faqId, searchKeywordId)); + } + + @Override + @DeleteMapping("/{faqId}/keyword") + public ApiResponse deleteKeyword(@PathVariable @ExistFaq Long faqId, @RequestParam Long searchKeywordId) { + return ApiResponse.onSuccess(faqService.removeKeyword(faqId, searchKeywordId)); + } } From 64e64e362200449bb19906ab09cd9f8518eef33e Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:19:04 +0900 Subject: [PATCH 54/58] =?UTF-8?q?[feat]=20Faq=EC=99=80=20SearchKeyword?= =?UTF-8?q?=EC=9D=98=20=EC=A4=91=EA=B0=84=20mapping=20=EA=B0=9D=EC=B2=B4,?= =?UTF-8?q?=20FaqKeyword=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/faqkeyword/domain/FaqKeyword.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/domain/FaqKeyword.java diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/domain/FaqKeyword.java b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/domain/FaqKeyword.java new file mode 100644 index 00000000..6f5e9f14 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/domain/FaqKeyword.java @@ -0,0 +1,32 @@ +package com.bbteam.budgetbuddies.domain.faqkeyword.domain; + +import com.bbteam.budgetbuddies.common.BaseEntity; +import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.*; +import lombok.experimental.SuperBuilder; +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@SuperBuilder +public class FaqKeyword extends BaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "faq_id") + @NotFound(action = NotFoundAction.IGNORE) + private Faq faq; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "search_keyword_id") + @NotFound(action = NotFoundAction.IGNORE) + private SearchKeyword searchKeyword; + +} From bd62f553458109e0530ed844940fb4f5859b13bd Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:20:02 +0900 Subject: [PATCH 55/58] =?UTF-8?q?[feat]=20FaqKeyword=20repository,=20dto,?= =?UTF-8?q?=20test=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../faqkeyword/dto/FaqKeywordResponseDto.java | 21 ++++ .../repository/FaqKeywordRepository.java | 12 +++ .../faq/repository/FaqRepositoryTest.java | 101 ++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/dto/FaqKeywordResponseDto.java create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/repository/FaqKeywordRepository.java create mode 100644 src/test/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepositoryTest.java diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/dto/FaqKeywordResponseDto.java b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/dto/FaqKeywordResponseDto.java new file mode 100644 index 00000000..da6ef042 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/dto/FaqKeywordResponseDto.java @@ -0,0 +1,21 @@ +package com.bbteam.budgetbuddies.domain.faqkeyword.dto; + +import com.bbteam.budgetbuddies.domain.faqkeyword.domain.FaqKeyword; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class FaqKeywordResponseDto { + + private Long faqId; + private Long searchKeywordId; + + private String faqTitle; + private String keyword; + + public static FaqKeywordResponseDto toDto(FaqKeyword faqKeyword) { + return new FaqKeywordResponseDto(faqKeyword.getFaq().getId(), faqKeyword.getSearchKeyword().getId(), + faqKeyword.getFaq().getTitle(), faqKeyword.getSearchKeyword().getKeyword()); + } +} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/repository/FaqKeywordRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/repository/FaqKeywordRepository.java new file mode 100644 index 00000000..c0606ba0 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faqkeyword/repository/FaqKeywordRepository.java @@ -0,0 +1,12 @@ +package com.bbteam.budgetbuddies.domain.faqkeyword.repository; + +import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import com.bbteam.budgetbuddies.domain.faqkeyword.domain.FaqKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface FaqKeywordRepository extends JpaRepository { + Optional findByFaqAndSearchKeyword(Faq faq, SearchKeyword searchKeyword); +} diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepositoryTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepositoryTest.java new file mode 100644 index 00000000..6263fd38 --- /dev/null +++ b/src/test/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqRepositoryTest.java @@ -0,0 +1,101 @@ +package com.bbteam.budgetbuddies.domain.faq.repository; + +import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import com.bbteam.budgetbuddies.domain.faqkeyword.domain.FaqKeyword; +import com.bbteam.budgetbuddies.domain.faqkeyword.repository.FaqKeywordRepository; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.repository.SearchKeywordRepository; +import com.bbteam.budgetbuddies.domain.user.entity.User; +import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.transaction.annotation.Transactional; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@Transactional +@ActiveProfiles("test") +class FaqRepositoryTest { + @Autowired + FaqRepository faqRepository; + @Autowired + FaqKeywordRepository faqKeywordRepository; + @Autowired + SearchKeywordRepository searchKeywordRepository; + @Autowired + UserRepository userRepository; + + + @Test + void searchTest() { + + User user1 = User.builder() + .name("tester1") + .email("1234") + .age(5) + .phoneNumber("123456") + .mobileCarrier("skt") + .build(); + userRepository.save(user1); + + Faq faq1 = Faq.builder() + .user(user1) + .title("test1") + .body("test1") + .build(); + faqRepository.save(faq1); + + Faq faq2 = Faq.builder() + .user(user1) + .title("test2") + .body("test2") + .build(); + faqRepository.save(faq2); + + SearchKeyword keyword1 = SearchKeyword.builder() + .keyword("러닝") + .build(); + searchKeywordRepository.save(keyword1); + + FaqKeyword faqKeyword = FaqKeyword.builder() + .searchKeyword(keyword1) + .faq(faq1) + .build(); + faqKeywordRepository.save(faqKeyword); + + SearchKeyword keyword2 = SearchKeyword.builder() + .keyword("헬스") + .build(); + searchKeywordRepository.save(keyword2); + + FaqKeyword faqKeyword2 = FaqKeyword.builder() + .searchKeyword(keyword2) + .faq(faq1) + .build(); + faqKeywordRepository.save(faqKeyword2); + + FaqKeyword faqKeyword3 = FaqKeyword.builder() + .searchKeyword(keyword1) + .faq(faq2) + .build(); + faqKeywordRepository.save(faqKeyword3); + + PageRequest pageRequest = PageRequest.of(0, 5); + + Page result1 = faqRepository.searchFaq(pageRequest, "러닝"); + + Page result2 = faqRepository.searchFaq(pageRequest, "헬스"); + + assertThat(result1.getNumberOfElements()).isEqualTo(2); + assertThat(result2.getNumberOfElements()).isEqualTo(1); + + } + + +} \ No newline at end of file From f6166e6dd77ed8f60778de33dd805456f712bab1 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:20:30 +0900 Subject: [PATCH 56/58] =?UTF-8?q?[feat]=20FaqService=20keyword=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/faq/service/FaqService.java | 5 +++ .../domain/faq/service/FaqServiceImpl.java | 34 ++++++++++++++++ .../domain/faq/service/FaqServiceTest.java | 40 +++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java index 2f276470..f334dac5 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqService.java @@ -2,6 +2,7 @@ import com.bbteam.budgetbuddies.domain.faq.dto.FaqRequestDto; import com.bbteam.budgetbuddies.domain.faq.dto.FaqResponseDto; +import com.bbteam.budgetbuddies.domain.faqkeyword.dto.FaqKeywordResponseDto; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -18,4 +19,8 @@ public interface FaqService { FaqResponseDto.FaqModifyResponse modifyFaq(FaqRequestDto.FaqModifyRequest dto, Long faqId); String deleteFaq(Long faqId); + + FaqKeywordResponseDto addKeyword(Long faqId, Long searchKeywordId); + + String removeKeyword(Long faqId, Long searchKeywordId); } diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java index 70c11286..6b732095 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceImpl.java @@ -7,6 +7,11 @@ import com.bbteam.budgetbuddies.domain.faq.dto.FaqResponseDto; import com.bbteam.budgetbuddies.domain.faq.entity.Faq; import com.bbteam.budgetbuddies.domain.faq.repository.FaqRepository; +import com.bbteam.budgetbuddies.domain.faqkeyword.domain.FaqKeyword; +import com.bbteam.budgetbuddies.domain.faqkeyword.dto.FaqKeywordResponseDto; +import com.bbteam.budgetbuddies.domain.faqkeyword.repository.FaqKeywordRepository; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.repository.SearchKeywordRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; import lombok.RequiredArgsConstructor; @@ -22,6 +27,8 @@ public class FaqServiceImpl implements FaqService{ private final FaqRepository faqRepository; private final UserRepository userRepository; + private final FaqKeywordRepository faqKeywordRepository; + private final SearchKeywordRepository searchKeywordRepository; @Override public FaqResponseDto.FaqFindResponse findOneFaq(Long faqId) { @@ -67,4 +74,31 @@ private Faq findFaq(Long faqId) { public Page searchFaq(Pageable pageable, String searchCondition) { return faqRepository.searchFaq(pageable, searchCondition).map(FaqConverter::entityToFind); } + + @Override + @Transactional + public FaqKeywordResponseDto addKeyword(Long faqId, Long searchKeywordId) { + Faq faq = findFaq(faqId); + SearchKeyword searchKeyword = searchKeywordRepository.findById(searchKeywordId).orElseThrow(() -> new GeneralException(ErrorStatus._SEARCH_KEYWORD_NOT_FOUND)); + + FaqKeyword faqKeyword = FaqKeyword.builder() + .searchKeyword(searchKeyword) + .faq(faq) + .build(); + + faqKeywordRepository.save(faqKeyword); + return FaqKeywordResponseDto.toDto(faqKeyword); + } + + @Override + @Transactional + public String removeKeyword(Long faqId, Long searchKeywordId) { + Faq faq = findFaq(faqId); + SearchKeyword searchKeyword = searchKeywordRepository.findById(searchKeywordId).orElseThrow(() -> new GeneralException(ErrorStatus._SEARCH_KEYWORD_NOT_FOUND)); + + FaqKeyword faqKeyword = faqKeywordRepository.findByFaqAndSearchKeyword(faq, searchKeyword).orElseThrow(() -> new GeneralException(ErrorStatus._FAQ_KEYWORD_NOT_FOUND)); + faqKeywordRepository.delete(faqKeyword); + + return "ok"; + } } diff --git a/src/test/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceTest.java b/src/test/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceTest.java index 4e895c18..67d5e7b1 100644 --- a/src/test/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceTest.java +++ b/src/test/java/com/bbteam/budgetbuddies/domain/faq/service/FaqServiceTest.java @@ -4,6 +4,10 @@ import com.bbteam.budgetbuddies.domain.faq.dto.FaqResponseDto; import com.bbteam.budgetbuddies.domain.faq.entity.Faq; import com.bbteam.budgetbuddies.domain.faq.repository.FaqRepository; +import com.bbteam.budgetbuddies.domain.faqkeyword.dto.FaqKeywordResponseDto; +import com.bbteam.budgetbuddies.domain.faqkeyword.repository.FaqKeywordRepository; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.repository.SearchKeywordRepository; import com.bbteam.budgetbuddies.domain.user.entity.User; import com.bbteam.budgetbuddies.domain.user.repository.UserRepository; import org.assertj.core.api.Assertions; @@ -14,6 +18,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; +import org.springframework.test.annotation.Rollback; import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @@ -31,6 +36,10 @@ class FaqServiceTest { FaqRepository faqRepository; @Autowired UserRepository userRepository; + @Autowired + FaqKeywordRepository faqKeywordRepository; + @Autowired + SearchKeywordRepository searchKeywordRepository; static Long userId; static Long faqId; @@ -149,4 +158,35 @@ void deleteFaq() { assertThat(faq.isEmpty()).isTrue(); } + + @Test + void addKeywordAndRemoveKeyword() { + User user = userRepository.findById(userId).get(); + + Faq faq1 = Faq.builder() + .title("test1") + .body("test1") + .user(user) + .build(); + faqRepository.save(faq1); + + SearchKeyword searchKeyword = SearchKeyword.builder() + .keyword("testKeyword") + .build(); + searchKeywordRepository.save(searchKeyword); + faqService.addKeyword(faq1.getId(), searchKeyword.getId()); + PageRequest pageRequest = PageRequest.of(0, 1); + + Page result1 = faqService.searchFaq(pageRequest, "test"); + Assertions.assertThat(result1.getNumberOfElements()).isEqualTo(1); + + Page result2 = faqService.searchFaq(pageRequest, "no"); + Assertions.assertThat(result2.getNumberOfElements()).isEqualTo(0); + + faqService.removeKeyword(faq1.getId(), searchKeyword.getId()); + Page result3 = faqService.searchFaq(pageRequest, "test"); + Assertions.assertThat(result3.getNumberOfElements()).isEqualTo(0); + + + } } \ No newline at end of file From f00df26c03493636d385d24a95e236a62644cb4c Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:20:55 +0900 Subject: [PATCH 57/58] =?UTF-8?q?[feat]=20FaqSearchRepository=EC=9D=98=20?= =?UTF-8?q?=EB=8F=99=EC=A0=81=20=EC=BF=BC=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(QueryDSL)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../faq/repository/FaqSearchRepositoryImpl.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java index 81205dbf..1e3116ab 100644 --- a/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java +++ b/src/main/java/com/bbteam/budgetbuddies/domain/faq/repository/FaqSearchRepositoryImpl.java @@ -1,6 +1,7 @@ package com.bbteam.budgetbuddies.domain.faq.repository; import com.bbteam.budgetbuddies.domain.faq.entity.Faq; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.QSearchKeyword; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.JPAExpressions; import com.querydsl.jpa.impl.JPAQueryFactory; @@ -14,6 +15,7 @@ import static com.bbteam.budgetbuddies.domain.faq.entity.QFaq.*; import static com.bbteam.budgetbuddies.domain.faqkeyword.domain.QFaqKeyword.*; +import static com.bbteam.budgetbuddies.domain.searchkeyword.domain.QSearchKeyword.*; public class FaqSearchRepositoryImpl implements FaqSearchRepository{ @@ -27,11 +29,11 @@ public FaqSearchRepositoryImpl(EntityManager em) { public Page searchFaq(Pageable pageable, String searchCondition) { List result = queryFactory.select(faq) .from(faq) - .where(faq.in( + .where(faq.id.in( JPAExpressions - .select(faqKeyword.faq) + .select(faqKeyword.faq.id) .from(faqKeyword) - .where(keywordMatch(searchCondition)) + .join(searchKeyword).on(keywordMatch(searchCondition)) )) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) @@ -39,11 +41,11 @@ public Page searchFaq(Pageable pageable, String searchCondition) { Long total = queryFactory.select(faq.count()) .from(faq) - .where(faq.in( + .where(faq.id.in( JPAExpressions - .select(faqKeyword.faq) + .select(faqKeyword.faq.id) .from(faqKeyword) - .where(keywordMatch(searchCondition)) + .join(searchKeyword).on(keywordMatch(searchCondition)) )) .fetchOne(); @@ -52,7 +54,7 @@ public Page searchFaq(Pageable pageable, String searchCondition) { } private BooleanExpression keywordMatch(String searchCondition) { - return searchCondition != null ? faqKeyword.searchKeyword.keyword.eq(searchCondition) : null; + return searchCondition != null ? searchKeyword.keyword.contains(searchCondition) : null; } } From d78df08091e6478a4af08a805f714663901cee86 Mon Sep 17 00:00:00 2001 From: wnd01jun Date: Wed, 13 Nov 2024 16:21:35 +0900 Subject: [PATCH 58/58] =?UTF-8?q?[feat]=20SearchKeyword=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SearchKeywordController.java | 48 +++++++++++++++++++ .../searchkeyword/domain/SearchKeyword.java | 23 +++++++++ .../repository/SearchKeywordRepository.java | 7 +++ .../service/SearchKeywordService.java | 44 +++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/controller/SearchKeywordController.java create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/domain/SearchKeyword.java create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/repository/SearchKeywordRepository.java create mode 100644 src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/service/SearchKeywordService.java diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/controller/SearchKeywordController.java b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/controller/SearchKeywordController.java new file mode 100644 index 00000000..45786bbe --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/controller/SearchKeywordController.java @@ -0,0 +1,48 @@ +package com.bbteam.budgetbuddies.domain.searchkeyword.controller; + +import com.bbteam.budgetbuddies.apiPayload.ApiResponse; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.service.SearchKeywordService; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/search-keyword") +public class SearchKeywordController { + + private final SearchKeywordService searchKeywordService; + + @PostMapping("") + public ApiResponse saveKeyword(String keyword) { + + return ApiResponse.onSuccess(searchKeywordService.saveKeyword(keyword)); + } + + @GetMapping("") + public ApiResponse findOne(Long searchKeywordId) { + return ApiResponse.onSuccess(searchKeywordService.findOne(searchKeywordId)); + } + + @GetMapping("/all") + public ApiResponse> findAll(Pageable pageable) { + return ApiResponse.onSuccess(searchKeywordService.findAll(pageable)); + } + + @PutMapping("") + public ApiResponse modifyOne(Long searchKeywordId, String newKeyword) { + return ApiResponse.onSuccess((searchKeywordService.modifyOne(searchKeywordId, newKeyword))); + } + + @DeleteMapping("") + public ApiResponse deleteOne(Long searchKeywordId) { + searchKeywordService.deleteOne(searchKeywordId); + return ApiResponse.onSuccess("OK"); + } + + + + +} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/domain/SearchKeyword.java b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/domain/SearchKeyword.java new file mode 100644 index 00000000..970d72f4 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/domain/SearchKeyword.java @@ -0,0 +1,23 @@ +package com.bbteam.budgetbuddies.domain.searchkeyword.domain; + +import com.bbteam.budgetbuddies.common.BaseEntity; +import jakarta.persistence.Entity; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class SearchKeyword extends BaseEntity { + + private String keyword; + + public void changeKeyword(String newKeyword) { + this.keyword = newKeyword; + } + +} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/repository/SearchKeywordRepository.java b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/repository/SearchKeywordRepository.java new file mode 100644 index 00000000..1fcea8b7 --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/repository/SearchKeywordRepository.java @@ -0,0 +1,7 @@ +package com.bbteam.budgetbuddies.domain.searchkeyword.repository; + +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SearchKeywordRepository extends JpaRepository { +} diff --git a/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/service/SearchKeywordService.java b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/service/SearchKeywordService.java new file mode 100644 index 00000000..b960855d --- /dev/null +++ b/src/main/java/com/bbteam/budgetbuddies/domain/searchkeyword/service/SearchKeywordService.java @@ -0,0 +1,44 @@ +package com.bbteam.budgetbuddies.domain.searchkeyword.service; + +import com.bbteam.budgetbuddies.apiPayload.code.status.ErrorStatus; +import com.bbteam.budgetbuddies.apiPayload.exception.GeneralException; +import com.bbteam.budgetbuddies.domain.searchkeyword.domain.SearchKeyword; +import com.bbteam.budgetbuddies.domain.searchkeyword.repository.SearchKeywordRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class SearchKeywordService { + + private final SearchKeywordRepository searchKeywordRepository; + + public SearchKeyword saveKeyword(String keyword) { + SearchKeyword searchKeyword = SearchKeyword.builder().keyword(keyword).build(); + searchKeywordRepository.save(searchKeyword); + return searchKeyword; + } + + public SearchKeyword findOne(Long searchKeywordId) { + return searchKeywordRepository.findById(searchKeywordId).orElseThrow(() -> new GeneralException(ErrorStatus._SEARCH_KEYWORD_NOT_FOUND)); + } + + public Page findAll(Pageable pageable) { + return searchKeywordRepository.findAll(pageable); + } + + public SearchKeyword modifyOne(Long searchKeywordId, String keyword) { + SearchKeyword searchKeyword = searchKeywordRepository.findById(searchKeywordId).orElseThrow(() -> new GeneralException(ErrorStatus._SEARCH_KEYWORD_NOT_FOUND)); + searchKeyword.changeKeyword(keyword); + return searchKeyword; + } + + public void deleteOne(Long searchKeywordId) { + SearchKeyword searchKeyword = searchKeywordRepository.findById(searchKeywordId).orElseThrow(() -> new GeneralException(ErrorStatus._SEARCH_KEYWORD_NOT_FOUND)); + searchKeywordRepository.delete(searchKeyword); + } +}