Skip to content

Commit

Permalink
feat: 특정 유저 코인 추가 API (관리자 전용)
Browse files Browse the repository at this point in the history
  • Loading branch information
toychip committed Sep 4, 2024
1 parent 31cd744 commit b732d55
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 0 deletions.
24 changes: 24 additions & 0 deletions api/src/main/kotlin/com/mashup/dojo/CoinController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,30 @@ class CoinController(
return coinUseCase.earnCoin(CoinUseCase.EarnCoinCommand(memberId, amount))
.let { DojoApiResponse.success(it) }
}

@PostMapping("/admin/update")
@Operation(
summary = "관리자가 직접 특정 사용자에게 잼을 제공하는 API",
description = "특정 사용자에게 잼을 제공하는 API (관리자 전용)",
responses = [
ApiResponse(responseCode = "200", description = "관리자 보상 제공 성공")
]
)
fun provideCoinByEvent(
@RequestParam fullName: String,
@RequestParam amount: Long,
@RequestParam(required = false) platform: String?,
): DojoApiResponse<CoinUseDetailId> {
val currentMemberId = MemberPrincipalContextHolder.current().id
return coinUseCase.earnCoinByEvent(
CoinUseCase.EarnCoinByEventCommand(
currentMemberId = currentMemberId,
fullName = fullName,
platform = platform,
coinAmount = amount
)
).let { DojoApiResponse.success(it) }
}
}

private const val DEFAULT_COMPLETE_PICK_OFFER_AMOUNT = 200L
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum class DojoExceptionType(
ARGUMENT_NOT_VALID("Method Argument Not Valid. Check argument validation.", "C009_ARGUMENT_NOT_VALID", 400),
INVALID_MEMBER_GENDER("The gender does not exist.", "C011_INVALID_MEMBER_GENDER", 400),
INVALID_MEMBER_PLATFORM("The platform does not exist.", "C010_INVALID_MEMBER_PLATFORM", 400),
DUPLICATED_MEMBER("DUPLICATED_MEMBER", "C013_DUPLICATED_MEMBER", 400),
MEMBER_NOT_FOUND("Member not found", "C012_MEMBER_NOT_FOUND", 400),
IMAGE_NOT_FOUND("Image not found", "C013_IMAGE_NOT_FOUND", 400),

Expand Down
49 changes: 49 additions & 0 deletions entity/src/main/kotlin/com/mashup/dojo/MemberRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ interface MemberQueryRepository {
memberId: String,
keyword: String,
): List<MemberEntity>

fun findSingleMemberByFullName(fullName: String): MemberEntity

fun findSingleMemberByFullNameAndPlatform(
fullName: String,
platform: String,
): MemberEntity
}

