feat: その他のActivityPubプロセッサーを追加

This commit is contained in:
usbharu 2023-11-27 13:43:37 +09:00
parent 8757d059be
commit ac4aa8a231
9 changed files with 231 additions and 1 deletions

View File

@ -10,6 +10,7 @@ import dev.usbharu.hideout.core.service.user.UserService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Deprecated("use activitypub processor")
interface APAcceptService { interface APAcceptService {
suspend fun receiveAccept(accept: Accept) suspend fun receiveAccept(accept: Accept)
} }

View File

@ -0,0 +1,50 @@
package dev.usbharu.hideout.activitypub.service.activity.accept
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
import dev.usbharu.hideout.activitypub.domain.model.Accept
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.query.FollowerQueryService
import dev.usbharu.hideout.core.query.UserQueryService
import dev.usbharu.hideout.core.service.user.UserService
class ApAcceptProcessor(
private val transaction: Transaction,
private val userQueryService: UserQueryService,
private val followerQueryService: FollowerQueryService,
private val userService: UserService
) :
AbstractActivityPubProcessor<Accept>(transaction) {
override suspend fun internalProcess(activity: ActivityPubProcessContext<Accept>) {
val value = activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
if (value.type.contains("Follow").not()) {
logger.warn("FAILED Activity type is not Follow.")
throw IllegalActivityPubObjectException("Invalid type ${value.type}")
}
val follow = value as Follow
val userUrl = follow.`object` ?: throw IllegalActivityPubObjectException("object is null")
val followerUrl = follow.actor ?: throw IllegalActivityPubObjectException("actor is null")
val user = userQueryService.findByUrl(userUrl)
val follower = userQueryService.findByUrl(followerUrl)
if (followerQueryService.alreadyFollow(user.id, follower.id)) {
logger.debug("END User already follow from ${follower.url} to ${user.url}.")
return
}
userService.follow(user.id, follower.id)
logger.debug("SUCCESS Follow from ${follower.url} to ${user.url}.")
}
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Accept
override fun type(): Class<Accept> = Accept::class.java
}

View File

@ -0,0 +1,35 @@
package dev.usbharu.hideout.activitypub.service.activity.delete
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
import dev.usbharu.hideout.activitypub.domain.model.Delete
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
import dev.usbharu.hideout.core.domain.model.post.PostRepository
import dev.usbharu.hideout.core.query.PostQueryService
class APDeleteProcessor(
transaction: Transaction,
private val postQueryService: PostQueryService,
private val postRepository: PostRepository
) :
AbstractActivityPubProcessor<Delete>(transaction) {
override suspend fun internalProcess(activity: ActivityPubProcessContext<Delete>) {
val deleteId = activity.activity.`object`?.id ?: throw IllegalActivityPubObjectException("object.id is null")
val post = try {
postQueryService.findByApId(deleteId)
} catch (e: FailedToGetResourcesException) {
logger.warn("FAILED delete id: {} is not found.", deleteId)
return
}
postRepository.delete(post.id)
}
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Delete
override fun type(): Class<Delete> = Delete::class.java
}

View File

@ -0,0 +1,35 @@
package dev.usbharu.hideout.activitypub.service.activity.follow
import com.fasterxml.jackson.databind.ObjectMapper
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.external.job.ReceiveFollowJob
import dev.usbharu.hideout.core.external.job.ReceiveFollowJobParam
import dev.usbharu.hideout.core.service.job.JobQueueParentService
class APFollowProcessor(
transaction: Transaction,
private val jobQueueParentService: JobQueueParentService,
private val objectMapper: ObjectMapper
) :
AbstractActivityPubProcessor<Follow>(transaction) {
override suspend fun internalProcess(activity: ActivityPubProcessContext<Follow>) {
logger.info("FOLLOW from: {} to {}", activity.activity.actor, activity.activity.`object`)
// inboxをジョブキューに乗せているので既に不要だが、フォロー承認制アカウントを実装する際に必要なので残す
val jobProps = ReceiveFollowJobParam(
activity.activity.actor ?: throw IllegalActivityPubObjectException("actor is null"),
objectMapper.writeValueAsString(activity.activity),
activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
)
jobQueueParentService.scheduleTypeSafe(ReceiveFollowJob, jobProps)
}
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Follow
override fun type(): Class<Follow> = Follow::class.java
}

View File

