mirror of https://github.com/usbharu/Hideout.git
feat: Mastodonの通知APIのNotificationStoreを追加
This commit is contained in:
parent
cf5c396d32
commit
ee3681468b
|
@ -0,0 +1,17 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.domain.model
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Document
|
||||||
|
data class MastodonNotification(
|
||||||
|
@Id
|
||||||
|
val id: Long,
|
||||||
|
val type: NotificationType,
|
||||||
|
val createdAt: Instant,
|
||||||
|
val accountId: Long,
|
||||||
|
val statusId: Long?,
|
||||||
|
val reportId: Long?,
|
||||||
|
val relationshipServeranceEvent: Long?
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.domain.model
|
||||||
|
|
||||||
|
interface MastodonNotificationRepository {
|
||||||
|
suspend fun save(mastodonNotification: MastodonNotification): MastodonNotification
|
||||||
|
suspend fun deleteById(id: Long)
|
||||||
|
suspend fun findById(id: Long): MastodonNotification?
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.domain.model
|
||||||
|
|
||||||
|
enum class NotificationType {
|
||||||
|
mention,
|
||||||
|
status,
|
||||||
|
reblog,
|
||||||
|
follow,
|
||||||
|
follow_request,
|
||||||
|
favourite,
|
||||||
|
poll,
|
||||||
|
update,
|
||||||
|
admin_sign_up,
|
||||||
|
admin_report,
|
||||||
|
severed_relationships;
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.infrastructure.exposedrepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
@Qualifier("jdbc")
|
||||||
|
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "false", matchIfMissing = true)
|
||||||
|
class ExposedMastodonNotificationRepository : MastodonNotificationRepository, AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
|
override suspend fun save(mastodonNotification: MastodonNotification): MastodonNotification = query {
|
||||||
|
val singleOrNull =
|
||||||
|
MastodonNotifications.select { MastodonNotifications.id eq mastodonNotification.id }.singleOrNull()
|
||||||
|
if (singleOrNull == null) {
|
||||||
|
MastodonNotifications.insert {
|
||||||
|
it[MastodonNotifications.id] = mastodonNotification.id
|
||||||
|
it[MastodonNotifications.type] = mastodonNotification.type.name
|
||||||
|
it[MastodonNotifications.createdAt] = mastodonNotification.createdAt
|
||||||
|
it[MastodonNotifications.accountId] = mastodonNotification.accountId
|
||||||
|
it[MastodonNotifications.statusId] = mastodonNotification.statusId
|
||||||
|
it[MastodonNotifications.reportId] = mastodonNotification.reportId
|
||||||
|
it[MastodonNotifications.relationshipServeranceEventId] =
|
||||||
|
mastodonNotification.relationshipServeranceEvent
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MastodonNotifications.update({ MastodonNotifications.id eq mastodonNotification.id }) {
|
||||||
|
it[MastodonNotifications.type] = mastodonNotification.type.name
|
||||||
|
it[MastodonNotifications.createdAt] = mastodonNotification.createdAt
|
||||||
|
it[MastodonNotifications.accountId] = mastodonNotification.accountId
|
||||||
|
it[MastodonNotifications.statusId] = mastodonNotification.statusId
|
||||||
|
it[MastodonNotifications.reportId] = mastodonNotification.reportId
|
||||||
|
it[MastodonNotifications.relationshipServeranceEventId] =
|
||||||
|
mastodonNotification.relationshipServeranceEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mastodonNotification
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteById(id: Long): Unit = query {
|
||||||
|
MastodonNotifications.deleteWhere {
|
||||||
|
MastodonNotifications.id eq id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findById(id: Long): MastodonNotification? = query {
|
||||||
|
MastodonNotifications.select { MastodonNotifications.id eq id }.singleOrNull()?.toMastodonNotification()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ExposedMastodonNotificationRepository::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ResultRow.toMastodonNotification(): MastodonNotification {
|
||||||
|
return MastodonNotification(
|
||||||
|
this[MastodonNotifications.id],
|
||||||
|
NotificationType.valueOf(this[MastodonNotifications.type]),
|
||||||
|
this[MastodonNotifications.createdAt],
|
||||||
|
this[MastodonNotifications.accountId],
|
||||||
|
this[MastodonNotifications.statusId],
|
||||||
|
this[MastodonNotifications.reportId],
|
||||||
|
this[MastodonNotifications.relationshipServeranceEventId],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object MastodonNotifications : Table("mastodon_notifications") {
|
||||||
|
val id = long("id")
|
||||||
|
val type = varchar("type", 100)
|
||||||
|
val createdAt = timestamp("created_at")
|
||||||
|
val accountId = long("account_id")
|
||||||
|
val statusId = long("status_id").nullable()
|
||||||
|
val reportId = long("report_id").nullable()
|
||||||
|
val relationshipServeranceEventId = long("relationship_serverance_event_id").nullable()
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.infrastructure.mongorepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
|
import org.springframework.data.mongodb.repository.MongoRepository
|
||||||
|
|
||||||
|
interface MongoMastodonNotificationRepository : MongoRepository<MastodonNotification, Long> {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.infrastructure.mongorepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
import org.springframework.stereotype.Repository
|
||||||
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "true", matchIfMissing = false)
|
||||||
|
class MongoMastodonNotificationRepositoryWrapper(private val mongoMastodonNotificationRepository: MongoMastodonNotificationRepository) :
|
||||||
|
MastodonNotificationRepository {
|
||||||
|
override suspend fun save(mastodonNotification: MastodonNotification): MastodonNotification {
|
||||||
|
return mongoMastodonNotificationRepository.save(mastodonNotification)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteById(id: Long) {
|
||||||
|
mongoMastodonNotificationRepository.deleteById(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findById(id: Long): MastodonNotification? {
|
||||||
|
return mongoMastodonNotificationRepository.findById(id).getOrNull()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package dev.usbharu.hideout.mastodon.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
|
||||||
|
import dev.usbharu.hideout.core.service.notification.NotificationStore
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotification
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.MastodonNotificationRepository
|
||||||
|
import dev.usbharu.hideout.mastodon.domain.model.NotificationType
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class MastodonNotificationStore(private val mastodonNotificationRepository: MastodonNotificationRepository) :
|
||||||
|
NotificationStore {
|
||||||
|
override suspend fun publishNotification(
|
||||||
|
notification: Notification,
|
||||||
|
user: Actor,
|
||||||
|
sourceActor: Actor?,
|
||||||
|
post: Post?,
|
||||||
|
reaction: Reaction?
|
||||||
|
): Boolean {
|
||||||
|
val notificationType = when (notification.type) {
|
||||||
|
"mention" -> NotificationType.mention
|
||||||
|
"post" -> NotificationType.status
|
||||||
|
"repost" -> NotificationType.reblog
|
||||||
|
"follow" -> NotificationType.follow
|
||||||
|
"follow-request" -> NotificationType.follow_request
|
||||||
|
"reaction" -> NotificationType.favourite
|
||||||
|
else -> {
|
||||||
|
logger.debug("Notification type does not support. type: {}", notification.type)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notification.sourceActorId == null) {
|
||||||
|
logger.debug("Notification does not support. notification.sourceActorId is null")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val mastodonNotification = MastodonNotification(
|
||||||
|
id = notification.id,
|
||||||
|
type = notificationType,
|
||||||
|
createdAt = notification.createdAt,
|
||||||
|
accountId = notification.sourceActorId,
|
||||||
|
statusId = notification.postId,
|
||||||
|
reportId = null,
|
||||||
|
relationshipServeranceEvent = null
|
||||||
|
)
|
||||||
|
|
||||||
|
mastodonNotificationRepository.save(mastodonNotification)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unpulishNotification(notificationId: Long): Boolean {
|
||||||
|
mastodonNotificationRepository.deleteById(notificationId)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(MastodonNotificationStore::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,8 @@ tags:
|
||||||
description: timeline
|
description: timeline
|
||||||
- name: media
|
- name: media
|
||||||
description: media
|
description: media
|
||||||
|
- name: notification
|
||||||
|
description: notification
|
||||||
|
|
||||||
paths:
|
paths:
|
||||||
/api/v2/instance:
|
/api/v2/instance:
|
||||||
|
@ -803,6 +805,122 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/Relationship"
|
$ref: "#/components/schemas/Relationship"
|
||||||
|
|
||||||
|
/api/v1/notifications:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
security:
|
||||||
|
- OAuth2:
|
||||||
|
- "read:notifications"
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: max_id
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: since_id
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: min_id
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: limit
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: types[]
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: exclude_types[]
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: account_id
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Notification"
|
||||||
|
|
||||||
|
/api/v1/notifications/{id}:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
security:
|
||||||
|
- OAuth2:
|
||||||
|
- "read:notifications"
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
required: true
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Notification"
|
||||||
|
|
||||||
|
/api/v1/notifications/clear:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
security:
|
||||||
|
- OAuth2:
|
||||||
|
- "write:notifications"
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
|
||||||
|
/api/v1/notifications/{id}/dismiss:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- notifications
|
||||||
|
security:
|
||||||
|
- OAuth2:
|
||||||
|
- "write:notifications"
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: 成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
V1MediaRequest:
|
V1MediaRequest:
|
||||||
|
@ -1935,6 +2053,47 @@ components:
|
||||||
value:
|
value:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
Report:
|
||||||
|
type: object
|
||||||
|
|
||||||
|
RelationshipServeranceEvent:
|
||||||
|
type: object
|
||||||
|
|
||||||
|
Notification:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- mention
|
||||||
|
- status
|
||||||
|
- reblog
|
||||||
|
- follow
|
||||||
|
- follow_request
|
||||||
|
- favourite
|
||||||
|
- poll
|
||||||
|
- update
|
||||||
|
- admin.sign_up
|
||||||
|
- admin.report
|
||||||
|
- severed_relationships
|
||||||
|
created_at:
|
||||||
|
type: string
|
||||||
|
account:
|
||||||
|
$ref: "#/components/schemas/Account"
|
||||||
|
status:
|
||||||
|
$ref: "#/components/schemas/Status"
|
||||||
|
report:
|
||||||
|
$ref: "#/components/schemas/Report"
|
||||||
|
relationship_severance_event:
|
||||||
|
$ref: "#/components/schemas/RelationshipServeranceEvent"
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- type
|
||||||
|
- created_at
|
||||||
|
- account
|
||||||
|
|
||||||
securitySchemes:
|
securitySchemes:
|
||||||
OAuth2:
|
OAuth2:
|
||||||
type: oauth2
|
type: oauth2
|
||||||
|
|
Loading…
Reference in New Issue