From 875650c2c0d86c382efe4a781ef7343d341bb15d Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Mon, 13 Nov 2023 15:04:11 +0900 Subject: [PATCH] =?UTF-8?q?test:=20=E3=83=A1=E3=83=87=E3=82=A3=E3=82=A2?= =?UTF-8?q?=E4=BB=98=E3=81=8D=E6=8A=95=E7=A8=BF=E3=81=A8=E3=83=AA=E3=83=97?= =?UTF-8?q?=E3=83=A9=E3=82=A4=E3=81=AE=E6=8A=95=E7=A8=BF=E3=81=AE=E3=83=86?= =?UTF-8?q?=E3=82=B9=E3=83=88=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/activitypub/note/NoteTest.kt | 31 +++++++++++++++++-- ...稿はattachmentにDocumentとして画像が存在する.sql | 22 +++++++++++++ ...イになっている投稿はinReplyToが存在する.sql | 16 ++++++++++ .../objects/note/NoteApApiServiceImpl.kt | 8 ++++- .../exposedrepository/PostRepositoryImpl.kt | 7 +++-- 5 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 src/intTest/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql create mode 100644 src/intTest/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql diff --git a/src/intTest/kotlin/activitypub/note/NoteTest.kt b/src/intTest/kotlin/activitypub/note/NoteTest.kt index e0433c9f..a559ca66 100644 --- a/src/intTest/kotlin/activitypub/note/NoteTest.kt +++ b/src/intTest/kotlin/activitypub/note/NoteTest.kt @@ -17,6 +17,7 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.transaction.annotation.Transactional import org.springframework.web.context.WebApplicationContext import util.WithHttpSignature +import util.WithMockHttpSignature @SpringBootTest(classes = [SpringApplication::class]) @AutoConfigureMockMvc @@ -143,12 +144,38 @@ class NoteTest { } @Test + @Sql("/sql/note/リプライになっている投稿はinReplyToが存在する.sql") + @WithMockHttpSignature fun リプライになっている投稿はinReplyToが存在する() { - + mockMvc + .get("/users/test-user10/posts/1241") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { content { contentType("application/activity+json") } } + .andExpect { jsonPath("\$.type") { value("Note") } } + .andExpect { jsonPath("\$.inReplyTo") { value("https://example.com/users/test-user10/posts/1240") } } } @Test + @Sql("/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql") + @WithMockHttpSignature fun メディア付き投稿はattachmentにDocumentとして画像が存在する() { - + mockMvc + .get("/users/test-user10/posts/1242") { + accept(MediaType("application", "activity+json")) + } + .asyncDispatch() + .andDo { print() } + .andExpect { status { isOk() } } + .andExpect { content { contentType("application/activity+json") } } + .andExpect { jsonPath("\$.type") { value("Note") } } + .andExpect { jsonPath("\$.attachment") { isArray() } } + .andExpect { jsonPath("\$.attachment[0].type") { value("Document") } } + .andExpect { jsonPath("\$.attachment[0].url") { value("https://example.com/media/test-media.png") } } + .andExpect { jsonPath("\$.attachment[1].type") { value("Document") } } + .andExpect { jsonPath("\$.attachment[1].url") { value("https://example.com/media/test-media2.png") } } } } diff --git a/src/intTest/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql b/src/intTest/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql new file mode 100644 index 00000000..9da287af --- /dev/null +++ b/src/intTest/resources/sql/note/メディア付き投稿はattachmentにDocumentとして画像が存在する.sql @@ -0,0 +1,22 @@ +insert into "USERS" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, PASSWORD, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, + CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS) +VALUES (11, 'test-user11', 'example.com', 'Im test-user11.', 'THis account is test-user11.', + '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', + 'https://example.com/users/test-user11/inbox', + 'https://example.com/users/test-user11/outbox', 'https://example.com/users/test-user11', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user11#pubkey', 'https://example.com/users/test-user11/following', + 'https://example.com/users/test-user11/followers'); + +insert into POSTS (ID, "userId", OVERVIEW, TEXT, "createdAt", VISIBILITY, URL, "repostId", "replyId", SENSITIVE, AP_ID) +VALUES (1242, 11, null, 'test post', 12345680, 0, 'https://example.com/users/test-user11/posts/1242', null, null, false, + 'https://example.com/users/test-user11/posts/1242'); + +insert into MEDIA (ID, NAME, URL, REMOTE_URL, THUMBNAIL_URL, TYPE, BLURHASH) +VALUES (1, 'test-media', 'https://example.com/media/test-media.png', null, null, 0, null), + (2, 'test-media2', 'https://example.com/media/test-media2.png', null, null, 0, null); + +insert into POSTSMEDIA(POST_ID, MEDIA_ID) +VALUES (1242, 1), + (1242, 2); diff --git a/src/intTest/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql b/src/intTest/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql new file mode 100644 index 00000000..cf6f842f --- /dev/null +++ b/src/intTest/resources/sql/note/リプライになっている投稿はinReplyToが存在する.sql @@ -0,0 +1,16 @@ +insert into "USERS" (ID, NAME, DOMAIN, SCREEN_NAME, DESCRIPTION, PASSWORD, INBOX, OUTBOX, URL, PUBLIC_KEY, PRIVATE_KEY, + CREATED_AT, KEY_ID, FOLLOWING, FOLLOWERS) +VALUES (10, 'test-user10', 'example.com', 'Im test-user10.', 'THis account is test-user10.', + '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8', + 'https://example.com/users/test-user10/inbox', + 'https://example.com/users/test-user10/outbox', 'https://example.com/users/test-user10', + '-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----', + '-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----', 12345678, + 'https://example.com/users/test-user10#pubkey', 'https://example.com/users/test-user10/following', + 'https://example.com/users/test-user10/followers'); + +insert into POSTS (ID, "userId", OVERVIEW, TEXT, "createdAt", VISIBILITY, URL, "repostId", "replyId", SENSITIVE, AP_ID) +VALUES (1240, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1240', null, null, false, + 'https://example.com/users/test-user10/posts/1240'), + (1241, 10, null, 'test post', 12345680, 0, 'https://example.com/users/test-user10/posts/1241', null, 1240, false, + 'https://example.com/users/test-user10/posts/1241'); diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt index ec92c515..547befbf 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/objects/note/NoteApApiServiceImpl.kt @@ -6,6 +6,7 @@ import dev.usbharu.hideout.application.external.Transaction import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException import dev.usbharu.hideout.core.domain.model.post.Visibility import dev.usbharu.hideout.core.query.FollowerQueryService +import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @Service @@ -17,7 +18,8 @@ class NoteApApiServiceImpl( override suspend fun getNote(postId: Long, userId: Long?): Note? = transaction.transaction { val findById = try { noteQueryService.findById(postId) - } catch (_: FailedToGetResourcesException) { + } catch (e: FailedToGetResourcesException) { + logger.warn("Note not found.", e) return@transaction null } when (findById.second.visibility) { @@ -39,4 +41,8 @@ class NoteApApiServiceImpl( Visibility.DIRECT -> return@transaction null } } + + companion object { + private val logger = LoggerFactory.getLogger(NoteApApiServiceImpl::class.java) + } } diff --git a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/PostRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/PostRepositoryImpl.kt index 39ddff21..c219f52c 100644 --- a/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/PostRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/PostRepositoryImpl.kt @@ -5,6 +5,7 @@ import dev.usbharu.hideout.application.service.id.IdGenerateService import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException import dev.usbharu.hideout.core.domain.model.post.Post import dev.usbharu.hideout.core.domain.model.post.PostRepository +import dev.usbharu.hideout.util.singleOr import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq import org.springframework.stereotype.Repository @@ -67,11 +68,11 @@ class PostRepositoryImpl( } override suspend fun findById(id: Long): Post = - Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { postId }) + Posts.leftJoin(PostsMedia) .select { Posts.id eq id } .let(postQueryMapper::map) - .singleOrNull() - ?: throw FailedToGetResourcesException("id: $id was not found.") + .singleOr { FailedToGetResourcesException("id: $id was not found.", it) } + override suspend fun delete(id: Long) { Posts.deleteWhere { Posts.id eq id }