Skip to content

Commit

Permalink
Merge pull request #94 from dnd-side-project/feat/#82-item
Browse files Browse the repository at this point in the history
회원이 아이템을 착용한다.
  • Loading branch information
hwangdaesun authored Feb 12, 2025
2 parents 63fb2a0 + 9c3504f commit d5d65b5
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.dnd.sbooky.api.docs.spec;

import com.dnd.sbooky.api.item.request.SwitchEquippedItemRequest;
import com.dnd.sbooky.api.support.response.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.core.userdetails.UserDetails;

@Tag(name = "[Item API]", description = "아이템에 관련된 API")
@SecurityRequirement(name = "access-token")
public interface SwitchEquippedItemApiSpec {
@Operation(summary = "아이템 착용", description = "새로운 아이템을 착용한다.")
ApiResponse<?> switchEqiuppedItem(UserDetails user, SwitchEquippedItemRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.dnd.sbooky.api.item;

import com.dnd.sbooky.api.docs.spec.SwitchEquippedItemApiSpec;
import com.dnd.sbooky.api.item.request.SwitchEquippedItemRequest;
import com.dnd.sbooky.api.support.response.ApiResponse;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class SwitchEquippedItemController implements SwitchEquippedItemApiSpec {

private final SwitchEquippedItemUsecase switchEquippedItemUsecase;

@PatchMapping("/items")
public ApiResponse<?> switchEqiuppedItem(
@Parameter(hidden = true) @AuthenticationPrincipal UserDetails userDetails,
@Valid @RequestBody SwitchEquippedItemRequest request) {
Long memberId = Long.parseLong(userDetails.getUsername());
switchEquippedItemUsecase.switchEquippedItem(memberId, request);
return ApiResponse.success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.dnd.sbooky.api.item;

import static com.dnd.sbooky.api.support.error.ErrorType.*;

import com.dnd.sbooky.api.item.exception.MemberHasNotItemException;
import com.dnd.sbooky.api.item.request.SwitchEquippedItemRequest;
import com.dnd.sbooky.core.item.MemberItemEntity;
import com.dnd.sbooky.core.item.MemberItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class SwitchEquippedItemUsecase {

private final MemberItemRepository memberItemRepository;

public void switchEquippedItem(Long memberId, SwitchEquippedItemRequest request) {
unEquipItem(memberId, request.equippedItemId());
equipItem(memberId, request.toEquipItemId());
}

private void unEquipItem(Long memberId, Long equippedItemId) {
MemberItemEntity equippedMemberItem =
memberItemRepository
.findMemberItemByMemberIdAndItemId(memberId, equippedItemId)
.orElseThrow(() -> new MemberHasNotItemException(MEMBER_HAS_NOT_ITEM));
equippedMemberItem.unEquip();
}

private void equipItem(Long memberId, Long toEquipItemId) {
MemberItemEntity unEquippedMemberItem =
memberItemRepository
.findMemberItemByMemberIdAndItemId(memberId, toEquipItemId)
.orElseThrow(() -> new MemberHasNotItemException(MEMBER_HAS_NOT_ITEM));
unEquippedMemberItem.equip();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.dnd.sbooky.api.item.exception;

import com.dnd.sbooky.api.support.error.ApiException;
import com.dnd.sbooky.api.support.error.ErrorType;

public class MemberHasNotItemException extends ApiException {
public MemberHasNotItemException(ErrorType errorType) {
super(errorType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.dnd.sbooky.api.item.request;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;

@Schema(description = "아이템 착용 요청 DTO")
public record SwitchEquippedItemRequest(
@Schema(description = "기존 착용하고 있는 아이템") @NotNull Long equippedItemId,
@Schema(description = "앞으로 착용할 아이템") @NotNull Long toEquipItemId) {}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public enum ErrorCode {

// Item Error
ITEM_404,
ITEM_404_2,

// Evaluation Error
EVALUATION_404_1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public enum ErrorType {

// Item Error
ITEM_NOT_FOUND(NOT_FOUND, ErrorCode.ITEM_404, "Item was not found.", LogLevel.INFO),
MEMBER_HAS_NOT_ITEM(NOT_FOUND, ErrorCode.ITEM_404_2, "Member has not item.", LogLevel.INFO),

// Evaluation Error
EVALUATION_KEYWORD_NOT_FOUND(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,12 @@ public static MemberItemEntity obtainItem(MemberEntity memberEntity, ItemEntity
.equipped(false)
.build();
}

public void equip() {
this.equipped = true;
}

public void unEquip() {
this.equipped = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.dnd.sbooky.core.item.dto.FindItemDTO;
import java.util.List;
import java.util.Optional;
import org.springframework.data.repository.NoRepositoryBean;

@NoRepositoryBean
Expand All @@ -10,5 +11,7 @@ public interface MemberItemRepositoryCustom {

List<FindItemDTO> findEquippedItemsByMemberId(Long memberId);

Optional<MemberItemEntity> findMemberItemByMemberIdAndItemId(Long memberId, Long itemId);

boolean existsByMemberIdAndItemId(Long memberId, Long itemId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
Expand Down Expand Up @@ -33,6 +34,12 @@ public List<FindItemDTO> findEquippedItemsByMemberId(Long memberId) {
.fetch();
}

@Override
public Optional<MemberItemEntity> findMemberItemByMemberIdAndItemId(Long memberId, Long itemId) {
return Optional.ofNullable(
queryFactory.selectFrom(memberItem).where(hasItem(memberId, itemId)).fetchFirst());
}

@Override
public boolean existsByMemberIdAndItemId(Long memberId, Long itemId) {
return queryFactory.selectOne().from(memberItem).where(hasItem(memberId, itemId)).fetchFirst()
Expand Down

0 comments on commit d5d65b5

Please sign in to comment.