feat: Actorのインスタンス化時にチェックするように

This commit is contained in:
usbharu 2024-02-26 15:58:32 +09:00
parent 15b3cf6796
commit 7719863b80
4 changed files with 78 additions and 30 deletions

View File

@ -18,37 +18,56 @@ package dev.usbharu.hideout.core.domain.model.actor
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.config.CharacterLimit
import jakarta.validation.Validator
import jakarta.validation.constraints.*
import org.hibernate.validator.constraints.URL
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.time.Instant
import kotlin.math.max
data class Actor private constructor(
@get:NotNull
@get:Positive
val id: Long,
@get:Pattern(regexp = "^[a-zA-Z0-9_-]{1,300}\$")
@get:Size(min = 1)
val name: String,
@get:Pattern(regexp = "^([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\\.){1,255}[a-zA-Z]{2,}\$")
val domain: String,
val screenName: String,
val description: String,
@get:URL
val inbox: String,
@get:URL
val outbox: String,
@get:URL
val url: String,
@get:NotBlank
val publicKey: String,
val privateKey: String? = null,
@get:PastOrPresent
val createdAt: Instant,
@get:NotBlank
val keyId: String,
val followers: String? = null,
val following: String? = null,
@get:Positive
val instance: Long? = null,
val locked: Boolean,
val followersCount: Int = 0,
val followingCount: Int = 0,
val postsCount: Int = 0,
val lastPostDate: Instant? = null,
val emojis: List<Long> = emptyList()
val emojis: List<Long> = emptyList(),
) {
@Component
class UserBuilder(private val characterLimit: CharacterLimit, private val applicationConfig: ApplicationConfig) {
class UserBuilder(
private val characterLimit: CharacterLimit,
private val applicationConfig: ApplicationConfig,
private val validator: Validator,
) {
private val logger = LoggerFactory.getLogger(UserBuilder::class.java)
@ -74,7 +93,7 @@ data class Actor private constructor(
followingCount: Int = 0,
postsCount: Int = 0,
lastPostDate: Instant? = null,
emojis: List<Long> = emptyList()
emojis: List<Long> = emptyList(),
): Actor {
if (id == 0L) {
return Actor(
@ -176,7 +195,7 @@ data class Actor private constructor(
"keyId must contain non-blank characters."
}
return Actor(
val actor = Actor(
id = id,
name = limitedName,
domain = domain,
@ -199,6 +218,13 @@ data class Actor private constructor(
lastPostDate = lastPostDate,
emojis = emojis
)
val validate = validator.validate(actor)
for (constraintViolation in validate) {
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
}
return actor
}
}
@ -217,27 +243,27 @@ data class Actor private constructor(
fun withLastPostAt(lastPostDate: Instant): Actor = this.copy(lastPostDate = lastPostDate)
override fun toString(): String {
return "Actor(" +
"id=$id, " +
"name='$name', " +
"domain='$domain', " +
"screenName='$screenName', " +
"description='$description', " +
"inbox='$inbox', " +
"outbox='$outbox', " +
"url='$url', " +
"publicKey='$publicKey', " +
"privateKey=$privateKey, " +
"createdAt=$createdAt, " +
"keyId='$keyId', " +
"followers=$followers, " +
"following=$following, " +
"instance=$instance, " +
"locked=$locked, " +
"followersCount=$followersCount, " +
"followingCount=$followingCount, " +
"postsCount=$postsCount, " +
"lastPostDate=$lastPostDate, " +
"emojis=$emojis" +
")"
"id=$id, " +
"name='$name', " +
"domain='$domain', " +
"screenName='$screenName', " +
"description='$description', " +
"inbox='$inbox', " +
"outbox='$outbox', " +
"url='$url', " +
"publicKey='$publicKey', " +
"privateKey=$privateKey, " +
"createdAt=$createdAt, " +
"keyId='$keyId', " +
"followers=$followers, " +
"following=$following, " +
"instance=$instance, " +
"locked=$locked, " +
"followersCount=$followersCount, " +
"followingCount=$followingCount, " +
"postsCount=$postsCount, " +
"lastPostDate=$lastPostDate, " +
"emojis=$emojis" +
")"
}
}

View File

@ -0,0 +1,13 @@
package dev.usbharu.hideout.core.domain.model.actor
import org.junit.jupiter.api.Test
import utils.UserBuilder
class ActorTest {
@Test
fun validator() {
org.junit.jupiter.api.assertThrows<IllegalArgumentException> {
UserBuilder.localUserOf(name = "うんこ")
}
}
}

View File

@ -25,6 +25,7 @@ import dev.usbharu.hideout.core.domain.model.actor.Actor
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter
import jakarta.validation.Validation
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Test
@ -37,7 +38,11 @@ import kotlin.test.assertEquals
import kotlin.test.assertNull
class ActorServiceTest {
val actorBuilder = Actor.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
val actorBuilder = Actor.UserBuilder(
CharacterLimit(),
ApplicationConfig(URL("https://example.com")),
Validation.buildDefaultValidatorFactory().validator
)
val postBuilder = Post.PostBuilder(CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()))
@Test
fun `createLocalUser ローカルユーザーを作成できる`() = runTest {

View File

@ -20,12 +20,16 @@ import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.config.CharacterLimit
import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.core.domain.model.actor.Actor
import jakarta.validation.Validation
import kotlinx.coroutines.runBlocking
import java.net.URL
import java.time.Instant
object UserBuilder {
private val actorBuilder = Actor.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
private val actorBuilder = Actor.UserBuilder(
CharacterLimit(), ApplicationConfig(URL("https://example.com")),
Validation.buildDefaultValidatorFactory().validator
)
private val idGenerator = TwitterSnowflakeIdGenerateService
@ -43,7 +47,7 @@ object UserBuilder {
createdAt: Instant = Instant.now(),
keyId: String = "https://$domain/users/$id#pubkey",
followers: String = "https://$domain/users/$id/followers",
following: String = "https://$domain/users/$id/following"
following: String = "https://$domain/users/$id/following",
): Actor {
return actorBuilder.of(
id = id,
@ -77,7 +81,7 @@ object UserBuilder {
createdAt: Instant = Instant.now(),
keyId: String = "https://$domain/$id#pubkey",
followers: String = "https://$domain/$id/followers",
following: String = "https://$domain/$id/following"
following: String = "https://$domain/$id/following",
): Actor {
return actorBuilder.of(
id = id,