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
98 changes: 97 additions & 1 deletion src/docs/asciidoc/post-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,100 @@ include::{snippetsDir}/loadPostDetail/1/response-fields.adoc[]

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

include::{snippetsDir}/loadPostDetail/2/http-response.adoc[]
include::{snippetsDir}/loadPostDetail/2/http-response.adoc[]

---

=== **3. 게시글 수정**

유저픽 게시글 수정 api 입니다. +
수정한 필드에 대해서만 요청 데이터에 담아서 요청하면 됩니다. +
다음과 같이 수정 요청 가능합니다. +
- 기존 게시글 내용 수정 +
- 새로운 게시글 이미지 추가 +
- 기존 게시글 이미지 삭제 +
- 새로운 상품 추가 +
- 기존 상품 내용 수정 +
- 기존 상품 삭제 +
- 새로운 상품 이미지 추가 +
- 기존 상품 이미지 삭제 +
기존 상품의 이미지를 변경할 때, 기존 이미지를 삭제한다면 `deleteProductImageId` 필드에 꼭 상품 이미지 ID를 기재하고, 새로운 이미지를 등록하면 `imageIndex` 필드에 관련 상품 이미지 파일의 인덱스를 꼭 기재해야 합니다. +
`imageIndex` 관련 내용은 게시글 저장 API와 동일합니다.

==== Request
include::{snippetsDir}/updatePost/1/curl-request.adoc[]

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

==== Request Parts
include::{snippetsDir}/updatePost/1/request-parts.adoc[]

==== Request Parts : **data** - Detail Fields
include::{snippetsDir}/updatePost/1/request-part-data-fields.adoc[]

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

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

==== 실패 Response
실패 1. 인증되지 않은 유저일 경우

include::{snippetsDir}/updatePost/2/http-response.adoc[]

실패 2. 존재하지 않는 게시글일 경우

include::{snippetsDir}/updatePost/3/http-response.adoc[]

실패 3. 게시글을 조작할 권한이 없을 경우 (요청한 유저 != 작성한 유저)

include::{snippetsDir}/updatePost/4/http-response.adoc[]


실패 4. 이미지와 상품 정보가 매핑되지 않을 경우 +
- 상품 정보 imageIndex 중복 +
- 이미지 개수와 상품 개수 불일치 (이미지를 등록하지 않은 상품을 제외한 개수로 비교) +

include::{snippetsDir}/updatePost/5/http-response.adoc[]


실패 5. 요청한 파일 목록 검증에 실패할 경우 (이미지 파일 X, 사이즈)

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

실패 6. 이미지 파일 업로드에 실패할 경우

include::{snippetsDir}/updatePost/7/http-response.adoc[]

실패 7. 요청 데이터의 게시글 이미지가 해당 게시글의 이미지가 아닐 경우 +
- 게시글 이미지 삭제 +
- deletePostImageIds +

include::{snippetsDir}/updatePost/8/http-response.adoc[]

실패 8. 요청 데이터의 상품 정보가 해당 게시글의 상품이 아닐 경우 +
- 상품 삭제 +
- 상품 업데이트 +
- deleteProductIds, updateProducts.id +

include::{snippetsDir}/updatePost/9/http-response.adoc[]

실패 9. 요청 데이터의 상품 이미지 정보가 해당 상품의 이미지가 아닐 경우 +
- 상품 이미지 변경 시 삭제 +
- updateProducts.deleteProductImageId +

include::{snippetsDir}/updatePost/10/http-response.adoc[]

실패 10. 기본 상품 이미지 삭제를 요청할 경우

include::{snippetsDir}/updatePost/11/http-response.adoc[]

실패 11. 기존 상품 이미지가 존재하지만, 새로운 이미지 등록을 요청할 경우

include::{snippetsDir}/updatePost/12/http-response.adoc[]




Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.ftm.server.adapter.in.web.post.controller;

