mirror of https://github.com/usbharu/Hideout.git
feat: メディア付き投稿を配送可能に
This commit is contained in:
parent
db517cf288
commit
216ee78da0
|
@ -0,0 +1,48 @@
|
||||||
|
package dev.usbharu.hideout.domain.model.ap
|
||||||
|
|
||||||
|
class Document : Object {
|
||||||
|
|
||||||
|
var mediaType: String? = null
|
||||||
|
var url: String? = null
|
||||||
|
|
||||||
|
protected constructor() : super()
|
||||||
|
constructor(
|
||||||
|
type: List<String> = emptyList(),
|
||||||
|
name: String? = null,
|
||||||
|
mediaType: String,
|
||||||
|
url: String
|
||||||
|
) : super(
|
||||||
|
type = add(type, "Document"),
|
||||||
|
name = name,
|
||||||
|
actor = null,
|
||||||
|
id = null
|
||||||
|
) {
|
||||||
|
this.mediaType = mediaType
|
||||||
|
this.url = url
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (other !is Document) return false
|
||||||
|
if (!super.equals(other)) return false
|
||||||
|
|
||||||
|
if (mediaType != other.mediaType) return false
|
||||||
|
if (url != other.url) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = super.hashCode()
|
||||||
|
result = 31 * result + (mediaType?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + (url?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Document(mediaType=$mediaType, url=$url) ${super.toString()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package dev.usbharu.hideout.domain.model.ap
|
||||||
|
|
||||||
open class Note : Object {
|
open class Note : Object {
|
||||||
var attributedTo: String? = null
|
var attributedTo: String? = null
|
||||||
|
var attachment: List<Document> = emptyList()
|
||||||
var content: String? = null
|
var content: String? = null
|
||||||
var published: String? = null
|
var published: String? = null
|
||||||
var to: List<String> = emptyList()
|
var to: List<String> = emptyList()
|
||||||
|
@ -22,7 +23,8 @@ open class Note : Object {
|
||||||
to: List<String> = emptyList(),
|
to: List<String> = emptyList(),
|
||||||
cc: List<String> = emptyList(),
|
cc: List<String> = emptyList(),
|
||||||
sensitive: Boolean = false,
|
sensitive: Boolean = false,
|
||||||
inReplyTo: String? = null
|
inReplyTo: String? = null,
|
||||||
|
attachment: List<Document> = emptyList()
|
||||||
) : super(
|
) : super(
|
||||||
type = add(type, "Note"),
|
type = add(type, "Note"),
|
||||||
name = name,
|
name = name,
|
||||||
|
@ -35,30 +37,43 @@ open class Note : Object {
|
||||||
this.cc = cc
|
this.cc = cc
|
||||||
this.sensitive = sensitive
|
this.sensitive = sensitive
|
||||||
this.inReplyTo = inReplyTo
|
this.inReplyTo = inReplyTo
|
||||||
|
this.attachment = attachment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other !is Note) return false
|
if (other !is Note) return false
|
||||||
if (!super.equals(other)) return false
|
if (!super.equals(other)) return false
|
||||||
|
|
||||||
if (id != other.id) return false
|
|
||||||
if (attributedTo != other.attributedTo) return false
|
if (attributedTo != other.attributedTo) return false
|
||||||
|
if (attachment != other.attachment) return false
|
||||||
if (content != other.content) return false
|
if (content != other.content) return false
|
||||||
if (published != other.published) return false
|
if (published != other.published) return false
|
||||||
return to == other.to
|
if (to != other.to) return false
|
||||||
|
if (cc != other.cc) return false
|
||||||
|
if (sensitive != other.sensitive) return false
|
||||||
|
if (inReplyTo != other.inReplyTo) return false
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + (id?.hashCode() ?: 0)
|
|
||||||
result = 31 * result + (attributedTo?.hashCode() ?: 0)
|
result = 31 * result + (attributedTo?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + attachment.hashCode()
|
||||||
result = 31 * result + (content?.hashCode() ?: 0)
|
result = 31 * result + (content?.hashCode() ?: 0)
|
||||||
result = 31 * result + (published?.hashCode() ?: 0)
|
result = 31 * result + (published?.hashCode() ?: 0)
|
||||||
result = 31 * result + to.hashCode()
|
result = 31 * result + to.hashCode()
|
||||||
|
result = 31 * result + cc.hashCode()
|
||||||
|
result = 31 * result + sensitive.hashCode()
|
||||||
|
result = 31 * result + (inReplyTo?.hashCode() ?: 0)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String =
|
override fun toString(): String {
|
||||||
"Note(id=$id, attributedTo=$attributedTo, content=$content, published=$published, to=$to) ${super.toString()}"
|
return "Note(attributedTo=$attributedTo, attachment=$attachment, content=$content, published=$published, to=$to, cc=$cc, sensitive=$sensitive, inReplyTo=$inReplyTo) ${super.toString()}"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class ObjectDeserializer : JsonDeserializer<Object>() {
|
||||||
ExtendedActivityVocabulary.Service -> TODO()
|
ExtendedActivityVocabulary.Service -> TODO()
|
||||||
ExtendedActivityVocabulary.Article -> TODO()
|
ExtendedActivityVocabulary.Article -> TODO()
|
||||||
ExtendedActivityVocabulary.Audio -> TODO()
|
ExtendedActivityVocabulary.Audio -> TODO()
|
||||||
ExtendedActivityVocabulary.Document -> TODO()
|
ExtendedActivityVocabulary.Document -> p.codec.treeToValue(treeNode, Document::class.java)
|
||||||
ExtendedActivityVocabulary.Event -> TODO()
|
ExtendedActivityVocabulary.Event -> TODO()
|
||||||
ExtendedActivityVocabulary.Image -> p.codec.treeToValue(treeNode, Image::class.java)
|
ExtendedActivityVocabulary.Image -> p.codec.treeToValue(treeNode, Image::class.java)
|
||||||
ExtendedActivityVocabulary.Page -> TODO()
|
ExtendedActivityVocabulary.Page -> TODO()
|
||||||
|
|
|
@ -18,6 +18,7 @@ object DeliverPostJob : HideoutJob("DeliverPostJob") {
|
||||||
val post: Prop<DeliverPostJob, String> = string("post")
|
val post: Prop<DeliverPostJob, String> = string("post")
|
||||||
val actor: Prop<DeliverPostJob, String> = string("actor")
|
val actor: Prop<DeliverPostJob, String> = string("actor")
|
||||||
val inbox: Prop<DeliverPostJob, String> = string("inbox")
|
val inbox: Prop<DeliverPostJob, String> = string("inbox")
|
||||||
|
val media: Prop<DeliverPostJob, String> = string("media")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Media
|
||||||
|
|
||||||
|
interface MediaQueryService {
|
||||||
|
suspend fun findByPostId(postId: Long): List<Media>
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Media
|
||||||
|
import dev.usbharu.hideout.repository.PostsMedia
|
||||||
|
import dev.usbharu.hideout.repository.toMedia
|
||||||
|
import org.jetbrains.exposed.sql.innerJoin
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
class MediaQueryServiceImpl : MediaQueryService {
|
||||||
|
override suspend fun findByPostId(postId: Long): List<Media> {
|
||||||
|
return dev.usbharu.hideout.repository.Media.innerJoin(PostsMedia, onColumn = { id }, otherColumn = { mediaId })
|
||||||
|
.select { PostsMedia.postId eq postId }
|
||||||
|
.map { it.toMedia() }
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.ApplicationConfig
|
import dev.usbharu.hideout.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.domain.model.ap.Create
|
import dev.usbharu.hideout.domain.model.ap.Create
|
||||||
|
import dev.usbharu.hideout.domain.model.ap.Document
|
||||||
import dev.usbharu.hideout.domain.model.ap.Note
|
import dev.usbharu.hideout.domain.model.ap.Note
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
|
@ -13,6 +14,7 @@ import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
import dev.usbharu.hideout.plugins.getAp
|
import dev.usbharu.hideout.plugins.getAp
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
import dev.usbharu.hideout.query.FollowerQueryService
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.MediaQueryService
|
||||||
import dev.usbharu.hideout.query.PostQueryService
|
import dev.usbharu.hideout.query.PostQueryService
|
||||||
import dev.usbharu.hideout.query.UserQueryService
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.PostRepository
|
import dev.usbharu.hideout.repository.PostRepository
|
||||||
|
@ -46,6 +48,7 @@ class APNoteServiceImpl(
|
||||||
private val userQueryService: UserQueryService,
|
private val userQueryService: UserQueryService,
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val postQueryService: PostQueryService,
|
private val postQueryService: PostQueryService,
|
||||||
|
private val mediaQueryService: MediaQueryService,
|
||||||
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val postService: PostService
|
private val postService: PostService
|
||||||
|
@ -62,11 +65,13 @@ class APNoteServiceImpl(
|
||||||
val followers = followerQueryService.findFollowersById(post.userId)
|
val followers = followerQueryService.findFollowersById(post.userId)
|
||||||
val userEntity = userQueryService.findById(post.userId)
|
val userEntity = userQueryService.findById(post.userId)
|
||||||
val note = objectMapper.writeValueAsString(post)
|
val note = objectMapper.writeValueAsString(post)
|
||||||
|
val mediaList = objectMapper.writeValueAsString(mediaQueryService.findByPostId(post.id))
|
||||||
followers.forEach { followerEntity ->
|
followers.forEach { followerEntity ->
|
||||||
jobQueueParentService.schedule(DeliverPostJob) {
|
jobQueueParentService.schedule(DeliverPostJob) {
|
||||||
props[DeliverPostJob.actor] = userEntity.url
|
props[DeliverPostJob.actor] = userEntity.url
|
||||||
props[DeliverPostJob.post] = note
|
props[DeliverPostJob.post] = note
|
||||||
props[DeliverPostJob.inbox] = followerEntity.inbox
|
props[DeliverPostJob.inbox] = followerEntity.inbox
|
||||||
|
props[DeliverPostJob.media] = mediaList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,13 +79,17 @@ class APNoteServiceImpl(
|
||||||
override suspend fun createNoteJob(props: JobProps<DeliverPostJob>) {
|
override suspend fun createNoteJob(props: JobProps<DeliverPostJob>) {
|
||||||
val actor = props[DeliverPostJob.actor]
|
val actor = props[DeliverPostJob.actor]
|
||||||
val postEntity = objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
val postEntity = objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
||||||
|
val mediaList =
|
||||||
|
objectMapper.readValue<List<dev.usbharu.hideout.domain.model.hideout.entity.Media>>(props[DeliverPostJob.media])
|
||||||
val note = Note(
|
val note = Note(
|
||||||
name = "Note",
|
name = "Note",
|
||||||
id = postEntity.url,
|
id = postEntity.url,
|
||||||
attributedTo = actor,
|
attributedTo = actor,
|
||||||
content = postEntity.text,
|
content = postEntity.text,
|
||||||
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
|
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
|
||||||
to = listOf(public, "$actor/follower")
|
to = listOf(public, "$actor/follower"),
|
||||||
|
attachment = mediaList.map { Document(mediaType = "image/jpeg", url = it.url) }
|
||||||
|
|
||||||
)
|
)
|
||||||
val inbox = props[DeliverPostJob.inbox]
|
val inbox = props[DeliverPostJob.inbox]
|
||||||
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
|
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
|
||||||
|
|
Loading…
Reference in New Issue