diff --git a/src/main/java/com/progbe/domain/category/dto/CategoryResponse.java b/src/main/java/com/progbe/domain/category/dto/CategoryResponse.java index b4b6f18..f45950d 100644 --- a/src/main/java/com/progbe/domain/category/dto/CategoryResponse.java +++ b/src/main/java/com/progbe/domain/category/dto/CategoryResponse.java @@ -1,9 +1,18 @@ package com.progbe.domain.category.dto; +import com.progbe.domain.category.entity.CategoryEntity; + public record CategoryResponse( Long categoryId, String name, String description ) { + public static CategoryResponse from(CategoryEntity entity) { + return new CategoryResponse( + entity.getId(), + entity.getName(), + entity.getDescription() + ); + } } diff --git a/src/main/java/com/progbe/domain/prompt/controller/PromptController.java b/src/main/java/com/progbe/domain/prompt/controller/PromptController.java index 55b54a1..80a4d80 100644 --- a/src/main/java/com/progbe/domain/prompt/controller/PromptController.java +++ b/src/main/java/com/progbe/domain/prompt/controller/PromptController.java @@ -1,20 +1,21 @@ package com.progbe.domain.prompt.controller; -import com.progbe.domain.prompt.dto.PromptCreateRequest; -import com.progbe.domain.prompt.dto.PromptListResponse; -import com.progbe.domain.prompt.dto.PromptResponse; -import com.progbe.domain.prompt.dto.PromptUpdateRequest; +import com.progbe.domain.prompt.dto.*; import com.progbe.domain.prompt.service.PromptService; import com.progbe.global.common.ApiResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.parameters.P; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("/prompts") @RequiredArgsConstructor @@ -108,5 +109,40 @@ public ResponseEntity> deletePrompt( promptService.deletePrompt(promptId, userId); return ResponseEntity.ok(ApiResponse.success(null)); } + + /** + * 프롬프트 최신순 API + * @param pageable + * @return + */ + @GetMapping("/createDesc") + public ApiResponse createPromptDesc( + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { + PromptListResponse prompts = promptService.getPromptsSortedTime(pageable); + return ApiResponse.success(prompts); + } + + /** + * 프롬프트 좋아요순 API + * @param pageable + * @return + */ + @GetMapping("/likeDesc") + public ApiResponse likePromptDesc( + @PageableDefault(size = 10, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) { + PromptListResponse prompts = promptService.getPromptsSortedLikeCount(pageable); + return ApiResponse.success(prompts); + } + + /** + * 금일 가장 많은 좋아요순 API + * @return + */ + @GetMapping("/today-hot") + public ApiResponse> getTodayHotPrompts() { + List prompts = promptService.getDailyHotPrompts(); + return ApiResponse.success(prompts); + } + } diff --git a/src/main/java/com/progbe/domain/prompt/repository/PromptRepository.java b/src/main/java/com/progbe/domain/prompt/repository/PromptRepository.java index e158106..d796be7 100644 --- a/src/main/java/com/progbe/domain/prompt/repository/PromptRepository.java +++ b/src/main/java/com/progbe/domain/prompt/repository/PromptRepository.java @@ -8,6 +8,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -29,5 +30,32 @@ public interface PromptRepository extends JpaRepository { "WHERE p.user.id IN :userIds AND p.deletedAt IS NULL " + "GROUP BY p.user.id") List countByUserIdsGrouped(@Param("userIds") List userIds); + + @Query("SELECT p FROM PromptEntity p " + + "JOIN FETCH p.category " + + "WHERE p.deletedAt IS NULL " + + "ORDER BY p.createdAt DESC") + Page findPromptSortedTime(Pageable pageable); + + @Query("SELECT p FROM PromptEntity p " + + "JOIN FETCH p.category " + + "LEFT JOIN PromptLikeEntity pl ON pl.prompt = p " + + "WHERE p.deletedAt IS NULL " + + "GROUP BY p.id, p.category.id " + + "ORDER BY COUNT(pl) DESC, p.createdAt DESC") + Page findPromptSortedLikeCount(Pageable pageable); + + @Query("SELECT p FROM PromptEntity p " + + "JOIN FETCH p.category " + + "LEFT JOIN PromptLikeEntity pl ON pl.prompt = p " + + "AND pl.createdAt >= :start AND pl.createdAt <= :end " + + "WHERE p.deletedAt IS NULL " + + "GROUP BY p.id, p.category.id " + + "ORDER BY COUNT(pl) DESC, p.createdAt DESC") + List findDailyHotPrompts( + @Param("start") LocalDateTime start, + @Param("end") LocalDateTime end, + Pageable pageable + ); } diff --git a/src/main/java/com/progbe/domain/prompt/service/PromptService.java b/src/main/java/com/progbe/domain/prompt/service/PromptService.java index f5bdfa0..ded066b 100644 --- a/src/main/java/com/progbe/domain/prompt/service/PromptService.java +++ b/src/main/java/com/progbe/domain/prompt/service/PromptService.java @@ -1,5 +1,6 @@ package com.progbe.domain.prompt.service; +import com.progbe.domain.category.dto.CategoryResponse; import com.progbe.domain.category.entity.CategoryEntity; import com.progbe.domain.category.repository.CategoryRepository; import com.progbe.domain.prompt.dto.*; @@ -12,10 +13,14 @@ import com.progbe.global.error.exception.CustomException; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; @Service @@ -107,4 +112,57 @@ public void deletePrompt(Long promptId, Long userId) { prompt.delete(); promptRepository.save(prompt); } + + // 최신순 프롬프트 띄어주기 로직 (#31) + public PromptListResponse getPromptsSortedTime(Pageable pageable) { + Page promptEntities = promptRepository.findPromptSortedTime(pageable); + + List promptList = promptEntities.getContent().stream() + .map(entity -> new PromptSummaryResponse( + entity.getId(), + promptMapper.toCategoryResponse(entity.getCategory()), + entity.getTitle(), + entity.getCreatedAt(), + entity.getUpdatedAt() + )) + .toList(); + + return new PromptListResponse( + promptList, + promptEntities.getTotalElements() + ); + } + + // 좋아요순 프롬프트 띄어주기 로직 (#31) + public PromptListResponse getPromptsSortedLikeCount(Pageable pageable) { + Page promptEntities = promptRepository.findPromptSortedLikeCount(pageable); + + List promptList = promptEntities.getContent().stream() + .map(entity -> new PromptSummaryResponse( + entity.getId(), + promptMapper.toCategoryResponse(entity.getCategory()), + entity.getTitle(), + entity.getCreatedAt(), + entity.getUpdatedAt() + )) + .toList(); + + return new PromptListResponse( + promptList, + promptEntities.getTotalElements() + ); + } + + // 오늘의 좋아요를 가장 많이 받은 프롬프트 띄어주기 로직 (#31) + // LocalDateTime 을 이용해서 오늘 (= 00시 ~ 23시 59분) 으로 설정했습니다. + public List getDailyHotPrompts() { + LocalDateTime start = LocalDate.now().atStartOfDay(); + LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX); + + Pageable topFive = PageRequest.of(0, 3); + + List promptEntities = promptRepository.findDailyHotPrompts(start, end, topFive); + + return promptMapper.toPromptSummaryResponseList(promptEntities); + } }