diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt index e9ff022b..f87c4dfd 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt @@ -1,5 +1,6 @@ package dev.usbharu.hideout.config +import com.fasterxml.jackson.annotation.JsonInclude import com.nimbusds.jose.jwk.JWKSet import com.nimbusds.jose.jwk.RSAKey import com.nimbusds.jose.jwk.source.ImmutableJWKSet @@ -8,12 +9,16 @@ import com.nimbusds.jose.proc.SecurityContext import dev.usbharu.hideout.domain.model.UserDetailsImpl import dev.usbharu.hideout.util.RsaUtil import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer import org.springframework.boot.autoconfigure.security.servlet.PathRequest import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary import org.springframework.core.annotation.Order import org.springframework.http.HttpMethod +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.security.config.Customizer import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity @@ -35,6 +40,7 @@ import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey import java.util.* + @EnableWebSecurity(debug = false) @Configuration class SecurityConfig { @@ -155,6 +161,21 @@ class SecurityConfig { } } } + + @Bean + @Primary + fun jackson2ObjectMapperBuilderCustomizer(): Jackson2ObjectMapperBuilderCustomizer { + return Jackson2ObjectMapperBuilderCustomizer { + it.serializationInclusion(JsonInclude.Include.ALWAYS).serializers() + } + } + + @Bean + fun mappingJackson2HttpMessageConverter(): MappingJackson2HttpMessageConverter { + val builder = Jackson2ObjectMapperBuilder() + .serializationInclusion(JsonInclude.Include.NON_NULL) + return MappingJackson2HttpMessageConverter(builder.build()) + } } @ConfigurationProperties("hideout.security.jwt") diff --git a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt index 5fba667c..d5a5b5c2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt @@ -50,16 +50,16 @@ class StatusQueryServiceImpl : StatusQueryService { @Suppress("FunctionMaxLength") private suspend fun findByPostIdsWithMediaAttachments(ids: List): List { val pairs = Posts - .innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) - .innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }) - .innerJoin(Media, onColumn = { PostsMedia.mediaId }, otherColumn = { id }) + .leftJoin(PostsMedia) + .leftJoin(Users) + .leftJoin(Media) .select { Posts.id inList ids } .groupBy { it[Posts.id] } .map { it.value } .map { toStatus(it.first()).copy( - mediaAttachments = it.map { - it.toMedia().let { + mediaAttachments = it.mapNotNull { + it.toMediaOrNull()?.let { MediaAttachment( id = it.id.toString(), type = when (it.type) { @@ -132,7 +132,7 @@ private fun toStatus(it: ResultRow) = Status( favouritesCount = 0, repliesCount = 0, url = it[Posts.apId], - inReplyToId = it[Posts.replyId].toString(), + inReplyToId = it[Posts.replyId]?.toString(), inReplyToAccountId = null, language = null, text = it[Posts.text], diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt index cfcae2c4..6bbacbd3 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt @@ -69,6 +69,18 @@ fun ResultRow.toMedia(): EntityMedia { ) } +fun ResultRow.toMediaOrNull(): EntityMedia? { + return EntityMedia( + id = this.getOrNull(Media.id) ?: return null, + name = this.getOrNull(Media.name) ?: return null, + url = this.getOrNull(Media.url) ?: return null, + remoteUrl = this[Media.remoteUrl], + thumbnailUrl = this[Media.thumbnailUrl], + type = FileType.values().first { it.ordinal == this.getOrNull(Media.type) }, + blurHash = this[Media.blurhash], + ) +} + object Media : Table("media") { val id = long("id") val name = varchar("name", 255) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 143486fb..60814a17 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -16,6 +16,7 @@ spring: jackson: serialization: WRITE_DATES_AS_TIMESTAMPS: false + default-property-inclusion: always datasource: driver-class-name: org.h2.Driver url: "jdbc:h2:./test-dev2;MODE=POSTGRESQL"