feat: ユーザー詳細からフォロー/アンフォローできるように

This commit is contained in:
usbharu 2024-09-07 18:46:49 +09:00
parent cf0b0017f6
commit b3a5749b54
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
4 changed files with 80 additions and 1 deletions

View File

@ -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 { companion object {
private val logger = LoggerFactory.getLogger(ExposedTimelineRelationshipRepository::class.java) private val logger = LoggerFactory.getLogger(ExposedTimelineRelationshipRepository::class.java)
} }

View File

@ -58,6 +58,17 @@ class ExposedTimelineRepository(override val domainEventPublisher: DomainEventPu
} }
} }
override suspend fun findAllByUserDetailIdAndVisibilityIn(
userDetailId: UserDetailId,
visibility: List<TimelineVisibility>
): List<Timeline> {
return query {
Timelines.selectAll().where {
Timelines.userDetailId eq userDetailId.id and (Timelines.visibility inList visibility.map { it.name })
}.map { it.toTimeline() }
}
}
companion object { companion object {
private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name) private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java.name)
} }

View File

@ -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.GetActorDetail
import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService import dev.usbharu.hideout.core.application.actor.GetActorDetailApplicationService
import dev.usbharu.hideout.core.application.instance.GetLocalInstanceApplicationService 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.GetUserTimeline
import dev.usbharu.hideout.core.application.timeline.GetUserTimelineApplicationService 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.acct.Acct
import dev.usbharu.hideout.core.domain.model.support.page.Page 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.Anonymous
import dev.usbharu.hideout.core.domain.model.support.principal.LocalUser
import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder import dev.usbharu.hideout.core.infrastructure.springframework.SpringSecurityFormLoginPrincipalContextHolder
import org.springframework.stereotype.Controller import org.springframework.stereotype.Controller
import org.springframework.ui.Model import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RequestParam
@Controller @Controller
@ -20,7 +28,11 @@ class UserController(
private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService, private val getLocalInstanceApplicationService: GetLocalInstanceApplicationService,
private val getUserDetailApplicationService: GetActorDetailApplicationService, private val getUserDetailApplicationService: GetActorDetailApplicationService,
private val springSecurityFormLoginPrincipalContextHolder: SpringSecurityFormLoginPrincipalContextHolder, 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}") @GetMapping("/users/{name}")
suspend fun userById( suspend fun userById(
@ -38,6 +50,15 @@ class UserController(
"user", "user",
actorDetail actorDetail
) )
val relationship =
if (principal is LocalUser) {
userGetRelationshipApplicationService.execute(GetRelationship(actorDetail.id), principal)
} else {
null
}
model.addAttribute("relationship", relationship)
model.addAttribute( model.addAttribute(
"userTimeline", "userTimeline",
getUserTimelineApplicationService.execute( getUserTimelineApplicationService.execute(
@ -50,4 +71,24 @@ class UserController(
) )
return "userById" 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"
}
} }

View File

@ -19,6 +19,17 @@
<h2 th:text="${user.screenName}"></h2> <h2 th:text="${user.screenName}"></h2>
</th:block> </th:block>
<p th:text="'@'+${user.name} + '@' + ${user.host}"></p> <p th:text="'@'+${user.name} + '@' + ${user.host}"></p>
<th:block th:if="${relationship != null}">
<form method="post" th:action="@{/users/{name}/unfollow(name=${user.name+'@'+user.host})}"
th:if="${relationship.following}">
<input type="submit" value="Unfollow">
</form>
<form method="post" th:action="@{/users/{name}/follow(name=${user.name+'@'+user.host})}"
th:unless="${relationship.following}">
<input type="submit" value="Follow">
</form>
</th:block>
</div> </div>
<div> <div>
<p th:text="${user.description}"></p> <p th:text="${user.description}"></p>