Skip to content
This repository has been archived by the owner on May 19, 2024. It is now read-only.

Commit

Permalink
[WEAV-119] 회원가입 유스케이스 구현 (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
waterfogSW authored Jan 30, 2024
1 parent 7c5df29 commit 8b81372
Show file tree
Hide file tree
Showing 16 changed files with 266 additions and 11 deletions.
1 change: 1 addition & 0 deletions application/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {
implementation(project(":support:security"))
implementation(project(":domain"))

implementation("org.springframework:spring-tx:${Version.SPRING}")
implementation("org.springframework.boot:spring-boot:${Version.SPRING_BOOT}")
testImplementation(testFixtures(project(":domain")))
testFixturesImplementation(testFixtures(project(":domain")))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ interface UserAuthInfoRepository {

fun findByEmail(email: Email): UserAuthInfo?

fun save(userAuthInfo: UserAuthInfo)

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.studentcenter.weave.application.port.outbound

import com.studentcenter.weave.domain.entity.User
import java.util.*

interface UserRepository {

fun save(user: User)

fun getById(id: UUID): User

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
package com.studentcenter.weave.application.service.application

import com.studentcenter.weave.application.port.inbound.UserRegisterUseCase
import com.studentcenter.weave.application.service.domain.UserAuthInfoDomainService
import com.studentcenter.weave.application.service.domain.UserDomainService
import com.studentcenter.weave.application.service.util.UserTokenService
import com.studentcenter.weave.domain.entity.User
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class UserRegisterApplicationService : UserRegisterUseCase {
class UserRegisterApplicationService(
private val userTokenService: UserTokenService,
private val userDomainService: UserDomainService,
private val userAuthInfoDomainService: UserAuthInfoDomainService,
) : UserRegisterUseCase {

@Transactional
override fun invoke(command: UserRegisterUseCase.Command): UserRegisterUseCase.Result {
val user: User = userDomainService.create(
nickname = command.nickname,
email = command.email,
gender = command.gender,
mbti = command.mbti,
birthYear = command.birthYear,
universityId = command.universityId,
majorId = command.majorId,
)

userAuthInfoDomainService.create(
user = user,
socialLoginProvider = command.socialLoginProvider,
)

return UserRegisterUseCase.Result.Success(
accessToken = "accessToken",
refreshToken = "refreshToken"
accessToken = userTokenService.generateAccessToken(user),
refreshToken = userTokenService.generateRefreshToken(user),
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.studentcenter.weave.application.service.domain

import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.entity.UserAuthInfo
import com.studentcenter.weave.domain.enum.SocialLoginProvider
import com.studentcenter.weave.support.common.vo.Email

interface UserAuthInfoDomainService {

fun findByEmail(email: Email): UserAuthInfo?

fun create(
user: User,
socialLoginProvider: SocialLoginProvider,
): UserAuthInfo

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
package com.studentcenter.weave.application.service.domain

import com.studentcenter.weave.domain.entity.User
import java.util.UUID
import com.studentcenter.weave.domain.enum.Gender
import com.studentcenter.weave.domain.enum.Mbti
import com.studentcenter.weave.domain.vo.BirthYear
import com.studentcenter.weave.domain.vo.Nickname
import com.studentcenter.weave.support.common.vo.Email
import com.studentcenter.weave.support.common.vo.Url
import java.util.*


interface UserDomainService {

fun getById(id: UUID): User

fun create(
nickname: Nickname,
email: Email,
gender: Gender,
mbti: Mbti,
birthYear: BirthYear,
universityId: UUID,
majorId: UUID,
avatar: Url? = null,
): User

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@ package com.studentcenter.weave.application.service.domain.impl

import com.studentcenter.weave.application.port.outbound.UserAuthInfoRepository
import com.studentcenter.weave.application.service.domain.UserAuthInfoDomainService
import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.entity.UserAuthInfo
import com.studentcenter.weave.domain.enum.SocialLoginProvider
import com.studentcenter.weave.support.common.vo.Email
import org.springframework.stereotype.Service

@Service
class UserAuthInfoDomainServiceImpl(
private val userAuthInfoRepository: UserAuthInfoRepository
): UserAuthInfoDomainService {
) : UserAuthInfoDomainService {

override fun findByEmail(email: Email): UserAuthInfo? {
return userAuthInfoRepository.findByEmail(email)
}

override fun create(
user: User,
socialLoginProvider: SocialLoginProvider
): UserAuthInfo {
return UserAuthInfo.create(
user = user,
socialLoginProvider = socialLoginProvider,
).also { userAuthInfoRepository.save(it) }
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
package com.studentcenter.weave.application.service.domain.impl

import com.studentcenter.weave.application.port.outbound.UserRepository
import com.studentcenter.weave.application.service.domain.UserDomainService
import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.enum.Gender
import com.studentcenter.weave.domain.enum.Mbti
import com.studentcenter.weave.domain.vo.BirthYear
import com.studentcenter.weave.domain.vo.Nickname
import com.studentcenter.weave.support.common.vo.Email
import com.studentcenter.weave.support.common.vo.Url
import org.springframework.stereotype.Service
import java.util.*

@Service
class UserDomainServiceImpl : UserDomainService {
class UserDomainServiceImpl(
private val userRepository: UserRepository
) : UserDomainService {

override fun getById(id: UUID): User {
TODO("Not yet implemented")
return userRepository.getById(id)
}

override fun create(
nickname: Nickname,
email: Email,
gender: Gender,
mbti: Mbti,
birthYear: BirthYear,
universityId: UUID,
majorId: UUID,
avatar: Url?,
): User {
return User.create(
nickname = nickname,
email = email,
gender = gender,
mbti = mbti,
birthYear = birthYear,
universityId = universityId,
majorId = majorId,
avatar = avatar,
).also { userRepository.save(it) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.studentcenter.weave.application.service.application

import com.studentcenter.weave.application.port.inbound.UserRegisterUseCase
import com.studentcenter.weave.application.port.outbound.UserAuthInfoRepositorySpy
import com.studentcenter.weave.application.port.outbound.UserRepositorySpy
import com.studentcenter.weave.application.service.domain.impl.UserAuthInfoDomainServiceImpl
import com.studentcenter.weave.application.service.domain.impl.UserDomainServiceImpl
import com.studentcenter.weave.application.service.util.UserTokenServiceStub
import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.entity.UserFixtureFactory
import com.studentcenter.weave.domain.enum.SocialLoginProvider
import io.kotest.core.spec.DisplayName
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.types.shouldBeTypeOf

@DisplayName("UserRegisterApplicationService")
class UserRegisterApplicationServiceTest : DescribeSpec({

describe("회원가입 유스케이스") {

val userRepositorySpy = UserRepositorySpy()
val userAuthInfoRepositorySpy = UserAuthInfoRepositorySpy()
val sut = UserRegisterApplicationService(
userTokenService = UserTokenServiceStub(),
userDomainService = UserDomainServiceImpl(userRepositorySpy),
userAuthInfoDomainService = UserAuthInfoDomainServiceImpl(userAuthInfoRepositorySpy)
)

context("회원가입 요청이 유효하면") {

it("해당회원을 생성하고 로그인 토큰을 반환한다") {
// arrange
val user: User = UserFixtureFactory.create()
val socialLoginProvider = SocialLoginProvider.KAKAO
val command = UserRegisterUseCase.Command(
nickname = user.nickname,
email = user.email,
socialLoginProvider = socialLoginProvider,
gender = user.gender,
mbti = user.mbti,
birthYear = user.birthYear,
universityId = user.universityId,
majorId = user.majorId
)

// act
val result: UserRegisterUseCase.Result = sut.invoke(command)

// assert
result.shouldBeTypeOf<UserRegisterUseCase.Result.Success>()
result.accessToken.shouldBeTypeOf<String>()
result.refreshToken.shouldBeTypeOf<String>()
}
}
}


})
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.studentcenter.weave.application.service.domain.impl

import com.studentcenter.weave.application.port.outbound.UserRepositorySpy
import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.entity.UserFixtureFactory
import io.kotest.core.spec.DisplayName
import io.kotest.core.spec.style.DescribeSpec
import io.kotest.matchers.shouldBe

@DisplayName("UserDomainServiceImpl")
class UserDomainServiceImplTest : DescribeSpec({

val userRepositorySpy = UserRepositorySpy()
val sut = UserDomainServiceImpl(userRepositorySpy)

afterTest { userRepositorySpy.clear() }

describe("create") {

it("유저를 생성하고 저장한다") {
// arrange
val userInfo: User = UserFixtureFactory.create()

// act
val createdUser: User = sut.create(
nickname = userInfo.nickname,
email = userInfo.email,
gender = userInfo.gender,
mbti = userInfo.mbti,
birthYear = userInfo.birthYear,
universityId = userInfo.universityId,
majorId = userInfo.majorId,
avatar = userInfo.avatar,
)

// assert
userRepositorySpy.findById(createdUser.id) shouldBe createdUser
}
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class UserAuthInfoRepositorySpy : UserAuthInfoRepository {
return bucket.values.find { it.email == email }
}

fun save(userAuthInfo: UserAuthInfo) {
override fun save(userAuthInfo: UserAuthInfo) {
bucket[userAuthInfo.id] = userAuthInfo
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.studentcenter.weave.application.port.outbound

import com.studentcenter.weave.domain.entity.User
import java.util.*
import java.util.concurrent.ConcurrentHashMap

class UserRepositorySpy : UserRepository {

private val bucket = ConcurrentHashMap<UUID, User>()

fun findById(id: UUID): User? {
return bucket[id]
}

override fun save(user: User) {
bucket[user.id] = user
}

override fun getById(id: UUID): User {
return bucket[id] ?: throw NoSuchElementException()
}

fun clear() {
bucket.clear()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,31 @@ package com.studentcenter.weave.application.service.domain

import com.studentcenter.weave.domain.entity.User
import com.studentcenter.weave.domain.entity.UserFixtureFactory
import com.studentcenter.weave.domain.enum.Gender
import com.studentcenter.weave.domain.enum.Mbti
import com.studentcenter.weave.domain.vo.BirthYear
import com.studentcenter.weave.domain.vo.Nickname
import com.studentcenter.weave.support.common.vo.Email
import com.studentcenter.weave.support.common.vo.Url
import java.util.*

class UserDomainServiceStub: UserDomainService {
class UserDomainServiceStub : UserDomainService {

override fun getById(id: UUID): User {
return UserFixtureFactory.create()
}

override fun create(
nickname: Nickname,
email: Email,
gender: Gender,
mbti: Mbti,
birthYear: BirthYear,
universityId: UUID,
majorId: UUID,
avatar: Url?
): User {
TODO("Not yet implemented")
}

}
1 change: 1 addition & 0 deletions buildSrc/src/main/kotlin/Version.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ object Version {
const val JAVA = "17"

// plugins
const val SPRING = "6.1.2"
const val SPRING_BOOT = "3.2.1"
const val SPRING_BOOT_DEPENDENCY_MANAGEMENT = "1.1.4"
const val KOTLIN = "1.9.21"
Expand Down
Loading

0 comments on commit 8b81372

Please sign in to comment.