mirror of https://github.com/usbharu/Hideout.git
wip
This commit is contained in:
parent
992cc18c62
commit
0463ad6b69
|
@ -15,7 +15,7 @@ data class ActorDetail(
|
||||||
val iconUrl: URI?,
|
val iconUrl: URI?,
|
||||||
val bannerURL: URI?,
|
val bannerURL: URI?,
|
||||||
val followingCount: Int?,
|
val followingCount: Int?,
|
||||||
val followersCount: Int?
|
val followersCount: Int?,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun of(actor: Actor, iconUrl: URI?, bannerURL: URI?): ActorDetail {
|
fun of(actor: Actor, iconUrl: URI?, bannerURL: URI?): ActorDetail {
|
||||||
|
@ -31,7 +31,7 @@ data class ActorDetail(
|
||||||
iconUrl = iconUrl,
|
iconUrl = iconUrl,
|
||||||
bannerURL = bannerURL,
|
bannerURL = bannerURL,
|
||||||
followingCount = actor.followingCount?.relationshipCount,
|
followingCount = actor.followingCount?.relationshipCount,
|
||||||
followersCount = actor.followersCount?.relationshipCount
|
followersCount = actor.followersCount?.relationshipCount,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.usbharu.hideout.core.application.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.page.Page
|
||||||
|
|
||||||
|
data class GetUserTimeline(val id: Long, val page: Page)
|
|
@ -0,0 +1,49 @@
|
||||||
|
package dev.usbharu.hideout.core.application.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.post.PostDetail
|
||||||
|
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
|
||||||
|
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||||
|
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.Visibility
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.page.PaginationList
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||||
|
import dev.usbharu.hideout.core.query.usertimeline.UserTimelineQueryService
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class GetUserTimelineApplicationService(
|
||||||
|
private val userTimelineQueryService: UserTimelineQueryService,
|
||||||
|
private val postRepository: PostRepository,
|
||||||
|
transaction: Transaction
|
||||||
|
) :
|
||||||
|
AbstractApplicationService<GetUserTimeline, PaginationList<PostDetail, PostId>>(transaction, logger) {
|
||||||
|
override suspend fun internalExecute(
|
||||||
|
command: GetUserTimeline,
|
||||||
|
principal: Principal
|
||||||
|
): PaginationList<PostDetail, PostId> {
|
||||||
|
val postList = postRepository.findByActorIdAndVisibilityInList(
|
||||||
|
ActorId(command.id),
|
||||||
|
listOf(Visibility.PUBLIC, Visibility.UNLISTED, Visibility.FOLLOWERS),
|
||||||
|
command.page
|
||||||
|
)
|
||||||
|
|
||||||
|
val postIdList =
|
||||||
|
postList.mapNotNull { it.repostId } + postList.mapNotNull { it.replyId } + postList.map { it.id }
|
||||||
|
|
||||||
|
val postDetailMap = userTimelineQueryService.findByIdAll(postIdList, principal).associateBy { it.id }
|
||||||
|
|
||||||
|
return PaginationList(postList.mapNotNull {
|
||||||
|
postDetailMap[it.id.id]?.copy(
|
||||||
|
repost = postDetailMap[it.repostId?.id],
|
||||||
|
reply = postDetailMap[it.replyId?.id]
|
||||||
|
)
|
||||||
|
}, postList.next, postList.prev)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(GetUserTimelineApplicationService::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.post.ActorDetail
|
||||||
|
import dev.usbharu.hideout.core.application.post.MediaDetail
|
||||||
|
import dev.usbharu.hideout.core.application.post.PostDetail
|
||||||
|
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.principal.Principal
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
||||||
|
import dev.usbharu.hideout.core.query.usertimeline.UserTimelineQueryService
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
class ExposedUserTimelineQueryService : UserTimelineQueryService, AbstractRepository() {
|
||||||
|
|
||||||
|
protected fun authorizedQuery(principal: Principal? = null): QueryAlias {
|
||||||
|
if (principal == null) {
|
||||||
|
return Posts
|
||||||
|
.selectAll()
|
||||||
|
.where {
|
||||||
|
Posts.visibility eq Visibility.PUBLIC.name or (Posts.visibility eq Visibility.UNLISTED.name)
|
||||||
|
}.alias("authorized_table")
|
||||||
|
}
|
||||||
|
|
||||||
|
val relationshipsAlias = Relationships.alias("inverse_relationships")
|
||||||
|
|
||||||
|
return Posts
|
||||||
|
.leftJoin(PostsVisibleActors)
|
||||||
|
.leftJoin(Relationships, onColumn = { Posts.actorId }, otherColumn = { actorId })
|
||||||
|
.leftJoin(
|
||||||
|
relationshipsAlias,
|
||||||
|
onColumn = { Posts.actorId },
|
||||||
|
otherColumn = { relationshipsAlias[Relationships.targetActorId] }
|
||||||
|
)
|
||||||
|
.select(Posts.columns)
|
||||||
|
.where {
|
||||||
|
Posts.visibility eq Visibility.PUBLIC.name or
|
||||||
|
(Posts.visibility eq Visibility.UNLISTED.name) or
|
||||||
|
(Posts.visibility eq Visibility.DIRECT.name and (PostsVisibleActors.actorId eq principal.actorId.id)) or
|
||||||
|
(Posts.visibility eq Visibility.FOLLOWERS.name and (Relationships.blocking eq false and (relationshipsAlias[Relationships.following] eq true))) or
|
||||||
|
(Posts.actorId eq principal.actorId.id)
|
||||||
|
}
|
||||||
|
.alias("authorized_table")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByIdAll(idList: List<PostId>, principal: Principal): List<PostDetail> {
|
||||||
|
val authorizedQuery = authorizedQuery(principal)
|
||||||
|
|
||||||
|
val iconMedia = Media.alias("ICON_MEDIA")
|
||||||
|
|
||||||
|
return authorizedQuery
|
||||||
|
.leftJoin(PostsVisibleActors, { authorizedQuery[Posts.id] }, { PostsVisibleActors.postId })
|
||||||
|
.leftJoin(Actors, { authorizedQuery[Posts.actorId] }, { Actors.id })
|
||||||
|
.leftJoin(iconMedia, { Actors.icon }, { iconMedia[Media.id] })
|
||||||
|
.leftJoin(PostsMedia, { authorizedQuery[Posts.id] }, { PostsMedia.postId })
|
||||||
|
.leftJoin(Media, { PostsMedia.mediaId }, { Media.id })
|
||||||
|
.selectAll()
|
||||||
|
.where { authorizedQuery[Posts.id] inList idList.map { it.id } }
|
||||||
|
.groupBy { it[authorizedQuery[Posts.id]] }
|
||||||
|
.map { it.value }
|
||||||
|
.map {
|
||||||
|
toPostDetail(it.first(), authorizedQuery, iconMedia).copy(
|
||||||
|
mediaDetailList = it.mapNotNull { resultRow ->
|
||||||
|
resultRow.toMediaOrNull()?.let { it1 -> MediaDetail.of(it1) }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toPostDetail(it: ResultRow, authorizedQuery: QueryAlias, iconMedia: Alias<Media>): PostDetail {
|
||||||
|
return PostDetail(
|
||||||
|
it[authorizedQuery[Posts.id]],
|
||||||
|
ActorDetail(
|
||||||
|
actorId = it[authorizedQuery[Posts.actorId]],
|
||||||
|
instanceId = it[Actors.instance],
|
||||||
|
name = it[Actors.name],
|
||||||
|
domain = it[Actors.domain],
|
||||||
|
screenName = it[Actors.screenName],
|
||||||
|
url = URI.create(it[Actors.url]),
|
||||||
|
locked = it[Actors.locked],
|
||||||
|
icon = it.getOrNull(iconMedia[Media.url])?.let { URI.create(it) }
|
||||||
|
),
|
||||||
|
overview = it[authorizedQuery[Posts.overview]],
|
||||||
|
text = it[authorizedQuery[Posts.text]],
|
||||||
|
content = it[authorizedQuery[Posts.content]],
|
||||||
|
createdAt = it[authorizedQuery[Posts.createdAt]],
|
||||||
|
visibility = Visibility.valueOf(it[authorizedQuery[Posts.visibility]]),
|
||||||
|
pureRepost = false,
|
||||||
|
url = URI.create(it[authorizedQuery[Posts.url]]),
|
||||||
|
apId = URI.create(it[authorizedQuery[Posts.apId]]),
|
||||||
|
repost = null,
|
||||||
|
reply = null,
|
||||||
|
sensitive = it[authorizedQuery[Posts.sensitive]],
|
||||||
|
deleted = it[authorizedQuery[Posts.deleted]],
|
||||||
|
mediaDetailList = emptyList(),
|
||||||
|
moveTo = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ExposedUserTimelineQueryService::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -211,17 +211,38 @@ class ExposedPostRepository(
|
||||||
visibilityList: List<Visibility>,
|
visibilityList: List<Visibility>,
|
||||||
of: Page?
|
of: Page?
|
||||||
): PaginationList<Post, PostId> {
|
): PaginationList<Post, PostId> {
|
||||||
|
val postList = query {
|
||||||
|
val query = Posts
|
||||||
|
.selectAll()
|
||||||
|
.where {
|
||||||
|
Posts.actorId eq actorId.id and (visibility inList visibilityList.map { it.name })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (of?.minId != null) {
|
||||||
|
query.orderBy(Posts.createdAt, SortOrder.ASC)
|
||||||
|
of.minId?.let { query.andWhere { Posts.id greater it } }
|
||||||
|
of.maxId?.let { query.andWhere { Posts.id less it } }
|
||||||
|
} else {
|
||||||
|
query.orderBy(Posts.createdAt, SortOrder.DESC)
|
||||||
|
of?.sinceId?.let { query.andWhere { Posts.id greater it } }
|
||||||
|
of?.maxId?.let { query.andWhere { Posts.id less it } }
|
||||||
|
}
|
||||||
|
|
||||||
|
of?.limit?.let { query.limit(it) }
|
||||||
|
|
||||||
|
query.let(postQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
val posts = if (of?.minId != null) {
|
||||||
|
postList.reversed()
|
||||||
|
} else {
|
||||||
|
postList
|
||||||
|
}
|
||||||
|
|
||||||
return PaginationList(
|
return PaginationList(
|
||||||
query {
|
posts,
|
||||||
Posts
|
posts.lastOrNull()?.id,
|
||||||
.selectAll()
|
posts.firstOrNull()?.id
|
||||||
.where {
|
|
||||||
Posts.actorId eq actorId.id and (visibility inList visibilityList.map { it.name })
|
|
||||||
}
|
|
||||||
.let(postQueryMapper::map)
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,23 @@ fun ResultRow.toMedia(): EntityMedia {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ResultRow.toMediaOrNull(): EntityMedia? {
|
||||||
|
val fileType = FileType.valueOf(this.getOrNull(Media.type) ?: return null)
|
||||||
|
val mimeType = this.getOrNull(Media.mimeType) ?: return null
|
||||||
|
return EntityMedia(
|
||||||
|
id = MediaId(this.getOrNull(Media.id) ?: return null),
|
||||||
|
name = MediaName(this.getOrNull(Media.name) ?: return null),
|
||||||
|
url = URI.create(this.getOrNull(Media.url) ?: return null),
|
||||||
|
remoteUrl = this[Media.remoteUrl]?.let { URI.create(it) },
|
||||||
|
thumbnailUrl = this[Media.thumbnailUrl]?.let { URI.create(it) },
|
||||||
|
type = FileType.valueOf(this[Media.type]),
|
||||||
|
blurHash = this[Media.blurhash]?.let { MediaBlurHash(it) },
|
||||||
|
mimeType = MimeType(mimeType.substringBefore("/"), mimeType.substringAfter("/"), fileType),
|
||||||
|
description = this[Media.description]?.let { MediaDescription(it) },
|
||||||
|
actorId = ActorId(this[Media.actorId])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
object Media : Table("media") {
|
object Media : Table("media") {
|
||||||
val id = long("id")
|
val id = long("id")
|
||||||
val name = varchar("name", 255)
|
val name = varchar("name", 255)
|
||||||
|
|
|
@ -3,28 +3,48 @@ package dev.usbharu.hideout.core.interfaces.web.user
|
||||||
import dev.usbharu.hideout.core.application.actor.GetActorDetail
|
import dev.usbharu.hideout.core.application.actor.GetActorDetail
|
||||||
import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService
|
import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService
|
||||||
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService
|
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService
|
||||||
|
import dev.usbharu.hideout.core.application.timeline.GetUserTimeline
|
||||||
|
import dev.usbharu.hideout.core.application.timeline.GetUserTimelineApplicationService
|
||||||
import dev.usbharu.hideout.core.domain.model.support.acct.Acct
|
import dev.usbharu.hideout.core.domain.model.support.acct.Acct
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.page.Page
|
||||||
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
|
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.ui.Model
|
import org.springframework.ui.Model
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.PathVariable
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class UserController(
|
class UserController(
|
||||||
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
|
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
|
||||||
private val getUserDetailApplicationService: GetActorDetailApplicationService,
|
private val getUserDetailApplicationService: GetActorDetailApplicationService,
|
||||||
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder,
|
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder,
|
||||||
|
private val getUserTimelineApplicationService: GetUserTimelineApplicationService
|
||||||
) {
|
) {
|
||||||
@GetMapping("/users/{name}")
|
@GetMapping("/users/{name}")
|
||||||
suspend fun userById(@PathVariable name: String, model: Model): String {
|
suspend fun userById(
|
||||||
|
@PathVariable name: String,
|
||||||
|
@RequestParam minId: Long?,
|
||||||
|
@RequestParam maxId: Long?,
|
||||||
|
@RequestParam sinceId: Long?,
|
||||||
|
model: Model
|
||||||
|
): String {
|
||||||
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal()
|
||||||
|
|
||||||
model.addAttribute("instance", getLocalInstanceApplicationService.execute(Unit, Anonymous))
|
model.addAttribute("instance", getLocalInstanceApplicationService.execute(Unit, Anonymous))
|
||||||
|
val actorDetail = getUserDetailApplicationService.execute(GetActorDetail(Acct.of(name)), principal)
|
||||||
model.addAttribute(
|
model.addAttribute(
|
||||||
"user",
|
"user",
|
||||||
getUserDetailApplicationService.execute(GetActorDetail(Acct.of(name)), principal)
|
actorDetail
|
||||||
|
)
|
||||||
|
model.addAttribute(
|
||||||
|
"userTimeline", getUserTimelineApplicationService.execute(
|
||||||
|
GetUserTimeline(
|
||||||
|
actorDetail.id,
|
||||||
|
Page.of(maxId, sinceId, minId, 20)
|
||||||
|
), principal
|
||||||
|
)
|
||||||
)
|
)
|
||||||
return "userById"
|
return "userById"
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.usbharu.hideout.core.query.usertimeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.post.PostDetail
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.PostId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
|
||||||
|
|
||||||
|
interface UserTimelineQueryService {
|
||||||
|
/**
|
||||||
|
* replyやrepost等はnullになります
|
||||||
|
*/
|
||||||
|
suspend fun findByIdAll(idList: List<PostId>, principal: Principal): List<PostDetail>
|
||||||
|
}
|
|
@ -22,4 +22,7 @@ post-form.new-posts-form-label=\u4ECA\u306A\u306B\u3057\u3066\u308B?
|
||||||
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
||||||
post.repost=\u30EA\u30DD\u30B9\u30C8
|
post.repost=\u30EA\u30DD\u30B9\u30C8
|
||||||
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
||||||
|
user-by-id.followersCount={0} \u30D5\u30A9\u30ED\u30EF\u30FC
|
||||||
|
user-by-id.followingCount={0} \u30D5\u30A9\u30ED\u30FC\u4E2D
|
||||||
|
user-by-id.postsCount={0} \u6295\u7A3F
|
||||||
user-by-id.title={0} \u3055\u3093 - {1}
|
user-by-id.title={0} \u3055\u3093 - {1}
|
|
@ -20,4 +20,7 @@ post-form.new-posts-cw-title=Add content warning
|
||||||
post-form.new-posts-form-label=What's on your mind?
|
post-form.new-posts-form-label=What's on your mind?
|
||||||
post-form.new-posts-submit=Submit!
|
post-form.new-posts-submit=Submit!
|
||||||
post.repost=Repost
|
post.repost=Repost
|
||||||
post.repost-by=Repost by {0}
|
post.repost-by=Repost by {0}
|
||||||
|
user-by-id.followersCount={0} Followers
|
||||||
|
user-by-id.followingCount={0} Following
|
||||||
|
user-by-id.postsCount={0} Posts
|
|
@ -22,4 +22,7 @@ post-form.new-posts-form-label=\u4ECA\u306A\u306B\u3057\u3066\u308B?
|
||||||
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
post-form.new-posts-submit=\u6295\u7A3F\u3059\u308B
|
||||||
post.repost=\u30EA\u30DD\u30B9\u30C8
|
post.repost=\u30EA\u30DD\u30B9\u30C8
|
||||||
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
post.repost-by={0}\u304C\u30EA\u30DD\u30B9\u30C8
|
||||||
|
user-by-id.followersCount={0} \u30D5\u30A9\u30ED\u30EF\u30FC
|
||||||
|
user-by-id.followingCount={0} \u30D5\u30A9\u30ED\u30FC\u4E2D
|
||||||
|
user-by-id.postsCount={0} \u6295\u7A3F
|
||||||
user-by-id.title={0} \u3055\u3093 - {1}
|
user-by-id.title={0} \u3055\u3093 - {1}
|
|
@ -7,8 +7,31 @@
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<div>
|
<div>
|
||||||
<img th:src="user.icon">
|
<img height="150px" th:src="${user.iconUrl}" width="150px">
|
||||||
|
<img height="150px" th:src="${user.bannerURL}" width="600px">
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<th:block th:if="${user.locked}">
|
||||||
|
<h2 th:text="${user.screenName} + '(private)'"></h2>
|
||||||
|
</th:block>
|
||||||
|
|
||||||
|
<th:block th:if="!${user.locked}">
|
||||||
|
<h2 th:text="${user.screenName}"></h2>
|
||||||
|
</th:block>
|
||||||
|
<p th:text="${user.name} + '@' + ${user.host}"></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p th:text="${user.description}"></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p th:if="user.postsCount != null" th:text="#{user-by-id.postsCount(${user.postsCount})}">0 Posts</p>
|
||||||
|
<p th:if="user.followingCount != null" th:text="#{user-by-id.followingCount(${user.followingCount})}">0
|
||||||
|
Following</p>
|
||||||
|
<p th:if="user.followersCount != null" th:text="#{user-by-id.followersCount(${user.followersCount})}">0
|
||||||
|
Followers</p>
|
||||||
|
</div>
|
||||||
|
<div th:replace="~{fragments-timeline :: simple-timline(${userTimeline},'/users/'+${user.name}+'@'+${user.host})}"></div>
|
||||||
|
|
||||||
</noscript>
|
</noscript>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -16,9 +16,8 @@
|
||||||
|
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
|
||||||
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.*
|
import dev.usbharu.hideout.core.domain.model.media.FileType
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
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.infrastructure.exposedrepository.*
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
||||||
|
@ -30,7 +29,6 @@ import dev.usbharu.hideout.mastodon.query.StatusQuery
|
||||||
import dev.usbharu.hideout.mastodon.query.StatusQueryService
|
import dev.usbharu.hideout.mastodon.query.StatusQueryService
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import java.net.URI
|
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
|
import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
|
||||||
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.CustomEmoji as MastodonEmoji
|
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.CustomEmoji as MastodonEmoji
|
||||||
|
|
||||||
|
@ -274,40 +272,6 @@ private fun toStatus(it: ResultRow, queryAlias: QueryAlias, inReplyToAlias: Alia
|
||||||
editedAt = null
|
editedAt = null
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ResultRow.toMedia(): EntityMedia {
|
|
||||||
val fileType = FileType.valueOf(this[Media.type])
|
|
||||||
val mimeType = this[Media.mimeType]
|
|
||||||
return EntityMedia(
|
|
||||||
id = MediaId(this[Media.id]),
|
|
||||||
name = MediaName(this[Media.name]),
|
|
||||||
url = URI.create(this[Media.url]),
|
|
||||||
remoteUrl = this[Media.remoteUrl]?.let { URI.create(it) },
|
|
||||||
thumbnailUrl = this[Media.thumbnailUrl]?.let { URI.create(it) },
|
|
||||||
type = fileType,
|
|
||||||
blurHash = this[Media.blurhash]?.let { MediaBlurHash(it) },
|
|
||||||
mimeType = MimeType(mimeType.substringBefore("/"), mimeType.substringAfter("/"), fileType),
|
|
||||||
description = this[Media.description]?.let { MediaDescription(it) },
|
|
||||||
actorId = ActorId(this[Media.actorId])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ResultRow.toMediaOrNull(): EntityMedia? {
|
|
||||||
val fileType = FileType.valueOf(this.getOrNull(Media.type) ?: return null)
|
|
||||||
val mimeType = this.getOrNull(Media.mimeType) ?: return null
|
|
||||||
return EntityMedia(
|
|
||||||
id = MediaId(this.getOrNull(Media.id) ?: return null),
|
|
||||||
name = MediaName(this.getOrNull(Media.name) ?: return null),
|
|
||||||
url = URI.create(this.getOrNull(Media.url) ?: return null),
|
|
||||||
remoteUrl = this[Media.remoteUrl]?.let { URI.create(it) },
|
|
||||||
thumbnailUrl = this[Media.thumbnailUrl]?.let { URI.create(it) },
|
|
||||||
type = FileType.valueOf(this[Media.type]),
|
|
||||||
blurHash = this[Media.blurhash]?.let { MediaBlurHash(it) },
|
|
||||||
mimeType = MimeType(mimeType.substringBefore("/"), mimeType.substringAfter("/"), fileType),
|
|
||||||
description = this[Media.description]?.let { MediaDescription(it) },
|
|
||||||
actorId = ActorId(this[Media.actorId])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun EntityMedia.toMediaAttachments(): MediaAttachment = MediaAttachment(
|
fun EntityMedia.toMediaAttachments(): MediaAttachment = MediaAttachment(
|
||||||
id = id.id.toString(),
|
id = id.id.toString(),
|
||||||
type = when (type) {
|
type = when (type) {
|
||||||
|
|
Loading…
Reference in New Issue