class MemberQueryRepositoryImpl(
Expand All @@ -41,4 +48,46 @@ class MemberQueryRepositoryImpl(
.where(member.id.notIn(memberId), member.fullName.contains(keyword))
.fetch()
}

override fun findSingleMemberByFullName(fullName: String): MemberEntity {
val member = QMemberEntity.memberEntity

val results =
jpaQueryFactory
.select(member)
.from(member)
.where(member.fullName.eq(fullName))
.fetch()

when {
results.size > 1 -> throw DojoException.of(DojoExceptionType.DUPLICATED_MEMBER)
results.isEmpty() -> throw DojoException.of(DojoExceptionType.MEMBER_NOT_FOUND)
}

return results.first()
}

override fun findSingleMemberByFullNameAndPlatform(
fullName: String,
platform: String,
): MemberEntity {
val member = QMemberEntity.memberEntity

val results =
jpaQueryFactory
.select(member)
.from(member)
.where(
member.platform.eq(platform),
member.fullName.eq(fullName)
)
.fetch()

when {
results.size > 1 -> throw DojoException.of(DojoExceptionType.DUPLICATED_MEMBER)
results.isEmpty() -> throw DojoException.of(DojoExceptionType.MEMBER_NOT_FOUND)
}

return results.first()
}
}
18 changes: 18 additions & 0 deletions service/src/main/kotlin/com/mashup/dojo/service/MemberService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ interface MemberService {

fun findAllByIds(memberIds: List<MemberId>): List<Member>

fun findByFullNameAndPlatform(
fullName: String,
platform: MemberPlatform,
): Member

fun findMemberByFullName(fullName: String): Member

data class CreateMember(
val fullName: String,
val profileImageId: ImageId?,
Expand Down Expand Up @@ -112,6 +119,17 @@ class DefaultMemberService(
return memberRepository.findAllById(memberIds.map { it.value }).map { it.toMember() }
}

override fun findByFullNameAndPlatform(
fullName: String,
platform: MemberPlatform,
): Member {
return memberRepository.findSingleMemberByFullNameAndPlatform(fullName, platform.name).toMember()
}

override fun findMemberByFullName(fullName: String): Member {
return memberRepository.findSingleMemberByFullName(fullName).toMember()
}

private fun mockMember(memberId: MemberId) =
Member(
memberId, "임준형", "", ImageId("123456"), MemberPlatform.SPRING, 14, MemberGender.MALE, LocalDateTime.now(), LocalDateTime.now()
Expand Down
40 changes: 40 additions & 0 deletions service/src/main/kotlin/com/mashup/dojo/usecase/CoinUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ import com.mashup.dojo.domain.Coin
import com.mashup.dojo.domain.CoinUseDetail
import com.mashup.dojo.domain.CoinUseDetailId
import com.mashup.dojo.domain.CoinUseType
import com.mashup.dojo.domain.Member
import com.mashup.dojo.domain.MemberId
import com.mashup.dojo.domain.MemberPlatform
import com.mashup.dojo.service.CoinService
import com.mashup.dojo.service.MemberService
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional

Expand All @@ -16,14 +19,19 @@ interface CoinUseCase {

data class EarnCoinCommand(val memberId: MemberId, val coinAmount: Long)

data class EarnCoinByEventCommand(val currentMemberId: MemberId, val fullName: String, val platform: String?, val coinAmount: Long)

fun getCurrentCoin(command: GetCurrentCoinCommand): Coin

fun earnCoin(command: EarnCoinCommand): CoinUseDetailId

fun earnCoinByEvent(command: EarnCoinByEventCommand): CoinUseDetailId
}

@Component
class DefaultCoinUseCase(
private val coinService: CoinService,
private val membersService: MemberService,
) : CoinUseCase {
override fun getCurrentCoin(command: CoinUseCase.GetCurrentCoinCommand): Coin {
return coinService.getCoin(command.memberId) ?: throw DojoException.of(DojoExceptionType.NOT_EXIST, "유저의 코인정보가 없습니다")
Expand All @@ -36,4 +44,36 @@ class DefaultCoinUseCase(
val updatedCoin = coin.earnCoin(command.coinAmount)
return coinService.updateCoin(CoinUseType.EARNED, CoinUseDetail.REASON_COMPLETE_PICK, command.coinAmount.toInt(), updatedCoin)
}

@Transactional
override fun earnCoinByEvent(command: CoinUseCase.EarnCoinByEventCommand): CoinUseDetailId {
validAdmin(command.currentMemberId)
val findMember = findMember(command.fullName, command.platform)
return earnCoin(CoinUseCase.EarnCoinCommand(findMember.id, command.coinAmount))
}

// todo 추후 Role을 넣어서 Security에서 관리하도록하면 좋을듯합니다.
private fun validAdmin(currentMemberId: MemberId) {
val currentMember =
membersService.findMemberById(currentMemberId)
?: throw DojoException.of(DojoExceptionType.MEMBER_NOT_FOUND)

val dojo = listOf("한정민", "오예원", "박세원", "임준형", "이현재", "황태규", "최민석", "낭은영", "오시연")

if (currentMember.fullName !in dojo) {
throw DojoException.of(DojoExceptionType.AUTHENTICATION_FAILURE, "You Are Not Dojo")
}
}

private fun findMember(
fullName: String,
inputPlatform: String?,
): Member {
if (inputPlatform.isNullOrEmpty()) {
return membersService.findMemberByFullName(fullName)
} else {
val platform = MemberPlatform.findByValue(inputPlatform)
return membersService.findByFullNameAndPlatform(fullName, platform)
}
}
}

0 comments on commit b732d55

Please sign in to comment.