mirror of https://github.com/usbharu/Hideout.git
feat: タイムラインを読み込めるように
This commit is contained in:
parent
efbf2b0af7
commit
d0ff47525f
|
@ -21,4 +21,5 @@ interface ActorRepository {
|
||||||
suspend fun delete(actor: Actor)
|
suspend fun delete(actor: Actor)
|
||||||
suspend fun findById(id: ActorId): Actor?
|
suspend fun findById(id: ActorId): Actor?
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String): Actor?
|
suspend fun findByNameAndDomain(name: String, domain: String): Actor?
|
||||||
|
suspend fun findAllById(actorIds: List<ActorId>): List<Actor>
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,12 @@ interface PostRepository {
|
||||||
suspend fun save(post: Post): Post
|
suspend fun save(post: Post): Post
|
||||||
suspend fun saveAll(posts: List<Post>): List<Post>
|
suspend fun saveAll(posts: List<Post>): List<Post>
|
||||||
suspend fun findById(id: PostId): Post?
|
suspend fun findById(id: PostId): Post?
|
||||||
|
suspend fun findAllById(ids: List<PostId>): List<Post>
|
||||||
suspend fun findByActorId(id: ActorId, page: Page? = null): PaginationList<Post, PostId>
|
suspend fun findByActorId(id: ActorId, page: Page? = null): PaginationList<Post, PostId>
|
||||||
suspend fun delete(post: Post)
|
suspend fun delete(post: Post)
|
||||||
|
suspend fun findByActorIdAndVisibilityInList(
|
||||||
|
actorId: ActorId,
|
||||||
|
visibilityList: List<Visibility>,
|
||||||
|
of: Page? = null
|
||||||
|
): PaginationList<Post, PostId>
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.model.support.timelineobjectdetail
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObject
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObjectId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObjectWarnFilter
|
||||||
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
data class TimelineObjectDetail(
|
||||||
|
val id: TimelineObjectId,
|
||||||
|
val timelineUserDetail: UserDetail,
|
||||||
|
val post: Post,
|
||||||
|
val postActor: Actor,
|
||||||
|
val replyPost: Post?,
|
||||||
|
val replyPostActor: Actor?,
|
||||||
|
val repostPost: Post?,
|
||||||
|
val repostPostActor: Actor?,
|
||||||
|
val isPureRepost: Boolean,
|
||||||
|
val lastUpdateAt: Instant,
|
||||||
|
val hasMediaInRepost: Boolean,
|
||||||
|
val warnFilter: List<TimelineObjectWarnFilter>
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun of(
|
||||||
|
timelineObject: TimelineObject,
|
||||||
|
timelineUserDetail: UserDetail,
|
||||||
|
post: Post,
|
||||||
|
postActor: Actor,
|
||||||
|
replyPost: Post?,
|
||||||
|
replyPostActor: Actor?,
|
||||||
|
repostPost: Post?,
|
||||||
|
repostPostActor: Actor?,
|
||||||
|
warnFilter: List<TimelineObjectWarnFilter>
|
||||||
|
): TimelineObjectDetail {
|
||||||
|
return TimelineObjectDetail(
|
||||||
|
timelineObject.id,
|
||||||
|
timelineUserDetail,
|
||||||
|
post,
|
||||||
|
postActor,
|
||||||
|
replyPost,
|
||||||
|
replyPostActor,
|
||||||
|
repostPost,
|
||||||
|
repostPostActor,
|
||||||
|
timelineObject.isPureRepost,
|
||||||
|
timelineObject.lastUpdatedAt,
|
||||||
|
timelineObject.hasMediaInRepost,
|
||||||
|
warnFilter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,9 @@ class TimelineObject(
|
||||||
val postActorId: ActorId,
|
val postActorId: ActorId,
|
||||||
val postCreatedAt: Instant,
|
val postCreatedAt: Instant,
|
||||||
val replyId: PostId?,
|
val replyId: PostId?,
|
||||||
|
val replyActorId: ActorId?,
|
||||||
val repostId: PostId?,
|
val repostId: PostId?,
|
||||||
|
val repostActorId: ActorId?,
|
||||||
visibility: Visibility,
|
visibility: Visibility,
|
||||||
isPureRepost: Boolean,
|
isPureRepost: Boolean,
|
||||||
mediaIds: List<MediaId>,
|
mediaIds: List<MediaId>,
|
||||||
|
@ -75,6 +77,7 @@ class TimelineObject(
|
||||||
timelineObjectId: TimelineObjectId,
|
timelineObjectId: TimelineObjectId,
|
||||||
timeline: Timeline,
|
timeline: Timeline,
|
||||||
post: Post,
|
post: Post,
|
||||||
|
replyActorId: ActorId?,
|
||||||
filterResults: List<FilterResult>
|
filterResults: List<FilterResult>
|
||||||
): TimelineObject {
|
): TimelineObject {
|
||||||
return TimelineObject(
|
return TimelineObject(
|
||||||
|
@ -85,7 +88,9 @@ class TimelineObject(
|
||||||
postActorId = post.actorId,
|
postActorId = post.actorId,
|
||||||
postCreatedAt = post.createdAt,
|
postCreatedAt = post.createdAt,
|
||||||
replyId = post.replyId,
|
replyId = post.replyId,
|
||||||
|
replyActorId = replyActorId,
|
||||||
repostId = null,
|
repostId = null,
|
||||||
|
repostActorId = null,
|
||||||
visibility = post.visibility,
|
visibility = post.visibility,
|
||||||
isPureRepost = true,
|
isPureRepost = true,
|
||||||
mediaIds = post.mediaIds,
|
mediaIds = post.mediaIds,
|
||||||
|
@ -101,6 +106,7 @@ class TimelineObject(
|
||||||
timelineObjectId: TimelineObjectId,
|
timelineObjectId: TimelineObjectId,
|
||||||
timeline: Timeline,
|
timeline: Timeline,
|
||||||
post: Post,
|
post: Post,
|
||||||
|
replyActorId: ActorId?,
|
||||||
repost: Post,
|
repost: Post,
|
||||||
filterResults: List<FilterResult>
|
filterResults: List<FilterResult>
|
||||||
): TimelineObject {
|
): TimelineObject {
|
||||||
|
@ -115,7 +121,9 @@ class TimelineObject(
|
||||||
postActorId = post.actorId,
|
postActorId = post.actorId,
|
||||||
postCreatedAt = post.createdAt,
|
postCreatedAt = post.createdAt,
|
||||||
replyId = post.replyId,
|
replyId = post.replyId,
|
||||||
|
replyActorId = replyActorId,
|
||||||
repostId = repost.id,
|
repostId = repost.id,
|
||||||
|
repostActorId = repost.actorId,
|
||||||
visibility = post.visibility,
|
visibility = post.visibility,
|
||||||
isPureRepost = repost.mediaIds.isEmpty() &&
|
isPureRepost = repost.mediaIds.isEmpty() &&
|
||||||
repost.overview == null &&
|
repost.overview == null &&
|
||||||
|
|
|
@ -6,5 +6,13 @@ import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||||
class TimelineRelationship(
|
class TimelineRelationship(
|
||||||
val id: TimelineRelationshipId,
|
val id: TimelineRelationshipId,
|
||||||
val timelineId: TimelineId,
|
val timelineId: TimelineId,
|
||||||
val actorId: ActorId
|
val actorId: ActorId,
|
||||||
|
val visible: Visible
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class Visible {
|
||||||
|
PUBLIC,
|
||||||
|
UNLISTED,
|
||||||
|
FOLLOWERS,
|
||||||
|
DIRECT
|
||||||
|
}
|
|
@ -21,4 +21,5 @@ interface UserDetailRepository {
|
||||||
suspend fun delete(userDetail: UserDetail)
|
suspend fun delete(userDetail: UserDetail)
|
||||||
suspend fun findByActorId(actorId: Long): UserDetail?
|
suspend fun findByActorId(actorId: Long): UserDetail?
|
||||||
suspend fun findById(id: Long): UserDetail?
|
suspend fun findById(id: Long): UserDetail?
|
||||||
|
suspend fun findAllById(idList: List<UserDetailId>): List<UserDetail>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.external.timeline
|
package dev.usbharu.hideout.core.external.timeline
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.timelineobjectdetail.TimelineObjectDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||||
|
|
||||||
|
@ -10,6 +11,10 @@ interface TimelineStore {
|
||||||
suspend fun removePost(post: Post)
|
suspend fun removePost(post: Post)
|
||||||
suspend fun addTimelineRelationship(timelineRelationship: TimelineRelationship)
|
suspend fun addTimelineRelationship(timelineRelationship: TimelineRelationship)
|
||||||
suspend fun removeTimelineRelationship(timelineRelationship: TimelineRelationship)
|
suspend fun removeTimelineRelationship(timelineRelationship: TimelineRelationship)
|
||||||
|
|
||||||
|
suspend fun updateTimelineRelationship(timelineRelationship: TimelineRelationship)
|
||||||
suspend fun addTimeline(timeline: Timeline, timelineRelationshipList: List<TimelineRelationship>)
|
suspend fun addTimeline(timeline: Timeline, timelineRelationshipList: List<TimelineRelationship>)
|
||||||
suspend fun removeTimeline(timeline: Timeline)
|
suspend fun removeTimeline(timeline: Timeline)
|
||||||
|
|
||||||
|
suspend fun readTimeline(timeline: Timeline): List<TimelineObjectDetail>
|
||||||
}
|
}
|
|
@ -98,6 +98,18 @@ class ExposedActorRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findAllById(actorIds: List<ActorId>): List<Actor> {
|
||||||
|
return query {
|
||||||
|
Actors
|
||||||
|
.leftJoin(ActorsAlsoKnownAs, onColumn = { id }, otherColumn = { actorId })
|
||||||
|
.selectAll()
|
||||||
|
.where {
|
||||||
|
Actors.id inList actorIds.map { it.id }
|
||||||
|
}
|
||||||
|
.let(actorQueryMapper::map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(ExposedActorRepository::class.java)
|
private val logger = LoggerFactory.getLogger(ExposedActorRepository::class.java)
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,6 +162,18 @@ class ExposedPostRepository(
|
||||||
.first()
|
.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findAllById(ids: List<PostId>): List<Post> {
|
||||||
|
return query {
|
||||||
|
Posts
|
||||||
|
.selectAll()
|
||||||
|
.where {
|
||||||
|
Posts.id inList ids.map { it.id }
|
||||||
|
}
|
||||||
|
.let(postQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByActorId(id: ActorId, page: Page?): PaginationList<Post, PostId> = PaginationList(query {
|
override suspend fun findByActorId(id: ActorId, page: Page?): PaginationList<Post, PostId> = PaginationList(query {
|
||||||
Posts
|
Posts
|
||||||
.selectAll()
|
.selectAll()
|
||||||
|
@ -180,6 +192,21 @@ class ExposedPostRepository(
|
||||||
update(post)
|
update(post)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByActorIdAndVisibilityInList(
|
||||||
|
actorId: ActorId,
|
||||||
|
visibilityList: List<Visibility>,
|
||||||
|
of: Page?
|
||||||
|
): PaginationList<Post, PostId> {
|
||||||
|
return PaginationList(query {
|
||||||
|
Posts
|
||||||
|
.selectAll()
|
||||||
|
.where {
|
||||||
|
Posts.actorId eq actorId.id and (visibility inList visibilityList.map { it.name })
|
||||||
|
}
|
||||||
|
.let(postQueryMapper::map)
|
||||||
|
}, null, null)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(ExposedPostRepository::class.java)
|
private val logger = LoggerFactory.getLogger(ExposedPostRepository::class.java)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
@ -22,6 +23,7 @@ class ExposedTimelineRelationshipRepository : AbstractRepository(), TimelineRela
|
||||||
it[id] = timelineRelationship.id.value
|
it[id] = timelineRelationship.id.value
|
||||||
it[timelineId] = timelineRelationship.timelineId.value
|
it[timelineId] = timelineRelationship.timelineId.value
|
||||||
it[actorId] = timelineRelationship.actorId.id
|
it[actorId] = timelineRelationship.actorId.id
|
||||||
|
it[visible] = timelineRelationship.visible.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return timelineRelationship
|
return timelineRelationship
|
||||||
|
@ -53,6 +55,7 @@ fun ResultRow.toTimelineRelationship(): TimelineRelationship {
|
||||||
TimelineRelationshipId(this[TimelineRelationships.id]),
|
TimelineRelationshipId(this[TimelineRelationships.id]),
|
||||||
TimelineId(this[TimelineRelationships.timelineId]),
|
TimelineId(this[TimelineRelationships.timelineId]),
|
||||||
ActorId(this[TimelineRelationships.actorId]),
|
ActorId(this[TimelineRelationships.actorId]),
|
||||||
|
Visible.valueOf(this[TimelineRelationships.visible])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,5 +63,6 @@ object TimelineRelationships : Table("timeline_relationships") {
|
||||||
val id = long("id")
|
val id = long("id")
|
||||||
val timelineId = long("timeline_id").references(Timelines.id)
|
val timelineId = long("timeline_id").references(Timelines.id)
|
||||||
val actorId = long("actor_id").references(Actors.id)
|
val actorId = long("actor_id").references(Actors.id)
|
||||||
|
val visible = varchar("visible", 100)
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
|
@ -89,6 +89,23 @@ class UserDetailRepositoryImpl : UserDetailRepository, AbstractRepository() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findAllById(idList: List<UserDetailId>): List<UserDetail> {
|
||||||
|
return query {
|
||||||
|
UserDetails
|
||||||
|
.selectAll()
|
||||||
|
.where { UserDetails.id inList idList.map { it.id } }
|
||||||
|
.map {
|
||||||
|
UserDetail.create(
|
||||||
|
UserDetailId(it[UserDetails.id]),
|
||||||
|
ActorId(it[UserDetails.actorId]),
|
||||||
|
UserDetailHashedPassword(it[UserDetails.password]),
|
||||||
|
it[UserDetails.autoAcceptFolloweeFollowRequest],
|
||||||
|
it[UserDetails.lastMigration]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java)
|
private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,11 @@ class MongoInternalTimelineObjectRepository(private val springDataMongoTimelineO
|
||||||
springDataMongoTimelineObjectRepository.deleteByTimelineId(timelineId.value)
|
springDataMongoTimelineObjectRepository.deleteByTimelineId(timelineId.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByTimelineId(timelineId: TimelineId): List<TimelineObject> {
|
||||||
|
return springDataMongoTimelineObjectRepository.findByTimelineId(timelineId).map { it.toTimelineObject() }
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +68,9 @@ data class SpringDataMongoTimelineObject(
|
||||||
val postActorId: Long,
|
val postActorId: Long,
|
||||||
val postCreatedAt: Long,
|
val postCreatedAt: Long,
|
||||||
val replyId: Long?,
|
val replyId: Long?,
|
||||||
|
val replyActorId: Long?,
|
||||||
val repostId: Long?,
|
val repostId: Long?,
|
||||||
|
val repostActorId: Long?,
|
||||||
val visibility: Visibility,
|
val visibility: Visibility,
|
||||||
val isPureRepost: Boolean,
|
val isPureRepost: Boolean,
|
||||||
val mediaIds: List<Long>,
|
val mediaIds: List<Long>,
|
||||||
|
@ -83,7 +90,9 @@ data class SpringDataMongoTimelineObject(
|
||||||
ActorId(postActorId),
|
ActorId(postActorId),
|
||||||
Instant.ofEpochSecond(postCreatedAt),
|
Instant.ofEpochSecond(postCreatedAt),
|
||||||
replyId?.let { PostId(it) },
|
replyId?.let { PostId(it) },
|
||||||
|
replyActorId?.let { ActorId(it) },
|
||||||
repostId?.let { PostId(it) },
|
repostId?.let { PostId(it) },
|
||||||
|
repostActorId?.let { ActorId(it) },
|
||||||
visibility,
|
visibility,
|
||||||
isPureRepost,
|
isPureRepost,
|
||||||
mediaIds.map { MediaId(it) },
|
mediaIds.map { MediaId(it) },
|
||||||
|
@ -105,7 +114,9 @@ data class SpringDataMongoTimelineObject(
|
||||||
timelineObject.postActorId.id,
|
timelineObject.postActorId.id,
|
||||||
timelineObject.postCreatedAt.epochSecond,
|
timelineObject.postCreatedAt.epochSecond,
|
||||||
timelineObject.replyId?.id,
|
timelineObject.replyId?.id,
|
||||||
|
timelineObject.replyActorId?.id,
|
||||||
timelineObject.repostId?.id,
|
timelineObject.repostId?.id,
|
||||||
|
timelineObject.repostActorId?.id,
|
||||||
timelineObject.visibility,
|
timelineObject.visibility,
|
||||||
timelineObject.isPureRepost,
|
timelineObject.isPureRepost,
|
||||||
timelineObject.mediaIds.map { it.id },
|
timelineObject.mediaIds.map { it.id },
|
||||||
|
@ -149,4 +160,6 @@ interface SpringDataMongoTimelineObjectRepository : CoroutineCrudRepository<Spri
|
||||||
suspend fun deleteByTimelineIdAndPostActorId(timelineId: Long, postActorId: Long)
|
suspend fun deleteByTimelineIdAndPostActorId(timelineId: Long, postActorId: Long)
|
||||||
|
|
||||||
suspend fun deleteByTimelineId(timelineId: Long)
|
suspend fun deleteByTimelineId(timelineId: Long)
|
||||||
|
|
||||||
|
suspend fun findByTimelineId(timelineId: TimelineId): Flow<SpringDataMongoTimelineObject>
|
||||||
}
|
}
|
|
@ -1,27 +1,36 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.timeline
|
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||||
|
|
||||||
|
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.actor.ActorId
|
||||||
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
||||||
import dev.usbharu.hideout.core.domain.model.filter.FilteredPost
|
import dev.usbharu.hideout.core.domain.model.filter.FilteredPost
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.timelineobjectdetail.TimelineObjectDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility
|
||||||
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObject
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObject
|
||||||
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObjectId
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObjectId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObjectWarnFilter
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible
|
||||||
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
||||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.external.timeline.TimelineStore
|
import dev.usbharu.hideout.core.external.timeline.TimelineStore
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateService) : TimelineStore {
|
abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateService) : TimelineStore {
|
||||||
override suspend fun addPost(post: Post) {
|
override suspend fun addPost(post: Post) {
|
||||||
val timelineList = getTimelines(post.actorId)
|
val timelineList = getTimelines(post.actorId)
|
||||||
|
|
||||||
val repost = post.repostId?.let { getPost(it) }
|
val repost = post.repostId?.let { getPost(it) }
|
||||||
|
val replyActorId = post.replyId?.let { getPost(it)?.actorId }
|
||||||
|
|
||||||
val timelineObjectList = timelineList.map {
|
val timelineObjectList = timelineList.mapNotNull {
|
||||||
createTimelineObject(post, repost, it)
|
createTimelineObject(post, replyActorId, repost, it)
|
||||||
}
|
}
|
||||||
|
|
||||||
insertTimelineObject(timelineObjectList)
|
insertTimelineObject(timelineObjectList)
|
||||||
|
@ -31,24 +40,46 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||||
|
|
||||||
protected abstract suspend fun getTimeline(timelineId: TimelineId): Timeline?
|
protected abstract suspend fun getTimeline(timelineId: TimelineId): Timeline?
|
||||||
|
|
||||||
protected suspend fun createTimelineObject(post: Post, repost: Post?, timeline: Timeline): TimelineObject {
|
protected suspend fun createTimelineObject(
|
||||||
|
post: Post,
|
||||||
|
replyActorId: ActorId?,
|
||||||
|
repost: Post?,
|
||||||
|
timeline: Timeline
|
||||||
|
): TimelineObject? {
|
||||||
|
if (post.visibility == Visibility.DIRECT) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (timeline.visibility == TimelineVisibility.PUBLIC && post.visibility != Visibility.PUBLIC) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (timeline.visibility == TimelineVisibility.UNLISTED && (post.visibility != Visibility.PUBLIC || post.visibility != Visibility.UNLISTED)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
val filters = getFilters(timeline.userDetailId)
|
val filters = getFilters(timeline.userDetailId)
|
||||||
|
|
||||||
val applyFilters = applyFilters(post, filters)
|
val applyFilters = applyFilters(post, filters)
|
||||||
|
|
||||||
if (repost != null) {
|
if (repost != null) {
|
||||||
return TimelineObject.create(
|
return TimelineObject.create(
|
||||||
TimelineObjectId(idGenerateService.generateId()), timeline, post, repost, applyFilters.filterResults
|
TimelineObjectId(idGenerateService.generateId()),
|
||||||
|
timeline,
|
||||||
|
post,
|
||||||
|
replyActorId,
|
||||||
|
repost,
|
||||||
|
applyFilters.filterResults
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimelineObject.create(
|
return TimelineObject.create(
|
||||||
TimelineObjectId(idGenerateService.generateId()), timeline, post, applyFilters.filterResults
|
TimelineObjectId(idGenerateService.generateId()), timeline, post, replyActorId, applyFilters.filterResults
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract suspend fun getFilters(userDetailId: UserDetailId): List<Filter>
|
protected abstract suspend fun getFilters(userDetailId: UserDetailId): List<Filter>
|
||||||
|
|
||||||
|
protected abstract suspend fun getNewerFilters(userDetailId: UserDetailId, lastUpdateAt: Instant): List<Filter>
|
||||||
|
|
||||||
protected abstract suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost
|
protected abstract suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost
|
||||||
|
|
||||||
protected abstract suspend fun getPost(postId: PostId): Post?
|
protected abstract suspend fun getPost(postId: PostId): Post?
|
||||||
|
@ -65,7 +96,11 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||||
|
|
||||||
protected abstract suspend fun removeTimelineObject(timelineId: TimelineId)
|
protected abstract suspend fun removeTimelineObject(timelineId: TimelineId)
|
||||||
|
|
||||||
protected abstract suspend fun getPosts(timelineRelationshipList: List<TimelineRelationship>): List<Post>
|
protected abstract suspend fun getPostsByTimelineRelationshipList(timelineRelationshipList: List<TimelineRelationship>): List<Post>
|
||||||
|
|
||||||
|
protected abstract suspend fun getPostsByPostId(postIds: List<PostId>): List<Post>
|
||||||
|
|
||||||
|
protected abstract suspend fun getTimelineObject(timelineId: TimelineId): List<TimelineObject>
|
||||||
|
|
||||||
override suspend fun updatePost(post: Post) {
|
override suspend fun updatePost(post: Post) {
|
||||||
val timelineObjectByPostId = getTimelineObjectByPostId(post.id)
|
val timelineObjectByPostId = getTimelineObjectByPostId(post.id)
|
||||||
|
@ -91,33 +126,62 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||||
updateTimelineObject(timelineObjectList)
|
updateTimelineObject(timelineObjectList)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract suspend fun getActorPost(actorId: ActorId): List<Post>
|
protected abstract suspend fun getActorPost(actorId: ActorId, visibilityList: List<Visibility>): List<Post>
|
||||||
|
|
||||||
override suspend fun removePost(post: Post) {
|
override suspend fun removePost(post: Post) {
|
||||||
removeTimelineObject(post.id)
|
removeTimelineObject(post.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun addTimelineRelationship(timelineRelationship: TimelineRelationship) {
|
override suspend fun addTimelineRelationship(timelineRelationship: TimelineRelationship) {
|
||||||
val postList = getActorPost(timelineRelationship.actorId)
|
val visibilityList = visibilities(timelineRelationship)
|
||||||
|
val postList = getActorPost(timelineRelationship.actorId, visibilityList)
|
||||||
val timeline = getTimeline(timelineRelationship.timelineId) ?: return
|
val timeline = getTimeline(timelineRelationship.timelineId) ?: return
|
||||||
val timelineObjects = postList.map { post ->
|
val timelineObjects = postList.mapNotNull { post ->
|
||||||
val repost = post.repostId?.let { getPost(it) }
|
val repost = post.repostId?.let { getPost(it) }
|
||||||
createTimelineObject(post, repost, timeline)
|
val replyActorId = post.replyId?.let { getPost(it)?.actorId }
|
||||||
|
createTimelineObject(post, replyActorId, repost, timeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
insertTimelineObject(timelineObjects)
|
insertTimelineObject(timelineObjects)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun visibilities(timelineRelationship: TimelineRelationship): List<Visibility> {
|
||||||
|
val visibilityList = when (timelineRelationship.visible) {
|
||||||
|
Visible.PUBLIC -> {
|
||||||
|
listOf(Visibility.PUBLIC)
|
||||||
|
}
|
||||||
|
|
||||||
|
Visible.UNLISTED -> {
|
||||||
|
listOf(Visibility.PUBLIC, Visibility.UNLISTED)
|
||||||
|
}
|
||||||
|
|
||||||
|
Visible.FOLLOWERS -> {
|
||||||
|
listOf(Visibility.PUBLIC, Visibility.UNLISTED, Visibility.FOLLOWERS)
|
||||||
|
}
|
||||||
|
|
||||||
|
Visible.DIRECT -> {
|
||||||
|
listOf(Visibility.PUBLIC, Visibility.UNLISTED, Visibility.FOLLOWERS, Visibility.DIRECT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visibilityList
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun removeTimelineRelationship(timelineRelationship: TimelineRelationship) {
|
override suspend fun removeTimelineRelationship(timelineRelationship: TimelineRelationship) {
|
||||||
removeTimelineObject(timelineRelationship.timelineId, timelineRelationship.actorId)
|
removeTimelineObject(timelineRelationship.timelineId, timelineRelationship.actorId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun addTimeline(timeline: Timeline, timelineRelationshipList: List<TimelineRelationship>) {
|
override suspend fun updateTimelineRelationship(timelineRelationship: TimelineRelationship) {
|
||||||
val postList = getPosts(timelineRelationshipList)
|
removeTimelineRelationship(timelineRelationship)
|
||||||
|
addTimelineRelationship(timelineRelationship)
|
||||||
|
}
|
||||||
|
|
||||||
val timelineObjectList = postList.map { post ->
|
override suspend fun addTimeline(timeline: Timeline, timelineRelationshipList: List<TimelineRelationship>) {
|
||||||
|
val postList = getPostsByTimelineRelationshipList(timelineRelationshipList)
|
||||||
|
|
||||||
|
val timelineObjectList = postList.mapNotNull { post ->
|
||||||
val repost = post.repostId?.let { getPost(it) }
|
val repost = post.repostId?.let { getPost(it) }
|
||||||
createTimelineObject(post, repost, timeline)
|
val replyActorId = post.replyId?.let { getPost(it)?.actorId }
|
||||||
|
createTimelineObject(post, replyActorId, repost, timeline)
|
||||||
}
|
}
|
||||||
|
|
||||||
insertTimelineObject(timelineObjectList)
|
insertTimelineObject(timelineObjectList)
|
||||||
|
@ -126,4 +190,53 @@ abstract class AbstractTimelineStore(private val idGenerateService: IdGenerateSe
|
||||||
override suspend fun removeTimeline(timeline: Timeline) {
|
override suspend fun removeTimeline(timeline: Timeline) {
|
||||||
removeTimelineObject(timeline.id)
|
removeTimelineObject(timeline.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun readTimeline(timeline: Timeline): List<TimelineObjectDetail> {
|
||||||
|
val timelineObjectList = getTimelineObject(timeline.id)
|
||||||
|
val lastUpdatedAt = timelineObjectList.minBy { it.lastUpdatedAt }.lastUpdatedAt
|
||||||
|
|
||||||
|
val newerFilters = getNewerFilters(timeline.userDetailId, lastUpdatedAt)
|
||||||
|
|
||||||
|
val posts =
|
||||||
|
getPostsByPostId(timelineObjectList.map { it.postId } + timelineObjectList.mapNotNull { it.repostId } + timelineObjectList.mapNotNull { it.replyId })
|
||||||
|
|
||||||
|
val userDetails = getUserDetails(timelineObjectList.map { it.userDetailId })
|
||||||
|
|
||||||
|
val actors =
|
||||||
|
getActors(timelineObjectList.map { it.postActorId } + timelineObjectList.mapNotNull { it.repostActorId } + timelineObjectList.mapNotNull { it.replyActorId })
|
||||||
|
|
||||||
|
val postMap = posts.associate { post ->
|
||||||
|
post.id to applyFilters(post, newerFilters)
|
||||||
|
}
|
||||||
|
|
||||||
|
return timelineObjectList.mapNotNull<TimelineObject, TimelineObjectDetail> {
|
||||||
|
val timelineUserDetail = userDetails[it.userDetailId] ?: return@mapNotNull null
|
||||||
|
val actor = actors[it.postActorId] ?: return@mapNotNull null
|
||||||
|
val post = postMap[it.postId] ?: return@mapNotNull null
|
||||||
|
val reply = postMap[it.replyId]
|
||||||
|
val replyActor = actors[it.replyActorId]
|
||||||
|
val repost = postMap[it.repostId]
|
||||||
|
val repostActor = actors[it.repostActorId]
|
||||||
|
TimelineObjectDetail.of(
|
||||||
|
timelineObject = it,
|
||||||
|
timelineUserDetail = timelineUserDetail,
|
||||||
|
post = post.post,
|
||||||
|
postActor = actor,
|
||||||
|
replyPost = reply?.post,
|
||||||
|
replyPostActor = replyActor,
|
||||||
|
repostPost = repost?.post,
|
||||||
|
repostPostActor = repostActor,
|
||||||
|
warnFilter = it.warnFilters + post.filterResults.map {
|
||||||
|
TimelineObjectWarnFilter(
|
||||||
|
it.filter.id,
|
||||||
|
it.matchedKeyword
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract suspend fun getActors(actorIds: List<ActorId>): Map<ActorId, Actor>
|
||||||
|
|
||||||
|
abstract suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail>
|
||||||
}
|
}
|
|
@ -1,7 +1,9 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.timeline
|
package dev.usbharu.hideout.core.infrastructure.timeline
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.config.DefaultTimelineStoreConfig
|
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
|
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
import dev.usbharu.hideout.core.domain.model.filter.Filter
|
||||||
import dev.usbharu.hideout.core.domain.model.filter.FilterContext
|
import dev.usbharu.hideout.core.domain.model.filter.FilterContext
|
||||||
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
|
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
|
||||||
|
@ -9,6 +11,7 @@ import dev.usbharu.hideout.core.domain.model.filter.FilteredPost
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostId
|
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.post.Visibility
|
||||||
import dev.usbharu.hideout.core.domain.model.support.page.Page
|
import dev.usbharu.hideout.core.domain.model.support.page.Page
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||||
|
@ -16,10 +19,13 @@ import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObject
|
import dev.usbharu.hideout.core.domain.model.timelineobject.TimelineObject
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||||
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||||
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||||
import dev.usbharu.hideout.core.domain.service.filter.FilterDomainService
|
import dev.usbharu.hideout.core.domain.service.filter.FilterDomainService
|
||||||
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
open class DefaultTimelineStore(
|
open class DefaultTimelineStore(
|
||||||
|
@ -30,7 +36,9 @@ open class DefaultTimelineStore(
|
||||||
private val filterDomainService: FilterDomainService,
|
private val filterDomainService: FilterDomainService,
|
||||||
idGenerateService: IdGenerateService,
|
idGenerateService: IdGenerateService,
|
||||||
private val defaultTimelineStoreConfig: DefaultTimelineStoreConfig,
|
private val defaultTimelineStoreConfig: DefaultTimelineStoreConfig,
|
||||||
private val internalTimelineObjectRepository: InternalTimelineObjectRepository
|
private val internalTimelineObjectRepository: InternalTimelineObjectRepository,
|
||||||
|
private val userDetailRepository: UserDetailRepository,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) : AbstractTimelineStore(idGenerateService) {
|
) : AbstractTimelineStore(idGenerateService) {
|
||||||
override suspend fun getTimelines(actorId: ActorId): List<Timeline> {
|
override suspend fun getTimelines(actorId: ActorId): List<Timeline> {
|
||||||
return timelineRepository.findByIds(
|
return timelineRepository.findByIds(
|
||||||
|
@ -49,6 +57,10 @@ open class DefaultTimelineStore(
|
||||||
return filterRepository.findByUserDetailId(userDetailId)
|
return filterRepository.findByUserDetailId(userDetailId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getNewerFilters(userDetailId: UserDetailId, lastUpdateAt: Instant): List<Filter> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost {
|
override suspend fun applyFilters(post: Post, filters: List<Filter>): FilteredPost {
|
||||||
return filterDomainService.apply(post, FilterContext.HOME, filters)
|
return filterDomainService.apply(post, FilterContext.HOME, filters)
|
||||||
}
|
}
|
||||||
|
@ -81,11 +93,31 @@ open class DefaultTimelineStore(
|
||||||
internalTimelineObjectRepository.deleteByTimelineId(timelineId)
|
internalTimelineObjectRepository.deleteByTimelineId(timelineId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getPosts(timelineRelationshipList: List<TimelineRelationship>): List<Post> {
|
override suspend fun getPostsByTimelineRelationshipList(timelineRelationshipList: List<TimelineRelationship>): List<Post> {
|
||||||
return timelineRelationshipList.map { it.actorId }.flatMap { getActorPost(it) }
|
return timelineRelationshipList.flatMap { getActorPost(it.actorId, visibilities(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getActorPost(actorId: ActorId): List<Post> {
|
override suspend fun getPostsByPostId(postIds: List<PostId>): List<Post> {
|
||||||
return postRepository.findByActorId(actorId, Page.of(limit = defaultTimelineStoreConfig.actorPostsCount))
|
return postRepository.findAllById(postIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getTimelineObject(timelineId: TimelineId): List<TimelineObject> {
|
||||||
|
return internalTimelineObjectRepository.findByTimelineId(timelineId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getActorPost(actorId: ActorId, visibilityList: List<Visibility>): List<Post> {
|
||||||
|
return postRepository.findByActorIdAndVisibilityInList(
|
||||||
|
actorId,
|
||||||
|
visibilityList,
|
||||||
|
Page.of(limit = defaultTimelineStoreConfig.actorPostsCount)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getActors(actorIds: List<ActorId>): Map<ActorId, Actor> {
|
||||||
|
return actorRepository.findAllById(actorIds).associateBy { it.id }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getUserDetails(userDetailIdList: List<UserDetailId>): Map<UserDetailId, UserDetail> {
|
||||||
|
return userDetailRepository.findAllById(userDetailIdList).associateBy { it.id }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,4 +17,5 @@ interface InternalTimelineObjectRepository {
|
||||||
suspend fun deleteByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId)
|
suspend fun deleteByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId)
|
||||||
|
|
||||||
suspend fun deleteByTimelineId(timelineId: TimelineId)
|
suspend fun deleteByTimelineId(timelineId: TimelineId)
|
||||||
|
suspend fun findByTimelineId(timelineId: TimelineId): List<TimelineObject>
|
||||||
}
|
}
|
Loading…
Reference in New Issue