From 4f552d9da74eee277c3847f937891e1efac49e24 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:31:57 +0900 Subject: [PATCH 1/9] =?UTF-8?q?:sparkles:=20feat=20:=20=EB=B6=80=ED=99=94?= =?UTF-8?q?=EA=B8=B0=20=EB=93=B1=EB=A1=9D,=20=EC=95=A0=EC=A0=95=20?= =?UTF-8?q?=EC=86=8C=EB=AA=A8=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/user/controller/EggController.java | 71 +++++++++++++++ .../controller/IncubatingEggQueryUsecase.java | 5 ++ .../IncubatingEggQueryUsecaseImpl.java | 21 +++++ .../QueryIncubatingEggResponse.java | 10 +++ .../user/controller/UseLovePointRequest.java | 7 ++ .../user/controller/UseLovePointResponse.java | 9 ++ .../request/RegisterEggRequest.java | 6 ++ .../runimo/runimo/user/domain/EggStatus.java | 8 ++ .../runimo/user/domain/IncubatingEgg.java | 90 +++++++++++++++++++ .../repository/IncubatingEggRepository.java | 32 +++++++ .../user/service/IncubatingEggFinder.java | 27 ++++++ .../user/service/IncubatingEggProcessor.java | 38 ++++++++ .../user/service/LovePointProcessor.java | 7 +- .../user/service/UserItemProcessor.java | 14 +++ .../user/service/dtos/IncubatingEggView.java | 28 ++++++ .../user/service/dtos/RegisterEggCommand.java | 7 ++ .../service/dtos/RegisterEggResponse.java | 8 ++ .../service/dtos/UseLovePointCommand.java | 4 + .../usecases/eggs/EggRegisterUsecase.java | 8 ++ .../usecases/eggs/EggRegisterUsecaseImpl.java | 33 +++++++ .../eggs/GiveLovePointToEggUsecase.java | 8 ++ .../eggs/GiveLovePointToEggUsecaseImpl.java | 30 +++++++ 22 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 src/main/java/org/runimo/runimo/user/controller/EggController.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java create mode 100644 src/main/java/org/runimo/runimo/user/controller/request/RegisterEggRequest.java create mode 100644 src/main/java/org/runimo/runimo/user/domain/EggStatus.java create mode 100644 src/main/java/org/runimo/runimo/user/domain/IncubatingEgg.java create mode 100644 src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java create mode 100644 src/main/java/org/runimo/runimo/user/service/IncubatingEggFinder.java create mode 100644 src/main/java/org/runimo/runimo/user/service/IncubatingEggProcessor.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/IncubatingEggView.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggCommand.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggResponse.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointCommand.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecase.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecaseImpl.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java diff --git a/src/main/java/org/runimo/runimo/user/controller/EggController.java b/src/main/java/org/runimo/runimo/user/controller/EggController.java new file mode 100644 index 00000000..c0a33edf --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/EggController.java @@ -0,0 +1,71 @@ +package org.runimo.runimo.user.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.common.response.SuccessResponse; +import org.runimo.runimo.user.controller.request.RegisterEggRequest; +import org.runimo.runimo.user.service.dtos.RegisterEggResponse; +import org.runimo.runimo.user.enums.UserHttpResponseCode; +import org.runimo.runimo.user.service.dtos.UseLovePointCommand; +import org.runimo.runimo.user.service.usecases.eggs.EggRegisterUsecase; +import org.runimo.runimo.user.service.dtos.RegisterEggCommand; +import org.runimo.runimo.user.service.usecases.eggs.GiveLovePointToEggUsecase; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; + +@Tag(name = "알 부화 API") +@RestController +@RequestMapping("/api/v1/users/eggs") +@RequiredArgsConstructor +public class EggController { + + private final EggRegisterUsecase eggRegisterUsecase; + private final GiveLovePointToEggUsecase giveLovePointToEggUsecase; + private final IncubatingEggQueryUsecase incubatingEggQueryUsecase; + + @PostMapping + public ResponseEntity> registerEgg( + @UserId Long userId, + @Valid @RequestBody RegisterEggRequest request + ) { + RegisterEggResponse registerEggResponse = eggRegisterUsecase.execute( + new RegisterEggCommand(userId, request.itemId()) + ); + return ResponseEntity.created(URI.create("/api/v1/users/eggs")).body( + SuccessResponse.of( + UserHttpResponseCode.REGISTER_EGG_SUCCESS, + registerEggResponse + )); + } + + @PatchMapping + public ResponseEntity> useLovePoint( + @UserId Long userId, + @Valid @RequestBody UseLovePointRequest request + ) { + UseLovePointResponse useLovePointResponse = giveLovePointToEggUsecase.execute( + new UseLovePointCommand(userId, request.itemId(), request.lovePointAmount()) + ); + return ResponseEntity.ok().body( + SuccessResponse.of( + UserHttpResponseCode.USE_LOVE_POINT_SUCCESS, + useLovePointResponse + )); + } + + @GetMapping + public ResponseEntity> getEgg( + @UserId Long userId + ) { + QueryIncubatingEggResponse response = incubatingEggQueryUsecase.execute(userId); + return ResponseEntity.ok().body( + SuccessResponse.of( + UserHttpResponseCode.MY_PAGE_DATA_FETCHED, + response + )); + } + +} diff --git a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java b/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java new file mode 100644 index 00000000..e5be9b52 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java @@ -0,0 +1,5 @@ +package org.runimo.runimo.user.controller; + +public interface IncubatingEggQueryUsecase { + QueryIncubatingEggResponse execute(Long userId); +} diff --git a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java new file mode 100644 index 00000000..46b78807 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java @@ -0,0 +1,21 @@ +package org.runimo.runimo.user.controller; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.service.dtos.IncubatingEggView; +import org.runimo.runimo.user.service.IncubatingEggFinder; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class IncubatingEggQueryUsecaseImpl implements IncubatingEggQueryUsecase { + private final IncubatingEggFinder incubatingEggFinder; + + @Override + public QueryIncubatingEggResponse execute(Long userId) { + + List incubatingEggs = incubatingEggFinder.findIncubatingEggsViewByUserId(userId); + return new QueryIncubatingEggResponse(incubatingEggs); + } +} diff --git a/src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java b/src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java new file mode 100644 index 00000000..22eb7628 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java @@ -0,0 +1,10 @@ +package org.runimo.runimo.user.controller; + +import org.runimo.runimo.user.service.dtos.IncubatingEggView; + +import java.util.List; + +public record QueryIncubatingEggResponse( + List incubatingEggs +) { +} diff --git a/src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java b/src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java new file mode 100644 index 00000000..e209cfff --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java @@ -0,0 +1,7 @@ +package org.runimo.runimo.user.controller; + +public record UseLovePointRequest( + Long itemId, + Long lovePointAmount +) { +} diff --git a/src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java b/src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java new file mode 100644 index 00000000..c2c2ded1 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java @@ -0,0 +1,9 @@ +package org.runimo.runimo.user.controller; + +public record UseLovePointResponse( + Long eggId, + Long currentLovePointAmount, + Long requiredLovePointAmount, + Boolean eggHatchable +) { +} diff --git a/src/main/java/org/runimo/runimo/user/controller/request/RegisterEggRequest.java b/src/main/java/org/runimo/runimo/user/controller/request/RegisterEggRequest.java new file mode 100644 index 00000000..75fa5991 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/request/RegisterEggRequest.java @@ -0,0 +1,6 @@ +package org.runimo.runimo.user.controller.request; + +public record RegisterEggRequest( + Long itemId +) { +} diff --git a/src/main/java/org/runimo/runimo/user/domain/EggStatus.java b/src/main/java/org/runimo/runimo/user/domain/EggStatus.java new file mode 100644 index 00000000..66230142 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/domain/EggStatus.java @@ -0,0 +1,8 @@ +package org.runimo.runimo.user.domain; + +public enum EggStatus { + WAITING, // 부화 대기 + INCUBATING, // 부화 중 + INCUBATED, // 부화 완료 대기 + HATCHED // 부화 완료 +} diff --git a/src/main/java/org/runimo/runimo/user/domain/IncubatingEgg.java b/src/main/java/org/runimo/runimo/user/domain/IncubatingEgg.java new file mode 100644 index 00000000..46eb0f4b --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/domain/IncubatingEgg.java @@ -0,0 +1,90 @@ +package org.runimo.runimo.user.domain; + +import jakarta.persistence.*; +import java.util.Objects; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.runimo.runimo.common.BaseEntity; + +@Table(name = "incubating_eggs") +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class IncubatingEgg extends BaseEntity { + + @Column(name = "user_id", nullable = false) + private Long userId; + + @Column(name = "egg_id", nullable = false) + private Long eggId; + + @Column(name = "current_love_point_amount", nullable = false) + private Long currentLovePointAmount; + + @Column(name = "hatch_require_amount", nullable = false) + private Long hatchRequireAmount; + + @Column(name = "egg_status", nullable = false) + @Enumerated(EnumType.STRING) + private EggStatus status; + + @Builder + public IncubatingEgg(Long userId, Long eggId, Long currentLovePointAmount, Long hatchRequireAmount, EggStatus status) { + validateCreation(status, currentLovePointAmount, hatchRequireAmount); + this.userId = userId; + this.eggId = eggId; + this.currentLovePointAmount = currentLovePointAmount; + this.hatchRequireAmount = hatchRequireAmount; + this.status = status; + } + + public void startIncubation() { + validateStateTransition(EggStatus.WAITING, "부화 대기중인 알에만 부화 시작가능"); + this.status = EggStatus.INCUBATING; + } + + public void gainLovePoint(final Long amount) { + validateStateTransition(EggStatus.INCUBATING, "부화중인 알에만 애정 포인트 추가가능"); + validateAmount(amount); + if (currentLovePointAmount + amount > hatchRequireAmount) { + throw new IllegalArgumentException("애정 포인트가 부화에 필요한 양을 초과했습니다. 현재: " + currentLovePointAmount + ", 추가량: " + amount + ", 필요량: " + hatchRequireAmount); + } + this.currentLovePointAmount += amount; + if (Objects.equals(this.currentLovePointAmount, hatchRequireAmount)) { + this.status = EggStatus.INCUBATED; + } + } + + public void hatch() { + validateStateTransition(EggStatus.INCUBATED, "애정 포인트가 가득찬 알만 부화 가능"); + this.status = EggStatus.HATCHED; + } + + private void validateCreation(final EggStatus status, final Long currentLovePointAmount, final Long hatchRequireAmount) { + if(status == EggStatus.WAITING && currentLovePointAmount != 0) { + throw new IllegalArgumentException("부화 대기중인 알은 애정 포인트가 0이어야 합니다. 현재: " + currentLovePointAmount); + } + if(hatchRequireAmount <= 0) { + throw new IllegalArgumentException("부화에 필요한 애정 포인트는 0보다 커야 합니다. 현재: " + hatchRequireAmount); + } + } + + + private void validateStateTransition(final EggStatus expected, final String message) { + if (status != expected) { + throw new IllegalStateException(message + " 현재 상태: " + status); + } + } + + private void validateAmount(final Long amount) { + if (amount == null || amount <= 0) { + throw new IllegalArgumentException("애정 포인트는 0보다 커야 합니다. 현재: " + amount); + } + } + + public boolean isReadyToHatch() { + return this.status == EggStatus.INCUBATED && currentLovePointAmount.equals(hatchRequireAmount); + } +} diff --git a/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java b/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java new file mode 100644 index 00000000..fc3f28ba --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java @@ -0,0 +1,32 @@ +package org.runimo.runimo.user.repository; + +import jakarta.persistence.LockModeType; +import jakarta.persistence.QueryHint; +import org.runimo.runimo.user.domain.IncubatingEgg; +import org.runimo.runimo.user.service.dtos.IncubatingEggView; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Lock; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.QueryHints; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface IncubatingEggRepository extends JpaRepository { + + @Lock(LockModeType.PESSIMISTIC_WRITE) + @QueryHints({@QueryHint(name = "jakarta.persistence.lock.timeout", value = "3000")}) + @Query("select ie from IncubatingEgg ie where ie.userId = :userId and ie.id = :eggId") + Optional findByUserIdAndEggIdForUpdate(Long userId, Long eggId); + + @Query("select ie from IncubatingEgg ie where ie.userId = :userId and ie.status = 'INCUBATING' or ie.status = 'INCUBATED'") + List findAllByUserId(Long userId); + + @Query("select new org.runimo.runimo.user.service.dtos.IncubatingEggView(ie.id, e.name, e.imgUrl, ie.hatchRequireAmount, ie.currentLovePointAmount, ie.status) " + + "from IncubatingEgg ie " + + "join Egg e on e.id = ie.eggId " + + "where ie.userId = :userId and (ie.status = 'INCUBATING' or ie.status = 'INCUBATED')") + List findAllViewByUserId(Long userId); +} diff --git a/src/main/java/org/runimo/runimo/user/service/IncubatingEggFinder.java b/src/main/java/org/runimo/runimo/user/service/IncubatingEggFinder.java new file mode 100644 index 00000000..73252a49 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/IncubatingEggFinder.java @@ -0,0 +1,27 @@ +package org.runimo.runimo.user.service; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.domain.IncubatingEgg; +import org.runimo.runimo.user.repository.IncubatingEggRepository; +import org.runimo.runimo.user.service.dtos.IncubatingEggView; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Component +@RequiredArgsConstructor +public class IncubatingEggFinder { + + private final IncubatingEggRepository incubatingEggRepository; + + @Transactional(readOnly = true) + public List findIncubatingEggsByUserId(Long userId) { + return incubatingEggRepository.findAllByUserId(userId); + } + + @Transactional(readOnly = true) + public List findIncubatingEggsViewByUserId(Long userId) { + return incubatingEggRepository.findAllViewByUserId(userId); + } +} diff --git a/src/main/java/org/runimo/runimo/user/service/IncubatingEggProcessor.java b/src/main/java/org/runimo/runimo/user/service/IncubatingEggProcessor.java new file mode 100644 index 00000000..e8f59f6d --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/IncubatingEggProcessor.java @@ -0,0 +1,38 @@ +package org.runimo.runimo.user.service; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.item.domain.Egg; +import org.runimo.runimo.user.domain.IncubatingEgg; +import org.runimo.runimo.user.repository.IncubatingEggRepository; +import org.runimo.runimo.user.service.dtos.UseLovePointCommand; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +public class IncubatingEggProcessor { + + private final IncubatingEggRepository incubatingEggRepository; + + @Transactional + public IncubatingEgg create(Long userId, Egg egg) { + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(userId) + .eggId(egg.getId()) + .currentLovePointAmount(0L) + .hatchRequireAmount(egg.getHatchRequireAmount()) + .build(); + return incubatingEggRepository.save(incubatingEgg); + } + + @Transactional + public IncubatingEgg giveLovePoint(UseLovePointCommand useLovePointCommand) { + IncubatingEgg incubatingEgg = incubatingEggRepository.findByUserIdAndEggIdForUpdate( + useLovePointCommand.userId(), + useLovePointCommand.incubatingEggId()) + .orElseThrow(() -> new IllegalArgumentException("Incubating egg not found")); + incubatingEgg.gainLovePoint(useLovePointCommand.lovePoint()); + return incubatingEgg; + } + +} diff --git a/src/main/java/org/runimo/runimo/user/service/LovePointProcessor.java b/src/main/java/org/runimo/runimo/user/service/LovePointProcessor.java index ad89c98f..c49485d0 100644 --- a/src/main/java/org/runimo/runimo/user/service/LovePointProcessor.java +++ b/src/main/java/org/runimo/runimo/user/service/LovePointProcessor.java @@ -3,6 +3,7 @@ import org.runimo.runimo.user.domain.LovePoint; import org.runimo.runimo.user.repository.LovePointRepository; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; @Component public class LovePointProcessor { @@ -13,7 +14,11 @@ public LovePointProcessor(LovePointRepository lovePointRepository) { this.lovePointRepository = lovePointRepository; } - // 유저의 러브포인트를 업데이트한다. XLOCK을 걸어서 동시성 문제를 해결한다. + /** + * [Warning] : LovePoint를 수정할때는, 항상 마지막 순서로 업데이트한다. (DEADLOCK 방지) + * 유저의 러브포인트를 업데이트한다. XLOCK을 걸어서 동시성 문제를 해결한다. + * */ + @Transactional public LovePoint updateLovePoint(Long userId, Long loveAmount) { LovePoint lp = lovePointRepository.findByUserIdWithXLock(userId) .orElseThrow(IllegalStateException::new); diff --git a/src/main/java/org/runimo/runimo/user/service/UserItemProcessor.java b/src/main/java/org/runimo/runimo/user/service/UserItemProcessor.java index 01a42c51..fa08ae10 100644 --- a/src/main/java/org/runimo/runimo/user/service/UserItemProcessor.java +++ b/src/main/java/org/runimo/runimo/user/service/UserItemProcessor.java @@ -1,6 +1,9 @@ package org.runimo.runimo.user.service; import lombok.RequiredArgsConstructor; +import org.runimo.runimo.item.domain.ActivityType; +import org.runimo.runimo.item.service.ItemActivityCreator; +import org.runimo.runimo.item.service.dtos.CreateActivityCommand; import org.runimo.runimo.user.domain.UserItem; import org.runimo.runimo.user.repository.UserItemRepository; import org.springframework.stereotype.Component; @@ -12,12 +15,23 @@ public class UserItemProcessor { private final UserItemFinder userItemFinder; private final UserItemRepository userItemRepository; + private final ItemActivityCreator itemActivityCreator; @Transactional public void updateItemQuantity(Long userId, Long itemId, Long amount) { UserItem userItem = userItemFinder.findByUserIdAndItemIdWithXLock(userId, itemId) .orElseThrow(IllegalStateException::new); userItem.gainItem(amount); + itemActivityCreator.createItemActivity(new CreateActivityCommand(itemId, userId, amount, ActivityType.CONSUME)); + userItemRepository.save(userItem); + } + + @Transactional + public void useItem(Long userId, Long itemId, Long amount) { + UserItem userItem = userItemFinder.findByUserIdAndItemIdWithXLock(userId, itemId) + .orElseThrow(IllegalStateException::new); + userItem.useItem(amount); + itemActivityCreator.createItemActivity(new CreateActivityCommand(itemId, userId, amount, ActivityType.CONSUME)); userItemRepository.save(userItem); } } diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/IncubatingEggView.java b/src/main/java/org/runimo/runimo/user/service/dtos/IncubatingEggView.java new file mode 100644 index 00000000..771c220c --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/IncubatingEggView.java @@ -0,0 +1,28 @@ +package org.runimo.runimo.user.service.dtos; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.runimo.runimo.user.domain.EggStatus; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class IncubatingEggView { + private Long id; + private String name; + private String imgUrl; + private Long hatchRequiredPointAmount; + private Long currentLovePointAmount; + private Boolean hatchable; + + @Builder + public IncubatingEggView(Long id, String name, String imgUrl, Long hatchRequiredPointAmount, Long currentLovePointAmount, EggStatus hatchable) { + this.id = id; + this.name = name; + this.imgUrl = imgUrl; + this.hatchRequiredPointAmount = hatchRequiredPointAmount; + this.currentLovePointAmount = currentLovePointAmount; + this.hatchable = (hatchable == EggStatus.INCUBATED); + } +} diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggCommand.java b/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggCommand.java new file mode 100644 index 00000000..fc42b722 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggCommand.java @@ -0,0 +1,7 @@ +package org.runimo.runimo.user.service.dtos; + +public record RegisterEggCommand( + Long userId, + Long itemId +) { +} diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggResponse.java b/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggResponse.java new file mode 100644 index 00000000..b7d433d2 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/RegisterEggResponse.java @@ -0,0 +1,8 @@ +package org.runimo.runimo.user.service.dtos; + +public record RegisterEggResponse( + Long incubatingEggId, + Long currentLovePointAmount, + Long requiredLovePointAmount +) { +} diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointCommand.java b/src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointCommand.java new file mode 100644 index 00000000..1a26bf63 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointCommand.java @@ -0,0 +1,4 @@ +package org.runimo.runimo.user.service.dtos; + +public record UseLovePointCommand(Long userId, Long incubatingEggId, Long lovePoint) { +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecase.java new file mode 100644 index 00000000..74e77005 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecase.java @@ -0,0 +1,8 @@ +package org.runimo.runimo.user.service.usecases.eggs; + +import org.runimo.runimo.user.service.dtos.RegisterEggResponse; +import org.runimo.runimo.user.service.dtos.RegisterEggCommand; + +public interface EggRegisterUsecase { + RegisterEggResponse execute(RegisterEggCommand command); +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecaseImpl.java new file mode 100644 index 00000000..530d692a --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/EggRegisterUsecaseImpl.java @@ -0,0 +1,33 @@ +package org.runimo.runimo.user.service.usecases.eggs; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.item.domain.Egg; +import org.runimo.runimo.user.domain.IncubatingEgg; +import org.runimo.runimo.item.service.ItemFinder; +import org.runimo.runimo.user.service.dtos.RegisterEggResponse; +import org.runimo.runimo.user.service.IncubatingEggProcessor; +import org.runimo.runimo.user.service.UserItemProcessor; +import org.runimo.runimo.user.service.dtos.RegisterEggCommand; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class EggRegisterUsecaseImpl implements EggRegisterUsecase { + + private final ItemFinder itemFinder; + private final IncubatingEggProcessor incubatingEggProcessor; + private final UserItemProcessor userItemProcessor; + + @Override + public RegisterEggResponse execute(RegisterEggCommand command) { + Egg egg = (Egg) itemFinder.findById(command.itemId()) + .orElseThrow(() -> new IllegalArgumentException("Egg not found")); + userItemProcessor.useItem(command.userId(), command.itemId(), 1L); + IncubatingEgg incubatingEgg = incubatingEggProcessor.create(command.userId(), egg); + return new RegisterEggResponse( + incubatingEgg.getId(), + incubatingEgg.getCurrentLovePointAmount(), + incubatingEgg.getHatchRequireAmount() + ); + } +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java new file mode 100644 index 00000000..9a3f510b --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java @@ -0,0 +1,8 @@ +package org.runimo.runimo.user.service.usecases.eggs; + +import org.runimo.runimo.user.controller.UseLovePointResponse; +import org.runimo.runimo.user.service.dtos.UseLovePointCommand; + +public interface GiveLovePointToEggUsecase { + UseLovePointResponse execute(UseLovePointCommand useLovePointCommand); +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java new file mode 100644 index 00000000..6f78be0a --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java @@ -0,0 +1,30 @@ +package org.runimo.runimo.user.service.usecases.eggs; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.domain.IncubatingEgg; +import org.runimo.runimo.user.controller.UseLovePointResponse; +import org.runimo.runimo.user.service.IncubatingEggProcessor; +import org.runimo.runimo.user.service.LovePointProcessor; +import org.runimo.runimo.user.service.dtos.UseLovePointCommand; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class GiveLovePointToEggUsecaseImpl implements GiveLovePointToEggUsecase { + private final IncubatingEggProcessor incubatingEggProcessor; + private final LovePointProcessor lovePointProcessor; + + @Override + @Transactional + public UseLovePointResponse execute(UseLovePointCommand command) { + IncubatingEgg incubatingEgg = incubatingEggProcessor.giveLovePoint(command); + lovePointProcessor.updateLovePoint(command.userId(), command.lovePoint()); + return new UseLovePointResponse( + incubatingEgg.getId(), + incubatingEgg.getCurrentLovePointAmount(), + incubatingEgg.getHatchRequireAmount(), + incubatingEgg.isReadyToHatch() + ); + } +} From cf20794bc49f1334a920e9bf49a47750ab03c20f Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:32:45 +0900 Subject: [PATCH 2/9] =?UTF-8?q?:truck:=20refactor=20:=20=EB=94=94=EB=A0=89?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/runimo/runimo/user/controller/MainViewController.java | 2 +- .../org/runimo/runimo/user/controller/UserController.java | 2 +- .../org/runimo/runimo/user/controller/UserItemController.java | 4 ++-- .../org/runimo/runimo/user/enums/UserHttpResponseCode.java | 3 ++- .../user/service/usecases/{ => auth}/UserOAuthUsecase.java | 2 +- .../service/usecases/{ => auth}/UserOAuthUsecaseImpl.java | 2 +- .../user/service/usecases/{ => auth}/UserRegisterService.java | 2 +- .../user/service/usecases/{ => items}/GainItemUsecase.java | 2 +- .../service/usecases/{ => items}/GainItemUsecaseImpl.java | 2 +- .../user/service/usecases/{ => items}/UseItemUsecase.java | 2 +- .../user/service/usecases/{ => items}/UseItemUsecaseImpl.java | 2 +- .../service/usecases/{ => query}/MainViewQueryUsecase.java | 2 +- .../usecases/{ => query}/MainViewQueryUsecaseImpl.java | 2 +- .../user/service/usecases/{ => query}/MyItemQueryUsecase.java | 2 +- .../service/usecases/{ => query}/MyItemQueryUsecaseImpl.java | 2 +- 15 files changed, 17 insertions(+), 16 deletions(-) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => auth}/UserOAuthUsecase.java (90%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => auth}/UserOAuthUsecaseImpl.java (97%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => auth}/UserRegisterService.java (95%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => items}/GainItemUsecase.java (79%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => items}/GainItemUsecaseImpl.java (95%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => items}/UseItemUsecase.java (79%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => items}/UseItemUsecaseImpl.java (95%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => query}/MainViewQueryUsecase.java (72%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => query}/MainViewQueryUsecaseImpl.java (96%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => query}/MyItemQueryUsecase.java (72%) rename src/main/java/org/runimo/runimo/user/service/usecases/{ => query}/MyItemQueryUsecaseImpl.java (92%) diff --git a/src/main/java/org/runimo/runimo/user/controller/MainViewController.java b/src/main/java/org/runimo/runimo/user/controller/MainViewController.java index 4b39f215..ceb542a2 100644 --- a/src/main/java/org/runimo/runimo/user/controller/MainViewController.java +++ b/src/main/java/org/runimo/runimo/user/controller/MainViewController.java @@ -6,7 +6,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.runimo.runimo.common.response.SuccessResponse; -import org.runimo.runimo.user.service.usecases.MainViewQueryUsecase; +import org.runimo.runimo.user.service.usecases.query.MainViewQueryUsecase; import org.runimo.runimo.user.service.dtos.MainViewResponse; import org.runimo.runimo.user.enums.UserHttpResponseCode; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/org/runimo/runimo/user/controller/UserController.java b/src/main/java/org/runimo/runimo/user/controller/UserController.java index 23a8ab48..a3ad8ca2 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UserController.java +++ b/src/main/java/org/runimo/runimo/user/controller/UserController.java @@ -13,7 +13,7 @@ import org.runimo.runimo.user.enums.UserHttpResponseCode; import org.runimo.runimo.user.service.dtos.AuthResponse; import org.runimo.runimo.user.service.dtos.SignupUserResponse; -import org.runimo.runimo.user.service.usecases.UserOAuthUsecase; +import org.runimo.runimo.user.service.usecases.auth.UserOAuthUsecase; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; diff --git a/src/main/java/org/runimo/runimo/user/controller/UserItemController.java b/src/main/java/org/runimo/runimo/user/controller/UserItemController.java index 56ae028e..15b425aa 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UserItemController.java +++ b/src/main/java/org/runimo/runimo/user/controller/UserItemController.java @@ -12,8 +12,8 @@ import org.runimo.runimo.user.service.dtos.ItemQueryResponse; import org.runimo.runimo.user.service.dtos.UseItemCommand; import org.runimo.runimo.user.service.dtos.UseItemResponse; -import org.runimo.runimo.user.service.usecases.MyItemQueryUsecase; -import org.runimo.runimo.user.service.usecases.UseItemUsecase; +import org.runimo.runimo.user.service.usecases.query.MyItemQueryUsecase; +import org.runimo.runimo.user.service.usecases.items.UseItemUsecase; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java b/src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java index e3b6f374..c66f25f4 100644 --- a/src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java +++ b/src/main/java/org/runimo/runimo/user/enums/UserHttpResponseCode.java @@ -10,7 +10,8 @@ public enum UserHttpResponseCode implements CustomResponseCode { REFRESH_SUCCESS("USH2004", "토큰 재발급 성공", "토큰 재발급 성공"), USE_ITEM_SUCCESS("USH2005", "아이템 사용 성공", "아이템 사용 성공"), - ; + REGISTER_EGG_SUCCESS("USH2006", "부화기 등록 성공", "부화기 등록 성공"), + USE_LOVE_POINT_SUCCESS("USH2007","애정 사용 성공" , "애정 사용 성공"); private final String code; private final String clientMessage; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecase.java similarity index 90% rename from src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecase.java rename to src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecase.java index 96a42ad1..16520f59 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecase.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.auth; import org.runimo.runimo.user.domain.SocialProvider; import org.runimo.runimo.user.service.dtos.AuthResponse; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecaseImpl.java similarity index 97% rename from src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecaseImpl.java index 15e22d8c..99e7b842 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserOAuthUsecaseImpl.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.auth; import com.auth0.jwt.JWT; import com.auth0.jwt.interfaces.DecodedJWT; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserRegisterService.java similarity index 95% rename from src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java rename to src/main/java/org/runimo/runimo/user/service/usecases/auth/UserRegisterService.java index 375e6a2f..a31d31bf 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/auth/UserRegisterService.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.auth; import lombok.RequiredArgsConstructor; import org.runimo.runimo.rewards.service.eggs.EggGrantService; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecase.java similarity index 79% rename from src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecase.java rename to src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecase.java index 09a060ce..067a3d94 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecase.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.items; import org.runimo.runimo.user.service.dtos.GainItemCommand; import org.runimo.runimo.user.service.dtos.GainItemResponse; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecaseImpl.java similarity index 95% rename from src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecaseImpl.java index f4f810e3..2a20d2bc 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/items/GainItemUsecaseImpl.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.items; import lombok.RequiredArgsConstructor; import org.runimo.runimo.user.domain.UserItem; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecase.java similarity index 79% rename from src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecase.java rename to src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecase.java index f572b929..ed6f3819 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecase.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.items; import org.runimo.runimo.user.service.dtos.UseItemCommand; import org.runimo.runimo.user.service.dtos.UseItemResponse; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecaseImpl.java similarity index 95% rename from src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecaseImpl.java index c4913e88..13e0c051 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/items/UseItemUsecaseImpl.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.items; import lombok.RequiredArgsConstructor; import org.runimo.runimo.item.service.ItemActivityCreator; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecase.java similarity index 72% rename from src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecase.java rename to src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecase.java index b4651678..7cc30ebf 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecase.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.query; import org.runimo.runimo.user.service.dtos.MainViewResponse; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecaseImpl.java similarity index 96% rename from src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecaseImpl.java index 2459ac56..6aaa4d09 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/MainViewQueryUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/query/MainViewQueryUsecaseImpl.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.query; import lombok.RequiredArgsConstructor; import org.runimo.runimo.records.service.RecordFinder; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecase.java similarity index 72% rename from src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java rename to src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecase.java index 114b6644..e2d19142 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecase.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.query; import org.runimo.runimo.user.service.dtos.ItemQueryResponse; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecaseImpl.java similarity index 92% rename from src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecaseImpl.java index 0f04f400..ef4e7a47 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/query/MyItemQueryUsecaseImpl.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.service.usecases; +package org.runimo.runimo.user.service.usecases.query; import lombok.RequiredArgsConstructor; From 5a4d2716b79e9c8e41a4e9a58bd8f5f8966058b7 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:33:59 +0900 Subject: [PATCH 3/9] =?UTF-8?q?:white=5Fcheck=5Fmark:=20test=20:=20?= =?UTF-8?q?=EB=B6=80=ED=99=94=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/item/domain/IncubatingEggTest.java | 162 ++++++++++++++++++ .../user/api/IncubatingEggAcceptanceTest.java | 111 ++++++++++++ 2 files changed, 273 insertions(+) create mode 100644 src/test/java/org/runimo/runimo/item/domain/IncubatingEggTest.java create mode 100644 src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java diff --git a/src/test/java/org/runimo/runimo/item/domain/IncubatingEggTest.java b/src/test/java/org/runimo/runimo/item/domain/IncubatingEggTest.java new file mode 100644 index 00000000..d1ea9efa --- /dev/null +++ b/src/test/java/org/runimo/runimo/item/domain/IncubatingEggTest.java @@ -0,0 +1,162 @@ +package org.runimo.runimo.item.domain; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.runimo.runimo.user.domain.EggStatus; +import org.runimo.runimo.user.domain.IncubatingEgg; + +class IncubatingEggTest { + + @Test + void startIncubation_성공() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(0L) + .hatchRequireAmount(10L) + .status(EggStatus.WAITING) + .build(); + + assertEquals(EggStatus.WAITING, incubatingEgg.getStatus()); + + // when + incubatingEgg.startIncubation(); + + // then + assertEquals(EggStatus.INCUBATING, incubatingEgg.getStatus()); + } + + @Test + void startIncubation_실패_이미_부화중() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(2L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATING) + .build(); + + // when & then + assertThrows(IllegalStateException.class, incubatingEgg::startIncubation); + } + + @Test + void gainLovePoint_성공() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(0L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATING) + .build(); + + // when + incubatingEgg.gainLovePoint(5L); + + // then + assertEquals(5L, incubatingEgg.getCurrentLovePointAmount()); + } + + @Test + void gainLovePoint_성공_부화조건_충족() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(0L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATING) + .build(); + + // when + incubatingEgg.gainLovePoint(10L); + + // then + assertEquals(10L, incubatingEgg.getCurrentLovePointAmount()); + assertEquals(EggStatus.INCUBATED, incubatingEgg.getStatus()); + } + + @Test + void gainLovePoint_실패_이미_부화됨() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(10L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATED) + .build(); + + // when & then + assertThrows(IllegalStateException.class, () -> incubatingEgg.gainLovePoint(1L)); + } + + @Test + void hatch_성공() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(10L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATED) + .build(); + + // when + incubatingEgg.hatch(); + + // then + assertEquals(EggStatus.HATCHED, incubatingEgg.getStatus()); + } + + @Test + void hatch_실패_애정포인트_미달() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(5L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATING) + .build(); + + // when & then + assertThrows(IllegalStateException.class, incubatingEgg::hatch); + } + + @Test + void hatch_실패_부화_대기중인_알() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(0L) + .hatchRequireAmount(10L) + .status(EggStatus.WAITING) + .build(); + + // when & then + assertThrows(IllegalStateException.class, incubatingEgg::hatch); + } + + @Test + void gainLovePoint_과다_지급() { + // given + IncubatingEgg incubatingEgg = IncubatingEgg.builder() + .userId(1L) + .eggId(100L) + .currentLovePointAmount(0L) + .hatchRequireAmount(10L) + .status(EggStatus.INCUBATING) + .build(); + + // when & then + assertThrows(IllegalArgumentException.class, () -> { + incubatingEgg.gainLovePoint(15L); + }); + } +} diff --git a/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java b/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java new file mode 100644 index 00000000..2538431f --- /dev/null +++ b/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java @@ -0,0 +1,111 @@ +package org.runimo.runimo.user.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.runimo.runimo.CleanUpUtil; +import org.runimo.runimo.auth.jwt.JwtTokenFactory; +import org.runimo.runimo.user.controller.UseLovePointRequest; +import org.runimo.runimo.user.controller.request.RegisterEggRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +class IncubatingEggAcceptanceTest { + + @LocalServerPort + int port; + + @Autowired + private JwtTokenFactory jwtTokenFactory; + + @Autowired + private CleanUpUtil cleanUpUtil; + @Autowired + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + RestAssured.port = port; + } + + @AfterEach + void tearDown() { + cleanUpUtil.cleanUpUserInfos(); + } + + @Test + @Sql(scripts = "/sql/incubating_egg_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자의_부화중인_알_조회_성공() { + String token = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .when() + .get("/api/v1/users/eggs") + .then() + .log().all() + .statusCode(200) + .body("code", equalTo("USH2001")) + .body("payload.incubating_eggs.size()", greaterThan(0)) + .body("payload.incubating_eggs[0].name", equalTo("마당알")) + .body("payload.incubating_eggs[0].id", equalTo(1)) + .body("payload.incubating_eggs[0].hatch_required_point_amount", equalTo(100)) + .body("payload.incubating_eggs[0].current_love_point_amount", equalTo(50)) + .body("payload.incubating_eggs[0].hatchable", equalTo(false)); + } + + @Test + @Sql(scripts = "/sql/incubating_egg_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 사용자의_알을_부화중으로_변경() throws JsonProcessingException { + String token = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + RegisterEggRequest request = new RegisterEggRequest(1L); + + + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .body(objectMapper.writeValueAsString(request)) + .when() + .post("/api/v1/users/eggs") + .then() + .log().all() + .statusCode(HttpStatus.CREATED.value()) + .body("code", equalTo("USH2006")) + .body("payload.current_love_point_amount", equalTo(0)) + .body("payload.required_love_point_amount", equalTo(100)); + } + + @Test + @Sql(scripts = "/sql/incubating_egg_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 부화중인_알에_애정을_부여() throws JsonProcessingException { + String token = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + UseLovePointRequest request = new UseLovePointRequest(1L, 20L); + given() + .header("Authorization", token) + .contentType(ContentType.JSON) + .body(objectMapper.writeValueAsString(request)) + .when() + .patch("/api/v1/users/eggs") + .then() + .log().all() + .statusCode(200) + .body("code", equalTo("USH2007")) + .body("payload.current_love_point_amount", equalTo(70)) + .body("payload.required_love_point_amount", equalTo(100)) + .body("payload.egg_hatchable", equalTo(false)); + } +} From 4c64d07fe4d871d3a31def351ce260c7dc3d40b8 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:35:05 +0900 Subject: [PATCH 4/9] =?UTF-8?q?:white=5Fcheck=5Fmark:=20test=20:=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usecases/UserRegisterServiceTest.java | 65 +++++++++++-------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java index db8a8d7d..9cf3678e 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java @@ -1,49 +1,58 @@ package org.runimo.runimo.user.service.usecases; -import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.runimo.runimo.CleanUpUtil; -import org.runimo.runimo.item.repository.ItemRepository; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.runimo.runimo.rewards.service.eggs.EggGrantService; import org.runimo.runimo.user.domain.SocialProvider; import org.runimo.runimo.user.domain.User; -import org.runimo.runimo.user.domain.UserItem; -import org.runimo.runimo.user.repository.UserItemRepository; +import org.runimo.runimo.user.service.UserCreator; +import org.runimo.runimo.user.service.UserItemCreator; import org.runimo.runimo.user.service.dtos.UserSignupCommand; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.jdbc.Sql; +import org.runimo.runimo.user.service.usecases.auth.UserRegisterService; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; -@ActiveProfiles("test") -@SpringBootTest class UserRegisterServiceTest { - @Autowired - private UserRegisterService userRegisterService; + @Mock + private UserCreator userCreator; + + @Mock + private UserItemCreator userItemCreator; + + @Mock + private EggGrantService eggGrantService; - @Autowired - private UserItemRepository userItemRepository; - @Autowired - private ItemRepository itemRepository; - @Autowired - private CleanUpUtil cleanUpUtil; + @InjectMocks + private UserRegisterService userRegisterService; - @AfterEach - void tearDown() { - cleanUpUtil.cleanUpUserInfos(); + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); } @Test - @Sql(scripts = "/sql/egg_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) void 회원가입_알_지급_테스트() { // given UserSignupCommand command = new UserSignupCommand("test", SocialProvider.KAKAO, "1234"); + User mockUser = mock(User.class); + when(userCreator.createUser(any(UserSignupCommand.class))).thenReturn(mockUser); + + // when User createdUser = userRegisterService.register(command, "1234"); - UserItem ui = userItemRepository.findByUserIdAndItemId(createdUser.getId(), 1L).get(); - assertNotNull(ui); - assertEquals(1L, ui.getQuantity()); + + // then + assertNotNull(createdUser); + verify(userCreator, times(1)).createUser(command); + verify(userCreator, times(1)).createUserOAuthInfo(mockUser, eq(SocialProvider.KAKAO), eq("1234")); + verify(userCreator, times(1)).createLovePoint(anyLong()); + verify(userItemCreator, times(1)).createAll(anyLong()); + verify(eggGrantService, times(1)).grantGreetingEggToUser(mockUser); } -} \ No newline at end of file +} From 88fabc35bb99a314aedb0a11b00a1450f1a18821 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:36:10 +0900 Subject: [PATCH 5/9] =?UTF-8?q?:hammer:=20script=20:=20`incubating=5FEggs`?= =?UTF-8?q?=20=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=B6=94=EA=B0=80,=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20dml?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/sql/schema.sql | 15 +++++++++++ .../java/org/runimo/runimo/CleanUpUtil.java | 3 ++- .../sql/incubating_egg_test_data.sql | 25 +++++++++++++++++++ src/test/resources/sql/schema.sql | 15 +++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/sql/incubating_egg_test_data.sql diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index af5a9d17..55dcefb9 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -11,6 +11,7 @@ DROP TABLE IF EXISTS runimo; DROP TABLE IF EXISTS items; DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS user_love_point; +DROP TABLE IF EXISTS incubating_eggs; SET FOREIGN_KEY_CHECKS = 1; @@ -116,6 +117,20 @@ CREATE TABLE `user_item` `deleted_at` TIMESTAMP ); +CREATE TABLE `incubating_eggs` +( + `id` + BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` integer NOT NULL, + `egg_id` integer NOT NULL, + `current_love_point_amount` integer, + `hatch_require_amount` integer, + `egg_status` varchar(255), + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP +); + ALTER TABLE `user_token` ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`); diff --git a/src/test/java/org/runimo/runimo/CleanUpUtil.java b/src/test/java/org/runimo/runimo/CleanUpUtil.java index ccaf9f7f..c2afccf0 100644 --- a/src/test/java/org/runimo/runimo/CleanUpUtil.java +++ b/src/test/java/org/runimo/runimo/CleanUpUtil.java @@ -12,7 +12,8 @@ public class CleanUpUtil { "oauth_accounts", "users", "running_records", - "user_love_point" + "user_love_point", + "incubating_eggs" }; @Autowired diff --git a/src/test/resources/sql/incubating_egg_test_data.sql b/src/test/resources/sql/incubating_egg_test_data.sql new file mode 100644 index 00000000..e6c15aa8 --- /dev/null +++ b/src/test/resources/sql/incubating_egg_test_data.sql @@ -0,0 +1,25 @@ +SET FOREIGN_KEY_CHECKS = 0; +TRUNCATE TABLE users; +TRUNCATE TABLE items; +TRUNCATE TABLE incubating_eggs; +TRUNCATE TABLE user_item; +TRUNCATE TABLE user_love_point; +SET FOREIGN_KEY_CHECKS = 1; + + +INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, total_time_in_seconds, created_at, updated_at) +VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 3000, 3600, NOW(), NOW()); + +INSERT INTO user_love_point (id, user_id, amount, created_at, updated_at) +VALUES (1, 1, 1000, NOW(), NOW()); + +-- 보유 아이템 +INSERT INTO user_item (id, user_id, item_id, quantity, created_at, updated_at) +VALUES (1001, 1, 1, 2, NOW(), NOW()), + (1002, 1, 2, 1, NOW(), NOW()); + +INSERT INTO items (id, name, item_code, description, item_type, img_url, dtype, egg_type, hatch_require_amount, created_at, updated_at) +VALUES (1, '마당알', 'A100', '기본 알', 'USABLE', 'https://example.com/images/egg.png', 'EGG', 'MADANG', 100, NOW(), NOW()); + +INSERT INTO incubating_eggs (id, user_id, egg_id, current_love_point_amount, hatch_require_amount, egg_status, created_at, updated_at) +VALUES (1, 1, 1, 50, 100, 'INCUBATING', NOW(), NOW()); diff --git a/src/test/resources/sql/schema.sql b/src/test/resources/sql/schema.sql index af5a9d17..3bf56a33 100644 --- a/src/test/resources/sql/schema.sql +++ b/src/test/resources/sql/schema.sql @@ -11,6 +11,7 @@ DROP TABLE IF EXISTS runimo; DROP TABLE IF EXISTS items; DROP TABLE IF EXISTS users; DROP TABLE IF EXISTS user_love_point; +DROP TABLE IF EXISTS incubating_eggs; SET FOREIGN_KEY_CHECKS = 1; @@ -116,6 +117,20 @@ CREATE TABLE `user_item` `deleted_at` TIMESTAMP ); +CREATE TABLE `incubating_eggs` +( + `id` + BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` integer NOT NULL, + `egg_id` integer NOT NULL, + `current_love_point_amount` integer, + `hatch_require_amount` integer, + `egg_status` varchar(255), + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP +); + ALTER TABLE `user_token` ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`); From 2d573d53e4d2b75cbb2a2b677ff6f5cf50ec8450 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:36:33 +0900 Subject: [PATCH 6/9] =?UTF-8?q?:white=5Fcheck=5Fmark:=20test=20:=20import?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/org/runimo/runimo/rewards/RewardTest.java | 2 +- .../java/org/runimo/runimo/user/api/MainViewControllerTest.java | 2 +- .../org/runimo/runimo/user/api/QueryItemControllerTest.java | 2 +- .../runimo/user/service/usecases/GainItemUsecaseTest.java | 1 + .../runimo/user/service/usecases/QueryUserItemUsecaseTest.java | 2 ++ .../runimo/runimo/user/service/usecases/UseItemUsecaseTest.java | 1 + 6 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/runimo/runimo/rewards/RewardTest.java b/src/test/java/org/runimo/runimo/rewards/RewardTest.java index 7c30f1e9..cbeeb47f 100644 --- a/src/test/java/org/runimo/runimo/rewards/RewardTest.java +++ b/src/test/java/org/runimo/runimo/rewards/RewardTest.java @@ -17,7 +17,7 @@ import org.runimo.runimo.user.domain.UserItem; import org.runimo.runimo.user.service.UserItemFinder; import org.runimo.runimo.user.service.dtos.UserSignupCommand; -import org.runimo.runimo.user.service.usecases.UserRegisterService; +import org.runimo.runimo.user.service.usecases.auth.UserRegisterService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; diff --git a/src/test/java/org/runimo/runimo/user/api/MainViewControllerTest.java b/src/test/java/org/runimo/runimo/user/api/MainViewControllerTest.java index d5aac688..e2347a03 100644 --- a/src/test/java/org/runimo/runimo/user/api/MainViewControllerTest.java +++ b/src/test/java/org/runimo/runimo/user/api/MainViewControllerTest.java @@ -2,7 +2,7 @@ import org.junit.jupiter.api.Test; import org.runimo.runimo.auth.jwt.JwtTokenFactory; -import org.runimo.runimo.user.service.usecases.MainViewQueryUsecase; +import org.runimo.runimo.user.service.usecases.query.MainViewQueryUsecase; import org.runimo.runimo.user.service.dtos.MainViewResponse; import org.runimo.runimo.user.UserFixtures; import org.runimo.runimo.user.service.UserFinder; diff --git a/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java b/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java index e3fe2835..e1b5f0e6 100644 --- a/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java +++ b/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java @@ -5,7 +5,7 @@ import org.runimo.runimo.user.UserFixtures; import org.runimo.runimo.user.service.UserFinder; import org.runimo.runimo.user.service.dtos.ItemQueryResponse; -import org.runimo.runimo.user.service.usecases.MyItemQueryUsecase; +import org.runimo.runimo.user.service.usecases.query.MyItemQueryUsecase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseTest.java index 64dcb850..2511d6ca 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/GainItemUsecaseTest.java @@ -5,6 +5,7 @@ import org.runimo.runimo.user.repository.UserItemRepository; import org.runimo.runimo.user.service.dtos.GainItemCommand; import org.runimo.runimo.user.service.dtos.GainItemResponse; +import org.runimo.runimo.user.service.usecases.items.GainItemUsecase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java index fa7f1021..6e0992c3 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java @@ -6,6 +6,8 @@ import org.runimo.runimo.user.repository.MyItemRepository; import org.runimo.runimo.user.service.dtos.InventoryItem; import org.runimo.runimo.user.service.dtos.ItemQueryResponse; +import org.runimo.runimo.user.service.usecases.query.MyItemQueryUsecase; +import org.runimo.runimo.user.service.usecases.query.MyItemQueryUsecaseImpl; import java.util.List; diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseTest.java index 004c38c0..dbf821b9 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/UseItemUsecaseTest.java @@ -6,6 +6,7 @@ import org.runimo.runimo.user.service.UserItemFinder; import org.runimo.runimo.user.service.dtos.UseItemCommand; import org.runimo.runimo.user.service.dtos.UseItemResponse; +import org.runimo.runimo.user.service.usecases.items.UseItemUsecase; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; From 7887d3c344a480aded7956f23f2df8ba26e77c12 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:41:01 +0900 Subject: [PATCH 7/9] =?UTF-8?q?:bug:=20fix=20:=20`mockito.ArgumentMatchers?= =?UTF-8?q?.eq`=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/user/service/usecases/UserRegisterServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java index 9cf3678e..7e7df3da 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java @@ -15,7 +15,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; class UserRegisterServiceTest { @@ -50,7 +49,7 @@ void setUp() { // then assertNotNull(createdUser); verify(userCreator, times(1)).createUser(command); - verify(userCreator, times(1)).createUserOAuthInfo(mockUser, eq(SocialProvider.KAKAO), eq("1234")); + verify(userCreator, times(1)).createUserOAuthInfo(mockUser, SocialProvider.KAKAO, "1234"); verify(userCreator, times(1)).createLovePoint(anyLong()); verify(userItemCreator, times(1)).createAll(anyLong()); verify(eggGrantService, times(1)).grantGreetingEggToUser(mockUser); From 205e4ce60f59acd51039e7c735be9495863f0bed Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:47:23 +0900 Subject: [PATCH 8/9] =?UTF-8?q?:sparkles:=20feat=20:=20jpql=20=EB=B6=80?= =?UTF-8?q?=ED=99=94=EC=A4=91=EC=9D=B8=20=EC=95=8C=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/runimo/user/repository/IncubatingEggRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java b/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java index fc3f28ba..714930fe 100644 --- a/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java +++ b/src/main/java/org/runimo/runimo/user/repository/IncubatingEggRepository.java @@ -21,7 +21,7 @@ public interface IncubatingEggRepository extends JpaRepository findByUserIdAndEggIdForUpdate(Long userId, Long eggId); - @Query("select ie from IncubatingEgg ie where ie.userId = :userId and ie.status = 'INCUBATING' or ie.status = 'INCUBATED'") + @Query("select ie from IncubatingEgg ie where ie.userId = :userId and (ie.status = 'INCUBATING' or ie.status = 'INCUBATED')") List findAllByUserId(Long userId); @Query("select new org.runimo.runimo.user.service.dtos.IncubatingEggView(ie.id, e.name, e.imgUrl, ie.hatchRequireAmount, ie.currentLovePointAmount, ie.status) " + From f0c0decfc8a3b526212e83bdbd51693a14f24a56 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Sat, 29 Mar 2025 23:55:09 +0900 Subject: [PATCH 9/9] =?UTF-8?q?:truck:=20refactor=20:=20controller?= =?UTF-8?q?=EC=97=90=20=EC=A1=B4=EC=9E=AC=ED=95=98=EB=8A=94=20=EB=B9=84?= =?UTF-8?q?=EC=A6=88=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/runimo/runimo/user/controller/EggController.java | 6 +++--- .../runimo/user/controller/IncubatingEggQueryUsecase.java | 5 ----- .../user/controller/{ => request}/UseLovePointRequest.java | 2 +- .../dtos}/QueryIncubatingEggResponse.java | 4 +--- .../{controller => service/dtos}/UseLovePointResponse.java | 2 +- .../service/usecases/eggs/GiveLovePointToEggUsecase.java | 2 +- .../usecases/eggs/GiveLovePointToEggUsecaseImpl.java | 2 +- .../service/usecases/eggs/IncubatingEggQueryUsecase.java | 7 +++++++ .../usecases/eggs}/IncubatingEggQueryUsecaseImpl.java | 3 ++- .../runimo/user/api/IncubatingEggAcceptanceTest.java | 2 +- 10 files changed, 18 insertions(+), 17 deletions(-) delete mode 100644 src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java rename src/main/java/org/runimo/runimo/user/controller/{ => request}/UseLovePointRequest.java (62%) rename src/main/java/org/runimo/runimo/user/{controller => service/dtos}/QueryIncubatingEggResponse.java (52%) rename src/main/java/org/runimo/runimo/user/{controller => service/dtos}/UseLovePointResponse.java (77%) create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecase.java rename src/main/java/org/runimo/runimo/user/{controller => service/usecases/eggs}/IncubatingEggQueryUsecaseImpl.java (83%) diff --git a/src/main/java/org/runimo/runimo/user/controller/EggController.java b/src/main/java/org/runimo/runimo/user/controller/EggController.java index c0a33edf..8fdadcfd 100644 --- a/src/main/java/org/runimo/runimo/user/controller/EggController.java +++ b/src/main/java/org/runimo/runimo/user/controller/EggController.java @@ -5,11 +5,11 @@ import lombok.RequiredArgsConstructor; import org.runimo.runimo.common.response.SuccessResponse; import org.runimo.runimo.user.controller.request.RegisterEggRequest; -import org.runimo.runimo.user.service.dtos.RegisterEggResponse; +import org.runimo.runimo.user.controller.request.UseLovePointRequest; +import org.runimo.runimo.user.service.dtos.*; import org.runimo.runimo.user.enums.UserHttpResponseCode; -import org.runimo.runimo.user.service.dtos.UseLovePointCommand; +import org.runimo.runimo.user.service.usecases.eggs.IncubatingEggQueryUsecase; import org.runimo.runimo.user.service.usecases.eggs.EggRegisterUsecase; -import org.runimo.runimo.user.service.dtos.RegisterEggCommand; import org.runimo.runimo.user.service.usecases.eggs.GiveLovePointToEggUsecase; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; diff --git a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java b/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java deleted file mode 100644 index e5be9b52..00000000 --- a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecase.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.runimo.runimo.user.controller; - -public interface IncubatingEggQueryUsecase { - QueryIncubatingEggResponse execute(Long userId); -} diff --git a/src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java b/src/main/java/org/runimo/runimo/user/controller/request/UseLovePointRequest.java similarity index 62% rename from src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java rename to src/main/java/org/runimo/runimo/user/controller/request/UseLovePointRequest.java index e209cfff..0a96c0ad 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UseLovePointRequest.java +++ b/src/main/java/org/runimo/runimo/user/controller/request/UseLovePointRequest.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.controller; +package org.runimo.runimo.user.controller.request; public record UseLovePointRequest( Long itemId, diff --git a/src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java b/src/main/java/org/runimo/runimo/user/service/dtos/QueryIncubatingEggResponse.java similarity index 52% rename from src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java rename to src/main/java/org/runimo/runimo/user/service/dtos/QueryIncubatingEggResponse.java index 22eb7628..fc384a02 100644 --- a/src/main/java/org/runimo/runimo/user/controller/QueryIncubatingEggResponse.java +++ b/src/main/java/org/runimo/runimo/user/service/dtos/QueryIncubatingEggResponse.java @@ -1,6 +1,4 @@ -package org.runimo.runimo.user.controller; - -import org.runimo.runimo.user.service.dtos.IncubatingEggView; +package org.runimo.runimo.user.service.dtos; import java.util.List; diff --git a/src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java b/src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointResponse.java similarity index 77% rename from src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java rename to src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointResponse.java index c2c2ded1..5e09b4e6 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UseLovePointResponse.java +++ b/src/main/java/org/runimo/runimo/user/service/dtos/UseLovePointResponse.java @@ -1,4 +1,4 @@ -package org.runimo.runimo.user.controller; +package org.runimo.runimo.user.service.dtos; public record UseLovePointResponse( Long eggId, diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java index 9a3f510b..c9e4df60 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecase.java @@ -1,6 +1,6 @@ package org.runimo.runimo.user.service.usecases.eggs; -import org.runimo.runimo.user.controller.UseLovePointResponse; +import org.runimo.runimo.user.service.dtos.UseLovePointResponse; import org.runimo.runimo.user.service.dtos.UseLovePointCommand; public interface GiveLovePointToEggUsecase { diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java index 6f78be0a..bef35765 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/GiveLovePointToEggUsecaseImpl.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.runimo.runimo.user.domain.IncubatingEgg; -import org.runimo.runimo.user.controller.UseLovePointResponse; +import org.runimo.runimo.user.service.dtos.UseLovePointResponse; import org.runimo.runimo.user.service.IncubatingEggProcessor; import org.runimo.runimo.user.service.LovePointProcessor; import org.runimo.runimo.user.service.dtos.UseLovePointCommand; diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecase.java new file mode 100644 index 00000000..b7bfaa3e --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecase.java @@ -0,0 +1,7 @@ +package org.runimo.runimo.user.service.usecases.eggs; + +import org.runimo.runimo.user.service.dtos.QueryIncubatingEggResponse; + +public interface IncubatingEggQueryUsecase { + QueryIncubatingEggResponse execute(Long userId); +} diff --git a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecaseImpl.java similarity index 83% rename from src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java rename to src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecaseImpl.java index 46b78807..3f15ae7b 100644 --- a/src/main/java/org/runimo/runimo/user/controller/IncubatingEggQueryUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/eggs/IncubatingEggQueryUsecaseImpl.java @@ -1,6 +1,7 @@ -package org.runimo.runimo.user.controller; +package org.runimo.runimo.user.service.usecases.eggs; import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.service.dtos.QueryIncubatingEggResponse; import org.runimo.runimo.user.service.dtos.IncubatingEggView; import org.runimo.runimo.user.service.IncubatingEggFinder; import org.springframework.stereotype.Service; diff --git a/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java b/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java index 2538431f..3ed5912d 100644 --- a/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java +++ b/src/test/java/org/runimo/runimo/user/api/IncubatingEggAcceptanceTest.java @@ -9,7 +9,7 @@ import org.junit.jupiter.api.Test; import org.runimo.runimo.CleanUpUtil; import org.runimo.runimo.auth.jwt.JwtTokenFactory; -import org.runimo.runimo.user.controller.UseLovePointRequest; +import org.runimo.runimo.user.controller.request.UseLovePointRequest; import org.runimo.runimo.user.controller.request.RegisterEggRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;