refactor: PostのQueryServiceを追加

This commit is contained in:
usbharu 2023-08-10 20:29:18 +09:00
parent a6658e9117
commit 5a5be82c50
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
8 changed files with 65 additions and 38 deletions

View File

@ -0,0 +1,9 @@
package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.Post
interface PostQueryService {
suspend fun findById(id: Long): Post
suspend fun findByUrl(url: String): Post
suspend fun findByApId(string: String): Post
}

View File

@ -0,0 +1,16 @@
package dev.usbharu.hideout.query
import dev.usbharu.hideout.domain.model.hideout.entity.Post
import dev.usbharu.hideout.repository.Posts
import dev.usbharu.hideout.repository.toPost
import org.jetbrains.exposed.sql.select
import org.koin.core.annotation.Single
@Single
class PostQueryServiceImpl : PostQueryService {
override suspend fun findById(id: Long): Post = Posts.select { Posts.id eq id }.single().toPost()
override suspend fun findByUrl(url: String): Post = Posts.select { Posts.url eq url }.single().toPost()
override suspend fun findByApId(string: String): Post = Posts.select { Posts.apId eq string }.single().toPost()
}

View File

@ -6,9 +6,6 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Post
interface IPostRepository { interface IPostRepository {
suspend fun generateId(): Long suspend fun generateId(): Long
suspend fun save(post: Post): Post suspend fun save(post: Post): Post
suspend fun findOneById(id: Long, userId: Long? = null): Post?
suspend fun findByUrl(url: String): Post?
suspend fun delete(id: Long) suspend fun delete(id: Long)
suspend fun findById(id: Long): Post
suspend fun findByApId(id: String): Post?
} }

View File

