From d87816d1eb38694efb4ce2b76021976d4f70e4df Mon Sep 17 00:00:00 2001 From: usbharu <64310155+usbharu@users.noreply.github.com> Date: Thu, 5 Oct 2023 19:26:10 +0900 Subject: [PATCH] =?UTF-8?q?feat:=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=82=92=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../usbharu/hideout/config/SecurityConfig.kt | 2 +- .../usbharu/hideout/config/SpringConfig.kt | 14 ++ .../domain/model/hideout/dto/PostCreateDto.kt | 3 +- .../domain/model/hideout/entity/Post.kt | 9 +- .../hideout/query/PostQueryServiceImpl.kt | 19 +- .../hideout/query/ReactionQueryServiceImpl.kt | 61 +++++++ .../query/mastodon/StatusQueryServiceImpl.kt | 162 +++++++++++------- .../hideout/repository/MediaRepositoryImpl.kt | 23 +-- .../hideout/repository/PostRepositoryImpl.kt | 34 +++- .../hideout/service/ap/APNoteService.kt | 1 + .../api/mastodon/StatusesApiService.kt | 33 +++- .../hideout/service/post/PostServiceImpl.kt | 3 +- src/main/resources/logback.xml | 1 + 13 files changed, 278 insertions(+), 87 deletions(-) create mode 100644 src/main/kotlin/dev/usbharu/hideout/query/ReactionQueryServiceImpl.kt diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt index 38424b81..e9ff022b 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SecurityConfig.kt @@ -35,7 +35,7 @@ import java.security.interfaces.RSAPrivateKey import java.security.interfaces.RSAPublicKey import java.util.* -@EnableWebSecurity(debug = true) +@EnableWebSecurity(debug = false) @Configuration class SecurityConfig { diff --git a/src/main/kotlin/dev/usbharu/hideout/config/SpringConfig.kt b/src/main/kotlin/dev/usbharu/hideout/config/SpringConfig.kt index 25ef84ed..cb66bde2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/config/SpringConfig.kt +++ b/src/main/kotlin/dev/usbharu/hideout/config/SpringConfig.kt @@ -2,9 +2,12 @@ package dev.usbharu.hideout.config import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.web.filter.CommonsRequestLoggingFilter import java.net.URL + @Configuration class SpringConfig { @@ -13,6 +16,17 @@ class SpringConfig { @Autowired lateinit var storageConfig: StorageConfig + + @Bean + fun requestLoggingFilter(): CommonsRequestLoggingFilter { + val loggingFilter = CommonsRequestLoggingFilter() + loggingFilter.setIncludeHeaders(true) + loggingFilter.setIncludeClientInfo(true) + loggingFilter.setIncludeQueryString(true) + loggingFilter.setIncludePayload(true) + loggingFilter.setMaxPayloadLength(64000) + return loggingFilter + } } @ConfigurationProperties("hideout") diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/PostCreateDto.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/PostCreateDto.kt index 1869da21..c9cf69de 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/PostCreateDto.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/PostCreateDto.kt @@ -8,5 +8,6 @@ data class PostCreateDto( val visibility: Visibility = Visibility.PUBLIC, val repostId: Long? = null, val repolyId: Long? = null, - val userId: Long + val userId: Long, + val mediaIds: List = emptyList() ) diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Post.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Post.kt index 3ed6ac53..afe45261 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Post.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Post.kt @@ -13,7 +13,8 @@ data class Post private constructor( val repostId: Long? = null, val replyId: Long? = null, val sensitive: Boolean = false, - val apId: String = url + val apId: String = url, + val mediaIds: List = emptyList() ) { companion object { @Suppress("FunctionMinLength", "LongParameterList") @@ -28,7 +29,8 @@ data class Post private constructor( repostId: Long? = null, replyId: Long? = null, sensitive: Boolean = false, - apId: String = url + apId: String = url, + mediaIds: List = emptyList() ): Post { val characterLimit = Config.configData.characterLimit @@ -67,7 +69,8 @@ data class Post private constructor( repostId = repostId, replyId = replyId, sensitive = sensitive, - apId = apId + apId = apId, + mediaIds = mediaIds ) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt index 545c2bfd..8e8ead0b 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/PostQueryServiceImpl.kt @@ -3,20 +3,29 @@ package dev.usbharu.hideout.query import dev.usbharu.hideout.domain.model.hideout.entity.Post import dev.usbharu.hideout.exception.FailedToGetResourcesException import dev.usbharu.hideout.repository.Posts +import dev.usbharu.hideout.repository.PostsMedia import dev.usbharu.hideout.repository.toPost import dev.usbharu.hideout.util.singleOr +import org.jetbrains.exposed.sql.innerJoin import org.jetbrains.exposed.sql.select import org.springframework.stereotype.Repository @Repository class PostQueryServiceImpl : PostQueryService { override suspend fun findById(id: Long): Post = - Posts.select { Posts.id eq id } + Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + .select { Posts.id eq id } .singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }.toPost() - override suspend fun findByUrl(url: String): Post = Posts.select { Posts.url eq url } - .singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }.toPost() + override suspend fun findByUrl(url: String): Post = + Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + .select { Posts.url eq url } + .toPost() + .singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) } - override suspend fun findByApId(string: String): Post = Posts.select { Posts.apId eq string } - .singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) }.toPost() + override suspend fun findByApId(string: String): Post = + Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + .select { Posts.apId eq string } + .toPost() + .singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/query/ReactionQueryServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/query/ReactionQueryServiceImpl.kt new file mode 100644 index 00000000..4d9897d9 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/query/ReactionQueryServiceImpl.kt @@ -0,0 +1,61 @@ +package dev.usbharu.hideout.query + +import dev.usbharu.hideout.domain.model.hideout.dto.Account +import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse +import dev.usbharu.hideout.domain.model.hideout.entity.Reaction +import dev.usbharu.hideout.exception.FailedToGetResourcesException +import dev.usbharu.hideout.repository.Reactions +import dev.usbharu.hideout.repository.Users +import dev.usbharu.hideout.repository.toReaction +import dev.usbharu.hideout.util.singleOr +import org.jetbrains.exposed.sql.* +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.springframework.stereotype.Repository + +@Repository +class ReactionQueryServiceImpl : ReactionQueryService { + override suspend fun findByPostId(postId: Long, userId: Long?): List { + return Reactions.select { + Reactions.postId.eq(postId) + }.map { it.toReaction() } + } + + @Suppress("FunctionMaxLength") + override suspend fun findByPostIdAndUserIdAndEmojiId(postId: Long, userId: Long, emojiId: Long): Reaction { + return Reactions + .select { + Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and( + Reactions.emojiId.eq(emojiId) + ) + } + .singleOr { + FailedToGetResourcesException( + "postId: $postId,userId: $userId,emojiId: $emojiId is duplicate or does not exist.", + it + ) + } + .toReaction() + } + + override suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean { + return Reactions.select { + Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and( + Reactions.emojiId.eq(emojiId) + ) + }.empty().not() + } + + override suspend fun deleteByPostIdAndUserId(postId: Long, userId: Long) { + Reactions.deleteWhere { Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)) } + } + + override suspend fun findByPostIdWithUsers(postId: Long, userId: Long?): List { + return Reactions + .leftJoin(Users, onColumn = { Reactions.userId }, otherColumn = { id }) + .select { Reactions.postId.eq(postId) } + .groupBy { _: ResultRow -> ReactionResponse("❤", true, "", emptyList()) } + .map { entry: Map.Entry> -> + entry.key.copy(accounts = entry.value.map { Account(it[Users.screenName], "", it[Users.url]) }) + } + } +} 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 ae9056f7..155b3bd5 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt @@ -1,9 +1,11 @@ package dev.usbharu.hideout.query.mastodon import dev.usbharu.hideout.domain.mastodon.model.generated.Account +import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment import dev.usbharu.hideout.domain.mastodon.model.generated.Status -import dev.usbharu.hideout.repository.Posts -import dev.usbharu.hideout.repository.Users +import dev.usbharu.hideout.domain.model.hideout.dto.FileType +import dev.usbharu.hideout.repository.* +import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.innerJoin import org.jetbrains.exposed.sql.select import org.springframework.stereotype.Repository @@ -12,67 +14,21 @@ import java.time.Instant @Repository class StatusQueryServiceImpl : StatusQueryService { @Suppress("LongMethod") - override suspend fun findByPostIds(ids: List): List { - val pairs = Posts.innerJoin(Users, onColumn = { userId }, otherColumn = { id }) + override suspend fun findByPostIds(ids: List): List = findByPostIdsWithMediaAttachments(ids) + + private suspend fun internalFindByPostIds(ids: List): List { + val pairs = Posts + .innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }) .select { Posts.id inList ids } .map { - Status( - id = it[Posts.id].toString(), - uri = it[Posts.apId], - createdAt = Instant.ofEpochMilli(it[Posts.createdAt]).toString(), - account = Account( - id = it[Users.id].toString(), - username = it[Users.name], - acct = "${it[Users.name]}@${it[Users.domain]}", - url = it[Users.url], - displayName = it[Users.screenName], - note = it[Users.description], - avatar = it[Users.url] + "/icon.jpg", - avatarStatic = it[Users.url] + "/icon.jpg", - header = it[Users.url] + "/header.jpg", - headerStatic = it[Users.url] + "/header.jpg", - locked = false, - fields = emptyList(), - emojis = emptyList(), - bot = false, - group = false, - discoverable = true, - createdAt = Instant.ofEpochMilli(it[Users.createdAt]).toString(), - lastStatusAt = Instant.ofEpochMilli(it[Users.createdAt]).toString(), - statusesCount = 0, - followersCount = 0, - followingCount = 0, - noindex = false, - moved = false, - suspendex = false, - limited = false - ), - content = it[Posts.text], - visibility = when (it[Posts.visibility]) { - 0 -> Status.Visibility.public - 1 -> Status.Visibility.unlisted - 2 -> Status.Visibility.private - 3 -> Status.Visibility.direct - else -> Status.Visibility.public - }, - sensitive = it[Posts.sensitive], - spoilerText = it[Posts.overview].orEmpty(), - mediaAttachments = emptyList(), - mentions = emptyList(), - tags = emptyList(), - emojis = emptyList(), - reblogsCount = 0, - favouritesCount = 0, - repliesCount = 0, - url = it[Posts.apId], - inReplyToId = it[Posts.replyId].toString(), - inReplyToAccountId = null, - language = null, - text = it[Posts.text], - editedAt = null - ) to it[Posts.repostId] + toStatus(it) to it[Posts.repostId] } + return resolveReplyAndRepost(pairs) + } + + + private fun resolveReplyAndRepost(pairs: List>): List { val statuses = pairs.map { it.first } return pairs .map { @@ -90,4 +46,92 @@ class StatusQueryServiceImpl : StatusQueryService { } } } + + 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 }) + .select { Posts.id inList ids } + .groupBy { it[Posts.id] } + .map { it.value } + .map { + toStatus(it.first()).copy(mediaAttachments = it.map { + it.toMedia().let { + MediaAttachment( + it.id.toString(), + when (it.type) { + FileType.Image -> MediaAttachment.Type.image + FileType.Video -> MediaAttachment.Type.video + FileType.Audio -> MediaAttachment.Type.audio + FileType.Unknown -> MediaAttachment.Type.unknown + }, + it.url, + it.thumbnailUrl, + it.remoteUrl, + "", + it.blurHash, + it.url + ) + } + }) to it.first()[Posts.repostId] + } + return resolveReplyAndRepost(pairs) + } } + +private fun toStatus(it: ResultRow) = Status( + id = it[Posts.id].toString(), + uri = it[Posts.apId], + createdAt = Instant.ofEpochMilli(it[Posts.createdAt]).toString(), + account = Account( + id = it[Users.id].toString(), + username = it[Users.name], + acct = "${it[Users.name]}@${it[Users.domain]}", + url = it[Users.url], + displayName = it[Users.screenName], + note = it[Users.description], + avatar = it[Users.url] + "/icon.jpg", + avatarStatic = it[Users.url] + "/icon.jpg", + header = it[Users.url] + "/header.jpg", + headerStatic = it[Users.url] + "/header.jpg", + locked = false, + fields = emptyList(), + emojis = emptyList(), + bot = false, + group = false, + discoverable = true, + createdAt = Instant.ofEpochMilli(it[Users.createdAt]).toString(), + lastStatusAt = Instant.ofEpochMilli(it[Users.createdAt]).toString(), + statusesCount = 0, + followersCount = 0, + followingCount = 0, + noindex = false, + moved = false, + suspendex = false, + limited = false + ), + content = it[Posts.text], + visibility = when (it[Posts.visibility]) { + 0 -> Status.Visibility.public + 1 -> Status.Visibility.unlisted + 2 -> Status.Visibility.private + 3 -> Status.Visibility.direct + else -> Status.Visibility.public + }, + sensitive = it[Posts.sensitive], + spoilerText = it[Posts.overview].orEmpty(), + mediaAttachments = emptyList(), + mentions = emptyList(), + tags = emptyList(), + emojis = emptyList(), + reblogsCount = 0, + favouritesCount = 0, + repliesCount = 0, + url = it[Posts.apId], + inReplyToId = it[Posts.replyId].toString(), + inReplyToAccountId = null, + language = null, + text = it[Posts.text], + editedAt = null +) diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt index 610d3e5a..cfcae2c4 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/MediaRepositoryImpl.kt @@ -55,18 +55,18 @@ class MediaRepositoryImpl(private val idGenerateService: IdGenerateService) : Me Media.id eq id } } +} - fun ResultRow.toMedia(): EntityMedia { - return EntityMedia( - id = this[Media.id], - name = this[Media.name], - url = this[Media.url], - remoteUrl = this[Media.remoteUrl], - thumbnailUrl = this[Media.thumbnailUrl], - type = FileType.values().first { it.ordinal == this[Media.type] }, - blurHash = this[Media.blurhash], - ) - } +fun ResultRow.toMedia(): EntityMedia { + return EntityMedia( + id = this[Media.id], + name = this[Media.name], + url = this[Media.url], + remoteUrl = this[Media.remoteUrl], + thumbnailUrl = this[Media.thumbnailUrl], + type = FileType.values().first { it.ordinal == this[Media.type] }, + blurHash = this[Media.blurhash], + ) } object Media : Table("media") { @@ -77,4 +77,5 @@ object Media : Table("media") { val thumbnailUrl = varchar("thumbnail_url", 255).nullable() val type = integer("type") val blurhash = varchar("blurhash", 255).nullable() + override val primaryKey = PrimaryKey(id) } diff --git a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt index 3bafd654..f95d56c6 100644 --- a/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/repository/PostRepositoryImpl.kt @@ -29,7 +29,18 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos it[sensitive] = post.sensitive it[apId] = post.apId } + PostsMedia.batchInsert(post.mediaIds) { + this[PostsMedia.postId] = post.id + this[PostsMedia.mediaId] = it + } } else { + PostsMedia.deleteWhere { + PostsMedia.postId eq post.id + } + PostsMedia.batchInsert(post.mediaIds) { + this[PostsMedia.postId] = post.id + this[PostsMedia.mediaId] = it + } Posts.update({ Posts.id eq post.id }) { it[userId] = post.userId it[overview] = post.overview @@ -46,8 +57,12 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos return post } - override suspend fun findById(id: Long): Post = Posts.select { Posts.id eq id }.singleOrNull()?.toPost() - ?: throw FailedToGetResourcesException("id: $id was not found.") + override suspend fun findById(id: Long): Post = + Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId }) + .select { Posts.id eq id } + .toPost() + .singleOrNull() + ?: throw FailedToGetResourcesException("id: $id was not found.") override suspend fun delete(id: Long) { Posts.deleteWhere { Posts.id eq id } @@ -69,6 +84,13 @@ object Posts : Table() { override val primaryKey: PrimaryKey = PrimaryKey(id) } +object PostsMedia : Table() { + val postId = long("post_id").references(Posts.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE) + val mediaId = long("media_id").references(Media.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE) + override val primaryKey = PrimaryKey(postId, mediaId) +} + + fun ResultRow.toPost(): Post { return Post.of( id = this[Posts.id], @@ -81,6 +103,12 @@ fun ResultRow.toPost(): Post { repostId = this[Posts.repostId], replyId = this[Posts.replyId], sensitive = this[Posts.sensitive], - apId = this[Posts.apId] + apId = this[Posts.apId], ) } + +fun Query.toPost(): List { + return this.groupBy { it[Posts.id] } + .map { it.value } + .map { it.first().toPost().copy(mediaIds = it.map { it[PostsMedia.mediaId] }) } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt index bc1958ea..8c365ba1 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/ap/APNoteService.kt @@ -168,6 +168,7 @@ class APNoteServiceImpl( postQueryService.findByUrl(it) } + // TODO: リモートのメディア処理を追加 postService.createRemote( Post.of( id = postRepository.generateId(), diff --git a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt index bebaa59a..20236eef 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/api/mastodon/StatusesApiService.kt @@ -1,12 +1,15 @@ package dev.usbharu.hideout.service.api.mastodon +import dev.usbharu.hideout.domain.mastodon.model.generated.MediaAttachment import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.StatusesRequest +import dev.usbharu.hideout.domain.model.hideout.dto.FileType import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto import dev.usbharu.hideout.domain.model.hideout.entity.Visibility import dev.usbharu.hideout.exception.FailedToGetResourcesException import dev.usbharu.hideout.query.PostQueryService import dev.usbharu.hideout.query.UserQueryService +import dev.usbharu.hideout.repository.MediaRepository import dev.usbharu.hideout.service.core.Transaction import dev.usbharu.hideout.service.mastodon.AccountService import dev.usbharu.hideout.service.post.PostService @@ -24,11 +27,13 @@ class StatsesApiServiceImpl( private val accountService: AccountService, private val postQueryService: PostQueryService, private val userQueryService: UserQueryService, + private val mediaRepository: MediaRepository, private val transaction: Transaction ) : StatusesApiService { @Suppress("LongMethod") override suspend fun postStatus(statusesRequest: StatusesRequest, userId: Long): Status = transaction.transaction { + println("Post status media ids " + statusesRequest.mediaIds) val visibility = when (statusesRequest.visibility) { StatusesRequest.Visibility.public -> Visibility.PUBLIC StatusesRequest.Visibility.unlisted -> Visibility.UNLISTED @@ -43,7 +48,8 @@ class StatsesApiServiceImpl( overview = statusesRequest.spoilerText, visibility = visibility, repolyId = statusesRequest.inReplyToId?.toLongOrNull(), - userId = userId + userId = userId, + mediaIds = statusesRequest.mediaIds.orEmpty().map { it.toLong() } ) ) val account = accountService.findById(userId) @@ -66,6 +72,27 @@ class StatsesApiServiceImpl( null } + // TODO: n+1解消 + val mediaAttachment = post.mediaIds.map { mediaId -> + mediaRepository.findById(mediaId) + }.map { + MediaAttachment( + it.id.toString(), + when (it.type) { + FileType.Image -> MediaAttachment.Type.image + FileType.Video -> MediaAttachment.Type.video + FileType.Audio -> MediaAttachment.Type.audio + FileType.Unknown -> MediaAttachment.Type.unknown + }, + it.url, + it.thumbnailUrl, + it.remoteUrl, + "", + it.blurHash, + it.url + ) + } + Status( id = post.id.toString(), uri = post.apId, @@ -75,7 +102,7 @@ class StatsesApiServiceImpl( visibility = postVisibility, sensitive = post.sensitive, spoilerText = post.overview.orEmpty(), - mediaAttachments = emptyList(), + mediaAttachments = mediaAttachment, mentions = emptyList(), tags = emptyList(), emojis = emptyList(), @@ -87,7 +114,7 @@ class StatsesApiServiceImpl( inReplyToAccountId = replyUser?.toString(), language = null, text = post.text, - editedAt = null + editedAt = null, ) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt index 755e5bb7..dbf30d9c 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/PostServiceImpl.kt @@ -44,7 +44,8 @@ class PostServiceImpl( text = post.text, createdAt = Instant.now().toEpochMilli(), visibility = post.visibility, - url = "${user.url}/posts/$id" + url = "${user.url}/posts/$id", + mediaIds = post.mediaIds ) return internalCreate(createPost, isLocal) } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 1736f642..1b8d5251 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -13,4 +13,5 @@ +