import com.ftm.server.adapter.in.web.post.dto.request.UpdatePostRequest;
import com.ftm.server.application.command.post.UpdatePostCommand;
import com.ftm.server.application.port.in.post.UpdatePostUseCase;
import com.ftm.server.common.response.ApiResponse;
import com.ftm.server.common.response.enums.SuccessResponseCode;
import com.ftm.server.infrastructure.security.UserPrincipal;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequiredArgsConstructor
public class UpdatePostController {

private final UpdatePostUseCase updatePostUseCase;

@PatchMapping("/api/posts/{postId}")
public ResponseEntity<ApiResponse<?>> updatePost(
@PathVariable Long postId,
@RequestPart(value = "data") UpdatePostRequest request,
@RequestPart(value = "postImageFiles", required = false)
List<MultipartFile> postImageFiles,
@RequestPart(value = "productImageFiles", required = false)
List<MultipartFile> productImageFiles,
@AuthenticationPrincipal UserPrincipal userPrincipal) {

updatePostUseCase.execute(
UpdatePostCommand.from(
postId, userPrincipal.getId(), request, postImageFiles, productImageFiles));

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

import com.ftm.server.domain.enums.HashTag;
import java.util.List;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class UpdatePostProductRequest {

private final Long id;
private final String name;
private final String brand;
private final List<HashTag> hashTags;
private final Long deleteProductImageId;
private final int imageIndex;

public static UpdatePostProductRequest of(
Long id,
String name,
String brand,
List<HashTag> hashTags,
Long deleteProductImageId,
int imageIndex) {
return UpdatePostProductRequest.builder()
.id(id)
.name(name)
.brand(brand)
.hashTags(hashTags)
.deleteProductImageId(deleteProductImageId)
.imageIndex(imageIndex)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.ftm.server.adapter.in.web.post.dto.request;

import com.ftm.server.domain.enums.GroomingCategory;
import com.ftm.server.domain.enums.HashTag;
import java.util.List;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class UpdatePostRequest {

private final String title;
private final GroomingCategory groomingCategory;
private final List<HashTag> hashTags;
private final String content;
private final List<Long> deletePostImageIds; // 삭제할 게시글 이미지 ID 목록

private final List<Long> deleteProductIds; // 삭제할 상품 ID 목록
private final List<SavePostProductRequest> addProducts; // 새로 추가할 상품 목록
private final List<UpdatePostProductRequest> updateProducts; // 수정할 상품 목록

public static UpdatePostRequest of(
String title,
GroomingCategory groomingCategory,
List<HashTag> hashTags,
String content,
List<Long> deletePostImageIds,
List<Long> deleteProductIds,
List<SavePostProductRequest> addProducts,
List<UpdatePostProductRequest> updateProducts) {
return UpdatePostRequest.builder()
.title(title)
.groomingCategory(groomingCategory)
.hashTags(hashTags)
.content(content)
.deletePostImageIds(deletePostImageIds)
.deleteProductIds(deleteProductIds)
.addProducts(addProducts)
.updateProducts(updateProducts)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
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.*;
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.application.query.*;
import com.ftm.server.common.annotation.Adapter;
import com.ftm.server.common.exception.CustomException;
import com.ftm.server.common.response.enums.ErrorResponseCode;
Expand All @@ -32,7 +29,12 @@ public class PostDomainPersistenceAdapter
LoadPostProductImagePort,
LoadUserForPostPort,
LoadUserImageForPostPort,
UpdatePostPort {
UpdatePostPort,
UpdatePostProductPort,
UpdatePostProductImagePort,
DeletePostImagePort,
DeletePostProductPort,
DeletePostProductImagePort {

private final PostRepository postRepository;
private final PostImageRepository postImageRepository;
Expand Down Expand Up @@ -162,14 +164,20 @@ public List<PostProduct> loadPostProductsByPostId(FindByPostIdQuery query) {
}

@Override
public Map<Long, PostProductImage> loadPostProductImagesByPostProductIds(
FindByPostProductIdsQuery query) {
public List<PostProduct> loadPostProductsByIds(FindByIdsQuery query) {
return postProductRepository.findAllById(query.getIds()).stream()
.map(postProductMapper::toDomainEntity)
.toList();
}

@Override
public List<PostProductImage> loadPostProductImagesByPostProductIds(FindByIdsQuery query) {
List<PostProductImageJpaEntity> postProductImageJpaEntities =
postProductImageRepository.findByPostProductIds(query);

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

@Override
Expand Down Expand Up @@ -198,4 +206,55 @@ public void updatePost(Post post) {

postJpaEntity.updatePostForDomainEntity(post);
}

@Override
public void updatePostProducts(List<PostProduct> postProducts) {
List<Long> ids = postProducts.stream().map(PostProduct::getId).toList();
Map<Long, PostProductJpaEntity> postProductJpaEntityMap =
postProductRepository.findAllById(ids).stream()
.collect(
Collectors.toMap(PostProductJpaEntity::getId, Function.identity()));

for (PostProduct postProduct : postProducts) {
PostProductJpaEntity postProductJpaEntity =
postProductJpaEntityMap.get(postProduct.getId());
postProductJpaEntity.updatePostProductForDomainEntity(postProduct);
}
}

@Override
public void updatePostProductImages(List<PostProductImage> postProductImages) {
List<Long> ids = postProductImages.stream().map(PostProductImage::getId).toList();
Map<Long, PostProductImageJpaEntity> postProductImageJpaEntityMap =
postProductImageRepository.findAllById(ids).stream()
.collect(
Collectors.toMap(
PostProductImageJpaEntity::getId, Function.identity()));

for (PostProductImage postProductImage : postProductImages) {
PostProductImageJpaEntity postProductImageJpaEntity =
postProductImageJpaEntityMap.get(postProductImage.getId());
postProductImageJpaEntity.updatePostProductImageForDomainEntity(postProductImage);
}
}

public void deletePostImages(List<PostImage> postImages) {
List<Long> ids = postImages.stream().map(PostImage::getId).toList();

postImageRepository.deleteAllById(ids);
}

@Override
public void deletePostProducts(List<PostProduct> postProducts) {
List<Long> ids = postProducts.stream().map(PostProduct::getId).toList();

postProductRepository.deleteAllById(ids);
}

@Override
public void deletePostProductImages(List<PostProductImage> postProductImages) {
List<Long> ids = postProductImages.stream().map(PostProductImage::getId).toList();

postProductImageRepository.deleteAllById(ids);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ public static PostImageJpaEntity from(PostImage postImage, PostJpaEntity postJpa
.objectKey(postImage.getObjectKey())
.build();
}

public void updatePostImageForDomainEntity(PostImage postImage) {
this.objectKey = objectKey;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ public static PostProductImageJpaEntity from(
.objectKey(postProductImage.getObjectKey())
.build();
}

public void updatePostProductImageForDomainEntity(PostProductImage postProductImage) {
this.objectKey = postProductImage.getObjectKey();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,10 @@ public static PostProductJpaEntity from(PostProduct postProduct, PostJpaEntity p
.hashtags(postProduct.getHashTags())
.build();
}

public void updatePostProductForDomainEntity(PostProduct postProduct) {
this.name = postProduct.getName();
this.brand = postProduct.getBrand();
this.hashtags = postProduct.getHashTags();
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +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 com.ftm.server.application.query.FindByIdsQuery;
import java.util.List;

public interface PostProductImageCustomRepository {

List<PostProductImageJpaEntity> findByPostProductIds(FindByPostProductIdsQuery query);
List<PostProductImageJpaEntity> findByPostProductIds(FindByIdsQuery query);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import static com.ftm.server.adapter.out.persistence.model.QPostProductImageJpaEntity.postProductImageJpaEntity;

import com.ftm.server.adapter.out.persistence.model.PostProductImageJpaEntity;
import com.ftm.server.application.query.FindByPostProductIdsQuery;
import com.ftm.server.application.query.FindByIdsQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -16,10 +16,10 @@ public class PostProductImageCustomRepositoryImpl implements PostProductImageCus
private final JPAQueryFactory queryFactory;

@Override
public List<PostProductImageJpaEntity> findByPostProductIds(FindByPostProductIdsQuery query) {
public List<PostProductImageJpaEntity> findByPostProductIds(FindByIdsQuery query) {
return queryFactory
.selectFrom(postProductImageJpaEntity)
.where(postProductImageJpaEntity.postProduct.id.in(query.getPostProductIds()))
.where(postProductImageJpaEntity.postProduct.id.in(query.getIds()))
.fetch();
}
}
Loading
Loading