feat: Likeを受け取れるように

This commit is contained in:
usbharu 2023-06-04 02:09:01 +09:00
parent f0dbb83c00
commit 9e3a019304
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
11 changed files with 241 additions and 6 deletions

View File

@ -0,0 +1,41 @@
package dev.usbharu.hideout.domain.model.ap
open class Emoji : Object {
var updated: String? = null
var icon: Image? = null
protected constructor() : super()
constructor(type: List<String>,
name: String?,
actor: String?,
id: String?,
updated: String?,
icon: Image?) : super(
type = add(type, "Emoji"),
name = name,
actor = actor,
id = id) {
this.updated = updated
this.icon = icon
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Emoji) return false
if (!super.equals(other)) return false
if (updated != other.updated) return false
return icon == other.icon
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + (updated?.hashCode() ?: 0)
result = 31 * result + (icon?.hashCode() ?: 0)
return result
}
override fun toString(): String = "Emoji(updated=$updated, icon=$icon) ${super.toString()}"
}

View File

@ -0,0 +1,51 @@
package dev.usbharu.hideout.domain.model.ap
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
open class Like : Object {
var `object`: String? = null
var content: String? = null
@JsonDeserialize(contentUsing = ObjectDeserializer::class)
var tag: List<Object> = emptyList()
protected constructor() : super()
constructor(type: List<String>,
name: String?,
actor: String?,
id: String?,
`object`: String?,
content: String?,
tag: List<Object>
) : super(
type = add(type, "Like"),
name = name,
actor = actor,
id = id) {
this.`object` = `object`
this.content = content
this.tag = tag
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Like) return false
if (!super.equals(other)) return false
if (`object` != other.`object`) return false
if (content != other.content) return false
return tag == other.tag
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + (`object`?.hashCode() ?: 0)
result = 31 * result + (content?.hashCode() ?: 0)
result = 31 * result + tag.hashCode()
return result
}
override fun toString(): String = "Like(`object`=$`object`, content=$content, tag=$tag) ${super.toString()}"
}

View File

@ -42,7 +42,7 @@ class ObjectDeserializer : JsonDeserializer<Object>() {
}
else -> {
TODO()
TODO("$activityType is not implementation")
}
}
} else {

View File

@ -0,0 +1,3 @@
package dev.usbharu.hideout.domain.model.hideout.entity
data class Reaction(val id: Long, val emojiId: Long, val postId: Long, val userId: Long)

View File

@ -0,0 +1,8 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
interface ReactionRepository {
suspend fun generateId(): Long
suspend fun save(reaction: Reaction): Reaction
}

View File

@ -0,0 +1,64 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
import dev.usbharu.hideout.service.core.IdGenerateService
import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.dao.id.LongIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
import org.jetbrains.exposed.sql.transactions.transaction
import org.koin.core.annotation.Single
@Single
class ReactionRepositoryImpl(private val database: Database, private val idGenerateService: IdGenerateService) : ReactionRepository {
init {
transaction(database) {
SchemaUtils.create(Reactions)
SchemaUtils.createMissingTablesAndColumns(Reactions)
}
}
@Suppress("InjectDispatcher")
suspend fun <T> query(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() }
override suspend fun generateId(): Long = idGenerateService.generateId()
override suspend fun save(reaction: Reaction): Reaction {
query {
if (Reactions.select { Reactions.id eq reaction.id }.empty()) {
Reactions.insert {
it[id] = reaction.id
it[emojiId] = reaction.emojiId
it[postId] = reaction.postId
it[userId] = reaction.postId
}
} else {
Reactions.update({ Reactions.id eq reaction.id }) {
it[emojiId] = reaction.emojiId
it[postId] = reaction.postId
it[userId] = reaction.postId
}
}
}
return reaction
}
}
fun ResultRow.toReaction(): Reaction {
return Reaction(
this[Reactions.id].value,
this[Reactions.emojiId],
this[Reactions.postId],
this[Reactions.userId]
)
}
object Reactions : LongIdTable("reactions") {
val emojiId = long("emoji_id")
val postId = long("post_id").references(Posts.id)
val userId = long("user_id").references(Users.id)
}

View File

@ -0,0 +1,8 @@
package dev.usbharu.hideout.service.activitypub
import dev.usbharu.hideout.domain.model.ActivityPubResponse
import dev.usbharu.hideout.domain.model.ap.Like
interface ActivityPubLikeService {
suspend fun receiveLike(like: Like): ActivityPubResponse
}

View File

@ -0,0 +1,35 @@
package dev.usbharu.hideout.service.activitypub
import dev.usbharu.hideout.domain.model.ActivityPubResponse
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
import dev.usbharu.hideout.domain.model.ap.Like
import dev.usbharu.hideout.exception.PostNotFoundException
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
import dev.usbharu.hideout.repository.IPostRepository
import dev.usbharu.hideout.service.reaction.IReactionService
import dev.usbharu.hideout.service.user.IUserService
import io.ktor.http.*
import org.koin.core.annotation.Single
@Single
class ActivityPubLikeServiceImpl(private val reactionService: IReactionService,
private val activityPubUserService: ActivityPubUserService,
private val userService: IUserService,
private val postService: IPostRepository) : ActivityPubLikeService {
override suspend fun receiveLike(like: Like): ActivityPubResponse {
val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null")
val content = like.content ?: throw IllegalActivityPubObjectException("content is null")
like.`object` ?: throw IllegalActivityPubObjectException("object is null")
val person = activityPubUserService.fetchPerson(actor)
val user = userService.findByUrl(person.url
?: throw IllegalActivityPubObjectException("actor is not found"))
val post = postService.findByUrl(like.`object`!!)
?: throw PostNotFoundException("${like.`object`} was not found")
reactionService.receiveReaction(content, actor.substringAfter("://").substringBefore("/"), user.id, post.id)
return ActivityPubStringResponse(HttpStatusCode.OK, "")
}
}

View File

@ -21,7 +21,8 @@ class ActivityPubServiceImpl(
private val activityPubNoteService: ActivityPubNoteService,
private val activityPubUndoService: ActivityPubUndoService,
private val activityPubAcceptService: ActivityPubAcceptService,
private val activityPubCreateService: ActivityPubCreateService
private val activityPubCreateService: ActivityPubCreateService,
private val activityPubLikeService: ActivityPubLikeService
) : ActivityPubService {
val logger: Logger = LoggerFactory.getLogger(this::class.java)
@ -53,6 +54,7 @@ class ActivityPubServiceImpl(
)
ActivityType.Create -> activityPubCreateService.receiveCreate(configData.objectMapper.readValue(json))
ActivityType.Like -> activityPubLikeService.receiveLike(configData.objectMapper.readValue(json))
ActivityType.Undo -> activityPubUndoService.receiveUndo(configData.objectMapper.readValue(json))
else -> {

View File

@ -0,0 +1,5 @@
package dev.usbharu.hideout.service.reaction
interface IReactionService {
suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long)
}

View File

@ -0,0 +1,18 @@
package dev.usbharu.hideout.service.reaction
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
import dev.usbharu.hideout.repository.ReactionRepository
import org.koin.core.annotation.Single
@Single
class ReactionServiceImpl(private val reactionRepository: ReactionRepository) : IReactionService {
override suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) {
reactionRepository.save(
Reaction(
reactionRepository.generateId(),
0,
postId, userId
)
)
}
}