diff --git a/src/main/java/com/brainpix/post/controller/SavedPostController.java b/src/main/java/com/brainpix/post/controller/SavedPostController.java index 2424c2c3..6d2a2ef9 100644 --- a/src/main/java/com/brainpix/post/controller/SavedPostController.java +++ b/src/main/java/com/brainpix/post/controller/SavedPostController.java @@ -14,26 +14,29 @@ import com.brainpix.post.dto.PostCollaborationResponse; import com.brainpix.post.dto.PostIdeaMarketResponse; import com.brainpix.post.dto.PostRequestTaskResponse; +import com.brainpix.post.dto.SavePostResponseDto; import com.brainpix.post.service.SavedPostService; import com.brainpix.security.authorization.AllUser; import com.brainpix.security.authorization.UserId; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @RestController @RequestMapping("/saved-posts") @RequiredArgsConstructor +@Tag(name = "게시글 저장 관련 API", description = "게시글을 저장 및 해제 하고, 저장된 게시글을 조회하는 API입니다.") public class SavedPostController { private final SavedPostService savedPostService; - @Operation(summary = "게시글 저장", description = "현재 로그인한 사용자가 특정 게시글을 저장합니다.") + @Operation(summary = "게시글 저장 및 해제", description = "토글 형식으로 현재 로그인한 사용자가 특정 게시글을 저장 또는 해제 합니다.
이미 저장된 게시글은 해제되고, 그렇지 않다면 저장합니다.") @AllUser @PostMapping - public ResponseEntity> savePost(@UserId Long userId, @RequestParam long postId) { - savedPostService.savePost(userId, postId); - return ResponseEntity.ok(ApiResponse.successWithNoData()); + public ResponseEntity> savePost(@UserId Long userId, @RequestParam long postId) { + SavePostResponseDto result = savedPostService.savePost(userId, postId); + return ResponseEntity.ok(ApiResponse.success(result)); } @Operation(summary = "저장된 요청 과제 조회", description = "현재 로그인한 사용자가 저장한 요청 과제를 조회합니다.") diff --git a/src/main/java/com/brainpix/post/dto/SavePostResponseDto.java b/src/main/java/com/brainpix/post/dto/SavePostResponseDto.java new file mode 100644 index 00000000..f139eb74 --- /dev/null +++ b/src/main/java/com/brainpix/post/dto/SavePostResponseDto.java @@ -0,0 +1,9 @@ +package com.brainpix.post.dto; + +public record SavePostResponseDto( + Boolean isSaved +) { + public static SavePostResponseDto from(Boolean isSaved) { + return new SavePostResponseDto(isSaved); + } +} diff --git a/src/main/java/com/brainpix/post/repository/SavedPostRepository.java b/src/main/java/com/brainpix/post/repository/SavedPostRepository.java index 4adfd2d8..e4fdd730 100644 --- a/src/main/java/com/brainpix/post/repository/SavedPostRepository.java +++ b/src/main/java/com/brainpix/post/repository/SavedPostRepository.java @@ -1,5 +1,7 @@ package com.brainpix.post.repository; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; import com.brainpix.post.entity.Post; @@ -7,8 +9,8 @@ import com.brainpix.user.entity.User; public interface SavedPostRepository extends JpaRepository, SavedPostRepositoryCustom { - - boolean existsByUserAndPost(User user, Post post); - + Long countByPostId(Long postId); + + Optional findByUserAndPost(User user, Post post); } \ No newline at end of file diff --git a/src/main/java/com/brainpix/post/service/SavedPostService.java b/src/main/java/com/brainpix/post/service/SavedPostService.java index 726f78c0..e1cea5d4 100644 --- a/src/main/java/com/brainpix/post/service/SavedPostService.java +++ b/src/main/java/com/brainpix/post/service/SavedPostService.java @@ -1,14 +1,19 @@ package com.brainpix.post.service; +import java.util.Optional; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.brainpix.api.code.error.SavedPostErrorCode; +import com.brainpix.api.code.error.CommonErrorCode; +import com.brainpix.api.code.error.PostErrorCode; +import com.brainpix.api.exception.BrainPixException; import com.brainpix.post.dto.PostCollaborationResponse; import com.brainpix.post.dto.PostIdeaMarketResponse; import com.brainpix.post.dto.PostRequestTaskResponse; +import com.brainpix.post.dto.SavePostResponseDto; import com.brainpix.post.entity.Post; import com.brainpix.post.entity.SavedPost; import com.brainpix.post.entity.collaboration_hub.CollaborationHub; @@ -31,21 +36,30 @@ public class SavedPostService { private final PostRepository postRepository; @Transactional - public void savePost(long userId, long postId) { + public SavePostResponseDto savePost(long userId, long postId) { User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException(SavedPostErrorCode.USER_NOT_FOUND.getMessage())); + .orElseThrow(() -> new BrainPixException(CommonErrorCode.USER_NOT_FOUND)); Post post = postRepository.findById(postId) - .orElseThrow(() -> new IllegalArgumentException(SavedPostErrorCode.POST_NOT_FOUND.getMessage())); + .orElseThrow(() -> new BrainPixException(PostErrorCode.POST_NOT_FOUND)); + + Optional savedPost = savedPostRepository.findByUserAndPost(user, post); - validateNotDuplicate(user, post); + boolean isSaved; + if (savedPost.isEmpty()) { + savedPostRepository.save(new SavedPost(user, post)); // 즐겨찾기 등록 + isSaved = true; + } else { + savedPostRepository.delete(savedPost.get()); // 즐겨찾기 해제 + isSaved = false; + } - savedPostRepository.save(new SavedPost(user, post)); + return SavePostResponseDto.from(isSaved); } public Page findSavedRequestTasks(long userId, Pageable pageable) { User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException(SavedPostErrorCode.USER_NOT_FOUND.getMessage())); + .orElseThrow(() -> new BrainPixException(CommonErrorCode.USER_NOT_FOUND)); return savedPostRepository.findSavedRequestTasksByUser(user, pageable) .map(savedPost -> { @@ -57,7 +71,7 @@ public Page findSavedRequestTasks(long userId, Pageable public Page findSavedIdeaMarkets(long userId, Pageable pageable) { User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException(SavedPostErrorCode.USER_NOT_FOUND.getMessage())); + .orElseThrow(() -> new BrainPixException(CommonErrorCode.USER_NOT_FOUND)); return savedPostRepository.findSavedIdeaMarketsByUser(user, pageable) .map(savedPost -> { @@ -69,7 +83,7 @@ public Page findSavedIdeaMarkets(long userId, Pageable p public Page findSavedCollaborationHubs(long userId, Pageable pageable) { User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException(SavedPostErrorCode.USER_NOT_FOUND.getMessage())); + .orElseThrow(() -> new BrainPixException(CommonErrorCode.USER_NOT_FOUND)); return savedPostRepository.findSavedCollaborationHubsByUser(user, pageable) .map(savedPost -> { @@ -84,10 +98,4 @@ public Page findSavedCollaborationHubs(long userId, P occupiedQuantity); }); } - - private void validateNotDuplicate(User user, Post post) { - if (savedPostRepository.existsByUserAndPost(user, post)) { - throw new IllegalStateException(SavedPostErrorCode.DUPLICATE_SAVED_POST.getMessage()); - } - } }