diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/dto/response/PostCardResponseDto.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/dto/response/PostCardResponseDto.java index 30f6be9..b8f2f7e 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/dto/response/PostCardResponseDto.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/api/dto/response/PostCardResponseDto.java @@ -1,7 +1,6 @@ package org.sopt.pawkey.backendapi.domain.post.api.dto.response; import java.time.format.DateTimeFormatter; -import java.util.List; import org.sopt.pawkey.backendapi.domain.post.application.dto.result.GetPostCardResult; @@ -10,44 +9,23 @@ @JsonInclude(JsonInclude.Include.NON_NULL) public record PostCardResponseDto( Long postId, - String createdAt, - boolean isLike, + String regionName, String title, - String representativeImageUrl, - Long routeId, - WriterDto writer, - List descriptionTags, - boolean isPublic, - boolean isMine + String date, + Integer durationMinutes, + boolean isLiked, + String imageUrl ) { public static PostCardResponseDto from(GetPostCardResult result) { return new PostCardResponseDto( result.postId(), + result.regionName(), + result.title(), result.createdAt().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")), + result.durationMinutes(), result.isLike(), - result.title(), - result.routeMapImageUrl(), - result.routeId(), - new WriterDto( - result.author().authorId(), - result.author().petName(), - result.author().petProfileImage() - ), - result.categoryTags(), - result.isPublic(), - result.isMine() + result.routeMapImageUrl() ); } - - public boolean getIsPublic() { - return isPublic; - } - - public record WriterDto( - Long userId, - String petName, - String petProfileImageUrl - ) { - } -} +} \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/dto/result/GetPostCardResult.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/dto/result/GetPostCardResult.java index 60f6d31..0f74fac 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/dto/result/GetPostCardResult.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/application/dto/result/GetPostCardResult.java @@ -10,14 +10,11 @@ @Builder public record GetPostCardResult( Long postId, + String regionName, String title, - boolean isLike, - AuthorDto author, - List categoryTags, LocalDateTime createdAt, - String routeMapImageUrl, - Long routeId, - boolean isPublic, - boolean isMine + Integer durationMinutes, + boolean isLike, + String routeMapImageUrl ) { } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java index 95e874a..774a0d0 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/domain/repository/PostLikeRepository.java @@ -4,6 +4,8 @@ import java.util.Optional; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface PostLikeRepository { PostLikeEntity save(PostLikeEntity postLike); @@ -13,4 +15,6 @@ public interface PostLikeRepository { List findAllByUserWithPostAndImages(Long userId); void deleteByUserIdAndPostId(Long userId, Long postId); + + List findLikedPostIdsByUserId(Long userId); } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java index 70ee244..b335ed7 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostLikeRepositoryImpl.java @@ -35,4 +35,9 @@ public void deleteByUserIdAndPostId(Long userId, Long postId) { public List findAllByUserWithPostAndImages(Long userId) { return jpaRepository.findAllByUserWithPostAndImages(userId); } + + @Override + public List findLikedPostIdsByUserId(Long userId) { + return jpaRepository.findLikedPostIdsByUserId(userId); + } } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostQueryRepositoryImpl.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostQueryRepositoryImpl.java index 059b584..313a61f 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostQueryRepositoryImpl.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/PostQueryRepositoryImpl.java @@ -17,6 +17,7 @@ import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.QPostLikeEntity; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.QPostSelectedCategoryOptionEntity; import org.sopt.pawkey.backendapi.domain.region.infra.persistence.entity.QRegionEntity; +import org.sopt.pawkey.backendapi.domain.region.infra.persistence.entity.RegionEntity; import org.sopt.pawkey.backendapi.domain.routes.infra.persistence.entity.QRouteEntity; import org.sopt.pawkey.backendapi.domain.user.api.dto.AuthorDto; import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.QUserEntity; @@ -121,22 +122,21 @@ public List findByFilter(FilterPostsRequestDto dto, Long user return posts.stream().map(p -> { Long postId = p.getPostId(); + RegionEntity region = p.getRoute().getRegion(); + String regionName = region.getParent() != null + ? region.getParent().getRegionName() + " " + region.getRegionName() + : region.getRegionName(); + + int durationMinutes = (int)(p.getRoute().getDuration() / 60); + return GetPostCardResult.builder() .postId(postId) + .regionName(regionName) .title(p.getTitle()) - .isLike(likedPostIds.contains(postId)) - .isPublic(p.isPublic()) - .author(new AuthorDto( - p.getUser().getUserId(), - p.getPet().getPetId(), - p.getPet().getName(), - p.getPet().getProfileImage().getImageUrl() - )) - .categoryTags(postIdToCategoryTags.getOrDefault(postId, List.of())) .createdAt(p.getCreatedAt()) + .durationMinutes(durationMinutes) + .isLike(likedPostIds.contains(postId)) .routeMapImageUrl(p.getRoute().getTrackingImage().getImageUrl()) - .routeId(p.getRoute().getRouteId()) - .isMine(p.getUser().getUserId().equals(userId)) .build(); }).toList(); } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java index 9be6c6e..6df073d 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/Post/infra/persistence/repository/SpringDataPostLikeRepository.java @@ -30,4 +30,7 @@ public interface SpringDataPostLikeRepository extends JpaRepository findLikedPostIdsByUserId(@Param("userId") Long userId); } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java index e7cacca..bec9ced 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/api/controller/UserController.java @@ -33,6 +33,7 @@ import org.springframework.web.multipart.MultipartFile; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.responses.ApiResponses; import jakarta.validation.Valid; @@ -79,7 +80,7 @@ public ResponseEntity> createUser( }) @GetMapping("/me/likes") public ResponseEntity>> getMyLikedPosts( - @UserId Long userId + @Parameter(hidden = true) @UserId Long userId ) { List likedPosts = userLikedPostQueryFacade.getLikedPosts(userId); return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(likedPosts))); @@ -107,7 +108,7 @@ public ResponseEntity> getUserProfile( }) @GetMapping("/me/posts") public ResponseEntity>> getMyPosts( - @UserId Long userId + @Parameter(hidden = true) @UserId Long userId ) { List myPosts = userWrittenPostQueryFacade.getMyPosts(userId); return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(myPosts))); diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserLikedPostQueryFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserLikedPostQueryFacade.java index ff0ad3f..be9b52f 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserLikedPostQueryFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserLikedPostQueryFacade.java @@ -42,38 +42,22 @@ public List getLikedPosts(Long userId) { .map(postLike -> { var post = postLike.getPost(); - String repImageUrl = post.getRoute().getTrackingImage().getImageUrl(); + String regionName = post.getRoute().getRegion().getParent().getRegionName() + " " + + post.getRoute().getRegion().getRegionName(); - var writer = post.getUser(); - var pet = writer.getPetEntityList().stream().findFirst().orElse(null); - - PostCardResponseDto.WriterDto writerDto = new PostCardResponseDto.WriterDto( - writer.getUserId(), - pet != null ? pet.getName() : null, - (pet != null && pet.getProfileImage() != null) ? pet.getProfileImage().getImageUrl() : null - ); - - List descriptionTags = post.getPostSelectedCategoryOptionEntityList() - .stream() - .map(selectedOption -> selectedOption.getCategoryOption().getOptionSummary()) - .toList(); + int durationMinutes = (int)(post.getRoute().getDuration() / 60); return new PostCardResponseDto( post.getPostId(), - post.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")), - true, // 좋아요한 게시글 + regionName, post.getTitle(), - repImageUrl, - post.getRoute().getRouteId(), - writerDto, - descriptionTags, + post.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")), + durationMinutes, true, - false - + post.getRoute().getTrackingImage().getImageUrl() ); }) .toList(); - } } diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserWrittenPostQueryFacade.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserWrittenPostQueryFacade.java index 7123a99..a64c216 100644 --- a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserWrittenPostQueryFacade.java +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/facade/query/UserWrittenPostQueryFacade.java @@ -6,8 +6,11 @@ import org.sopt.pawkey.backendapi.domain.pet.infra.persistence.entity.PetEntity; import org.sopt.pawkey.backendapi.domain.post.api.dto.response.PostCardResponseDto; +import org.sopt.pawkey.backendapi.domain.post.application.dto.result.GetPostCardResult; +import org.sopt.pawkey.backendapi.domain.post.domain.repository.PostLikeRepository; import org.sopt.pawkey.backendapi.domain.post.domain.repository.PostRepository; import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostEntity; +import org.sopt.pawkey.backendapi.domain.user.application.service.UserWrittenPostQueryService; import org.sopt.pawkey.backendapi.domain.user.domain.repository.UserQueryRepository; import org.sopt.pawkey.backendapi.domain.user.exception.UserBusinessException; import org.sopt.pawkey.backendapi.domain.user.exception.UserErrorCode; @@ -23,46 +26,17 @@ public class UserWrittenPostQueryFacade { private final UserQueryRepository userQueryRepository; - private final PostRepository postRepository; + private final UserWrittenPostQueryService userWrittenPostQueryService; public List getMyPosts(Long userId) { UserEntity user = userQueryRepository.getUserByUserId(userId) .orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND)); - List posts = postRepository.findAllByUser(user) - .stream() - .sorted(Comparator.comparing(PostEntity::getPostId).reversed()) - .toList(); - - return posts.stream() - .map(post -> { - String repImageUrl = post.getRoute().getTrackingImage().getImageUrl(); - - PetEntity pet = post.getUser().getPet(); - PostCardResponseDto.WriterDto writer = new PostCardResponseDto.WriterDto( - post.getUser().getUserId(), - pet != null ? pet.getName() : null, - (pet != null && pet.getProfileImage() != null) ? pet.getProfileImage().getImageUrl() : null - ); + List likedPostIds = userWrittenPostQueryService.getLikedPostIds(userId); + List results = userWrittenPostQueryService.findMyPostResults(user, likedPostIds); - List tags = post.getPostSelectedCategoryOptionEntityList().stream() - .map(opt -> opt.getCategoryOption().getOptionSummary()) - .toList(); - - return new PostCardResponseDto( - post.getPostId(), - post.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy/MM/dd")), - false, - post.getTitle(), - repImageUrl, - post.getRoute().getRouteId(), - writer, - tags, - post.isPublic(), - true - ); - }) + return results.stream() + .map(PostCardResponseDto::from) .toList(); } - } \ No newline at end of file diff --git a/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserWrittenPostQueryService.java b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserWrittenPostQueryService.java new file mode 100644 index 0000000..d22a3b7 --- /dev/null +++ b/src/main/java/org/sopt/pawkey/backendapi/domain/user/application/service/UserWrittenPostQueryService.java @@ -0,0 +1,60 @@ +package org.sopt.pawkey.backendapi.domain.user.application.service; + +import java.util.Comparator; +import java.util.List; + +import org.sopt.pawkey.backendapi.domain.post.application.dto.result.GetPostCardResult; +import org.sopt.pawkey.backendapi.domain.post.domain.repository.PostLikeRepository; +import org.sopt.pawkey.backendapi.domain.post.domain.repository.PostRepository; +import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostEntity; +import org.sopt.pawkey.backendapi.domain.post.infra.persistence.entity.PostLikeEntity; +import org.sopt.pawkey.backendapi.domain.region.infra.persistence.entity.RegionEntity; +import org.sopt.pawkey.backendapi.domain.user.infra.persistence.entity.UserEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserWrittenPostQueryService { + + private final PostRepository postRepository; + private final PostLikeRepository postLikeRepository; + + public List findMyPostResults(UserEntity user, List likedPostIds) { + return postRepository.findAllByUser(user).stream() + .sorted(Comparator.comparing(PostEntity::getPostId).reversed()) + .map(post -> { + var route = post.getRoute(); + + RegionEntity region = route.getRegion(); + + String regionName = route.getRegion().getParent() != null + ? region.getParent().getRegionName() + " " + region.getRegionName() + : region.getRegionName(); + + int durationMinutes = (route != null) ? (int)(route.getDuration() / 60) : 0; + + String routeMapImageUrl = (route != null && route.getTrackingImage() != null) + ? route.getTrackingImage().getImageUrl() + : null; + + return GetPostCardResult.builder() + .postId(post.getPostId()) + .regionName(regionName) + .title(post.getTitle()) + .createdAt(post.getCreatedAt()) + .durationMinutes(durationMinutes) + .isLike(likedPostIds.contains(post.getPostId())) + .routeMapImageUrl(routeMapImageUrl) + .build(); + }) + .toList(); + } + + public List getLikedPostIds(Long userId) { + return postLikeRepository.findLikedPostIdsByUserId(userId); + } +} \ No newline at end of file