From 2e7faf787d0c622f38e09996154ec87bcf66ba10 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 14 Nov 2024 15:52:27 +0900 Subject: [PATCH 1/5] =?UTF-8?q?[feat]=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=EB=B3=84=20=EC=B5=9C=EC=8B=A0=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84=20(#4?= =?UTF-8?q?34)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../playground/PlaygroundAuthService.java | 64 +++++++++++++++++-- .../playground/PlaygroundClient.java | 5 ++ .../java/org/sopt/app/facade/HomeFacade.java | 12 ++++ .../app/presentation/home/HomeController.java | 16 +++++ .../home/response/RecentPostsResponse.java | 18 ++++++ 5 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java diff --git a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java index c5f92678..91c3d102 100755 --- a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java +++ b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java @@ -1,20 +1,39 @@ package org.sopt.app.application.playground; -import static org.sopt.app.application.playground.PlaygroundHeaderCreator.*; +import static org.sopt.app.application.playground.PlaygroundHeaderCreator.createAuthorizationHeaderByUserPlaygroundToken; +import static org.sopt.app.application.playground.PlaygroundHeaderCreator.createDefaultHeader; -import lombok.*; import io.jsonwebtoken.ExpiredJwtException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.stream.Collectors; -import org.sopt.app.application.playground.dto.PlaygroundPostInfo.*; -import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.*; +import lombok.RequiredArgsConstructor; +import lombok.val; import org.sopt.app.application.auth.dto.PlaygroundAuthTokenInfo.RefreshedToken; -import org.sopt.app.common.exception.*; +import org.sopt.app.application.playground.dto.PlaygroundPostInfo.PlaygroundPost; +import org.sopt.app.application.playground.dto.PlaygroundPostInfo.PlaygroundPostResponse; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.ActiveUserIds; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.ActivityCardinalInfo; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.MainView; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.MainViewUser; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.OwnPlaygroundProfile; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.PlaygroundMain; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.PlaygroundProfile; +import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.UserActiveInfo; +import org.sopt.app.common.exception.BadRequestException; +import org.sopt.app.common.exception.UnauthorizedException; import org.sopt.app.common.response.ErrorCode; import org.sopt.app.domain.enums.UserStatus; -import org.sopt.app.presentation.auth.AppAuthRequest.*; +import org.sopt.app.presentation.auth.AppAuthRequest.AccessTokenRequest; +import org.sopt.app.presentation.auth.AppAuthRequest.CodeRequest; +import org.sopt.app.presentation.home.response.RecentPostsResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException.BadRequest; @@ -158,4 +177,35 @@ private String convertPlaygroundWebPageUrl(Long postId) { public boolean isCurrentGeneration(Long generation) { return generation.equals(currentGeneration); } + + public List getRecentPosts(String playgroundToken) { + final Map accessToken = createAuthorizationHeaderByUserPlaygroundToken(playgroundToken); + try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { + List categories = List.of("SOPT 활동", "자유", "파트"); + + CompletableFuture hotPostFuture = CompletableFuture.supplyAsync(() -> { + PlaygroundPostResponse hotpost = playgroundClient.getPlaygroundHotPost(accessToken); + return RecentPostsResponse.builder() + .category("HOT") + .isHotPost(true) + .content(hotpost.content()) + .title(hotpost.title()) + .id(hotpost.postId()) + .build(); + }, executor); + List> categoryFutures = categories.stream() + .map(category -> CompletableFuture.supplyAsync(() -> { + RecentPostsResponse recentPosts = playgroundClient.getRecentPosts(accessToken, category); + return recentPosts; + }, executor)) + .toList(); + List> allFutures = new ArrayList<>(categoryFutures); + allFutures.addFirst(hotPostFuture); + CompletableFuture allOf = CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0])); + return allOf.thenApply(v -> allFutures.stream() + .map(CompletableFuture::join) + .collect(Collectors.toList())) + .join(); + } + } } diff --git a/src/main/java/org/sopt/app/application/playground/PlaygroundClient.java b/src/main/java/org/sopt/app/application/playground/PlaygroundClient.java index 4922bbf1..568b359a 100755 --- a/src/main/java/org/sopt/app/application/playground/PlaygroundClient.java +++ b/src/main/java/org/sopt/app/application/playground/PlaygroundClient.java @@ -10,6 +10,7 @@ import org.sopt.app.application.playground.dto.PlaygroundUserFindCondition; import org.sopt.app.application.playground.dto.RecommendedFriendInfo.PlaygroundUserIds; import org.sopt.app.presentation.auth.AppAuthRequest.*; +import org.sopt.app.presentation.home.response.RecentPostsResponse; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.web.bind.annotation.RequestBody; @@ -45,4 +46,8 @@ PlaygroundUserIds getPlaygroundUserIdsByCondition(@HeaderMap Map @RequestLine("GET /api/v1/community/posts/hot") PlaygroundPostResponse getPlaygroundHotPost(@HeaderMap Map headers); + + @RequestLine("GET /internal/api/v1/community/post/recent?category={category}") + RecentPostsResponse getRecentPosts(@HeaderMap Map headers, @Param("category") String category); + } diff --git a/src/main/java/org/sopt/app/facade/HomeFacade.java b/src/main/java/org/sopt/app/facade/HomeFacade.java index 466732aa..e5cd33f6 100755 --- a/src/main/java/org/sopt/app/facade/HomeFacade.java +++ b/src/main/java/org/sopt/app/facade/HomeFacade.java @@ -13,6 +13,7 @@ import org.sopt.app.domain.entity.User; import org.sopt.app.domain.enums.UserStatus; import org.sopt.app.presentation.home.HomeDescriptionResponse; +import org.sopt.app.presentation.home.response.RecentPostsResponse; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -67,4 +68,15 @@ private boolean isServiceVisibleToUser(AppServiceInfo appServiceInfo, User user) return false; } + + public List getRecentPosts(User user) { + return playgroundAuthService.getRecentPosts(user.getPlaygroundToken()).stream() + .map(post -> RecentPostsResponse.builder() + .id(post.getId()) + .title(post.getTitle()) + .category(post.getCategory()) + .isHotPost(post.isHotPost()) + .build() + ).toList(); + } } diff --git a/src/main/java/org/sopt/app/presentation/home/HomeController.java b/src/main/java/org/sopt/app/presentation/home/HomeController.java index 23f1ee75..7694c951 100644 --- a/src/main/java/org/sopt/app/presentation/home/HomeController.java +++ b/src/main/java/org/sopt/app/presentation/home/HomeController.java @@ -10,6 +10,7 @@ import org.sopt.app.application.app_service.dto.AppServiceEntryStatusResponse; import org.sopt.app.domain.entity.User; import org.sopt.app.facade.HomeFacade; +import org.sopt.app.presentation.home.response.RecentPostsResponse; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -51,4 +52,19 @@ public ResponseEntity> getAppService( homeFacade.checkAppServiceEntryStatus(user) ); } + + @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("/posts") + public ResponseEntity> getRecentPost( + @AuthenticationPrincipal User user + ) { + return ResponseEntity.ok( + homeFacade.getRecentPosts(user) + ); + } } diff --git a/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java b/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java new file mode 100644 index 00000000..e203faff --- /dev/null +++ b/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java @@ -0,0 +1,18 @@ +package org.sopt.app.presentation.home.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RecentPostsResponse { + private Long id; + private String title; + private String category; + private String content; + private boolean isHotPost; +} \ No newline at end of file From b0bccee7f43a557eb3500d1fdec1db748bff955e Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 14 Nov 2024 16:10:51 +0900 Subject: [PATCH 2/5] =?UTF-8?q?[refactor]=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20(#434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../playground/PlaygroundAuthService.java | 18 +++--------------- .../home/response/RecentPostsResponse.java | 11 +++++++++++ 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java index 91c3d102..52f4a268 100755 --- a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java +++ b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java @@ -182,22 +182,10 @@ public List getRecentPosts(String playgroundToken) { final Map accessToken = createAuthorizationHeaderByUserPlaygroundToken(playgroundToken); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { List categories = List.of("SOPT 활동", "자유", "파트"); - - CompletableFuture hotPostFuture = CompletableFuture.supplyAsync(() -> { - PlaygroundPostResponse hotpost = playgroundClient.getPlaygroundHotPost(accessToken); - return RecentPostsResponse.builder() - .category("HOT") - .isHotPost(true) - .content(hotpost.content()) - .title(hotpost.title()) - .id(hotpost.postId()) - .build(); - }, executor); + CompletableFuture hotPostFuture = CompletableFuture.supplyAsync(() -> + RecentPostsResponse.of(playgroundClient.getPlaygroundHotPost(accessToken)), executor); List> categoryFutures = categories.stream() - .map(category -> CompletableFuture.supplyAsync(() -> { - RecentPostsResponse recentPosts = playgroundClient.getRecentPosts(accessToken, category); - return recentPosts; - }, executor)) + .map(category -> CompletableFuture.supplyAsync(() -> playgroundClient.getRecentPosts(accessToken, category), executor)) .toList(); List> allFutures = new ArrayList<>(categoryFutures); allFutures.addFirst(hotPostFuture); diff --git a/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java b/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java index e203faff..d6dbcf83 100644 --- a/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java +++ b/src/main/java/org/sopt/app/presentation/home/response/RecentPostsResponse.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.sopt.app.application.playground.dto.PlaygroundPostInfo.PlaygroundPostResponse; @Data @Builder @@ -15,4 +16,14 @@ public class RecentPostsResponse { private String category; private String content; private boolean isHotPost; + + public static RecentPostsResponse of(PlaygroundPostResponse playgroundPostResponse) { + return RecentPostsResponse.builder() + .id(playgroundPostResponse.postId()) + .title(playgroundPostResponse.title()) + .category("HOT") + .content(playgroundPostResponse.content()) + .isHotPost(true) + .build(); + } } \ No newline at end of file From 098481e8a87a5aa8cc36f627b94b0779dc95feaa Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 14 Nov 2024 16:17:13 +0900 Subject: [PATCH 3/5] =?UTF-8?q?[fix]=20;=20=EC=B6=94=EA=B0=80=20(#434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/sopt/app/presentation/home/HomeController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/sopt/app/presentation/home/HomeController.java b/src/main/java/org/sopt/app/presentation/home/HomeController.java index bc1b56c8..6b867c25 100644 --- a/src/main/java/org/sopt/app/presentation/home/HomeController.java +++ b/src/main/java/org/sopt/app/presentation/home/HomeController.java @@ -66,9 +66,9 @@ public ResponseEntity> getRecentPost( @AuthenticationPrincipal User user ) { return ResponseEntity.ok( - homeFacade.getRecentPosts(user) + homeFacade.getRecentPosts(user)); } - + @ApiResponses({ @ApiResponse(responseCode = "200", description = "success"), @ApiResponse(responseCode = "401", description = "token error", content = @Content), From 46df82dc84d03f9a4c60850971d63ee48b158592 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 14 Nov 2024 19:25:42 +0900 Subject: [PATCH 4/5] =?UTF-8?q?[feat]=20=ED=8F=AC=EC=8A=A4=ED=8C=85=20?= =?UTF-8?q?=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=20enum=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(#434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../playground/dto/PlayGroundPostCategory.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/org/sopt/app/application/playground/dto/PlayGroundPostCategory.java diff --git a/src/main/java/org/sopt/app/application/playground/dto/PlayGroundPostCategory.java b/src/main/java/org/sopt/app/application/playground/dto/PlayGroundPostCategory.java new file mode 100644 index 00000000..e88a317c --- /dev/null +++ b/src/main/java/org/sopt/app/application/playground/dto/PlayGroundPostCategory.java @@ -0,0 +1,17 @@ +package org.sopt.app.application.playground.dto; + +public enum PlayGroundPostCategory { + SOPT_ACTIVITY("SOPT 활동"), + FREE("자유"), + PART("파트"); + private final String displayName; + + PlayGroundPostCategory(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return displayName; + } +} + From 8c18846cbc599931498027454ade382cad18b382 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 14 Nov 2024 19:25:59 +0900 Subject: [PATCH 5/5] =?UTF-8?q?[refactor]=20enum=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20(#434)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../playground/PlaygroundAuthService.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java index 0e607d7a..57a124c8 100755 --- a/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java +++ b/src/main/java/org/sopt/app/application/playground/PlaygroundAuthService.java @@ -16,10 +16,9 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.val; -import org.sopt.app.application.playground.dto.PlayGroundEmploymentResponse; -import org.sopt.app.application.playground.dto.PlaygroundPostInfo.*; -import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.*; import org.sopt.app.application.auth.dto.PlaygroundAuthTokenInfo.RefreshedToken; +import org.sopt.app.application.playground.dto.PlayGroundEmploymentResponse; +import org.sopt.app.application.playground.dto.PlayGroundPostCategory; import org.sopt.app.application.playground.dto.PlaygroundPostInfo.PlaygroundPost; import org.sopt.app.application.playground.dto.PlaygroundPostInfo.PlaygroundPostResponse; import org.sopt.app.application.playground.dto.PlaygroundProfileInfo.ActiveUserIds; @@ -34,9 +33,10 @@ import org.sopt.app.common.exception.UnauthorizedException; import org.sopt.app.common.response.ErrorCode; import org.sopt.app.domain.enums.UserStatus; -import org.sopt.app.presentation.home.response.RecentPostsResponse; -import org.sopt.app.presentation.auth.AppAuthRequest.*; +import org.sopt.app.presentation.auth.AppAuthRequest.AccessTokenRequest; +import org.sopt.app.presentation.auth.AppAuthRequest.CodeRequest; import org.sopt.app.presentation.home.response.EmploymentPostResponse; +import org.sopt.app.presentation.home.response.RecentPostsResponse; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.web.client.HttpClientErrorException.BadRequest; @@ -184,18 +184,18 @@ public boolean isCurrentGeneration(Long generation) { public List getRecentPosts(String playgroundToken) { final Map accessToken = createAuthorizationHeaderByUserPlaygroundToken(playgroundToken); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { - List categories = List.of("SOPT 활동", "자유", "파트"); + List categories = List.of(PlayGroundPostCategory.SOPT_ACTIVITY, PlayGroundPostCategory.FREE, PlayGroundPostCategory.PART); CompletableFuture hotPostFuture = CompletableFuture.supplyAsync(() -> RecentPostsResponse.of(playgroundClient.getPlaygroundHotPost(accessToken)), executor); List> categoryFutures = categories.stream() - .map(category -> CompletableFuture.supplyAsync(() -> playgroundClient.getRecentPosts(accessToken, category), executor)) + .map(category -> CompletableFuture.supplyAsync(() -> playgroundClient.getRecentPosts(accessToken, category.getDisplayName()), executor)) .toList(); List> allFutures = new ArrayList<>(categoryFutures); allFutures.addFirst(hotPostFuture); CompletableFuture allOf = CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[0])); return allOf.thenApply(v -> allFutures.stream() .map(CompletableFuture::join) - .collect(Collectors.toList())) + .toList()) .join(); } }