mirror of https://github.com/usbharu/Hideout.git
feat: アカウント作成時に自動でホームタイムラインを作成するように
This commit is contained in:
parent
8e84c8e59c
commit
e728b0f990
|
@ -63,6 +63,9 @@ class RegisterLocalActorApplicationService(
|
||||||
id = UserDetailId(idGenerateService.generateId()),
|
id = UserDetailId(idGenerateService.generateId()),
|
||||||
actorId = actor.id,
|
actorId = actor.id,
|
||||||
password = userDetailDomainService.hashPassword(command.password),
|
password = userDetailDomainService.hashPassword(command.password),
|
||||||
|
autoAcceptFolloweeFollowRequest = false,
|
||||||
|
lastMigration = null,
|
||||||
|
homeTimelineId = null
|
||||||
)
|
)
|
||||||
userDetailRepository.save(userDetail)
|
userDetailRepository.save(userDetail)
|
||||||
return actor.url
|
return actor.url
|
||||||
|
|
|
@ -7,4 +7,4 @@ interface DomainEventSubscriber {
|
||||||
fun <T : DomainEventBody> subscribe(eventName: String, domainEventConsumer: DomainEventConsumer<T>)
|
fun <T : DomainEventBody> subscribe(eventName: String, domainEventConsumer: DomainEventConsumer<T>)
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias DomainEventConsumer<T> = (DomainEvent<T>) -> Unit
|
typealias DomainEventConsumer<T> = suspend (DomainEvent<T>) -> Unit
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
package dev.usbharu.hideout.core.application.domainevent.subscribers
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.shared.DomainEventCommandExecutor
|
||||||
|
import dev.usbharu.hideout.core.application.shared.UserDetailGettableCommandExecutor
|
||||||
|
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,
|
||||||
|
domainEventSubscriber: DomainEventSubscriber
|
||||||
|
) : Subscriber {
|
||||||
|
|
||||||
|
init {
|
||||||
|
domainEventSubscriber.subscribe<RelationshipEventBody>(RelationshipEvent.FOLLOW.eventName) {
|
||||||
|
val relationship = it.body.getRelationship()
|
||||||
|
val userDetail = userDetailRepository.findByActorId(relationship.actorId.id) ?: throw Exception()
|
||||||
|
if (userDetail.homeTimelineId == null) {
|
||||||
|
logger.warn("Home timeline for ${relationship.actorId} is not found")
|
||||||
|
return@subscribe
|
||||||
|
}
|
||||||
|
userAddTimelineRelationshipApplicationService.execute(
|
||||||
|
AddTimelineRelationship(
|
||||||
|
TimelineRelationship(
|
||||||
|
TimelineRelationshipId(idGenerateService.generateId()),
|
||||||
|
userDetail.homeTimelineId,
|
||||||
|
relationship.targetActorId,
|
||||||
|
Visible.FOLLOWERS
|
||||||
|
)
|
||||||
|
), DomainEventCommandExecutor("", object : UserDetailGettableCommandExecutor {
|
||||||
|
override val userDetailId: Long
|
||||||
|
get() = userDetail.id.id
|
||||||
|
override val executor: String
|
||||||
|
get() = userDetail.id.id.toString()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(TimelineRelationshipFollowSubscriber::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,3 +23,8 @@ interface CommandExecutor {
|
||||||
interface UserDetailGettableCommandExecutor : CommandExecutor {
|
interface UserDetailGettableCommandExecutor : CommandExecutor {
|
||||||
val userDetailId: Long
|
val userDetailId: Long
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class DomainEventCommandExecutor(
|
||||||
|
override val executor: String,
|
||||||
|
val commandExecutor: CommandExecutor?
|
||||||
|
) : CommandExecutor
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.usbharu.hideout.core.application.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationship
|
||||||
|
|
||||||
|
data class AddTimelineRelationship(
|
||||||
|
val timelineRelationship: TimelineRelationship
|
||||||
|
)
|
|
@ -0,0 +1,26 @@
|
||||||
|
package dev.usbharu.hideout.core.application.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
|
||||||
|
import dev.usbharu.hideout.core.application.shared.CommandExecutor
|
||||||
|
import dev.usbharu.hideout.core.application.shared.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class UserAddTimelineRelationshipApplicationService(
|
||||||
|
private val timelineRelationshipRepository: TimelineRelationshipRepository,
|
||||||
|
transaction: Transaction
|
||||||
|
) :
|
||||||
|
AbstractApplicationService<AddTimelineRelationship, Unit>(
|
||||||
|
transaction, logger
|
||||||
|
) {
|
||||||
|
override suspend fun internalExecute(command: AddTimelineRelationship, executor: CommandExecutor) {
|
||||||
|
timelineRelationshipRepository.save(command.timelineRelationship)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(UserAddTimelineRelationshipApplicationService::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,7 +25,11 @@ class RelationshipEventFactory(private val relationship: Relationship) {
|
||||||
DomainEvent.create(relationshipEvent.eventName, RelationshipEventBody(relationship))
|
DomainEvent.create(relationshipEvent.eventName, RelationshipEventBody(relationship))
|
||||||
}
|
}
|
||||||
|
|
||||||
class RelationshipEventBody(relationship: Relationship) : DomainEventBody(mapOf("relationship" to relationship))
|
class RelationshipEventBody(relationship: Relationship) : DomainEventBody(mapOf("relationship" to relationship)) {
|
||||||
|
fun getRelationship(): Relationship {
|
||||||
|
return toMap()["relationship"] as Relationship
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class RelationshipEvent(val eventName: String) {
|
enum class RelationshipEvent(val eventName: String) {
|
||||||
FOLLOW("RelationshipFollow"),
|
FOLLOW("RelationshipFollow"),
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.userdetails
|
package dev.usbharu.hideout.core.domain.model.userdetails
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
||||||
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineId
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class UserDetail private constructor(
|
class UserDetail private constructor(
|
||||||
|
@ -25,6 +26,7 @@ class UserDetail private constructor(
|
||||||
var password: UserDetailHashedPassword,
|
var password: UserDetailHashedPassword,
|
||||||
var autoAcceptFolloweeFollowRequest: Boolean,
|
var autoAcceptFolloweeFollowRequest: Boolean,
|
||||||
var lastMigration: Instant? = null,
|
var lastMigration: Instant? = null,
|
||||||
|
val homeTimelineId: TimelineId?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
|
@ -45,13 +47,15 @@ class UserDetail private constructor(
|
||||||
password: UserDetailHashedPassword,
|
password: UserDetailHashedPassword,
|
||||||
autoAcceptFolloweeFollowRequest: Boolean = false,
|
autoAcceptFolloweeFollowRequest: Boolean = false,
|
||||||
lastMigration: Instant? = null,
|
lastMigration: Instant? = null,
|
||||||
|
homeTimelineId: TimelineId?
|
||||||
): UserDetail {
|
): UserDetail {
|
||||||
return UserDetail(
|
return UserDetail(
|
||||||
id,
|
id,
|
||||||
actorId,
|
actorId,
|
||||||
password,
|
password,
|
||||||
autoAcceptFolloweeFollowRequest,
|
autoAcceptFolloweeFollowRequest,
|
||||||
lastMigration
|
lastMigration,
|
||||||
|
homeTimelineId
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorId
|
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.userdetails.UserDetail
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetail
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailHashedPassword
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
|
||||||
|
@ -64,13 +65,7 @@ class UserDetailRepositoryImpl : UserDetailRepository, AbstractRepository() {
|
||||||
.selectAll().where { UserDetails.actorId eq actorId }
|
.selectAll().where { UserDetails.actorId eq actorId }
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
?.let {
|
?.let {
|
||||||
UserDetail.create(
|
userDetail(it)
|
||||||
UserDetailId(it[UserDetails.id]),
|
|
||||||
ActorId(it[UserDetails.actorId]),
|
|
||||||
UserDetailHashedPassword(it[UserDetails.password]),
|
|
||||||
it[UserDetails.autoAcceptFolloweeFollowRequest],
|
|
||||||
it[UserDetails.lastMigration]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,13 +74,7 @@ class UserDetailRepositoryImpl : UserDetailRepository, AbstractRepository() {
|
||||||
.selectAll().where { UserDetails.id eq id }
|
.selectAll().where { UserDetails.id eq id }
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
?.let {
|
?.let {
|
||||||
UserDetail.create(
|
userDetail(it)
|
||||||
UserDetailId(it[UserDetails.id]),
|
|
||||||
ActorId(it[UserDetails.actorId]),
|
|
||||||
UserDetailHashedPassword(it[UserDetails.password]),
|
|
||||||
it[UserDetails.autoAcceptFolloweeFollowRequest],
|
|
||||||
it[UserDetails.lastMigration]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,16 +84,19 @@ class UserDetailRepositoryImpl : UserDetailRepository, AbstractRepository() {
|
||||||
.selectAll()
|
.selectAll()
|
||||||
.where { UserDetails.id inList idList.map { it.id } }
|
.where { UserDetails.id inList idList.map { it.id } }
|
||||||
.map {
|
.map {
|
||||||
UserDetail.create(
|
userDetail(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun userDetail(it: ResultRow) = UserDetail.create(
|
||||||
UserDetailId(it[UserDetails.id]),
|
UserDetailId(it[UserDetails.id]),
|
||||||
ActorId(it[UserDetails.actorId]),
|
ActorId(it[UserDetails.actorId]),
|
||||||
UserDetailHashedPassword(it[UserDetails.password]),
|
UserDetailHashedPassword(it[UserDetails.password]),
|
||||||
it[UserDetails.autoAcceptFolloweeFollowRequest],
|
it[UserDetails.autoAcceptFolloweeFollowRequest],
|
||||||
it[UserDetails.lastMigration]
|
it[UserDetails.lastMigration],
|
||||||
|
it[UserDetails.homeTimelineId]?.let { it1 -> TimelineId(it1) }
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java)
|
private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java)
|
||||||
|
@ -117,5 +109,6 @@ object UserDetails : Table("user_details") {
|
||||||
val password = varchar("password", 255)
|
val password = varchar("password", 255)
|
||||||
val autoAcceptFolloweeFollowRequest = bool("auto_accept_followee_follow_request")
|
val autoAcceptFolloweeFollowRequest = bool("auto_accept_followee_follow_request")
|
||||||
val lastMigration = timestamp("last_migration").nullable()
|
val lastMigration = timestamp("last_migration").nullable()
|
||||||
|
val homeTimelineId = long("home_timeline_id").references(Timelines.id).nullable()
|
||||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class SpringFrameworkDomainEventSubscriber : DomainEventSubscriber {
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventListener
|
@EventListener
|
||||||
fun onDomainEventPublished(domainEvent: DomainEvent<*>) {
|
suspend fun onDomainEventPublished(domainEvent: DomainEvent<*>) {
|
||||||
map[domainEvent.name]?.forEach {
|
map[domainEvent.name]?.forEach {
|
||||||
try {
|
try {
|
||||||
it.invoke(domainEvent)
|
it.invoke(domainEvent)
|
||||||
|
|
Loading…
Reference in New Issue