From bad24ef4da1ed532452b6d94e1de066789a88577 Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:16:39 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[modify]=20=EB=B3=80=EA=B2=BD=EB=90=98?= =?UTF-8?q?=EA=B8=B0=20=EC=A0=84=20=EC=BD=94=EB=93=9C=20Deprecated=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20(#427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../description/DescriptionInfo.java | 1 + .../description/DescriptionService.java | 1 + .../sopt/app/facade/DescriptionFacade.java | 24 ------- .../postgres/MainDescriptionRepository.java | 1 + .../app/facade/DescriptionFacadeTest.java | 65 ------------------- 5 files changed, 3 insertions(+), 89 deletions(-) delete mode 100755 src/main/java/org/sopt/app/facade/DescriptionFacade.java delete mode 100755 src/test/java/org/sopt/app/facade/DescriptionFacadeTest.java diff --git a/src/main/java/org/sopt/app/application/description/DescriptionInfo.java b/src/main/java/org/sopt/app/application/description/DescriptionInfo.java index ffb7fdf5..ac9dcee1 100755 --- a/src/main/java/org/sopt/app/application/description/DescriptionInfo.java +++ b/src/main/java/org/sopt/app/application/description/DescriptionInfo.java @@ -7,6 +7,7 @@ import lombok.ToString; @NoArgsConstructor(access = AccessLevel.PRIVATE) +@Deprecated public class DescriptionInfo { @Getter diff --git a/src/main/java/org/sopt/app/application/description/DescriptionService.java b/src/main/java/org/sopt/app/application/description/DescriptionService.java index c2c4b54d..293d9f27 100755 --- a/src/main/java/org/sopt/app/application/description/DescriptionService.java +++ b/src/main/java/org/sopt/app/application/description/DescriptionService.java @@ -8,6 +8,7 @@ @Service @RequiredArgsConstructor +@Deprecated public class DescriptionService { private final MainDescriptionRepository mainDescriptionRepository; diff --git a/src/main/java/org/sopt/app/facade/DescriptionFacade.java b/src/main/java/org/sopt/app/facade/DescriptionFacade.java deleted file mode 100755 index ad025f7d..00000000 --- a/src/main/java/org/sopt/app/facade/DescriptionFacade.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.sopt.app.facade; - -import lombok.RequiredArgsConstructor; -import lombok.val; -import org.sopt.app.application.playground.PlaygroundAuthService; -import org.sopt.app.application.description.DescriptionInfo.MainDescription; -import org.sopt.app.application.description.DescriptionService; -import org.sopt.app.domain.entity.User; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class DescriptionFacade { - - private final DescriptionService descriptionService; - private final PlaygroundAuthService playgroundAuthService; - - @Transactional(readOnly = true) - public MainDescription getMainDescriptionForUser(User user) { - val userActiveInfo = playgroundAuthService.getPlaygroundUserActiveInfo(user.getPlaygroundToken(), user.getPlaygroundId()); - return descriptionService.getMainDescription(userActiveInfo.status()); - } -} diff --git a/src/main/java/org/sopt/app/interfaces/postgres/MainDescriptionRepository.java b/src/main/java/org/sopt/app/interfaces/postgres/MainDescriptionRepository.java index 82f852d1..a36abb0d 100755 --- a/src/main/java/org/sopt/app/interfaces/postgres/MainDescriptionRepository.java +++ b/src/main/java/org/sopt/app/interfaces/postgres/MainDescriptionRepository.java @@ -3,6 +3,7 @@ import org.sopt.app.domain.entity.MainDescription; import org.springframework.data.jpa.repository.JpaRepository; +@Deprecated public interface MainDescriptionRepository extends JpaRepository { } diff --git a/src/test/java/org/sopt/app/facade/DescriptionFacadeTest.java b/src/test/java/org/sopt/app/facade/DescriptionFacadeTest.java deleted file mode 100755 index e981c656..00000000 --- a/src/test/java/org/sopt/app/facade/DescriptionFacadeTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.sopt.app.facade; - -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.UserActiveInfo; -import org.sopt.app.application.playground.PlaygroundAuthService; -import org.sopt.app.application.description.DescriptionInfo; -import org.sopt.app.application.description.DescriptionInfo.MainDescription; -import org.sopt.app.application.description.DescriptionService; -import org.sopt.app.domain.entity.User; -import org.sopt.app.domain.enums.UserStatus; - -@ExtendWith(MockitoExtension.class) -class DescriptionFacadeTest { - - @Mock - private DescriptionService descriptionService; - - @Mock - private PlaygroundAuthService playgroundAuthService; - - @InjectMocks - private DescriptionFacade descriptionFacade; - - @Test - @DisplayName("SUCCESS_활동 유저 메인 문구 조회") - void SUCCESS_getMainDescriptionForUserActive() { - User user = User.builder().playgroundId(1L).playgroundToken("token").build(); - UserStatus userStatus = UserStatus.ACTIVE; - Mockito.when(playgroundAuthService.getPlaygroundUserActiveInfo(anyString(), anyLong())) - .thenReturn(new UserActiveInfo(34L, userStatus)); - Mockito.when(descriptionService.getMainDescription(userStatus)) - .thenReturn(DescriptionInfo.MainDescription.builder().topDescription("activeTop") - .bottomDescription("activeBottom").build()); - - MainDescription result = descriptionFacade.getMainDescriptionForUser(user); - Assertions.assertEquals("activeTop", result.getTopDescription()); - Assertions.assertEquals("activeBottom", result.getBottomDescription()); - } - - @Test - @DisplayName("SUCCESS_비활동 유저 메인 문구 조회") - void SUCCESS_getMainDescriptionForUserInactive() { - User user = User.builder().playgroundId(1L).playgroundToken("token").build(); - UserStatus userStatus = UserStatus.INACTIVE; - Mockito.when(playgroundAuthService.getPlaygroundUserActiveInfo(anyString(), anyLong())) - .thenReturn(new UserActiveInfo(29L, userStatus)); - Mockito.when(descriptionService.getMainDescription(userStatus)) - .thenReturn(DescriptionInfo.MainDescription.builder().topDescription("inactiveTop") - .bottomDescription("inactiveBottom").build()); - - MainDescription result = descriptionFacade.getMainDescriptionForUser(user); - Assertions.assertEquals("inactiveTop", result.getTopDescription()); - Assertions.assertEquals("inactiveBottom", result.getBottomDescription()); - } -} From e1b2032414d052250d0eeed8c6afc25b8823a656 Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:17:27 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[feat]=20HomeController=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/presentation/home/HomeController.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/org/sopt/app/presentation/home/HomeController.java diff --git a/src/main/java/org/sopt/app/presentation/home/HomeController.java b/src/main/java/org/sopt/app/presentation/home/HomeController.java new file mode 100644 index 00000000..81deff47 --- /dev/null +++ b/src/main/java/org/sopt/app/presentation/home/HomeController.java @@ -0,0 +1,37 @@ +package org.sopt.app.presentation.home; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import lombok.RequiredArgsConstructor; +import org.sopt.app.domain.entity.User; +import org.sopt.app.facade.HomeFacade; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v2/home") +@SecurityRequirement(name = "Authorization") +public class HomeController { + + private final HomeFacade homeFacade; + + @Operation(summary = "홈 메인 문구 조회") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "success"), + @ApiResponse(responseCode = "401", description = "token error", content = @Content), + @ApiResponse(responseCode = "500", description = "server error", content = @Content) + }) + @GetMapping("/description") + public ResponseEntity getHomeMainDescription( + @AuthenticationPrincipal User user + ) { + return ResponseEntity.ok( + homeFacade.getHomeMainDescription(user) + ); + } +} From 20cf96f7a92d8dd35e33635c3532f3a49fd96935 Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:17:54 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[feat]=20=ED=99=88=20=EB=A9=94=EC=9D=B8=20?= =?UTF-8?q?=EB=AC=B8=EA=B5=AC=20=EC=A1=B0=ED=9A=8C=20Response=20DTO=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/home/HomeDescriptionResponse.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java diff --git a/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java b/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java new file mode 100644 index 00000000..0a23e49c --- /dev/null +++ b/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java @@ -0,0 +1,14 @@ +package org.sopt.app.presentation.home; + +import lombok.*; + +@Getter +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class HomeDescriptionResponse { + private final String activityDescription; + public static HomeDescriptionResponse of(String userName, int totalActivityMonths) { + return new HomeDescriptionResponse( + userName + "님은\nSOPT와" + totalActivityMonths + "개월째" + ); + } +} From 4c1a64a222fde7daea7b4f1bf73a665ebd791436 Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:18:32 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[modify]=20=EA=B8=B0=EC=A1=B4=20Description?= =?UTF-8?q?Facade=EB=A5=BC=20HomeFacade=EB=A1=9C=20=EC=88=98=EC=A0=95=20(#?= =?UTF-8?q?427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/sopt/app/facade/HomeFacade.java | 39 +++++++++++ .../description/DescriptionController.java | 6 +- .../org/sopt/app/facade/HomeFacadeTest.java | 65 +++++++++++++++++++ 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100755 src/main/java/org/sopt/app/facade/HomeFacade.java create mode 100755 src/test/java/org/sopt/app/facade/HomeFacadeTest.java diff --git a/src/main/java/org/sopt/app/facade/HomeFacade.java b/src/main/java/org/sopt/app/facade/HomeFacade.java new file mode 100755 index 00000000..96956bc3 --- /dev/null +++ b/src/main/java/org/sopt/app/facade/HomeFacade.java @@ -0,0 +1,39 @@ +package org.sopt.app.facade; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.val; +import org.sopt.app.application.home.ActivityDurationCalculator; +import org.sopt.app.application.playground.PlaygroundAuthService; +import org.sopt.app.application.description.DescriptionInfo.MainDescription; +import org.sopt.app.application.description.DescriptionService; +import org.sopt.app.domain.entity.User; +import org.sopt.app.presentation.home.HomeDescriptionResponse; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class HomeFacade { + + private final DescriptionService descriptionService; + private final PlaygroundAuthService playgroundAuthService; + + @Transactional(readOnly = true) + @Deprecated + public MainDescription getMainDescriptionForUser(User user) { + val userActiveInfo = playgroundAuthService.getPlaygroundUserActiveInfo(user.getPlaygroundToken(), user.getPlaygroundId()); + return descriptionService.getMainDescription(userActiveInfo.status()); + } + + @Transactional(readOnly = true) + public HomeDescriptionResponse getHomeMainDescription(User user) { + List ownGenerations = playgroundAuthService.getOwnPlaygroundProfile(user.getPlaygroundToken()) + .getAllGenerations(); + ActivityDurationCalculator calculator = ActivityDurationCalculator.of(ownGenerations); + return HomeDescriptionResponse.of( + user.getUsername(), + calculator.getActivityDuration() + ); + } +} diff --git a/src/main/java/org/sopt/app/presentation/description/DescriptionController.java b/src/main/java/org/sopt/app/presentation/description/DescriptionController.java index 9bdf4be3..78a51aff 100755 --- a/src/main/java/org/sopt/app/presentation/description/DescriptionController.java +++ b/src/main/java/org/sopt/app/presentation/description/DescriptionController.java @@ -7,7 +7,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import lombok.RequiredArgsConstructor; import lombok.val; -import org.sopt.app.facade.DescriptionFacade; +import org.sopt.app.facade.HomeFacade; import org.sopt.app.domain.entity.User; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; @@ -19,7 +19,7 @@ @SecurityRequirement(name = "Authorization") public class DescriptionController { - private final DescriptionFacade descriptionFacade; + private final HomeFacade homeFacade; @Operation(summary = "메인 문구 조회") @ApiResponses({ @@ -31,7 +31,7 @@ public class DescriptionController { public ResponseEntity getMainDescription( @AuthenticationPrincipal User user ) { - val response = descriptionFacade.getMainDescriptionForUser(user); + val response = homeFacade.getMainDescriptionForUser(user); return ResponseEntity.ok( DescriptionResponse.MainDescription.builder() .topDescription(response.getTopDescription()) diff --git a/src/test/java/org/sopt/app/facade/HomeFacadeTest.java b/src/test/java/org/sopt/app/facade/HomeFacadeTest.java new file mode 100755 index 00000000..7455cea0 --- /dev/null +++ b/src/test/java/org/sopt/app/facade/HomeFacadeTest.java @@ -0,0 +1,65 @@ +package org.sopt.app.facade; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.UserActiveInfo; +import org.sopt.app.application.playground.PlaygroundAuthService; +import org.sopt.app.application.description.DescriptionInfo; +import org.sopt.app.application.description.DescriptionInfo.MainDescription; +import org.sopt.app.application.description.DescriptionService; +import org.sopt.app.domain.entity.User; +import org.sopt.app.domain.enums.UserStatus; + +@ExtendWith(MockitoExtension.class) +class HomeFacadeTest { + + @Mock + private DescriptionService descriptionService; + + @Mock + private PlaygroundAuthService playgroundAuthService; + + @InjectMocks + private HomeFacade homeFacade; + + @Test + @DisplayName("SUCCESS_활동 유저 메인 문구 조회") + void SUCCESS_getMainDescriptionForUserActive() { + User user = User.builder().playgroundId(1L).playgroundToken("token").build(); + UserStatus userStatus = UserStatus.ACTIVE; + Mockito.when(playgroundAuthService.getPlaygroundUserActiveInfo(anyString(), anyLong())) + .thenReturn(new UserActiveInfo(34L, userStatus)); + Mockito.when(descriptionService.getMainDescription(userStatus)) + .thenReturn(DescriptionInfo.MainDescription.builder().topDescription("activeTop") + .bottomDescription("activeBottom").build()); + + MainDescription result = homeFacade.getMainDescriptionForUser(user); + Assertions.assertEquals("activeTop", result.getTopDescription()); + Assertions.assertEquals("activeBottom", result.getBottomDescription()); + } + + @Test + @DisplayName("SUCCESS_비활동 유저 메인 문구 조회") + void SUCCESS_getMainDescriptionForUserInactive() { + User user = User.builder().playgroundId(1L).playgroundToken("token").build(); + UserStatus userStatus = UserStatus.INACTIVE; + Mockito.when(playgroundAuthService.getPlaygroundUserActiveInfo(anyString(), anyLong())) + .thenReturn(new UserActiveInfo(29L, userStatus)); + Mockito.when(descriptionService.getMainDescription(userStatus)) + .thenReturn(DescriptionInfo.MainDescription.builder().topDescription("inactiveTop") + .bottomDescription("inactiveBottom").build()); + + MainDescription result = homeFacade.getMainDescriptionForUser(user); + Assertions.assertEquals("inactiveTop", result.getTopDescription()); + Assertions.assertEquals("inactiveBottom", result.getBottomDescription()); + } +} From 3699a5177aa15abc64b658d577a0740e39794c6c Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:19:56 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[feat]=20=EA=B8=B0=EC=88=98=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EB=B0=9B=EC=95=84=20=ED=99=9C=EB=8F=99?= =?UTF-8?q?=ED=95=9C=20=EB=8B=AC=EC=9D=84=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20(#427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../home/ActivityDurationCalculator.java | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/main/java/org/sopt/app/application/home/ActivityDurationCalculator.java diff --git a/src/main/java/org/sopt/app/application/home/ActivityDurationCalculator.java b/src/main/java/org/sopt/app/application/home/ActivityDurationCalculator.java new file mode 100644 index 00000000..f62ca67a --- /dev/null +++ b/src/main/java/org/sopt/app/application/home/ActivityDurationCalculator.java @@ -0,0 +1,47 @@ +package org.sopt.app.application.home; + +import java.time.*; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.sopt.app.common.exception.BadRequestException; +import org.sopt.app.common.response.ErrorCode; + +@RequiredArgsConstructor +public class ActivityDurationCalculator { + private final Long firstActivityGeneration; + + public static ActivityDurationCalculator of(final List generations) { + if (generations == null || generations.isEmpty()) { + throw new BadRequestException(ErrorCode.USER_GENERATION_INFO_NOT_FOUND); + } + + Long firstGeneration = Long.MAX_VALUE; + for (Long generation : generations) { + if (generation < firstGeneration) { + firstGeneration = generation; + } + } + return new ActivityDurationCalculator(firstGeneration); + } + + public int getActivityDuration() { + LocalDate startDate = calculateStartDate(); + return calculateMonthDifference(startDate); + } + + private LocalDate calculateStartDate() { + final int SOPT_START_YEAR = 2007; + final int EVEN_GENERATION_START_MONTH = 3; + final int ODD_GENERATION_START_MONTH = 9; + int startMonth = (firstActivityGeneration % 2 == 0) ? EVEN_GENERATION_START_MONTH : ODD_GENERATION_START_MONTH; + int startYear = SOPT_START_YEAR + (int) (firstActivityGeneration / 2); + return LocalDate.of(startYear, startMonth, 1); + } + + private int calculateMonthDifference(LocalDate startDate) { + LocalDate currentDate = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).toLocalDate(); + Period period = Period.between(startDate, currentDate); + int monthDifference = period.getYears() * 12 + period.getMonths(); + return monthDifference + 1; + } +} From 44eed699b7d96a7166753f968e74cbed9a72e4a1 Mon Sep 17 00:00:00 2001 From: kseysh Date: Tue, 5 Nov 2024 15:23:02 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[modify]=20=EB=A9=94=EC=9D=B8=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=EC=97=90=20=EB=9D=84=EC=96=B4=EC=93=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#427)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/sopt/app/presentation/home/HomeDescriptionResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java b/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java index 0a23e49c..0eb736f5 100644 --- a/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java +++ b/src/main/java/org/sopt/app/presentation/home/HomeDescriptionResponse.java @@ -8,7 +8,7 @@ public class HomeDescriptionResponse { private final String activityDescription; public static HomeDescriptionResponse of(String userName, int totalActivityMonths) { return new HomeDescriptionResponse( - userName + "님은\nSOPT와" + totalActivityMonths + "개월째" + userName + "님은\nSOPT와 " + totalActivityMonths + "개월째" ); } }