mirror of https://github.com/usbharu/Hideout.git
Merge pull request #20 from usbharu/feature/activitypub-like
Feature/activitypub like
This commit is contained in:
commit
714621e098
src/main/kotlin/dev/usbharu/hideout
|
@ -78,6 +78,7 @@ fun Application.parent() {
|
||||||
install(httpSignaturePlugin) {
|
install(httpSignaturePlugin) {
|
||||||
keyMap = KtorKeyMap(get())
|
keyMap = KtorKeyMap(get())
|
||||||
}
|
}
|
||||||
|
expectSuccess = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
single<IdGenerateService> { TwitterSnowflakeIdGenerateService }
|
single<IdGenerateService> { TwitterSnowflakeIdGenerateService }
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
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()}"
|
||||||
|
}
|
|
@ -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()}"
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonParser
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext
|
import com.fasterxml.jackson.databind.DeserializationContext
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import com.fasterxml.jackson.databind.JsonNode
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityVocabulary
|
import dev.usbharu.hideout.service.activitypub.ExtendedActivityVocabulary
|
||||||
|
|
||||||
class ObjectDeserializer : JsonDeserializer<Object>() {
|
class ObjectDeserializer : JsonDeserializer<Object>() {
|
||||||
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Object {
|
override fun deserialize(p: JsonParser?, ctxt: DeserializationContext?): Object {
|
||||||
|
@ -22,28 +22,78 @@ class ObjectDeserializer : JsonDeserializer<Object>() {
|
||||||
val type = treeNode["type"]
|
val type = treeNode["type"]
|
||||||
val activityType = if (type.isArray) {
|
val activityType = if (type.isArray) {
|
||||||
type.firstNotNullOf { jsonNode: JsonNode ->
|
type.firstNotNullOf { jsonNode: JsonNode ->
|
||||||
ActivityVocabulary.values().firstOrNull { it.name.equals(jsonNode.asText(), true) }
|
ExtendedActivityVocabulary.values().firstOrNull { it.name.equals(jsonNode.asText(), true) }
|
||||||
}
|
}
|
||||||
} else if (type.isValueNode) {
|
} else if (type.isValueNode) {
|
||||||
ActivityVocabulary.values().first { it.name.equals(type.asText(), true) }
|
ExtendedActivityVocabulary.values().first { it.name.equals(type.asText(), true) }
|
||||||
} else {
|
} else {
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (activityType) {
|
return when (activityType) {
|
||||||
ActivityVocabulary.Follow -> {
|
ExtendedActivityVocabulary.Follow -> {
|
||||||
val readValue = p.codec.treeToValue(treeNode, Follow::class.java)
|
val readValue = p.codec.treeToValue(treeNode, Follow::class.java)
|
||||||
println(readValue)
|
println(readValue)
|
||||||
readValue
|
readValue
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityVocabulary.Note -> {
|
ExtendedActivityVocabulary.Note -> {
|
||||||
p.codec.treeToValue(treeNode, Note::class.java)
|
p.codec.treeToValue(treeNode, Note::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
ExtendedActivityVocabulary.Object -> p.codec.treeToValue(treeNode, Object::class.java)
|
||||||
TODO()
|
ExtendedActivityVocabulary.Link -> TODO()
|
||||||
}
|
ExtendedActivityVocabulary.Activity -> TODO()
|
||||||
|
ExtendedActivityVocabulary.IntransitiveActivity -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Collection -> TODO()
|
||||||
|
ExtendedActivityVocabulary.OrderedCollection -> TODO()
|
||||||
|
ExtendedActivityVocabulary.CollectionPage -> TODO()
|
||||||
|
ExtendedActivityVocabulary.OrderedCollectionPage -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Accept -> p.codec.treeToValue(treeNode, Accept::class.java)
|
||||||
|
ExtendedActivityVocabulary.Add -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Announce -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Arrive -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Block -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Create -> p.codec.treeToValue(treeNode, Create::class.java)
|
||||||
|
ExtendedActivityVocabulary.Delete -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Dislike -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Flag -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Ignore -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Invite -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Join -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Leave -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Like -> p.codec.treeToValue(treeNode, Like::class.java)
|
||||||
|
ExtendedActivityVocabulary.Listen -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Move -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Offer -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Question -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Reject -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Read -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Remove -> TODO()
|
||||||
|
ExtendedActivityVocabulary.TentativeReject -> TODO()
|
||||||
|
ExtendedActivityVocabulary.TentativeAccept -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Travel -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Undo -> p.codec.treeToValue(treeNode, Undo::class.java)
|
||||||
|
ExtendedActivityVocabulary.Update -> TODO()
|
||||||
|
ExtendedActivityVocabulary.View -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Application -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Group -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Organization -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Person -> p.codec.treeToValue(treeNode, Person::class.java)
|
||||||
|
ExtendedActivityVocabulary.Service -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Article -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Audio -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Document -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Event -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Image -> p.codec.treeToValue(treeNode, Image::class.java)
|
||||||
|
ExtendedActivityVocabulary.Page -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Place -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Profile -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Relationship -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Tombstone -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Video -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Mention -> TODO()
|
||||||
|
ExtendedActivityVocabulary.Emoji -> p.codec.treeToValue(treeNode, Emoji::class.java)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TODO()
|
TODO()
|
||||||
|
|
|
@ -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)
|
|
@ -44,12 +44,14 @@ suspend fun HttpClient.postAp(urlString: String, username: String, jsonLd: JsonL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun HttpClient.getAp(urlString: String, username: String): HttpResponse {
|
suspend fun HttpClient.getAp(urlString: String, username: String?): HttpResponse {
|
||||||
return this.get(urlString) {
|
return this.get(urlString) {
|
||||||
header("Accept", ContentType.Application.Activity)
|
header("Accept", ContentType.Application.Activity)
|
||||||
|
username?.let {
|
||||||
header("Signature", "keyId=\"$username\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date\"")
|
header("Signature", "keyId=\"$username\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class HttpSignaturePluginConfig {
|
class HttpSignaturePluginConfig {
|
||||||
lateinit var keyMap: KeyMap
|
lateinit var keyMap: KeyMap
|
||||||
|
|
|
@ -63,7 +63,9 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findOneById(id: Long, userId: Long?): Post? {
|
override suspend fun findOneById(id: Long, userId: Long?): Post? {
|
||||||
TODO("Not yet implemented")
|
return query {
|
||||||
|
Posts.select { Posts.id eq id }.singleOrNull()?.toPost()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): Post? {
|
override suspend fun findByUrl(url: String): Post? {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
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
|
||||||
|
suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
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.userId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Reactions.update({ Reactions.id eq reaction.id }) {
|
||||||
|
it[emojiId] = reaction.emojiId
|
||||||
|
it[postId] = reaction.postId
|
||||||
|
it[userId] = reaction.userId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reaction
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean {
|
||||||
|
return query {
|
||||||
|
Reactions.select {
|
||||||
|
Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and(
|
||||||
|
Reactions.emojiId.eq(emojiId)
|
||||||
|
)
|
||||||
|
}.empty().not()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
init {
|
||||||
|
uniqueIndex(emojiId, postId, userId)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
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,
|
||||||
|
private val activityPubNoteService: ActivityPubNoteService
|
||||||
|
) : 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)
|
||||||
|
activityPubNoteService.fetchNote(like.`object`!!)
|
||||||
|
|
||||||
|
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, "")
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ import dev.usbharu.hideout.repository.IPostRepository
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.call.*
|
import io.ktor.client.statement.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -76,9 +76,9 @@ class ActivityPubNoteServiceImpl(
|
||||||
}
|
}
|
||||||
val response = httpClient.getAp(
|
val response = httpClient.getAp(
|
||||||
url,
|
url,
|
||||||
"$targetActor#pubkey"
|
targetActor?.let { "$targetActor#pubkey" }
|
||||||
)
|
)
|
||||||
val note = response.body<Note>()
|
val note = Config.configData.objectMapper.readValue<Note>(response.bodyAsText())
|
||||||
return note(note, targetActor, url)
|
return note(note, targetActor, url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -100,3 +100,65 @@ enum class ActivityVocabulary {
|
||||||
Video,
|
Video,
|
||||||
Mention,
|
Mention,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class ExtendedActivityVocabulary {
|
||||||
|
Object,
|
||||||
|
Link,
|
||||||
|
Activity,
|
||||||
|
IntransitiveActivity,
|
||||||
|
Collection,
|
||||||
|
OrderedCollection,
|
||||||
|
CollectionPage,
|
||||||
|
OrderedCollectionPage,
|
||||||
|
Accept,
|
||||||
|
Add,
|
||||||
|
Announce,
|
||||||
|
Arrive,
|
||||||
|
Block,
|
||||||
|
Create,
|
||||||
|
Delete,
|
||||||
|
Dislike,
|
||||||
|
Flag,
|
||||||
|
Follow,
|
||||||
|
Ignore,
|
||||||
|
Invite,
|
||||||
|
Join,
|
||||||
|
Leave,
|
||||||
|
Like,
|
||||||
|
Listen,
|
||||||
|
Move,
|
||||||
|
Offer,
|
||||||
|
Question,
|
||||||
|
Reject,
|
||||||
|
Read,
|
||||||
|
Remove,
|
||||||
|
TentativeReject,
|
||||||
|
TentativeAccept,
|
||||||
|
Travel,
|
||||||
|
Undo,
|
||||||
|
Update,
|
||||||
|
View,
|
||||||
|
Application,
|
||||||
|
Group,
|
||||||
|
Organization,
|
||||||
|
Person,
|
||||||
|
Service,
|
||||||
|
Article,
|
||||||
|
Audio,
|
||||||
|
Document,
|
||||||
|
Event,
|
||||||
|
Image,
|
||||||
|
Note,
|
||||||
|
Page,
|
||||||
|
Place,
|
||||||
|
Profile,
|
||||||
|
Relationship,
|
||||||
|
Tombstone,
|
||||||
|
Video,
|
||||||
|
Mention,
|
||||||
|
Emoji
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ExtendedVocabulary {
|
||||||
|
Emoji
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ class ActivityPubServiceImpl(
|
||||||
private val activityPubNoteService: ActivityPubNoteService,
|
private val activityPubNoteService: ActivityPubNoteService,
|
||||||
private val activityPubUndoService: ActivityPubUndoService,
|
private val activityPubUndoService: ActivityPubUndoService,
|
||||||
private val activityPubAcceptService: ActivityPubAcceptService,
|
private val activityPubAcceptService: ActivityPubAcceptService,
|
||||||
private val activityPubCreateService: ActivityPubCreateService
|
private val activityPubCreateService: ActivityPubCreateService,
|
||||||
|
private val activityPubLikeService: ActivityPubLikeService
|
||||||
) : ActivityPubService {
|
) : ActivityPubService {
|
||||||
|
|
||||||
val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
val logger: Logger = LoggerFactory.getLogger(this::class.java)
|
||||||
|
@ -53,6 +54,7 @@ class ActivityPubServiceImpl(
|
||||||
)
|
)
|
||||||
|
|
||||||
ActivityType.Create -> activityPubCreateService.receiveCreate(configData.objectMapper.readValue(json))
|
ActivityType.Create -> activityPubCreateService.receiveCreate(configData.objectMapper.readValue(json))
|
||||||
|
ActivityType.Like -> activityPubLikeService.receiveLike(configData.objectMapper.readValue(json))
|
||||||
ActivityType.Undo -> activityPubUndoService.receiveUndo(configData.objectMapper.readValue(json))
|
ActivityType.Undo -> activityPubUndoService.receiveUndo(configData.objectMapper.readValue(json))
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|
|
@ -93,7 +93,7 @@ class ActivityPubUserServiceImpl(
|
||||||
RemoteUserCreateDto(
|
RemoteUserCreateDto(
|
||||||
name = person.preferredUsername
|
name = person.preferredUsername
|
||||||
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
||||||
domain = url.substringAfter("://").substringBeforeLast("/"),
|
domain = url.substringAfter("://").substringBefore("/"),
|
||||||
screenName = (person.name ?: person.preferredUsername)
|
screenName = (person.name ?: person.preferredUsername)
|
||||||
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
||||||
description = person.summary.orEmpty(),
|
description = person.summary.orEmpty(),
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.usbharu.hideout.service.api
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
interface IPostApiService {
|
interface IPostApiService {
|
||||||
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): Post
|
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): Post
|
||||||
suspend fun getById(id: Long, userId: Long?): Post
|
suspend fun getById(id: Long, userId: Long?): Post
|
||||||
|
|
|
@ -56,15 +56,15 @@ class PostApiServiceImpl(
|
||||||
return if (idOrNull == null) {
|
return if (idOrNull == null) {
|
||||||
val acct = AcctUtil.parse(nameOrId)
|
val acct = AcctUtil.parse(nameOrId)
|
||||||
postRepository.findByUserNameAndDomain(
|
postRepository.findByUserNameAndDomain(
|
||||||
acct.username,
|
username = acct.username,
|
||||||
acct.domain
|
s = acct.domain
|
||||||
?: Config.configData.domain,
|
?: Config.configData.domain,
|
||||||
since,
|
since = since,
|
||||||
until,
|
until = until,
|
||||||
minId,
|
minId = minId,
|
||||||
maxId,
|
maxId = maxId,
|
||||||
limit,
|
limit = limit,
|
||||||
userId
|
userId = userId
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
postRepository.findByUserId(idOrNull, since, until, minId, maxId, limit, userId)
|
postRepository.findByUserId(idOrNull, since, until, minId, maxId, limit, userId)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.usbharu.hideout.service.reaction
|
||||||
|
|
||||||
|
interface IReactionService {
|
||||||
|
suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long)
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
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) {
|
||||||
|
if (reactionRepository.reactionAlreadyExist(postId, userId, 0).not()) {
|
||||||
|
reactionRepository.save(
|
||||||
|
Reaction(reactionRepository.generateId(), 0, postId, userId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue