feat: UserBUilderを追加

This commit is contained in:
usbharu 2023-10-23 12:35:48 +09:00
parent 657936c3d9
commit 45e196edab
3 changed files with 128 additions and 7 deletions

View File

@ -1,7 +1,10 @@
package dev.usbharu.hideout.domain.model.hideout.entity package dev.usbharu.hideout.domain.model.hideout.entity
import dev.usbharu.hideout.config.ApplicationConfig
import dev.usbharu.hideout.config.CharacterLimit
import dev.usbharu.hideout.config.Config import dev.usbharu.hideout.config.Config
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.time.Instant import java.time.Instant
data class User private constructor( data class User private constructor(
@ -145,4 +148,121 @@ data class User private constructor(
) )
} }
} }
@Component
class UserBuilder(private val characterLimit: CharacterLimit, private val applicationConfig: ApplicationConfig) {
private val logger = LoggerFactory.getLogger(UserBuilder::class.java)
@Suppress("LongParameterList", "FunctionMinLength", "LongMethod")
fun of(
id: Long,
name: String,
domain: String,
screenName: String,
description: String,
password: String? = null,
inbox: String,
outbox: String,
url: String,
publicKey: String,
privateKey: String? = null,
createdAt: Instant,
keyId: String,
following: String? = null,
followers: String? = null
): User {
// idは0未満ではいけない
require(id >= 0) { "id must be greater than or equal to 0." }
// nameは空文字以外を含める必要がある
require(name.isNotBlank()) { "name must contain non-blank characters." }
// nameは指定された長さ以下である必要がある
val limitedName = if (name.length >= characterLimit.account.id) {
logger.warn("name must not exceed ${characterLimit.account.id} characters.")
name.substring(0, characterLimit.account.id)
} else {
name
}
// domainは空文字以外を含める必要がある
require(domain.isNotBlank()) { "domain must contain non-blank characters." }
// domainは指定された長さ以下である必要がある
require(domain.length <= characterLimit.general.domain) {
"domain must not exceed ${characterLimit.general.domain} characters."
}
// screenNameは空文字以外を含める必要がある
require(screenName.isNotBlank()) { "screenName must contain non-blank characters." }
// screenNameは指定された長さ以下である必要がある
val limitedScreenName = if (screenName.length >= characterLimit.account.name) {
logger.warn("screenName must not exceed ${characterLimit.account.name} characters.")
screenName.substring(0, characterLimit.account.name)
} else {
screenName
}
// descriptionは指定された長さ以下である必要がある
val limitedDescription = if (description.length >= characterLimit.account.description) {
logger.warn("description must not exceed ${characterLimit.account.description} characters.")
description.substring(0, characterLimit.account.description)
} else {
description
}
// ローカルユーザーはpasswordとprivateKeyをnullにしてはいけない
if (domain == applicationConfig.url.host) {
requireNotNull(password) { "password and privateKey must not be null for local users." }
requireNotNull(privateKey) { "password and privateKey must not be null for local users." }
}
// urlは空文字以外を含める必要がある
require(url.isNotBlank()) { "url must contain non-blank characters." }
// urlは指定された長さ以下である必要がある
require(url.length <= characterLimit.general.url) {
"url must not exceed ${characterLimit.general.url} characters."
}
// inboxは空文字以外を含める必要がある
require(inbox.isNotBlank()) { "inbox must contain non-blank characters." }
// inboxは指定された長さ以下である必要がある
require(inbox.length <= characterLimit.general.url) {
"inbox must not exceed ${characterLimit.general.url} characters."
}
// outboxは空文字以外を含める必要がある
require(outbox.isNotBlank()) { "outbox must contain non-blank characters." }
// outboxは指定された長さ以下である必要がある
require(outbox.length <= characterLimit.general.url) {
"outbox must not exceed ${characterLimit.general.url} characters."
}
require(keyId.isNotBlank()) {
"keyId must contain non-blank characters."
}
return User(
id = id,
name = limitedName,
domain = domain,
screenName = limitedScreenName,
description = limitedDescription,
password = password,
inbox = inbox,
outbox = outbox,
url = url,
publicKey = publicKey,
privateKey = privateKey,
createdAt = createdAt,
keyId = keyId,
followers = followers,
following = following
)
}
}
} }

