Skip to content

Commit

Permalink
[FEATURE] 팝업스토어 게시글 스크랩 관련 기능 구현 (#13)
Browse files Browse the repository at this point in the history
* [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 계층 추가에 따라 실패하는 테스트 코드 수정
  • Loading branch information
kyukong authored Feb 22, 2024
1 parent fecf949 commit 9bbaf91
Show file tree
Hide file tree
Showing 15 changed files with 456 additions and 45 deletions.
14 changes: 14 additions & 0 deletions src/main/java/com/oya/kr/popup/controller/PopupController.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,18 @@ public ResponseEntity<ApplicationResponse<PopupImageResponse>> saveImage(
PopupImageResponse response = popupService.saveImage(principal.getName(), image);
return ResponseEntity.ok(ApplicationResponse.success(response));
}

/**
* 팝업스토어 게시글 스크랩 / 스크랩 취소 기능 구현
*
* @parameter Principal, Long
* @return ResponseEntity<ApplicationResponse<Void>>
* @author 김유빈
* @since 2024.02.21
*/
@PostMapping("/{popupId}/collections")
public ResponseEntity<ApplicationResponse<Void>> collect(Principal principal, @PathVariable Long popupId) {
popupService.collect(principal.getName(), popupId);
return ResponseEntity.ok(ApplicationResponse.success(null));
}
}
26 changes: 21 additions & 5 deletions src/main/java/com/oya/kr/popup/domain/enums/PopupSort.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -19,6 +20,7 @@ public enum PopupSort {
ALL("all", "모든 팝업스토어 게시글 리스트 조회"),
PROGRESS("progress", "진행중인 팝업스토어 게시글 리스트 조회"),
SCHEDULED("scheduled", "예정된 팝업스토어 게시글 리스트 조회"),
COLLECTIONS("collections", "스크랩한 팝업스토어 게시글 리스트 조회"),
;

private final String name;
Expand Down Expand Up @@ -52,15 +54,18 @@ public static PopupSort from(String name) {
* @author 김유빈
* @since 2024.02.19
*/
public Supplier<List<PopupDetailMapperResponse>> selectForSorting(PopupRepository popupRepository, int pageNo, int amount) {
public Supplier<List<PopupDetailMapperResponse>> 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;
}
Expand Down Expand Up @@ -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;
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/oya/kr/popup/mapper/PopupCollectionMapper.java
Original file line number Diff line number Diff line change
@@ -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<PopupCollectionMapperResponse> findByPopupIdAndUserId(PopupCollectionMapperRequest request);

void save(PopupCollectionSaveMapperRequest request);

void deleteById(Long id);

void deleteAll();
}
2 changes: 2 additions & 0 deletions src/main/java/com/oya/kr/popup/mapper/PopupMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ public interface PopupMapper {

List<PopupDetailMapperResponse> findScheduled(PopupSearchMapperRequest request);

List<PopupDetailMapperResponse> findCollections(PopupSearchMapperRequest request);

List<PopupDetailMapperResponse> findAllRecommended(PopupSearchMapperRequest request);

void save(PopupSaveMapperRequest request);
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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;
}
65 changes: 34 additions & 31 deletions src/main/java/com/oya/kr/popup/repository/PopupRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@
import static com.oya.kr.popup.exception.PopupErrorCodeList.NOT_EXIST_POPUP;

import java.util.List;
import java.util.Optional;

import org.springframework.stereotype.Repository;

import com.oya.kr.global.exception.ApplicationException;
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;

Expand All @@ -34,6 +41,7 @@ public class PopupRepository {
private final PopupMapper popupMapper;
private final PopupImageMapper popupImageMapper;
private final PopupViewMapper popupViewMapper;
private final PopupCollectionMapper popupCollectionMapper;

/**
* repository 계층으로 분리
Expand All @@ -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));
Expand All @@ -78,37 +86,14 @@ public List<PopupMapperResponse> findAllByPlanId(Long planId) {
/**
* repository 계층으로 분리
*
* @parameter int, int
* @return List<PopupDetailMapperResponse>
* @author 김유빈
* @since 2024.02.21
*/
public List<PopupDetailMapperResponse> findAll(int pageNo, int amount) {
return popupMapper.findAll(new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount));
}

/**
* repository 계층으로 분리
*
* @parameter int, int
* @return List<PopupDetailMapperResponse>
* @author 김유빈
* @since 2024.02.21
*/
public List<PopupDetailMapperResponse> 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<PopupDetailMapperResponse>
* @author 김유빈
* @since 2024.02.21
* @since 2024.02.22
*/
public List<PopupDetailMapperResponse> findScheduled(int pageNo, int amount) {
return popupMapper.findScheduled(new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount));
public List<PopupDetailMapperResponse> findAll(PopupSort popupSort, int pageNo, int amount) {
PopupSearchMapperRequest request = new PopupSearchMapperRequest(WithdrawalStatus.APPROVAL.getName(), pageNo, amount);
return popupSort.selectForSorting(popupMapper, request).get();
}

/**
Expand Down Expand Up @@ -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
*/
Expand All @@ -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<PopupCollectionMapperResponse> 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);
Expand Down
19 changes: 16 additions & 3 deletions src/main/java/com/oya/kr/popup/service/PopupService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand All @@ -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<PopupDetailMapperResponse> mapperResponses = popupSort.selectForSorting(
popupRepository, paginationRequest.getPageNo(), paginationRequest.getAmount()).get();
List<PopupDetailMapperResponse> mapperResponses = popupRepository.findAll(popupSort,
paginationRequest.getPageNo(), paginationRequest.getAmount());
return PopupsListResponse.from(mapperResponses);
}

Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.oya.kr.popup.mapper.PopupCollectionMapper">

