refactor: Pagination APIを追加

This commit is contained in:
usbharu 2024-01-29 19:22:08 +09:00
parent 592aba3edc
commit 7a116513b2
4 changed files with 129 additions and 8 deletions

View File

@ -1,5 +1,8 @@
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
import dev.usbharu.hideout.application.infrastructure.exposed.pagination
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
import dev.usbharu.hideout.core.infrastructure.exposedrepository.* import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
@ -108,6 +111,57 @@ class StatusQueryServiceImpl : StatusQueryService {
return resolveReplyAndRepost(pairs) return resolveReplyAndRepost(pairs)
} }
override suspend fun accountsStatus(
accountId: Long,
onlyMedia: Boolean,
excludeReplies: Boolean,
excludeReblogs: Boolean,
pinned: Boolean,
tagged: String?,
includeFollowers: Boolean,
page: Page
): PaginationList<Status, Long> {
val query = Posts
.leftJoin(PostsMedia)
.leftJoin(Actors)
.leftJoin(Media)
.select { Posts.actorId eq accountId }
query.pagination(page, Posts.id)
if (onlyMedia) {
query.andWhere { PostsMedia.mediaId.isNotNull() }
}
if (excludeReplies) {
query.andWhere { Posts.replyId.isNotNull() }
}
if (excludeReblogs) {
query.andWhere { Posts.repostId.isNotNull() }
}
if (includeFollowers) {
query.andWhere { Posts.visibility inList listOf(public.ordinal, unlisted.ordinal, private.ordinal) }
} else {
query.andWhere { Posts.visibility inList listOf(public.ordinal, unlisted.ordinal) }
}
val pairs = query.groupBy { it[Posts.id] }
.map { it.value }
.map {
toStatus(it.first()).copy(
mediaAttachments = it.mapNotNull { resultRow ->
resultRow.toMediaOrNull()?.toMediaAttachments()
}
) to it.first()[Posts.repostId]
}
val statuses = resolveReplyAndRepost(pairs)
return PaginationList(
statuses,
statuses.lastOrNull()?.id?.toLongOrNull(),
statuses.firstOrNull()?.id?.toLongOrNull()
)
}
override suspend fun findByPostId(id: Long): Status { override suspend fun findByPostId(id: Long): Status {
val map = Posts val map = Posts
.leftJoin(PostsMedia) .leftJoin(PostsMedia)

View File

@ -65,20 +65,31 @@ class MastodonAccountApiController(
tagged: String? tagged: String?
): ResponseEntity<Flow<Status>> = runBlocking { ): ResponseEntity<Flow<Status>> = runBlocking {
val userid = loginUserContextHolder.getLoginUserId() val userid = loginUserContextHolder.getLoginUserId()
val statusFlow = accountApiService.accountsStatuses( val statuses = accountApiService.accountsStatuses(
userid = id.toLong(), userid = id.toLong(),
maxId = maxId?.toLongOrNull(),
sinceId = sinceId?.toLongOrNull(),
minId = minId?.toLongOrNull(),
limit = limit,
onlyMedia = onlyMedia, onlyMedia = onlyMedia,
excludeReplies = excludeReplies, excludeReplies = excludeReplies,
excludeReblogs = excludeReblogs, excludeReblogs = excludeReblogs,
pinned = pinned, pinned = pinned,
tagged = tagged, tagged = tagged,
loginUser = userid loginUser = userid,
).asFlow() page = Page.of(
ResponseEntity.ok(statusFlow) maxId?.toLongOrNull(),
sinceId?.toLongOrNull(),
minId?.toLongOrNull(),
limit.coerceIn(0, 80) ?: 40
)
)
val httpHeader = statuses.toHttpHeader(
{ "${applicationConfig.url}/api/v1/follow_requests?max_id=$it" },
{ "${applicationConfig.url}/api/v1/follow_requests?min_id=$it" },
)
if (httpHeader != null) {
return@runBlocking ResponseEntity.ok().header("Link", httpHeader).body(statuses.asFlow())
}
ResponseEntity.ok(statuses.asFlow())
} }
override fun apiV1AccountsRelationshipsGet( override fun apiV1AccountsRelationshipsGet(

View File

@ -1,5 +1,7 @@
package dev.usbharu.hideout.mastodon.query package dev.usbharu.hideout.mastodon.query
import dev.usbharu.hideout.application.infrastructure.exposed.Page
import dev.usbharu.hideout.application.infrastructure.exposed.PaginationList
import dev.usbharu.hideout.domain.mastodon.model.generated.Status import dev.usbharu.hideout.domain.mastodon.model.generated.Status
import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery import dev.usbharu.hideout.mastodon.interfaces.api.status.StatusQuery
@ -37,5 +39,16 @@ interface StatusQueryService {
includeFollowers: Boolean = false includeFollowers: Boolean = false
): List<Status> ): List<Status>
suspend fun accountsStatus(
accountId: Long,
onlyMedia: Boolean = false,
excludeReplies: Boolean = false,
excludeReblogs: Boolean = false,
pinned: Boolean = false,
tagged: String?,
includeFollowers: Boolean = false,
page: Page
): PaginationList<Status, Long>
suspend fun findByPostId(id: Long): Status suspend fun findByPostId(id: Long): Status
} }

View File

@ -34,6 +34,17 @@ interface AccountApiService {
loginUser: Long? loginUser: Long?
): List<Status> ): List<Status>
suspend fun accountsStatuses(
userid: Long,
onlyMedia: Boolean,
excludeReplies: Boolean,
excludeReblogs: Boolean,
pinned: Boolean,
tagged: String?,
loginUser: Long?,
page: Page
): PaginationList<Status, Long>
suspend fun verifyCredentials(userid: Long): CredentialAccount suspend fun verifyCredentials(userid: Long): CredentialAccount
suspend fun registerAccount(userCreateDto: UserCreateDto): Unit suspend fun registerAccount(userCreateDto: UserCreateDto): Unit
suspend fun follow(loginUser: Long, followTargetUserId: Long): Relationship suspend fun follow(loginUser: Long, followTargetUserId: Long): Relationship
@ -115,6 +126,38 @@ class AccountApiServiceImpl(
} }
} }
override suspend fun accountsStatuses(
userid: Long,
onlyMedia: Boolean,
excludeReplies: Boolean,
excludeReblogs: Boolean,
pinned: Boolean,
tagged: String?,
loginUser: Long?,
page: Page
): PaginationList<Status, Long> {
val canViewFollowers = if (loginUser == null) {
false
} else {
transaction.transaction {
isFollowing(loginUser, userid)
}
}
return transaction.transaction {
statusQueryService.accountsStatus(
accountId = userid,
onlyMedia = onlyMedia,
excludeReplies = excludeReplies,
excludeReblogs = excludeReblogs,
pinned = pinned,
tagged = tagged,
includeFollowers = canViewFollowers,
page = page
)
}
}
override suspend fun verifyCredentials(userid: Long): CredentialAccount = transaction.transaction { override suspend fun verifyCredentials(userid: Long): CredentialAccount = transaction.transaction {
val account = accountService.findById(userid) val account = accountService.findById(userid)
from(account) from(account)