View File

@ -9,7 +9,7 @@ import org.springframework.stereotype.Repository
import java.time.Instant import java.time.Instant
@Repository @Repository
class FollowerQueryServiceImpl : FollowerQueryService { class FollowerQueryServiceImpl(private val userBuilder: User.UserBuilder) : FollowerQueryService {
override suspend fun findFollowersById(id: Long): List<User> { override suspend fun findFollowersById(id: Long): List<User> {
val followers = Users.alias("FOLLOWERS") val followers = Users.alias("FOLLOWERS")
return Users.innerJoin( return Users.innerJoin(
@ -41,7 +41,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
) )
.select { Users.id eq id } .select { Users.id eq id }
.map { .map {
User.of( userBuilder.of(
id = it[followers[Users.id]], id = it[followers[Users.id]],
name = it[followers[Users.name]], name = it[followers[Users.name]],
domain = it[followers[Users.domain]], domain = it[followers[Users.domain]],
@ -92,7 +92,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
) )
.select { Users.name eq name and (Users.domain eq domain) } .select { Users.name eq name and (Users.domain eq domain) }
.map { .map {
User.of( userBuilder.of(
id = it[followers[Users.id]], id = it[followers[Users.id]],
name = it[followers[Users.name]], name = it[followers[Users.name]],
domain = it[followers[Users.domain]], domain = it[followers[Users.domain]],
@ -143,7 +143,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
) )
.select { followers[Users.id] eq id } .select { followers[Users.id] eq id }
.map { .map {
User.of( userBuilder.of(
id = it[followers[Users.id]], id = it[followers[Users.id]],
name = it[followers[Users.name]], name = it[followers[Users.name]],
domain = it[followers[Users.domain]], domain = it[followers[Users.domain]],
@ -194,7 +194,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
) )
.select { followers[Users.name] eq name and (followers[Users.domain] eq domain) } .select { followers[Users.name] eq name and (followers[Users.domain] eq domain) }
.map { .map {
User.of( userBuilder.of(
id = it[followers[Users.id]], id = it[followers[Users.id]],
name = it[followers[Users.name]], name = it[followers[Users.name]],
domain = it[followers[Users.domain]], domain = it[followers[Users.domain]],

View File

@ -21,6 +21,7 @@ class UserServiceImpl(
private val apSendFollowService: APSendFollowService, private val apSendFollowService: APSendFollowService,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,
private val followerQueryService: FollowerQueryService, private val followerQueryService: FollowerQueryService,
private val userBuilder: User.UserBuilder,
private val applicationConfig: ApplicationConfig private val applicationConfig: ApplicationConfig
) : ) :
UserService { UserService {
@ -35,7 +36,7 @@ class UserServiceImpl(
val hashedPassword = userAuthService.hash(user.password) val hashedPassword = userAuthService.hash(user.password)
val keyPair = userAuthService.generateKeyPair() val keyPair = userAuthService.generateKeyPair()
val userUrl = "${applicationConfig.url}/users/${user.name}" val userUrl = "${applicationConfig.url}/users/${user.name}"
val userEntity = User.of( val userEntity = userBuilder.of(
id = nextId, id = nextId,
name = user.name, name = user.name,
domain = applicationConfig.url.host, domain = applicationConfig.url.host,
@ -57,7 +58,7 @@ class UserServiceImpl(
override suspend fun createRemoteUser(user: RemoteUserCreateDto): User { override suspend fun createRemoteUser(user: RemoteUserCreateDto): User {
val nextId = userRepository.nextId() val nextId = userRepository.nextId()
val userEntity = User.of( val userEntity = userBuilder.of(
id = nextId, id = nextId,
name = user.name, name = user.name,
domain = user.domain, domain = user.domain,