mirror of https://github.com/usbharu/Hideout.git
Merge pull request #375 from usbharu/feature/undo-delete
ActorのUndo Deleteに対応
This commit is contained in:
commit
07b240961a
|
@ -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.post.PostService
|
||||||
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
|
import dev.usbharu.hideout.core.service.user.UserService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -41,7 +42,8 @@ class APUndoProcessor(
|
||||||
private val reactionService: ReactionService,
|
private val reactionService: ReactionService,
|
||||||
private val actorRepository: ActorRepository,
|
private val actorRepository: ActorRepository,
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: PostRepository,
|
||||||
private val postService: PostService
|
private val postService: PostService,
|
||||||
|
private val userService: UserService,
|
||||||
) : AbstractActivityPubProcessor<Undo>(transaction) {
|
) : AbstractActivityPubProcessor<Undo>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
|
||||||
val undo = activity.activity
|
val undo = activity.activity
|
||||||
|
@ -71,6 +73,11 @@ class APUndoProcessor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"Delete" -> {
|
||||||
|
delete(undo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
TODO()
|
TODO()
|
||||||
|
@ -124,6 +131,14 @@ class APUndoProcessor(
|
||||||
postService.deleteRemote(findByApId)
|
postService.deleteRemote(findByApId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Undo
|
||||||
|
|
||||||
override fun type(): Class<Undo> = Undo::class.java
|
override fun type(): Class<Undo> = Undo::class.java
|
||||||
|
|
|
@ -40,9 +40,13 @@ interface APUserService {
|
||||||
* @param targetActor 署名するユーザー
|
* @param targetActor 署名するユーザー
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
suspend fun fetchPerson(url: String, targetActor: String? = null): Person
|
suspend fun fetchPerson(url: String, targetActor: String? = null, idOverride: Long? = null): Person
|
||||||
|
|
||||||
suspend fun fetchPersonWithEntity(url: String, targetActor: String? = null): Pair<Person, Actor>
|
suspend fun fetchPersonWithEntity(
|
||||||
|
url: String,
|
||||||
|
targetActor: String? = null,
|
||||||
|
idOverride: Long? = null,
|
||||||
|
): Pair<Person, Actor>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -51,7 +55,7 @@ class APUserServiceImpl(
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val apResourceResolveService: APResourceResolveService,
|
private val apResourceResolveService: APResourceResolveService,
|
||||||
private val actorRepository: ActorRepository
|
private val actorRepository: ActorRepository,
|
||||||
) :
|
) :
|
||||||
APUserService {
|
APUserService {
|
||||||
|
|
||||||
|
@ -88,13 +92,17 @@ class APUserServiceImpl(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchPerson(url: String, targetActor: String?): Person =
|
override suspend fun fetchPerson(url: String, targetActor: String?, idOverride: Long?): Person =
|
||||||
fetchPersonWithEntity(url, targetActor).first
|
fetchPersonWithEntity(url, targetActor, idOverride).first
|
||||||
|
|
||||||
override suspend fun fetchPersonWithEntity(url: String, targetActor: String?): Pair<Person, Actor> {
|
override suspend fun fetchPersonWithEntity(
|
||||||
|
url: String,
|
||||||
|
targetActor: String?,
|
||||||
|
idOverride: Long?,
|
||||||
|
): Pair<Person, Actor> {
|
||||||
val userEntity = actorRepository.findByUrl(url)
|
val userEntity = actorRepository.findByUrl(url)
|
||||||
|
|
||||||
if (userEntity != null) {
|
if (userEntity != null && idOverride == null) {
|
||||||
return entityToPerson(userEntity, userEntity.url) to userEntity
|
return entityToPerson(userEntity, userEntity.url) to userEntity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +112,7 @@ class APUserServiceImpl(
|
||||||
|
|
||||||
val actor = actorRepository.findByUrlWithLock(id)
|
val actor = actorRepository.findByUrlWithLock(id)
|
||||||
|
|
||||||
if (actor != null) {
|
if (actor != null && idOverride == null) {
|
||||||
return person to actor
|
return person to actor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,13 +131,14 @@ class APUserServiceImpl(
|
||||||
followers = person.followers,
|
followers = person.followers,
|
||||||
sharedInbox = person.endpoints["sharedInbox"],
|
sharedInbox = person.endpoints["sharedInbox"],
|
||||||
locked = person.manuallyApprovesFollowers
|
locked = person.manuallyApprovesFollowers
|
||||||
)
|
),
|
||||||
|
idOverride
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun entityToPerson(
|
private fun entityToPerson(
|
||||||
actorEntity: Actor,
|
actorEntity: Actor,
|
||||||
id: String
|
id: String,
|
||||||
) = Person(
|
) = Person(
|
||||||
type = emptyList(),
|
type = emptyList(),
|
||||||
name = actorEntity.name,
|
name = actorEntity.name,
|
||||||
|
|
|
@ -22,6 +22,7 @@ data class DeletedActor(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val name: String,
|
val name: String,
|
||||||
val domain: String,
|
val domain: String,
|
||||||
|
val apiId: String,
|
||||||
val publicKey: String,
|
val publicKey: String,
|
||||||
val deletedAt: Instant
|
val deletedAt: Instant,
|
||||||
)
|
)
|
||||||
|
|
|
@ -43,7 +43,7 @@ data class Post private constructor(
|
||||||
@get:URL
|
@get:URL
|
||||||
val apId: String = url,
|
val apId: String = url,
|
||||||
val mediaIds: List<Long> = emptyList(),
|
val mediaIds: List<Long> = emptyList(),
|
||||||
val delted: Boolean = false,
|
val deleted: Boolean = false,
|
||||||
val emojiIds: List<Long> = emptyList(),
|
val emojiIds: List<Long> = emptyList(),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -67,7 +67,8 @@ data class Post private constructor(
|
||||||
sensitive: Boolean = false,
|
sensitive: Boolean = false,
|
||||||
apId: String = url,
|
apId: String = url,
|
||||||
mediaIds: List<Long> = emptyList(),
|
mediaIds: List<Long> = emptyList(),
|
||||||
emojiIds: List<Long> = emptyList()
|
emojiIds: List<Long> = emptyList(),
|
||||||
|
deleted: Boolean = false,
|
||||||
): Post {
|
): Post {
|
||||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
require(id >= 0) { "id must be greater than or equal to 0." }
|
||||||
|
|
||||||
|
@ -109,7 +110,7 @@ data class Post private constructor(
|
||||||
sensitive = sensitive,
|
sensitive = sensitive,
|
||||||
apId = apId,
|
apId = apId,
|
||||||
mediaIds = mediaIds,
|
mediaIds = mediaIds,
|
||||||
delted = false,
|
deleted = deleted,
|
||||||
emojiIds = emojiIds
|
emojiIds = emojiIds
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -119,6 +120,10 @@ data class Post private constructor(
|
||||||
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
|
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (post.deleted) {
|
||||||
|
return post.delete()
|
||||||
|
}
|
||||||
|
|
||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +135,7 @@ data class Post private constructor(
|
||||||
createdAt: Instant,
|
createdAt: Instant,
|
||||||
url: String,
|
url: String,
|
||||||
repost: Post,
|
repost: Post,
|
||||||
apId: String
|
apId: String,
|
||||||
): Post {
|
): Post {
|
||||||
// リポストの公開範囲は元のポストより広くてはいけない
|
// リポストの公開範囲は元のポストより広くてはいけない
|
||||||
val fixedVisibility = if (visibility.ordinal <= repost.visibility.ordinal) {
|
val fixedVisibility = if (visibility.ordinal <= repost.visibility.ordinal) {
|
||||||
|
@ -139,16 +144,11 @@ data class Post private constructor(
|
||||||
visibility
|
visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
val post = of(
|
||||||
|
|
||||||
require(actorId >= 0) { "actorId must be greater than or equal to 0." }
|
|
||||||
|
|
||||||
val post = Post(
|
|
||||||
id = id,
|
id = id,
|
||||||
actorId = actorId,
|
actorId = actorId,
|
||||||
overview = null,
|
overview = null,
|
||||||
content = "",
|
content = "",
|
||||||
text = "",
|
|
||||||
createdAt = createdAt.toEpochMilli(),
|
createdAt = createdAt.toEpochMilli(),
|
||||||
visibility = fixedVisibility,
|
visibility = fixedVisibility,
|
||||||
url = url,
|
url = url,
|
||||||
|
@ -157,16 +157,9 @@ data class Post private constructor(
|
||||||
sensitive = false,
|
sensitive = false,
|
||||||
apId = apId,
|
apId = apId,
|
||||||
mediaIds = emptyList(),
|
mediaIds = emptyList(),
|
||||||
delted = false,
|
deleted = false,
|
||||||
emojiIds = emptyList()
|
emojiIds = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
val validate = validator.validate(post)
|
|
||||||
|
|
||||||
for (constraintViolation in validate) {
|
|
||||||
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +177,7 @@ data class Post private constructor(
|
||||||
sensitive: Boolean = false,
|
sensitive: Boolean = false,
|
||||||
apId: String = url,
|
apId: String = url,
|
||||||
mediaIds: List<Long> = emptyList(),
|
mediaIds: List<Long> = emptyList(),
|
||||||
emojiIds: List<Long> = emptyList()
|
emojiIds: List<Long> = emptyList(),
|
||||||
): Post {
|
): Post {
|
||||||
// リポストの公開範囲は元のポストより広くてはいけない
|
// リポストの公開範囲は元のポストより広くてはいけない
|
||||||
val fixedVisibility = if (visibility.ordinal <= repost.visibility.ordinal) {
|
val fixedVisibility = if (visibility.ordinal <= repost.visibility.ordinal) {
|
||||||
|
@ -193,37 +186,11 @@ data class Post private constructor(
|
||||||
visibility
|
visibility
|
||||||
}
|
}
|
||||||
|
|
||||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
val post = of(
|
||||||
|
|
||||||
require(actorId >= 0) { "actorId must be greater than or equal to 0." }
|
|
||||||
|
|
||||||
val limitedOverview = if ((overview?.length ?: 0) >= characterLimit.post.overview) {
|
|
||||||
overview?.substring(0, characterLimit.post.overview)
|
|
||||||
} else {
|
|
||||||
overview
|
|
||||||
}
|
|
||||||
|
|
||||||
val limitedText = if (content.length >= characterLimit.post.text) {
|
|
||||||
content.substring(0, characterLimit.post.text)
|
|
||||||
} else {
|
|
||||||
content
|
|
||||||
}
|
|
||||||
|
|
||||||
val (html, content1) = postContentFormatter.format(limitedText)
|
|
||||||
|
|
||||||
require(url.isNotBlank()) { "url must contain non-blank characters" }
|
|
||||||
require(url.length <= characterLimit.general.url) {
|
|
||||||
"url must not exceed ${characterLimit.general.url} characters."
|
|
||||||
}
|
|
||||||
|
|
||||||
require((replyId ?: 0) >= 0) { "replyId must be greater then or equal to 0." }
|
|
||||||
|
|
||||||
val post = Post(
|
|
||||||
id = id,
|
id = id,
|
||||||
actorId = actorId,
|
actorId = actorId,
|
||||||
overview = limitedOverview,
|
overview = overview,
|
||||||
content = html,
|
content = content,
|
||||||
text = content1,
|
|
||||||
createdAt = createdAt.toEpochMilli(),
|
createdAt = createdAt.toEpochMilli(),
|
||||||
visibility = fixedVisibility,
|
visibility = fixedVisibility,
|
||||||
url = url,
|
url = url,
|
||||||
|
@ -232,70 +199,26 @@ data class Post private constructor(
|
||||||
sensitive = sensitive,
|
sensitive = sensitive,
|
||||||
apId = apId,
|
apId = apId,
|
||||||
mediaIds = mediaIds,
|
mediaIds = mediaIds,
|
||||||
delted = false,
|
deleted = false,
|
||||||
emojiIds = emojiIds
|
emojiIds = emojiIds
|
||||||
)
|
)
|
||||||
|
|
||||||
val validate = validator.validate(post)
|
|
||||||
|
|
||||||
for (constraintViolation in validate) {
|
|
||||||
throw IllegalArgumentException("${constraintViolation.propertyPath} : ${constraintViolation.message}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return post
|
return post
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
fun deleteOf(
|
|
||||||
id: Long,
|
|
||||||
visibility: Visibility,
|
|
||||||
url: String,
|
|
||||||
repostId: Long?,
|
|
||||||
replyId: Long?,
|
|
||||||
apId: String
|
|
||||||
): Post {
|
|
||||||
return Post(
|
|
||||||
id = id,
|
|
||||||
actorId = 0,
|
|
||||||
overview = null,
|
|
||||||
content = "",
|
|
||||||
text = "",
|
|
||||||
createdAt = Instant.EPOCH.toEpochMilli(),
|
|
||||||
visibility = visibility,
|
|
||||||
url = url,
|
|
||||||
repostId = repostId,
|
|
||||||
replyId = replyId,
|
|
||||||
sensitive = false,
|
|
||||||
apId = apId,
|
|
||||||
mediaIds = emptyList(),
|
|
||||||
delted = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isPureRepost(): Boolean =
|
fun isPureRepost(): Boolean =
|
||||||
this.text.isEmpty() &&
|
this.text.isEmpty() &&
|
||||||
this.content.isEmpty() &&
|
this.content.isEmpty() &&
|
||||||
this.overview == null &&
|
this.overview == null &&
|
||||||
this.replyId == null &&
|
this.replyId == null &&
|
||||||
this.repostId != null
|
this.repostId != null
|
||||||
|
|
||||||
fun delete(): Post {
|
fun delete(): Post {
|
||||||
return Post(
|
return copy(deleted = true)
|
||||||
id = this.id,
|
}
|
||||||
actorId = 0,
|
|
||||||
overview = null,
|
fun restore(): Post {
|
||||||
content = "",
|
return copy(deleted = false)
|
||||||
text = "",
|
|
||||||
createdAt = Instant.EPOCH.toEpochMilli(),
|
|
||||||
visibility = visibility,
|
|
||||||
url = url,
|
|
||||||
repostId = repostId,
|
|
||||||
replyId = replyId,
|
|
||||||
sensitive = false,
|
|
||||||
apId = apId,
|
|
||||||
mediaIds = emptyList(),
|
|
||||||
delted = true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.springframework.stereotype.Repository
|
||||||
interface PostRepository {
|
interface PostRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(post: Post): Post
|
suspend fun save(post: Post): Post
|
||||||
|
suspend fun saveAll(posts: List<Post>)
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
suspend fun findById(id: Long): Post?
|
suspend fun findById(id: Long): Post?
|
||||||
suspend fun findByUrl(url: String): Post?
|
suspend fun findByUrl(url: String): Post?
|
||||||
|
@ -30,6 +31,7 @@ interface PostRepository {
|
||||||
suspend fun findByApId(apId: String): Post?
|
suspend fun findByApId(apId: String): Post?
|
||||||
suspend fun existByApIdWithLock(apId: String): Boolean
|
suspend fun existByApIdWithLock(apId: String): Boolean
|
||||||
suspend fun findByActorId(actorId: Long): List<Post>
|
suspend fun findByActorId(actorId: Long): List<Post>
|
||||||
|
suspend fun findByActorIdAndDeleted(actorId: Long, deleted: Boolean): List<Post>
|
||||||
|
|
||||||
suspend fun countByActorId(actorId: Long): Int
|
suspend fun countByActorId(actorId: Long): Int
|
||||||
}
|
}
|
||||||
|
|
33
hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/UpdateActorTask.kt
vendored
Normal file
33
hideout-core/src/main/kotlin/dev/usbharu/hideout/core/external/job/UpdateActorTask.kt
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 usbharu
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dev.usbharu.hideout.core.external.job
|
||||||
|
|
||||||
|
import dev.usbharu.owl.common.task.Task
|
||||||
|
import dev.usbharu.owl.common.task.TaskDefinition
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
data class UpdateActorTask(
|
||||||
|
val id: Long,
|
||||||
|
val apId: String,
|
||||||
|
) : Task()
|
||||||
|
|
||||||
|
|
||||||
|
@Component
|
||||||
|
data object UpdateActorTaskDef : TaskDefinition<UpdateActorTask> {
|
||||||
|
override val type: Class<UpdateActorTask>
|
||||||
|
get() = UpdateActorTask::class.java
|
||||||
|
}
|
|
@ -26,16 +26,6 @@ import org.springframework.stereotype.Component
|
||||||
@Component
|
@Component
|
||||||
class PostResultRowMapper(private val postBuilder: Post.PostBuilder) : ResultRowMapper<Post> {
|
class PostResultRowMapper(private val postBuilder: Post.PostBuilder) : ResultRowMapper<Post> {
|
||||||
override fun map(resultRow: ResultRow): Post {
|
override fun map(resultRow: ResultRow): Post {
|
||||||
if (resultRow[Posts.deleted]) {
|
|
||||||
return postBuilder.deleteOf(
|
|
||||||
id = resultRow[Posts.id],
|
|
||||||
visibility = Visibility.values().first { it.ordinal == resultRow[Posts.visibility] },
|
|
||||||
url = resultRow[Posts.url],
|
|
||||||
repostId = resultRow[Posts.repostId],
|
|
||||||
replyId = resultRow[Posts.replyId],
|
|
||||||
apId = resultRow[Posts.apId]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return postBuilder.of(
|
return postBuilder.of(
|
||||||
id = resultRow[Posts.id],
|
id = resultRow[Posts.id],
|
||||||
|
@ -49,6 +39,7 @@ class PostResultRowMapper(private val postBuilder: Post.PostBuilder) : ResultRow
|
||||||
replyId = resultRow[Posts.replyId],
|
replyId = resultRow[Posts.replyId],
|
||||||
sensitive = resultRow[Posts.sensitive],
|
sensitive = resultRow[Posts.sensitive],
|
||||||
apId = resultRow[Posts.apId],
|
apId = resultRow[Posts.apId],
|
||||||
|
deleted = resultRow[Posts.deleted],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
|
||||||
it[id] = deletedActor.id
|
it[id] = deletedActor.id
|
||||||
it[name] = deletedActor.name
|
it[name] = deletedActor.name
|
||||||
it[domain] = deletedActor.domain
|
it[domain] = deletedActor.domain
|
||||||
|
it[apId] = deletedActor.apiId
|
||||||
it[publicKey] = deletedActor.publicKey
|
it[publicKey] = deletedActor.publicKey
|
||||||
it[deletedAt] = deletedActor.deletedAt
|
it[deletedAt] = deletedActor.deletedAt
|
||||||
}
|
}
|
||||||
|
@ -46,6 +47,7 @@ class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository()
|
||||||
DeletedActors.update({ DeletedActors.id eq deletedActor.id }) {
|
DeletedActors.update({ DeletedActors.id eq deletedActor.id }) {
|
||||||
it[name] = deletedActor.name
|
it[name] = deletedActor.name
|
||||||
it[domain] = deletedActor.domain
|
it[domain] = deletedActor.domain
|
||||||
|
it[apId] = deletedActor.apiId
|
||||||
it[publicKey] = deletedActor.publicKey
|
it[publicKey] = deletedActor.publicKey
|
||||||
it[deletedAt] = deletedActor.deletedAt
|
it[deletedAt] = deletedActor.deletedAt
|
||||||
}
|
}
|
||||||
|
@ -84,6 +86,7 @@ private fun deletedActor(singleOr: ResultRow): DeletedActor {
|
||||||
singleOr[DeletedActors.name],
|
singleOr[DeletedActors.name],
|
||||||
singleOr[DeletedActors.domain],
|
singleOr[DeletedActors.domain],
|
||||||
singleOr[DeletedActors.publicKey],
|
singleOr[DeletedActors.publicKey],
|
||||||
|
singleOr[DeletedActors.apId],
|
||||||
singleOr[DeletedActors.deletedAt]
|
singleOr[DeletedActors.deletedAt]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -92,6 +95,7 @@ object DeletedActors : Table("deleted_actors") {
|
||||||
val id = long("id")
|
val id = long("id")
|
||||||
val name = varchar("name", 300)
|
val name = varchar("name", 300)
|
||||||
val domain = varchar("domain", 255)
|
val domain = varchar("domain", 255)
|
||||||
|
val apId = varchar("ap_id", 255).uniqueIndex()
|
||||||
val publicKey = varchar("public_key", 10000).uniqueIndex()
|
val publicKey = varchar("public_key", 10000).uniqueIndex()
|
||||||
val deletedAt = timestamp("deleted_at")
|
val deletedAt = timestamp("deleted_at")
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
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.application.service.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
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.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
@ -29,7 +42,7 @@ import org.springframework.stereotype.Repository
|
||||||
@Repository
|
@Repository
|
||||||
class PostRepositoryImpl(
|
class PostRepositoryImpl(
|
||||||
private val idGenerateService: IdGenerateService,
|
private val idGenerateService: IdGenerateService,
|
||||||
private val postQueryMapper: QueryMapper<Post>
|
private val postQueryMapper: QueryMapper<Post>,
|
||||||
) : PostRepository, AbstractRepository() {
|
) : PostRepository, AbstractRepository() {
|
||||||
override val logger: Logger
|
override val logger: Logger
|
||||||
get() = Companion.logger
|
get() = Companion.logger
|
||||||
|
@ -37,7 +50,7 @@ class PostRepositoryImpl(
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(post: Post): Post = query {
|
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) {
|
if (singleOrNull == null) {
|
||||||
Posts.insert {
|
Posts.insert {
|
||||||
it[id] = post.id
|
it[id] = post.id
|
||||||
|
@ -52,7 +65,7 @@ class PostRepositoryImpl(
|
||||||
it[replyId] = post.replyId
|
it[replyId] = post.replyId
|
||||||
it[sensitive] = post.sensitive
|
it[sensitive] = post.sensitive
|
||||||
it[apId] = post.apId
|
it[apId] = post.apId
|
||||||
it[deleted] = post.delted
|
it[deleted] = post.deleted
|
||||||
}
|
}
|
||||||
PostsMedia.batchInsert(post.mediaIds) {
|
PostsMedia.batchInsert(post.mediaIds) {
|
||||||
this[PostsMedia.postId] = post.id
|
this[PostsMedia.postId] = post.id
|
||||||
|
@ -77,7 +90,7 @@ class PostRepositoryImpl(
|
||||||
this[PostsEmojis.postId] = post.id
|
this[PostsEmojis.postId] = post.id
|
||||||
this[PostsEmojis.emojiId] = it
|
this[PostsEmojis.emojiId] = it
|
||||||
}
|
}
|
||||||
Posts.update({ Posts.id eq post.id }) {
|
Posts.update({ id eq post.id }) {
|
||||||
it[actorId] = post.actorId
|
it[actorId] = post.actorId
|
||||||
it[overview] = post.overview
|
it[overview] = post.overview
|
||||||
it[content] = post.content
|
it[content] = post.content
|
||||||
|
@ -89,12 +102,45 @@ class PostRepositoryImpl(
|
||||||
it[replyId] = post.replyId
|
it[replyId] = post.replyId
|
||||||
it[sensitive] = post.sensitive
|
it[sensitive] = post.sensitive
|
||||||
it[apId] = post.apId
|
it[apId] = post.apId
|
||||||
it[deleted] = post.delted
|
it[deleted] = post.deleted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@query post
|
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 {
|
override suspend fun findById(id: Long): Post? = query {
|
||||||
return@query Posts
|
return@query Posts
|
||||||
.leftJoin(PostsMedia)
|
.leftJoin(PostsMedia)
|
||||||
|
@ -133,6 +179,10 @@ class PostRepositoryImpl(
|
||||||
.selectAll().where { Posts.actorId eq actorId }.let(postQueryMapper::map)
|
.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 {
|
override suspend fun countByActorId(actorId: Long): Int = query {
|
||||||
return@query Posts
|
return@query Posts
|
||||||
.selectAll()
|
.selectAll()
|
||||||
|
@ -168,13 +218,13 @@ object Posts : Table() {
|
||||||
}
|
}
|
||||||
|
|
||||||
object PostsMedia : Table("posts_media") {
|
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)
|
val mediaId = long("media_id").references(Media.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||||
override val primaryKey = PrimaryKey(postId, mediaId)
|
override val primaryKey = PrimaryKey(postId, mediaId)
|
||||||
}
|
}
|
||||||
|
|
||||||
object PostsEmojis : Table("posts_emojis") {
|
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)
|
val emojiId = long("emoji_id").references(CustomEmojis.id)
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(postId, emojiId)
|
override val primaryKey: PrimaryKey = PrimaryKey(postId, emojiId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,5 @@ interface PostService {
|
||||||
suspend fun deleteLocal(post: Post)
|
suspend fun deleteLocal(post: Post)
|
||||||
suspend fun deleteRemote(post: Post)
|
suspend fun deleteRemote(post: Post)
|
||||||
suspend fun deleteByActor(actorId: Long)
|
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.create.ApSendCreateService
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService
|
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.DuplicateException
|
||||||
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
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.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
|
@ -38,7 +38,7 @@ class PostServiceImpl(
|
||||||
private val postBuilder: Post.PostBuilder,
|
private val postBuilder: Post.PostBuilder,
|
||||||
private val apSendCreateService: ApSendCreateService,
|
private val apSendCreateService: ApSendCreateService,
|
||||||
private val reactionRepository: ReactionRepository,
|
private val reactionRepository: ReactionRepository,
|
||||||
private val apSendDeleteService: APSendDeleteService
|
private val apSendDeleteService: APSendDeleteService,
|
||||||
) : PostService {
|
) : PostService {
|
||||||
|
|
||||||
override suspend fun createLocal(post: PostCreateDto): Post {
|
override suspend fun createLocal(post: PostCreateDto): Post {
|
||||||
|
@ -52,14 +52,14 @@ class PostServiceImpl(
|
||||||
override suspend fun createRemote(post: Post): Post {
|
override suspend fun createRemote(post: Post): Post {
|
||||||
logger.info("START Create Remote Post user: {}, remote url: {}", post.actorId, post.apId)
|
logger.info("START Create Remote Post user: {}, remote url: {}", post.actorId, post.apId)
|
||||||
val actor =
|
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)
|
val createdPost = internalCreate(post, false)
|
||||||
logger.info("SUCCESS Create Remote Post url: {}", createdPost.url)
|
logger.info("SUCCESS Create Remote Post url: {}", createdPost.url)
|
||||||
return createdPost
|
return createdPost
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteLocal(post: Post) {
|
override suspend fun deleteLocal(post: Post) {
|
||||||
if (post.delted) {
|
if (post.deleted) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reactionRepository.deleteByPostId(post.id)
|
reactionRepository.deleteByPostId(post.id)
|
||||||
|
@ -73,7 +73,7 @@ class PostServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteRemote(post: Post) {
|
override suspend fun deleteRemote(post: Post) {
|
||||||
if (post.delted) {
|
if (post.deleted) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reactionRepository.deleteByPostId(post.id)
|
reactionRepository.deleteByPostId(post.id)
|
||||||
|
@ -86,14 +86,25 @@ class PostServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByActor(actorId: Long) {
|
override suspend fun deleteByActor(actorId: Long) {
|
||||||
postRepository.findByActorId(actorId).filterNot { it.delted }.forEach { postRepository.save(it.delete()) }
|
|
||||||
|
|
||||||
val actor = actorRepository.findById(actorId)
|
val actor = actorRepository.findById(actorId)
|
||||||
?: throw IllegalStateException("actor: $actorId was not found.")
|
?: 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))
|
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 {
|
private suspend fun internalCreate(post: Post, isLocal: Boolean): Post {
|
||||||
return try {
|
return try {
|
||||||
val save = postRepository.save(post)
|
val save = postRepository.save(post)
|
||||||
|
|
|
@ -26,12 +26,14 @@ interface UserService {
|
||||||
|
|
||||||
suspend fun createLocalUser(user: UserCreateDto): Actor
|
suspend fun createLocalUser(user: UserCreateDto): Actor
|
||||||
|
|
||||||
suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor
|
suspend fun createRemoteUser(user: RemoteUserCreateDto, idOverride: Long? = null): Actor
|
||||||
|
|
||||||
suspend fun updateUser(userId: Long, updateUserDto: UpdateUserDto)
|
suspend fun updateUser(userId: Long, updateUserDto: UpdateUserDto)
|
||||||
|
|
||||||
suspend fun deleteRemoteActor(actorId: Long)
|
suspend fun deleteRemoteActor(actorId: Long)
|
||||||
|
|
||||||
|
suspend fun restorationRemoteActor(actorId: Long)
|
||||||
|
|
||||||
suspend fun deleteLocalUser(userId: Long)
|
suspend fun deleteLocalUser(userId: Long)
|
||||||
|
|
||||||
suspend fun updateUserStatistics(userId: Long)
|
suspend fun updateUserStatistics(userId: Long)
|
||||||
|
|
|
@ -29,8 +29,10 @@ import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||||
|
import dev.usbharu.hideout.core.external.job.UpdateActorTask
|
||||||
import dev.usbharu.hideout.core.service.instance.InstanceService
|
import dev.usbharu.hideout.core.service.instance.InstanceService
|
||||||
import dev.usbharu.hideout.core.service.post.PostService
|
import dev.usbharu.hideout.core.service.post.PostService
|
||||||
|
import dev.usbharu.owl.producer.api.OwlProducer
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -50,6 +52,7 @@ class UserServiceImpl(
|
||||||
private val postService: PostService,
|
private val postService: PostService,
|
||||||
private val apSendDeleteService: APSendDeleteService,
|
private val apSendDeleteService: APSendDeleteService,
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: PostRepository,
|
||||||
|
private val owlProducer: OwlProducer,
|
||||||
) :
|
) :
|
||||||
UserService {
|
UserService {
|
||||||
|
|
||||||
|
@ -90,7 +93,7 @@ class UserServiceImpl(
|
||||||
return save
|
return save
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor {
|
override suspend fun createRemoteUser(user: RemoteUserCreateDto, idOverride: Long?): Actor {
|
||||||
logger.info("START Create New remote user. name: {} url: {}", user.name, user.url)
|
logger.info("START Create New remote user. name: {} url: {}", user.name, user.url)
|
||||||
|
|
||||||
val deletedActor = deletedActorRepository.findByNameAndDomain(user.name, user.domain)
|
val deletedActor = deletedActorRepository.findByNameAndDomain(user.name, user.domain)
|
||||||
|
@ -104,7 +107,7 @@ class UserServiceImpl(
|
||||||
|
|
||||||
val nextId = actorRepository.nextId()
|
val nextId = actorRepository.nextId()
|
||||||
val userEntity = actorBuilder.of(
|
val userEntity = actorBuilder.of(
|
||||||
id = nextId,
|
id = idOverride ?: nextId,
|
||||||
name = user.name,
|
name = user.name,
|
||||||
domain = user.domain,
|
domain = user.domain,
|
||||||
screenName = user.screenName,
|
screenName = user.screenName,
|
||||||
|
@ -156,6 +159,7 @@ class UserServiceImpl(
|
||||||
actor.id,
|
actor.id,
|
||||||
actor.name,
|
actor.name,
|
||||||
actor.domain,
|
actor.domain,
|
||||||
|
actor.url,
|
||||||
actor.publicKey,
|
actor.publicKey,
|
||||||
Instant.now()
|
Instant.now()
|
||||||
)
|
)
|
||||||
|
@ -169,6 +173,15 @@ class UserServiceImpl(
|
||||||
deletedActorRepository.save(deletedActor)
|
deletedActorRepository.save(deletedActor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun restorationRemoteActor(actorId: Long) {
|
||||||
|
val deletedActor = deletedActorRepository.findById(actorId)
|
||||||
|
?: return
|
||||||
|
|
||||||
|
deletedActorRepository.delete(deletedActor)
|
||||||
|
|
||||||
|
owlProducer.publishTask(UpdateActorTask(deletedActor.id, deletedActor.apiId))
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun deleteLocalUser(userId: Long) {
|
override suspend fun deleteLocalUser(userId: Long) {
|
||||||
val actor = actorRepository.findByIdWithLock(userId) ?: throw UserNotFoundException.withId(userId)
|
val actor = actorRepository.findByIdWithLock(userId) ?: throw UserNotFoundException.withId(userId)
|
||||||
apSendDeleteService.sendDeleteActor(actor)
|
apSendDeleteService.sendDeleteActor(actor)
|
||||||
|
@ -176,6 +189,7 @@ class UserServiceImpl(
|
||||||
actor.id,
|
actor.id,
|
||||||
actor.name,
|
actor.name,
|
||||||
actor.domain,
|
actor.domain,
|
||||||
|
actor.url,
|
||||||
actor.publicKey,
|
actor.publicKey,
|
||||||
Instant.now()
|
Instant.now()
|
||||||
)
|
)
|
||||||
|
|
|
@ -154,7 +154,7 @@ class APNoteServiceImplTest {
|
||||||
|
|
||||||
)
|
)
|
||||||
val apUserService = mock<APUserService> {
|
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> {
|
val postRepository = mock<PostRepository> {
|
||||||
onBlocking { generateId() } doReturn TwitterSnowflakeIdGenerateService.generateId()
|
onBlocking { generateId() } doReturn TwitterSnowflakeIdGenerateService.generateId()
|
||||||
|
@ -255,7 +255,7 @@ class APNoteServiceImplTest {
|
||||||
followers = user.followers
|
followers = user.followers
|
||||||
)
|
)
|
||||||
val apUserService = mock<APUserService> {
|
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 postService = mock<PostService>()
|
||||||
val noteQueryService = mock<NoteQueryService> {
|
val noteQueryService = mock<NoteQueryService> {
|
||||||
|
|
|
@ -69,7 +69,8 @@ class ActorServiceTest {
|
||||||
relationshipRepository = mock(),
|
relationshipRepository = mock(),
|
||||||
postService = mock(),
|
postService = mock(),
|
||||||
apSendDeleteService = mock(),
|
apSendDeleteService = mock(),
|
||||||
postRepository = mock()
|
postRepository = mock(),
|
||||||
|
owlProducer = mock()
|
||||||
)
|
)
|
||||||
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
||||||
verify(actorRepository, times(1)).save(any())
|
verify(actorRepository, times(1)).save(any())
|
||||||
|
@ -112,7 +113,8 @@ class ActorServiceTest {
|
||||||
relationshipRepository = mock(),
|
relationshipRepository = mock(),
|
||||||
postService = mock(),
|
postService = mock(),
|
||||||
apSendDeleteService = mock(),
|
apSendDeleteService = mock(),
|
||||||
postRepository = mock()
|
postRepository = mock(),
|
||||||
|
owlProducer = mock()
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThrows<IllegalStateException> {
|
assertThrows<IllegalStateException> {
|
||||||
|
@ -162,7 +164,8 @@ class ActorServiceTest {
|
||||||
relationshipRepository = mock(),
|
relationshipRepository = mock(),
|
||||||
postService = mock(),
|
postService = mock(),
|
||||||
apSendDeleteService = mock(),
|
apSendDeleteService = mock(),
|
||||||
postRepository = mock()
|
postRepository = mock(),
|
||||||
|
owlProducer = mock()
|
||||||
)
|
)
|
||||||
val user = RemoteUserCreateDto(
|
val user = RemoteUserCreateDto(
|
||||||
name = "test",
|
name = "test",
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 usbharu
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package dev.usbharu.hideout.worker
|
||||||
|
|
||||||
|
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
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@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