Skip to content
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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<String> 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
) {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@
@Builder
public record GetPostCardResult(
Long postId,
String regionName,
String title,
boolean isLike,
AuthorDto author,
List<String> categoryTags,
LocalDateTime createdAt,
String routeMapImageUrl,
Long routeId,
boolean isPublic,
boolean isMine
Integer durationMinutes,
boolean isLike,
String routeMapImageUrl
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -13,4 +15,6 @@ public interface PostLikeRepository {
List<PostLikeEntity> findAllByUserWithPostAndImages(Long userId);

void deleteByUserIdAndPostId(Long userId, Long postId);

List<Long> findLikedPostIdsByUserId(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ public void deleteByUserIdAndPostId(Long userId, Long postId) {
public List<PostLikeEntity> findAllByUserWithPostAndImages(Long userId) {
return jpaRepository.findAllByUserWithPostAndImages(userId);
}

@Override
public List<Long> findLikedPostIdsByUserId(Long userId) {
return jpaRepository.findLikedPostIdsByUserId(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -121,22 +122,21 @@ public List<GetPostCardResult> 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ public interface SpringDataPostLikeRepository extends JpaRepository<PostLikeEnti
@Modifying
@Query("DELETE FROM PostLikeEntity pl WHERE pl.user.userId = :userId AND pl.post.postId = :postId")
void deleteByUserIdAndPostIdQuery(@Param("userId") Long userId, @Param("postId") Long postId);

@Query("SELECT pl.post.postId FROM PostLikeEntity pl WHERE pl.user.userId = :userId")
List<Long> findLikedPostIdsByUserId(@Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -79,7 +80,7 @@ public ResponseEntity<ApiResponse<UserRegisterResponseDto>> createUser(
})
@GetMapping("/me/likes")
public ResponseEntity<ApiResponse<ListResponseWrapper<PostCardResponseDto>>> getMyLikedPosts(
@UserId Long userId
@Parameter(hidden = true) @UserId Long userId
) {
List<PostCardResponseDto> likedPosts = userLikedPostQueryFacade.getLikedPosts(userId);
return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(likedPosts)));
Expand Down Expand Up @@ -107,7 +108,7 @@ public ResponseEntity<ApiResponse<UserInfoResponseDto>> getUserProfile(
})
@GetMapping("/me/posts")
public ResponseEntity<ApiResponse<ListResponseWrapper<PostCardResponseDto>>> getMyPosts(
@UserId Long userId
@Parameter(hidden = true) @UserId Long userId
) {
List<PostCardResponseDto> myPosts = userWrittenPostQueryFacade.getMyPosts(userId);
return ResponseEntity.ok(ApiResponse.success(ListResponseWrapper.from(myPosts)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,38 +42,22 @@ public List<PostCardResponseDto> 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<String> 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();

}
}

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -23,46 +26,17 @@
public class UserWrittenPostQueryFacade {

private final UserQueryRepository userQueryRepository;
private final PostRepository postRepository;
private final UserWrittenPostQueryService userWrittenPostQueryService;

public List<PostCardResponseDto> getMyPosts(Long userId) {
UserEntity user = userQueryRepository.getUserByUserId(userId)
.orElseThrow(() -> new UserBusinessException(UserErrorCode.USER_NOT_FOUND));

List<PostEntity> 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<Long> likedPostIds = userWrittenPostQueryService.getLikedPostIds(userId);
List<GetPostCardResult> results = userWrittenPostQueryService.findMyPostResults(user, likedPostIds);

List<String> 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();
}

}
Original file line number Diff line number Diff line change
@@ -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<GetPostCardResult> findMyPostResults(UserEntity user, List<Long> 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<Long> getLikedPostIds(Long userId) {
return postLikeRepository.findLikedPostIdsByUserId(userId);
}
}