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

This commit is contained in:
usbharu 2024-02-26 16:20:37 +09:00
parent 7719863b80
commit 12ffbd7c51
6 changed files with 56 additions and 27 deletions

View File

@ -33,7 +33,6 @@ data class Actor private constructor(
@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,

View File

@ -18,31 +18,40 @@ package dev.usbharu.hideout.core.domain.model.post
import dev.usbharu.hideout.application.config.CharacterLimit
import dev.usbharu.hideout.core.service.post.PostContentFormatter
import jakarta.validation.Validator
import jakarta.validation.constraints.Positive
import org.hibernate.validator.constraints.URL
import org.springframework.stereotype.Component
import java.time.Instant
data class Post private constructor(
@get:Positive
val id: Long,
@get:Positive
val actorId: Long,
val overview: String? = null,
val content: String,
val text: String,
@get:Positive
val createdAt: Long,
val visibility: Visibility,
@get:URL
val url: String,
val repostId: Long? = null,
val replyId: Long? = null,
val sensitive: Boolean = false,
@get:URL
val apId: String = url,
val mediaIds: List<Long> = emptyList(),
val delted: Boolean = false,
val emojiIds: List<Long> = emptyList()
val emojiIds: List<Long> = emptyList(),
) {
@Component
class PostBuilder(
private val characterLimit: CharacterLimit,
private val postContentFormatter: PostContentFormatter
private val postContentFormatter: PostContentFormatter,
private val validator: Validator,
) {
@Suppress("FunctionMinLength", "LongParameterList")
fun of(
@ -86,7 +95,7 @@ data class Post private constructor(
require((repostId ?: 0) >= 0) { "repostId must be greater then or equal to 0." }
require((replyId ?: 0) >= 0) { "replyId must be greater then or equal to 0." }
return Post(
val post = Post(
id = id,
actorId = actorId,
overview = limitedOverview,
@ -103,6 +112,14 @@ data class Post private constructor(
delted = false,
emojiIds = emojiIds
)
val validate = validator.validate(post)
for (constraintViolation in validate) {
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
}
return post
}
@Suppress("LongParameterList")
@ -126,7 +143,7 @@ data class Post private constructor(
require(actorId >= 0) { "actorId must be greater than or equal to 0." }
return Post(
val post = Post(
id = id,
actorId = actorId,
overview = null,
@ -143,6 +160,14 @@ data class Post private constructor(
delted = false,
emojiIds = emptyList()
)
val validate = validator.validate(post)
for (constraintViolation in validate) {
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
}
return post
}
@Suppress("LongParameterList")
@ -193,7 +218,7 @@ data class Post private constructor(
require((replyId ?: 0) >= 0) { "replyId must be greater then or equal to 0." }
return Post(
val post = Post(
id = id,
actorId = actorId,
overview = limitedOverview,
@ -210,6 +235,14 @@ data class Post private constructor(
delted = false,
emojiIds = emojiIds
)
val validate = validator.validate(post)
for (constraintViolation in validate) {
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
}
return post
}
@Suppress("LongParameterList")

View File

@ -45,6 +45,7 @@ import io.ktor.http.*
import io.ktor.http.content.*
import io.ktor.util.*
import io.ktor.util.date.*
import jakarta.validation.Validation
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
@ -60,7 +61,10 @@ import java.time.Instant
class APNoteServiceImplTest {
val postBuilder = Post.PostBuilder(CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()))
val postBuilder = Post.PostBuilder(
CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()),
Validation.buildDefaultValidatorFactory().validator
)
@Test
fun `fetchNote(String,String) ートが既に存在する場合はDBから取得したものを返す`() = runTest {
@ -89,10 +93,7 @@ class APNoteServiceImplTest {
apUserService = mock(),
postService = mock(),
apResourceResolveService = mock(),
postBuilder = Post.PostBuilder(
CharacterLimit(),
DefaultPostContentFormatter(HtmlSanitizeConfig().policy())
),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
@ -163,10 +164,7 @@ class APNoteServiceImplTest {
apUserService = apUserService,
postService = mock(),
apResourceResolveService = apResourceResolveService,
postBuilder = Post.PostBuilder(
CharacterLimit(),
DefaultPostContentFormatter(HtmlSanitizeConfig().policy())
),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock { },
@ -216,14 +214,11 @@ class APNoteServiceImplTest {
apUserService = mock(),
postService = mock(),
apResourceResolveService = apResourceResolveService,
postBuilder = Post.PostBuilder(
CharacterLimit(),
DefaultPostContentFormatter(HtmlSanitizeConfig().policy())
),
postBuilder = postBuilder,
noteQueryService = noteQueryService,
mock(),
mock(),
mock { }
mock { }
)
assertThrows<FailedToGetActivityPubResourceException> { apNoteServiceImpl.fetchNote(url) }

View File

@ -26,6 +26,7 @@ import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
import dev.usbharu.hideout.core.service.timeline.TimelineService
import jakarta.validation.Validation
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
@ -56,7 +57,7 @@ class PostServiceImplTest {
private var postBuilder: Post.PostBuilder = Post.PostBuilder(
CharacterLimit(), DefaultPostContentFormatter(
HtmlSanitizeConfig().policy()
)
), Validation.buildDefaultValidatorFactory().validator
)
@Mock

View File

@ -20,11 +20,8 @@ package dev.usbharu.hideout.core.service.user
import dev.usbharu.hideout.application.config.ApplicationConfig
import dev.usbharu.hideout.application.config.CharacterLimit
import dev.usbharu.hideout.application.config.HtmlSanitizeConfig
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
@ -43,7 +40,6 @@ class ActorServiceTest {
ApplicationConfig(URL("https://example.com")),
Validation.buildDefaultValidatorFactory().validator
)
val postBuilder = Post.PostBuilder(CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()))
@Test
fun `createLocalUser ローカルユーザーを作成できる`() = runTest {

View File

@ -22,13 +22,18 @@ import dev.usbharu.hideout.application.service.id.TwitterSnowflakeIdGenerateServ
import dev.usbharu.hideout.core.domain.model.post.Post
import dev.usbharu.hideout.core.domain.model.post.Visibility
import dev.usbharu.hideout.core.service.post.DefaultPostContentFormatter
import jakarta.validation.Validation
import kotlinx.coroutines.runBlocking
import java.time.Instant
object PostBuilder {
private val postBuilder =
Post.PostBuilder(CharacterLimit(), DefaultPostContentFormatter(HtmlSanitizeConfig().policy()))
Post.PostBuilder(
CharacterLimit(),
DefaultPostContentFormatter(HtmlSanitizeConfig().policy()),
Validation.buildDefaultValidatorFactory().validator
)
private val idGenerator = TwitterSnowflakeIdGenerateService
@ -39,7 +44,7 @@ object PostBuilder {
text: String = "Hello World",
createdAt: Long = Instant.now().toEpochMilli(),
visibility: Visibility = Visibility.PUBLIC,
url: String = "https://example.com/users/$userId/posts/$id"
url: String = "https://example.com/users/$userId/posts/$id",
): Post {
return postBuilder.of(
id = id,