@ -3,6 +3,7 @@ package dev.usbharu.hideout.activitypub.service.activity.follow
import dev.usbharu.hideout.core.external.job.ReceiveFollowJob import dev.usbharu.hideout.core.external.job.ReceiveFollowJob
import kjob.core.job.JobProps import kjob.core.job.JobProps
@Deprecated("use activitypub processor")
interface APReceiveFollowJobService { interface APReceiveFollowJobService {
suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>) suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>)
} }

View File

@ -16,6 +16,7 @@ import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
@Component @Component
@Deprecated("use activitypub processor")
class APReceiveFollowJobServiceImpl( class APReceiveFollowJobServiceImpl(
private val apUserService: APUserService, private val apUserService: APUserService,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,

View File

@ -0,0 +1,54 @@
package dev.usbharu.hideout.activitypub.service.activity.like
import dev.usbharu.hideout.activitypub.domain.exception.FailedToGetActivityPubResourceException
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
import dev.usbharu.hideout.activitypub.domain.model.Like
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteService
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.query.PostQueryService
import dev.usbharu.hideout.core.service.reaction.ReactionService
class APLikeProcessor(
transaction: Transaction,
private val apUserService: APUserService,
private val apNoteService: APNoteService,
private val postQueryService: PostQueryService,
private val reactionService: ReactionService
) :
AbstractActivityPubProcessor<Like>(transaction) {
override suspend fun internalProcess(activity: ActivityPubProcessContext<Like>) {
val actor = activity.activity.actor ?: throw IllegalActivityPubObjectException("actor is null")
val content = activity.activity.content ?: throw IllegalActivityPubObjectException("content is null")
val target = activity.activity.`object` ?: throw IllegalActivityPubObjectException("object is null")
val personWithEntity = apUserService.fetchPersonWithEntity(actor)
try {
apNoteService.fetchNoteAsync(target).await()
} catch (e: FailedToGetActivityPubResourceException) {
logger.debug("FAILED failed to get {}", target)
logger.trace("", e)
return
}
val post = postQueryService.findByUrl(target)
reactionService.receiveReaction(
content,
actor.substringAfter("://").substringBefore("/"),
personWithEntity.second.id,
post.id
)
logger.debug("SUCCESS Add Like($content) from ${personWithEntity.second.url} to ${post.url}")
}
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Like
override fun type(): Class<Like> = Like::class.java
}

View File

@ -0,0 +1,53 @@
package dev.usbharu.hideout.activitypub.service.activity.undo
import dev.usbharu.hideout.activitypub.domain.model.Follow
import dev.usbharu.hideout.activitypub.domain.model.Undo
import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcessor
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
import dev.usbharu.hideout.activitypub.service.common.ActivityType
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
import dev.usbharu.hideout.application.external.Transaction
import dev.usbharu.hideout.core.query.UserQueryService
import dev.usbharu.hideout.core.service.user.UserService
class APUndoProcessor(
transaction: Transaction,
private val apUserService: APUserService,
private val userQueryService: UserQueryService,
private val userService: UserService
) :
AbstractActivityPubProcessor<Undo>(transaction) {
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
val undo = activity.activity
if (undo.actor == null) {
return
}
val type =
undo.`object`?.type.orEmpty()
.firstOrNull { it == "Block" || it == "Follow" || it == "Like" || it == "Announce" || it == "Accept" }
?: return
when (type) {
"Follow" -> {
val follow = undo.`object` as Follow
if (follow.`object` == null) {
return
}
apUserService.fetchPerson(undo.actor!!, follow.`object`)
val follower = userQueryService.findByUrl(undo.actor!!)
val target = userQueryService.findByUrl(follow.`object`!!)
userService.unfollow(target.id, follower.id)
return
}
else -> {}
}
TODO()
}
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Undo
override fun type(): Class<Undo> = Undo::class.java
}

View File

@ -11,7 +11,7 @@ abstract class AbstractActivityPubProcessor<T : Object>(
private val transaction: Transaction, private val transaction: Transaction,
private val allowUnauthorized: Boolean = false private val allowUnauthorized: Boolean = false
) : ActivityPubProcessor<T> { ) : ActivityPubProcessor<T> {
private val logger = LoggerFactory.getLogger(this::class.java) protected val logger = LoggerFactory.getLogger(this::class.java)
override suspend fun process(activity: ActivityPubProcessContext<T>) { override suspend fun process(activity: ActivityPubProcessContext<T>) {
if (activity.isAuthorized.not() && allowUnauthorized.not()) { if (activity.isAuthorized.not() && allowUnauthorized.not()) {