diff --git a/src/main/java/blacktokkies/toquiz/domain/panel/api/PanelApi.java b/src/main/java/blacktokkies/toquiz/domain/panel/api/PanelApi.java index 7355c27..f90b83f 100644 --- a/src/main/java/blacktokkies/toquiz/domain/panel/api/PanelApi.java +++ b/src/main/java/blacktokkies/toquiz/domain/panel/api/PanelApi.java @@ -3,10 +3,14 @@ import blacktokkies.toquiz.domain.panel.application.PanelService; import blacktokkies.toquiz.domain.panel.dto.request.CreatePanelRequest; import blacktokkies.toquiz.domain.panel.dto.request.UpdatePanelRequest; +import blacktokkies.toquiz.domain.panel.dto.response.GetMyActiveInfoResponse; import blacktokkies.toquiz.domain.panel.dto.response.GetMyPanelsResponse; import blacktokkies.toquiz.domain.panel.dto.response.PanelResponse; import blacktokkies.toquiz.global.common.response.SuccessMessage; import blacktokkies.toquiz.global.common.response.SuccessResponse; +import blacktokkies.toquiz.global.util.auth.CookieService; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -19,6 +23,8 @@ @RequiredArgsConstructor public class PanelApi { private final PanelService panelService; + private final CookieService cookieService; + @PostMapping("api/panel") public ResponseEntity> createPanel( @RequestBody @Valid CreatePanelRequest createPanelRequest @@ -60,4 +66,23 @@ public ResponseEntity> getPanelInfo(@PathVariable return ResponseEntity.ok(new SuccessResponse<>(response)); } + + @GetMapping("api/panels/{panelId}/active-info") + public ResponseEntity> getActiveInfo( + HttpServletResponse httpResponse, + @PathVariable Long panelId, + @CookieValue(value = "active_info_id", required = false) String activeInfoId + ){ + // ActiveInfoId가 없는 사용자에게 ActiveInfoId를 쿠키로 새로 발급한다. + if(activeInfoId == null){ + Cookie activeInfoIdCookie = cookieService.issueActiveInfoIdCookie(); + httpResponse.addCookie(activeInfoIdCookie); + + activeInfoId = activeInfoIdCookie.getValue(); + } + + GetMyActiveInfoResponse response = panelService.getMyActiveInfo(panelId, activeInfoId); + + return ResponseEntity.ok(new SuccessResponse<>(response)); + } } diff --git a/src/main/java/blacktokkies/toquiz/domain/panel/application/PanelService.java b/src/main/java/blacktokkies/toquiz/domain/panel/application/PanelService.java index 72b5b6a..1214484 100644 --- a/src/main/java/blacktokkies/toquiz/domain/panel/application/PanelService.java +++ b/src/main/java/blacktokkies/toquiz/domain/panel/application/PanelService.java @@ -1,13 +1,18 @@ package blacktokkies.toquiz.domain.panel.application; +import blacktokkies.toquiz.domain.activeinfo.ActiveInfoRepository; +import blacktokkies.toquiz.domain.activeinfo.domain.ActiveInfo; +import blacktokkies.toquiz.domain.activeinfo.domain.ActivePanel; import blacktokkies.toquiz.domain.member.domain.Member; import blacktokkies.toquiz.domain.panel.dao.PanelRepository; import blacktokkies.toquiz.domain.panel.domain.Panel; import blacktokkies.toquiz.domain.panel.dto.request.CreatePanelRequest; import blacktokkies.toquiz.domain.panel.dto.request.UpdatePanelRequest; +import blacktokkies.toquiz.domain.panel.dto.response.GetMyActiveInfoResponse; import blacktokkies.toquiz.domain.panel.dto.response.GetMyPanelsResponse; import blacktokkies.toquiz.domain.panel.dto.response.PanelResponse; import blacktokkies.toquiz.global.common.error.RestApiException; +import blacktokkies.toquiz.global.util.auth.CookieService; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -16,8 +21,10 @@ import org.springframework.transaction.annotation.Transactional; import java.util.List; +import java.util.Map; import java.util.Objects; +import static blacktokkies.toquiz.domain.activeinfo.exception.ActiveInfoException.NOT_EXIST_ACTIVE_INFO; import static blacktokkies.toquiz.domain.panel.exception.PanelErrorCode.NOT_AUTHORIZED_DELETE; import static blacktokkies.toquiz.domain.panel.exception.PanelErrorCode.NOT_EXIST_PANEL; @@ -25,7 +32,9 @@ @RequiredArgsConstructor @Transactional(readOnly = true) public class PanelService { + private final ActiveInfoRepository activeInfoRepository; private final PanelRepository panelRepository; + private final CookieService cookieService; @Transactional public PanelResponse createPanel(CreatePanelRequest createPanelRequest) { @@ -63,6 +72,25 @@ public PanelResponse updatePanel(UpdatePanelRequest updatePanelRequest, Long pan return PanelResponse.toDto(updatedPanel); } + public GetMyActiveInfoResponse getMyActiveInfo(Long panelId, String activeInfoId) { + checkIsExistPanel(panelId); + + ActiveInfo activeInfo = getActiveInfo(activeInfoId); + Map activePanelMap = activeInfo.getActivePanels(); + + // 현재 패널이 활동 정보에 존재하지 않으면 새로 추가한다. + if(!activePanelMap.containsKey(panelId)){ + activePanelMap.put(panelId, new ActivePanel()); + } + + return GetMyActiveInfoResponse.toDto(activePanelMap.get(panelId)); + } + + private ActiveInfo getActiveInfo(String activeInfoId) { + return activeInfoRepository.findById(activeInfoId) + .orElseThrow(() -> new RestApiException(NOT_EXIST_ACTIVE_INFO)); + } + private void checkIsAuthorizedToDelete(Long panelId) { Panel panel = getPanel(panelId); Member member = getMember(); @@ -72,6 +100,11 @@ private void checkIsAuthorizedToDelete(Long panelId) { } } + private void checkIsExistPanel(Long panelId){ + panelRepository.findById(panelId) + .orElseThrow(() -> new RestApiException(NOT_EXIST_PANEL)); + } + public Panel getPanel(Long panelId){ return panelRepository.findById(panelId) .orElseThrow(() -> new RestApiException(NOT_EXIST_PANEL)); diff --git a/src/main/java/blacktokkies/toquiz/domain/panel/dto/response/GetMyActiveInfoResponse.java b/src/main/java/blacktokkies/toquiz/domain/panel/dto/response/GetMyActiveInfoResponse.java new file mode 100644 index 0000000..8e951f0 --- /dev/null +++ b/src/main/java/blacktokkies/toquiz/domain/panel/dto/response/GetMyActiveInfoResponse.java @@ -0,0 +1,21 @@ +package blacktokkies.toquiz.domain.panel.dto.response; + +import blacktokkies.toquiz.domain.activeinfo.domain.ActivePanel; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; + +@Getter +@AllArgsConstructor +public class GetMyActiveInfoResponse { + public List createdIds; + public List likedIds; + + public static GetMyActiveInfoResponse toDto(ActivePanel activePanel){ + return new GetMyActiveInfoResponse( + activePanel.getCreatedQuestionIds(), + activePanel.getLikedQuestionIds() + ); + } +} diff --git a/src/main/java/blacktokkies/toquiz/domain/question/application/QuestionService.java b/src/main/java/blacktokkies/toquiz/domain/question/application/QuestionService.java index 027f526..5dd0869 100644 --- a/src/main/java/blacktokkies/toquiz/domain/question/application/QuestionService.java +++ b/src/main/java/blacktokkies/toquiz/domain/question/application/QuestionService.java @@ -40,7 +40,15 @@ public QuestionResponse createQuestion( String activeInfoId, Long panelId) { - Question question = questionRepository.save(new Question(createQuestionRequest.getContent(), getPanel(panelId), activeInfoId)); + Question question = questionRepository.save( + new Question(createQuestionRequest.getContent(), getPanel(panelId), + activeInfoId)); + + ActiveInfo activeInfo = getActiveInfo(activeInfoId); + List createdQuestionIds = getCreatedQuestions(activeInfo, panelId); + createdQuestionIds.add(question.getId()); + + activeInfoRepository.save(activeInfo); return QuestionResponse.toDto(question); } @@ -64,39 +72,50 @@ public ToggleLikeQuestionResponse toggleLike(Long questionId, String activeInfoI Long panelId = question.getPanel().getId(); ActiveInfo activeInfo = getActiveInfo(activeInfoId); - List likedQuestions = getLikedQuestions(activeInfo, panelId); + List likedQuestionIds = getLikedQuestions(activeInfo, panelId); - updateLikedQuestions(likedQuestions, question, active); + updateLikedQuestions(likedQuestionIds, question, active); activeInfoRepository.save(activeInfo); return ToggleLikeQuestionResponse.toDto(question, active); } - private void updateLikedQuestions(List likedQuestions, Question question, boolean active) { + private void updateLikedQuestions(List likedQuestionIds, Question question, boolean active) { Long questionId = question.getId(); - boolean isAlreadyLikedQuestion = likedQuestions.stream().anyMatch((id)-> Objects.equals(id, questionId)); + boolean isAlreadyLikedQuestion = likedQuestionIds.stream().anyMatch((id)-> Objects.equals(id, questionId)); if(active){ // 좋아요가 이미 활성화된 상태에서 활성화를 하려고 시도할 때 에러처리 if(isAlreadyLikedQuestion) throw new RestApiException(INVALID_ACTIVE_LIKE_QUESTION); - likedQuestions.add(questionId); + likedQuestionIds.add(questionId); question.increaseLikeNum(); }else{ // 좋아요가 이미 비활성화된 상태에서 비활성화를 하려고 시도할 때 에러처리 if(!isAlreadyLikedQuestion) throw new RestApiException(INVALID_INACTIVE_LIKE_QUESTION); - likedQuestions.removeIf((id)->Objects.equals(id, questionId)); + likedQuestionIds.removeIf((id)->Objects.equals(id, questionId)); question.decreaseLikeNum(); } } + private List getCreatedQuestions(ActiveInfo activeInfo, Long panelId){ + Map activePanelMap = activeInfo.getActivePanels(); + if(!activePanelMap.containsKey(panelId)){ + activePanelMap.put(panelId, new ActivePanel()); + } + ActivePanel activePanel = activePanelMap.get(panelId); + + return activePanel.getCreatedQuestionIds(); + } + private List getLikedQuestions(ActiveInfo activeInfo, Long panelId) { Map activePanelMap = activeInfo.getActivePanels(); if(!activePanelMap.containsKey(panelId)){ activePanelMap.put(panelId, new ActivePanel()); } ActivePanel activePanel = activePanelMap.get(panelId); + return activePanel.getLikedQuestionIds(); } diff --git a/src/main/java/blacktokkies/toquiz/global/config/SecurityConfig.java b/src/main/java/blacktokkies/toquiz/global/config/SecurityConfig.java index f9048e0..9660a2f 100644 --- a/src/main/java/blacktokkies/toquiz/global/config/SecurityConfig.java +++ b/src/main/java/blacktokkies/toquiz/global/config/SecurityConfig.java @@ -63,6 +63,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers( // GET 메서드 HttpMethod.GET, "api/panels/{panelId}", + "api/panels/{panelId}/active-info", "api/panels/{panelId}/questions", "api/questions/{questionId}/answers" ).permitAll() diff --git a/src/main/java/blacktokkies/toquiz/global/util/auth/CookieService.java b/src/main/java/blacktokkies/toquiz/global/util/auth/CookieService.java index aaccb02..26283a6 100644 --- a/src/main/java/blacktokkies/toquiz/global/util/auth/CookieService.java +++ b/src/main/java/blacktokkies/toquiz/global/util/auth/CookieService.java @@ -1,5 +1,7 @@ package blacktokkies.toquiz.global.util.auth; +import blacktokkies.toquiz.domain.activeinfo.ActiveInfoRepository; +import blacktokkies.toquiz.domain.activeinfo.domain.ActiveInfo; import blacktokkies.toquiz.domain.member.exception.MemberErrorCode; import blacktokkies.toquiz.global.common.error.RestApiException; import blacktokkies.toquiz.domain.member.dao.MemberRepository; @@ -14,11 +16,23 @@ public class CookieService { private final MemberRepository memberRepository; private final TokenService tokenService; + private final ActiveInfoRepository activeInfoRepository; + @Value("${application.security.cookie.active-info-id.expiration}") private Integer ACTIVE_INFO_ID_EXPIRATION; @Value("${application.security.cookie.refresh-token.expiration}") private Integer REFRESH_TOKEN_EXPIRATION; + public Cookie issueActiveInfoIdCookie(){ + ActiveInfo activeInfo = activeInfoRepository.save(new ActiveInfo()); + Cookie cookie = new Cookie("active_info_id", activeInfo.getId()); + cookie.setMaxAge(ACTIVE_INFO_ID_EXPIRATION); + cookie.setHttpOnly(true); + cookie.setPath("/"); + + return cookie; + } + public Cookie issueActiveInfoIdCookie(String email){ Member member = memberRepository.findByEmail(email) .orElseThrow(() -> new RestApiException(MemberErrorCode.NOT_EXIST_MEMBER));