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..0430a7a2 --- /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) + } +} diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/model/Timeline.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/model/Timeline.kt new file mode 100644 index 00000000..8abc559a --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/model/Timeline.kt @@ -0,0 +1,23 @@ +package dev.usbharu.hideout.core.application.model + +import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility + +data class Timeline( + val id: Long, + val userDetailId: Long, + val name: String, + val visibility: TimelineVisibility, + val isSystem: Boolean +) { + companion object { + fun of(timeline: dev.usbharu.hideout.core.domain.model.timeline.Timeline): Timeline { + return Timeline( + timeline.id.value, + timeline.userDetailId.id, + timeline.name.value, + timeline.visibility, + timeline.isSystem + ) + } + } +} 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/GetTimelines.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/GetTimelines.kt new file mode 100644 index 00000000..a4233829 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/GetTimelines.kt @@ -0,0 +1,3 @@ +package dev.usbharu.hideout.core.application.timeline + +data class GetTimelines(val userDetailId: Long) 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/UserGetTimelinesApplicationService.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserGetTimelinesApplicationService.kt new file mode 100644 index 00000000..2ebced42 --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserGetTimelinesApplicationService.kt @@ -0,0 +1,37 @@ +package dev.usbharu.hideout.core.application.timeline + +import dev.usbharu.hideout.core.application.model.Timeline +import dev.usbharu.hideout.core.application.shared.AbstractApplicationService +import dev.usbharu.hideout.core.application.shared.Transaction +import dev.usbharu.hideout.core.domain.model.support.principal.Principal +import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository +import dev.usbharu.hideout.core.domain.model.timeline.TimelineVisibility +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId +import org.slf4j.LoggerFactory +import org.springframework.stereotype.Service + +@Service +class UserGetTimelinesApplicationService(transaction: Transaction, private val timelineRepository: TimelineRepository) : + AbstractApplicationService>( + transaction, + logger + ) { + override suspend fun internalExecute(command: GetTimelines, principal: Principal): List { + val userDetailId = UserDetailId(command.userDetailId) + + val timelineVisibility = if (userDetailId == principal.userDetailId) { + listOf(TimelineVisibility.PUBLIC, TimelineVisibility.UNLISTED, TimelineVisibility.PRIVATE) + } else { + listOf(TimelineVisibility.PUBLIC) + } + + val timelineList = + timelineRepository.findAllByUserDetailIdAndVisibilityIn(userDetailId, timelineVisibility) + + return timelineList.map { Timeline.of(it) } + } + + companion object { + private val logger = LoggerFactory.getLogger(UserGetTimelinesApplicationService::class.java) + } +} 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..ee2819bd --- /dev/null +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/application/timeline/UserRemoveTimelineRelationshipApplicationService.kt @@ -0,0 +1,44 @@ +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) + } +} 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..f1f48851 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,15 +44,12 @@ 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)) + followRequesting = false + val relationshipEventFactory = RelationshipEventFactory(this) + addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW)) + addDomainEvent(relationshipEventFactory.createEvent(RelationshipEvent.UNFOLLOW_REQUEST)) } fun block() { @@ -96,11 +93,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/timeline/TimelineRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/TimelineRepository.kt index 28fdb0f1..c0d4242f 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/TimelineRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/domain/model/timeline/TimelineRepository.kt @@ -1,5 +1,7 @@ package dev.usbharu.hideout.core.domain.model.timeline +import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId + interface TimelineRepository { suspend fun save(timeline: Timeline): Timeline suspend fun delete(timeline: Timeline) @@ -7,4 +9,8 @@ interface TimelineRepository { suspend fun findByIds(ids: List): List suspend fun findById(id: TimelineId): Timeline? + suspend fun findAllByUserDetailIdAndVisibilityIn( + userDetailId: UserDetailId, + visibility: List + ): List } 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? } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepository.kt index 5ea3c74d..1ab6986a 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRelationshipRepository.kt @@ -45,6 +45,22 @@ class ExposedTimelineRelationshipRepository : AbstractRepository(), TimelineRela } } + override suspend fun findById(timelineRelationshipId: TimelineRelationshipId): TimelineRelationship? { + return query { + TimelineRelationships.selectAll().where { + TimelineRelationships.id eq timelineRelationshipId.value + }.singleOrNull()?.toTimelineRelationship() + } + } + + override suspend fun findByTimelineIdAndActorId(timelineId: TimelineId, actorId: ActorId): TimelineRelationship? { + return query { + TimelineRelationships.selectAll().where { + TimelineRelationships.timelineId eq timelineId.value and (TimelineRelationships.actorId eq actorId.id) + }.singleOrNull()?.toTimelineRelationship() + } + } + companion object { private val logger = LoggerFactory.getLogger(ExposedTimelineRelationshipRepository::class.java) } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt index cd2b3f77..9fe9f694 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/infrastructure/exposedrepository/ExposedTimelineRepository.kt @@ -58,6 +58,17 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu } } + override suspend fun findAllByUserDetailIdAndVisibilityIn( + userDetailId: UserDetailId, + visibility: List + ): List { + return query { + Timelines.selectAll().where { + Timelines.userDetailId eq userDetailId.id and (Timelines.visibility inList visibility.map { it.name }) + }.map { it.toTimeline() } + } + } + companion object { private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name) } diff --git a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/web/user/UserController.kt b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/web/user/UserController.kt index c2691652..a7d8a900 100644 --- a/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/web/user/UserController.kt +++ b/hideout-core/src/main/kotlin/dev/usbharu/hideout/core/interfaces/web/user/UserController.kt @@ -3,16 +3,24 @@ package dev.usbharu.hideout.core.interfaces.web.user import dev.usbharu.hideout.core.application.actor.GetActorDetail import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService +import dev.usbharu.hideout.core.application.relationship.followrequest.FollowRequest +import dev.usbharu.hideout.core.application.relationship.followrequest.UserFollowRequestApplicationService +import dev.usbharu.hideout.core.application.relationship.get.GetRelationship +import dev.usbharu.hideout.core.application.relationship.get.GetRelationshipApplicationService +import dev.usbharu.hideout.core.application.relationship.unfollow.Unfollow +import dev.usbharu.hideout.core.application.relationship.unfollow.UserUnfollowApplicationService import dev.usbharu.hideout.core.application.timeline.GetUserTimeline import dev.usbharu.hideout.core.application.timeline.GetUserTimelineApplicationService import dev.usbharu.hideout.core.domain.model.support.acct.Acct import dev.usbharu.hideout.core.domain.model.support.page.Page import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous +import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder import org.springframework.stereotype.Controller import org.springframework.ui.Model import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestParam @Controller @@ -20,7 +28,11 @@ class UserController( private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService, private val getUserDetailApplicationService: GetActorDetailApplicationService, private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder, - private val getUserTimelineApplicationService: GetUserTimelineApplicationService + private val getUserTimelineApplicationService: GetUserTimelineApplicationService, + private val userFollowRequestApplicationService: UserFollowRequestApplicationService, + private val getActorDetailApplicationService: GetActorDetailApplicationService, + private val userUnfollowApplicationService: UserUnfollowApplicationService, + private val userGetRelationshipApplicationService: GetRelationshipApplicationService ) { @GetMapping("/users/{name}") suspend fun userById( @@ -38,6 +50,14 @@ class UserController( "user", actorDetail ) + val relationship = + if (principal is LocalUser) { + userGetRelationshipApplicationService.execute(GetRelationship(actorDetail.id), principal) + } else { + null + } + + model.addAttribute("relationship", relationship) model.addAttribute( "userTimeline", getUserTimelineApplicationService.execute( @@ -50,4 +70,24 @@ class UserController( ) return "userById" } + + @PostMapping("/users/{name}/follow") + suspend fun follow(@PathVariable name: String): String { + val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal() + + val actorDetail = getActorDetailApplicationService.execute(GetActorDetail(Acct.of(name), null), principal) + userFollowRequestApplicationService.execute(FollowRequest((actorDetail.id)), principal) + + return "redirect:/users/$name" + } + + @PostMapping("/users/{name}/unfollow") + suspend fun unfollow(@PathVariable name: String): String { + val principal = springSecurityFormLoginPrincipalContextHolder.getPrincipal() + + val actorDetail = getActorDetailApplicationService.execute(GetActorDetail(Acct.of(name), null), principal) + userUnfollowApplicationService.execute(Unfollow((actorDetail.id)), principal) + + return "redirect:/users/$name" + } } diff --git a/hideout-core/src/main/resources/templates/userById.html b/hideout-core/src/main/resources/templates/userById.html index 822c9a3d..cf45d55f 100644 --- a/hideout-core/src/main/resources/templates/userById.html +++ b/hideout-core/src/main/resources/templates/userById.html @@ -19,6 +19,17 @@

+ +
+ +
+
+ +
+
+