@ -61,15 +61,9 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
} }
} }
override suspend fun findOneById(id: Long, userId: Long?): Post? { override suspend fun findById(id: Long): Post {
return query { return query {
Posts.select { Posts.id eq id }.singleOrNull()?.toPost() Posts.select { Posts.id eq id }.single().toPost()
}
}
override suspend fun findByUrl(url: String): Post? {
return query {
Posts.select { Posts.url eq url }.singleOrNull()?.toPost()
} }
} }
@ -78,12 +72,6 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
Posts.deleteWhere { Posts.id eq id } Posts.deleteWhere { Posts.id eq id }
} }
} }
override suspend fun findByApId(id: String): Post? {
return query {
Posts.select { Posts.apId eq id }.singleOrNull()?.toPost()
}
}
} }
object Posts : Table() { object Posts : Table() {

View File

@ -3,10 +3,9 @@ package dev.usbharu.hideout.service.activitypub
import dev.usbharu.hideout.domain.model.ActivityPubResponse import dev.usbharu.hideout.domain.model.ActivityPubResponse
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
import dev.usbharu.hideout.domain.model.ap.Like import dev.usbharu.hideout.domain.model.ap.Like
import dev.usbharu.hideout.exception.PostNotFoundException
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
import dev.usbharu.hideout.query.PostQueryService
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.IPostRepository
import dev.usbharu.hideout.service.reaction.IReactionService import dev.usbharu.hideout.service.reaction.IReactionService
import io.ktor.http.* import io.ktor.http.*
import org.koin.core.annotation.Single import org.koin.core.annotation.Single
@ -15,9 +14,9 @@ import org.koin.core.annotation.Single
class ActivityPubLikeServiceImpl( class ActivityPubLikeServiceImpl(
private val reactionService: IReactionService, private val reactionService: IReactionService,
private val activityPubUserService: ActivityPubUserService, private val activityPubUserService: ActivityPubUserService,
private val postService: IPostRepository,
private val activityPubNoteService: ActivityPubNoteService, private val activityPubNoteService: ActivityPubNoteService,
private val userQueryService: UserQueryService private val userQueryService: UserQueryService,
private val postQueryService: PostQueryService
) : ActivityPubLikeService { ) : ActivityPubLikeService {
override suspend fun receiveLike(like: Like): ActivityPubResponse { override suspend fun receiveLike(like: Like): ActivityPubResponse {
val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null") val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null")
@ -31,8 +30,7 @@ class ActivityPubLikeServiceImpl(
?: throw IllegalActivityPubObjectException("actor is not found") ?: throw IllegalActivityPubObjectException("actor is not found")
) )
val post = postService.findByUrl(like.`object`!!) val post = postQueryService.findByUrl(like.`object`!!)
?: throw PostNotFoundException("${like.`object`} was not found")
reactionService.receiveReaction(content, actor.substringAfter("://").substringBefore("/"), user.id, post.id) reactionService.receiveReaction(content, actor.substringAfter("://").substringBefore("/"), user.id, post.id)
return ActivityPubStringResponse(HttpStatusCode.OK, "") return ActivityPubStringResponse(HttpStatusCode.OK, "")

View File

@ -11,6 +11,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.PostQueryService
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.IPostRepository import dev.usbharu.hideout.repository.IPostRepository
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
@ -28,7 +29,8 @@ class ActivityPubNoteServiceImpl(
private val postRepository: IPostRepository, private val postRepository: IPostRepository,
private val activityPubUserService: ActivityPubUserService, private val activityPubUserService: ActivityPubUserService,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,
private val followerQueryService: FollowerQueryService private val followerQueryService: FollowerQueryService,
private val postQueryService: PostQueryService
) : ActivityPubNoteService { ) : ActivityPubNoteService {
private val logger = LoggerFactory.getLogger(this::class.java) private val logger = LoggerFactory.getLogger(this::class.java)
@ -72,7 +74,7 @@ class ActivityPubNoteServiceImpl(
} }
override suspend fun fetchNote(url: String, targetActor: String?): Note { override suspend fun fetchNote(url: String, targetActor: String?): Note {
val post = postRepository.findByUrl(url) val post = postQueryService.findByUrl(url)
if (post != null) { if (post != null) {
return postToNote(post) return postToNote(post)
} }
@ -86,7 +88,7 @@ class ActivityPubNoteServiceImpl(
private suspend fun postToNote(post: Post): Note { private suspend fun postToNote(post: Post): Note {
val user = userQueryService.findById(post.userId) val user = userQueryService.findById(post.userId)
val reply = post.replyId?.let { postRepository.findOneById(it) } val reply = post.replyId?.let { postQueryService.findById(it) }
return Note( return Note(
name = "Post", name = "Post",
id = post.apId, id = post.apId,
@ -100,15 +102,22 @@ class ActivityPubNoteServiceImpl(
) )
} }
private suspend fun ActivityPubNoteServiceImpl.note( private suspend fun note(
note: Note, note: Note,
targetActor: String?, targetActor: String?,
url: String url: String
): Note { ): Note {
val findByApId = postRepository.findByApId(url) val findByApId = try {
if (findByApId != null) { postQueryService.findByApId(url)
return postToNote(findByApId) } catch (_: NoSuchElementException) {
return internalNote(note, targetActor, url)
} catch (_: IllegalArgumentException) {
return internalNote(note, targetActor, url)
} }
return postToNote(findByApId)
}
private suspend fun internalNote(note: Note, targetActor: String?, url: String): Note {
val person = activityPubUserService.fetchPerson( val person = activityPubUserService.fetchPerson(
note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"), note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"),
targetActor targetActor
@ -129,7 +138,7 @@ class ActivityPubNoteServiceImpl(
val reply = note.inReplyTo?.let { val reply = note.inReplyTo?.let {
fetchNote(it, targetActor) fetchNote(it, targetActor)
postRepository.findByUrl(it) postQueryService.findByUrl(it)
} }
postRepository.save( postRepository.save(

View File

@ -7,9 +7,9 @@ import dev.usbharu.hideout.domain.model.ap.Undo
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
import dev.usbharu.hideout.domain.model.job.DeliverReactionJob import dev.usbharu.hideout.domain.model.job.DeliverReactionJob
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
import dev.usbharu.hideout.exception.PostNotFoundException
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.PostQueryService
import dev.usbharu.hideout.query.UserQueryService import dev.usbharu.hideout.query.UserQueryService
import dev.usbharu.hideout.repository.IPostRepository import dev.usbharu.hideout.repository.IPostRepository
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
@ -24,13 +24,14 @@ class ActivityPubReactionServiceImpl(
private val iPostRepository: IPostRepository, private val iPostRepository: IPostRepository,
private val httpClient: HttpClient, private val httpClient: HttpClient,
private val userQueryService: UserQueryService, private val userQueryService: UserQueryService,
private val followerQueryService: FollowerQueryService private val followerQueryService: FollowerQueryService,
private val postQueryService: PostQueryService
) : ActivityPubReactionService { ) : ActivityPubReactionService {
override suspend fun reaction(like: Reaction) { override suspend fun reaction(like: Reaction) {
val followers = followerQueryService.findFollowersById(like.userId) val followers = followerQueryService.findFollowersById(like.userId)
val user = userQueryService.findById(like.userId) val user = userQueryService.findById(like.userId)
val post = val post =
iPostRepository.findOneById(like.postId) ?: throw PostNotFoundException("${like.postId} was not found.") postQueryService.findById(like.postId)
followers.forEach { follower -> followers.forEach { follower ->
jobQueueParentService.schedule(DeliverReactionJob) { jobQueueParentService.schedule(DeliverReactionJob) {
props[it.actor] = user.url props[it.actor] = user.url
@ -46,7 +47,7 @@ class ActivityPubReactionServiceImpl(
val followers = followerQueryService.findFollowersById(like.userId) val followers = followerQueryService.findFollowersById(like.userId)
val user = userQueryService.findById(like.userId) val user = userQueryService.findById(like.userId)
val post = val post =
iPostRepository.findOneById(like.postId) ?: throw PostNotFoundException("${like.postId} was not found.") postQueryService.findById(like.postId)
followers.forEach { follower -> followers.forEach { follower ->
jobQueueParentService.schedule(DeliverRemoveReactionJob) { jobQueueParentService.schedule(DeliverRemoveReactionJob) {
props[it.actor] = user.url props[it.actor] = user.url

View File

@ -82,7 +82,8 @@ class ActivityPubNoteServiceImplTest {
mock(), mock(),
mock(), mock(),
userQueryService, userQueryService,
followerQueryService followerQueryService,
mock()
) )
val postEntity = Post( val postEntity = Post(
1L, 1L,
@ -106,7 +107,15 @@ class ActivityPubNoteServiceImplTest {
respondOk() respondOk()
} }
) )
val activityPubNoteService = ActivityPubNoteServiceImpl(httpClient, mock(), mock(), mock(), mock(), mock()) val activityPubNoteService = ActivityPubNoteServiceImpl(
httpClient,
mock(),
mock(),
mock(),
mock(),
mock(),
mock()
)
activityPubNoteService.createNoteJob( activityPubNoteService.createNoteJob(
JobProps( JobProps(
data = mapOf<String, Any>( data = mapOf<String, Any>(