diff --git a/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt b/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt index 247e43b..6ea1fe4 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/auth/application/AuthFacade.kt @@ -84,7 +84,7 @@ class AuthFacade( val userInfo = txTemplates.writer.coExecute { val userInfo = userInfoService.saveSync(UserInfo(nickname = request.username)) - credentialUserInfoService.save( + credentialUserInfoService.saveSync( CredentialUserInfo( uid = userInfo.id, username = request.username, diff --git a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevOAuthResource.kt b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevOAuthResource.kt index 058c57e..b5eb57c 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevOAuthResource.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevOAuthResource.kt @@ -1,6 +1,7 @@ package com.hero.alignlab.domain.dev.resource import com.hero.alignlab.common.extension.wrapOk +import com.hero.alignlab.config.swagger.SwaggerTag.DEV_TAG import com.hero.alignlab.domain.auth.model.OAuthProvider import com.hero.alignlab.domain.dev.application.DevOAuthService import io.swagger.v3.oas.annotations.Operation @@ -8,26 +9,26 @@ import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.MediaType import org.springframework.web.bind.annotation.* -@Tag(name = "Dev OAuth 인증 및 인가 관리") +@Tag(name = DEV_TAG) @RestController @RequestMapping(produces = [MediaType.APPLICATION_JSON_VALUE]) class DevOAuthResource( private val devOAuthService: DevOAuthService, ) { - @Operation(summary = "인가 코드 받기") + @Operation(summary = "[DEV] 인가 코드 받기") @GetMapping("/api/dev/v1/oauth/{provider}/authorize") suspend fun getDevOAuthAuthorizeCode( @PathVariable provider: OAuthProvider, ) = devOAuthService.getOAuthAuthorizeCode(provider).wrapOk() - @Operation(summary = "OAuth Token Generate") + @Operation(summary = "[DEV] OAuth Token Generate") @GetMapping("/api/dev/v1/oauth/{provider}/token") suspend fun redirectedDevOAuthAuthorizeCode( @PathVariable provider: OAuthProvider, @RequestParam code: String, ) = devOAuthService.resolveOAuth(provider, code).wrapOk() - @Operation(summary = "사용자 정보 조회") + @Operation(summary = "[DEV] 사용자 정보 조회") @GetMapping("/api/dev/v1/oauth/user") suspend fun getOAuthUserInfos( @RequestParam accessToken: String diff --git a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt index 20a27cc..dc2f8b8 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevUserInfoResource.kt @@ -15,7 +15,7 @@ import org.springframework.web.bind.annotation.* class DevUserInfoResource( private val userInfoService: UserInfoService, ) { - @Operation(summary = "유저 정보 조회") + @Operation(summary = "[DEV] 유저 정보 조회") @GetMapping("/api/dev/v1/users/{id}") suspend fun getUserInfo( @PathVariable id: Long, diff --git a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt index 2f31040..365d57b 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/dev/resource/DevWebsocketResource.kt @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.RestController class DevWebsocketResource( private val reactiveConcurrentUserWebSocketHandler: ReactiveConcurrentUserWebSocketHandler ) { - @Operation(summary = "websocket connection closed") + @Operation(summary = "[DEV] websocket connection closed") @PostMapping("/api/dev/v1/websocket/connection-closed") suspend fun closedConnection( @RequestHeader("X-HERO-DEV-TOKEN") token: String diff --git a/src/main/kotlin/com/hero/alignlab/domain/group/application/GroupFacade.kt b/src/main/kotlin/com/hero/alignlab/domain/group/application/GroupFacade.kt index 83f49bd..6c8a992 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/group/application/GroupFacade.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/group/application/GroupFacade.kt @@ -2,8 +2,11 @@ package com.hero.alignlab.domain.group.application import arrow.fx.coroutines.parZip import com.hero.alignlab.common.extension.executes +import com.hero.alignlab.common.extension.executesOrNull import com.hero.alignlab.config.database.TransactionTemplates import com.hero.alignlab.domain.auth.model.AuthUser +import com.hero.alignlab.domain.group.domain.Group +import com.hero.alignlab.domain.group.domain.GroupUser import com.hero.alignlab.domain.group.model.response.GetGroupResponse import com.hero.alignlab.domain.group.model.response.JoinGroupResponse import com.hero.alignlab.exception.ErrorCode @@ -20,17 +23,33 @@ class GroupFacade( suspend fun withdraw(user: AuthUser, groupId: Long) { val group = groupService.findByIdOrThrow(groupId) - if (group.ownerUid == user.uid) { - val groupUser = groupUserService.findTop1ByGroupIdOrderByCreatedAtAsc(groupId) + when (group.ownerUid == user.uid) { + true -> withdrawGroupOwner(group) + false -> withdrawGroupUser(groupId, user) + } + } - if (groupUser == null) { - groupService.deleteByIdSync(groupId) - } else { - group.apply { - this.ownerUid = groupUser.uid - }.run { groupService.saveSync(this) } - } - } else { + private suspend fun withdrawGroupOwner(group: Group) { + val groupUser = groupUserService.findTop1ByGroupIdOrderByCreatedAtAsc(group.id) + + when (groupUser == null) { + true -> groupService.deleteByIdSync(group.id) + false -> succeedGroupOwner(group, groupUser) + } + } + + private fun succeedGroupOwner(group: Group, groupUser: GroupUser) { + val succeedGroup = group.apply { + this.ownerUid = groupUser.uid + } + + txTemplates.writer.executesOrNull { + groupService.saveSync(succeedGroup) + } + } + + private suspend fun withdrawGroupUser(groupId: Long, user: AuthUser) { + txTemplates.writer.executesOrNull { groupUserService.deleteBySync(groupId, user.uid) } } @@ -50,27 +69,34 @@ class GroupFacade( val groupUser = groupUsers[groupId] - if (groupUser == null && groupUsers.isNotEmpty()) { - throw InvalidRequestException(ErrorCode.DUPLICATE_GROUP_JOIN_ERROR) - } + when { + /** 이미 다른 그룹에 속해있는 유저 */ + groupUser == null && groupUsers.isNotEmpty() -> { + throw InvalidRequestException(ErrorCode.DUPLICATE_GROUP_JOIN_ERROR) + } - if (groupUser != null) { - JoinGroupResponse( - groupId = group.id, - uid = groupUser.uid, - groupUserId = groupUser.id - ) - } + /** 이미 그룹원인 경우 */ + groupUser != null -> { + JoinGroupResponse( + groupId = group.id, + uid = groupUser.uid, + groupUserId = groupUser.id + ) + } - val createdGroupUser = txTemplates.writer.executes { - groupUserService.saveSync(groupId, user.uid) - } + /** 그룹에 조인 */ + else -> { + val createdGroupUser = txTemplates.writer.executes { + groupUserService.saveSync(groupId, user.uid) + } - JoinGroupResponse( - groupId = createdGroupUser.groupId, - uid = createdGroupUser.uid, - groupUserId = createdGroupUser.id - ) + JoinGroupResponse( + groupId = createdGroupUser.groupId, + uid = createdGroupUser.uid, + groupUserId = createdGroupUser.id + ) + } + } } } @@ -78,8 +104,8 @@ class GroupFacade( return parZip( { groupService.findByIdOrThrow(groupId) }, { groupUserService.existsByGroupIdAndUid(groupId, user.uid) }, - ) { group, includeGroup -> - if (!includeGroup) { + ) { group, joinedGroup -> + if (!joinedGroup) { throw NotFoundException(ErrorCode.NOT_FOUND_GROUP_ERROR) } diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/application/CredentialUserInfoService.kt b/src/main/kotlin/com/hero/alignlab/domain/user/application/CredentialUserInfoService.kt index 3aeed7f..bfb6c23 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/application/CredentialUserInfoService.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/user/application/CredentialUserInfoService.kt @@ -1,33 +1,28 @@ package com.hero.alignlab.domain.user.application -import com.hero.alignlab.common.encrypt.EncryptData -import com.hero.alignlab.common.encrypt.Encryptor import com.hero.alignlab.domain.user.domain.CredentialUserInfo import com.hero.alignlab.domain.user.infrastructure.CredentialUserInfoRepository -import com.hero.alignlab.exception.ErrorCode -import com.hero.alignlab.exception.NotFoundException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service class CredentialUserInfoService( private val credentialUserInfoRepository: CredentialUserInfoRepository, - private val encryptor: Encryptor, ) { suspend fun existsByUsername(username: String): Boolean { return withContext(Dispatchers.IO) { - credentialUserInfoRepository.existsByUsername(username) + existsByUsernameSync(username) } } - fun save(credentialUserInfo: CredentialUserInfo): CredentialUserInfo { - return credentialUserInfoRepository.save(credentialUserInfo) + private fun existsByUsernameSync(username: String): Boolean { + return credentialUserInfoRepository.existsByUsername(username) } - suspend fun findByUsernameAndPassword(username: String, password: String): CredentialUserInfo { - return withContext(Dispatchers.IO) { - credentialUserInfoRepository.findByUsernameAndPassword(username, EncryptData.enc(password, encryptor)) - } ?: throw NotFoundException(ErrorCode.NOT_FOUND_USER_ERROR) + @Transactional + fun saveSync(credentialUserInfo: CredentialUserInfo): CredentialUserInfo { + return credentialUserInfoRepository.save(credentialUserInfo) } } diff --git a/src/main/kotlin/com/hero/alignlab/domain/user/application/UserInfoService.kt b/src/main/kotlin/com/hero/alignlab/domain/user/application/UserInfoService.kt index 6939208..c6a974e 100644 --- a/src/main/kotlin/com/hero/alignlab/domain/user/application/UserInfoService.kt +++ b/src/main/kotlin/com/hero/alignlab/domain/user/application/UserInfoService.kt @@ -40,13 +40,17 @@ class UserInfoService( suspend fun findByCredential(username: String, password: String): UserInfo { return withContext(Dispatchers.IO) { - userInfoRepository.findByCredential( - username = username, - password = EncryptData.enc(password, encryptor) - ) + findByCredentialSync(username, password) } ?: throw NotFoundException(ErrorCode.NOT_FOUND_USER_ERROR) } + private fun findByCredentialSync(username: String, password: String): UserInfo? { + return userInfoRepository.findByCredential( + username = username, + password = EncryptData.enc(password, encryptor) + ) + } + fun findAllByIds(ids: List): List { return userInfoRepository.findAllById(ids) }