mirror of https://github.com/usbharu/Hideout.git
feat: Post詳細ページでリアクションを表示できるように
This commit is contained in:
parent
1b4dbc8566
commit
2b567bb1d5
|
@ -0,0 +1,28 @@
|
||||||
|
package dev.usbharu.hideout.core.application.model
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
|
||||||
|
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
data class Reactions(
|
||||||
|
val postId: Long,
|
||||||
|
val count: Int,
|
||||||
|
val name: String,
|
||||||
|
val domain: String,
|
||||||
|
val url: URI?,
|
||||||
|
val actorIds: List<Long>,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun of(reactionList: List<Reaction>, customEmoji: CustomEmoji?): Reactions {
|
||||||
|
val first = reactionList.first()
|
||||||
|
return Reactions(
|
||||||
|
first.id.value,
|
||||||
|
reactionList.size,
|
||||||
|
customEmoji?.name ?: first.unicodeEmoji.name,
|
||||||
|
customEmoji?.domain?.domain ?: first.unicodeEmoji.domain.domain,
|
||||||
|
customEmoji?.url,
|
||||||
|
reactionList.map { it.actorId.id }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||||
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
import dev.usbharu.hideout.core.domain.service.post.IPostReadAccessControl
|
||||||
|
import dev.usbharu.hideout.core.query.reactions.ReactionsQueryService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -20,7 +21,8 @@ class GetPostDetailApplicationService(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: PostRepository,
|
||||||
private val actorRepository: ActorRepository,
|
private val actorRepository: ActorRepository,
|
||||||
private val mediaRepository: MediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val iPostReadAccessControl: IPostReadAccessControl
|
private val iPostReadAccessControl: IPostReadAccessControl,
|
||||||
|
private val reactionsQueryService: ReactionsQueryService,
|
||||||
) : AbstractApplicationService<GetPostDetail, PostDetail>(
|
) : AbstractApplicationService<GetPostDetail, PostDetail>(
|
||||||
transaction,
|
transaction,
|
||||||
logger
|
logger
|
||||||
|
@ -38,6 +40,8 @@ class GetPostDetailApplicationService(
|
||||||
|
|
||||||
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
||||||
|
|
||||||
|
val reactions = reactionsQueryService.findAllByPostId(post.id)
|
||||||
|
|
||||||
return PostDetail.of(
|
return PostDetail.of(
|
||||||
post = post,
|
post = post,
|
||||||
actor = actor,
|
actor = actor,
|
||||||
|
@ -46,6 +50,7 @@ class GetPostDetailApplicationService(
|
||||||
reply = post.replyId?.let { fetchChild(it, actor, iconMedia, principal) },
|
reply = post.replyId?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||||
repost = post.repostId?.let { fetchChild(it, actor, iconMedia, principal) },
|
repost = post.repostId?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||||
moveTo = post.moveTo?.let { fetchChild(it, actor, iconMedia, principal) },
|
moveTo = post.moveTo?.let { fetchChild(it, actor, iconMedia, principal) },
|
||||||
|
reactionsList = reactions
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,10 +74,11 @@ class GetPostDetailApplicationService(
|
||||||
|
|
||||||
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
val mediaList = mediaRepository.findByIds(post.mediaIds)
|
||||||
return PostDetail.of(
|
return PostDetail.of(
|
||||||
post,
|
post = post,
|
||||||
first,
|
actor = first,
|
||||||
third,
|
iconMedia = third,
|
||||||
mediaList
|
mediaList = mediaList,
|
||||||
|
reactionsList = emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.core.application.post
|
package dev.usbharu.hideout.core.application.post
|
||||||
|
|
||||||
|
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.Actor
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
import dev.usbharu.hideout.core.domain.model.media.Media
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
|
@ -23,7 +24,8 @@ data class PostDetail(
|
||||||
val sensitive: Boolean,
|
val sensitive: Boolean,
|
||||||
val deleted: Boolean,
|
val deleted: Boolean,
|
||||||
val mediaDetailList: List<MediaDetail>,
|
val mediaDetailList: List<MediaDetail>,
|
||||||
val moveTo: PostDetail?
|
val moveTo: PostDetail?,
|
||||||
|
val reactionsList: List<Reactions>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
|
@ -35,6 +37,7 @@ data class PostDetail(
|
||||||
reply: PostDetail? = null,
|
reply: PostDetail? = null,
|
||||||
repost: PostDetail? = null,
|
repost: PostDetail? = null,
|
||||||
moveTo: PostDetail? = null,
|
moveTo: PostDetail? = null,
|
||||||
|
reactionsList: List<Reactions>
|
||||||
): PostDetail {
|
): PostDetail {
|
||||||
return PostDetail(
|
return PostDetail(
|
||||||
id = post.id.id,
|
id = post.id.id,
|
||||||
|
@ -52,7 +55,8 @@ data class PostDetail(
|
||||||
sensitive = post.sensitive,
|
sensitive = post.sensitive,
|
||||||
deleted = false,
|
deleted = false,
|
||||||
mediaDetailList = mediaList.map { MediaDetail.of(it) },
|
mediaDetailList = mediaList.map { MediaDetail.of(it) },
|
||||||
moveTo = moveTo
|
moveTo = moveTo,
|
||||||
|
reactionsList = reactionsList
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ class ReadTimelineApplicationService(
|
||||||
it.replyPost,
|
it.replyPost,
|
||||||
it.replyPostActor!!,
|
it.replyPostActor!!,
|
||||||
it.replyPostActorIconMedia,
|
it.replyPostActorIconMedia,
|
||||||
it.replyPostMedias.orEmpty()
|
it.replyPostMedias.orEmpty(),
|
||||||
|
reactionsList = emptyList(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -56,10 +57,11 @@ class ReadTimelineApplicationService(
|
||||||
val repost = if (it.repostPost != null) {
|
val repost = if (it.repostPost != null) {
|
||||||
@Suppress("UnsafeCallOnNullableType")
|
@Suppress("UnsafeCallOnNullableType")
|
||||||
PostDetail.of(
|
PostDetail.of(
|
||||||
it.repostPost,
|
post = it.repostPost,
|
||||||
it.repostPostActor!!,
|
actor = it.repostPostActor!!,
|
||||||
it.repostPostActorIconMedia,
|
iconMedia = it.repostPostActorIconMedia,
|
||||||
it.repostPostMedias.orEmpty()
|
mediaList = it.repostPostMedias.orEmpty(),
|
||||||
|
reactionsList = emptyList()
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
|
@ -71,7 +73,8 @@ class ReadTimelineApplicationService(
|
||||||
iconMedia = it.postActorIconMedia,
|
iconMedia = it.postActorIconMedia,
|
||||||
mediaList = it.postMedias,
|
mediaList = it.postMedias,
|
||||||
reply = reply,
|
reply = reply,
|
||||||
repost = repost
|
repost = repost,
|
||||||
|
reactionsList = emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.reaction
|
package dev.usbharu.hideout.core.domain.model.reaction
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||||
|
|
||||||
interface ReactionRepository {
|
interface ReactionRepository {
|
||||||
suspend fun save(reaction: Reaction): Reaction
|
suspend fun save(reaction: Reaction): Reaction
|
||||||
suspend fun findById(reactionId: ReactionId): Reaction?
|
suspend fun findById(reactionId: ReactionId): Reaction?
|
||||||
|
suspend fun findByPostId(postId: PostId): List<Reaction>
|
||||||
suspend fun delete(reaction: Reaction)
|
suspend fun delete(reaction: Reaction)
|
||||||
}
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.model.Reactions
|
||||||
|
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.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Reactions as ExposedrepositoryReactions
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
class ExposedReactionsQueryService : ReactionsQueryService, AbstractRepository() {
|
||||||
|
override suspend fun findAllByPostId(postId: PostId): List<Reactions> {
|
||||||
|
return query {
|
||||||
|
ExposedrepositoryReactions.leftJoin(CustomEmojis).selectAll()
|
||||||
|
.where { ExposedrepositoryReactions.postId eq postId.id }
|
||||||
|
.groupBy {
|
||||||
|
it[ExposedrepositoryReactions.customEmojiId]?.toString()
|
||||||
|
?: it[ExposedrepositoryReactions.unicodeEmoji]
|
||||||
|
}
|
||||||
|
.map { it.value }
|
||||||
|
.map {
|
||||||
|
Reactions.of(
|
||||||
|
it.map { resultRow -> resultRow.toReaction() },
|
||||||
|
it.first().toCustomEmojiOrNull()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ExposedReactionsQueryService::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -100,7 +100,8 @@ class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractReposi
|
||||||
sensitive = it[authorizedQuery[Posts.sensitive]],
|
sensitive = it[authorizedQuery[Posts.sensitive]],
|
||||||
deleted = it[authorizedQuery[Posts.deleted]],
|
deleted = it[authorizedQuery[Posts.deleted]],
|
||||||
mediaDetailList = emptyList(),
|
mediaDetailList = emptyList(),
|
||||||
moveTo = null
|
moveTo = null,
|
||||||
|
emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,14 @@ class ExposedReactionRepository(override val domainEventPublisher: DomainEventPu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByPostId(postId: PostId): List<Reaction> {
|
||||||
|
return query {
|
||||||
|
Reactions.selectAll().where {
|
||||||
|
Reactions.postId eq postId.id
|
||||||
|
}.map { it.toReaction() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun delete(reaction: Reaction) {
|
override suspend fun delete(reaction: Reaction) {
|
||||||
return query {
|
return query {
|
||||||
Reactions.deleteWhere {
|
Reactions.deleteWhere {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.core.query.reactions
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.model.Reactions
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||||
|
|
||||||
|
interface ReactionsQueryService {
|
||||||
|
suspend fun findAllByPostId(postId: PostId): List<Reactions>
|
||||||
|
}
|
Loading…
Reference in New Issue