diff --git a/detekt.yml b/detekt.yml index c1b54432..6059d595 100644 --- a/detekt.yml +++ b/detekt.yml @@ -5,6 +5,7 @@ build: MagicNumber: 0 InjectDispatcher: 0 EnumEntryNameCase: 0 + ReplaceSafeCallChainWithRun: 0 style: ClassOrdering: diff --git a/src/main/kotlin/dev/usbharu/hideout/controller/NoteApControllerImpl.kt b/src/main/kotlin/dev/usbharu/hideout/controller/NoteApControllerImpl.kt index 36e27859..0c330524 100644 --- a/src/main/kotlin/dev/usbharu/hideout/controller/NoteApControllerImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/controller/NoteApControllerImpl.kt @@ -17,7 +17,9 @@ class NoteApControllerImpl(private val noteApApiService: NoteApApiService) : Not @CurrentSecurityContext context: SecurityContext ): ResponseEntity { val userId = - if (context.authentication is PreAuthenticatedAuthenticationToken && context.authentication.details is HttpSignatureUser) { + if (context.authentication is PreAuthenticatedAuthenticationToken && + context.authentication.details is HttpSignatureUser + ) { (context.authentication.details as HttpSignatureUser).id } else { null diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/StatusQuery.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/StatusQuery.kt new file mode 100644 index 00000000..cba8477b --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/dto/StatusQuery.kt @@ -0,0 +1,8 @@ +package dev.usbharu.hideout.domain.model.hideout.dto + +data class StatusQuery( + val postId: Long, + val replyId: Long?, + val repostId: Long?, + val mediaIds: List +) diff --git a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt index e4aeabb6..73568b90 100644 --- a/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt +++ b/src/main/kotlin/dev/usbharu/hideout/domain/model/hideout/entity/Timeline.kt @@ -16,5 +16,7 @@ data class Timeline( val repostId: Long?, val visibility: Visibility, val sensitive: Boolean, - val isLocal: Boolean + val isLocal: Boolean, + val isPureRepost: Boolean = false, + val mediaIds: List = emptyList() ) diff --git a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryService.kt b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryService.kt index a4ed048c..fbceccc7 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryService.kt @@ -1,7 +1,9 @@ package dev.usbharu.hideout.query.mastodon import dev.usbharu.hideout.domain.mastodon.model.generated.Status +import dev.usbharu.hideout.domain.model.hideout.dto.StatusQuery interface StatusQueryService { suspend fun findByPostIds(ids: List): List + suspend fun findByPostIdsWithMediaIds(statusQueries: List): List } 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 d5a5b5c2..cb058663 100644 --- a/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt +++ b/src/main/kotlin/dev/usbharu/hideout/query/mastodon/StatusQueryServiceImpl.kt @@ -4,6 +4,7 @@ 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.domain.model.hideout.dto.FileType +import dev.usbharu.hideout.domain.model.hideout.dto.StatusQuery import dev.usbharu.hideout.repository.* import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.innerJoin @@ -16,6 +17,46 @@ class StatusQueryServiceImpl : StatusQueryService { @Suppress("LongMethod") override suspend fun findByPostIds(ids: List): List = findByPostIdsWithMediaAttachments(ids) + override suspend fun findByPostIdsWithMediaIds(statusQueries: List): List { + val postIdSet = mutableSetOf() + postIdSet.addAll(statusQueries.flatMap { listOfNotNull(it.postId, it.replyId, it.repostId) }) + val mediaIdSet = mutableSetOf() + mediaIdSet.addAll(statusQueries.flatMap { it.mediaIds }) + val postMap = Posts + .leftJoin(Users) + .select { Posts.id inList postIdSet } + .associate { it[Posts.id] to toStatus(it) } + val mediaMap = Media.select { Media.id inList mediaIdSet } + .associate { + it[Media.id] to it.toMedia().let { + MediaAttachment( + id = it.id.toString(), + type = when (it.type) { + FileType.Image -> MediaAttachment.Type.image + FileType.Video -> MediaAttachment.Type.video + FileType.Audio -> MediaAttachment.Type.audio + FileType.Unknown -> MediaAttachment.Type.unknown + }, + url = it.url, + previewUrl = it.thumbnailUrl, + remoteUrl = it.remoteUrl, + description = "", + blurhash = it.blurHash, + textUrl = it.url + ) + } + } + + return statusQueries.mapNotNull { + postMap[it.postId]?.copy( + inReplyToId = it.replyId?.toString(), + inReplyToAccountId = postMap[it.replyId]?.account?.id, + reblog = postMap[it.repostId], + mediaAttachments = it.mediaIds.mapNotNull { mediaMap[it] } + ) + } + } + @Suppress("unused") private suspend fun internalFindByPostIds(ids: List): List { val pairs = Posts diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/MongoGenerateTimelineService.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/MongoGenerateTimelineService.kt index 0a677430..1a75c9b0 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/MongoGenerateTimelineService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/MongoGenerateTimelineService.kt @@ -1,6 +1,7 @@ package dev.usbharu.hideout.service.post import dev.usbharu.hideout.domain.mastodon.model.generated.Status +import dev.usbharu.hideout.domain.model.hideout.dto.StatusQuery import dev.usbharu.hideout.domain.model.hideout.entity.Timeline import dev.usbharu.hideout.query.mastodon.StatusQueryService import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty @@ -50,6 +51,15 @@ class MongoGenerateTimelineService( val timelines = mongoTemplate.find(query, Timeline::class.java) - return statusQueryService.findByPostIds(timelines.flatMap { setOfNotNull(it.postId, it.replyId, it.repostId) }) + return statusQueryService.findByPostIdsWithMediaIds( + timelines.map { + StatusQuery( + it.postId, + it.replyId, + it.repostId, + it.mediaIds + ) + } + ) } } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/post/TimelineService.kt b/src/main/kotlin/dev/usbharu/hideout/service/post/TimelineService.kt index 97f83a08..cdd3d94d 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/post/TimelineService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/post/TimelineService.kt @@ -33,7 +33,9 @@ class TimelineService( repostId = post.repostId, visibility = post.visibility, sensitive = post.sensitive, - isLocal = isLocal + isLocal = isLocal, + isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()), + mediaIds = post.mediaIds ) }.toMutableList() if (post.visibility == Visibility.PUBLIC) { @@ -49,7 +51,9 @@ class TimelineService( repostId = post.repostId, visibility = post.visibility, sensitive = post.sensitive, - isLocal = isLocal + isLocal = isLocal, + isPureRepost = post.repostId == null || (post.text.isBlank() && post.overview.isNullOrBlank()), + mediaIds = post.mediaIds ) ) } diff --git a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureFilter.kt b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureFilter.kt index 07c2b7b1..6a2444b8 100644 --- a/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureFilter.kt +++ b/src/main/kotlin/dev/usbharu/hideout/service/signature/HttpSignatureFilter.kt @@ -18,9 +18,9 @@ class HttpSignatureFilter(private val httpSignatureHeaderParser: SignatureHeader val signature = try { httpSignatureHeaderParser.parse(HttpHeaders(headers)) - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { return null - } catch (e: RuntimeException) { + } catch (_: RuntimeException) { return "" } return signature.keyId