From 9bbaf9175780a725ea43ce17e1f3b27f537738d7 Mon Sep 17 00:00:00 2001 From: kyukong <92148749+kyukong@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:53:10 +0900 Subject: [PATCH] =?UTF-8?q?[FEATURE]=20=ED=8C=9D=EC=97=85=EC=8A=A4?= =?UTF-8?q?=ED=86=A0=EC=96=B4=20=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=9E=A9=20=EA=B4=80=EB=A0=A8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20(#13)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [FEAT] 팝업스토어 게시글 스크랩 기능 구현 * [REFACTOR] profile 설정 및 Github Actions 적용 (#12) * [REFACTOR] profile 에 따라 properties 파일 분리 * [CHORE] Dockerfile 설정 추가 * [CHORE] Github Actions 파일 작성 * [CHORE] 프로젝트 기본 설정 추가 * [CHORE] Github Actions 폴더 공백 제거 * [CHORE] Github Actions 시 Maven 빌드로 수정 * [CHORE] Github Actions 시 sudo 권한 추가 * [CHORE] Github Actions 시 push 브랜치 변경 * [REFACTOR] 팝업스토어 게시글 리스트 조회 선택 채임 mapper 로 변경 * [FEAT] 스크랩한 팝업스토어 게시글 리스트 조회 기능 구현 * [FIX] repository 계층 추가에 따라 실패하는 테스트 코드 수정 --- .../kr/popup/controller/PopupController.java | 14 ++ .../oya/kr/popup/domain/enums/PopupSort.java | 26 ++- .../popup/mapper/PopupCollectionMapper.java | 18 ++ .../com/oya/kr/popup/mapper/PopupMapper.java | 2 + .../request/PopupCollectionMapperRequest.java | 12 + .../PopupCollectionSaveMapperRequest.java | 13 ++ .../PopupCollectionMapperResponse.java | 13 ++ .../kr/popup/repository/PopupRepository.java | 65 +++--- .../oya/kr/popup/service/PopupService.java | 19 +- .../kr/popup/mapper/PopupCollectionMapper.xml | 32 +++ .../com/oya/kr/popup/mapper/PopupMapper.xml | 15 ++ src/main/resources/mybatis/mybatis-config.xml | 3 + .../mapper/PopupCollectionMapperTest.java | 215 ++++++++++++++++++ .../oya/kr/popup/mapper/PopupMapperTest.java | 33 +++ .../oya/kr/user/service/UserServiceTest.java | 21 +- 15 files changed, 456 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/oya/kr/popup/mapper/PopupCollectionMapper.java create mode 100644 src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionMapperRequest.java create mode 100644 src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionSaveMapperRequest.java create mode 100644 src/main/java/com/oya/kr/popup/mapper/dto/response/PopupCollectionMapperResponse.java create mode 100644 src/main/resources/com/oya/kr/popup/mapper/PopupCollectionMapper.xml create mode 100644 src/test/java/com/oya/kr/popup/mapper/PopupCollectionMapperTest.java diff --git a/src/main/java/com/oya/kr/popup/controller/PopupController.java b/src/main/java/com/oya/kr/popup/controller/PopupController.java index 21e687a..cc39459 100644 --- a/src/main/java/com/oya/kr/popup/controller/PopupController.java +++ b/src/main/java/com/oya/kr/popup/controller/PopupController.java @@ -112,4 +112,18 @@ public ResponseEntity> saveImage( PopupImageResponse response = popupService.saveImage(principal.getName(), image); return ResponseEntity.ok(ApplicationResponse.success(response)); } + + /** + * 팝업스토어 게시글 스크랩 / 스크랩 취소 기능 구현 + * + * @parameter Principal, Long + * @return ResponseEntity> + * @author 김유빈 + * @since 2024.02.21 + */ + @PostMapping("/{popupId}/collections") + public ResponseEntity> collect(Principal principal, @PathVariable Long popupId) { + popupService.collect(principal.getName(), popupId); + return ResponseEntity.ok(ApplicationResponse.success(null)); + } } diff --git a/src/main/java/com/oya/kr/popup/domain/enums/PopupSort.java b/src/main/java/com/oya/kr/popup/domain/enums/PopupSort.java index 2063e63..bae1460 100644 --- a/src/main/java/com/oya/kr/popup/domain/enums/PopupSort.java +++ b/src/main/java/com/oya/kr/popup/domain/enums/PopupSort.java @@ -8,8 +8,9 @@ import java.util.function.Supplier; import com.oya.kr.global.exception.ApplicationException; +import com.oya.kr.popup.mapper.PopupMapper; +import com.oya.kr.popup.mapper.dto.request.PopupSearchMapperRequest; import com.oya.kr.popup.mapper.dto.response.PopupDetailMapperResponse; -import com.oya.kr.popup.repository.PopupRepository; import lombok.Getter; @@ -19,6 +20,7 @@ public enum PopupSort { ALL("all", "모든 팝업스토어 게시글 리스트 조회"), PROGRESS("progress", "진행중인 팝업스토어 게시글 리스트 조회"), SCHEDULED("scheduled", "예정된 팝업스토어 게시글 리스트 조회"), + COLLECTIONS("collections", "스크랩한 팝업스토어 게시글 리스트 조회"), ; private final String name; @@ -52,15 +54,18 @@ public static PopupSort from(String name) { * @author 김유빈 * @since 2024.02.19 */ - public Supplier> selectForSorting(PopupRepository popupRepository, int pageNo, int amount) { + public Supplier> selectForSorting(PopupMapper popupMapper, PopupSearchMapperRequest request) { if (isAll()) { - return () -> popupRepository.findAll(pageNo, amount); + return () -> popupMapper.findAll(request); } if (isProgress()) { - return () -> popupRepository.findInProgress(pageNo, amount); + return () -> popupMapper.findInProgress(request); } if (isScheduled()) { - return () -> popupRepository.findScheduled(pageNo, amount); + return () -> popupMapper.findScheduled(request); + } + if (isCollections()) { + return () -> popupMapper.findCollections(request); } return ArrayList::new; } @@ -97,4 +102,15 @@ public boolean isProgress() { public boolean isScheduled() { return this == SCHEDULED; } + + /** + * 스크랩 조회 여부 반환 + * + * @return boolean + * @author 김유빈 + * @since 2024.02.22 + */ + public boolean isCollections() { + return this == COLLECTIONS; + } } diff --git a/src/main/java/com/oya/kr/popup/mapper/PopupCollectionMapper.java b/src/main/java/com/oya/kr/popup/mapper/PopupCollectionMapper.java new file mode 100644 index 0000000..21233d3 --- /dev/null +++ b/src/main/java/com/oya/kr/popup/mapper/PopupCollectionMapper.java @@ -0,0 +1,18 @@ +package com.oya.kr.popup.mapper; + +import java.util.Optional; + +import com.oya.kr.popup.mapper.dto.request.PopupCollectionMapperRequest; +import com.oya.kr.popup.mapper.dto.request.PopupCollectionSaveMapperRequest; +import com.oya.kr.popup.mapper.dto.response.PopupCollectionMapperResponse; + +public interface PopupCollectionMapper { + + Optional findByPopupIdAndUserId(PopupCollectionMapperRequest request); + + void save(PopupCollectionSaveMapperRequest request); + + void deleteById(Long id); + + void deleteAll(); +} diff --git a/src/main/java/com/oya/kr/popup/mapper/PopupMapper.java b/src/main/java/com/oya/kr/popup/mapper/PopupMapper.java index d9dd598..c354b23 100644 --- a/src/main/java/com/oya/kr/popup/mapper/PopupMapper.java +++ b/src/main/java/com/oya/kr/popup/mapper/PopupMapper.java @@ -26,6 +26,8 @@ public interface PopupMapper { List findScheduled(PopupSearchMapperRequest request); + List findCollections(PopupSearchMapperRequest request); + List findAllRecommended(PopupSearchMapperRequest request); void save(PopupSaveMapperRequest request); diff --git a/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionMapperRequest.java b/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionMapperRequest.java new file mode 100644 index 0000000..077cbd7 --- /dev/null +++ b/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionMapperRequest.java @@ -0,0 +1,12 @@ +package com.oya.kr.popup.mapper.dto.request; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class PopupCollectionMapperRequest { + + private final Long userId; + private final Long popupId; +} diff --git a/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionSaveMapperRequest.java b/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionSaveMapperRequest.java new file mode 100644 index 0000000..d1030d4 --- /dev/null +++ b/src/main/java/com/oya/kr/popup/mapper/dto/request/PopupCollectionSaveMapperRequest.java @@ -0,0 +1,13 @@ +package com.oya.kr.popup.mapper.dto.request; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class PopupCollectionSaveMapperRequest { + + private long popupCollectionId; + private final Long userId; + private final Long popupId; +} diff --git a/src/main/java/com/oya/kr/popup/mapper/dto/response/PopupCollectionMapperResponse.java b/src/main/java/com/oya/kr/popup/mapper/dto/response/PopupCollectionMapperResponse.java new file mode 100644 index 0000000..0501ed8 --- /dev/null +++ b/src/main/java/com/oya/kr/popup/mapper/dto/response/PopupCollectionMapperResponse.java @@ -0,0 +1,13 @@ +package com.oya.kr.popup.mapper.dto.response; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public class PopupCollectionMapperResponse { + + private long id; + private final long userId; + private final long popupId; +} diff --git a/src/main/java/com/oya/kr/popup/repository/PopupRepository.java b/src/main/java/com/oya/kr/popup/repository/PopupRepository.java index ea2efaa..3f1aadd 100644 --- a/src/main/java/com/oya/kr/popup/repository/PopupRepository.java +++ b/src/main/java/com/oya/kr/popup/repository/PopupRepository.java @@ -3,6 +3,7 @@ import static com.oya.kr.popup.exception.PopupErrorCodeList.NOT_EXIST_POPUP; import java.util.List; +import java.util.Optional; import org.springframework.stereotype.Repository; @@ -10,16 +11,22 @@ import com.oya.kr.popup.domain.Plan; import com.oya.kr.popup.domain.Popup; import com.oya.kr.popup.domain.PopupImage; +import com.oya.kr.popup.domain.enums.PopupSort; import com.oya.kr.popup.domain.enums.WithdrawalStatus; +import com.oya.kr.popup.mapper.PopupCollectionMapper; import com.oya.kr.popup.mapper.PopupImageMapper; import com.oya.kr.popup.mapper.PopupMapper; import com.oya.kr.popup.mapper.PopupViewMapper; +import com.oya.kr.popup.mapper.dto.request.PopupCollectionMapperRequest; +import com.oya.kr.popup.mapper.dto.request.PopupCollectionSaveMapperRequest; import com.oya.kr.popup.mapper.dto.request.PopupImageSaveMapperRequest; import com.oya.kr.popup.mapper.dto.request.PopupSaveMapperRequest; import com.oya.kr.popup.mapper.dto.request.PopupSearchMapperRequest; import com.oya.kr.popup.mapper.dto.request.PopupViewCreateOrUpdateMapperRequest; +import com.oya.kr.popup.mapper.dto.response.PopupCollectionMapperResponse; import com.oya.kr.popup.mapper.dto.response.PopupDetailMapperResponse; import com.oya.kr.popup.mapper.dto.response.PopupMapperResponse; +import com.oya.kr.user.domain.User; import lombok.RequiredArgsConstructor; @@ -34,6 +41,7 @@ public class PopupRepository { private final PopupMapper popupMapper; private final PopupImageMapper popupImageMapper; private final PopupViewMapper popupViewMapper; + private final PopupCollectionMapper popupCollectionMapper; /** * repository 계층으로 분리 @@ -57,7 +65,7 @@ public Popup findById(Long id, Plan plan) { * @author 김유빈 * @since 2024.02.21 */ - public PopupDetailMapperResponse findByIdWithDate(Long id, Long userId) { + public PopupDetailMapperResponse findByIdWithView(Long id, Long userId) { countView(userId, id); return popupMapper.findByIdWithDate(id) .orElseThrow(() -> new ApplicationException(NOT_EXIST_POPUP)); @@ -78,37 +86,14 @@ public List findAllByPlanId(Long planId) { /** * repository 계층으로 분리 * - * @parameter int, int - * @return List - * @author 김유빈 - * @since 2024.02.21 - */ - public List findAll(int pageNo, int amount) { - return popupMapper.findAll(new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount)); - } - - /** - * repository 계층으로 분리 - * - * @parameter int, int - * @return List - * @author 김유빈 - * @since 2024.02.21 - */ - public List findInProgress(int pageNo, int amount) { - return popupMapper.findInProgress(new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount)); - } - - /** - * repository 계층으로 분리 - * - * @parameter int, int + * @parameter PopupSort, int, int * @return List * @author 김유빈 - * @since 2024.02.21 + * @since 2024.02.22 */ - public List findScheduled(int pageNo, int amount) { - return popupMapper.findScheduled(new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount)); + public List findAll(PopupSort popupSort, int pageNo, int amount) { + PopupSearchMapperRequest request = new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount); + return popupSort.selectForSorting(popupMapper, request).get(); } /** @@ -143,8 +128,7 @@ public void save(Popup popup, Plan plan, String thumbnailUrl) { /** * repository 계층으로 분리 * - * @parameter Popup - * @return long + * @parameter PopupImage * @author 김유빈 * @since 2024.02.21 */ @@ -153,6 +137,25 @@ public void saveImage(PopupImage popupImage) { popupImageMapper.save(popupImageSaveMapperRequest); } + /** + * 팝업스토어 게시글 스크랩 / 스크랩 취소 기능 구현 + * + * @parameter Popup, User + * @author 김유빈 + * @since 2024.02.21 + */ + public void collect(Popup popup, User user) { + Optional popupCollection = popupCollectionMapper.findByPopupIdAndUserId( + new PopupCollectionMapperRequest(user.getId(), popup.getId())); + + if (popupCollection.isPresent()) { + PopupCollectionMapperResponse savedPopupCollection = popupCollection.get(); + popupCollectionMapper.deleteById(savedPopupCollection.getId()); + } else { + popupCollectionMapper.save(new PopupCollectionSaveMapperRequest(user.getId(), popup.getId())); + } + } + private void countView(Long id, Long userId) { PopupViewCreateOrUpdateMapperRequest request = new PopupViewCreateOrUpdateMapperRequest(userId, id); popupViewMapper.createOrUpdatePopupView(request); diff --git a/src/main/java/com/oya/kr/popup/service/PopupService.java b/src/main/java/com/oya/kr/popup/service/PopupService.java index 6fb132a..16eb476 100644 --- a/src/main/java/com/oya/kr/popup/service/PopupService.java +++ b/src/main/java/com/oya/kr/popup/service/PopupService.java @@ -52,7 +52,7 @@ public class PopupService { @Transactional(readOnly = true) public PopupResponse findById(String email, Long popupId) { User savedUser = userRepository.findByEmail(email); - PopupDetailMapperResponse popupMapperResponse = popupRepository.findByIdWithDate(savedUser.getId(), popupId); + PopupDetailMapperResponse popupMapperResponse = popupRepository.findByIdWithView(savedUser.getId(), popupId); return PopupResponse.from(popupMapperResponse); } @@ -67,8 +67,8 @@ public PopupResponse findById(String email, Long popupId) { @Transactional(readOnly = true) public PopupsListResponse findAll(String email, PaginationRequest paginationRequest, String sort) { PopupSort popupSort = PopupSort.from(sort); - List mapperResponses = popupSort.selectForSorting( - popupRepository, paginationRequest.getPageNo(), paginationRequest.getAmount()).get(); + List mapperResponses = popupRepository.findAll(popupSort, + paginationRequest.getPageNo(), paginationRequest.getAmount()); return PopupsListResponse.from(mapperResponses); } @@ -123,6 +123,19 @@ public PopupImageResponse saveImage(String email, MultipartFile image) { return new PopupImageResponse(s3Connector.save(image)); } + /** + * 팝업스토어 게시글 스크랩 / 스크랩 취소 기능 구현 + * + * @parameter String, Long + * @author 김유빈 + * @since 2024.02.21 + */ + public void collect(String email, Long popupId) { + User savedUser = userRepository.findByEmail(email); + Popup savedPopup = popupRepository.findById(popupId, null); + popupRepository.collect(savedPopup, savedUser); + } + private void validatePlanDoesNotHavePopup(Plan plan) { if (!popupRepository.findAllByPlanId(plan.getId()).isEmpty()) { throw new ApplicationException(PLAN_HAS_POPUP); diff --git a/src/main/resources/com/oya/kr/popup/mapper/PopupCollectionMapper.xml b/src/main/resources/com/oya/kr/popup/mapper/PopupCollectionMapper.xml new file mode 100644 index 0000000..421dd2d --- /dev/null +++ b/src/main/resources/com/oya/kr/popup/mapper/PopupCollectionMapper.xml @@ -0,0 +1,32 @@ + + + + + + + + INSERT INTO POPUP_COLLECTION (USER_ID, POPUP_ID) + VALUES (#{userId}, #{popupId}) + + SELECT NVL(MAX(ID), 0) + FROM POPUP_COLLECTION + + + + + DELETE FROM POPUP_COLLECTION + WHERE ID = #{id} + + + + DELETE + FROM POPUP_COLLECTION + + + diff --git a/src/main/resources/com/oya/kr/popup/mapper/PopupMapper.xml b/src/main/resources/com/oya/kr/popup/mapper/PopupMapper.xml index 8c61808..b21bdcf 100644 --- a/src/main/resources/com/oya/kr/popup/mapper/PopupMapper.xml +++ b/src/main/resources/com/oya/kr/popup/mapper/PopupMapper.xml @@ -52,6 +52,19 @@ + +