<select id="findByPopupIdAndUserId" parameterType="popupCollectionMapperRequest" resultType="popupCollectionMapperResponse">
SELECT ID, USER_ID, POPUP_ID
FROM POPUP_COLLECTION
WHERE POPUP_ID = #{popupId}
AND USER_ID = #{userId}
AND DELETED = 0
</select>

<insert id="save" parameterType="popupCollectionMapperRequest">
INSERT INTO POPUP_COLLECTION (USER_ID, POPUP_ID)
VALUES (#{userId}, #{popupId})
<selectKey keyProperty="popupCollectionId" resultType="long" order="AFTER">
SELECT NVL(MAX(ID), 0)
FROM POPUP_COLLECTION
</selectKey>
</insert>

<delete id="deleteById" parameterType="Long">
DELETE FROM POPUP_COLLECTION
WHERE ID = #{id}
</delete>

<delete id="deleteAll">
DELETE
FROM POPUP_COLLECTION
</delete>

</mapper>
15 changes: 15 additions & 0 deletions src/main/resources/com/oya/kr/popup/mapper/PopupMapper.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,19 @@
<include refid="offsetForPaging" />
</select>

<select id="findCollections" parameterType="popupSearchRequest" resultType="popupDetailMapperResponse">
<include refid="selectPopupWithPlanAndPopupImage" />
JOIN POPUP_COLLECTION PC
ON P.ID = PC.POPUP_ID
AND PC.DELETED = 0
<![CDATA[
WHERE WITHDRAWAL_STATUS != #{withdrawalStatus}
AND P.DELETED = 0
ORDER BY PULLED_DATE DESC
]]>
<include refid="offsetForPaging" />
</select>

<select id="findAllRecommended" parameterType="popupSearchRequest" resultType="popupDetailMapperResponse">
<include refid="selectPopupWithPlanAndPopupImage" />
LEFT JOIN (
Expand Down Expand Up @@ -86,8 +99,10 @@
FROM POPUP P
LEFT JOIN POPUP_IMAGE PI
ON P.ID = PI.POPUP_ID
AND PI.DELETED = 0
JOIN PLAN PN
ON P.PLAN_ID = PN.ID
AND PN.DELETED = 0
</sql>

<sql id="offsetForPaging">
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/mybatis/mybatis-config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<typeAlias type="com.oya.kr.popup.mapper.dto.request.PopupImageSaveMapperRequest" alias="popupImageSaveMapperRequest"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.request.PopupSearchMapperRequest" alias="popupSearchRequest"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.request.PopupViewCreateOrUpdateMapperRequest" alias="popupViewCreateOrUpdateMapperRequest"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.request.PopupCollectionMapperRequest" alias="popupCollectionMapperRequest"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.request.PopupCollectionSaveMapperRequest" alias="popupCollectionSaveMapperRequest"/>

<!-- user -->
<typeAlias type="com.oya.kr.user.mapper.dto.request.SignupAdministratorMapperRequest" alias="SignupUserRequest"/>
Expand All @@ -68,6 +70,7 @@
<typeAlias type="com.oya.kr.popup.mapper.dto.response.PlanMapperResponse" alias="planMapperResponse"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.response.PopupMapperResponse" alias="popupMapperResponse"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.response.PopupDetailMapperResponse" alias="popupDetailMapperResponse"/>
<typeAlias type="com.oya.kr.popup.mapper.dto.response.PopupCollectionMapperResponse" alias="popupCollectionMapperResponse"/>

<!-- user -->
<typeAlias type="com.oya.kr.user.mapper.dto.response.UserMapperResponse" alias="userMapperResponse"/>
Expand Down
Loading

0 comments on commit 9bbaf91

Please sign in to comment.