mirror of https://github.com/usbharu/Hideout.git
feat: タイムラインにリアクションを表示するように
This commit is contained in:
parent
2b567bb1d5
commit
e42919ce3c
|
@ -29,9 +29,9 @@ sealed class Emoji {
|
|||
abstract fun id(): String
|
||||
override fun toString(): String {
|
||||
return "Emoji(" +
|
||||
"domain='$domain', " +
|
||||
"name='$name'" +
|
||||
")"
|
||||
"domain='$domain', " +
|
||||
"name='$name'" +
|
||||
")"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,10 @@ data class CustomEmoji(
|
|||
data class UnicodeEmoji(
|
||||
override val name: String
|
||||
) : Emoji() {
|
||||
override val domain: Domain = Domain("unicode.org")
|
||||
override val domain: Domain = Companion.domain
|
||||
override fun id(): String = name
|
||||
|
||||
companion object {
|
||||
val domain = Domain("unicode.org")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package dev.usbharu.hideout.core.domain.model.support.timelineobjectdetail
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
|
@ -29,7 +30,8 @@ data class TimelineObjectDetail(
|
|||
val isPureRepost: Boolean,
|
||||
val lastUpdateAt: Instant,
|
||||
val hasMediaInRepost: Boolean,
|
||||
val warnFilter: List<TimelineObjectWarnFilter>
|
||||
val warnFilter: List<TimelineObjectWarnFilter>,
|
||||
val reactionsList: List<Reactions>
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("LongParameterList")
|
||||
|
@ -48,7 +50,8 @@ data class TimelineObjectDetail(
|
|||
repostPostMedias: List<Media>?,
|
||||
repostPostActor: Actor?,
|
||||
repostPostActorIconMedia: Media?,
|
||||
warnFilter: List<TimelineObjectWarnFilter>
|
||||
warnFilter: List<TimelineObjectWarnFilter>,
|
||||
reactionsList: List<Reactions>
|
||||
): TimelineObjectDetail {
|
||||
return TimelineObjectDetail(
|
||||
id = timelineObject.id,
|
||||
|
@ -69,7 +72,8 @@ data class TimelineObjectDetail(
|
|||
isPureRepost = timelineObject.isPureRepost,
|
||||
lastUpdateAt = timelineObject.lastUpdatedAt,
|
||||
hasMediaInRepost = timelineObject.hasMediaInRepost,
|
||||
warnFilter = warnFilter
|
||||
warnFilter = warnFilter,
|
||||
reactionsList = reactionsList
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.emoji.UnicodeEmoji
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.CustomEmojis
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toCustomEmojiOrNull
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toReaction
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import org.jetbrains.exposed.sql.selectAll
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.net.URI
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Reactions as ExposedrepositoryReactions
|
||||
|
||||
@Repository
|
||||
|
@ -33,6 +35,35 @@ class ExposedReactionsQueryService : ReactionsQueryService, AbstractRepository()
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun findAllByPostIdIn(postIds: List<PostId>): List<Reactions> {
|
||||
return query {
|
||||
|
||||
val actorIdsQuery =
|
||||
ExposedrepositoryReactions.actorId.castTo<String>(VarCharColumnType()).groupConcat(",", true)
|
||||
|
||||
ExposedrepositoryReactions.leftJoin(CustomEmojis)
|
||||
.select(
|
||||
ExposedrepositoryReactions.postId,
|
||||
ExposedrepositoryReactions.postId.count(),
|
||||
ExposedrepositoryReactions.customEmojiId.max(),
|
||||
ExposedrepositoryReactions.unicodeEmoji.max(),
|
||||
actorIdsQuery
|
||||
)
|
||||
.where { ExposedrepositoryReactions.postId inList postIds.map { it.id } }
|
||||
.groupBy(ExposedrepositoryReactions.postId)
|
||||
.map {
|
||||
Reactions(
|
||||
it[ExposedrepositoryReactions.postId],
|
||||
it[ExposedrepositoryReactions.postId.count()].toInt(),
|
||||
it.getOrNull(CustomEmojis.name) ?: it[ExposedrepositoryReactions.unicodeEmoji],
|
||||
it.getOrNull(CustomEmojis.domain) ?: UnicodeEmoji.domain.domain,
|
||||
it.getOrNull(CustomEmojis.url)?.let { it1 -> URI.create(it1) },
|
||||
it[actorIdsQuery].split(",").mapNotNull { it.toLongOrNull() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
||||
|
@ -243,8 +244,8 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
|||
val actors =
|
||||
getActors(
|
||||
timelineObjectList.map { it.postActorId } +
|
||||
timelineObjectList.mapNotNull { it.repostActorId } +
|
||||
timelineObjectList.mapNotNull { it.replyActorId }
|
||||
timelineObjectList.mapNotNull { it.repostActorId } +
|
||||
timelineObjectList.mapNotNull { it.replyActorId }
|
||||
)
|
||||
|
||||
val postMap = posts.associate { post ->
|
||||
|
@ -253,9 +254,11 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
|||
|
||||
val mediaMap = getMedias(
|
||||
posts.flatMap { it.mediaIds } +
|
||||
actors.mapNotNull { it.value.icon }
|
||||
actors.mapNotNull { it.value.icon }
|
||||
)
|
||||
|
||||
val reactions = getReactions(posts.map { it.id })
|
||||
|
||||
return PaginationList(
|
||||
timelineObjectList.mapNotNull<TimelineObject, TimelineObjectDetail> {
|
||||
val timelineUserDetail = userDetails[it.userDetailId] ?: return@mapNotNull null
|
||||
|
@ -268,6 +271,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
|||
val repost = postMap[it.repostId]
|
||||
val repostMedias = repost?.post?.mediaIds?.mapNotNull { mediaId -> mediaMap[mediaId] }
|
||||
val repostActor = actors[it.repostActorId]
|
||||
val reactionsList = reactions[it.postId].orEmpty()
|
||||
TimelineObjectDetail.of(
|
||||
timelineObject = it,
|
||||
timelineUserDetail = timelineUserDetail,
|
||||
|
@ -288,7 +292,8 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
|||
filterResult.filter.id,
|
||||
filterResult.matchedKeyword
|
||||
)
|
||||
}
|
||||
},
|
||||
reactionsList = reactionsList
|
||||
)
|
||||
},
|
||||
timelineObjectList.lastOrNull()?.postId,
|
||||
|
@ -300,5 +305,7 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
|||
|
||||
protected abstract suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media>
|
||||
|
||||
protected abstract suspend fun getReactions(postIds: List<PostId>): Map<PostId, List<Reactions>>
|
||||
|
||||
protected abstract suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||
|
||||
import dev.usbharu.hideout.core.application.model.Reactions
|
||||
import dev.usbharu.hideout.core.config.DefaultTimelineStoreConfig
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||
|
@ -32,6 +33,7 @@ import dev.usbharu.hideout.core.domain.service.filter.FilterDomainService
|
|||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||
import dev.usbharu.hideout.core.external.timeline.ReadTimelineOption
|
||||
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Instant
|
||||
|
||||
|
@ -49,7 +51,8 @@ open class DefaultTimelineStore(
|
|||
private val userDetailRepository: UserDetailRepository,
|
||||
private val actorRepository: ActorRepository,
|
||||
private val mediaRepository: MediaRepository,
|
||||
private val postIPostReadAccessControl: IPostReadAccessControl
|
||||
private val postIPostReadAccessControl: IPostReadAccessControl,
|
||||
private val reactionsQueryService: ReactionsQueryService,
|
||||
) : AbstractTimelineStore(idGenerateService) {
|
||||
override suspend fun getTimelines(actorId: ActorId): List<Timeline> {
|
||||
return timelineRepository.findByIds(
|
||||
|
@ -157,6 +160,10 @@ open class DefaultTimelineStore(
|
|||
override suspend fun getMedias(mediaIds: List<MediaId>): Map<MediaId, Media> =
|
||||
mediaRepository.findByIds(mediaIds).associateBy { it.id }
|
||||
|
||||
override suspend fun getReactions(postIds: List<PostId>): Map<PostId, List<Reactions>> {
|
||||
return reactionsQueryService.findAllByPostIdIn(postIds).groupBy { PostId(it.postId) }
|
||||
}
|
||||
|
||||
override suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail> =
|
||||
userDetailRepository.findAllById(userDetailIdList).associateBy { it.id }
|
||||
}
|
||||
|
|
|
@ -5,4 +5,5 @@ import dev.usbharu.hideout.core.domain.model.post.PostId
|
|||
|
||||
interface ReactionsQueryService {
|
||||
suspend fun findAllByPostId(postId: PostId): List<Reactions>
|
||||
suspend fun findAllByPostIdIn(postIds: List<PostId>): List<Reactions>
|
||||
}
|
Loading…
Reference in New Issue