From 12ffbd7c510fdad92cb0dbabfe585123605147df Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:20:37 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Post=E3=81=AE=E3=82=A4=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=83=B3=E3=82=B9=E5=8C=96=E6=99=82=E3=81=AB?= =?UTF-8?q?=E3=83=81=E3=82=A7=E3=83=83=E3=82=AF=E3=81=99=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hideout/core/domain/model/actor/Actor.kt | 1 - .../hideout/core/domain/model/post/Post.kt | 43 ++++++++++++++++--- .../objects/note/APNoteServiceImplTest.kt | 23 ++++------ .../core/service/post/PostServiceImplTest.kt | 3 +- .../core/service/user/ActorServiceTest.kt | 4 -- src/test/kotlin/utils/PostBuilder.kt | 9 +++- 6 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt index 5d93dd8a..1bfb4905 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/actor/Actor.kt @@ -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, diff --git a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt index b4ceac6a..881f6ca3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/domain/model/post/Post.kt @@ -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 = emptyList(), val delted: Boolean = false, - val emojiIds: List = emptyList() + val emojiIds: List = 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") diff --git a/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt index cda0d284..b5301461 100644 --- a/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/APNoteServiceImplTest.kt @@ -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 { apNoteServiceImpl.fetchNote(url) } diff --git a/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt index 0c5a43a4..80cbb571 100644 --- a/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/core/service/post/PostServiceImplTest.kt @@ -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 diff --git a/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt b/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt index b0d75293..c44479cc 100644 --- a/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/core/service/user/ActorServiceTest.kt @@ -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 { diff --git a/src/test/kotlin/utils/PostBuilder.kt b/src/test/kotlin/utils/PostBuilder.kt index ef3cd173..4ddd2e89 100644 --- a/src/test/kotlin/utils/PostBuilder.kt +++ b/src/test/kotlin/utils/PostBuilder.kt @@ -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,