mirror of https://github.com/usbharu/Hideout.git
feat: 通知の仕組みを実装
This commit is contained in:
parent
ffdf34e934
commit
90da507e41
|
@ -27,6 +27,7 @@ class ExposedNotificationRepository(private val idGenerateService: IdGenerateSer
|
|||
if (singleOrNull == null) {
|
||||
Notifications.insert {
|
||||
it[id] = notification.id
|
||||
it[type] = notification.type
|
||||
it[userId] = notification.userId
|
||||
it[sourceActorId] = notification.sourceActorId
|
||||
it[postId] = notification.postId
|
||||
|
@ -36,6 +37,7 @@ class ExposedNotificationRepository(private val idGenerateService: IdGenerateSer
|
|||
}
|
||||
} else {
|
||||
Notifications.update({ Notifications.id eq notification.id }) {
|
||||
it[type] = notification.type
|
||||
it[userId] = notification.userId
|
||||
it[sourceActorId] = notification.sourceActorId
|
||||
it[postId] = notification.postId
|
||||
|
@ -62,6 +64,7 @@ class ExposedNotificationRepository(private val idGenerateService: IdGenerateSer
|
|||
|
||||
fun ResultRow.toNotifications() = Notification(
|
||||
this[Notifications.id],
|
||||
this[Notifications.type],
|
||||
this[Notifications.userId],
|
||||
this[Notifications.sourceActorId],
|
||||
this[Notifications.postId],
|
||||
|
@ -72,6 +75,7 @@ fun ResultRow.toNotifications() = Notification(
|
|||
|
||||
object Notifications : Table("notifications") {
|
||||
val id = long("id")
|
||||
val type = varchar("type", 100)
|
||||
val userId = long("user_id").references(Actors.id)
|
||||
val sourceActorId = long("source_actor_id").references(Actors.id).nullable()
|
||||
val postId = long("post_id").references(Posts.id).nullable()
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.time.Instant
|
|||
|
||||
data class Notification(
|
||||
val id: Long,
|
||||
val type: String,
|
||||
val userId: Long,
|
||||
val sourceActorId: Long?,
|
||||
val postId: Long?,
|
||||
|
|
|
@ -13,6 +13,7 @@ interface ReactionRepository {
|
|||
suspend fun deleteByActorId(actorId: Long): Int
|
||||
suspend fun deleteByPostIdAndActorId(postId: Long, actorId: Long)
|
||||
suspend fun deleteByPostIdAndActorIdAndEmoji(postId: Long, actorId: Long, emoji: Emoji)
|
||||
suspend fun findById(id: Long): Reaction?
|
||||
suspend fun findByPostId(postId: Long): List<Reaction>
|
||||
suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction?
|
||||
suspend fun existByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Boolean
|
||||
|
|
|
@ -101,6 +101,10 @@ class ReactionRepositoryImpl(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun findById(id: Long): Reaction? = query {
|
||||
return@query Reactions.select { Reactions.id eq id }.singleOrNull()?.toReaction()
|
||||
}
|
||||
|
||||
override suspend fun findByPostId(postId: Long): List<Reaction> = query {
|
||||
return@query Reactions.leftJoin(CustomEmojis).select { Reactions.postId eq postId }.map { it.toReaction() }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package dev.usbharu.hideout.core.service.notification
|
||||
|
||||
sealed class NotificationRequest(open val userId: Long, open val sourceActorId: Long)
|
||||
import dev.usbharu.hideout.core.domain.model.notification.Notification
|
||||
import java.time.Instant
|
||||
|
||||
sealed class NotificationRequest(open val userId: Long, open val sourceActorId: Long?, val type: String) {
|
||||
abstract fun buildNotification(id: Long, createdAt: Instant): Notification
|
||||
}
|
||||
|
||||
interface PostId {
|
||||
val postId: Long
|
||||
|
@ -9,28 +14,94 @@ interface PostId {
|
|||
data class MentionNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long
|
||||
) : NotificationRequest(
|
||||
userId, sourceActorId
|
||||
), PostId
|
||||
userId, sourceActorId,
|
||||
"mention"
|
||||
), PostId {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
postId,
|
||||
null,
|
||||
null,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
||||
data class PostNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long
|
||||
|
||||
) : NotificationRequest(userId, sourceActorId), PostId
|
||||
) : NotificationRequest(userId, sourceActorId, "post"), PostId {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
postId,
|
||||
null,
|
||||
null,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
||||
data class RepostNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long
|
||||
) : NotificationRequest(userId, sourceActorId), PostId
|
||||
) : NotificationRequest(userId, sourceActorId, "repost"), PostId {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
postId,
|
||||
null,
|
||||
null,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
||||
data class FollowNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long
|
||||
|
||||
) : NotificationRequest(userId, sourceActorId), PostId
|
||||
override val userId: Long, override val sourceActorId: Long
|
||||
) : NotificationRequest(userId, sourceActorId, "follow") {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
||||
data class FollowRequestNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long
|
||||
) : NotificationRequest(userId, sourceActorId), PostId
|
||||
override val userId: Long, override val sourceActorId: Long
|
||||
) : NotificationRequest(userId, sourceActorId, "follow-request") {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
||||
data class ReactionNotificationRequest(
|
||||
override val userId: Long, override val sourceActorId: Long, override val postId: Long, val reactionId: Long
|
||||
|
||||
) : NotificationRequest(userId, sourceActorId), PostId
|
||||
) : NotificationRequest(userId, sourceActorId, "reaction"), PostId {
|
||||
override fun buildNotification(id: Long, createdAt: Instant): Notification = Notification(
|
||||
id,
|
||||
type,
|
||||
userId,
|
||||
sourceActorId,
|
||||
postId,
|
||||
null,
|
||||
reactionId,
|
||||
createdAt
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,6 +3,6 @@ package dev.usbharu.hideout.core.service.notification
|
|||
import dev.usbharu.hideout.core.domain.model.notification.Notification
|
||||
|
||||
interface NotificationService {
|
||||
suspend fun publishNotify(notificationRequest: NotificationRequest): Notification
|
||||
suspend fun publishNotify(notificationRequest: NotificationRequest): Notification?
|
||||
suspend fun unpublishNotify(notificationId: Long)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
package dev.usbharu.hideout.core.service.notification
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||
import dev.usbharu.hideout.core.domain.model.notification.Notification
|
||||
import dev.usbharu.hideout.core.domain.model.notification.NotificationRepository
|
||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.Instant
|
||||
|
||||
@Service
|
||||
class NotificationServiceImpl(
|
||||
private val relationshipNotificationManagementService: RelationshipNotificationManagementService,
|
||||
private val relationshipRepository: RelationshipRepository,
|
||||
private val notificationStoreList: List<NotificationStore>,
|
||||
private val notificationRepository: NotificationRepository,
|
||||
private val actorRepository: ActorRepository,
|
||||
private val postRepository: PostRepository,
|
||||
private val reactionRepository: ReactionRepository
|
||||
) : NotificationService {
|
||||
@Suppress("ReplaceNotNullAssertionWithElvisReturn")
|
||||
override suspend fun publishNotify(notificationRequest: NotificationRequest): Notification? {
|
||||
|
||||
// とりあえず個人間のRelationshipに基づいてきめる。今後増やす
|
||||
if (!relationship(notificationRequest)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val id = notificationRepository.generateId()
|
||||
val createdAt = Instant.now()
|
||||
|
||||
val notification = notificationRequest.buildNotification(id, createdAt)
|
||||
|
||||
val savedNotification = notificationRepository.save(notification)
|
||||
|
||||
// saveで参照整合性違反が発生するはずなので
|
||||
val user = actorRepository.findById(savedNotification.userId)!!
|
||||
val sourceActor = savedNotification.sourceActorId?.let { actorRepository.findById(it) }
|
||||
|
||||
val post = savedNotification.postId?.let { postRepository.findById(it) }
|
||||
val reaction = savedNotification.reactionId?.let { reactionRepository.findById(it) }
|
||||
|
||||
for (it in notificationStoreList) {
|
||||
it.publishNotification(savedNotification, user, sourceActor, post, reaction)
|
||||
}
|
||||
|
||||
return savedNotification
|
||||
}
|
||||
|
||||
override suspend fun unpublishNotify(notificationId: Long) {
|
||||
notificationRepository.deleteById(notificationId)
|
||||
for (notificationStore in notificationStoreList) {
|
||||
notificationStore.unpulishNotification(notificationId)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 個人間のRelationshipに基づいて通知を送信するか判断します
|
||||
*
|
||||
* @param notificationRequest
|
||||
* @return trueの場合送信する
|
||||
*/
|
||||
private suspend fun relationship(notificationRequest: NotificationRequest): Boolean {
|
||||
val targetActorId = notificationRequest.sourceActorId ?: return true
|
||||
val relationship =
|
||||
relationshipRepository.findByUserIdAndTargetUserId(notificationRequest.userId, targetActorId) ?: return true
|
||||
return relationshipNotificationManagementService.sendNotification(relationship, notificationRequest)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package dev.usbharu.hideout.core.service.notification
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||
import dev.usbharu.hideout.core.domain.model.notification.Notification
|
||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||
|
||||
interface NotificationStore {
|
||||
suspend fun publishNotification(
|
||||
notification: Notification,
|
||||
user: Actor,
|
||||
sourceActor: Actor?,
|
||||
post: Post?,
|
||||
reaction: Reaction?
|
||||
): Boolean
|
||||
|
||||
suspend fun unpulishNotification(notificationId: Long): Boolean
|
||||
}
|
|
@ -2,6 +2,6 @@ package dev.usbharu.hideout.core.service.notification
|
|||
|
||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
||||
|
||||
interface NotificationManagimentService {
|
||||
interface RelationshipNotificationManagementService {
|
||||
fun sendNotification(relationship: Relationship, notificationRequest: NotificationRequest): Boolean
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package dev.usbharu.hideout.core.service.notification
|
||||
|
||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
||||
import org.springframework.stereotype.Service
|
||||
|
||||
@Service
|
||||
class RelationshipNotificationManagementServiceImpl : RelationshipNotificationManagementService {
|
||||
override fun sendNotification(relationship: Relationship, notificationRequest: NotificationRequest): Boolean =
|
||||
relationship.muting.not()
|
||||
}
|
Loading…
Reference in New Issue