Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/docs/asciidoc/post-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,27 @@ include::{snippetsDir}/savePost/5/http-response.adoc[]
실패 5. 이미지 파일 업로드에 실패할 경우

include::{snippetsDir}/savePost/6/http-response.adoc[]

---

=== **2. 게시글 상세 조회**

유저픽 게시글 상세 조회 api 입니다.

==== Request
include::{snippetsDir}/loadPostDetail/1/http-request.adoc[]

==== Request Path Parameters
include::{snippetsDir}/loadPostDetail/1/path-parameters.adoc[]

==== 성공 Response
include::{snippetsDir}/loadPostDetail/1/http-response.adoc[]

==== Response Body Fields
include::{snippetsDir}/loadPostDetail/1/response-fields.adoc[]

==== 실패 Response

실패 1. 존재하지 않는 게시글이거나, 삭제된 게시글인 경우

include::{snippetsDir}/loadPostDetail/2/http-response.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.ftm.server.adapter.in.web.post.controller;

import com.ftm.server.adapter.in.web.post.dto.response.LoadPostDetailResponse;
import com.ftm.server.application.port.in.post.LoadPostDetailUseCase;
import com.ftm.server.application.query.FindByIdQuery;
import com.ftm.server.application.vo.post.PostDetailVo;
import com.ftm.server.common.response.ApiResponse;
import com.ftm.server.common.response.enums.SuccessResponseCode;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class LoadPostDetailController {

private final LoadPostDetailUseCase loadPostDetailUseCase;

@GetMapping("/api/posts/{postId}")
public ResponseEntity<ApiResponse<?>> loadPostDetail(@PathVariable Long postId) {
PostDetailVo vo = loadPostDetailUseCase.execute(FindByIdQuery.of(postId));

return ResponseEntity.status(HttpStatus.OK)
.body(ApiResponse.success(SuccessResponseCode.OK, LoadPostDetailResponse.from(vo)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.ftm.server.adapter.in.web.post.dto.response;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.ftm.server.application.vo.post.PostDetailVo;
import com.ftm.server.domain.enums.GroomingCategory;
import com.ftm.server.domain.enums.HashTag;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import lombok.Getter;

@Getter
public class LoadPostDetailResponse {

private final Long postId;
private final String title;
private final String content;
private final GroomingCategory groomingCategory;
private final List<String> hashTags;
private final Integer viewCount;
private final Integer likeCount;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm", shape = JsonFormat.Shape.STRING)
private final LocalDateTime createdAt;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm", shape = JsonFormat.Shape.STRING)
private final LocalDateTime updatedAt;

private final List<PostImageResponse> postImages;
private final PostWriterResponse writer;
private final List<PostProductResponse> postProducts;

private LoadPostDetailResponse(PostDetailVo postDetailVo) {
this.postId = postDetailVo.getPostId();
this.title = postDetailVo.getTitle();
this.content = postDetailVo.getContent();
this.groomingCategory = postDetailVo.getGroomingCategory();
this.hashTags = Arrays.stream(postDetailVo.getHashTags()).map(HashTag::getValue).toList();
this.viewCount = postDetailVo.getViewCount();
this.likeCount = postDetailVo.getLikeCount();
this.createdAt = postDetailVo.getCreatedAt();
this.updatedAt = postDetailVo.getUpdatedAt();
this.postImages =
postDetailVo.getPostImages().stream().map(PostImageResponse::from).toList();
this.writer = PostWriterResponse.from(postDetailVo.getUser(), postDetailVo.getUserImage());
this.postProducts =
postDetailVo.getProducts().stream().map(PostProductResponse::from).toList();
}

public static LoadPostDetailResponse from(PostDetailVo postDetailVo) {
return new LoadPostDetailResponse(postDetailVo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ftm.server.adapter.in.web.post.dto.response;

import static com.ftm.server.common.consts.PropertiesHolder.CDN_PATH;

import com.ftm.server.domain.entity.PostImage;
import lombok.Getter;

@Getter
public class PostImageResponse {

private final Long postImageId;
private final String imageUrl;

private PostImageResponse(PostImage postImage) {
this.postImageId = postImage.getId();
this.imageUrl = CDN_PATH + "/" + postImage.getObjectKey();
}

public static PostImageResponse from(PostImage postImage) {
return new PostImageResponse(postImage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.ftm.server.adapter.in.web.post.dto.response;

import static com.ftm.server.common.consts.PropertiesHolder.CDN_PATH;

import com.ftm.server.domain.entity.PostProductImage;
import lombok.Getter;

@Getter
public class PostProductImageResponse {

private final Long postProductImageId;
private final String imageUrl;

private PostProductImageResponse(PostProductImage postProductImage) {
this.postProductImageId = postProductImage.getId();
this.imageUrl = CDN_PATH + "/" + postProductImage.getObjectKey();
}

public static PostProductImageResponse from(PostProductImage postProductImage) {
return new PostProductImageResponse(postProductImage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.ftm.server.adapter.in.web.post.dto.response;

import com.ftm.server.application.vo.post.PostProductDetailVo;
import com.ftm.server.domain.enums.HashTag;
import java.util.Arrays;
import java.util.List;
import lombok.Getter;

@Getter
public class PostProductResponse {

private final Long postProductId;
private final String name;
private final String brand;
private final List<String> hashTags;
private final PostProductImageResponse postProductImage;

private PostProductResponse(PostProductDetailVo postProductDetailVo) {
this.postProductId = postProductDetailVo.getPostProductId();
this.name = postProductDetailVo.getName();
this.brand = postProductDetailVo.getBrand();
this.hashTags =
Arrays.stream(postProductDetailVo.getHashTags()).map(HashTag::getValue).toList();
this.postProductImage =
PostProductImageResponse.from(postProductDetailVo.getPostProductImage());
}

public static PostProductResponse from(PostProductDetailVo postProductDetailVo) {
return new PostProductResponse(postProductDetailVo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.ftm.server.adapter.in.web.post.dto.response;

import static com.ftm.server.common.consts.PropertiesHolder.CDN_PATH;

import com.ftm.server.domain.entity.User;
import com.ftm.server.domain.entity.UserImage;
import lombok.Getter;

@Getter
public class PostWriterResponse {

private final Long userId;
private final String nickname;
private final String imageUrl;

private PostWriterResponse(User user, UserImage userImage) {
this.userId = user.getId();
this.nickname = user.getNickname();
this.imageUrl = CDN_PATH + "/" + userImage.getObjectKey();
}

public static PostWriterResponse from(User user, UserImage userImage) {
return new PostWriterResponse(user, userImage);
}
}
Original file line number Diff line number Diff line change
@@ -1,40 +1,52 @@
package com.ftm.server.adapter.out.persistence.adapter.post;

import com.ftm.server.adapter.out.persistence.mapper.PostImageMapper;
import com.ftm.server.adapter.out.persistence.mapper.PostMapper;
import com.ftm.server.adapter.out.persistence.mapper.PostProductImageMapper;
import com.ftm.server.adapter.out.persistence.mapper.PostProductMapper;
import com.ftm.server.adapter.out.persistence.mapper.*;
import com.ftm.server.adapter.out.persistence.model.*;
import com.ftm.server.adapter.out.persistence.repository.*;
import com.ftm.server.application.port.out.persistence.post.SavePostImagePort;
import com.ftm.server.application.port.out.persistence.post.SavePostPort;
import com.ftm.server.application.port.out.persistence.post.SavePostProductImagePort;
import com.ftm.server.application.port.out.persistence.post.SavePostProductPort;
import com.ftm.server.application.port.out.persistence.post.*;
import com.ftm.server.application.query.FindByIdQuery;
import com.ftm.server.application.query.FindByPostIdQuery;
import com.ftm.server.application.query.FindByPostProductIdsQuery;
import com.ftm.server.application.query.FindByUserIdQuery;
import com.ftm.server.common.annotation.Adapter;
import com.ftm.server.common.exception.CustomException;
import com.ftm.server.common.response.enums.ErrorResponseCode;
import com.ftm.server.domain.entity.Post;
import com.ftm.server.domain.entity.PostImage;
import com.ftm.server.domain.entity.PostProduct;
import com.ftm.server.domain.entity.PostProductImage;
import com.ftm.server.domain.entity.*;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;

@Adapter
@RequiredArgsConstructor
public class PostDomainPersistenceAdapter
implements SavePostPort, SavePostImagePort, SavePostProductPort, SavePostProductImagePort {
implements SavePostPort,
SavePostImagePort,
SavePostProductPort,
SavePostProductImagePort,
LoadPostPort,
LoadPostImagePort,
LoadPostProductPort,
LoadPostProductImagePort,
LoadUserForPostPort,
LoadUserImageForPostPort,
UpdatePostPort {

private final PostRepository postRepository;
private final PostImageRepository postImageRepository;
private final PostProductRepository postProductRepository;
private final PostProductImageRepository postProductImageRepository;
private final UserRepository userRepository;
private final UserImageRepository userImageRepository;

private final PostMapper postMapper;
private final PostImageMapper postImageMapper;
private final PostProductMapper postProductMapper;
private final PostProductImageMapper postProductImageMapper;
private final UserMapper userMapper;
private final UserImageMapper userImageMapper;

@Override
public Post savePost(Post post) {
Expand Down Expand Up @@ -119,4 +131,71 @@ public List<PostProductImage> savePostProductImages(List<PostProductImage> produ
.map(postProductImageMapper::toDomainEntity)
.toList();
}

@Override
public Optional<Post> loadPost(FindByIdQuery query) {
return postRepository.findById(query.getId()).map(postMapper::toDomainEntity);
}

@Override
public List<PostImage> loadPostImagesByPostId(FindByPostIdQuery query) {
PostJpaEntity postJpaEntity =
postRepository
.findById(query.getPostId())
.orElseThrow(() -> new CustomException(ErrorResponseCode.POST_NOT_FOUND));

return postImageRepository.findAllByPost(postJpaEntity).stream()
.map(postImageMapper::toDomainEntity)
.toList();
}

@Override
public List<PostProduct> loadPostProductsByPostId(FindByPostIdQuery query) {
PostJpaEntity postJpaEntity =
postRepository
.findById(query.getPostId())
.orElseThrow(() -> new CustomException(ErrorResponseCode.POST_NOT_FOUND));

return postProductRepository.findAllByPost(postJpaEntity).stream()
.map(postProductMapper::toDomainEntity)
.toList();
}

@Override
public Map<Long, PostProductImage> loadPostProductImagesByPostProductIds(
FindByPostProductIdsQuery query) {
List<PostProductImageJpaEntity> postProductImageJpaEntities =
postProductImageRepository.findByPostProductIds(query);

return postProductImageJpaEntities.stream()
.map(postProductImageMapper::toDomainEntity)
.collect(Collectors.toMap(PostProductImage::getPostProductId, Function.identity()));
}

@Override
public Optional<User> loadUserById(FindByIdQuery query) {
return userRepository.findById(query.getId()).map(userMapper::toDomainEntity);
}

@Override
public Optional<UserImage> loadUserImageByUserId(FindByUserIdQuery query) {
UserJpaEntity userJpaEntity =
userRepository
.findById(query.getUserId())
.orElseThrow(() -> CustomException.USER_NOT_FOUND);

return userImageRepository
.findByUserId(query.getUserId())
.map(userImageMapper::toDomainEntity);
}

@Override
public void updatePost(Post post) {
PostJpaEntity postJpaEntity =
postRepository
.findById(post.getId())
.orElseThrow(() -> new CustomException(ErrorResponseCode.POST_NOT_FOUND));

postJpaEntity.updatePostForDomainEntity(post);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,15 @@ public static PostJpaEntity from(Post post, UserJpaEntity userJpaEntity) {
.deletedAt(post.getDeletedAt())
.build();
}

public void updatePostForDomainEntity(Post post) {
this.title = post.getTitle();
this.content = post.getContent();
this.groomingCategory = post.getGroomingCategory();
this.hashtags = post.getHashtags();
this.viewCount = post.getViewCount();
this.likeCount = post.getLikeCount();
this.isDeleted = post.getIsDeleted();
this.deletedAt = post.getDeletedAt();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.PostImageJpaEntity;
import com.ftm.server.adapter.out.persistence.model.PostJpaEntity;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PostImageRepository extends JpaRepository<PostImageJpaEntity, Long> {}
public interface PostImageRepository extends JpaRepository<PostImageJpaEntity, Long> {

List<PostImageJpaEntity> findAllByPost(PostJpaEntity post);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.ftm.server.adapter.out.persistence.repository;

import com.ftm.server.adapter.out.persistence.model.PostProductImageJpaEntity;
import com.ftm.server.application.query.FindByPostProductIdsQuery;
import java.util.List;

public interface PostProductImageCustomRepository {

List<PostProductImageJpaEntity> findByPostProductIds(FindByPostProductIdsQuery query);
}
Loading
Loading