diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickService.java index afc2f82d..d6d7f469 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickService.java @@ -51,7 +51,7 @@ @Service @Transactional(readOnly = true) -public class GuestPickService extends PickCommonService implements PickService { +public class GuestPickService extends PickCommonService implements PickServiceV1 { public static final String INVALID_ANONYMOUS_CAN_NOT_USE_THIS_FUNCTION_MESSAGE = "비회원은 현재 해당 기능을 이용할 수 없습니다."; diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickServiceV2.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickServiceV2.java new file mode 100644 index 00000000..e24f1682 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/GuestPickServiceV2.java @@ -0,0 +1,51 @@ +package com.dreamypatisiel.devdevdev.domain.service.pick; + +import com.dreamypatisiel.devdevdev.domain.policy.PickBestCommentsPolicy; +import com.dreamypatisiel.devdevdev.domain.policy.PickPopularScorePolicy; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickCommentRecommendRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickCommentRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; +import com.dreamypatisiel.devdevdev.global.common.TimeProvider; +import com.dreamypatisiel.devdevdev.openai.embeddings.EmbeddingsService; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional(readOnly = true) +public class GuestPickServiceV2 extends PickCommonService implements PickServiceV2 { + public GuestPickServiceV2(EmbeddingsService embeddingsService, + PickBestCommentsPolicy pickBestCommentsPolicy, + PickPopularScorePolicy pickPopularScorePolicy, + TimeProvider timeProvider, + PickRepository pickRepository, + PickCommentRepository pickCommentRepository, + PickCommentRecommendRepository pickCommentRecommendRepository) { + super(embeddingsService, pickBestCommentsPolicy, pickPopularScorePolicy, timeProvider, pickRepository, + pickCommentRepository, pickCommentRecommendRepository); + } + + @Override + public Slice findPicksMain(Pageable pageable, Long pickId, PickSort pickSort, String anonymousMemberId, Authentication authentication) { + return null; + } + + @Override + public PickDetailResponse findPickDetail(Long pickId, String anonymousMemberId, Authentication authentication) { + return null; + } + + @Override + public List findTop3SimilarPicks(Long pickId) { + return null; + } + +} diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickService.java index d907a0fb..9202c4f0 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickService.java @@ -72,7 +72,7 @@ @Service @Transactional(readOnly = true) -public class MemberPickService extends PickCommonService implements PickService { +public class MemberPickService extends PickCommonService implements PickServiceV1 { public static final String FIRST_PICK_OPTION_IMAGE = "firstPickOptionImage"; public static final String SECOND_PICK_OPTION_IMAGE = "secondPickOptionImage"; diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickServiceV2.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickServiceV2.java new file mode 100644 index 00000000..5102de41 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/MemberPickServiceV2.java @@ -0,0 +1,52 @@ +package com.dreamypatisiel.devdevdev.domain.service.pick; + +import com.dreamypatisiel.devdevdev.domain.policy.PickBestCommentsPolicy; +import com.dreamypatisiel.devdevdev.domain.policy.PickPopularScorePolicy; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickCommentRecommendRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickCommentRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickRepository; +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; +import com.dreamypatisiel.devdevdev.global.common.TimeProvider; +import com.dreamypatisiel.devdevdev.openai.embeddings.EmbeddingsService; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional(readOnly = true) +public class MemberPickServiceV2 extends PickCommonService implements PickServiceV2 { + + public MemberPickServiceV2(EmbeddingsService embeddingsService, + PickBestCommentsPolicy pickBestCommentsPolicy, + PickPopularScorePolicy pickPopularScorePolicy, + TimeProvider timeProvider, + PickRepository pickRepository, + PickCommentRepository pickCommentRepository, + PickCommentRecommendRepository pickCommentRecommendRepository) { + super(embeddingsService, pickBestCommentsPolicy, pickPopularScorePolicy, timeProvider, pickRepository, + pickCommentRepository, pickCommentRecommendRepository); + } + + @Override + public Slice findPicksMain(Pageable pageable, Long pickId, PickSort pickSort, String anonymousMemberId, Authentication authentication) { + return null; + } + + @Override + public PickDetailResponse findPickDetail(Long pickId, String anonymousMemberId, Authentication authentication) { + return null; + } + + @Override + public List findTop3SimilarPicks(Long pickId) { + return null; + } + +} diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickFacadeService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickFacadeService.java index 6ea030fc..416cd6e7 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickFacadeService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickFacadeService.java @@ -18,7 +18,7 @@ @RequiredArgsConstructor public class PickFacadeService { - private PickService pickService; + private PickServiceV1 pickService; private final EmbeddingsService embeddingsService; @Transactional @@ -54,12 +54,12 @@ public PickModifyResponse modifyPickAndSaveEmbedding(Long pickId, return response; } - public void injectPickService(PickService pickService) { + public void injectPickService(PickServiceV1 pickService) { validatePickService(pickService); this.pickService = pickService; } - private void validatePickService(PickService pickService) { + private void validatePickService(PickServiceV1 pickService) { if (ObjectUtils.isEmpty(pickService)) { throw new IllegalStateException("Pick service cannot be empty"); } diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickService.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickService.java index 77455529..d93220dc 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickService.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickService.java @@ -1,39 +1,8 @@ package com.dreamypatisiel.devdevdev.domain.service.pick; -import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; -import com.dreamypatisiel.devdevdev.domain.service.pick.dto.VotePickOptionDto; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickRequest; -import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickRequest; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickModifyResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickRegisterResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickUploadImageResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; -import com.dreamypatisiel.devdevdev.web.dto.response.pick.VotePickResponse; -import java.util.List; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.security.core.Authentication; -import org.springframework.web.multipart.MultipartFile; - +/** + * PickService의 공통 인터페이스 + * 각 버전별 인터페이스에서 상속받아 사용 + */ public interface PickService { - Slice findPicksMain(Pageable pageable, Long pickId, PickSort pickSort, String anonymousMemberId, - Authentication authentication); - - PickUploadImageResponse uploadImages(String name, List images); - - void deleteImage(Long pickOptionImageId); - - PickRegisterResponse registerPick(RegisterPickRequest registerPickRequest, Authentication authentication); - - PickModifyResponse modifyPick(Long pickId, ModifyPickRequest modifyPickRequest, Authentication authentication); - - PickDetailResponse findPickDetail(Long pickId, String anonymousMemberId, Authentication authentication); - - VotePickResponse votePickOption(VotePickOptionDto votePickOptionDto, Authentication authentication); - - void deletePick(Long pickId, Authentication authentication); - - List findTop3SimilarPicks(Long pickId); } \ No newline at end of file diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategy.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategy.java index 17b4d73f..542a55c9 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategy.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategy.java @@ -1,6 +1,7 @@ package com.dreamypatisiel.devdevdev.domain.service.pick; import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; +import com.dreamypatisiel.devdevdev.web.controller.ApiVersion; import lombok.RequiredArgsConstructor; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @@ -11,11 +12,15 @@ public class PickServiceStrategy { private final ApplicationContext applicationContext; - public PickService getPickService() { - if (AuthenticationMemberUtils.isAnonymous()) { - return applicationContext.getBean(GuestPickService.class); - } - return applicationContext.getBean(MemberPickService.class); + public PickService getPickService(ApiVersion apiVersion) { + return switch (apiVersion) { + case V1 -> AuthenticationMemberUtils.isAnonymous() + ? applicationContext.getBean(GuestPickService.class) + : applicationContext.getBean(MemberPickService.class); + case V2 -> AuthenticationMemberUtils.isAnonymous() + ? applicationContext.getBean(GuestPickServiceV2.class) + : applicationContext.getBean(MemberPickServiceV2.class); + }; } public PickCommentService pickCommentService() { diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV1.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV1.java new file mode 100644 index 00000000..da150dc8 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV1.java @@ -0,0 +1,39 @@ +package com.dreamypatisiel.devdevdev.domain.service.pick; + +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; +import com.dreamypatisiel.devdevdev.domain.service.pick.dto.VotePickOptionDto; +import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickRequest; +import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickRequest; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickModifyResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickRegisterResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickUploadImageResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.VotePickResponse; +import java.util.List; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.core.Authentication; +import org.springframework.web.multipart.MultipartFile; + +public interface PickServiceV1 extends PickService { + Slice findPicksMain(Pageable pageable, Long pickId, PickSort pickSort, String anonymousMemberId, + Authentication authentication); + + PickUploadImageResponse uploadImages(String name, List images); + + void deleteImage(Long pickOptionImageId); + + PickRegisterResponse registerPick(RegisterPickRequest registerPickRequest, Authentication authentication); + + PickModifyResponse modifyPick(Long pickId, ModifyPickRequest modifyPickRequest, Authentication authentication); + + PickDetailResponse findPickDetail(Long pickId, String anonymousMemberId, Authentication authentication); + + VotePickResponse votePickOption(VotePickOptionDto votePickOptionDto, Authentication authentication); + + void deletePick(Long pickId, Authentication authentication); + + List findTop3SimilarPicks(Long pickId); +} diff --git a/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV2.java b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV2.java new file mode 100644 index 00000000..1d0b2818 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceV2.java @@ -0,0 +1,20 @@ +package com.dreamypatisiel.devdevdev.domain.service.pick; + +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.security.core.Authentication; + +import java.util.List; + +public interface PickServiceV2 extends PickService { + Slice findPicksMain(Pageable pageable, Long pickId, PickSort pickSort, String anonymousMemberId, + Authentication authentication); + + PickDetailResponse findPickDetail(Long pickId, String anonymousMemberId, Authentication authentication); + + List findTop3SimilarPicks(Long pickId); +} \ No newline at end of file diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/ApiVersion.java b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/ApiVersion.java new file mode 100644 index 00000000..132d46f4 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/ApiVersion.java @@ -0,0 +1,6 @@ +package com.dreamypatisiel.devdevdev.web.controller; + +public enum ApiVersion { + V1, + V2 +} diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickController.java b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickController.java index ecef1fd7..6450d49c 100644 --- a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickController.java +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickController.java @@ -4,8 +4,8 @@ import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; import com.dreamypatisiel.devdevdev.domain.service.pick.PickFacadeService; -import com.dreamypatisiel.devdevdev.domain.service.pick.PickService; import com.dreamypatisiel.devdevdev.domain.service.pick.PickServiceStrategy; +import com.dreamypatisiel.devdevdev.domain.service.pick.PickServiceV1; import com.dreamypatisiel.devdevdev.domain.service.pick.dto.VotePickOptionDto; import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; import com.dreamypatisiel.devdevdev.global.utils.HttpRequestUtils; @@ -13,6 +13,7 @@ import com.dreamypatisiel.devdevdev.openai.data.response.Embedding; import com.dreamypatisiel.devdevdev.openai.data.response.OpenAIResponse; import com.dreamypatisiel.devdevdev.openai.embeddings.EmbeddingRequestHandler; +import com.dreamypatisiel.devdevdev.web.controller.ApiVersion; import com.dreamypatisiel.devdevdev.web.dto.request.pick.ModifyPickRequest; import com.dreamypatisiel.devdevdev.web.dto.request.pick.RegisterPickRequest; import com.dreamypatisiel.devdevdev.web.dto.request.pick.VotePickOptionRequest; @@ -69,7 +70,7 @@ public ResponseEntity>> getPicksMain( Authentication authentication = AuthenticationMemberUtils.getAuthentication(); String anonymousMemberId = HttpRequestUtils.getHeaderValue(HEADER_ANONYMOUS_MEMBER_ID); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); Slice response = pickService.findPicksMain(pageable, pickId, pickSort, anonymousMemberId, authentication); @@ -83,7 +84,7 @@ public ResponseEntity> uploadPickOptionIm @RequestParam String name, @RequestPart List pickOptionImages) { - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); PickUploadImageResponse pickUploadImageResponse = pickService.uploadImages(name, pickOptionImages); return ResponseEntity.ok(BasicResponse.success(pickUploadImageResponse)); @@ -93,7 +94,7 @@ public ResponseEntity> uploadPickOptionIm @DeleteMapping("/picks/image/{pickOptionImageId}") public ResponseEntity> deletePickImage(@PathVariable Long pickOptionImageId) { - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); pickService.deleteImage(pickOptionImageId); return ResponseEntity.ok(BasicResponse.success()); @@ -110,7 +111,7 @@ public ResponseEntity> registerPick( OpenAIResponse embeddingOpenAIResponse = embeddingRequestHandler.postEmbeddings( EmbeddingRequest.createTextEmbedding3Small(registerPickRequest.getPickTitle())); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); pickFacadeService.injectPickService(pickService); @@ -133,7 +134,7 @@ public ResponseEntity> modifyPick( OpenAIResponse embeddingOpenAIResponse = embeddingRequestHandler.postEmbeddings( EmbeddingRequest.createTextEmbedding3Small(modifyPickRequest.getPickTitle())); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); pickFacadeService.injectPickService(pickService); @@ -150,7 +151,7 @@ public ResponseEntity> getPickDetail(@PathVari @RequestHeader(value = HEADER_ANONYMOUS_MEMBER_ID, required = false) String anonymousMemberId) { Authentication authentication = AuthenticationMemberUtils.getAuthentication(); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); PickDetailResponse response = pickService.findPickDetail(pickId, anonymousMemberId, authentication); return ResponseEntity.ok(BasicResponse.success(response)); @@ -164,7 +165,7 @@ public ResponseEntity> votePickOption( Authentication authentication = AuthenticationMemberUtils.getAuthentication(); String anonymousMemberId = HttpRequestUtils.getHeaderValue(HEADER_ANONYMOUS_MEMBER_ID); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); VotePickOptionDto votePickOptionDto = VotePickOptionDto.of(votePickOptionRequest, anonymousMemberId); VotePickResponse response = pickService.votePickOption(votePickOptionDto, authentication); @@ -177,7 +178,7 @@ public ResponseEntity> votePickOption( public ResponseEntity> deletePick(@PathVariable Long pickId) { Authentication authentication = AuthenticationMemberUtils.getAuthentication(); - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); pickService.deletePick(pickId, authentication); return ResponseEntity.ok(BasicResponse.success()); @@ -187,7 +188,7 @@ public ResponseEntity> deletePick(@PathVariable Long pickId) @GetMapping("picks/{pickId}/similarties") public ResponseEntity> getSimilarPicks(@PathVariable Long pickId) { - PickService pickService = pickServiceStrategy.getPickService(); + PickServiceV1 pickService = (PickServiceV1) pickServiceStrategy.getPickService(ApiVersion.V1); List response = pickService.findTop3SimilarPicks(pickId); return ResponseEntity.ok(BasicResponse.success(response)); diff --git a/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickControllerV2.java b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickControllerV2.java new file mode 100644 index 00000000..ef08db98 --- /dev/null +++ b/src/main/java/com/dreamypatisiel/devdevdev/web/controller/pick/PickControllerV2.java @@ -0,0 +1,76 @@ +package com.dreamypatisiel.devdevdev.web.controller.pick; + +import com.dreamypatisiel.devdevdev.domain.repository.pick.PickSort; +import com.dreamypatisiel.devdevdev.domain.service.pick.PickFacadeService; +import com.dreamypatisiel.devdevdev.domain.service.pick.PickServiceV2; +import com.dreamypatisiel.devdevdev.domain.service.pick.PickServiceStrategy; +import com.dreamypatisiel.devdevdev.global.utils.AuthenticationMemberUtils; +import com.dreamypatisiel.devdevdev.global.utils.HttpRequestUtils; +import com.dreamypatisiel.devdevdev.openai.embeddings.EmbeddingRequestHandler; +import com.dreamypatisiel.devdevdev.web.controller.ApiVersion; +import com.dreamypatisiel.devdevdev.web.dto.response.BasicResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickDetailResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.PickMainResponse; +import com.dreamypatisiel.devdevdev.web.dto.response.pick.SimilarPickResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.data.web.PageableDefault; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static com.dreamypatisiel.devdevdev.web.WebConstant.HEADER_ANONYMOUS_MEMBER_ID; + +@Tag(name = "픽픽픽 API", description = "") +@RestController +@RequiredArgsConstructor +@RequestMapping("/devdevdev/api/v2") +public class PickControllerV2 { + + private final PickServiceStrategy pickServiceStrategy; + + @Operation(summary = "픽픽픽 메인 조회", description = "픽픽픽 메인 페이지에 필요한 데이터를 커서 방식으로 조회합니다.") + @GetMapping("/picks") + public ResponseEntity>> getPicksMain( + @PageableDefault(sort = "id", direction = Direction.DESC) Pageable pageable, + @RequestParam(required = false) Long pickId, + @RequestParam(required = false) PickSort pickSort) { + + Authentication authentication = AuthenticationMemberUtils.getAuthentication(); + String anonymousMemberId = HttpRequestUtils.getHeaderValue(HEADER_ANONYMOUS_MEMBER_ID); + + PickServiceV2 pickService = (PickServiceV2) pickServiceStrategy.getPickService(ApiVersion.V2); + Slice response = pickService.findPicksMain(pageable, pickId, pickSort, anonymousMemberId, + authentication); + + return ResponseEntity.ok(BasicResponse.success(response)); + } + + @Operation(summary = "픽픽픽 상세 조회", description = "픽픽픽 상세 페이지를 조회합니다.") + @GetMapping("/picks/{pickId}") + public ResponseEntity> getPickDetail(@PathVariable Long pickId, + @RequestHeader(value = HEADER_ANONYMOUS_MEMBER_ID, required = false) String anonymousMemberId) { + Authentication authentication = AuthenticationMemberUtils.getAuthentication(); + + PickServiceV2 pickService = (PickServiceV2) pickServiceStrategy.getPickService(ApiVersion.V2); + PickDetailResponse response = pickService.findPickDetail(pickId, anonymousMemberId, authentication); + + return ResponseEntity.ok(BasicResponse.success(response)); + } + + @Operation(summary = "나도 고민했는데 픽픽픽", description = "픽픽픽 상세와 유사한 성격의 픽픽픽 3개를 추천합니다.") + @GetMapping("picks/{pickId}/similarties") + public ResponseEntity> getSimilarPicks(@PathVariable Long pickId) { + + PickServiceV2 pickService = (PickServiceV2) pickServiceStrategy.getPickService(ApiVersion.V2); + List response = pickService.findTop3SimilarPicks(pickId); + + return ResponseEntity.ok(BasicResponse.success(response)); + } +} diff --git a/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategyTest.java b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategyTest.java new file mode 100644 index 00000000..1858d907 --- /dev/null +++ b/src/test/java/com/dreamypatisiel/devdevdev/domain/service/pick/PickServiceStrategyTest.java @@ -0,0 +1,98 @@ +package com.dreamypatisiel.devdevdev.domain.service.pick; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.when; + +import com.dreamypatisiel.devdevdev.domain.entity.enums.SocialType; +import com.dreamypatisiel.devdevdev.global.security.oauth2.model.UserPrincipal; +import com.dreamypatisiel.devdevdev.web.controller.ApiVersion; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.transaction.annotation.Transactional; + +@SpringBootTest +@Transactional +class PickServiceStrategyTest { + + @Autowired + PickServiceStrategy pickServiceStrategy; + + @Mock + Authentication authentication; + + @Mock + SecurityContext securityContext; + + @Test + @DisplayName("V1이면서 익명 사용자이면 GuestPickService를 반환한다.") + void getPickService_V1_Anonymous() { + // given + when(authentication.getPrincipal()).thenReturn("anonymousUser"); + when(securityContext.getAuthentication()).thenReturn(authentication); + SecurityContextHolder.setContext(securityContext); + + // when + PickService result = pickServiceStrategy.getPickService(ApiVersion.V1); + + // then + assertThat(result).isInstanceOf(GuestPickService.class); + } + + @Test + @DisplayName("V1이면서 로그인 사용자이면 MemberPickService를 반환한다.") + void getPickService_V1_Member() { + // given + UserPrincipal userPrincipal = UserPrincipal.createByEmailAndRoleAndSocialType( + "email@test.com", "ROLE_USER", SocialType.KAKAO.name()); + + when(authentication.getPrincipal()).thenReturn(userPrincipal); + when(securityContext.getAuthentication()).thenReturn(authentication); + SecurityContextHolder.setContext(securityContext); + + // when + PickService result = pickServiceStrategy.getPickService(ApiVersion.V1); + + // then + assertThat(result).isInstanceOf(MemberPickService.class); + } + + @Test + @DisplayName("V2이면서 익명 사용자이면 GuestPickServiceV2를 반환한다.") + void getPickService_V2_Anonymous() { + // given + when(authentication.getPrincipal()).thenReturn("anonymousUser"); + when(securityContext.getAuthentication()).thenReturn(authentication); + SecurityContextHolder.setContext(securityContext); + + // when + PickService result = pickServiceStrategy.getPickService(ApiVersion.V2); + + // then + assertThat(result).isInstanceOf(GuestPickServiceV2.class); + } + + @Test + @DisplayName("V2이면서 로그인 사용자이면 MemberPickServiceV2를 반환한다.") + void getPickService_V2_Member() { + // given + UserPrincipal userPrincipal = UserPrincipal.createByEmailAndRoleAndSocialType( + "email@test.com", "ROLE_USER", SocialType.KAKAO.name()); + + when(authentication.getPrincipal()).thenReturn(userPrincipal); + when(securityContext.getAuthentication()).thenReturn(authentication); + SecurityContextHolder.setContext(securityContext); + + // when + PickService result = pickServiceStrategy.getPickService(ApiVersion.V2); + + // then + assertThat(result).isInstanceOf(MemberPickServiceV2.class); + } +}