Skip to content

Commit

Permalink
Feat: 부스 상품 수정 API (#265)
Browse files Browse the repository at this point in the history
* Add: 부스 상품 필드를 업데이트할 dto 객체 추가

* Add: 부스 상품 엔티티에 업데이트 메서드 추가

* Add: 부스 상품 수정 요청 객체 추가

* Feat: 부스 상품의 내용을 업데이트하는 기능 추가

* Add: 다른 부스의 카테고리 id를 요청했을 경우의 에러코드 추가

* Feat: 부스 상품의 카테고리를 변경하는 기능 추가

* Feat: 부스 상품 수정 api 컨트롤러 추가

* Refactor: 부스 상품 이미지 서비스 분리

* Refactor: 부스 상품 카테고리 수정 기능 클래스 분리

* Add: 부스 상품 이미지를 수정하는 기능

* Style: 사용하지 않은 줄 삭제

* Fix: 이미지 파일을 받을 수 있도록 요청 방식 변경

* Fix: 카테고리를 변경하지 않는 경우의 처리
  • Loading branch information
muncool39 authored Oct 14, 2024
1 parent 09e5c11 commit 5df2f83
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.openbook.openbook.api.booth;

import com.openbook.openbook.api.booth.request.ProductModifyRequest;
import com.openbook.openbook.api.booth.request.ProductCategoryRegister;
import com.openbook.openbook.api.booth.request.ProductRegistrationRequest;
import com.openbook.openbook.api.booth.response.CategoryProductsResponse;
import com.openbook.openbook.api.booth.response.ProductCategoryResponse;
import com.openbook.openbook.service.booth.BoothProductService;
import com.openbook.openbook.api.ResponseMessage;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
Expand All @@ -15,8 +17,10 @@
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -65,6 +69,16 @@ public List<ProductCategoryResponse> getProductCategory(@PathVariable Long booth
return boothProductService.getProductCategoryResponseList(booth_id);
}

@ResponseStatus(HttpStatus.OK)
@PatchMapping("/booths/products/{product_id}")
public ResponseMessage modifyProduct(Authentication authentication,
@PathVariable long product_id,
@NotNull ProductModifyRequest request) {
boothProductService.updateProduct(Long.parseLong(authentication.getName()), product_id, request);
return new ResponseMessage("상품 수정에 성공했습니다.");
}


@ResponseStatus(HttpStatus.OK)
@DeleteMapping("/booths/products/{product_id}")
public ResponseMessage deleteProduct(Authentication authentication,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.openbook.openbook.api.booth.request;

import java.util.List;
import org.springframework.web.multipart.MultipartFile;

public record ProductModifyRequest(
String name,
String description,
Integer stock,
Integer price,
Long categoryId,
List<MultipartFile> imageToAdd,
List<Long> imageToDelete
) {
}
16 changes: 16 additions & 0 deletions src/main/java/com/openbook/openbook/domain/booth/BoothProduct.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.openbook.openbook.domain.booth;

import com.openbook.openbook.service.booth.dto.BoothProductUpdateData;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -40,6 +41,21 @@ public BoothProduct(String name, String description, int stock, int price, Booth
this.linkedCategory = linkedCategory;
}

public void updateProduct(BoothProductUpdateData updateData) {
if (updateData.name()!=null) {
this.name = updateData.name();
}
if (updateData.description()!=null) {
this.description = updateData.description();
}
if (updateData.stock()!=null) {
this.stock = updateData.stock();
}
if (updateData.price()!=null) {
this.price = updateData.price();
}
}

public void updateCategory(BoothProductCategory category) {
this.linkedCategory = category;
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/openbook/openbook/exception/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public enum ErrorCode {
EXCEED_MAXIMUM_CATEGORY(HttpStatus.CONFLICT, "생성할 수 있는 최대 카테고리 수를 초과했습니다."),
DEFAULT_CATEGORY_CANNOT_DELETED(HttpStatus.CONFLICT, "기본 카테고리는 삭제할 수 없습니다."),
ALREADY_EXIST_CATEGORY(HttpStatus.CONFLICT, "이미 존재하는 카테고리 입니다."),
NOT_SELECTABLE_CATEGORY(HttpStatus.CONFLICT, "해당 부스의 카테고리만 선택 가능합니다."),


// NOT FOUND
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "유저 정보를 찾을 수 없습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public interface BoothProductImageRepository extends JpaRepository<BoothProductI

List<BoothProductImage> findAllByLinkedProductId(Long linkedProductId);

int countAllByLinkedProductId(Long linkedProductId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ public void createProductCategory(String categoryName, String description, Booth
);
}

public void updateProductCategory(Long id, final BoothProduct product) {
if(id==null) return;
BoothProductCategory category = getProductCategoryOrException(id);
if(category.getLinkedBooth()!=product.getLinkedCategory().getLinkedBooth()) {
throw new OpenBookException(ErrorCode.NOT_SELECTABLE_CATEGORY);
}
product.updateCategory(category);
}

public void deleteProductCategory(final BoothProductCategory category) {
if(category.getName().equals(DEFAULT_NAME)) {
throw new OpenBookException(ErrorCode.DEFAULT_CATEGORY_CANNOT_DELETED);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.openbook.openbook.service.booth;

import com.openbook.openbook.domain.booth.BoothProduct;
import com.openbook.openbook.domain.booth.BoothProductImage;
import com.openbook.openbook.exception.ErrorCode;
import com.openbook.openbook.exception.OpenBookException;
import com.openbook.openbook.repository.booth.BoothProductImageRepository;
import com.openbook.openbook.util.S3Service;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
public class BoothProductImageService {

private final BoothProductImageRepository boothProductImageRepository;
private final S3Service s3Service;

public void createBoothProductImage(final List<MultipartFile> images, final BoothProduct product) {
if(images==null || images.isEmpty()) return;
images.forEach(image -> boothProductImageRepository.save(
BoothProductImage.builder()
.imageUrl(s3Service.uploadFileAndGetUrl(image))
.linkedProduct(product)
.build()
));
}

public List<BoothProductImage> getProductImages(final BoothProduct product) {
return boothProductImageRepository.findAllByLinkedProductId(product.getId());
}

public void modifyReviewImage(List<MultipartFile> add, List<Long> delete, BoothProduct product) {
int addSize = (add!=null)?add.size():0, deleteSize = (delete!=null)?delete.size():0;
if(getProductImageCount(product) - deleteSize + addSize > 5) {
throw new OpenBookException(ErrorCode.EXCEED_MAXIMUM_IMAGE);
}
createBoothProductImage(add, product);
for(int i = 0; i < deleteSize; i++) {
BoothProductImage image = getProductImageOrException(delete.get(i));
boothProductImageRepository.delete(image);
}
}

private BoothProductImage getProductImageOrException(long id) {
return boothProductImageRepository.findById(id).orElseThrow(() ->
new OpenBookException(ErrorCode.IMAGE_NOT_FOUND)
);
}

private int getProductImageCount(final BoothProduct product) {
return boothProductImageRepository.countAllByLinkedProductId(product.getId());
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.openbook.openbook.service.booth;


import com.openbook.openbook.api.booth.request.ProductModifyRequest;
import com.openbook.openbook.api.booth.request.ProductCategoryRegister;
import com.openbook.openbook.api.booth.request.ProductRegistrationRequest;
import com.openbook.openbook.api.booth.response.BoothProductResponse;
Expand All @@ -9,13 +10,11 @@
import com.openbook.openbook.domain.booth.Booth;
import com.openbook.openbook.domain.booth.BoothProduct;
import com.openbook.openbook.domain.booth.BoothProductCategory;
import com.openbook.openbook.domain.booth.BoothProductImage;
import com.openbook.openbook.domain.booth.dto.BoothStatus;
import com.openbook.openbook.repository.booth.BoothProductImageRepository;
import com.openbook.openbook.repository.booth.BoothProductRepository;
import com.openbook.openbook.exception.ErrorCode;
import com.openbook.openbook.exception.OpenBookException;
import com.openbook.openbook.util.S3Service;
import com.openbook.openbook.service.booth.dto.BoothProductUpdateData;
import com.openbook.openbook.domain.user.User;
import com.openbook.openbook.service.user.UserService;
import java.util.ArrayList;
Expand All @@ -25,19 +24,17 @@
import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

@Service
@RequiredArgsConstructor
public class BoothProductService {

private final BoothProductRepository boothProductRepository;
private final BoothProductImageRepository boothProductImageRepository;
private final S3Service s3Service;

private final UserService userService;
private final BoothService boothService;
private final BoothProductCategoryService categoryService;
private final BoothProductImageService imageService;


@Transactional(readOnly = true)
Expand All @@ -49,7 +46,7 @@ public List<CategoryProductsResponse> findAllBoothProducts(final long boothId, f
Slice<BoothProductResponse> products = getProductsByCategory(category, pageable).map(
boothProduct -> BoothProductResponse.of(
boothProduct,
getProductImages(boothProduct)
imageService.getProductImages(boothProduct)
)
);
if(products.getNumberOfElements()!=0) {
Expand All @@ -75,7 +72,7 @@ public CategoryProductsResponse findCategoryProducts(final long categoryId, fina
Slice<BoothProductResponse> products = getProductsByCategory(category, pageable).map(
boothProduct -> BoothProductResponse.of(
boothProduct,
getProductImages(boothProduct)
imageService.getProductImages(boothProduct)
)
);
return CategoryProductsResponse.of(category, products);
Expand Down Expand Up @@ -105,11 +102,24 @@ public void addBoothProduct(Long userId, Long boothId, ProductRegistrationReques
.linkedCategory(categoryService.getProductCategoryOrException(request.categoryId()))
.build()
);
if(request.images()!=null && !request.images().isEmpty()) {
request.images().forEach(imageUrl -> {
createBoothProductImage(imageUrl, product);
});
imageService.createBoothProductImage(request.images(), product);
}

@Transactional
public void updateProduct(final long userId, final long productId, final ProductModifyRequest request) {
BoothProduct product = getBoothProductOrException(productId);
if(product.getLinkedCategory().getLinkedBooth().getManager().getId()!=userId) {
throw new OpenBookException(ErrorCode.FORBIDDEN_ACCESS);
}
product.updateProduct(BoothProductUpdateData.builder()
.name(request.name())
.description(request.description())
.stock(request.stock())
.price(request.price())
.build()
);
categoryService.updateProductCategory(request.categoryId(), product);
imageService.modifyReviewImage(request.imageToAdd(), request.imageToDelete(), product);
}

@Transactional
Expand All @@ -132,8 +142,7 @@ public void deleteCategory(final long userId, final long categoryId, final Strin
boothProductRepository.findAllByLinkedCategoryId(categoryId).forEach(product -> {
if(delete) {
boothProductRepository.delete(product);
}
else {
} else {
product.updateCategory(defaultCategory);
}
});
Expand All @@ -144,19 +153,6 @@ public Slice<BoothProduct> getProductsByCategory(final BoothProductCategory cate
return boothProductRepository.findAllByLinkedCategoryId(category.getId(), pageable);
}

public List<BoothProductImage> getProductImages(final BoothProduct product) {
return boothProductImageRepository.findAllByLinkedProductId(product.getId());
}

public void createBoothProductImage(final MultipartFile imageUrl, final BoothProduct boothProduct) {
boothProductImageRepository.save(
BoothProductImage.builder()
.imageUrl(s3Service.uploadFileAndGetUrl(imageUrl))
.linkedProduct(boothProduct)
.build()
);
}

private Booth getValidBoothOrException(Long userId, Long boothId) {
User user = userService.getUserOrException(userId);
Booth booth = boothService.getBoothOrException(boothId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.openbook.openbook.service.booth.dto;

import lombok.Builder;

@Builder
public record BoothProductUpdateData(
String name,
String description,
Integer stock,
Integer price
) {
}

0 comments on commit 5df2f83

Please sign in to comment.