diff --git a/detekt.yml b/detekt.yml index cbdfa515..c4fee204 100644 --- a/detekt.yml +++ b/detekt.yml @@ -6,6 +6,8 @@ build: InjectDispatcher: 0 EnumEntryNameCase: 0 ReplaceSafeCallChainWithRun: 0 + VariableNaming: 0 + NoNameShadowing: 0 style: ClassOrdering: diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt new file mode 100644 index 00000000..48409e92 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Delete.kt @@ -0,0 +1,47 @@ +package dev.usbharu.hideout.activitypub.domain.model + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import dev.usbharu.hideout.activitypub.domain.model.objects.Object +import dev.usbharu.hideout.activitypub.domain.model.objects.ObjectDeserializer + +open class Delete : Object { + @JsonDeserialize(using = ObjectDeserializer::class) + var `object`: Object? = null + var published: String? = null + + constructor( + type: List = emptyList(), + name: String = "Delete", + actor: String, + id: String, + `object`: Object, + published: String? + ) : super(add(type, "Delete"), name, actor, id) { + this.`object` = `object` + this.published = published + } + + protected constructor() : super() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Delete) return false + if (!super.equals(other)) return false + + if (`object` != other.`object`) return false + if (published != other.published) return false + + return true + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + (`object`?.hashCode() ?: 0) + result = 31 * result + (published?.hashCode() ?: 0) + return result + } + + override fun toString(): String { + return "Delete(`object`=$`object`, published=$published) ${super.toString()}" + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Tombstone.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Tombstone.kt new file mode 100644 index 00000000..0017eac4 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/Tombstone.kt @@ -0,0 +1,12 @@ +package dev.usbharu.hideout.activitypub.domain.model + +import dev.usbharu.hideout.activitypub.domain.model.objects.Object + +open class Tombstone : Object { + constructor( + type: List = emptyList(), + name: String = "Tombstone", + actor: String? = null, + id: String + ) : super(add(type, "Tombstone"), name, actor, id) +} diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectDeserializer.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectDeserializer.kt index ad9969a2..377dfcff 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectDeserializer.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/domain/model/objects/ObjectDeserializer.kt @@ -56,7 +56,7 @@ class ObjectDeserializer : JsonDeserializer() { ExtendedActivityVocabulary.Arrive -> TODO() ExtendedActivityVocabulary.Block -> TODO() ExtendedActivityVocabulary.Create -> p.codec.treeToValue(treeNode, Create::class.java) - ExtendedActivityVocabulary.Delete -> TODO() + ExtendedActivityVocabulary.Delete -> p.codec.treeToValue(treeNode, Delete::class.java) ExtendedActivityVocabulary.Dislike -> TODO() ExtendedActivityVocabulary.Flag -> TODO() ExtendedActivityVocabulary.Ignore -> TODO() @@ -91,7 +91,7 @@ class ObjectDeserializer : JsonDeserializer() { ExtendedActivityVocabulary.Place -> TODO() ExtendedActivityVocabulary.Profile -> TODO() ExtendedActivityVocabulary.Relationship -> TODO() - ExtendedActivityVocabulary.Tombstone -> TODO() + ExtendedActivityVocabulary.Tombstone -> p.codec.treeToValue(treeNode, Tombstone::class.java) ExtendedActivityVocabulary.Video -> TODO() ExtendedActivityVocabulary.Mention -> TODO() ExtendedActivityVocabulary.Emoji -> p.codec.treeToValue(treeNode, Emoji::class.java) diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteService.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteService.kt new file mode 100644 index 00000000..9d047605 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteService.kt @@ -0,0 +1,8 @@ +package dev.usbharu.hideout.activitypub.service.activity.delete + +import dev.usbharu.hideout.activitypub.domain.model.Delete +import dev.usbharu.hideout.activitypub.interfaces.api.common.ActivityPubResponse + +interface APReceiveDeleteService { + suspend fun receiveDelete(delete: Delete): ActivityPubResponse +} diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteServiceImpl.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteServiceImpl.kt new file mode 100644 index 00000000..d5272203 --- /dev/null +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/activity/delete/APReceiveDeleteServiceImpl.kt @@ -0,0 +1,31 @@ +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.interfaces.api.common.ActivityPubResponse +import dev.usbharu.hideout.activitypub.interfaces.api.common.ActivityPubStringResponse +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 +import io.ktor.http.* +import org.springframework.stereotype.Service + +@Service +class APReceiveDeleteServiceImpl( + private val postQueryService: PostQueryService, + private val postRepository: PostRepository, + private val transaction: Transaction +) : APReceiveDeleteService { + override suspend fun receiveDelete(delete: Delete): ActivityPubResponse = transaction.transaction { + val deleteId = delete.`object`?.id ?: throw IllegalActivityPubObjectException("object.id is null") + + val post = try { + postQueryService.findByApId(deleteId) + } catch (e: FailedToGetResourcesException) { + return@transaction ActivityPubStringResponse(HttpStatusCode.OK, "Resource not found or already deleted") + } + postRepository.delete(post.id) + return@transaction ActivityPubStringResponse(HttpStatusCode.OK, "Resource was deleted.") + } +} diff --git a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APService.kt b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APService.kt index 102929da..c7df1df2 100644 --- a/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APService.kt +++ b/src/main/kotlin/dev/usbharu/hideout/activitypub/service/common/APService.kt @@ -8,6 +8,7 @@ import dev.usbharu.hideout.activitypub.domain.model.Follow import dev.usbharu.hideout.activitypub.interfaces.api.common.ActivityPubResponse import dev.usbharu.hideout.activitypub.service.activity.accept.APAcceptService import dev.usbharu.hideout.activitypub.service.activity.create.APCreateService +import dev.usbharu.hideout.activitypub.service.activity.delete.APReceiveDeleteService import dev.usbharu.hideout.activitypub.service.activity.follow.APReceiveFollowService import dev.usbharu.hideout.activitypub.service.activity.like.APLikeService import dev.usbharu.hideout.activitypub.service.activity.undo.APUndoService @@ -180,6 +181,7 @@ class APServiceImpl( private val apAcceptService: APAcceptService, private val apCreateService: APCreateService, private val apLikeService: APLikeService, + private val apReceiveDeleteService: APReceiveDeleteService, @Qualifier("activitypub") private val objectMapper: ObjectMapper ) : APService { @@ -234,6 +236,7 @@ class APServiceImpl( ActivityType.Create -> apCreateService.receiveCreate(objectMapper.readValue(json)) ActivityType.Like -> apLikeService.receiveLike(objectMapper.readValue(json)) ActivityType.Undo -> apUndoService.receiveUndo(objectMapper.readValue(json)) + ActivityType.Delete -> apReceiveDeleteService.receiveDelete(objectMapper.readValue(json)) else -> { throw IllegalArgumentException("$type is not supported.") diff --git a/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt b/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt index 0ddef889..1b6591f8 100644 --- a/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt +++ b/src/test/kotlin/dev/usbharu/hideout/activitypub/service/common/APServiceImplTest.kt @@ -16,6 +16,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -33,6 +34,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -50,6 +52,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -67,6 +70,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -84,6 +88,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -101,6 +106,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -118,6 +124,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -135,6 +142,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -152,6 +160,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -169,6 +178,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -186,6 +196,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -203,6 +214,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper ) @@ -220,6 +232,7 @@ class APServiceImplTest { apAcceptService = mock(), apCreateService = mock(), apLikeService = mock(), + apReceiveDeleteService = mock(), objectMapper = objectMapper )