diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipFollowSubscriber.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipFollowSubscriber.kt index 3b3970bd..0707c496 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipFollowSubscriber.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipFollowSubscriber.kt @@ -5,24 +5,20 @@ import dev.usbharu.hideout.core.application.timeline.AddTimelineRelationship import dev.usbharu.hideout.core.application.timeline.UserAddTimelineRelationshipApplicationService import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEvent import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEventBody -import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship -import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository -import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import org.slf4j.LoggerFactory import org.springframework.stereotype.Component @Component class TimelineRelationshipFollowSubscriber( private val userAddTimelineRelationshipApplicationService: UserAddTimelineRelationshipApplicationService, - private val idGenerateService: IdGenerateService, private val userDetailRepository: UserDetailRepository, private val domainEventSubscriber: DomainEventSubscriber ) : Subscriber { override fun init() { - domainEventSubscriber.subscribe(RelationshipEvent.FOLLOW.eventName) { + domainEventSubscriber.subscribe(RelationshipEvent.ACCEPT_FOLLOW.eventName) { val relationship = it.body.getRelationship() val userDetail = userDetailRepository.findByActorId(relationship.actorId.id) ?: throw InternalServerException("Userdetail ${relationship.actorId} not found by actorid.") @@ -34,12 +30,9 @@ class TimelineRelationshipFollowSubscriber( @Suppress("UnsafeCallOnNullableType") userAddTimelineRelationshipApplicationService.execute( AddTimelineRelationship( - TimelineRelationship( - TimelineRelationshipId(idGenerateService.generateId()), - userDetail.homeTimelineId!!, - relationship.targetActorId, - Visible.FOLLOWERS - ) + userDetail.homeTimelineId!!, + relationship.targetActorId, + Visible.FOLLOWERS ), it.body.principal ) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipUnfollowSubscriber.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipUnfollowSubscriber.kt new file mode 100644 index 00000000..018420d8 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/domainevent/subscribers/TimelineRelationshipUnfollowSubscriber.kt @@ -0,0 +1,46 @@ +package dev.usbharu.hideout.core.application.domainevent.subscribers + +import dev.usbharu.hideout.core.application.timeline.RemoveTimelineRelationship +import dev.usbharu.hideout.core.application.timeline.UserRemoveTimelineRelationshipApplicationService +import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEvent +import dev.usbharu.hideout.core.domain.event.relationship.RelationshipEventBody +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Component + +@Component +class TimelineRelationshipUnfollowSubscriber( + private val domainEventSubscriber: DomainEventSubscriber, + private val userRemoveTimelineRelationshipApplicationService: UserRemoveTimelineRelationshipApplicationService, + private val userDetailRepository: UserDetailRepository, + private val timelineRelationshipRepository: TimelineRelationshipRepository, +) : Subscriber { + override fun init() { + domainEventSubscriber.subscribe(RelationshipEvent.UNFOLLOW.eventName) { + val relationship = it.body.getRelationship() + val userDetail = userDetailRepository.findByActorId(relationship.actorId.id) ?: throw IllegalStateException( + "UserDetail ${relationship.actorId} not found by actorId." + ) + if (userDetail.homeTimelineId == null) { + logger.warn("HomeTimeline for ${userDetail.id} not found.") + return@subscribe + } + + val timelineRelationship = timelineRelationshipRepository.findByTimelineIdAndActorId( + userDetail.homeTimelineId!!, + relationship.targetActorId + ) + ?: throw IllegalStateException("TimelineRelationship ${userDetail.homeTimelineId} to ${relationship.targetActorId} not found by timelineId and ActorId") + + userRemoveTimelineRelationshipApplicationService.execute( + RemoveTimelineRelationship(timelineRelationship.id), + it.body.principal + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(TimelineRelationshipUnfollowSubscriber::class.java) + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/AddTimelineRelationship.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/AddTimelineRelationship.kt index e8c7bda4..21684dda 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/AddTimelineRelationship.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/AddTimelineRelationship.kt @@ -1,7 +1,11 @@ package dev.usbharu.hideout.core.application.timeline -import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship +import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.timeline.TimelineId +import dev.usbharu.hideout.core.domain.model.timelinerelationship.Visible data class AddTimelineRelationship( - val timelineRelationship: TimelineRelationship + val timelineId: TimelineId, + val actorId: ActorId, + val visible: Visible ) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/RemoveTimelineRelationship.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/RemoveTimelineRelationship.kt new file mode 100644 index 00000000..5565ca22 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/RemoveTimelineRelationship.kt @@ -0,0 +1,5 @@ +package dev.usbharu.hideout.core.application.timeline + +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId + +data class RemoveTimelineRelationship(val timelineRelationshipId: TimelineRelationshipId) diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserAddTimelineRelationshipApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserAddTimelineRelationshipApplicationService.kt index 3809fb3a..d78f03b2 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserAddTimelineRelationshipApplicationService.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserAddTimelineRelationshipApplicationService.kt @@ -1,15 +1,22 @@ package dev.usbharu.hideout.core.application.timeline +import dev.usbharu.hideout.core.application.exception.PermissionDeniedException import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser +import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipId import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository +import dev.usbharu.hideout.core.domain.shared.id.IdGenerateService import org.slf4j.LoggerFactory import org.springframework.stereotype.Service @Service class UserAddTimelineRelationshipApplicationService( private val timelineRelationshipRepository: TimelineRelationshipRepository, + private val timelineRepository: TimelineRepository, + private val idGenerateService: IdGenerateService, transaction: Transaction ) : LocalUserAbstractApplicationService( @@ -17,7 +24,21 @@ class UserAddTimelineRelationshipApplicationService( logger ) { override suspend fun internalExecute(command: AddTimelineRelationship, principal: LocalUser) { - timelineRelationshipRepository.save(command.timelineRelationship) + val timeline = timelineRepository.findById(command.timelineId) + ?: throw IllegalArgumentException("Timeline ${command.timelineId} not found.") + + if (timeline.userDetailId != principal.userDetailId) { + throw PermissionDeniedException() + } + + timelineRelationshipRepository.save( + TimelineRelationship( + TimelineRelationshipId(idGenerateService.generateId()), + command.timelineId, + command.actorId, + command.visible + ) + ) } companion object { diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserRemoveTimelineRelationshipApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserRemoveTimelineRelationshipApplicationService.kt new file mode 100644 index 00000000..cdb434bf --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserRemoveTimelineRelationshipApplicationService.kt @@ -0,0 +1,39 @@ +package dev.usbharu.hideout.core.application.timeline + +import dev.usbharu.hideout.core.application.exception.PermissionDeniedException +import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService +import dev.usbharu.hideout.core.application.shared.Transaction +import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser +import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository +import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service + +@Service +class UserRemoveTimelineRelationshipApplicationService( + transaction: Transaction, + private val timelineRelationshipRepository: TimelineRelationshipRepository, + private val timelineRepository: TimelineRepository +) : + LocalUserAbstractApplicationService( + transaction, logger + ) { + + override suspend fun internalExecute(command: RemoveTimelineRelationship, principal: LocalUser) { + val timelineRelationship = (timelineRelationshipRepository.findById(command.timelineRelationshipId) + ?: throw IllegalArgumentException("TimelineRelationship ${command.timelineRelationshipId} not found.")) + + val timeline = (timelineRepository.findById(timelineRelationship.timelineId) + ?: throw IllegalArgumentException("Timeline ${timelineRelationship.timelineId} not found.")) + + if (timeline.userDetailId != principal.userDetailId) { + throw PermissionDeniedException() + } + + timelineRelationshipRepository.delete(timelineRelationship) + } + + companion object { + private val logger = LoggerFactory.getLogger(UserRemoveTimelineRelationshipApplicationService::class.java) + } +} \ No newline at end of file diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/event/relationship/RelationshipEvent.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/event/relationship/RelationshipEvent.kt index 5e26b130..fdd7f4a1 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/event/relationship/RelationshipEvent.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/event/relationship/RelationshipEvent.kt @@ -35,7 +35,8 @@ class RelationshipEventBody( } enum class RelationshipEvent(val eventName: String) { - FOLLOW("RelationshipFollow"), + ACCEPT_FOLLOW("RelationshipFollow"), + REJECT_FOLLOW("RelationshipRejectFollow"), UNFOLLOW("RelationshipUnfollow"), BLOCK("RelationshipBlock"), UNBLOCK("RelationshipUnblock"), diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/Relationship.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/Relationship.kt index af32b48d..93babff4 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/Relationship.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/relationship/Relationship.kt @@ -44,12 +44,6 @@ class Relationship( var mutingFollowRequest: Boolean = mutingFollowRequest private set - fun follow() { - require(blocking.not()) - following = true - addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.FOLLOW)) - } - fun unfollow() { following = false addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.UNFOLLOW)) @@ -96,11 +90,15 @@ class Relationship( } fun acceptFollowRequest() { - follow() + require(blocking.not()) + following = true + addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.ACCEPT_FOLLOW)) followRequesting = false } fun rejectFollowRequest() { + require(followRequesting) + addDomainEvent(RelationshipEventFactory(this).createEvent(RelationshipEvent.REJECT_FOLLOW)) followRequesting = false } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationship.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationship.kt index df2cf099..592630e0 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationship.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationship.kt @@ -8,7 +8,20 @@ class TimelineRelationship( val timelineId: TimelineId, val actorId: ActorId, val visible: Visible -) +) { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as TimelineRelationship + + return id == other.id + } + + override fun hashCode(): Int { + return id.hashCode() + } +} enum class Visible { PUBLIC, diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationshipRepository.kt index ccf1c463..5fd8f176 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timelinerelationship/TimelineRelationshipRepository.kt @@ -1,10 +1,13 @@ package dev.usbharu.hideout.core.domain.model.timelinerelationship import dev.usbharu.hideout.core.domain.model.actor.ActorId +import dev.usbharu.hideout.core.domain.model.timeline.TimelineId interface TimelineRelationshipRepository { suspend fun save(timelineRelationship: TimelineRelationship): TimelineRelationship suspend fun delete(timelineRelationship: TimelineRelationship) suspend fun findByActorId(actorId: ActorId): List + suspend fun findById(timelineRelationshipId: TimelineRelationshipId): TimelineRelationship? + suspend fun findByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId): TimelineRelationship? }