-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DPMBE-73] 인터렉션 init, 비지니스 로직을 구현한다 #111
Changes from 7 commits
348011c
4b42a01
7870cc6
20cc9fb
21fee03
06edf88
517c307
f37690b
d20d13a
ef30747
c2a9051
5fb3d0a
1441e9b
093b129
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package com.depromeet.whatnow.api.interaction.controller | ||
|
||
import com.depromeet.whatnow.api.interaction.dto.InteractionDetailResponse | ||
import com.depromeet.whatnow.api.interaction.dto.InteractionResponse | ||
import com.depromeet.whatnow.api.interaction.usecase.InteractionReadDetailUseCase | ||
import com.depromeet.whatnow.api.interaction.usecase.InteractionReadUseCase | ||
import com.depromeet.whatnow.api.interaction.usecase.InteractionSendUseCase | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
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.http.HttpStatus | ||
import org.springframework.http.ResponseEntity | ||
import org.springframework.web.bind.annotation.GetMapping | ||
import org.springframework.web.bind.annotation.PathVariable | ||
import org.springframework.web.bind.annotation.PostMapping | ||
import org.springframework.web.bind.annotation.RequestMapping | ||
import org.springframework.web.bind.annotation.RestController | ||
|
||
@RestController | ||
@Tag(name = "7. [인터렉션]") | ||
@RequestMapping("/v1") | ||
@SecurityRequirement(name = "access-token") | ||
class InteractionController( | ||
val interactionSendUseCase: InteractionSendUseCase, | ||
val interactionReadUseCase: InteractionReadUseCase, | ||
val interactionReadDetailUseCase: InteractionReadDetailUseCase, | ||
) { | ||
@PostMapping("/promises/{promiseId}/interactions/{interactionType}/target/{targetUserId}") | ||
@Operation(summary = "인터렉션을 발송합니다.") | ||
fun sendInteraction( | ||
@PathVariable promiseId: Long, | ||
@PathVariable interactionType: InteractionType, | ||
@PathVariable targetUserId: Long, | ||
): ResponseEntity<Unit> { | ||
interactionSendUseCase.execute(promiseId, interactionType, targetUserId) | ||
return ResponseEntity.status(HttpStatus.ACCEPTED).body(Unit) | ||
} | ||
|
||
@GetMapping("/users/me/promises/{promiseId}/interactions") | ||
@Operation(summary = "자신의 인터렉션 정보를 가져옵니다.") | ||
fun getMyInteraction( | ||
@PathVariable promiseId: Long, | ||
): InteractionResponse { | ||
return interactionReadUseCase.findMyInteraction(promiseId) | ||
} | ||
|
||
@GetMapping("/users/me/promises/{promiseId}/interactions/{interactionType}") | ||
@Operation(summary = "자신의 인터렉션 상세 정보를 가져옵니다.") | ||
fun getMyInteractionDetail( | ||
@PathVariable promiseId: Long, | ||
@PathVariable interactionType: InteractionType, | ||
): InteractionDetailResponse { | ||
return interactionReadDetailUseCase.findMyInteractionDetail(promiseId, interactionType) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 흠 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋은 의견인것같슴니다! |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.depromeet.whatnow.api.interaction.dto | ||
|
||
import com.depromeet.whatnow.common.vo.UserInfoVo | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
import com.depromeet.whatnow.domains.interactionhistory.domain.InteractionHistory | ||
|
||
data class InteractionDetailDto( | ||
val senderUser: UserInfoVo, | ||
val count: Long, | ||
val interactionType: InteractionType, | ||
) { | ||
companion object { | ||
fun from(it: InteractionHistory) { | ||
TODO("Not yet implemented") | ||
} | ||
// fun from(interaction: Interaction): InteractionDetailDto { | ||
// return InteractionDetailDto(interaction.promiseId, interaction.userId, interaction.interactionType, interaction.count) | ||
// } | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요곤 아직 구현이 안된건가요? |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.depromeet.whatnow.api.interaction.dto | ||
|
||
data class InteractionDetailResponse( | ||
val interactions: List<InteractionDetailDto>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.depromeet.whatnow.api.interaction.dto | ||
|
||
import com.depromeet.whatnow.domains.interaction.domain.Interaction | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
|
||
data class InteractionDto( | ||
val promiseId: Long, | ||
val userId: Long, | ||
val interactionType: InteractionType, | ||
val count: Long, | ||
) { | ||
companion object { | ||
fun from(interaction: Interaction): InteractionDto { | ||
return InteractionDto(interaction.promiseId, interaction.userId, interaction.interactionType, interaction.count) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.depromeet.whatnow.api.interaction.dto | ||
|
||
data class InteractionResponse( | ||
val interactionDtoList: List<InteractionDto>, | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.depromeet.whatnow.api.interaction.usecase | ||
|
||
import com.depromeet.whatnow.annotation.UseCase | ||
import com.depromeet.whatnow.api.interaction.dto.InteractionDetailDto | ||
import com.depromeet.whatnow.api.interaction.dto.InteractionDetailResponse | ||
import com.depromeet.whatnow.config.security.SecurityUtils | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
import com.depromeet.whatnow.domains.interactionhistory.service.InteractionHistoryDomainService | ||
import com.depromeet.whatnow.domains.user.adapter.UserAdapter | ||
|
||
@UseCase | ||
class InteractionReadDetailUseCase( | ||
val interactionHistoryDomainService: InteractionHistoryDomainService, | ||
val userAdapter: UserAdapter, | ||
) { | ||
fun findMyInteractionDetail(promiseId: Long, interactionType: InteractionType): InteractionDetailResponse { | ||
val userId = SecurityUtils.currentUserId | ||
return InteractionDetailResponse( | ||
interactionHistoryDomainService.queryAllByInteractionType(userId, promiseId, interactionType) | ||
.groupBy { it.targetUserId }.map { (targetUserId, interactionHistories) -> | ||
InteractionDetailDto( | ||
userAdapter.queryUser(targetUserId).toUserInfoVo(), | ||
interactionHistories.size.toLong(), | ||
interactionType, | ||
) | ||
}.sortedByDescending { it.count }, | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.depromeet.whatnow.api.interaction.usecase | ||
|
||
import com.depromeet.whatnow.annotation.UseCase | ||
import com.depromeet.whatnow.api.interaction.dto.InteractionDto | ||
import com.depromeet.whatnow.api.interaction.dto.InteractionResponse | ||
import com.depromeet.whatnow.config.security.SecurityUtils | ||
import com.depromeet.whatnow.domains.interaction.service.InteractionDomainService | ||
|
||
@UseCase | ||
class InteractionReadUseCase( | ||
val interactionDomainService: InteractionDomainService, | ||
) { | ||
|
||
fun findMyInteraction(promiseId: Long): InteractionResponse { | ||
val userId: Long = SecurityUtils.currentUserId | ||
return InteractionResponse( | ||
interactionDomainService.queryAllInteraction(promiseId, userId).map { InteractionDto.from(it) }, | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.depromeet.whatnow.api.interaction.usecase | ||
|
||
import com.depromeet.whatnow.annotation.UseCase | ||
import com.depromeet.whatnow.config.security.SecurityUtils | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
import com.depromeet.whatnow.domains.interactionhistory.service.InteractionHistoryDomainService | ||
|
||
@UseCase | ||
class InteractionSendUseCase( | ||
val interactionHistoryDomainService: InteractionHistoryDomainService, | ||
) { | ||
fun execute(promiseId: Long, interactionType: InteractionType, targetUserId: Long) { | ||
val userId = SecurityUtils.currentUserId | ||
interactionHistoryDomainService.sendInteraction(promiseId, interactionType, userId, targetUserId) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.whatnow.exception.custom | ||
|
||
import com.depromeet.whatnow.exception.GlobalErrorCode | ||
import com.depromeet.whatnow.exception.WhatnowCodeException | ||
|
||
class NotParticipatedInPromiseException : WhatnowCodeException( | ||
GlobalErrorCode.USER_NOT_PARTICIPATE, | ||
) { | ||
companion object { | ||
val EXCEPTION: WhatnowCodeException = NotParticipatedInPromiseException() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.whatnow.exception.custom | ||
|
||
import com.depromeet.whatnow.exception.GlobalErrorCode | ||
import com.depromeet.whatnow.exception.WhatnowCodeException | ||
|
||
class PromiseIdConversionException : WhatnowCodeException( | ||
GlobalErrorCode.PROMISE_ID_NOT_LONG, | ||
) { | ||
companion object { | ||
val EXCEPTION: WhatnowCodeException = PromiseIdConversionException() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.whatnow.exception.custom | ||
|
||
import com.depromeet.whatnow.exception.GlobalErrorCode | ||
import com.depromeet.whatnow.exception.WhatnowCodeException | ||
|
||
class PromiseIdParameterNotFoundException : WhatnowCodeException( | ||
GlobalErrorCode.PROMISE_ID_PARAMETER_NOT_FOUND, | ||
) { | ||
companion object { | ||
val EXCEPTION: WhatnowCodeException = PromiseIdParameterNotFoundException() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.whatnow.exception.custom | ||
|
||
import com.depromeet.whatnow.exception.GlobalErrorCode | ||
import com.depromeet.whatnow.exception.WhatnowCodeException | ||
|
||
class UserIdConversionException : WhatnowCodeException( | ||
GlobalErrorCode.USER_ID_NOT_LONG, | ||
) { | ||
companion object { | ||
val EXCEPTION: WhatnowCodeException = UserIdConversionException() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.depromeet.whatnow.exception.custom | ||
|
||
import com.depromeet.whatnow.exception.GlobalErrorCode | ||
import com.depromeet.whatnow.exception.WhatnowCodeException | ||
|
||
class UserIdParameterNotFoundException : WhatnowCodeException( | ||
GlobalErrorCode.USER_ID_PARAMETER_NOT_FOUND, | ||
) { | ||
companion object { | ||
val EXCEPTION: WhatnowCodeException = UserIdParameterNotFoundException() | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.depromeet.whatnow.common.aop.verify | ||
|
||
@Target(AnnotationTarget.FUNCTION) | ||
@Retention(AnnotationRetention.RUNTIME) | ||
annotation class CheckUserParticipation |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package com.depromeet.whatnow.common.aop.verify | ||
|
||
import com.depromeet.whatnow.domains.promiseuser.adaptor.PromiseUserAdaptor | ||
import com.depromeet.whatnow.domains.promiseuser.exception.PromiseUserNotFoundException | ||
import com.depromeet.whatnow.exception.custom.NotParticipatedInPromiseException | ||
import com.depromeet.whatnow.exception.custom.PromiseIdConversionException | ||
import com.depromeet.whatnow.exception.custom.PromiseIdParameterNotFoundException | ||
import com.depromeet.whatnow.exception.custom.UserIdConversionException | ||
import com.depromeet.whatnow.exception.custom.UserIdParameterNotFoundException | ||
import org.aspectj.lang.ProceedingJoinPoint | ||
import org.aspectj.lang.annotation.Around | ||
import org.aspectj.lang.annotation.Aspect | ||
import org.aspectj.lang.reflect.MethodSignature | ||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression | ||
import org.springframework.stereotype.Component | ||
import java.lang.NumberFormatException | ||
|
||
@Aspect | ||
@Component | ||
@ConditionalOnExpression("\${ableCheckUserParticipation:true}") | ||
class CheckUserParticipationAop( | ||
val promiseUserAdaptor: PromiseUserAdaptor, | ||
) { | ||
@Around("@annotation(com.depromeet.whatnow.common.aop.verify.CheckUserParticipation)") | ||
fun verify(joinPoint: ProceedingJoinPoint): Any? { | ||
val signature = joinPoint.signature as MethodSignature | ||
val args = joinPoint.args | ||
val userId = findUserIdArg(signature.parameterNames, args) | ||
val promiseId = findPromiseIdArg(signature.parameterNames, args) | ||
|
||
if (userIdInPromise(userId, promiseId)) { | ||
return joinPoint.proceed() | ||
} | ||
throw NotParticipatedInPromiseException.EXCEPTION | ||
} | ||
|
||
private fun findUserIdArg(methodParameterNames: Array<String>, args: Array<Any>): Long { | ||
for (i in methodParameterNames.indices) { | ||
if ((methodParameterNames[i] == "userId")) { | ||
val arg = args[i] | ||
if (arg is Long) { | ||
return arg | ||
} else if (arg is String) { | ||
try { | ||
return arg.toLong() | ||
} catch (e: NumberFormatException) { | ||
throw UserIdConversionException.EXCEPTION | ||
} | ||
} else { | ||
UserIdParameterNotFoundException.EXCEPTION | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. when 으로 좀더 이쁘게 바꿔볼수 있을것같음!! |
||
} | ||
throw UserIdParameterNotFoundException.EXCEPTION | ||
} | ||
|
||
private fun findPromiseIdArg(methodParameterNames: Array<String>, args: Array<Any>): Long { | ||
for (i in methodParameterNames.indices) { | ||
if ((methodParameterNames[i] == "promiseId")) { | ||
val arg = args[i] | ||
if (arg is Long) { | ||
return arg | ||
} else if (arg is String) { | ||
try { | ||
return arg.toLong() | ||
} catch (e: NumberFormatException) { | ||
throw PromiseIdConversionException.EXCEPTION | ||
} | ||
} else { | ||
PromiseIdParameterNotFoundException.EXCEPTION | ||
} | ||
} | ||
} | ||
throw PromiseIdParameterNotFoundException.EXCEPTION | ||
} | ||
|
||
private fun userIdInPromise(userId: Long, promiseId: Long): Boolean { | ||
return try { | ||
promiseUserAdaptor.findByPromiseIdAndUserId(promiseId, userId) | ||
true | ||
} catch (e: PromiseUserNotFoundException) { | ||
false | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.depromeet.whatnow.domains.interaction.adapter | ||
|
||
import com.depromeet.whatnow.annotation.Adapter | ||
import com.depromeet.whatnow.domains.interaction.domain.Interaction | ||
import com.depromeet.whatnow.domains.interaction.domain.InteractionType | ||
import com.depromeet.whatnow.domains.interaction.repository.InteractionRepository | ||
|
||
@Adapter | ||
class InteractionAdapter( | ||
val interactionRepository: InteractionRepository, | ||
) { | ||
fun save(interaction: Interaction) { | ||
interactionRepository.save(interaction) | ||
} | ||
|
||
fun queryInteraction(promiseId: Long, userId: Long, interactionType: InteractionType): Interaction { | ||
return interactionRepository.findByPromiseIdAndUserIdAndInteractionType(promiseId, userId, interactionType) | ||
} | ||
|
||
fun queryAllInteraction(promiseId: Long, userId: Long): List<Interaction> { | ||
return interactionRepository.findAllByPromiseIdAndUserId(promiseId, userId) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
target 이 userId 와 매칭 되는 맥락이 부족한 것 같아요.
users/{user-id} ? 같은 느낌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
음 뭔가 직관적인게 있을까요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리뷰 남겨주시면 확인후 다음 PR에서 반영해보겠습니다