Skip to content

Commit

Permalink
Merge pull request #87 from dnd-side-project/feat/#71-member
Browse files Browse the repository at this point in the history
회원이 온보딩을 수행한다.
  • Loading branch information
hwangdaesun authored Feb 11, 2025
2 parents a550943 + 3a4050c commit 6e9b46b
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 1 deletion.
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.member.request.PerformOnboardingRequest;
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 = "[Member API]", description = "회원에 관련된 API")
@SecurityRequirement(name = "access-token")
public interface PerformOnboardingApiSpec {
@Operation(summary = "회원 온보딩", description = "회원을 온보딩한다.")
ApiResponse<?> performOnboarding(UserDetails user, PerformOnboardingRequest request);
}
41 changes: 41 additions & 0 deletions api/src/main/java/com/dnd/sbooky/api/item/ObtainItemUseCase.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.dnd.sbooky.api.item;

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

import com.dnd.sbooky.api.item.exception.ItemNotFoundException;
import com.dnd.sbooky.api.member.exception.MemberNotFoundException;
import com.dnd.sbooky.core.item.ItemEntity;
import com.dnd.sbooky.core.item.ItemRepository;
import com.dnd.sbooky.core.item.MemberItemEntity;
import com.dnd.sbooky.core.item.MemberItemRepository;
import com.dnd.sbooky.core.member.MemberEntity;
import com.dnd.sbooky.core.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class ObtainItemUseCase {

private final MemberItemRepository memberItemRepository;
private final ItemRepository itemRepository;
private final MemberRepository memberRepository;

public void obtainItem(Long memberId, Long itemId) {
ItemEntity itemEntity =
itemRepository
.findById(itemId)
.orElseThrow(() -> new ItemNotFoundException(ITEM_NOT_FOUND));
MemberEntity memberEntity =
memberRepository
.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(MEMBER_NOT_FOUND));
boolean isExisted = memberItemRepository.existsByMemberIdAndItemId(memberId, itemId);
if (!isExisted) {
MemberItemEntity memberItemEntity = MemberItemEntity.obtainItem(memberEntity, itemEntity);
memberItemRepository.save(memberItemEntity);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.dnd.sbooky.api.member;

import com.dnd.sbooky.api.docs.spec.PerformOnboardingApiSpec;
import com.dnd.sbooky.api.member.request.PerformOnboardingRequest;
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.PostMapping;
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 PerformOnboardingController implements PerformOnboardingApiSpec {

private final PerformOnboardingUseCase performOnboardingUseCase;

@PostMapping("/members/onboarding")
public ApiResponse<?> performOnboarding(
@Parameter(hidden = true) @AuthenticationPrincipal UserDetails userDetails,
@Valid @RequestBody PerformOnboardingRequest request) {
Long memberId = Long.valueOf(userDetails.getUsername());
performOnboardingUseCase.performOnboarding(memberId, request);
return ApiResponse.success();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.dnd.sbooky.api.member;

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

import com.dnd.sbooky.api.item.ObtainItemUseCase;
import com.dnd.sbooky.api.member.exception.MemberNotFoundException;
import com.dnd.sbooky.api.member.request.PerformOnboardingRequest;
import com.dnd.sbooky.core.member.MemberEntity;
import com.dnd.sbooky.core.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Transactional
public class PerformOnboardingUseCase {
public static final long BASIC_GHOST_ID = 2L;
private final MemberRepository memberRepository;
private final ObtainItemUseCase obtainItemUseCase;

public void performOnboarding(Long memberId, PerformOnboardingRequest request) {
MemberEntity member =
memberRepository
.findById(memberId)
.orElseThrow(() -> new MemberNotFoundException(MEMBER_NOT_FOUND));
member.updateNickname(request.nickname());
obtainItemUseCase.obtainItem(memberId, BASIC_GHOST_ID);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.dnd.sbooky.api.member.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record PerformOnboardingRequest(@NotBlank @Size(min = 1, max = 10) String nickname) {}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class MemberItemEntity extends BaseEntity {
@Column(name = ENTITY_PREFIX + "_equipped", nullable = false)
private boolean equipped;

@Builder
@Builder(access = AccessLevel.PRIVATE)
private MemberItemEntity(MemberEntity memberEntity, ItemEntity itemEntity, boolean equipped) {
this.memberEntity = memberEntity;
this.itemEntity = itemEntity;
Expand All @@ -48,4 +48,12 @@ public static MemberItemEntity newInstance(MemberEntity memberEntity, ItemEntity
.equipped(true)
.build();
}

public static MemberItemEntity obtainItem(MemberEntity memberEntity, ItemEntity itemEntity) {
return MemberItemEntity.builder()
.memberEntity(memberEntity)
.itemEntity(itemEntity)
.equipped(false)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ public interface MemberItemRepositoryCustom {
List<FindItemDTO> findItemsByMemberId(Long memberId);

List<FindItemDTO> findEquippedItemsByMemberId(Long memberId);

boolean existsByMemberIdAndItemId(Long memberId, Long itemId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ public List<FindItemDTO> findEquippedItemsByMemberId(Long memberId) {
.fetch();
}

@Override
public boolean existsByMemberIdAndItemId(Long memberId, Long itemId) {
return queryFactory.selectOne().from(memberItem).where(hasItem(memberId, itemId)).fetchFirst()
!= null;
}

public BooleanExpression hasItem(Long memberId, Long itemId) {
return memberItem.memberEntity.id.eq(memberId).and(memberItem.itemEntity.id.eq(itemId));
}

private BooleanExpression isEquipped() {
return memberItem.equipped.isTrue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,8 @@ private MemberEntity(
public static MemberEntity newInstance(String nickname, String introduction) {
return MemberEntity.builder().nickname(nickname).introduction(introduction).build();
}

public void updateNickname(String nickname) {
this.nickname = nickname;
}
}

0 comments on commit 6e9b46b

Please sign in to comment.