mirror of https://github.com/usbharu/Hideout.git
feat: Repositoryを修正
This commit is contained in:
parent
84b038f472
commit
2e7efd5d6d
|
@ -31,6 +31,7 @@ import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
|||
import dev.usbharu.hideout.core.service.post.PostService
|
||||
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||
import dev.usbharu.hideout.core.service.user.UserService
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
|
@ -41,7 +42,8 @@ class APUndoProcessor(
|
|||
private val reactionService: ReactionService,
|
||||
private val actorRepository: ActorRepository,
|
||||
private val postRepository: PostRepository,
|
||||
private val postService: PostService
|
||||
private val postService: PostService,
|
||||
private val userService: UserService,
|
||||
) : AbstractActivityPubProcessor<Undo>(transaction) {
|
||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
|
||||
val undo = activity.activity
|
||||
|
@ -132,7 +134,9 @@ class APUndoProcessor(
|
|||
private suspend fun delete(undo: Undo) {
|
||||
val announce = undo.apObject as Delete
|
||||
|
||||
val actor = actorRepository.findByUrl(announce.actor) ?: throw UserNotFoundException.withUrl(announce.actor)
|
||||
|
||||
userService.restorationRemoteActor(actor.id)
|
||||
}
|
||||
|
||||
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Undo
|
||||
|
|
|
@ -215,21 +215,10 @@ data class Post private constructor(
|
|||
this.repostId != null
|
||||
|
||||
fun delete(): Post {
|
||||
return Post(
|
||||
id = this.id,
|
||||
actorId = actorId,
|
||||
overview = overview,
|
||||
content = content,
|
||||
text = text,
|
||||
createdAt = createdAt,
|
||||
visibility = visibility,
|
||||
url = url,
|
||||
repostId = repostId,
|
||||
replyId = replyId,
|
||||
sensitive = sensitive,
|
||||
apId = apId,
|
||||
mediaIds = mediaIds,
|
||||
deleted = true
|
||||
)
|
||||
return copy(deleted = true)
|
||||
}
|
||||
|
||||
fun restore(): Post {
|
||||
return copy(deleted = false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.stereotype.Repository
|
|||
interface PostRepository {
|
||||
suspend fun generateId(): Long
|
||||
suspend fun save(post: Post): Post
|
||||
suspend fun saveAll(posts: List<Post>)
|
||||
suspend fun delete(id: Long)
|
||||
suspend fun findById(id: Long): Post?
|
||||
suspend fun findByUrl(url: String): Post?
|
||||
|
@ -30,6 +31,7 @@ interface PostRepository {
|
|||
suspend fun findByApId(apId: String): Post?
|
||||
suspend fun existByApIdWithLock(apId: String): Boolean
|
||||
suspend fun findByActorId(actorId: Long): List<Post>
|
||||
suspend fun findByActorIdAndDeleted(actorId: Long, deleted: Boolean): List<Post>
|
||||
|
||||
suspend fun countByActorId(actorId: Long): Int
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
|
|||
it[id] = deletedActor.id
|
||||
it[name] = deletedActor.name
|
||||
it[domain] = deletedActor.domain
|
||||
it[apId] = deletedActor.apiId
|
||||
it[publicKey] = deletedActor.publicKey
|
||||
it[deletedAt] = deletedActor.deletedAt
|
||||
}
|
||||
|
@ -46,6 +47,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
|
|||
DeletedActors.update({ DeletedActors.id eq deletedActor.id }) {
|
||||
it[name] = deletedActor.name
|
||||
it[domain] = deletedActor.domain
|
||||
it[apId] = deletedActor.apiId
|
||||
it[publicKey] = deletedActor.publicKey
|
||||
it[deletedAt] = deletedActor.deletedAt
|
||||
}
|
||||
|
@ -84,6 +86,7 @@ private fun deletedActor(singleOr: ResultRow): DeletedActor {
|
|||
singleOr[DeletedActors.name],
|
||||
singleOr[DeletedActors.domain],
|
||||
singleOr[DeletedActors.publicKey],
|
||||
singleOr[DeletedActors.apId],
|
||||
singleOr[DeletedActors.deletedAt]
|
||||
)
|
||||
}
|
||||
|
@ -92,6 +95,7 @@ object DeletedActors : Table("deleted_actors") {
|
|||
val id = long("id")
|
||||
val name = varchar("name", 300)
|
||||
val domain = varchar("domain", 255)
|
||||
val apId = varchar("ap_id", 255).uniqueIndex()
|
||||
val publicKey = varchar("public_key", 10000).uniqueIndex()
|
||||
val deletedAt = timestamp("deleted_at")
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||
|
|
|
@ -20,6 +20,19 @@ import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
|||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.actorId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.apId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.content
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.createdAt
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.deleted
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.id
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.overview
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.replyId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.repostId
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.sensitive
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.text
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.url
|
||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.visibility
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.slf4j.Logger
|
||||
|
@ -29,7 +42,7 @@ import org.springframework.stereotype.Repository
|
|||
@Repository
|
||||
class PostRepositoryImpl(
|
||||
private val idGenerateService: IdGenerateService,
|
||||
private val postQueryMapper: QueryMapper<Post>
|
||||
private val postQueryMapper: QueryMapper<Post>,
|
||||
) : PostRepository, AbstractRepository() {
|
||||
override val logger: Logger
|
||||
get() = Companion.logger
|
||||
|
@ -37,7 +50,7 @@ class PostRepositoryImpl(
|
|||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||
|
||||
override suspend fun save(post: Post): Post = query {
|
||||
val singleOrNull = Posts.selectAll().where { Posts.id eq post.id }.forUpdate().singleOrNull()
|
||||
val singleOrNull = Posts.selectAll().where { id eq post.id }.forUpdate().singleOrNull()
|
||||
if (singleOrNull == null) {
|
||||
Posts.insert {
|
||||
it[id] = post.id
|
||||
|
@ -77,7 +90,7 @@ class PostRepositoryImpl(
|
|||
this[PostsEmojis.postId] = post.id
|
||||
this[PostsEmojis.emojiId] = it
|
||||
}
|
||||
Posts.update({ Posts.id eq post.id }) {
|
||||
Posts.update({ id eq post.id }) {
|
||||
it[actorId] = post.actorId
|
||||
it[overview] = post.overview
|
||||
it[content] = post.content
|
||||
|
@ -95,6 +108,39 @@ class PostRepositoryImpl(
|
|||
return@query post
|
||||
}
|
||||
|
||||
override suspend fun saveAll(posts: List<Post>) {
|
||||
Posts.batchUpsert(
|
||||
posts, id,
|
||||
) {
|
||||
this[id] = it.id
|
||||
this[actorId] = it.actorId
|
||||
this[overview] = it.overview
|
||||
this[content] = it.content
|
||||
this[text] = it.text
|
||||
this[createdAt] = it.createdAt
|
||||
this[visibility] = it.visibility.ordinal
|
||||
this[url] = it.url
|
||||
this[repostId] = it.repostId
|
||||
this[replyId] = it.replyId
|
||||
this[sensitive] = it.sensitive
|
||||
this[apId] = it.apId
|
||||
this[deleted] = it.deleted
|
||||
}
|
||||
val mediaIds = posts.flatMap { post -> post.mediaIds.map { post.id to it } }
|
||||
PostsMedia.batchUpsert(
|
||||
mediaIds, PostsMedia.postId
|
||||
) {
|
||||
this[PostsMedia.postId] = it.first
|
||||
this[PostsMedia.mediaId] = it.second
|
||||
}
|
||||
|
||||
val emojiIds = posts.flatMap { post -> post.emojiIds.map { post.id to it } }
|
||||
PostsEmojis.batchUpsert(emojiIds, PostsEmojis.postId) {
|
||||
this[PostsEmojis.postId] = it.first
|
||||
this[PostsEmojis.emojiId] = it.second
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Long): Post? = query {
|
||||
return@query Posts
|
||||
.leftJoin(PostsMedia)
|
||||
|
@ -133,6 +179,10 @@ class PostRepositoryImpl(
|
|||
.selectAll().where { Posts.actorId eq actorId }.let(postQueryMapper::map)
|
||||
}
|
||||
|
||||
override suspend fun findByActorIdAndDeleted(actorId: Long, deleted: Boolean): List<Post> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun countByActorId(actorId: Long): Int = query {
|
||||
return@query Posts
|
||||
.selectAll()
|
||||
|
@ -168,13 +218,13 @@ object Posts : Table() {
|
|||
}
|
||||
|
||||
object PostsMedia : Table("posts_media") {
|
||||
val postId = long("post_id").references(Posts.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||
val postId = long("post_id").references(id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||
val mediaId = long("media_id").references(Media.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||
override val primaryKey = PrimaryKey(postId, mediaId)
|
||||
}
|
||||
|
||||
object PostsEmojis : Table("posts_emojis") {
|
||||
val postId = long("post_id").references(Posts.id)
|
||||
val postId = long("post_id").references(id)
|
||||
val emojiId = long("emoji_id").references(CustomEmojis.id)
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(postId, emojiId)
|
||||
}
|
||||
|
|
|
@ -26,4 +26,5 @@ interface PostService {
|
|||
suspend fun deleteLocal(post: Post)
|
||||
suspend fun deleteRemote(post: Post)
|
||||
suspend fun deleteByActor(actorId: Long)
|
||||
suspend fun restoreByRemoteActor(actorId: Long)
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ package dev.usbharu.hideout.core.service.post
|
|||
|
||||
import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService
|
||||
import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService
|
||||
import dev.usbharu.hideout.core.domain.exception.UserNotFoundException
|
||||
import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException
|
||||
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
||||
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||
|
@ -38,7 +38,7 @@ class PostServiceImpl(
|
|||
private val postBuilder: Post.PostBuilder,
|
||||
private val apSendCreateService: ApSendCreateService,
|
||||
private val reactionRepository: ReactionRepository,
|
||||
private val apSendDeleteService: APSendDeleteService
|
||||
private val apSendDeleteService: APSendDeleteService,
|
||||
) : PostService {
|
||||
|
||||
override suspend fun createLocal(post: PostCreateDto): Post {
|
||||
|
@ -52,7 +52,7 @@ class PostServiceImpl(
|
|||
override suspend fun createRemote(post: Post): Post {
|
||||
logger.info("START Create Remote Post user: {}, remote url: {}", post.actorId, post.apId)
|
||||
val actor =
|
||||
actorRepository.findById(post.actorId) ?: throw UserNotFoundException("${post.actorId} was not found.")
|
||||
actorRepository.findById(post.actorId) ?: throw UserNotFoundException.withId(post.actorId)
|
||||
val createdPost = internalCreate(post, false)
|
||||
logger.info("SUCCESS Create Remote Post url: {}", createdPost.url)
|
||||
return createdPost
|
||||
|
@ -86,14 +86,25 @@ class PostServiceImpl(
|
|||
}
|
||||
|
||||
override suspend fun deleteByActor(actorId: Long) {
|
||||
postRepository.findByActorId(actorId).filterNot { it.deleted }.forEach { postRepository.save(it.delete()) }
|
||||
|
||||
val actor = actorRepository.findById(actorId)
|
||||
?: throw IllegalStateException("actor: $actorId was not found.")
|
||||
|
||||
postRepository.findByActorId(actorId).filterNot { it.deleted }.forEach { postRepository.save(it.delete()) }
|
||||
|
||||
|
||||
actorRepository.save(actor.copy(postsCount = 0, lastPostDate = null))
|
||||
}
|
||||
|
||||
override suspend fun restoreByRemoteActor(actorId: Long) {
|
||||
val actor = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||
|
||||
val postList = postRepository.findByActorIdAndDeleted(actorId, true).map { it.restore() }
|
||||
|
||||
postRepository.saveAll(postList)
|
||||
|
||||
actorRepository.save(actor.copy(postsCount = actor.postsCount.plus(postList.size)))
|
||||
}
|
||||
|
||||
private suspend fun internalCreate(post: Post, isLocal: Boolean): Post {
|
||||
return try {
|
||||
val save = postRepository.save(post)
|
||||
|
|
|
@ -154,7 +154,7 @@ class APNoteServiceImplTest {
|
|||
|
||||
)
|
||||
val apUserService = mock<APUserService> {
|
||||
onBlocking { fetchPersonWithEntity(eq(note.attributedTo), isNull()) } doReturn (person to user)
|
||||
onBlocking { fetchPersonWithEntity(eq(note.attributedTo), isNull(), anyOrNull()) } doReturn (person to user)
|
||||
}
|
||||
val postRepository = mock<PostRepository> {
|
||||
onBlocking { generateId() } doReturn TwitterSnowflakeIdGenerateService.generateId()
|
||||
|
@ -255,7 +255,7 @@ class APNoteServiceImplTest {
|
|||
followers = user.followers
|
||||
)
|
||||
val apUserService = mock<APUserService> {
|
||||
onBlocking { fetchPersonWithEntity(eq(user.url), anyOrNull()) } doReturn (person to user)
|
||||
onBlocking { fetchPersonWithEntity(eq(user.url), anyOrNull(), anyOrNull()) } doReturn (person to user)
|
||||
}
|
||||
val postService = mock<PostService>()
|
||||
val noteQueryService = mock<NoteQueryService> {
|
||||
|
|
|
@ -69,7 +69,8 @@ class ActorServiceTest {
|
|||
relationshipRepository = mock(),
|
||||
postService = mock(),
|
||||
apSendDeleteService = mock(),
|
||||
postRepository = mock()
|
||||
postRepository = mock(),
|
||||
owlProducer = mock()
|
||||
)
|
||||
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
||||
verify(actorRepository, times(1)).save(any())
|
||||
|
@ -112,7 +113,8 @@ class ActorServiceTest {
|
|||
relationshipRepository = mock(),
|
||||
postService = mock(),
|
||||
apSendDeleteService = mock(),
|
||||
postRepository = mock()
|
||||
postRepository = mock(),
|
||||
owlProducer = mock()
|
||||
)
|
||||
|
||||
assertThrows<IllegalStateException> {
|
||||
|
@ -162,7 +164,8 @@ class ActorServiceTest {
|
|||
relationshipRepository = mock(),
|
||||
postService = mock(),
|
||||
apSendDeleteService = mock(),
|
||||
postRepository = mock()
|
||||
postRepository = mock(),
|
||||
owlProducer = mock()
|
||||
)
|
||||
val user = RemoteUserCreateDto(
|
||||
name = "test",
|
||||
|
|
|
@ -20,6 +20,7 @@ import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
|||
import dev.usbharu.hideout.application.external.Transaction
|
||||
import dev.usbharu.hideout.core.external.job.UpdateActorTask
|
||||
import dev.usbharu.hideout.core.external.job.UpdateActorTaskDef
|
||||
import dev.usbharu.hideout.core.service.post.PostService
|
||||
import dev.usbharu.owl.consumer.AbstractTaskRunner
|
||||
import dev.usbharu.owl.consumer.TaskRequest
|
||||
import dev.usbharu.owl.consumer.TaskResult
|
||||
|
@ -29,10 +30,13 @@ import org.springframework.stereotype.Component
|
|||
class UpdateActorWorker(
|
||||
private val transaction: Transaction,
|
||||
private val apUserService: APUserService,
|
||||
private val postService: PostService,
|
||||
) : AbstractTaskRunner<UpdateActorTask, UpdateActorTaskDef>(UpdateActorTaskDef) {
|
||||
override suspend fun typedRun(typedParam: UpdateActorTask, taskRequest: TaskRequest): TaskResult {
|
||||
transaction.transaction {
|
||||
apUserService.fetchPerson(typedParam.apId, idOverride = typedParam.id)
|
||||
|
||||
postService.restoreByRemoteActor(typedParam.id)
|
||||
}
|
||||
|
||||
return TaskResult.ok()
|
||||
|
|
Loading…
Reference in New Issue