Skip to content

Commit

Permalink
refactor: 대표장비 업데이트 로직 수정
Browse files Browse the repository at this point in the history
Co-authored-by: hamcheeseburger <[email protected]>
Co-authored-by: yangdongjue5510 <[email protected]>
  • Loading branch information
3 people committed Aug 1, 2022
1 parent 464c784 commit 69e84a4
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import com.woowacourse.f12.domain.inventoryproduct.InventoryProduct;
import com.woowacourse.f12.domain.inventoryproduct.InventoryProductRepository;
import com.woowacourse.f12.domain.member.Member;
import com.woowacourse.f12.domain.member.MemberRepository;
import com.woowacourse.f12.dto.request.inventoryproduct.ProfileProductRequest;
import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse;
import com.woowacourse.f12.exception.badrequest.InvalidProfileProductException;
import com.woowacourse.f12.exception.notfound.InventoryProductNotFoundException;
import com.woowacourse.f12.exception.internalserver.SqlUpdateException;
import com.woowacourse.f12.exception.notfound.MemberNotFoundException;
import java.util.List;
import java.util.Objects;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -28,31 +27,19 @@ public InventoryProductService(final InventoryProductRepository inventoryProduct

@Transactional
public void updateProfileProducts(final Long memberId, final ProfileProductRequest profileProductRequest) {
validateMember(memberId);
validateInvalidProfileProductRequest(profileProductRequest);
updateProfileProduct(profileProductRequest);
}

private void validateInvalidProfileProductRequest(final ProfileProductRequest profileProductRequest) {
if (Objects.isNull(profileProductRequest.getSelectedInventoryProductId()) && Objects.isNull(
profileProductRequest.getUnselectedInventoryProductId())) {
throw new InvalidProfileProductException();
}
final Member member = memberRepository.findById(memberId)
.orElseThrow(MemberNotFoundException::new);
updateProfileProduct(member, profileProductRequest);
}

private void updateProfileProduct(final ProfileProductRequest profileProductRequest) {
if (!Objects.isNull(profileProductRequest.getSelectedInventoryProductId())) {
updateProfileProduct(profileProductRequest.getSelectedInventoryProductId(), true);
private void updateProfileProduct(final Member member, final ProfileProductRequest profileProductRequest) {
final List<Long> selectedInventoryProductIds = profileProductRequest.getSelectedInventoryProductIds();
inventoryProductRepository.updateBulkProfileProductByMember(member);
final int updateCount = inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member,
selectedInventoryProductIds);
if (updateCount != selectedInventoryProductIds.size()) {
throw new SqlUpdateException();
}
if (!Objects.isNull(profileProductRequest.getUnselectedInventoryProductId())) {
updateProfileProduct(profileProductRequest.getUnselectedInventoryProductId(), false);
}
}

private void updateProfileProduct(final Long inventoryItemId, final boolean selected) {
final InventoryProduct inventoryProduct = inventoryProductRepository.findById(inventoryItemId)
.orElseThrow(InventoryProductNotFoundException::new);
inventoryProduct.updateSelected(selected);
}

public InventoryProductsResponse findByMemberId(final Long memberId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
import com.woowacourse.f12.domain.product.Product;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;

public interface InventoryProductRepository extends JpaRepository<InventoryProduct, Long> {

List<InventoryProduct> findByMemberId(Long memberId);

boolean existsByMemberAndProduct(Member member, Product product);

@Modifying(clearAutomatically = true)
@Query("update InventoryProduct i set i.selected = false where i.member = :member")
int updateBulkProfileProductByMember(Member member);

@Modifying(clearAutomatically = true)
@Query("update InventoryProduct i set i.selected = true "
+ "where i.member = :member and i.id in :selectedInventoryProductIds")
int updateBulkProfileProductByMemberAndIds(Member member, List<Long> selectedInventoryProductIds);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
package com.woowacourse.f12.dto.request.inventoryproduct;

import java.util.List;
import javax.validation.constraints.NotNull;
import lombok.Getter;

@Getter
public class ProfileProductRequest {

private Long selectedInventoryProductId;
private Long unselectedInventoryProductId;
@NotNull(message = "등록할 대표장비가 없습니다.")
private List<Long> selectedInventoryProductIds;

private ProfileProductRequest() {
}

public ProfileProductRequest(final Long selectedInventoryProductId, final Long unselectedInventoryProductId) {
this.selectedInventoryProductId = selectedInventoryProductId;
this.unselectedInventoryProductId = unselectedInventoryProductId;
public ProfileProductRequest(final List<Long> selectedInventoryProductIds) {
this.selectedInventoryProductIds = selectedInventoryProductIds;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.woowacourse.f12.exception.internalserver;

import com.woowacourse.f12.exception.CustomException;
import com.woowacourse.f12.exception.ErrorCode;

public class InternalServerException extends CustomException {

public InternalServerException(final ErrorCode errorCode, final String message) {
super(errorCode, message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.woowacourse.f12.exception.internalserver;

import com.woowacourse.f12.exception.ErrorCode;

public class SqlUpdateException extends InternalServerException {

public SqlUpdateException() {
super(ErrorCode.INTERNAL_SERVER_ERROR, "요청된 업데이트 개수와 실행된 업데이트의 수가 다릅니다.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
import static com.woowacourse.f12.exception.ErrorCode.INVALID_SEARCH_PARAM;

import com.woowacourse.f12.dto.response.ExceptionResponse;
import com.woowacourse.f12.exception.CustomException;
import com.woowacourse.f12.exception.badrequest.InvalidValueException;
import com.woowacourse.f12.exception.forbidden.ForbiddenMemberException;
import com.woowacourse.f12.exception.internalserver.ExternalServerException;
import com.woowacourse.f12.exception.internalserver.InternalServerException;
import com.woowacourse.f12.exception.notfound.NotFoundException;
import com.woowacourse.f12.exception.unauthorized.UnauthorizedException;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -67,6 +70,11 @@ public ResponseEntity<ExceptionResponse> handleForbiddenMemberException(final Fo
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ExceptionResponse.from(e));
}

@ExceptionHandler({ExternalServerException.class, InternalServerException.class})
public ResponseEntity<ExceptionResponse> handleInternalException(final CustomException e) {
return ResponseEntity.internalServerError().body(ExceptionResponse.from(e));
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ExceptionResponse> handleUnhandledException(final Exception e) {
log.error("[ERROR]", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse;
import com.woowacourse.f12.presentation.auth.LoginRequired;
import com.woowacourse.f12.presentation.auth.VerifiedMember;
import javax.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
Expand All @@ -25,8 +26,9 @@ public InventoryProductController(final InventoryProductService inventoryProduct

@PatchMapping("/inventoryProducts")
@LoginRequired
public ResponseEntity<Void> updateProfileProducts(@RequestBody final ProfileProductRequest profileProductRequest,
@VerifiedMember final Long memberId) {
public ResponseEntity<Void> updateProfileProducts(
@RequestBody @Valid final ProfileProductRequest profileProductRequest,
@VerifiedMember final Long memberId) {
inventoryProductService.updateProfileProducts(memberId, profileProductRequest);
return ResponseEntity.ok().build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class InventoryProductAcceptanceTest extends AcceptanceTest {
// when
ExtractableResponse<Response> profileProductResponse = 로그인된_상태로_PATCH_요청을_보낸다(
"api/v1/members/inventoryProducts", token,
new ProfileProductRequest(savedInventoryProduct.getId(), null));
new ProfileProductRequest(List.of(savedInventoryProduct.getId())));

List<InventoryProductResponse> inventoryProductResponses = 로그인된_상태로_GET_요청을_보낸다(
"/api/v1/members/inventoryProducts",
Expand All @@ -83,6 +83,34 @@ class InventoryProductAcceptanceTest extends AcceptanceTest {
);
}

@Test
void 대표_장비가_있는_상태에서_대표_장비를_모두_해제한다() {
// given
Product product = 제품을_저장한다(KEYBOARD_1.생성());
LoginResponse loginResponse = 로그인을_한다(CORINNE_GITHUB.getCode());
String token = loginResponse.getToken();
Member member = 응답을_회원으로_변환한다(loginResponse.getMember());

InventoryProduct inventoryProduct = SELECTED_INVENTORY_PRODUCT.생성(member, product);
InventoryProduct savedInventoryProduct = 인벤토리에_장비를_한다(inventoryProduct);

// when
ExtractableResponse<Response> profileProductResponse = 로그인된_상태로_PATCH_요청을_보낸다(
"api/v1/members/inventoryProducts", token,
new ProfileProductRequest(List.of()));

List<InventoryProductResponse> inventoryProductResponses = 로그인된_상태로_GET_요청을_보낸다(
"/api/v1/members/inventoryProducts",
token)
.as(InventoryProductsResponse.class).getItems();

// then
assertAll(
() -> assertThat(profileProductResponse.statusCode()).isEqualTo(HttpStatus.OK.value()),
() -> assertThat(inventoryProductResponses.get(0).isSelected()).isFalse()
);
}

@Test
void 등록된_장비_목록을_대표_장비를_포함해서_조회한다() {
// given
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.woowacourse.f12.application.inventoryproduct;

import static com.woowacourse.f12.support.InventoryProductFixtures.SELECTED_INVENTORY_PRODUCT;
import static com.woowacourse.f12.support.InventoryProductFixtures.UNSELECTED_INVENTORY_PRODUCT;
import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_1;
import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_2;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;
Expand All @@ -17,7 +15,7 @@
import com.woowacourse.f12.dto.request.inventoryproduct.ProfileProductRequest;
import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductResponse;
import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse;
import com.woowacourse.f12.exception.badrequest.InvalidProfileProductException;
import com.woowacourse.f12.exception.internalserver.SqlUpdateException;
import com.woowacourse.f12.support.MemberFixtures;
import java.util.List;
import java.util.Optional;
Expand All @@ -40,42 +38,51 @@ class InventoryProductServiceTest {
private InventoryProductService inventoryProductService;

@Test
void 대표_장비를_등록한다() {
void 대표_장비를_수정한다() {
// given
ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L);
List<Long> selectedInventoryProductIds = List.of(2L);
ProfileProductRequest profileProductRequest = new ProfileProductRequest(selectedInventoryProductIds);
Member member = MemberFixtures.CORINNE.생성(1L);
InventoryProduct inventoryProduct1 = UNSELECTED_INVENTORY_PRODUCT.생성(1L, member, KEYBOARD_1.생성());
InventoryProduct inventoryProduct2 = SELECTED_INVENTORY_PRODUCT.생성(2L, member, KEYBOARD_2.생성());
given(memberRepository.existsById(1L))
.willReturn(true);
given(inventoryProductRepository.findById(1L))
.willReturn(Optional.of(inventoryProduct1));
given(inventoryProductRepository.findById(2L))
.willReturn(Optional.of(inventoryProduct2));
given(memberRepository.findById(1L))
.willReturn(Optional.of(member));
given(inventoryProductRepository.updateBulkProfileProductByMember(member))
.willReturn(1);
given(inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, selectedInventoryProductIds))
.willReturn(selectedInventoryProductIds.size());

// when
inventoryProductService.updateProfileProducts(1L, profileProductRequest);

// then
assertAll(
() -> verify(memberRepository).existsById(1L),
() -> verify(inventoryProductRepository).findById(1L),
() -> verify(inventoryProductRepository).findById(2L)
() -> verify(memberRepository).findById(1L),
() -> verify(inventoryProductRepository).updateBulkProfileProductByMember(member),
() -> verify(inventoryProductRepository).updateBulkProfileProductByMemberAndIds(member,
selectedInventoryProductIds)
);
}

@Test
void 대표_장비를_업데이트할__요청된_장비가_모두_null_경우_예외가_발생한다() {
void 수정하려는_장비_갯수와_실제_등록된_대표_장비_갯수와_일치하지_않으면_예외를_반환한다() {
// given
ProfileProductRequest profileProductRequest = new ProfileProductRequest(null, null);
given(memberRepository.existsById(1L))
.willReturn(true);
List<Long> selectedInventoryProductIds = List.of(2L);
ProfileProductRequest profileProductRequest = new ProfileProductRequest(selectedInventoryProductIds);
Member member = MemberFixtures.CORINNE.생성(1L);
given(memberRepository.findById(1L))
.willReturn(Optional.of(member));
given(inventoryProductRepository.updateBulkProfileProductByMember(member))
.willReturn(1);
given(inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, selectedInventoryProductIds))
.willReturn(0);

// when, then
assertAll(
() -> assertThatThrownBy(() -> inventoryProductService.updateProfileProducts(1L, profileProductRequest))
.isExactlyInstanceOf(InvalidProfileProductException.class),
() -> verify(memberRepository).existsById(1L)
.isExactlyInstanceOf(SqlUpdateException.class),
() -> verify(memberRepository).findById(1L),
() -> verify(inventoryProductRepository).updateBulkProfileProductByMember(member),
() -> verify(inventoryProductRepository).updateBulkProfileProductByMemberAndIds(member,
selectedInventoryProductIds)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class InventoryProductDocumentation extends Documentation {
given(jwtProvider.getPayload(authorizationHeader))
.willReturn("1");
Long memberId = 1L;
ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L);
ProfileProductRequest profileProductRequest = new ProfileProductRequest(List.of(1L));
willDoNothing().given(inventoryProductService).updateProfileProducts(memberId, profileProductRequest);

// when
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.woowacourse.f12.domain.inventoryproduct;

import static com.woowacourse.f12.support.InventoryProductFixtures.SELECTED_INVENTORY_PRODUCT;
import static com.woowacourse.f12.support.InventoryProductFixtures.UNSELECTED_INVENTORY_PRODUCT;
import static com.woowacourse.f12.support.MemberFixtures.CORINNE;
import static com.woowacourse.f12.support.MemberFixtures.MINCHO;
import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_1;
Expand Down Expand Up @@ -64,6 +65,37 @@ class InventoryProductRepositoryTest {
assertThat(actual).isTrue();
}

@Test
void 인벤토리_상품_모두를_대표_장비에서_해제한다() {
// given
Member member = 회원을_저장한다(CORINNE.생성());
Product product = 제품을_저장한다(KEYBOARD_1.생성(1L));
InventoryProduct inventoryProduct = UNSELECTED_INVENTORY_PRODUCT.생성(member, product);
inventoryProductRepository.save(inventoryProduct);

// when
int actual = inventoryProductRepository.updateBulkProfileProductByMember(member);

// then
assertThat(actual).isOne();
}

@Test
void 인벤토리_상품을_대표_장비로_등록한다() {
// given
Member member = 회원을_저장한다(CORINNE.생성());
Product product = 제품을_저장한다(KEYBOARD_1.생성(1L));
InventoryProduct inventoryProduct = UNSELECTED_INVENTORY_PRODUCT.생성(member, product);
inventoryProductRepository.save(inventoryProduct);

// when
int actual = inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member,
List.of(inventoryProduct.getId()));

// then
assertThat(actual).isOne();
}

private Product 제품을_저장한다(Product product) {
return productRepository.save(product);
}
Expand Down
Loading

0 comments on commit 69e84a4

Please sign in to comment.