mirror of https://github.com/usbharu/Hideout.git
Merge pull request #228 from usbharu/feature/for-update-transaction
Feature/for update transaction
This commit is contained in:
commit
f32102fef1
|
@ -43,3 +43,5 @@ out/
|
||||||
/tomcat-e2e/
|
/tomcat-e2e/
|
||||||
/e2eTest.log
|
/e2eTest.log
|
||||||
/files/
|
/files/
|
||||||
|
|
||||||
|
*.log
|
||||||
|
|
|
@ -9,6 +9,9 @@ hideout:
|
||||||
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"
|
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"
|
||||||
storage:
|
storage:
|
||||||
type: local
|
type: local
|
||||||
|
debug:
|
||||||
|
trace-query-exception: true
|
||||||
|
trace-query-call: true
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
flyway:
|
flyway:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package mastodon.account
|
package mastodon.account
|
||||||
|
|
||||||
import dev.usbharu.hideout.SpringApplication
|
import dev.usbharu.hideout.SpringApplication
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedquery.ActorQueryServiceImpl
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedquery.FollowerQueryServiceImpl
|
import dev.usbharu.hideout.core.infrastructure.exposedquery.FollowerQueryServiceImpl
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
|
@ -39,7 +39,7 @@ class AccountApiTest {
|
||||||
private lateinit var followerQueryServiceImpl: FollowerQueryServiceImpl
|
private lateinit var followerQueryServiceImpl: FollowerQueryServiceImpl
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private lateinit var userQueryServiceImpl: ActorQueryServiceImpl
|
private lateinit var actorRepository: ActorRepository
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -100,7 +100,7 @@ class AccountApiTest {
|
||||||
.asyncDispatch()
|
.asyncDispatch()
|
||||||
.andExpect { status { isFound() } }
|
.andExpect { status { isFound() } }
|
||||||
|
|
||||||
userQueryServiceImpl.findByNameAndDomain("api-test-user-1", "example.com")
|
actorRepository.findByNameAndDomain("api-test-user-1", "example.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -116,7 +116,7 @@ class AccountApiTest {
|
||||||
.asyncDispatch()
|
.asyncDispatch()
|
||||||
.andExpect { status { isFound() } }
|
.andExpect { status { isFound() } }
|
||||||
|
|
||||||
userQueryServiceImpl.findByNameAndDomain("api-test-user-2", "example.com")
|
actorRepository.findByNameAndDomain("api-test-user-2", "example.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUser
|
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUser
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.httpsignature.common.HttpHeaders
|
import dev.usbharu.httpsignature.common.HttpHeaders
|
||||||
import dev.usbharu.httpsignature.common.HttpMethod
|
import dev.usbharu.httpsignature.common.HttpMethod
|
||||||
import dev.usbharu.httpsignature.common.HttpRequest
|
import dev.usbharu.httpsignature.common.HttpRequest
|
||||||
|
@ -14,7 +15,7 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
class WithHttpSignatureSecurityContextFactory(
|
class WithHttpSignatureSecurityContextFactory(
|
||||||
private val actorQueryService: ActorQueryService,
|
private val actorRepository: ActorRepository,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction
|
||||||
) : WithSecurityContextFactory<WithHttpSignature> {
|
) : WithSecurityContextFactory<WithHttpSignature> {
|
||||||
|
|
||||||
|
@ -28,7 +29,8 @@ class WithHttpSignatureSecurityContextFactory(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val httpSignatureUser = transaction.transaction {
|
val httpSignatureUser = transaction.transaction {
|
||||||
val findByKeyId = actorQueryService.findByKeyId(annotation.keyId)
|
val findByKeyId =
|
||||||
|
actorRepository.findByKeyId(annotation.keyId) ?: throw UserNotFoundException.withKeyId(annotation.keyId)
|
||||||
HttpSignatureUser(
|
HttpSignatureUser(
|
||||||
findByKeyId.name,
|
findByKeyId.name,
|
||||||
findByKeyId.domain,
|
findByKeyId.domain,
|
||||||
|
|
|
@ -49,9 +49,9 @@ constructor(
|
||||||
@Suppress("CyclomaticComplexMethod")
|
@Suppress("CyclomaticComplexMethod")
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = super.hashCode()
|
var result = super.hashCode()
|
||||||
result = 31 * result + name.hashCode()
|
result = 31 * result + (name?.hashCode() ?: 0)
|
||||||
result = 31 * result + id.hashCode()
|
result = 31 * result + id.hashCode()
|
||||||
result = 31 * result + (preferredUsername?.hashCode() ?: 0)
|
result = 31 * result + preferredUsername.hashCode()
|
||||||
result = 31 * result + (summary?.hashCode() ?: 0)
|
result = 31 * result + (summary?.hashCode() ?: 0)
|
||||||
result = 31 * result + inbox.hashCode()
|
result = 31 * result + inbox.hashCode()
|
||||||
result = 31 * result + outbox.hashCode()
|
result = 31 * result + outbox.hashCode()
|
||||||
|
@ -61,15 +61,15 @@ constructor(
|
||||||
result = 31 * result + endpoints.hashCode()
|
result = 31 * result + endpoints.hashCode()
|
||||||
result = 31 * result + (followers?.hashCode() ?: 0)
|
result = 31 * result + (followers?.hashCode() ?: 0)
|
||||||
result = 31 * result + (following?.hashCode() ?: 0)
|
result = 31 * result + (following?.hashCode() ?: 0)
|
||||||
result = 31 * result + manuallyApprovesFollowers.hashCode()
|
result = 31 * result + (manuallyApprovesFollowers?.hashCode() ?: 0)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Person(" +
|
return "Person(" +
|
||||||
"name='$name', " +
|
"name=$name, " +
|
||||||
"id='$id', " +
|
"id='$id', " +
|
||||||
"preferredUsername=$preferredUsername, " +
|
"preferredUsername='$preferredUsername', " +
|
||||||
"summary=$summary, " +
|
"summary=$summary, " +
|
||||||
"inbox='$inbox', " +
|
"inbox='$inbox', " +
|
||||||
"outbox='$outbox', " +
|
"outbox='$outbox', " +
|
||||||
|
|
|
@ -5,12 +5,10 @@ import dev.usbharu.hideout.activitypub.domain.model.Note
|
||||||
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public
|
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteServiceImpl.Companion.public
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.Query
|
import org.jetbrains.exposed.sql.Query
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
|
@ -21,39 +19,42 @@ import java.time.Instant
|
||||||
@Repository
|
@Repository
|
||||||
class NoteQueryServiceImpl(private val postRepository: PostRepository, private val postQueryMapper: QueryMapper<Post>) :
|
class NoteQueryServiceImpl(private val postRepository: PostRepository, private val postQueryMapper: QueryMapper<Post>) :
|
||||||
NoteQueryService {
|
NoteQueryService {
|
||||||
override suspend fun findById(id: Long): Pair<Note, Post> {
|
override suspend fun findById(id: Long): Pair<Note, Post>? {
|
||||||
return Posts
|
return Posts
|
||||||
.leftJoin(Actors)
|
.leftJoin(Actors)
|
||||||
.leftJoin(PostsMedia)
|
.leftJoin(PostsMedia)
|
||||||
.leftJoin(Media)
|
.leftJoin(Media)
|
||||||
.select { Posts.id eq id }
|
.select { Posts.id eq id }
|
||||||
.let {
|
.let {
|
||||||
it.toNote() to postQueryMapper.map(it)
|
(it.toNote() ?: return null) to (
|
||||||
.singleOr { FailedToGetResourcesException("id: $id does not exist.") }
|
postQueryMapper.map(it)
|
||||||
|
.singleOrNull() ?: return null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByApid(apId: String): Pair<Note, Post> {
|
override suspend fun findByApid(apId: String): Pair<Note, Post>? {
|
||||||
return Posts
|
return Posts
|
||||||
.leftJoin(Actors)
|
.leftJoin(Actors)
|
||||||
.leftJoin(PostsMedia)
|
.leftJoin(PostsMedia)
|
||||||
.leftJoin(Media)
|
.leftJoin(Media)
|
||||||
.select { Posts.apId eq apId }
|
.select { Posts.apId eq apId }
|
||||||
.let {
|
.let {
|
||||||
it.toNote() to postQueryMapper.map(it)
|
(it.toNote() ?: return null) to (
|
||||||
.singleOr { FailedToGetResourcesException("apid: $apId does not exist.") }
|
postQueryMapper.map(it)
|
||||||
|
.singleOrNull() ?: return null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ResultRow.toNote(mediaList: List<dev.usbharu.hideout.core.domain.model.media.Media>): Note {
|
private suspend fun ResultRow.toNote(mediaList: List<dev.usbharu.hideout.core.domain.model.media.Media>): Note {
|
||||||
val replyId = this[Posts.replyId]
|
val replyId = this[Posts.replyId]
|
||||||
val replyTo = if (replyId != null) {
|
val replyTo = if (replyId != null) {
|
||||||
try {
|
val url = postRepository.findById(replyId)?.url
|
||||||
postRepository.findById(replyId).url
|
if (url == null) {
|
||||||
} catch (e: FailedToGetResourcesException) {
|
logger.warn("Failed to get replyId: $replyId")
|
||||||
logger.warn("Failed to get replyId: $replyId", e)
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
url
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -76,11 +77,11 @@ class NoteQueryServiceImpl(private val postRepository: PostRepository, private v
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Query.toNote(): Note {
|
private suspend fun Query.toNote(): Note? {
|
||||||
return this.groupBy { it[Posts.id] }
|
return this.groupBy { it[Posts.id] }
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
.map { it.first().toNote(it.mapNotNull { resultRow -> resultRow.toMediaOrNull() }) }
|
.map { it.first().toNote(it.mapNotNull { resultRow -> resultRow.toMediaOrNull() }) }
|
||||||
.singleOr { FailedToGetResourcesException("resource does not exist.") }
|
.singleOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun visibility(visibility: Visibility, followers: String?): Pair<List<String>, List<String>> {
|
private fun visibility(visibility: Visibility, followers: String?): Pair<List<String>, List<String>> {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package dev.usbharu.hideout.activitypub.interfaces.api.actor
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Person
|
import dev.usbharu.hideout.activitypub.domain.model.Person
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.ResponseEntity
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
@ -12,7 +12,7 @@ class UserAPControllerImpl(private val apUserService: APUserService) : UserAPCon
|
||||||
override suspend fun userAp(username: String): ResponseEntity<Person> {
|
override suspend fun userAp(username: String): ResponseEntity<Person> {
|
||||||
val person = try {
|
val person = try {
|
||||||
apUserService.getPersonByName(username)
|
apUserService.getPersonByName(username)
|
||||||
} catch (_: FailedToGetResourcesException) {
|
} catch (_: UserNotFoundException) {
|
||||||
return ResponseEntity.notFound().build()
|
return ResponseEntity.notFound().build()
|
||||||
}
|
}
|
||||||
person.context += listOf("https://www.w3.org/ns/activitystreams")
|
person.context += listOf("https://www.w3.org/ns/activitystreams")
|
||||||
|
|
|
@ -3,7 +3,7 @@ package dev.usbharu.hideout.activitypub.interfaces.api.webfinger
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.webfinger.WebFinger
|
import dev.usbharu.hideout.activitypub.domain.model.webfinger.WebFinger
|
||||||
import dev.usbharu.hideout.activitypub.service.webfinger.WebFingerApiService
|
import dev.usbharu.hideout.activitypub.service.webfinger.WebFingerApiService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.util.AcctUtil
|
import dev.usbharu.hideout.util.AcctUtil
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -29,7 +29,7 @@ class WebFingerController(
|
||||||
}
|
}
|
||||||
val user = try {
|
val user = try {
|
||||||
webFingerApiService.findByNameAndDomain(acct.username, acct.domain ?: applicationConfig.url.host)
|
webFingerApiService.findByNameAndDomain(acct.username, acct.domain ?: applicationConfig.url.host)
|
||||||
} catch (_: FailedToGetResourcesException) {
|
} catch (_: UserNotFoundException) {
|
||||||
return@runBlocking ResponseEntity.notFound().build()
|
return@runBlocking ResponseEntity.notFound().build()
|
||||||
}
|
}
|
||||||
val webFinger = WebFinger(
|
val webFinger = WebFinger(
|
||||||
|
|
|
@ -4,6 +4,6 @@ import dev.usbharu.hideout.activitypub.domain.model.Note
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
|
|
||||||
interface NoteQueryService {
|
interface NoteQueryService {
|
||||||
suspend fun findById(id: Long): Pair<Note, Post>
|
suspend fun findById(id: Long): Pair<Note, Post>?
|
||||||
suspend fun findByApid(apId: String): Pair<Note, Post>
|
suspend fun findByApid(apId: String): Pair<Note, Post>?
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,22 @@ package dev.usbharu.hideout.activitypub.service.activity.accept
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverAcceptJob
|
import dev.usbharu.hideout.core.external.job.DeliverAcceptJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverAcceptJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class APDeliverAcceptJobProcessor(
|
class APDeliverAcceptJobProcessor(
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val deliverAcceptJob: DeliverAcceptJob,
|
private val deliverAcceptJob: DeliverAcceptJob,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
JobProcessor<DeliverAcceptJobParam, DeliverAcceptJob> {
|
JobProcessor<DeliverAcceptJobParam, DeliverAcceptJob> {
|
||||||
override suspend fun process(param: DeliverAcceptJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverAcceptJobParam): Unit = transaction.transaction {
|
||||||
apRequestService.apPost(param.inbox, param.accept, actorQueryService.findById(param.signer))
|
apRequestService.apPost(param.inbox, param.accept, actorRepository.findById(param.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun job(): DeliverAcceptJob = deliverAcceptJob
|
override fun job(): DeliverAcceptJob = deliverAcceptJob
|
||||||
|
|
|
@ -7,15 +7,16 @@ import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcess
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ApAcceptProcessor(
|
class ApAcceptProcessor(
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val relationshipService: RelationshipService,
|
||||||
private val relationshipService: RelationshipService
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Accept>(transaction) {
|
AbstractActivityPubProcessor<Accept>(transaction) {
|
||||||
|
|
||||||
|
@ -32,8 +33,8 @@ class ApAcceptProcessor(
|
||||||
val userUrl = follow.apObject
|
val userUrl = follow.apObject
|
||||||
val followerUrl = follow.actor
|
val followerUrl = follow.actor
|
||||||
|
|
||||||
val user = actorQueryService.findByUrl(userUrl)
|
val user = actorRepository.findByUrl(userUrl) ?: throw UserNotFoundException.withUrl(userUrl)
|
||||||
val follower = actorQueryService.findByUrl(followerUrl)
|
val follower = actorRepository.findByUrl(followerUrl) ?: throw UserNotFoundException.withUrl(followerUrl)
|
||||||
|
|
||||||
relationshipService.acceptFollowRequest(user.id, follower.id)
|
relationshipService.acceptFollowRequest(user.id, follower.id)
|
||||||
logger.debug("SUCCESS Follow from ${user.url} to ${follower.url}.")
|
logger.debug("SUCCESS Follow from ${user.url} to ${follower.url}.")
|
||||||
|
|
|
@ -5,7 +5,8 @@ import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcess
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -14,14 +15,17 @@ import org.springframework.stereotype.Service
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
class BlockActivityPubProcessor(
|
class BlockActivityPubProcessor(
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val relationshipService: RelationshipService,
|
private val relationshipService: RelationshipService,
|
||||||
|
private val actorRepository: ActorRepository,
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Block>(transaction) {
|
AbstractActivityPubProcessor<Block>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Block>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Block>) {
|
||||||
val user = actorQueryService.findByUrl(activity.activity.actor)
|
val user = actorRepository.findByUrl(activity.activity.actor)
|
||||||
val target = actorQueryService.findByUrl(activity.activity.apObject)
|
?: throw UserNotFoundException.withUrl(activity.activity.actor)
|
||||||
|
val target = actorRepository.findByUrl(activity.activity.apObject) ?: throw UserNotFoundException.withUrl(
|
||||||
|
activity.activity.apObject
|
||||||
|
)
|
||||||
relationshipService.block(user.id, target.id)
|
relationshipService.block(user.id, target.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,11 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Create
|
import dev.usbharu.hideout.activitypub.domain.model.Create
|
||||||
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverPostJob
|
import dev.usbharu.hideout.core.external.job.DeliverPostJob
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -17,9 +19,9 @@ class ApSendCreateServiceImpl(
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val noteQueryService: NoteQueryService,
|
private val noteQueryService: NoteQueryService,
|
||||||
private val applicationConfig: ApplicationConfig
|
private val applicationConfig: ApplicationConfig,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) : ApSendCreateService {
|
) : ApSendCreateService {
|
||||||
override suspend fun createNote(post: Post) {
|
override suspend fun createNote(post: Post) {
|
||||||
logger.info("CREATE Create Local Note ${post.url}")
|
logger.info("CREATE Create Local Note ${post.url}")
|
||||||
|
@ -29,8 +31,8 @@ class ApSendCreateServiceImpl(
|
||||||
|
|
||||||
logger.debug("DELIVER Deliver Note Create ${followers.size} accounts.")
|
logger.debug("DELIVER Deliver Note Create ${followers.size} accounts.")
|
||||||
|
|
||||||
val userEntity = actorQueryService.findById(post.actorId)
|
val userEntity = actorRepository.findById(post.actorId) ?: throw UserNotFoundException.withId(post.actorId)
|
||||||
val note = noteQueryService.findById(post.id).first
|
val note = noteQueryService.findById(post.id)?.first ?: throw PostNotFoundException.withId(post.id)
|
||||||
val create = Create(
|
val create = Create(
|
||||||
name = "Create Note",
|
name = "Create Note",
|
||||||
apObject = note,
|
apObject = note,
|
||||||
|
|
|
@ -8,9 +8,8 @@ import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcess
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.post.PostService
|
import dev.usbharu.hideout.core.service.post.PostService
|
||||||
import dev.usbharu.hideout.core.service.user.UserService
|
import dev.usbharu.hideout.core.service.user.UserService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -18,10 +17,10 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
class APDeleteProcessor(
|
class APDeleteProcessor(
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val postQueryService: PostQueryService,
|
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val postService: PostService
|
private val postService: PostService,
|
||||||
|
private val actorRepository: ActorRepository,
|
||||||
|
private val postRepository: PostRepository
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Delete>(transaction) {
|
AbstractActivityPubProcessor<Delete>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Delete>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Delete>) {
|
||||||
|
@ -34,19 +33,15 @@ class APDeleteProcessor(
|
||||||
throw IllegalActivityPubObjectException("object hasn't id or object")
|
throw IllegalActivityPubObjectException("object hasn't id or object")
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
val actor = actorRepository.findByUrl(deleteId)
|
||||||
val actor = actorQueryService.findByUrl(deleteId)
|
actor?.let { userService.deleteRemoteActor(it.id) }
|
||||||
userService.deleteRemoteActor(actor.id)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
logger.warn("FAILED delete id: {} is not found.", deleteId, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
val post = postRepository.findByApId(deleteId)
|
||||||
val post = postQueryService.findByApId(deleteId)
|
if (post == null) {
|
||||||
postService.deleteRemote(post)
|
logger.warn("FAILED Delete id: {} is not found.", deleteId)
|
||||||
} catch (e: FailedToGetResourcesException) {
|
return
|
||||||
logger.warn("FAILED delete id: {} is not found.", deleteId, e)
|
|
||||||
}
|
}
|
||||||
|
postService.deleteRemote(post)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Delete
|
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Delete
|
||||||
|
|
|
@ -2,21 +2,21 @@ package dev.usbharu.hideout.activitypub.service.activity.delete
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverDeleteJob
|
import dev.usbharu.hideout.core.external.job.DeliverDeleteJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class APDeliverDeleteJobProcessor(
|
class APDeliverDeleteJobProcessor(
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val deliverDeleteJob: DeliverDeleteJob
|
private val deliverDeleteJob: DeliverDeleteJob,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) : JobProcessor<DeliverDeleteJobParam, DeliverDeleteJob> {
|
) : JobProcessor<DeliverDeleteJobParam, DeliverDeleteJob> {
|
||||||
override suspend fun process(param: DeliverDeleteJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverDeleteJobParam): Unit = transaction.transaction {
|
||||||
apRequestService.apPost(param.inbox, param.delete, actorQueryService.findById(param.signer))
|
apRequestService.apPost(param.inbox, param.delete, actorRepository.findById(param.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun job(): DeliverDeleteJob = deliverDeleteJob
|
override fun job(): DeliverDeleteJob = deliverDeleteJob
|
||||||
|
|
|
@ -4,11 +4,12 @@ import dev.usbharu.hideout.activitypub.domain.model.Delete
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Tombstone
|
import dev.usbharu.hideout.activitypub.domain.model.Tombstone
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.objects.ObjectValue
|
import dev.usbharu.hideout.activitypub.domain.model.objects.ObjectValue
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverDeleteJob
|
import dev.usbharu.hideout.core.external.job.DeliverDeleteJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverDeleteJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -24,11 +25,12 @@ class APSendDeleteServiceImpl(
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val delverDeleteJob: DeliverDeleteJob,
|
private val delverDeleteJob: DeliverDeleteJob,
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val applicationConfig: ApplicationConfig
|
private val actorRepository: ActorRepository
|
||||||
) : APSendDeleteService {
|
) : APSendDeleteService {
|
||||||
override suspend fun sendDeleteNote(deletedPost: Post) {
|
override suspend fun sendDeleteNote(deletedPost: Post) {
|
||||||
val actor = actorQueryService.findById(deletedPost.actorId)
|
val actor =
|
||||||
|
actorRepository.findById(deletedPost.actorId) ?: throw UserNotFoundException.withId(deletedPost.actorId)
|
||||||
val followersById = followerQueryService.findFollowersById(deletedPost.actorId)
|
val followersById = followerQueryService.findFollowersById(deletedPost.actorId)
|
||||||
|
|
||||||
val delete = Delete(
|
val delete = Delete(
|
||||||
|
|
|
@ -5,9 +5,10 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Follow
|
import dev.usbharu.hideout.activitypub.domain.model.Follow
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.ReceiveFollowJob
|
import dev.usbharu.hideout.core.external.job.ReceiveFollowJob
|
||||||
import dev.usbharu.hideout.core.external.job.ReceiveFollowJobParam
|
import dev.usbharu.hideout.core.external.job.ReceiveFollowJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -16,10 +17,10 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
class APReceiveFollowJobProcessor(
|
class APReceiveFollowJobProcessor(
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val relationshipService: RelationshipService
|
private val relationshipService: RelationshipService,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
JobProcessor<ReceiveFollowJobParam, ReceiveFollowJob> {
|
JobProcessor<ReceiveFollowJobParam, ReceiveFollowJob> {
|
||||||
override suspend fun process(param: ReceiveFollowJobParam) = transaction.transaction {
|
override suspend fun process(param: ReceiveFollowJobParam) = transaction.transaction {
|
||||||
|
@ -28,9 +29,10 @@ class APReceiveFollowJobProcessor(
|
||||||
|
|
||||||
logger.info("START Follow from: {} to {}", param.targetActor, param.actor)
|
logger.info("START Follow from: {} to {}", param.targetActor, param.actor)
|
||||||
|
|
||||||
val targetEntity = actorQueryService.findByUrl(param.targetActor)
|
val targetEntity =
|
||||||
|
actorRepository.findByUrl(param.targetActor) ?: throw UserNotFoundException.withUrl(param.targetActor)
|
||||||
val followActorEntity =
|
val followActorEntity =
|
||||||
actorQueryService.findByUrl(follow.actor)
|
actorRepository.findByUrl(follow.actor) ?: throw UserNotFoundException.withUrl(follow.actor)
|
||||||
|
|
||||||
relationshipService.followRequest(followActorEntity.id, targetEntity.id)
|
relationshipService.followRequest(followActorEntity.id, targetEntity.id)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteService
|
import dev.usbharu.hideout.activitypub.service.objects.note.APNoteService
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -17,7 +16,6 @@ class APLikeProcessor(
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val apNoteService: APNoteService,
|
private val apNoteService: APNoteService,
|
||||||
private val postQueryService: PostQueryService,
|
|
||||||
private val reactionService: ReactionService
|
private val reactionService: ReactionService
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Like>(transaction) {
|
AbstractActivityPubProcessor<Like>(transaction) {
|
||||||
|
@ -30,23 +28,20 @@ class APLikeProcessor(
|
||||||
val personWithEntity = apUserService.fetchPersonWithEntity(actor)
|
val personWithEntity = apUserService.fetchPersonWithEntity(actor)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
apNoteService.fetchNoteAsync(target).await()
|
val post = apNoteService.fetchNoteWithEntity(target).second
|
||||||
|
reactionService.receiveReaction(
|
||||||
|
content,
|
||||||
|
actor.substringAfter("://").substringBefore("/"),
|
||||||
|
personWithEntity.second.id,
|
||||||
|
post.id
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug("SUCCESS Add Like($content) from ${personWithEntity.second.url} to ${post.url}")
|
||||||
} catch (e: FailedToGetActivityPubResourceException) {
|
} catch (e: FailedToGetActivityPubResourceException) {
|
||||||
logger.debug("FAILED failed to get {}", target)
|
logger.debug("FAILED failed to get {}", target)
|
||||||
logger.trace("", e)
|
logger.trace("", e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val post = postQueryService.findByUrl(target)
|
|
||||||
|
|
||||||
reactionService.receiveReaction(
|
|
||||||
content,
|
|
||||||
actor.substringAfter("://").substringBefore("/"),
|
|
||||||
personWithEntity.second.id,
|
|
||||||
post.id
|
|
||||||
)
|
|
||||||
|
|
||||||
logger.debug("SUCCESS Add Like($content) from ${personWithEntity.second.url} to ${post.url}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Like
|
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Like
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.activity.like
|
package dev.usbharu.hideout.activitypub.service.activity.like
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
|
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
|
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
import dev.usbharu.hideout.core.service.job.JobQueueParentService
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -19,16 +21,16 @@ interface APReactionService {
|
||||||
@Service
|
@Service
|
||||||
class APReactionServiceImpl(
|
class APReactionServiceImpl(
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val postQueryService: PostQueryService,
|
private val actorRepository: ActorRepository,
|
||||||
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
||||||
|
private val postRepository: PostRepository
|
||||||
) : APReactionService {
|
) : APReactionService {
|
||||||
override suspend fun reaction(like: Reaction) {
|
override suspend fun reaction(like: Reaction) {
|
||||||
val followers = followerQueryService.findFollowersById(like.actorId)
|
val followers = followerQueryService.findFollowersById(like.actorId)
|
||||||
val user = actorQueryService.findById(like.actorId)
|
val user = actorRepository.findById(like.actorId) ?: throw UserNotFoundException.withId(like.actorId)
|
||||||
val post =
|
val post =
|
||||||
postQueryService.findById(like.postId)
|
postRepository.findById(like.postId) ?: throw PostNotFoundException.withId(like.postId)
|
||||||
followers.forEach { follower ->
|
followers.forEach { follower ->
|
||||||
jobQueueParentService.schedule(DeliverReactionJob) {
|
jobQueueParentService.schedule(DeliverReactionJob) {
|
||||||
props[DeliverReactionJob.actor] = user.url
|
props[DeliverReactionJob.actor] = user.url
|
||||||
|
@ -42,9 +44,9 @@ class APReactionServiceImpl(
|
||||||
|
|
||||||
override suspend fun removeReaction(like: Reaction) {
|
override suspend fun removeReaction(like: Reaction) {
|
||||||
val followers = followerQueryService.findFollowersById(like.actorId)
|
val followers = followerQueryService.findFollowersById(like.actorId)
|
||||||
val user = actorQueryService.findById(like.actorId)
|
val user = actorRepository.findById(like.actorId) ?: throw UserNotFoundException.withId(like.actorId)
|
||||||
val post =
|
val post =
|
||||||
postQueryService.findById(like.postId)
|
postRepository.findById(like.postId) ?: throw PostNotFoundException.withId(like.postId)
|
||||||
followers.forEach { follower ->
|
followers.forEach { follower ->
|
||||||
jobQueueParentService.schedule(DeliverRemoveReactionJob) {
|
jobQueueParentService.schedule(DeliverRemoveReactionJob) {
|
||||||
props[DeliverRemoveReactionJob.actor] = user.url
|
props[DeliverRemoveReactionJob.actor] = user.url
|
||||||
|
|
|
@ -4,21 +4,21 @@ import dev.usbharu.hideout.activitypub.domain.model.Like
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
|
import dev.usbharu.hideout.core.external.job.DeliverReactionJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverReactionJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverReactionJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ApReactionJobProcessor(
|
class ApReactionJobProcessor(
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) : JobProcessor<DeliverReactionJobParam, DeliverReactionJob> {
|
) : JobProcessor<DeliverReactionJobParam, DeliverReactionJob> {
|
||||||
override suspend fun process(param: DeliverReactionJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverReactionJobParam): Unit = transaction.transaction {
|
||||||
val signer = actorQueryService.findByUrl(param.actor)
|
val signer = actorRepository.findByUrl(param.actor)
|
||||||
|
|
||||||
apRequestService.apPost(
|
apRequestService.apPost(
|
||||||
param.inbox,
|
param.inbox,
|
||||||
|
|
|
@ -7,25 +7,25 @@ import dev.usbharu.hideout.activitypub.domain.model.Undo
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
|
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverRemoveReactionJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ApRemoveReactionJobProcessor(
|
class ApRemoveReactionJobProcessor(
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val applicationConfig: ApplicationConfig
|
private val applicationConfig: ApplicationConfig,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) : JobProcessor<DeliverRemoveReactionJobParam, DeliverRemoveReactionJob> {
|
) : JobProcessor<DeliverRemoveReactionJobParam, DeliverRemoveReactionJob> {
|
||||||
override suspend fun process(param: DeliverRemoveReactionJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverRemoveReactionJobParam): Unit = transaction.transaction {
|
||||||
val like = objectMapper.readValue<Like>(param.like)
|
val like = objectMapper.readValue<Like>(param.like)
|
||||||
|
|
||||||
val signer = actorQueryService.findByUrl(param.actor)
|
val signer = actorRepository.findByUrl(param.actor)
|
||||||
|
|
||||||
apRequestService.apPost(
|
apRequestService.apPost(
|
||||||
param.inbox,
|
param.inbox,
|
||||||
|
|
|
@ -2,22 +2,22 @@ package dev.usbharu.hideout.activitypub.service.activity.reject
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverRejectJob
|
import dev.usbharu.hideout.core.external.job.DeliverRejectJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverRejectJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverRejectJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class APDeliverRejectJobProcessor(
|
class APDeliverRejectJobProcessor(
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val deliverRejectJob: DeliverRejectJob,
|
private val deliverRejectJob: DeliverRejectJob,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
JobProcessor<DeliverRejectJobParam, DeliverRejectJob> {
|
JobProcessor<DeliverRejectJobParam, DeliverRejectJob> {
|
||||||
override suspend fun process(param: DeliverRejectJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverRejectJobParam): Unit = transaction.transaction {
|
||||||
apRequestService.apPost(param.inbox, param.reject, actorQueryService.findById(param.signer))
|
apRequestService.apPost(param.inbox, param.reject, actorRepository.findById(param.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun job(): DeliverRejectJob = deliverRejectJob
|
override fun job(): DeliverRejectJob = deliverRejectJob
|
||||||
|
|
|
@ -6,15 +6,16 @@ import dev.usbharu.hideout.activitypub.service.common.AbstractActivityPubProcess
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ApRejectProcessor(
|
class ApRejectProcessor(
|
||||||
private val relationshipService: RelationshipService,
|
private val relationshipService: RelationshipService,
|
||||||
private val actorQueryService: ActorQueryService,
|
transaction: Transaction,
|
||||||
transaction: Transaction
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
AbstractActivityPubProcessor<Reject>(transaction) {
|
AbstractActivityPubProcessor<Reject>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Reject>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Reject>) {
|
||||||
|
@ -26,13 +27,15 @@ class ApRejectProcessor(
|
||||||
}
|
}
|
||||||
when (activityType) {
|
when (activityType) {
|
||||||
"Follow" -> {
|
"Follow" -> {
|
||||||
val user = actorQueryService.findByUrl(activity.activity.actor)
|
val user = actorRepository.findByUrl(activity.activity.actor) ?: throw UserNotFoundException.withUrl(
|
||||||
|
activity.activity.actor
|
||||||
|
)
|
||||||
|
|
||||||
activity.activity.apObject as Follow
|
activity.activity.apObject as Follow
|
||||||
|
|
||||||
val actor = activity.activity.apObject.actor
|
val actor = activity.activity.apObject.actor
|
||||||
|
|
||||||
val target = actorQueryService.findByUrl(actor)
|
val target = actorRepository.findByUrl(actor) ?: throw UserNotFoundException.withUrl(actor)
|
||||||
|
|
||||||
logger.debug("REJECT Follow user {} target {}", user.url, target.url)
|
logger.debug("REJECT Follow user {} target {}", user.url, target.url)
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ package dev.usbharu.hideout.activitypub.service.activity.undo
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverUndoJob
|
import dev.usbharu.hideout.core.external.job.DeliverUndoJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverUndoJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverUndoJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -12,11 +12,11 @@ import org.springframework.stereotype.Service
|
||||||
class APDeliverUndoJobProcessor(
|
class APDeliverUndoJobProcessor(
|
||||||
private val deliverUndoJob: DeliverUndoJob,
|
private val deliverUndoJob: DeliverUndoJob,
|
||||||
private val apRequestService: APRequestService,
|
private val apRequestService: APRequestService,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val transaction: Transaction,
|
||||||
private val transaction: Transaction
|
private val actorRepository: ActorRepository
|
||||||
) : JobProcessor<DeliverUndoJobParam, DeliverUndoJob> {
|
) : JobProcessor<DeliverUndoJobParam, DeliverUndoJob> {
|
||||||
override suspend fun process(param: DeliverUndoJobParam): Unit = transaction.transaction {
|
override suspend fun process(param: DeliverUndoJobParam): Unit = transaction.transaction {
|
||||||
apRequestService.apPost(param.inbox, param.undo, actorQueryService.findById(param.signer))
|
apRequestService.apPost(param.inbox, param.undo, actorRepository.findById(param.signer))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun job(): DeliverUndoJob = deliverUndoJob
|
override fun job(): DeliverUndoJob = deliverUndoJob
|
||||||
|
|
|
@ -7,8 +7,11 @@ import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
import dev.usbharu.hideout.activitypub.service.common.ActivityType
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.local.LocalUserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
import dev.usbharu.hideout.core.service.reaction.ReactionService
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -17,69 +20,36 @@ import org.springframework.stereotype.Service
|
||||||
class APUndoProcessor(
|
class APUndoProcessor(
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val relationshipService: RelationshipService,
|
private val relationshipService: RelationshipService,
|
||||||
private val postQueryService: PostQueryService,
|
private val reactionService: ReactionService,
|
||||||
private val reactionService: ReactionService
|
private val actorRepository: ActorRepository,
|
||||||
) :
|
private val postRepository: PostRepository
|
||||||
AbstractActivityPubProcessor<Undo>(transaction) {
|
) : AbstractActivityPubProcessor<Undo>(transaction) {
|
||||||
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
|
override suspend fun internalProcess(activity: ActivityPubProcessContext<Undo>) {
|
||||||
val undo = activity.activity
|
val undo = activity.activity
|
||||||
|
|
||||||
val type =
|
val type = undo.apObject.type.firstOrNull {
|
||||||
undo.apObject.type
|
it == "Block" || it == "Follow" || it == "Like" || it == "Announce" || it == "Accept"
|
||||||
.firstOrNull { it == "Block" || it == "Follow" || it == "Like" || it == "Announce" || it == "Accept" }
|
} ?: return
|
||||||
?: return
|
|
||||||
|
|
||||||
when (type) {
|
when (type) {
|
||||||
"Follow" -> {
|
"Follow" -> {
|
||||||
val follow = undo.apObject as Follow
|
follow(undo)
|
||||||
|
|
||||||
apUserService.fetchPerson(undo.actor, follow.apObject)
|
|
||||||
val follower = actorQueryService.findByUrl(undo.actor)
|
|
||||||
val target = actorQueryService.findByUrl(follow.apObject)
|
|
||||||
|
|
||||||
relationshipService.unfollow(follower.id, target.id)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
"Block" -> {
|
"Block" -> {
|
||||||
val block = undo.apObject as Block
|
block(undo)
|
||||||
|
|
||||||
val blocker = apUserService.fetchPersonWithEntity(undo.actor, block.apObject).second
|
|
||||||
val target = actorQueryService.findByUrl(block.apObject)
|
|
||||||
|
|
||||||
relationshipService.unblock(blocker.id, target.id)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
"Accept" -> {
|
"Accept" -> {
|
||||||
val accept = undo.apObject as Accept
|
accept(undo)
|
||||||
|
|
||||||
val acceptObject = if (accept.apObject is ObjectValue) {
|
|
||||||
accept.apObject.`object`
|
|
||||||
} else if (accept.apObject is Follow) {
|
|
||||||
accept.apObject.apObject
|
|
||||||
} else {
|
|
||||||
logger.warn("FAILED Unsupported type. Undo Accept {}", accept.apObject.type)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val accepter = apUserService.fetchPersonWithEntity(undo.actor, acceptObject).second
|
|
||||||
val target = actorQueryService.findByUrl(acceptObject)
|
|
||||||
|
|
||||||
relationshipService.rejectFollowRequest(accepter.id, target.id)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
"Like" -> {
|
"Like" -> {
|
||||||
val like = undo.apObject as Like
|
like(undo)
|
||||||
|
|
||||||
val post = postQueryService.findByUrl(like.apObject)
|
|
||||||
|
|
||||||
val actor = actorQueryService.findByUrl(like.actor)
|
|
||||||
|
|
||||||
reactionService.receiveRemoveReaction(actor.id, post.id)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +58,57 @@ class APUndoProcessor(
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun accept(undo: Undo) {
|
||||||
|
val accept = undo.apObject as Accept
|
||||||
|
|
||||||
|
val acceptObject = if (accept.apObject is ObjectValue) {
|
||||||
|
accept.apObject.`object`
|
||||||
|
} else if (accept.apObject is Follow) {
|
||||||
|
accept.apObject.apObject
|
||||||
|
} else {
|
||||||
|
logger.warn("FAILED Unsupported type. Undo Accept {}", accept.apObject.type)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val accepter = apUserService.fetchPersonWithEntity(undo.actor, acceptObject).second
|
||||||
|
val target = actorRepository.findByUrl(acceptObject) ?: throw UserNotFoundException.withUrl(acceptObject)
|
||||||
|
|
||||||
|
relationshipService.rejectFollowRequest(accepter.id, target.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun like(undo: Undo) {
|
||||||
|
val like = undo.apObject as Like
|
||||||
|
|
||||||
|
val post = postRepository.findByUrl(like.apObject) ?: throw PostNotFoundException.withUrl(like.apObject)
|
||||||
|
|
||||||
|
val signer = actorRepository.findById(post.actorId) ?: throw LocalUserNotFoundException.withId(post.actorId)
|
||||||
|
val actor = apUserService.fetchPersonWithEntity(like.actor, signer.url).second
|
||||||
|
|
||||||
|
reactionService.receiveRemoveReaction(actor.id, post.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun block(undo: Undo) {
|
||||||
|
val block = undo.apObject as Block
|
||||||
|
|
||||||
|
val blocker = apUserService.fetchPersonWithEntity(undo.actor, block.apObject).second
|
||||||
|
val target = actorRepository.findByUrl(block.apObject) ?: throw UserNotFoundException.withUrl(block.apObject)
|
||||||
|
|
||||||
|
relationshipService.unblock(blocker.id, target.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun follow(undo: Undo) {
|
||||||
|
val follow = undo.apObject as Follow
|
||||||
|
|
||||||
|
val follower = apUserService.fetchPersonWithEntity(undo.actor, follow.apObject).second
|
||||||
|
val target = actorRepository.findByUrl(follow.apObject) ?: throw UserNotFoundException.withUrl(follow.apObject)
|
||||||
|
|
||||||
|
relationshipService.unfollow(follower.id, target.id)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Undo
|
override fun isSupported(activityType: ActivityType): Boolean = activityType == ActivityType.Undo
|
||||||
|
|
||||||
override fun type(): Class<Undo> = Undo::class.java
|
override fun type(): Class<Undo> = Undo::class.java
|
||||||
|
|
|
@ -229,7 +229,6 @@ class APServiceImpl(
|
||||||
props[it.json] = json
|
props[it.json] = json
|
||||||
props[it.type] = type.name
|
props[it.type] = type.name
|
||||||
val writeValueAsString = objectMapper.writeValueAsString(httpRequest)
|
val writeValueAsString = objectMapper.writeValueAsString(httpRequest)
|
||||||
println(writeValueAsString)
|
|
||||||
props[it.httpRequest] = writeValueAsString
|
props[it.httpRequest] = writeValueAsString
|
||||||
props[it.headers] = objectMapper.writeValueAsString(map)
|
props[it.headers] = objectMapper.writeValueAsString(map)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ abstract class AbstractActivityPubProcessor<T : Object>(
|
||||||
if (activity.isAuthorized.not() && allowUnauthorized.not()) {
|
if (activity.isAuthorized.not() && allowUnauthorized.not()) {
|
||||||
throw HttpSignatureUnauthorizedException()
|
throw HttpSignatureUnauthorizedException()
|
||||||
}
|
}
|
||||||
logger.info("START ActivityPub process")
|
logger.info("START ActivityPub process. {}", this.type())
|
||||||
try {
|
try {
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
internalProcess(activity)
|
internalProcess(activity)
|
||||||
|
@ -27,7 +27,7 @@ abstract class AbstractActivityPubProcessor<T : Object>(
|
||||||
logger.warn("FAILED ActivityPub process", e)
|
logger.warn("FAILED ActivityPub process", e)
|
||||||
throw FailedProcessException("Failed process", e)
|
throw FailedProcessException("Failed process", e)
|
||||||
}
|
}
|
||||||
logger.info("SUCCESS ActivityPub process")
|
logger.info("SUCCESS ActivityPub process. {}", this.type())
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract suspend fun internalProcess(activity: ActivityPubProcessContext<T>)
|
abstract suspend fun internalProcess(activity: ActivityPubProcessContext<T>)
|
||||||
|
|
|
@ -7,10 +7,8 @@ import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessContext
|
||||||
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessor
|
import dev.usbharu.hideout.activitypub.service.common.ActivityPubProcessor
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.external.job.InboxJob
|
import dev.usbharu.hideout.core.external.job.InboxJob
|
||||||
import dev.usbharu.hideout.core.external.job.InboxJobParam
|
import dev.usbharu.hideout.core.external.job.InboxJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import dev.usbharu.httpsignature.common.HttpHeaders
|
import dev.usbharu.httpsignature.common.HttpHeaders
|
||||||
|
@ -30,7 +28,6 @@ class InboxJobProcessor(
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val signatureHeaderParser: SignatureHeaderParser,
|
private val signatureHeaderParser: SignatureHeaderParser,
|
||||||
private val signatureVerifier: HttpSignatureVerifier,
|
private val signatureVerifier: HttpSignatureVerifier,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction
|
||||||
) : JobProcessor<InboxJobParam, InboxJob> {
|
) : JobProcessor<InboxJobParam, InboxJob> {
|
||||||
|
@ -41,7 +38,8 @@ class InboxJobProcessor(
|
||||||
private suspend fun verifyHttpSignature(
|
private suspend fun verifyHttpSignature(
|
||||||
httpRequest: HttpRequest,
|
httpRequest: HttpRequest,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
transaction: Transaction
|
transaction: Transaction,
|
||||||
|
actor: String
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val requiredHeaders = when (httpRequest.method) {
|
val requiredHeaders = when (httpRequest.method) {
|
||||||
HttpMethod.GET -> getRequiredHeaders
|
HttpMethod.GET -> getRequiredHeaders
|
||||||
|
@ -53,11 +51,7 @@ class InboxJobProcessor(
|
||||||
}
|
}
|
||||||
|
|
||||||
val user = transaction.transaction {
|
val user = transaction.transaction {
|
||||||
try {
|
apUserService.fetchPersonWithEntity(actor).second
|
||||||
actorQueryService.findByKeyId(signature.keyId)
|
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
apUserService.fetchPersonWithEntity(signature.keyId).second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
|
@ -93,7 +87,6 @@ class InboxJobProcessor(
|
||||||
logger.trace("type: {}\njson: \n{}", param.type, jsonNode.toPrettyString())
|
logger.trace("type: {}\njson: \n{}", param.type, jsonNode.toPrettyString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val map = objectMapper.readValue<Map<String, List<String>>>(param.headers)
|
val map = objectMapper.readValue<Map<String, List<String>>>(param.headers)
|
||||||
|
|
||||||
val httpRequest = objectMapper.readValue<HttpRequest>(param.httpRequest).copy(headers = HttpHeaders(map))
|
val httpRequest = objectMapper.readValue<HttpRequest>(param.httpRequest).copy(headers = HttpHeaders(map))
|
||||||
|
@ -104,7 +97,17 @@ class InboxJobProcessor(
|
||||||
|
|
||||||
logger.debug("Has signature? {}", signature != null)
|
logger.debug("Has signature? {}", signature != null)
|
||||||
|
|
||||||
val verify = signature?.let { verifyHttpSignature(httpRequest, it, transaction) } ?: false
|
// todo 不正なactorを取得してしまわないようにする
|
||||||
|
val verify =
|
||||||
|
signature?.let {
|
||||||
|
verifyHttpSignature(
|
||||||
|
httpRequest,
|
||||||
|
it,
|
||||||
|
transaction,
|
||||||
|
jsonNode.get("actor")?.asText() ?: signature.keyId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
?: false
|
||||||
|
|
||||||
logger.debug("Is verifying success? {}", verify)
|
logger.debug("Is verifying success? {}", verify)
|
||||||
|
|
||||||
|
|
|
@ -6,39 +6,21 @@ import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService
|
import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService
|
||||||
import dev.usbharu.hideout.activitypub.service.common.resolve
|
import dev.usbharu.hideout.activitypub.service.common.resolve
|
||||||
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
import dev.usbharu.hideout.activitypub.service.objects.user.APUserService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.media.MediaService
|
import dev.usbharu.hideout.core.service.media.MediaService
|
||||||
import dev.usbharu.hideout.core.service.media.RemoteMedia
|
import dev.usbharu.hideout.core.service.media.RemoteMedia
|
||||||
import dev.usbharu.hideout.core.service.post.PostService
|
import dev.usbharu.hideout.core.service.post.PostService
|
||||||
import io.ktor.client.plugins.*
|
import io.ktor.client.plugins.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Deferred
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.slf4j.MDCContext
|
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.cache.annotation.Cacheable
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
interface APNoteService {
|
interface APNoteService {
|
||||||
|
suspend fun fetchNote(url: String, targetActor: String? = null): Note = fetchNoteWithEntity(url, targetActor).first
|
||||||
@Cacheable("fetchNote")
|
|
||||||
fun fetchNoteAsync(url: String, targetActor: String? = null): Deferred<Note> {
|
|
||||||
return CoroutineScope(Dispatchers.IO + MDCContext()).async {
|
|
||||||
newSuspendedTransaction(MDCContext()) {
|
|
||||||
fetchNote(url, targetActor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun fetchNote(url: String, targetActor: String? = null): Note
|
|
||||||
suspend fun fetchNote(note: Note, targetActor: String? = null): Note
|
suspend fun fetchNote(note: Note, targetActor: String? = null): Note
|
||||||
|
suspend fun fetchNoteWithEntity(url: String, targetActor: String? = null): Pair<Note, Post>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -46,7 +28,6 @@ interface APNoteService {
|
||||||
class APNoteServiceImpl(
|
class APNoteServiceImpl(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: PostRepository,
|
||||||
private val apUserService: APUserService,
|
private val apUserService: APUserService,
|
||||||
private val postQueryService: PostQueryService,
|
|
||||||
private val postService: PostService,
|
private val postService: PostService,
|
||||||
private val apResourceResolveService: APResourceResolveService,
|
private val apResourceResolveService: APResourceResolveService,
|
||||||
private val postBuilder: Post.PostBuilder,
|
private val postBuilder: Post.PostBuilder,
|
||||||
|
@ -57,13 +38,14 @@ class APNoteServiceImpl(
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(APNoteServiceImpl::class.java)
|
private val logger = LoggerFactory.getLogger(APNoteServiceImpl::class.java)
|
||||||
|
|
||||||
override suspend fun fetchNote(url: String, targetActor: String?): Note {
|
override suspend fun fetchNoteWithEntity(url: String, targetActor: String?): Pair<Note, Post> {
|
||||||
logger.debug("START Fetch Note url: {}", url)
|
logger.debug("START Fetch Note url: {}", url)
|
||||||
try {
|
|
||||||
val post = noteQueryService.findByApid(url)
|
val post = noteQueryService.findByApid(url)
|
||||||
|
|
||||||
|
if (post != null) {
|
||||||
logger.debug("SUCCESS Found in local url: {}", url)
|
logger.debug("SUCCESS Found in local url: {}", url)
|
||||||
return post.first
|
return post
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("AP GET url: {}", url)
|
logger.info("AP GET url: {}", url)
|
||||||
|
@ -77,7 +59,7 @@ class APNoteServiceImpl(
|
||||||
)
|
)
|
||||||
throw FailedToGetActivityPubResourceException("Could not retrieve $url.", e)
|
throw FailedToGetActivityPubResourceException("Could not retrieve $url.", e)
|
||||||
}
|
}
|
||||||
val savedNote = saveNote(note, targetActor, url)
|
val savedNote = saveIfMissing(note, targetActor, url)
|
||||||
logger.debug("SUCCESS Fetch Note url: {}", url)
|
logger.debug("SUCCESS Fetch Note url: {}", url)
|
||||||
return savedNote
|
return savedNote
|
||||||
}
|
}
|
||||||
|
@ -86,58 +68,51 @@ class APNoteServiceImpl(
|
||||||
note: Note,
|
note: Note,
|
||||||
targetActor: String?,
|
targetActor: String?,
|
||||||
url: String
|
url: String
|
||||||
): Note {
|
): Pair<Note, Post> = noteQueryService.findByApid(note.id) ?: saveNote(note, targetActor, url)
|
||||||
requireNotNull(note.id) { "id is null" }
|
|
||||||
|
|
||||||
return try {
|
private suspend fun saveNote(note: Note, targetActor: String?, url: String): Pair<Note, Post> {
|
||||||
noteQueryService.findByApid(note.id).first
|
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
saveNote(note, targetActor, url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun saveNote(note: Note, targetActor: String?, url: String): Note {
|
|
||||||
val person = apUserService.fetchPersonWithEntity(
|
val person = apUserService.fetchPersonWithEntity(
|
||||||
note.attributedTo,
|
note.attributedTo,
|
||||||
targetActor
|
targetActor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val post = postRepository.findByApId(note.id)
|
||||||
|
|
||||||
|
if (post != null) {
|
||||||
|
return note to post
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug("VISIBILITY url: {} to: {} cc: {}", note.id, note.to, note.cc)
|
logger.debug("VISIBILITY url: {} to: {} cc: {}", note.id, note.to, note.cc)
|
||||||
|
|
||||||
val visibility =
|
val visibility = if (note.to.contains(public)) {
|
||||||
if (note.to.contains(public)) {
|
Visibility.PUBLIC
|
||||||
Visibility.PUBLIC
|
} else if (note.to.contains(person.second.followers) && note.cc.contains(public)) {
|
||||||
} else if (note.to.contains(person.second.followers) && note.cc.contains(public)) {
|
Visibility.UNLISTED
|
||||||
Visibility.UNLISTED
|
} else if (note.to.contains(person.second.followers)) {
|
||||||
} else if (note.to.contains(person.second.followers)) {
|
Visibility.FOLLOWERS
|
||||||
Visibility.FOLLOWERS
|
} else {
|
||||||
} else {
|
Visibility.DIRECT
|
||||||
Visibility.DIRECT
|
}
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("VISIBILITY is {} url: {}", visibility.name, note.id)
|
logger.debug("VISIBILITY is {} url: {}", visibility.name, note.id)
|
||||||
|
|
||||||
val reply = note.inReplyTo?.let {
|
val reply = note.inReplyTo?.let {
|
||||||
fetchNote(it, targetActor)
|
fetchNote(it, targetActor)
|
||||||
postQueryService.findByUrl(it)
|
postRepository.findByUrl(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
val mediaList = note.attachment
|
val mediaList = note.attachment.map {
|
||||||
.filter { it.url != null }
|
mediaService.uploadRemoteMedia(
|
||||||
.map {
|
RemoteMedia(
|
||||||
mediaService.uploadRemoteMedia(
|
it.name,
|
||||||
RemoteMedia(
|
it.url,
|
||||||
it.name,
|
it.mediaType,
|
||||||
it.url,
|
description = it.name
|
||||||
it.mediaType,
|
|
||||||
description = it.name
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
.map { it.id }
|
}.map { it.id }
|
||||||
|
|
||||||
// TODO: リモートのメディア処理を追加
|
val createRemote = postService.createRemote(
|
||||||
postService.createRemote(
|
|
||||||
postBuilder.of(
|
postBuilder.of(
|
||||||
id = postRepository.generateId(),
|
id = postRepository.generateId(),
|
||||||
actorId = person.second.id,
|
actorId = person.second.id,
|
||||||
|
@ -151,11 +126,11 @@ class APNoteServiceImpl(
|
||||||
mediaIds = mediaList
|
mediaIds = mediaList
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return note
|
return note to createRemote
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
||||||
saveIfMissing(note, targetActor, note.id)
|
saveIfMissing(note, targetActor, note.id).first
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
const val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
||||||
|
|
|
@ -5,9 +5,9 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Create
|
import dev.usbharu.hideout.activitypub.domain.model.Create
|
||||||
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
import dev.usbharu.hideout.activitypub.service.common.APRequestService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverPostJob
|
import dev.usbharu.hideout.core.external.job.DeliverPostJob
|
||||||
import dev.usbharu.hideout.core.external.job.DeliverPostJobParam
|
import dev.usbharu.hideout.core.external.job.DeliverPostJobParam
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.job.JobProcessor
|
import dev.usbharu.hideout.core.service.job.JobProcessor
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -16,13 +16,13 @@ import org.springframework.stereotype.Service
|
||||||
class ApNoteJobProcessor(
|
class ApNoteJobProcessor(
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val apRequestService: APRequestService,
|
||||||
private val apRequestService: APRequestService
|
private val actorRepository: ActorRepository
|
||||||
) : JobProcessor<DeliverPostJobParam, DeliverPostJob> {
|
) : JobProcessor<DeliverPostJobParam, DeliverPostJob> {
|
||||||
override suspend fun process(param: DeliverPostJobParam) {
|
override suspend fun process(param: DeliverPostJobParam) {
|
||||||
val create = objectMapper.readValue<Create>(param.create)
|
val create = objectMapper.readValue<Create>(param.create)
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
val signer = actorQueryService.findByUrl(param.actor)
|
val signer = actorRepository.findByUrl(param.actor)
|
||||||
|
|
||||||
logger.debug("CreateNoteJob: actor: {} create: {} inbox: {}", param.actor, create, param.inbox)
|
logger.debug("CreateNoteJob: actor: {} create: {} inbox: {}", param.actor, create, param.inbox)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package dev.usbharu.hideout.activitypub.service.objects.note
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Note
|
import dev.usbharu.hideout.activitypub.domain.model.Note
|
||||||
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
import dev.usbharu.hideout.activitypub.query.NoteQueryService
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
|
@ -17,12 +16,13 @@ class NoteApApiServiceImpl(
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction
|
||||||
) : NoteApApiService {
|
) : NoteApApiService {
|
||||||
override suspend fun getNote(postId: Long, userId: Long?): Note? = transaction.transaction {
|
override suspend fun getNote(postId: Long, userId: Long?): Note? = transaction.transaction {
|
||||||
val findById = try {
|
val findById = noteQueryService.findById(postId)
|
||||||
noteQueryService.findById(postId)
|
|
||||||
} catch (e: FailedToGetResourcesException) {
|
if (findById == null) {
|
||||||
logger.warn("Note not found.", e)
|
logger.warn("Note not found. $postId $userId")
|
||||||
return@transaction null
|
return@transaction null
|
||||||
}
|
}
|
||||||
|
|
||||||
when (findById.second.visibility) {
|
when (findById.second.visibility) {
|
||||||
Visibility.PUBLIC, Visibility.UNLISTED -> {
|
Visibility.PUBLIC, Visibility.UNLISTED -> {
|
||||||
return@transaction findById.first
|
return@transaction findById.first
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.objects.user
|
package dev.usbharu.hideout.activitypub.service.objects.user
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.exception.IllegalActivityPubObjectException
|
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Image
|
import dev.usbharu.hideout.activitypub.domain.model.Image
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Key
|
import dev.usbharu.hideout.activitypub.domain.model.Key
|
||||||
import dev.usbharu.hideout.activitypub.domain.model.Person
|
import dev.usbharu.hideout.activitypub.domain.model.Person
|
||||||
|
@ -8,13 +7,12 @@ import dev.usbharu.hideout.activitypub.service.common.APResourceResolveService
|
||||||
import dev.usbharu.hideout.activitypub.service.common.resolve
|
import dev.usbharu.hideout.activitypub.service.common.resolve
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.service.user.RemoteUserCreateDto
|
import dev.usbharu.hideout.core.service.user.RemoteUserCreateDto
|
||||||
import dev.usbharu.hideout.core.service.user.UserService
|
import dev.usbharu.hideout.core.service.user.UserService
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
|
||||||
|
|
||||||
interface APUserService {
|
interface APUserService {
|
||||||
suspend fun getPersonByName(name: String): Person
|
suspend fun getPersonByName(name: String): Person
|
||||||
|
@ -34,16 +32,17 @@ interface APUserService {
|
||||||
@Service
|
@Service
|
||||||
class APUserServiceImpl(
|
class APUserServiceImpl(
|
||||||
private val userService: UserService,
|
private val userService: UserService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val apResourceResolveService: APResourceResolveService
|
private val apResourceResolveService: APResourceResolveService,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
APUserService {
|
APUserService {
|
||||||
|
|
||||||
override suspend fun getPersonByName(name: String): Person {
|
override suspend fun getPersonByName(name: String): Person {
|
||||||
val userEntity = transaction.transaction {
|
val userEntity = transaction.transaction {
|
||||||
actorQueryService.findByNameAndDomain(name, applicationConfig.url.host)
|
actorRepository.findByNameAndDomain(name, applicationConfig.url.host)
|
||||||
|
?: throw UserNotFoundException.withNameAndDomain(name, applicationConfig.url.host)
|
||||||
}
|
}
|
||||||
// TODO: JOINで書き直し
|
// TODO: JOINで書き直し
|
||||||
val userUrl = "${applicationConfig.url}/users/$name"
|
val userUrl = "${applicationConfig.url}/users/$name"
|
||||||
|
@ -76,40 +75,40 @@ class APUserServiceImpl(
|
||||||
override suspend fun fetchPerson(url: String, targetActor: String?): Person =
|
override suspend fun fetchPerson(url: String, targetActor: String?): Person =
|
||||||
fetchPersonWithEntity(url, targetActor).first
|
fetchPersonWithEntity(url, targetActor).first
|
||||||
|
|
||||||
@Transactional
|
|
||||||
override suspend fun fetchPersonWithEntity(url: String, targetActor: String?): Pair<Person, Actor> {
|
override suspend fun fetchPersonWithEntity(url: String, targetActor: String?): Pair<Person, Actor> {
|
||||||
return try {
|
val userEntity = actorRepository.findByUrl(url)
|
||||||
val userEntity = actorQueryService.findByUrl(url)
|
|
||||||
val id = userEntity.url
|
|
||||||
return entityToPerson(userEntity, id) to userEntity
|
|
||||||
} catch (ignore: FailedToGetResourcesException) {
|
|
||||||
val person = apResourceResolveService.resolve<Person>(url, null as Long?)
|
|
||||||
|
|
||||||
val id = person.id
|
if (userEntity != null) {
|
||||||
try {
|
return entityToPerson(userEntity, userEntity.url) to userEntity
|
||||||
val userEntity = actorQueryService.findByUrl(id)
|
|
||||||
return entityToPerson(userEntity, id) to userEntity
|
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
|
||||||
person to userService.createRemoteUser(
|
|
||||||
RemoteUserCreateDto(
|
|
||||||
name = person.preferredUsername
|
|
||||||
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
|
||||||
domain = id.substringAfter("://").substringBefore("/"),
|
|
||||||
screenName = person.name ?: person.preferredUsername,
|
|
||||||
description = person.summary.orEmpty(),
|
|
||||||
inbox = person.inbox,
|
|
||||||
outbox = person.outbox,
|
|
||||||
url = id,
|
|
||||||
publicKey = person.publicKey.publicKeyPem,
|
|
||||||
keyId = person.publicKey.id,
|
|
||||||
following = person.following,
|
|
||||||
followers = person.followers,
|
|
||||||
sharedInbox = person.endpoints["sharedInbox"],
|
|
||||||
locked = person.manuallyApprovesFollowers
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val person = apResourceResolveService.resolve<Person>(url, null as Long?)
|
||||||
|
|
||||||
|
val id = person.id
|
||||||
|
|
||||||
|
val actor = actorRepository.findByUrlWithLock(id)
|
||||||
|
|
||||||
|
if (actor != null) {
|
||||||
|
return person to actor
|
||||||
|
}
|
||||||
|
|
||||||
|
return person to userService.createRemoteUser(
|
||||||
|
RemoteUserCreateDto(
|
||||||
|
name = person.preferredUsername,
|
||||||
|
domain = id.substringAfter("://").substringBefore("/"),
|
||||||
|
screenName = person.name ?: person.preferredUsername,
|
||||||
|
description = person.summary.orEmpty(),
|
||||||
|
inbox = person.inbox,
|
||||||
|
outbox = person.outbox,
|
||||||
|
url = id,
|
||||||
|
publicKey = person.publicKey.publicKeyPem,
|
||||||
|
keyId = person.publicKey.id,
|
||||||
|
following = person.following,
|
||||||
|
followers = person.followers,
|
||||||
|
sharedInbox = person.endpoints["sharedInbox"],
|
||||||
|
locked = person.manuallyApprovesFollowers
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun entityToPerson(
|
private fun entityToPerson(
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package dev.usbharu.hideout.activitypub.service.webfinger
|
package dev.usbharu.hideout.activitypub.service.webfinger
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -11,11 +12,17 @@ interface WebFingerApiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class WebFingerApiServiceImpl(private val transaction: Transaction, private val actorQueryService: ActorQueryService) :
|
class WebFingerApiServiceImpl(
|
||||||
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
|
) :
|
||||||
WebFingerApiService {
|
WebFingerApiService {
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): Actor {
|
override suspend fun findByNameAndDomain(name: String, domain: String): Actor {
|
||||||
return transaction.transaction {
|
return transaction.transaction {
|
||||||
actorQueryService.findByNameAndDomain(name, domain)
|
actorRepository.findByNameAndDomain(name, domain) ?: throw UserNotFoundException.withNameAndDomain(
|
||||||
|
name,
|
||||||
|
domain
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,19 +7,18 @@ import com.nimbusds.jose.jwk.source.ImmutableJWKSet
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource
|
import com.nimbusds.jose.jwk.source.JWKSource
|
||||||
import com.nimbusds.jose.proc.SecurityContext
|
import com.nimbusds.jose.proc.SecurityContext
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureFilter
|
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureFilter
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUserDetailsService
|
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureUserDetailsService
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureVerifierComposite
|
import dev.usbharu.hideout.core.infrastructure.springframework.httpsignature.HttpSignatureVerifierComposite
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsImpl
|
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsImpl
|
||||||
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsServiceImpl
|
import dev.usbharu.hideout.core.infrastructure.springframework.oauth2.UserDetailsServiceImpl
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import dev.usbharu.hideout.util.hasAnyScope
|
import dev.usbharu.hideout.util.hasAnyScope
|
||||||
import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner
|
import dev.usbharu.httpsignature.sign.RsaSha256HttpSignatureSigner
|
||||||
import dev.usbharu.httpsignature.verify.DefaultSignatureHeaderParser
|
import dev.usbharu.httpsignature.verify.DefaultSignatureHeaderParser
|
||||||
import dev.usbharu.httpsignature.verify.RsaSha256HttpSignatureVerifier
|
import dev.usbharu.httpsignature.verify.RsaSha256HttpSignatureVerifier
|
||||||
import jakarta.annotation.PostConstruct
|
import jakarta.annotation.PostConstruct
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
|
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
@ -68,9 +67,6 @@ import java.util.*
|
||||||
@Suppress("FunctionMaxLength", "TooManyFunctions")
|
@Suppress("FunctionMaxLength", "TooManyFunctions")
|
||||||
class SecurityConfig {
|
class SecurityConfig {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private lateinit var actorQueryService: ActorQueryService
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? =
|
fun authenticationManager(authenticationConfiguration: AuthenticationConfiguration): AuthenticationManager? =
|
||||||
authenticationConfiguration.authenticationManager
|
authenticationConfiguration.authenticationManager
|
||||||
|
@ -130,12 +126,14 @@ class SecurityConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Order(1)
|
@Order(1)
|
||||||
fun httpSignatureAuthenticationProvider(transaction: Transaction): PreAuthenticatedAuthenticationProvider {
|
fun httpSignatureAuthenticationProvider(
|
||||||
|
transaction: Transaction,
|
||||||
|
actorRepository: ActorRepository
|
||||||
|
): PreAuthenticatedAuthenticationProvider {
|
||||||
val provider = PreAuthenticatedAuthenticationProvider()
|
val provider = PreAuthenticatedAuthenticationProvider()
|
||||||
val signatureHeaderParser = DefaultSignatureHeaderParser()
|
val signatureHeaderParser = DefaultSignatureHeaderParser()
|
||||||
provider.setPreAuthenticatedUserDetailsService(
|
provider.setPreAuthenticatedUserDetailsService(
|
||||||
HttpSignatureUserDetailsService(
|
HttpSignatureUserDetailsService(
|
||||||
actorQueryService,
|
|
||||||
HttpSignatureVerifierComposite(
|
HttpSignatureVerifierComposite(
|
||||||
mapOf(
|
mapOf(
|
||||||
"rsa-sha256" to RsaSha256HttpSignatureVerifier(
|
"rsa-sha256" to RsaSha256HttpSignatureVerifier(
|
||||||
|
@ -145,7 +143,8 @@ class SecurityConfig {
|
||||||
signatureHeaderParser
|
signatureHeaderParser
|
||||||
),
|
),
|
||||||
transaction,
|
transaction,
|
||||||
signatureHeaderParser
|
signatureHeaderParser,
|
||||||
|
actorRepository
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
provider.setUserDetailsChecker(AccountStatusUserDetailsChecker())
|
provider.setUserDetailsChecker(AccountStatusUserDetailsChecker())
|
||||||
|
|
|
@ -1,25 +1,37 @@
|
||||||
package dev.usbharu.hideout.application.infrastructure.exposed
|
package dev.usbharu.hideout.application.infrastructure.exposed
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.slf4j.MDCContext
|
import kotlinx.coroutines.slf4j.MDCContext
|
||||||
import org.jetbrains.exposed.sql.StdOutSqlLogger
|
import org.jetbrains.exposed.sql.Slf4jSqlDebugLogger
|
||||||
import org.jetbrains.exposed.sql.addLogger
|
import org.jetbrains.exposed.sql.addLogger
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class ExposedTransaction : Transaction {
|
class ExposedTransaction : Transaction {
|
||||||
override suspend fun <T> transaction(block: suspend () -> T): T {
|
override suspend fun <T> transaction(block: suspend () -> T): T {
|
||||||
return newSuspendedTransaction(MDCContext(), transactionIsolation = Connection.TRANSACTION_SERIALIZABLE) {
|
// return newSuspendedTransaction(MDCContext(), transactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED) {
|
||||||
addLogger(StdOutSqlLogger)
|
// warnLongQueriesDuration = 1000
|
||||||
block()
|
// addLogger(Slf4jSqlDebugLogger)
|
||||||
|
// block()
|
||||||
|
// }
|
||||||
|
|
||||||
|
return transaction(transactionIsolation = Connection.TRANSACTION_READ_COMMITTED) {
|
||||||
|
debug = true
|
||||||
|
warnLongQueriesDuration = 1000
|
||||||
|
addLogger(Slf4jSqlDebugLogger)
|
||||||
|
runBlocking(MDCContext()) {
|
||||||
|
block()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun <T> transaction(transactionLevel: Int, block: suspend () -> T): T {
|
override suspend fun <T> transaction(transactionLevel: Int, block: suspend () -> T): T {
|
||||||
return newSuspendedTransaction(MDCContext(), transactionIsolation = transactionLevel) {
|
return newSuspendedTransaction(MDCContext(), transactionIsolation = transactionLevel) {
|
||||||
addLogger(StdOutSqlLogger)
|
addLogger(Slf4jSqlDebugLogger)
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
|
open class HideoutException : RuntimeException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 8506638570017469956L
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.ResourceAccessException
|
||||||
|
|
||||||
|
interface SQLExceptionTranslator {
|
||||||
|
fun translate(message: String, sql: String? = null, exception: Exception): ResourceAccessException
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.ResourceAccessException
|
||||||
|
import org.springframework.dao.DataAccessException
|
||||||
|
import org.springframework.dao.DuplicateKeyException
|
||||||
|
|
||||||
|
class SpringDataAccessExceptionSQLExceptionTranslator : SQLExceptionTranslator {
|
||||||
|
override fun translate(message: String, sql: String?, exception: Exception): ResourceAccessException {
|
||||||
|
if (exception !is DataAccessException) {
|
||||||
|
throw IllegalArgumentException("exception must be DataAccessException.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (exception) {
|
||||||
|
is DuplicateKeyException -> DuplicateException(message, exception.rootCause)
|
||||||
|
else -> ResourceAccessException(message, exception.rootCause)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
|
class DuplicateException : ResourceAccessException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 7092046653037974417L
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource
|
||||||
|
|
||||||
|
open class NotFoundException : ResourceAccessException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
|
class PostNotFoundException : NotFoundException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 1315818410686905717L
|
||||||
|
|
||||||
|
fun withApId(apId: String): PostNotFoundException = PostNotFoundException("apId: $apId was not found.")
|
||||||
|
|
||||||
|
fun withId(id: Long): PostNotFoundException = PostNotFoundException("id: $id was not found.")
|
||||||
|
|
||||||
|
fun withUrl(url: String): PostNotFoundException = PostNotFoundException("url: $url was not found.")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.HideoutException
|
||||||
|
|
||||||
|
open class ResourceAccessException : HideoutException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource
|
||||||
|
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
|
open class UserNotFoundException : NotFoundException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = 3219433672235626200L
|
||||||
|
|
||||||
|
fun withName(string: String, throwable: Throwable? = null): UserNotFoundException =
|
||||||
|
UserNotFoundException("name: $string was not found.", throwable)
|
||||||
|
|
||||||
|
fun withId(id: Long, throwable: Throwable? = null): UserNotFoundException =
|
||||||
|
UserNotFoundException("id: $id was not found.", throwable)
|
||||||
|
|
||||||
|
fun withUrl(url: String, throwable: Throwable? = null): UserNotFoundException =
|
||||||
|
UserNotFoundException("url: $url was not found.", throwable)
|
||||||
|
|
||||||
|
fun withNameAndDomain(name: String, domain: String, throwable: Throwable? = null): UserNotFoundException =
|
||||||
|
UserNotFoundException("name: $name domain: $domain (@$name@$domain) was not found.", throwable)
|
||||||
|
|
||||||
|
fun withKeyId(keyId: String, throwable: Throwable? = null) =
|
||||||
|
UserNotFoundException("keyId: $keyId was not found.", throwable)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package dev.usbharu.hideout.core.domain.exception.resource.local
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import java.io.Serial
|
||||||
|
|
||||||
|
class LocalUserNotFoundException : UserNotFoundException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(message: String?) : super(message)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
||||||
|
message,
|
||||||
|
cause,
|
||||||
|
enableSuppression,
|
||||||
|
writableStackTrace
|
||||||
|
)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Serial
|
||||||
|
private const val serialVersionUID: Long = -4742548128672528145L
|
||||||
|
|
||||||
|
fun withName(string: String, throwable: Throwable? = null): LocalUserNotFoundException =
|
||||||
|
LocalUserNotFoundException("name: $string was not found.", throwable)
|
||||||
|
|
||||||
|
fun withId(id: Long, throwable: Throwable? = null): LocalUserNotFoundException =
|
||||||
|
LocalUserNotFoundException("id: $id was not found.", throwable)
|
||||||
|
|
||||||
|
fun withUrl(url: String, throwable: Throwable? = null): LocalUserNotFoundException =
|
||||||
|
LocalUserNotFoundException("url: $url was not found.", throwable)
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,6 +57,31 @@ data class Actor private constructor(
|
||||||
postsCount: Int = 0,
|
postsCount: Int = 0,
|
||||||
lastPostDate: Instant? = null
|
lastPostDate: Instant? = null
|
||||||
): Actor {
|
): Actor {
|
||||||
|
if (id == 0L) {
|
||||||
|
return Actor(
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
domain = domain,
|
||||||
|
screenName = screenName,
|
||||||
|
description = description,
|
||||||
|
inbox = inbox,
|
||||||
|
outbox = outbox,
|
||||||
|
url = url,
|
||||||
|
publicKey = publicKey,
|
||||||
|
privateKey = privateKey,
|
||||||
|
createdAt = createdAt,
|
||||||
|
keyId = keyId,
|
||||||
|
followers = followers,
|
||||||
|
following = following,
|
||||||
|
instance = instance,
|
||||||
|
locked = locked,
|
||||||
|
followersCount = followersCount,
|
||||||
|
followingCount = followingCount,
|
||||||
|
postsCount = postsCount,
|
||||||
|
lastPostDate = lastPostDate
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// idは0未満ではいけない
|
// idは0未満ではいけない
|
||||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
require(id >= 0) { "id must be greater than or equal to 0." }
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,30 @@ package dev.usbharu.hideout.core.domain.model.actor
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
|
@Suppress("TooManyFunctions")
|
||||||
interface ActorRepository {
|
interface ActorRepository {
|
||||||
suspend fun save(actor: Actor): Actor
|
suspend fun save(actor: Actor): Actor
|
||||||
|
|
||||||
suspend fun findById(id: Long): Actor?
|
suspend fun findById(id: Long): Actor?
|
||||||
|
|
||||||
|
suspend fun findByIdWithLock(id: Long): Actor?
|
||||||
|
|
||||||
|
suspend fun findAll(limit: Int, offset: Long): List<Actor>
|
||||||
|
|
||||||
|
suspend fun findByName(name: String): List<Actor>
|
||||||
|
|
||||||
|
suspend fun findByNameAndDomain(name: String, domain: String): Actor?
|
||||||
|
|
||||||
|
suspend fun findByNameAndDomainWithLock(name: String, domain: String): Actor?
|
||||||
|
|
||||||
|
suspend fun findByUrl(url: String): Actor?
|
||||||
|
|
||||||
|
suspend fun findByUrlWithLock(url: String): Actor?
|
||||||
|
|
||||||
|
suspend fun findByIds(ids: List<Long>): List<Actor>
|
||||||
|
|
||||||
|
suspend fun findByKeyId(keyId: String): Actor?
|
||||||
|
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
|
|
||||||
suspend fun nextId(): Long
|
suspend fun nextId(): Long
|
||||||
|
|
|
@ -3,5 +3,6 @@ package dev.usbharu.hideout.core.domain.model.deletedActor
|
||||||
interface DeletedActorRepository {
|
interface DeletedActorRepository {
|
||||||
suspend fun save(deletedActor: DeletedActor): DeletedActor
|
suspend fun save(deletedActor: DeletedActor): DeletedActor
|
||||||
suspend fun delete(deletedActor: DeletedActor)
|
suspend fun delete(deletedActor: DeletedActor)
|
||||||
suspend fun findById(id: Long): DeletedActor
|
suspend fun findById(id: Long): DeletedActor?
|
||||||
|
suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor?
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.usbharu.hideout.core.domain.model.instance
|
||||||
interface InstanceRepository {
|
interface InstanceRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(instance: Instance): Instance
|
suspend fun save(instance: Instance): Instance
|
||||||
suspend fun findById(id: Long): Instance
|
suspend fun findById(id: Long): Instance?
|
||||||
suspend fun delete(instance: Instance)
|
suspend fun delete(instance: Instance)
|
||||||
|
suspend fun findByUrl(url: String): Instance?
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package dev.usbharu.hideout.core.domain.model.media
|
||||||
interface MediaRepository {
|
interface MediaRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(media: Media): Media
|
suspend fun save(media: Media): Media
|
||||||
suspend fun findById(id: Long): Media
|
suspend fun findById(id: Long): Media?
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
|
suspend fun findByRemoteUrl(remoteUrl: String): Media?
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,12 @@ import org.springframework.stereotype.Repository
|
||||||
@Repository
|
@Repository
|
||||||
interface PostRepository {
|
interface PostRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(post: Post): Boolean
|
suspend fun save(post: Post): Post
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
suspend fun findById(id: Long): Post
|
suspend fun findById(id: Long): Post?
|
||||||
|
suspend fun findByUrl(url: String): Post?
|
||||||
|
|
||||||
|
suspend fun findByApId(apId: String): Post?
|
||||||
|
suspend fun existByApIdWithLock(apId: String): Boolean
|
||||||
|
suspend fun findByActorId(actorId: Long): List<Post>
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,15 @@ package dev.usbharu.hideout.core.domain.model.reaction
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
|
@Suppress("FunctionMaxLength")
|
||||||
interface ReactionRepository {
|
interface ReactionRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(reaction: Reaction): Reaction
|
suspend fun save(reaction: Reaction): Reaction
|
||||||
suspend fun delete(reaction: Reaction): Reaction
|
suspend fun delete(reaction: Reaction): Reaction
|
||||||
suspend fun deleteByPostId(postId: Long): Int
|
suspend fun deleteByPostId(postId: Long): Int
|
||||||
suspend fun deleteByActorId(actorId: Long): Int
|
suspend fun deleteByActorId(actorId: Long): Int
|
||||||
|
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
|
||||||
|
suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List<Reaction>
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,4 +30,16 @@ interface RelationshipRepository {
|
||||||
suspend fun findByUserIdAndTargetUserId(actorId: Long, targetActorId: Long): Relationship?
|
suspend fun findByUserIdAndTargetUserId(actorId: Long, targetActorId: Long): Relationship?
|
||||||
|
|
||||||
suspend fun deleteByActorIdOrTargetActorId(actorId: Long, targetActorId: Long)
|
suspend fun deleteByActorIdOrTargetActorId(actorId: Long, targetActorId: Long)
|
||||||
|
|
||||||
|
suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship>
|
||||||
|
|
||||||
|
@Suppress("LongParameterList", "FunctionMaxLength")
|
||||||
|
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
|
maxId: Long?,
|
||||||
|
sinceId: Long?,
|
||||||
|
limit: Int,
|
||||||
|
targetId: Long,
|
||||||
|
followRequest: Boolean,
|
||||||
|
ignoreFollowRequest: Boolean
|
||||||
|
): List<Relationship>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
package dev.usbharu.hideout.core.domain.model.relationship
|
package dev.usbharu.hideout.core.domain.model.relationship
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.AbstractRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
||||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class RelationshipRepositoryImpl : RelationshipRepository {
|
class RelationshipRepositoryImpl : RelationshipRepository, AbstractRepository() {
|
||||||
override suspend fun save(relationship: Relationship): Relationship {
|
override suspend fun save(relationship: Relationship): Relationship = query {
|
||||||
val singleOrNull =
|
val singleOrNull = Relationships.select {
|
||||||
Relationships
|
(Relationships.actorId eq relationship.actorId).and(
|
||||||
.select {
|
Relationships.targetActorId eq relationship.targetActorId
|
||||||
(Relationships.actorId eq relationship.actorId)
|
)
|
||||||
.and(Relationships.targetActorId eq relationship.targetActorId)
|
}.forUpdate().singleOrNull()
|
||||||
}
|
|
||||||
.singleOrNull()
|
|
||||||
|
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
Relationships.insert {
|
Relationships.insert {
|
||||||
|
@ -28,41 +29,77 @@ class RelationshipRepositoryImpl : RelationshipRepository {
|
||||||
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
|
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Relationships
|
Relationships.update({
|
||||||
.update({
|
(Relationships.actorId eq relationship.actorId).and(
|
||||||
(Relationships.actorId eq relationship.actorId)
|
Relationships.targetActorId eq relationship.targetActorId
|
||||||
.and(Relationships.targetActorId eq relationship.targetActorId)
|
)
|
||||||
}) {
|
}) {
|
||||||
it[following] = relationship.following
|
it[following] = relationship.following
|
||||||
it[blocking] = relationship.blocking
|
it[blocking] = relationship.blocking
|
||||||
it[muting] = relationship.muting
|
it[muting] = relationship.muting
|
||||||
it[followRequest] = relationship.followRequest
|
it[followRequest] = relationship.followRequest
|
||||||
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
|
it[ignoreFollowRequestFromTarget] = relationship.ignoreFollowRequestToTarget
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return relationship
|
return@query relationship
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(relationship: Relationship) {
|
override suspend fun delete(relationship: Relationship): Unit = query {
|
||||||
Relationships.deleteWhere {
|
Relationships.deleteWhere {
|
||||||
(Relationships.actorId eq relationship.actorId)
|
(Relationships.actorId eq relationship.actorId).and(
|
||||||
.and(Relationships.targetActorId eq relationship.targetActorId)
|
Relationships.targetActorId eq relationship.targetActorId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByUserIdAndTargetUserId(actorId: Long, targetActorId: Long): Relationship? {
|
override suspend fun findByUserIdAndTargetUserId(actorId: Long, targetActorId: Long): Relationship? = query {
|
||||||
return Relationships.select {
|
return@query Relationships.select {
|
||||||
(Relationships.actorId eq actorId)
|
(Relationships.actorId eq actorId).and(Relationships.targetActorId eq targetActorId)
|
||||||
.and(Relationships.targetActorId eq targetActorId)
|
}.singleOrNull()?.toRelationships()
|
||||||
}.singleOrNull()
|
|
||||||
?.toRelationships()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByActorIdOrTargetActorId(actorId: Long, targetActorId: Long) {
|
override suspend fun deleteByActorIdOrTargetActorId(actorId: Long, targetActorId: Long): Unit = query {
|
||||||
Relationships.deleteWhere {
|
Relationships.deleteWhere {
|
||||||
Relationships.actorId.eq(actorId).or(Relationships.targetActorId.eq(targetActorId))
|
Relationships.actorId.eq(actorId).or(Relationships.targetActorId.eq(targetActorId))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship> = query {
|
||||||
|
return@query Relationships
|
||||||
|
.select { Relationships.targetActorId eq targetId and (Relationships.following eq following) }
|
||||||
|
.map { it.toRelationships() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
|
maxId: Long?,
|
||||||
|
sinceId: Long?,
|
||||||
|
limit: Int,
|
||||||
|
targetId: Long,
|
||||||
|
followRequest: Boolean,
|
||||||
|
ignoreFollowRequest: Boolean
|
||||||
|
): List<Relationship> = query {
|
||||||
|
val query = Relationships.select {
|
||||||
|
Relationships.targetActorId.eq(targetId).and(Relationships.followRequest.eq(followRequest))
|
||||||
|
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
|
||||||
|
}.limit(limit)
|
||||||
|
|
||||||
|
if (maxId != null) {
|
||||||
|
query.andWhere { Relationships.id lessEq maxId }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sinceId != null) {
|
||||||
|
query.andWhere { Relationships.id greaterEq sinceId }
|
||||||
|
}
|
||||||
|
|
||||||
|
return@query query.map { it.toRelationships() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(RelationshipRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toRelationships(): Relationship = Relationship(
|
fun ResultRow.toRelationships(): Relationship = Relationship(
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class ActorQueryServiceImpl(
|
|
||||||
private val actorResultRowMapper: ResultRowMapper<Actor>,
|
|
||||||
private val actorQueryMapper: QueryMapper<Actor>
|
|
||||||
) : ActorQueryService {
|
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(ActorQueryServiceImpl::class.java)
|
|
||||||
|
|
||||||
override suspend fun findAll(limit: Int, offset: Long): List<Actor> =
|
|
||||||
Actors.selectAll().limit(limit, offset).let(actorQueryMapper::map)
|
|
||||||
|
|
||||||
override suspend fun findById(id: Long): Actor = Actors.select { Actors.id eq id }
|
|
||||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }
|
|
||||||
.let(actorResultRowMapper::map)
|
|
||||||
|
|
||||||
override suspend fun findByName(name: String): List<Actor> =
|
|
||||||
Actors.select { Actors.name eq name }.let(actorQueryMapper::map)
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): Actor =
|
|
||||||
Actors
|
|
||||||
.select { Actors.name eq name and (Actors.domain eq domain) }
|
|
||||||
.singleOr {
|
|
||||||
FailedToGetResourcesException("name: $name,domain: $domain is duplicate or does not exist.", it)
|
|
||||||
}
|
|
||||||
.let(actorResultRowMapper::map)
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): Actor {
|
|
||||||
logger.trace("findByUrl url: $url")
|
|
||||||
return Actors.select { Actors.url eq url }
|
|
||||||
.singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }
|
|
||||||
.let(actorResultRowMapper::map)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<Actor> =
|
|
||||||
Actors.select { Actors.id inList ids }.let(actorQueryMapper::map)
|
|
||||||
|
|
||||||
override suspend fun existByNameAndDomain(name: String, domain: String): Boolean =
|
|
||||||
Actors.select { Actors.name eq name and (Actors.domain eq domain) }.empty().not()
|
|
||||||
|
|
||||||
override suspend fun findByKeyId(keyId: String): Actor {
|
|
||||||
return Actors.select { Actors.keyId eq keyId }
|
|
||||||
.singleOr { FailedToGetResourcesException("keyId: $keyId is duplicate or does not exist.", it) }
|
|
||||||
.let(actorResultRowMapper::map)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.DeletedActors
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toDeletedActor
|
|
||||||
import dev.usbharu.hideout.core.query.DeletedActorQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class DeletedActorQueryServiceImpl : DeletedActorQueryService {
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor {
|
|
||||||
return DeletedActors
|
|
||||||
.select { DeletedActors.name eq name and (DeletedActors.domain eq domain) }
|
|
||||||
.singleOr {
|
|
||||||
FailedToGetResourcesException("name: $name domain: $domain was not exist or duplicate.", it)
|
|
||||||
}
|
|
||||||
.toDeletedActor()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +1,19 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
import dev.usbharu.hideout.core.query.RelationshipQueryService
|
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class FollowerQueryServiceImpl(
|
class FollowerQueryServiceImpl(
|
||||||
private val relationshipQueryService: RelationshipQueryService,
|
private val relationshipRepository: RelationshipRepository,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val actorRepository: ActorRepository
|
||||||
private val relationshipRepository: RelationshipRepository
|
|
||||||
) : FollowerQueryService {
|
) : FollowerQueryService {
|
||||||
override suspend fun findFollowersById(id: Long): List<Actor> {
|
override suspend fun findFollowersById(id: Long): List<Actor> {
|
||||||
return actorQueryService.findByIds(
|
return actorRepository.findByIds(
|
||||||
relationshipQueryService.findByTargetIdAndFollowing(id, true).map { it.actorId }
|
relationshipRepository.findByTargetIdAndFollowing(id, true).map { it.actorId }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Instance
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toInstance
|
|
||||||
import dev.usbharu.hideout.core.query.InstanceQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Instance as InstanceEntity
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class InstanceQueryServiceImpl : InstanceQueryService {
|
|
||||||
override suspend fun findByUrl(url: String): InstanceEntity = Instance.select { Instance.url eq url }
|
|
||||||
.singleOr { FailedToGetResourcesException("$url is doesn't exist", it) }.toInstance()
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Media
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.PostsMedia
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toMedia
|
|
||||||
import dev.usbharu.hideout.core.query.MediaQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.innerJoin
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media as MediaEntity
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class MediaQueryServiceImpl : MediaQueryService {
|
|
||||||
override suspend fun findByPostId(postId: Long): List<MediaEntity> {
|
|
||||||
return Media.innerJoin(
|
|
||||||
PostsMedia,
|
|
||||||
onColumn = { id },
|
|
||||||
otherColumn = { mediaId }
|
|
||||||
)
|
|
||||||
.select { PostsMedia.postId eq postId }
|
|
||||||
.map { it.toMedia() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByRemoteUrl(remoteUrl: String): MediaEntity {
|
|
||||||
return Media.select { Media.remoteUrl eq remoteUrl }
|
|
||||||
.singleOr { FailedToGetResourcesException("remoteUrl: $remoteUrl is duplicate or not exist.", it) }
|
|
||||||
.toMedia()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.PostsMedia
|
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class PostQueryServiceImpl(
|
|
||||||
private val postResultRowMapper: ResultRowMapper<Post>,
|
|
||||||
private val postQueryMapper: QueryMapper<Post>
|
|
||||||
) : PostQueryService {
|
|
||||||
override suspend fun findById(id: Long): Post =
|
|
||||||
Posts.leftJoin(PostsMedia)
|
|
||||||
.select { Posts.id eq id }
|
|
||||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }
|
|
||||||
.let(postResultRowMapper::map)
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): Post =
|
|
||||||
Posts.leftJoin(PostsMedia)
|
|
||||||
.select { Posts.url eq url }
|
|
||||||
.let(postQueryMapper::map)
|
|
||||||
.singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }
|
|
||||||
|
|
||||||
override suspend fun findByApId(string: String): Post =
|
|
||||||
Posts.leftJoin(PostsMedia)
|
|
||||||
.select { Posts.apId eq string }
|
|
||||||
.let(postQueryMapper::map)
|
|
||||||
.singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) }
|
|
||||||
|
|
||||||
override suspend fun findByActorId(actorId: Long): List<Post> =
|
|
||||||
Posts.leftJoin(PostsMedia).select { Posts.actorId eq actorId }.let(postQueryMapper::map)
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Reactions
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.toReaction
|
|
||||||
import dev.usbharu.hideout.core.query.ReactionQueryService
|
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
class ReactionQueryServiceImpl : ReactionQueryService {
|
|
||||||
override suspend fun findByPostId(postId: Long, actorId: Long?): List<Reaction> {
|
|
||||||
return Reactions.select {
|
|
||||||
Reactions.postId.eq(postId)
|
|
||||||
}.map { it.toReaction() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("FunctionMaxLength")
|
|
||||||
override suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction {
|
|
||||||
return Reactions
|
|
||||||
.select {
|
|
||||||
Reactions.postId.eq(postId).and(Reactions.actorId.eq(actorId)).and(
|
|
||||||
Reactions.emojiId.eq(emojiId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.singleOr {
|
|
||||||
FailedToGetResourcesException(
|
|
||||||
"postId: $postId,userId: $actorId,emojiId: $emojiId is duplicate or does not exist.",
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.toReaction()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun reactionAlreadyExist(postId: Long, actorId: Long, emojiId: Long): Boolean {
|
|
||||||
return Reactions.select {
|
|
||||||
Reactions.postId.eq(postId).and(Reactions.actorId.eq(actorId)).and(
|
|
||||||
Reactions.emojiId.eq(emojiId)
|
|
||||||
)
|
|
||||||
}.empty().not()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List<Reaction> {
|
|
||||||
return Reactions.select { Reactions.postId eq postId and (Reactions.actorId eq actorId) }
|
|
||||||
.map { it.toReaction() }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedquery
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationships
|
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.toRelationships
|
|
||||||
import dev.usbharu.hideout.core.query.RelationshipQueryService
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.andWhere
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.springframework.stereotype.Service
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class RelationshipQueryServiceImpl : RelationshipQueryService {
|
|
||||||
override suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship> =
|
|
||||||
Relationships.select { Relationships.targetActorId eq targetId and (Relationships.following eq following) }
|
|
||||||
.map { it.toRelationships() }
|
|
||||||
|
|
||||||
override suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
targetId: Long,
|
|
||||||
followRequest: Boolean,
|
|
||||||
ignoreFollowRequest: Boolean
|
|
||||||
): List<Relationship> {
|
|
||||||
val query = Relationships
|
|
||||||
.select {
|
|
||||||
Relationships.targetActorId.eq(targetId)
|
|
||||||
.and(Relationships.followRequest.eq(followRequest))
|
|
||||||
.and(Relationships.ignoreFollowRequestFromTarget.eq(ignoreFollowRequest))
|
|
||||||
}.limit(limit)
|
|
||||||
|
|
||||||
if (maxId != null) {
|
|
||||||
query.andWhere { Relationships.id greater maxId }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sinceId != null) {
|
|
||||||
query.andWhere { Relationships.id less sinceId }
|
|
||||||
}
|
|
||||||
|
|
||||||
return query.map { it.toRelationships() }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.SpringDataAccessExceptionSQLExceptionTranslator
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
|
||||||
|
import java.sql.SQLException
|
||||||
|
|
||||||
|
@Suppress("VarCouldBeVal")
|
||||||
|
abstract class AbstractRepository {
|
||||||
|
protected abstract val logger: Logger
|
||||||
|
private val sqlErrorCodeSQLExceptionTranslator = SQLErrorCodeSQLExceptionTranslator()
|
||||||
|
private val springDataAccessExceptionSQLExceptionTranslator = SpringDataAccessExceptionSQLExceptionTranslator()
|
||||||
|
|
||||||
|
@Value("\${hideout.debug.trace-query-exception:false}")
|
||||||
|
private var traceQueryException: Boolean = false
|
||||||
|
|
||||||
|
@Value("\${hideout.debug.trace-query-call:false}")
|
||||||
|
private var traceQueryCall: Boolean = false
|
||||||
|
|
||||||
|
protected suspend fun <T> query(block: () -> T): T = try {
|
||||||
|
if (traceQueryCall) {
|
||||||
|
@Suppress("ThrowingExceptionsWithoutMessageOrCause")
|
||||||
|
logger.trace(
|
||||||
|
"""
|
||||||
|
***** QUERY CALL STACK TRACE *****
|
||||||
|
|
||||||
|
${Throwable().stackTrace.joinToString("\n")}
|
||||||
|
|
||||||
|
***** QUERY CALL STACK TRACE *****
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
block.invoke()
|
||||||
|
} catch (e: SQLException) {
|
||||||
|
if (traceQueryException) {
|
||||||
|
logger.trace("FAILED EXECUTE SQL", e)
|
||||||
|
}
|
||||||
|
if (e.cause !is SQLException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataAccessException =
|
||||||
|
sqlErrorCodeSQLExceptionTranslator.translate("Failed to persist entity", null, e.cause as SQLException)
|
||||||
|
?: throw e
|
||||||
|
|
||||||
|
if (traceQueryException) {
|
||||||
|
logger.trace("EXCEPTION TRANSLATED TO", dataAccessException)
|
||||||
|
}
|
||||||
|
|
||||||
|
val translate = springDataAccessExceptionSQLExceptionTranslator.translate(
|
||||||
|
"Failed to persist entity",
|
||||||
|
null,
|
||||||
|
dataAccessException
|
||||||
|
)
|
||||||
|
|
||||||
|
if (traceQueryException) {
|
||||||
|
logger.trace("EXCEPTION TRANSLATED TO", translate)
|
||||||
|
}
|
||||||
|
throw translate
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper
|
import dev.usbharu.hideout.application.infrastructure.exposed.ResultRowMapper
|
||||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
|
@ -7,17 +8,21 @@ import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.jetbrains.exposed.sql.javatime.timestamp
|
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class ActorRepositoryImpl(
|
class ActorRepositoryImpl(
|
||||||
private val idGenerateService: IdGenerateService,
|
private val idGenerateService: IdGenerateService,
|
||||||
private val actorResultRowMapper: ResultRowMapper<Actor>
|
private val actorResultRowMapper: ResultRowMapper<Actor>,
|
||||||
) :
|
private val actorQueryMapper: QueryMapper<Actor>
|
||||||
ActorRepository {
|
) : ActorRepository, AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun save(actor: Actor): Actor {
|
override suspend fun save(actor: Actor): Actor = query {
|
||||||
val singleOrNull = Actors.select { Actors.id eq actor.id }.empty()
|
val singleOrNull = Actors.select { Actors.id eq actor.id }.forUpdate().empty()
|
||||||
if (singleOrNull) {
|
if (singleOrNull) {
|
||||||
Actors.insert {
|
Actors.insert {
|
||||||
it[id] = actor.id
|
it[id] = actor.id
|
||||||
|
@ -64,17 +69,60 @@ class ActorRepositoryImpl(
|
||||||
it[lastPostAt] = actor.lastPostDate
|
it[lastPostAt] = actor.lastPostDate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return actor
|
return@query actor
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): Actor? =
|
override suspend fun findById(id: Long): Actor? = query {
|
||||||
Actors.select { Actors.id eq id }.singleOrNull()?.let(actorResultRowMapper::map)
|
return@query Actors.select { Actors.id eq id }.singleOrNull()?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
override suspend fun findByIdWithLock(id: Long): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.id eq id }.forUpdate().singleOrNull()?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findAll(limit: Int, offset: Long): List<Actor> = query {
|
||||||
|
return@query Actors.selectAll().limit(limit, offset).let(actorQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByName(name: String): List<Actor> = query {
|
||||||
|
return@query Actors.select { Actors.name eq name }.let(actorQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomain(name: String, domain: String): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.name eq name and (Actors.domain eq domain) }.singleOrNull()
|
||||||
|
?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomainWithLock(name: String, domain: String): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.name eq name and (Actors.domain eq domain) }.forUpdate().singleOrNull()
|
||||||
|
?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrl(url: String): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.url eq url }.singleOrNull()?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrlWithLock(url: String): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.url eq url }.forUpdate().singleOrNull()?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByIds(ids: List<Long>): List<Actor> = query {
|
||||||
|
return@query Actors.select { Actors.id inList ids }.let(actorQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByKeyId(keyId: String): Actor? = query {
|
||||||
|
return@query Actors.select { Actors.keyId eq keyId }.singleOrNull()?.let(actorResultRowMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun delete(id: Long): Unit = query {
|
||||||
Actors.deleteWhere { Actors.id.eq(id) }
|
Actors.deleteWhere { Actors.id.eq(id) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun nextId(): Long = idGenerateService.generateId()
|
override suspend fun nextId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ActorRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Actors : Table("actors") {
|
object Actors : Table("actors") {
|
||||||
|
|
|
@ -1,18 +1,21 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
||||||
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActorRepository
|
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActorRepository
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.jetbrains.exposed.sql.javatime.timestamp
|
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class DeletedActorRepositoryImpl : DeletedActorRepository {
|
class DeletedActorRepositoryImpl : DeletedActorRepository, AbstractRepository() {
|
||||||
override suspend fun save(deletedActor: DeletedActor): DeletedActor {
|
override val logger: Logger
|
||||||
val singleOrNull = DeletedActors.select { DeletedActors.id eq deletedActor.id }.singleOrNull()
|
get() = Companion.logger
|
||||||
|
|
||||||
|
override suspend fun save(deletedActor: DeletedActor): DeletedActor = query {
|
||||||
|
val singleOrNull = DeletedActors.select { DeletedActors.id eq deletedActor.id }.forUpdate().singleOrNull()
|
||||||
|
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
DeletedActors.insert {
|
DeletedActors.insert {
|
||||||
|
@ -30,18 +33,29 @@ class DeletedActorRepositoryImpl : DeletedActorRepository {
|
||||||
it[DeletedActors.deletedAt] = deletedActor.deletedAt
|
it[DeletedActors.deletedAt] = deletedActor.deletedAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return deletedActor
|
return@query deletedActor
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(deletedActor: DeletedActor) {
|
override suspend fun delete(deletedActor: DeletedActor): Unit = query {
|
||||||
DeletedActors.deleteWhere { DeletedActors.id eq deletedActor.id }
|
DeletedActors.deleteWhere { DeletedActors.id eq deletedActor.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): DeletedActor {
|
override suspend fun findById(id: Long): DeletedActor? = query {
|
||||||
val singleOr = DeletedActors.select { DeletedActors.id eq id }
|
return@query DeletedActors
|
||||||
.singleOr { FailedToGetResourcesException("id: $id was not exist or duplicate", it) }
|
.select { DeletedActors.id eq id }
|
||||||
|
.singleOrNull()
|
||||||
|
?.toDeletedActor()
|
||||||
|
}
|
||||||
|
|
||||||
return deletedActor(singleOr)
|
override suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor? = query {
|
||||||
|
return@query DeletedActors
|
||||||
|
.select { DeletedActors.name eq name and (DeletedActors.domain eq domain) }
|
||||||
|
.singleOrNull()
|
||||||
|
?.toDeletedActor()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(DeletedActorRepositoryImpl::class.java)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@ import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
@ -12,11 +14,15 @@ import org.springframework.stereotype.Repository
|
||||||
@Repository
|
@Repository
|
||||||
@Qualifier("jdbc")
|
@Qualifier("jdbc")
|
||||||
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "false", matchIfMissing = true)
|
@ConditionalOnProperty("hideout.use-mongodb", havingValue = "false", matchIfMissing = true)
|
||||||
class ExposedTimelineRepository(private val idGenerateService: IdGenerateService) : TimelineRepository {
|
class ExposedTimelineRepository(private val idGenerateService: IdGenerateService) : TimelineRepository,
|
||||||
|
AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(timeline: Timeline): Timeline {
|
override suspend fun save(timeline: Timeline): Timeline = query {
|
||||||
if (Timelines.select { Timelines.id eq timeline.id }.singleOrNull() == null) {
|
if (Timelines.select { Timelines.id eq timeline.id }.forUpdate().singleOrNull() == null) {
|
||||||
Timelines.insert {
|
Timelines.insert {
|
||||||
it[id] = timeline.id
|
it[id] = timeline.id
|
||||||
it[userId] = timeline.userId
|
it[userId] = timeline.userId
|
||||||
|
@ -48,10 +54,10 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
|
||||||
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
it[mediaIds] = timeline.mediaIds.joinToString(",")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return timeline
|
return@query timeline
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun saveAll(timelines: List<Timeline>): List<Timeline> {
|
override suspend fun saveAll(timelines: List<Timeline>): List<Timeline> = query {
|
||||||
Timelines.batchInsert(timelines, true, false) {
|
Timelines.batchInsert(timelines, true, false) {
|
||||||
this[Timelines.id] = it.id
|
this[Timelines.id] = it.id
|
||||||
this[Timelines.userId] = it.userId
|
this[Timelines.userId] = it.userId
|
||||||
|
@ -67,15 +73,21 @@ class ExposedTimelineRepository(private val idGenerateService: IdGenerateService
|
||||||
this[Timelines.isPureRepost] = it.isPureRepost
|
this[Timelines.isPureRepost] = it.isPureRepost
|
||||||
this[Timelines.mediaIds] = it.mediaIds.joinToString(",")
|
this[Timelines.mediaIds] = it.mediaIds.joinToString(",")
|
||||||
}
|
}
|
||||||
return timelines
|
return@query timelines
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByUserId(id: Long): List<Timeline> =
|
override suspend fun findByUserId(id: Long): List<Timeline> = query {
|
||||||
Timelines.select { Timelines.userId eq id }.map { it.toTimeline() }
|
return@query Timelines.select { Timelines.userId eq id }.map { it.toTimeline() }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByUserIdAndTimelineId(userId: Long, timelineId: Long): List<Timeline> =
|
override suspend fun findByUserIdAndTimelineId(userId: Long, timelineId: Long): List<Timeline> = query {
|
||||||
Timelines.select { Timelines.userId eq userId and (Timelines.timelineId eq timelineId) }
|
return@query Timelines.select { Timelines.userId eq userId and (Timelines.timelineId eq timelineId) }
|
||||||
.map { it.toTimeline() }
|
.map { it.toTimeline() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ExposedTimelineRepository::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toTimeline(): Timeline {
|
fun ResultRow.toTimeline(): Timeline {
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.jetbrains.exposed.sql.javatime.timestamp
|
import org.jetbrains.exposed.sql.javatime.timestamp
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Instance as InstanceEntity
|
import dev.usbharu.hideout.core.domain.model.instance.Instance as InstanceEntity
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class InstanceRepositoryImpl(private val idGenerateService: IdGenerateService) : InstanceRepository {
|
class InstanceRepositoryImpl(private val idGenerateService: IdGenerateService) : InstanceRepository,
|
||||||
|
AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(instance: InstanceEntity): InstanceEntity {
|
override suspend fun save(instance: InstanceEntity): InstanceEntity = query {
|
||||||
if (Instance.select { Instance.id.eq(instance.id) }.empty()) {
|
if (Instance.select { Instance.id.eq(instance.id) }.forUpdate().empty()) {
|
||||||
Instance.insert {
|
Instance.insert {
|
||||||
it[id] = instance.id
|
it[id] = instance.id
|
||||||
it[name] = instance.name
|
it[name] = instance.name
|
||||||
|
@ -45,17 +49,25 @@ class InstanceRepositoryImpl(private val idGenerateService: IdGenerateService) :
|
||||||
it[createdAt] = instance.createdAt
|
it[createdAt] = instance.createdAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return instance
|
return@query instance
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): InstanceEntity {
|
override suspend fun findById(id: Long): InstanceEntity? = query {
|
||||||
return Instance.select { Instance.id eq id }
|
return@query Instance.select { Instance.id eq id }
|
||||||
.singleOr { FailedToGetResourcesException("id: $id doesn't exist.") }.toInstance()
|
.singleOrNull()?.toInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(instance: InstanceEntity) {
|
override suspend fun delete(instance: InstanceEntity): Unit = query {
|
||||||
Instance.deleteWhere { id eq instance.id }
|
Instance.deleteWhere { id eq instance.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrl(url: String): dev.usbharu.hideout.core.domain.model.instance.Instance? = query {
|
||||||
|
return@query Instance.select { Instance.url eq url }.singleOrNull()?.toInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(InstanceRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toInstance(): InstanceEntity {
|
fun ResultRow.toInstance(): InstanceEntity {
|
||||||
|
|
|
@ -1,25 +1,28 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Media.mimeType
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Media.mimeType
|
||||||
import dev.usbharu.hideout.core.service.media.FileType
|
import dev.usbharu.hideout.core.service.media.FileType
|
||||||
import dev.usbharu.hideout.core.service.media.MimeType
|
import dev.usbharu.hideout.core.service.media.MimeType
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
|
import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class MediaRepositoryImpl(private val idGenerateService: IdGenerateService) : MediaRepository {
|
class MediaRepositoryImpl(private val idGenerateService: IdGenerateService) : MediaRepository, AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(media: EntityMedia): EntityMedia {
|
override suspend fun save(media: EntityMedia): EntityMedia = query {
|
||||||
if (Media.select {
|
if (Media.select {
|
||||||
Media.id eq media.id
|
Media.id eq media.id
|
||||||
}.singleOrNull() != null
|
}.forUpdate().singleOrNull() != null
|
||||||
) {
|
) {
|
||||||
Media.update({ Media.id eq media.id }) {
|
Media.update({ Media.id eq media.id }) {
|
||||||
it[name] = media.name
|
it[name] = media.name
|
||||||
|
@ -44,24 +47,32 @@ class MediaRepositoryImpl(private val idGenerateService: IdGenerateService) : Me
|
||||||
it[description] = media.description
|
it[description] = media.description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return media
|
return@query media
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): EntityMedia {
|
override suspend fun findById(id: Long): EntityMedia? = query {
|
||||||
return Media
|
return@query Media
|
||||||
.select {
|
.select {
|
||||||
Media.id eq id
|
Media.id eq id
|
||||||
}
|
}
|
||||||
.singleOr {
|
.singleOrNull()
|
||||||
FailedToGetResourcesException("id: $id was not found.")
|
?.toMedia()
|
||||||
}.toMedia()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
override suspend fun delete(id: Long): Unit = query {
|
||||||
Media.deleteWhere {
|
Media.deleteWhere {
|
||||||
Media.id eq id
|
Media.id eq id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByRemoteUrl(remoteUrl: String): dev.usbharu.hideout.core.domain.model.media.Media? =
|
||||||
|
query {
|
||||||
|
return@query Media.select { Media.remoteUrl eq remoteUrl }.singleOrNull()?.toMedia()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(MediaRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toMedia(): EntityMedia {
|
fun ResultRow.toMedia(): EntityMedia {
|
||||||
|
|
|
@ -2,24 +2,26 @@ package dev.usbharu.hideout.core.infrastructure.exposedrepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
import dev.usbharu.hideout.application.infrastructure.exposed.QueryMapper
|
||||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class PostRepositoryImpl(
|
class PostRepositoryImpl(
|
||||||
private val idGenerateService: IdGenerateService,
|
private val idGenerateService: IdGenerateService,
|
||||||
private val postQueryMapper: QueryMapper<Post>
|
private val postQueryMapper: QueryMapper<Post>
|
||||||
) : PostRepository {
|
) : PostRepository, AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(post: Post): Boolean {
|
override suspend fun save(post: Post): Post = query {
|
||||||
val singleOrNull = Posts.select { Posts.id eq post.id }.singleOrNull()
|
val singleOrNull = Posts.select { Posts.id eq post.id }.forUpdate().singleOrNull()
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
Posts.insert {
|
Posts.insert {
|
||||||
it[id] = post.id
|
it[id] = post.id
|
||||||
|
@ -61,18 +63,45 @@ class PostRepositoryImpl(
|
||||||
it[deleted] = post.delted
|
it[deleted] = post.delted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return singleOrNull == null
|
return@query post
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): Post =
|
override suspend fun findById(id: Long): Post? = query {
|
||||||
Posts.leftJoin(PostsMedia)
|
return@query Posts.leftJoin(PostsMedia)
|
||||||
.select { Posts.id eq id }
|
.select { Posts.id eq id }
|
||||||
.let(postQueryMapper::map)
|
.let(postQueryMapper::map)
|
||||||
.singleOr { FailedToGetResourcesException("id: $id was not found.", it) }
|
.singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
override suspend fun findByUrl(url: String): Post? = query {
|
||||||
|
return@query Posts.leftJoin(PostsMedia)
|
||||||
|
.select { Posts.url eq url }
|
||||||
|
.let(postQueryMapper::map)
|
||||||
|
.singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByApId(apId: String): Post? = query {
|
||||||
|
return@query Posts.leftJoin(PostsMedia)
|
||||||
|
.select { Posts.apId eq apId }
|
||||||
|
.let(postQueryMapper::map)
|
||||||
|
.singleOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun existByApIdWithLock(apId: String): Boolean = query {
|
||||||
|
return@query Posts.select { Posts.apId eq apId }.forUpdate().empty().not()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByActorId(actorId: Long): List<Post> = query {
|
||||||
|
return@query Posts.select { Posts.actorId eq actorId }.let(postQueryMapper::map)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun delete(id: Long): Unit = query {
|
||||||
Posts.deleteWhere { Posts.id eq id }
|
Posts.deleteWhere { Posts.id eq id }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(PostRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Posts : Table() {
|
object Posts : Table() {
|
||||||
|
|
|
@ -6,17 +6,21 @@ import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class ReactionRepositoryImpl(
|
class ReactionRepositoryImpl(
|
||||||
private val idGenerateService: IdGenerateService
|
private val idGenerateService: IdGenerateService
|
||||||
) : ReactionRepository {
|
) : ReactionRepository, AbstractRepository() {
|
||||||
|
override val logger: Logger
|
||||||
|
get() = Companion.logger
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(reaction: Reaction): Reaction {
|
override suspend fun save(reaction: Reaction): Reaction = query {
|
||||||
if (Reactions.select { Reactions.id eq reaction.id }.empty()) {
|
if (Reactions.select { Reactions.id eq reaction.id }.forUpdate().empty()) {
|
||||||
Reactions.insert {
|
Reactions.insert {
|
||||||
it[id] = reaction.id
|
it[id] = reaction.id
|
||||||
it[emojiId] = reaction.emojiId
|
it[emojiId] = reaction.emojiId
|
||||||
|
@ -30,30 +34,62 @@ class ReactionRepositoryImpl(
|
||||||
it[actorId] = reaction.actorId
|
it[actorId] = reaction.actorId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return reaction
|
return@query reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(reaction: Reaction): Reaction {
|
override suspend fun delete(reaction: Reaction): Reaction = query {
|
||||||
Reactions.deleteWhere {
|
Reactions.deleteWhere {
|
||||||
id.eq(reaction.id)
|
id.eq(reaction.id).and(postId.eq(reaction.postId)).and(actorId.eq(reaction.actorId))
|
||||||
.and(postId.eq(reaction.postId))
|
|
||||||
.and(actorId.eq(reaction.actorId))
|
|
||||||
.and(emojiId.eq(reaction.emojiId))
|
.and(emojiId.eq(reaction.emojiId))
|
||||||
}
|
}
|
||||||
return reaction
|
return@query reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByPostId(postId: Long): Int {
|
override suspend fun deleteByPostId(postId: Long): Int = query {
|
||||||
return Reactions.deleteWhere {
|
return@query Reactions.deleteWhere {
|
||||||
Reactions.postId eq postId
|
Reactions.postId eq postId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByActorId(actorId: Long): Int {
|
override suspend fun deleteByActorId(actorId: Long): Int = query {
|
||||||
return Reactions.deleteWhere {
|
return@query Reactions.deleteWhere {
|
||||||
Reactions.actorId eq actorId
|
Reactions.actorId eq actorId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByPostId(postId: Long): List<Reaction> = query {
|
||||||
|
return@query Reactions.select { Reactions.postId eq postId }.map { it.toReaction() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction? =
|
||||||
|
query {
|
||||||
|
return@query Reactions.select {
|
||||||
|
Reactions.postId eq postId and (Reactions.actorId eq actorId).and(
|
||||||
|
Reactions.emojiId.eq(
|
||||||
|
emojiId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}.singleOrNull()?.toReaction()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun existByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Boolean =
|
||||||
|
query {
|
||||||
|
return@query Reactions.select {
|
||||||
|
Reactions.postId
|
||||||
|
.eq(postId)
|
||||||
|
.and(Reactions.actorId.eq(actorId))
|
||||||
|
.and(Reactions.emojiId.eq(emojiId))
|
||||||
|
}.empty().not()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List<Reaction> = query {
|
||||||
|
return@query Reactions.select { Reactions.postId eq postId and (Reactions.actorId eq actorId) }
|
||||||
|
.map { it.toReaction() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(ReactionRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toReaction(): Reaction {
|
fun ResultRow.toReaction(): Reaction {
|
||||||
|
@ -67,10 +103,10 @@ fun ResultRow.toReaction(): Reaction {
|
||||||
|
|
||||||
object Reactions : LongIdTable("reactions") {
|
object Reactions : LongIdTable("reactions") {
|
||||||
val emojiId: Column<Long> = long("emoji_id")
|
val emojiId: Column<Long> = long("emoji_id")
|
||||||
val postId: Column<Long> = long("post_id")
|
val postId: Column<Long> =
|
||||||
.references(Posts.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
long("post_id").references(Posts.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||||
val actorId: Column<Long> = long("actor_id")
|
val actorId: Column<Long> =
|
||||||
.references(Actors.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
long("actor_id").references(Actors.id, onDelete = ReferenceOption.CASCADE, onUpdate = ReferenceOption.CASCADE)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
uniqueIndex(emojiId, postId, actorId)
|
uniqueIndex(emojiId, postId, actorId)
|
||||||
|
|
|
@ -8,12 +8,17 @@ import org.jetbrains.exposed.sql.deleteWhere
|
||||||
import org.jetbrains.exposed.sql.insert
|
import org.jetbrains.exposed.sql.insert
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.update
|
import org.jetbrains.exposed.sql.update
|
||||||
|
import org.slf4j.Logger
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class UserDetailRepositoryImpl : UserDetailRepository {
|
class UserDetailRepositoryImpl : UserDetailRepository, AbstractRepository() {
|
||||||
override suspend fun save(userDetail: UserDetail): UserDetail {
|
override val logger: Logger
|
||||||
val singleOrNull = UserDetails.select { UserDetails.actorId eq userDetail.actorId }.singleOrNull()
|
get() = Companion.logger
|
||||||
|
|
||||||
|
override suspend fun save(userDetail: UserDetail): UserDetail = query {
|
||||||
|
val singleOrNull = UserDetails.select { UserDetails.actorId eq userDetail.actorId }.forUpdate().singleOrNull()
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
UserDetails.insert {
|
UserDetails.insert {
|
||||||
it[actorId] = userDetail.actorId
|
it[actorId] = userDetail.actorId
|
||||||
|
@ -26,15 +31,15 @@ class UserDetailRepositoryImpl : UserDetailRepository {
|
||||||
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
|
it[autoAcceptFolloweeFollowRequest] = userDetail.autoAcceptFolloweeFollowRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return userDetail
|
return@query userDetail
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun delete(userDetail: UserDetail) {
|
override suspend fun delete(userDetail: UserDetail): Unit = query {
|
||||||
UserDetails.deleteWhere { UserDetails.actorId eq userDetail.actorId }
|
UserDetails.deleteWhere { UserDetails.actorId eq userDetail.actorId }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByActorId(actorId: Long): UserDetail? {
|
override suspend fun findByActorId(actorId: Long): UserDetail? = query {
|
||||||
return UserDetails
|
return@query UserDetails
|
||||||
.select { UserDetails.actorId eq actorId }
|
.select { UserDetails.actorId eq actorId }
|
||||||
.singleOrNull()
|
.singleOrNull()
|
||||||
?.let {
|
?.let {
|
||||||
|
@ -45,6 +50,10 @@ class UserDetailRepositoryImpl : UserDetailRepository {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger = LoggerFactory.getLogger(UserDetailRepositoryImpl::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object UserDetails : LongIdTable("user_details") {
|
object UserDetails : LongIdTable("user_details") {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import java.net.URL
|
||||||
|
|
||||||
@JsonDeserialize(using = HttpRequestDeserializer::class)
|
@JsonDeserialize(using = HttpRequestDeserializer::class)
|
||||||
@JsonSubTypes
|
@JsonSubTypes
|
||||||
|
@Suppress("UnnecessaryAbstractClass")
|
||||||
abstract class HttpRequestMixIn
|
abstract class HttpRequestMixIn
|
||||||
|
|
||||||
class HttpRequestDeserializer : JsonDeserializer<HttpRequest>() {
|
class HttpRequestDeserializer : JsonDeserializer<HttpRequest>() {
|
||||||
|
|
|
@ -7,8 +7,11 @@ import dev.usbharu.hideout.core.service.job.JobQueueWorkerService
|
||||||
import kjob.core.dsl.JobContextWithProps
|
import kjob.core.dsl.JobContextWithProps
|
||||||
import kjob.core.dsl.JobRegisterContext
|
import kjob.core.dsl.JobRegisterContext
|
||||||
import kjob.core.dsl.KJobFunctions
|
import kjob.core.dsl.KJobFunctions
|
||||||
|
import kjob.core.job.JobExecutionType
|
||||||
import kjob.core.kjob
|
import kjob.core.kjob
|
||||||
import kjob.mongo.Mongo
|
import kjob.mongo.Mongo
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import org.slf4j.MDC
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@ -24,6 +27,8 @@ class KJobMongoJobQueueWorkerService(
|
||||||
nonBlockingMaxJobs = 10
|
nonBlockingMaxJobs = 10
|
||||||
blockingMaxJobs = 10
|
blockingMaxJobs = 10
|
||||||
jobExecutionPeriodInSeconds = 1
|
jobExecutionPeriodInSeconds = 1
|
||||||
|
maxRetries = 3
|
||||||
|
defaultJobExecutor = JobExecutionType.NON_BLOCKING
|
||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +42,21 @@ class KJobMongoJobQueueWorkerService(
|
||||||
for (jobProcessor in jobQueueProcessorList) {
|
for (jobProcessor in jobQueueProcessorList) {
|
||||||
kjob.register(jobProcessor.job()) {
|
kjob.register(jobProcessor.job()) {
|
||||||
execute {
|
execute {
|
||||||
val param = it.convertUnsafe(props)
|
@Suppress("TooGenericExceptionCaught")
|
||||||
jobProcessor.process(param)
|
try {
|
||||||
|
MDC.put("x-job-id", this.jobId)
|
||||||
|
val param = it.convertUnsafe(props)
|
||||||
|
jobProcessor.process(param)
|
||||||
|
} catch (e: CancellationException) {
|
||||||
|
throw e
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logger.warn("FAILED Excute Job. job name: {} job id: {}", it.name, this.jobId, e)
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
MDC.remove("x-job-id")
|
||||||
|
}
|
||||||
|
}.onError {
|
||||||
|
logger.warn("FAILED Excute Job. job name: {} job id: {}", this.jobName, this.jobId, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.mongorepository
|
package dev.usbharu.hideout.core.infrastructure.mongorepository
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
import dev.usbharu.hideout.application.service.id.IdGenerateService
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.ResourceAccessException
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
|
||||||
|
import org.springframework.dao.DataAccessException
|
||||||
|
import org.springframework.dao.DuplicateKeyException
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
|
@ -23,8 +27,15 @@ class MongoTimelineRepositoryWrapper(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun saveAll(timelines: List<Timeline>): List<Timeline> =
|
override suspend fun saveAll(timelines: List<Timeline>): List<Timeline> {
|
||||||
mongoTimelineRepository.saveAll(timelines)
|
try {
|
||||||
|
return mongoTimelineRepository.saveAll(timelines)
|
||||||
|
} catch (e: DuplicateKeyException) {
|
||||||
|
throw DuplicateException("Timeline duplicate.", e)
|
||||||
|
} catch (e: DataAccessException) {
|
||||||
|
throw ResourceAccessException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByUserId(id: Long): List<Timeline> {
|
override suspend fun findByUserId(id: Long): List<Timeline> {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature
|
package dev.usbharu.hideout.core.infrastructure.springframework.httpsignature
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.HttpSignatureVerifyException
|
import dev.usbharu.hideout.core.domain.exception.HttpSignatureVerifyException
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import dev.usbharu.httpsignature.common.HttpMethod
|
import dev.usbharu.httpsignature.common.HttpMethod
|
||||||
import dev.usbharu.httpsignature.common.HttpRequest
|
import dev.usbharu.httpsignature.common.HttpRequest
|
||||||
|
@ -20,10 +19,10 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException
|
||||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
||||||
|
|
||||||
class HttpSignatureUserDetailsService(
|
class HttpSignatureUserDetailsService(
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val httpSignatureVerifier: HttpSignatureVerifier,
|
private val httpSignatureVerifier: HttpSignatureVerifier,
|
||||||
private val transaction: Transaction,
|
private val transaction: Transaction,
|
||||||
private val httpSignatureHeaderParser: SignatureHeaderParser
|
private val httpSignatureHeaderParser: SignatureHeaderParser,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
|
||||||
override fun loadUserDetails(token: PreAuthenticatedAuthenticationToken): UserDetails = runBlocking {
|
override fun loadUserDetails(token: PreAuthenticatedAuthenticationToken): UserDetails = runBlocking {
|
||||||
|
@ -34,11 +33,7 @@ class HttpSignatureUserDetailsService(
|
||||||
|
|
||||||
val keyId = token.principal as String
|
val keyId = token.principal as String
|
||||||
val findByKeyId = transaction.transaction {
|
val findByKeyId = transaction.transaction {
|
||||||
try {
|
actorRepository.findByKeyId(keyId) ?: throw UsernameNotFoundException("keyId: $keyId not found.")
|
||||||
actorQueryService.findByKeyId(keyId)
|
|
||||||
} catch (e: FailedToGetResourcesException) {
|
|
||||||
throw UsernameNotFoundException("User not found", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val signature = httpSignatureHeaderParser.parse(credentials.headers)
|
val signature = httpSignatureHeaderParser.parse(credentials.headers)
|
||||||
|
|
|
@ -2,9 +2,9 @@ package dev.usbharu.hideout.core.infrastructure.springframework.oauth2
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.springframework.security.core.userdetails.UserDetails
|
import org.springframework.security.core.userdetails.UserDetails
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService
|
import org.springframework.security.core.userdetails.UserDetailsService
|
||||||
|
@ -13,10 +13,10 @@ import org.springframework.stereotype.Service
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class UserDetailsServiceImpl(
|
class UserDetailsServiceImpl(
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val userDetailRepository: UserDetailRepository,
|
private val userDetailRepository: UserDetailRepository,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository
|
||||||
) :
|
) :
|
||||||
UserDetailsService {
|
UserDetailsService {
|
||||||
override fun loadUserByUsername(username: String?): UserDetails = runBlocking {
|
override fun loadUserByUsername(username: String?): UserDetails = runBlocking {
|
||||||
|
@ -24,11 +24,10 @@ class UserDetailsServiceImpl(
|
||||||
throw UsernameNotFoundException("$username not found")
|
throw UsernameNotFoundException("$username not found")
|
||||||
}
|
}
|
||||||
transaction.transaction {
|
transaction.transaction {
|
||||||
val findById = try {
|
val findById =
|
||||||
actorQueryService.findByNameAndDomain(username, applicationConfig.url.host)
|
actorRepository.findByNameAndDomain(username, applicationConfig.url.host)
|
||||||
} catch (e: FailedToGetResourcesException) {
|
?: throw UserNotFoundException.withNameAndDomain(username, applicationConfig.url.host)
|
||||||
throw UsernameNotFoundException("$username not found", e)
|
|
||||||
}
|
|
||||||
val userDetails = userDetailRepository.findByActorId(findById.id)
|
val userDetails = userDetailRepository.findByActorId(findById.id)
|
||||||
?: throw UsernameNotFoundException("${findById.id} not found.")
|
?: throw UsernameNotFoundException("${findById.id} not found.")
|
||||||
UserDetailsImpl(
|
UserDetailsImpl(
|
||||||
|
|
|
@ -6,5 +6,6 @@ import org.springframework.web.bind.annotation.GetMapping
|
||||||
@Controller
|
@Controller
|
||||||
class AuthController {
|
class AuthController {
|
||||||
@GetMapping("/auth/sign_up")
|
@GetMapping("/auth/sign_up")
|
||||||
|
@Suppress("FunctionOnlyReturningConstant")
|
||||||
fun signUp(): String = "sign_up"
|
fun signUp(): String = "sign_up"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
interface ActorQueryService {
|
|
||||||
suspend fun findAll(limit: Int, offset: Long): List<Actor>
|
|
||||||
suspend fun findById(id: Long): Actor
|
|
||||||
suspend fun findByName(name: String): List<Actor>
|
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String): Actor
|
|
||||||
suspend fun findByUrl(url: String): Actor
|
|
||||||
suspend fun findByIds(ids: List<Long>): List<Actor>
|
|
||||||
suspend fun existByNameAndDomain(name: String, domain: String): Boolean
|
|
||||||
suspend fun findByKeyId(keyId: String): Actor
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
|
||||||
|
|
||||||
interface DeletedActorQueryService {
|
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String): DeletedActor
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Instance
|
|
||||||
|
|
||||||
interface InstanceQueryService {
|
|
||||||
suspend fun findByUrl(url: String): Instance
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
|
||||||
|
|
||||||
interface MediaQueryService {
|
|
||||||
suspend fun findByPostId(postId: Long): List<Media>
|
|
||||||
suspend fun findByRemoteUrl(remoteUrl: String): Media
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
interface PostQueryService {
|
|
||||||
suspend fun findById(id: Long): Post
|
|
||||||
suspend fun findByUrl(url: String): Post
|
|
||||||
suspend fun findByApId(string: String): Post
|
|
||||||
suspend fun findByActorId(actorId: Long): List<Post>
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
|
||||||
import org.springframework.stereotype.Repository
|
|
||||||
|
|
||||||
@Repository
|
|
||||||
interface ReactionQueryService {
|
|
||||||
suspend fun findByPostId(postId: Long, actorId: Long? = null): List<Reaction>
|
|
||||||
|
|
||||||
@Suppress("FunctionMaxLength")
|
|
||||||
suspend fun findByPostIdAndActorIdAndEmojiId(postId: Long, actorId: Long, emojiId: Long): Reaction
|
|
||||||
|
|
||||||
suspend fun reactionAlreadyExist(postId: Long, actorId: Long, emojiId: Long): Boolean
|
|
||||||
|
|
||||||
suspend fun findByPostIdAndActorId(postId: Long, actorId: Long): List<Reaction>
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package dev.usbharu.hideout.core.query
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
|
||||||
|
|
||||||
interface RelationshipQueryService {
|
|
||||||
|
|
||||||
suspend fun findByTargetIdAndFollowing(targetId: Long, following: Boolean): List<Relationship>
|
|
||||||
|
|
||||||
@Suppress("LongParameterList", "FunctionMaxLength")
|
|
||||||
suspend fun findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
|
||||||
maxId: Long?,
|
|
||||||
sinceId: Long?,
|
|
||||||
limit: Int,
|
|
||||||
targetId: Long,
|
|
||||||
followRequest: Boolean,
|
|
||||||
ignoreFollowRequest: Boolean
|
|
||||||
): List<Relationship>
|
|
||||||
}
|
|
|
@ -1,12 +1,10 @@
|
||||||
package dev.usbharu.hideout.core.service.instance
|
package dev.usbharu.hideout.core.service.instance
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Instance
|
import dev.usbharu.hideout.core.domain.model.instance.Instance
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
import dev.usbharu.hideout.core.domain.model.instance.InstanceRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo
|
import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo
|
||||||
import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo2_0
|
import dev.usbharu.hideout.core.domain.model.instance.Nodeinfo2_0
|
||||||
import dev.usbharu.hideout.core.query.InstanceQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.resource.ResourceResolveService
|
import dev.usbharu.hideout.core.service.resource.ResourceResolveService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
|
@ -23,20 +21,20 @@ interface InstanceService {
|
||||||
class InstanceServiceImpl(
|
class InstanceServiceImpl(
|
||||||
private val instanceRepository: InstanceRepository,
|
private val instanceRepository: InstanceRepository,
|
||||||
private val resourceResolveService: ResourceResolveService,
|
private val resourceResolveService: ResourceResolveService,
|
||||||
@Qualifier("activitypub") private val objectMapper: ObjectMapper,
|
@Qualifier("activitypub") private val objectMapper: ObjectMapper
|
||||||
private val instanceQueryService: InstanceQueryService
|
|
||||||
) : InstanceService {
|
) : InstanceService {
|
||||||
override suspend fun fetchInstance(url: String, sharedInbox: String?): Instance {
|
override suspend fun fetchInstance(url: String, sharedInbox: String?): Instance {
|
||||||
val u = URL(url)
|
val u = URL(url)
|
||||||
val resolveInstanceUrl = u.protocol + "://" + u.host
|
val resolveInstanceUrl = u.protocol + "://" + u.host
|
||||||
|
|
||||||
try {
|
val instance = instanceRepository.findByUrl(resolveInstanceUrl)
|
||||||
return instanceQueryService.findByUrl(resolveInstanceUrl)
|
|
||||||
} catch (e: FailedToGetResourcesException) {
|
if (instance != null) {
|
||||||
logger.info("Instance not found. try fetch instance info. url: {}", resolveInstanceUrl)
|
return instance
|
||||||
logger.debug("Failed to get resources. url: {}", resolveInstanceUrl, e)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Instance not found. try fetch instance info. url: {}", resolveInstanceUrl)
|
||||||
|
|
||||||
val nodeinfoJson = resourceResolveService.resolve("$resolveInstanceUrl/.well-known/nodeinfo").bodyAsText()
|
val nodeinfoJson = resourceResolveService.resolve("$resolveInstanceUrl/.well-known/nodeinfo").bodyAsText()
|
||||||
val nodeinfo = objectMapper.readValue(nodeinfoJson, Nodeinfo::class.java)
|
val nodeinfo = objectMapper.readValue(nodeinfoJson, Nodeinfo::class.java)
|
||||||
val nodeinfoPathMap = nodeinfo.links.associate { it.rel to it.href }
|
val nodeinfoPathMap = nodeinfo.links.associate { it.rel to it.href }
|
||||||
|
|
|
@ -74,6 +74,7 @@ class LocalFileSystemMediaDataStore(
|
||||||
val fileSavePathString = fileSavePath.toAbsolutePath().toString()
|
val fileSavePathString = fileSavePath.toAbsolutePath().toString()
|
||||||
logger.info("MEDIA save. path: {}", fileSavePathString)
|
logger.info("MEDIA save. path: {}", fileSavePathString)
|
||||||
|
|
||||||
|
@Suppress("TooGenericExceptionCaught")
|
||||||
try {
|
try {
|
||||||
dataSaveRequest.filePath.copyTo(fileSavePath)
|
dataSaveRequest.filePath.copyTo(fileSavePath)
|
||||||
dataSaveRequest.thumbnailPath?.copyTo(thumbnailSavePath)
|
dataSaveRequest.thumbnailPath?.copyTo(thumbnailSavePath)
|
||||||
|
@ -97,6 +98,7 @@ class LocalFileSystemMediaDataStore(
|
||||||
*/
|
*/
|
||||||
override suspend fun delete(id: String) {
|
override suspend fun delete(id: String) {
|
||||||
logger.info("START Media delete. id: {}", id)
|
logger.info("START Media delete. id: {}", id)
|
||||||
|
@Suppress("TooGenericExceptionCaught")
|
||||||
try {
|
try {
|
||||||
buildSavePath(savePath, id).deleteIfExists()
|
buildSavePath(savePath, id).deleteIfExists()
|
||||||
buildSavePath(savePath, "thumbnail-$id").deleteIfExists()
|
buildSavePath(savePath, "thumbnail-$id").deleteIfExists()
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package dev.usbharu.hideout.core.service.media
|
package dev.usbharu.hideout.core.service.media
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.exception.media.MediaSaveException
|
import dev.usbharu.hideout.core.domain.exception.media.MediaSaveException
|
||||||
import dev.usbharu.hideout.core.domain.exception.media.UnsupportedMediaException
|
import dev.usbharu.hideout.core.domain.exception.media.UnsupportedMediaException
|
||||||
import dev.usbharu.hideout.core.domain.model.media.Media
|
import dev.usbharu.hideout.core.domain.model.media.Media
|
||||||
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
||||||
import dev.usbharu.hideout.core.query.MediaQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.media.converter.MediaProcessService
|
import dev.usbharu.hideout.core.service.media.converter.MediaProcessService
|
||||||
import dev.usbharu.hideout.mastodon.interfaces.api.media.MediaRequest
|
import dev.usbharu.hideout.mastodon.interfaces.api.media.MediaRequest
|
||||||
import dev.usbharu.hideout.util.withDelete
|
import dev.usbharu.hideout.util.withDelete
|
||||||
|
@ -24,8 +22,7 @@ class MediaServiceImpl(
|
||||||
private val mediaRepository: MediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val mediaProcessServices: List<MediaProcessService>,
|
private val mediaProcessServices: List<MediaProcessService>,
|
||||||
private val remoteMediaDownloadService: RemoteMediaDownloadService,
|
private val remoteMediaDownloadService: RemoteMediaDownloadService,
|
||||||
private val renameService: MediaFileRenameService,
|
private val renameService: MediaFileRenameService
|
||||||
private val mediaQueryService: MediaQueryService
|
|
||||||
) : MediaService {
|
) : MediaService {
|
||||||
@Suppress("LongMethod", "NestedBlockDepth")
|
@Suppress("LongMethod", "NestedBlockDepth")
|
||||||
override suspend fun uploadLocalMedia(mediaRequest: MediaRequest): EntityMedia {
|
override suspend fun uploadLocalMedia(mediaRequest: MediaRequest): EntityMedia {
|
||||||
|
@ -102,11 +99,10 @@ class MediaServiceImpl(
|
||||||
override suspend fun uploadRemoteMedia(remoteMedia: RemoteMedia): Media {
|
override suspend fun uploadRemoteMedia(remoteMedia: RemoteMedia): Media {
|
||||||
logger.info("MEDIA Remote media. filename:${remoteMedia.name} url:${remoteMedia.url}")
|
logger.info("MEDIA Remote media. filename:${remoteMedia.name} url:${remoteMedia.url}")
|
||||||
|
|
||||||
try {
|
val findByRemoteUrl = mediaRepository.findByRemoteUrl(remoteMedia.url)
|
||||||
val findByRemoteUrl = mediaQueryService.findByRemoteUrl(remoteMedia.url)
|
if (findByRemoteUrl != null) {
|
||||||
logger.warn("DUPLICATED Remote media is duplicated. url: {}", remoteMedia.url)
|
logger.warn("DUPLICATED Remote media is duplicated. url: {}", remoteMedia.url)
|
||||||
return findByRemoteUrl
|
return findByRemoteUrl
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteMediaDownloadService.download(remoteMedia.url).withDelete().use {
|
remoteMediaDownloadService.download(remoteMedia.url).withDelete().use {
|
||||||
|
@ -159,7 +155,7 @@ class MediaServiceImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun findMediaProcessor(mimeType: MimeType): MediaProcessService {
|
private fun findMediaProcessor(mimeType: MimeType): MediaProcessService {
|
||||||
try {
|
try {
|
||||||
return mediaProcessServices.first {
|
return mediaProcessServices.first {
|
||||||
try {
|
try {
|
||||||
|
@ -173,7 +169,7 @@ class MediaServiceImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun generateBlurhash(process: ProcessedMediaPath): String {
|
private fun generateBlurhash(process: ProcessedMediaPath): String {
|
||||||
val path = if (process.thumbnailPath != null && process.thumbnailMimeType != null) {
|
val path = if (process.thumbnailPath != null && process.thumbnailMimeType != null) {
|
||||||
process.thumbnailPath
|
process.thumbnailPath
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2,16 +2,15 @@ package dev.usbharu.hideout.core.service.post
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService
|
import dev.usbharu.hideout.activitypub.service.activity.create.ApSendCreateService
|
||||||
import dev.usbharu.hideout.core.domain.exception.UserNotFoundException
|
import dev.usbharu.hideout.core.domain.exception.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.PostNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
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.reaction.ReactionRepository
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.timeline.TimelineService
|
import dev.usbharu.hideout.core.service.timeline.TimelineService
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.dao.DuplicateKeyException
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@ -20,7 +19,6 @@ class PostServiceImpl(
|
||||||
private val postRepository: PostRepository,
|
private val postRepository: PostRepository,
|
||||||
private val actorRepository: ActorRepository,
|
private val actorRepository: ActorRepository,
|
||||||
private val timelineService: TimelineService,
|
private val timelineService: TimelineService,
|
||||||
private val postQueryService: PostQueryService,
|
|
||||||
private val postBuilder: Post.PostBuilder,
|
private val postBuilder: Post.PostBuilder,
|
||||||
private val apSendCreateService: ApSendCreateService,
|
private val apSendCreateService: ApSendCreateService,
|
||||||
private val reactionRepository: ReactionRepository
|
private val reactionRepository: ReactionRepository
|
||||||
|
@ -69,7 +67,7 @@ class PostServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteByActor(actorId: Long) {
|
override suspend fun deleteByActor(actorId: Long) {
|
||||||
postQueryService.findByActorId(actorId).filterNot { it.delted }.forEach { postRepository.save(it.delete()) }
|
postRepository.findByActorId(actorId).filterNot { it.delted }.forEach { postRepository.save(it.delete()) }
|
||||||
|
|
||||||
val actor = actorRepository.findById(actorId)
|
val actor = actorRepository.findById(actorId)
|
||||||
?: throw IllegalStateException("actor: $actorId was not found.")
|
?: throw IllegalStateException("actor: $actorId was not found.")
|
||||||
|
@ -79,18 +77,12 @@ class PostServiceImpl(
|
||||||
|
|
||||||
private suspend fun internalCreate(post: Post, isLocal: Boolean, actor: Actor): Post {
|
private suspend fun internalCreate(post: Post, isLocal: Boolean, actor: Actor): Post {
|
||||||
return try {
|
return try {
|
||||||
if (postRepository.save(post)) {
|
val save = postRepository.save(post)
|
||||||
try {
|
timelineService.publishTimeline(post, isLocal)
|
||||||
timelineService.publishTimeline(post, isLocal)
|
actorRepository.save(actor.incrementPostsCount())
|
||||||
actorRepository.save(actor.incrementPostsCount())
|
save
|
||||||
} catch (e: DuplicateKeyException) {
|
} catch (_: DuplicateException) {
|
||||||
logger.trace("Timeline already exists.", e)
|
postRepository.findByApId(post.apId) ?: throw PostNotFoundException.withApId(post.apId)
|
||||||
}
|
|
||||||
}
|
|
||||||
post
|
|
||||||
} catch (e: ExposedSQLException) {
|
|
||||||
logger.warn("FAILED Save to post. url: ${post.apId}", e)
|
|
||||||
postQueryService.findByApId(post.apId)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package dev.usbharu.hideout.core.service.reaction
|
package dev.usbharu.hideout.core.service.reaction
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.like.APReactionService
|
import dev.usbharu.hideout.activitypub.service.activity.like.APReactionService
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
import dev.usbharu.hideout.core.domain.model.reaction.Reaction
|
||||||
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||||
import dev.usbharu.hideout.core.query.ReactionQueryService
|
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
@ -13,11 +11,10 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
class ReactionServiceImpl(
|
class ReactionServiceImpl(
|
||||||
private val reactionRepository: ReactionRepository,
|
private val reactionRepository: ReactionRepository,
|
||||||
private val apReactionService: APReactionService,
|
private val apReactionService: APReactionService
|
||||||
private val reactionQueryService: ReactionQueryService
|
|
||||||
) : ReactionService {
|
) : ReactionService {
|
||||||
override suspend fun receiveReaction(name: String, domain: String, actorId: Long, postId: Long) {
|
override suspend fun receiveReaction(name: String, domain: String, actorId: Long, postId: Long) {
|
||||||
if (reactionQueryService.reactionAlreadyExist(postId, actorId, 0).not()) {
|
if (reactionRepository.existByPostIdAndActorIdAndEmojiId(postId, actorId, 0).not()) {
|
||||||
try {
|
try {
|
||||||
reactionRepository.save(
|
reactionRepository.save(
|
||||||
Reaction(reactionRepository.generateId(), 0, postId, actorId)
|
Reaction(reactionRepository.generateId(), 0, postId, actorId)
|
||||||
|
@ -28,31 +25,37 @@ class ReactionServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun receiveRemoveReaction(actorId: Long, postId: Long) {
|
override suspend fun receiveRemoveReaction(actorId: Long, postId: Long) {
|
||||||
val reaction = reactionQueryService.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
val reaction = reactionRepository.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
||||||
|
if (reaction == null) {
|
||||||
|
LOGGER.warn("FAILED receive Remove Reaction. $actorId $postId")
|
||||||
|
return
|
||||||
|
}
|
||||||
reactionRepository.delete(reaction)
|
reactionRepository.delete(reaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendReaction(name: String, actorId: Long, postId: Long) {
|
override suspend fun sendReaction(name: String, actorId: Long, postId: Long) {
|
||||||
try {
|
val findByPostIdAndUserIdAndEmojiId =
|
||||||
val findByPostIdAndUserIdAndEmojiId =
|
reactionRepository.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
||||||
reactionQueryService.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
|
||||||
|
if (findByPostIdAndUserIdAndEmojiId != null) {
|
||||||
apReactionService.removeReaction(findByPostIdAndUserIdAndEmojiId)
|
apReactionService.removeReaction(findByPostIdAndUserIdAndEmojiId)
|
||||||
reactionRepository.delete(findByPostIdAndUserIdAndEmojiId)
|
reactionRepository.delete(findByPostIdAndUserIdAndEmojiId)
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val reaction = Reaction(reactionRepository.generateId(), 0, postId, actorId)
|
val reaction = Reaction(reactionRepository.generateId(), 0, postId, actorId)
|
||||||
reactionRepository.save(reaction)
|
reactionRepository.save(reaction)
|
||||||
apReactionService.reaction(reaction)
|
apReactionService.reaction(reaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeReaction(actorId: Long, postId: Long) {
|
override suspend fun removeReaction(actorId: Long, postId: Long) {
|
||||||
try {
|
val findByPostIdAndUserIdAndEmojiId =
|
||||||
val findByPostIdAndUserIdAndEmojiId =
|
reactionRepository.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
||||||
reactionQueryService.findByPostIdAndActorIdAndEmojiId(postId, actorId, 0)
|
if (findByPostIdAndUserIdAndEmojiId == null) {
|
||||||
reactionRepository.delete(findByPostIdAndUserIdAndEmojiId)
|
LOGGER.warn("FAILED Remove reaction. actorId: $actorId postId: $postId")
|
||||||
apReactionService.removeReaction(findByPostIdAndUserIdAndEmojiId)
|
return
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
}
|
||||||
|
reactionRepository.delete(findByPostIdAndUserIdAndEmojiId)
|
||||||
|
apReactionService.removeReaction(findByPostIdAndUserIdAndEmojiId)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -6,12 +6,11 @@ import dev.usbharu.hideout.activitypub.service.activity.follow.APSendFollowServi
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.reject.ApSendRejectService
|
import dev.usbharu.hideout.activitypub.service.activity.reject.ApSendRejectService
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService
|
import dev.usbharu.hideout.activitypub.service.activity.undo.APSendUndoService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
import dev.usbharu.hideout.core.domain.model.relationship.Relationship
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.follow.SendFollowDto
|
import dev.usbharu.hideout.core.service.follow.SendFollowDto
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -19,7 +18,6 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
class RelationshipServiceImpl(
|
class RelationshipServiceImpl(
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val relationshipRepository: RelationshipRepository,
|
private val relationshipRepository: RelationshipRepository,
|
||||||
private val apSendFollowService: APSendFollowService,
|
private val apSendFollowService: APSendFollowService,
|
||||||
private val apSendBlockService: APSendBlockService,
|
private val apSendBlockService: APSendBlockService,
|
||||||
|
@ -78,10 +76,10 @@ class RelationshipServiceImpl(
|
||||||
val remoteUser = isRemoteUser(targetId)
|
val remoteUser = isRemoteUser(targetId)
|
||||||
|
|
||||||
if (remoteUser != null) {
|
if (remoteUser != null) {
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
apSendFollowService.sendFollow(SendFollowDto(user, remoteUser))
|
apSendFollowService.sendFollow(SendFollowDto(user, remoteUser))
|
||||||
} else {
|
} else {
|
||||||
val target = actorQueryService.findById(targetId)
|
val target = actorRepository.findById(targetId) ?: throw UserNotFoundException.withId(targetId)
|
||||||
if (target.locked.not()) {
|
if (target.locked.not()) {
|
||||||
acceptFollowRequest(targetId, actorId)
|
acceptFollowRequest(targetId, actorId)
|
||||||
}
|
}
|
||||||
|
@ -93,8 +91,8 @@ class RelationshipServiceImpl(
|
||||||
override suspend fun block(actorId: Long, targetId: Long) {
|
override suspend fun block(actorId: Long, targetId: Long) {
|
||||||
val relationship = relationshipRepository.findByUserIdAndTargetUserId(actorId, targetId)
|
val relationship = relationshipRepository.findByUserIdAndTargetUserId(actorId, targetId)
|
||||||
|
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
val targetActor = actorQueryService.findById(targetId)
|
val targetActor = actorRepository.findById(targetId) ?: throw UserNotFoundException.withId(targetId)
|
||||||
if (relationship?.following == true) {
|
if (relationship?.following == true) {
|
||||||
actorRepository.save(user.decrementFollowing())
|
actorRepository.save(user.decrementFollowing())
|
||||||
actorRepository.save(targetActor.decrementFollowers())
|
actorRepository.save(targetActor.decrementFollowers())
|
||||||
|
@ -174,13 +172,13 @@ class RelationshipServiceImpl(
|
||||||
|
|
||||||
val copy = relationship.copy(followRequest = false, following = true, blocking = false)
|
val copy = relationship.copy(followRequest = false, following = true, blocking = false)
|
||||||
|
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
|
|
||||||
actorRepository.save(user.incrementFollowers())
|
actorRepository.save(user.incrementFollowers())
|
||||||
|
|
||||||
relationshipRepository.save(copy)
|
relationshipRepository.save(copy)
|
||||||
|
|
||||||
val remoteActor = actorQueryService.findById(targetId)
|
val remoteActor = actorRepository.findById(targetId) ?: throw UserNotFoundException.withId(targetId)
|
||||||
|
|
||||||
actorRepository.save(remoteActor.incrementFollowing())
|
actorRepository.save(remoteActor.incrementFollowing())
|
||||||
|
|
||||||
|
@ -209,7 +207,7 @@ class RelationshipServiceImpl(
|
||||||
val remoteUser = isRemoteUser(targetId)
|
val remoteUser = isRemoteUser(targetId)
|
||||||
|
|
||||||
if (remoteUser != null) {
|
if (remoteUser != null) {
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
apSendRejectService.sendRejectFollow(user, remoteUser)
|
apSendRejectService.sendRejectFollow(user, remoteUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,8 +236,8 @@ class RelationshipServiceImpl(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
val targetActor = actorQueryService.findById(targetId)
|
val targetActor = actorRepository.findById(targetId) ?: throw UserNotFoundException.withId(targetId)
|
||||||
|
|
||||||
if (relationship.following) {
|
if (relationship.following) {
|
||||||
actorRepository.save(user.decrementFollowing())
|
actorRepository.save(user.decrementFollowing())
|
||||||
|
@ -280,7 +278,7 @@ class RelationshipServiceImpl(
|
||||||
|
|
||||||
val remoteUser = isRemoteUser(targetId)
|
val remoteUser = isRemoteUser(targetId)
|
||||||
if (remoteUser != null) {
|
if (remoteUser != null) {
|
||||||
val user = actorQueryService.findById(actorId)
|
val user = actorRepository.findById(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
apSendUndoService.sendUndoBlock(user, remoteUser)
|
apSendUndoService.sendUndoBlock(user, remoteUser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,12 +313,8 @@ class RelationshipServiceImpl(
|
||||||
|
|
||||||
private suspend fun isRemoteUser(userId: Long): Actor? {
|
private suspend fun isRemoteUser(userId: Long): Actor? {
|
||||||
logger.trace("isRemoteUser({})", userId)
|
logger.trace("isRemoteUser({})", userId)
|
||||||
val user = try {
|
val user =
|
||||||
actorQueryService.findById(userId)
|
actorRepository.findById(userId) ?: throw UserNotFoundException.withId(userId)
|
||||||
} catch (e: FailedToGetResourcesException) {
|
|
||||||
logger.warn("User not found.", e)
|
|
||||||
throw IllegalStateException("User not found.", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.trace("user info {}", user)
|
logger.trace("user info {}", user)
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,7 @@ class InMemoryCacheManager : CacheManager {
|
||||||
override suspend fun getOrWait(key: String): ResolveResponse {
|
override suspend fun getOrWait(key: String): ResolveResponse {
|
||||||
while (valueStore.contains(key).not()) {
|
while (valueStore.contains(key).not()) {
|
||||||
if (cacheKey.containsKey(key).not()) {
|
if (cacheKey.containsKey(key).not()) {
|
||||||
throw IllegalStateException("Invalid cache key.")
|
throw IllegalStateException("Invalid cache key. $key")
|
||||||
}
|
}
|
||||||
delay(1)
|
delay(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package dev.usbharu.hideout.core.service.timeline
|
package dev.usbharu.hideout.core.service.timeline
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Post
|
import dev.usbharu.hideout.core.domain.model.post.Post
|
||||||
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
import dev.usbharu.hideout.core.domain.model.post.Visibility
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
import dev.usbharu.hideout.core.domain.model.timeline.Timeline
|
||||||
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
import dev.usbharu.hideout.core.domain.model.timeline.TimelineRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.FollowerQueryService
|
import dev.usbharu.hideout.core.query.FollowerQueryService
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -12,14 +13,14 @@ import org.springframework.stereotype.Service
|
||||||
@Service
|
@Service
|
||||||
class TimelineService(
|
class TimelineService(
|
||||||
private val followerQueryService: FollowerQueryService,
|
private val followerQueryService: FollowerQueryService,
|
||||||
private val actorQueryService: ActorQueryService,
|
private val timelineRepository: TimelineRepository,
|
||||||
private val timelineRepository: TimelineRepository
|
private val actorRepository: ActorRepository
|
||||||
) {
|
) {
|
||||||
suspend fun publishTimeline(post: Post, isLocal: Boolean) {
|
suspend fun publishTimeline(post: Post, isLocal: Boolean) {
|
||||||
val findFollowersById = followerQueryService.findFollowersById(post.actorId).toMutableList()
|
val findFollowersById = followerQueryService.findFollowersById(post.actorId).toMutableList()
|
||||||
if (isLocal) {
|
if (isLocal) {
|
||||||
// 自分自身も含める必要がある
|
// 自分自身も含める必要がある
|
||||||
val user = actorQueryService.findById(post.actorId)
|
val user = actorRepository.findById(post.actorId) ?: throw UserNotFoundException.withId(post.actorId)
|
||||||
findFollowersById.add(user)
|
findFollowersById.add(user)
|
||||||
}
|
}
|
||||||
val timelines = findFollowersById.map {
|
val timelines = findFollowersById.map {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.core.service.user
|
package dev.usbharu.hideout.core.service.user
|
||||||
|
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import java.security.*
|
import java.security.*
|
||||||
|
@ -8,13 +9,14 @@ import java.util.*
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class UserAuthServiceImpl(
|
class UserAuthServiceImpl(
|
||||||
val actorQueryService: ActorQueryService
|
private val actorRepository: ActorRepository,
|
||||||
|
private val applicationConfig: ApplicationConfig
|
||||||
) : UserAuthService {
|
) : UserAuthService {
|
||||||
|
|
||||||
override fun hash(password: String): String = BCryptPasswordEncoder().encode(password)
|
override fun hash(password: String): String = BCryptPasswordEncoder().encode(password)
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
actorQueryService.findByName(username)
|
actorRepository.findByNameAndDomain(username, applicationConfig.url.host) ?: return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,8 @@ package dev.usbharu.hideout.core.service.user
|
||||||
|
|
||||||
import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService
|
import dev.usbharu.hideout.activitypub.service.activity.delete.APSendDeleteService
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.exception.resource.DuplicateException
|
||||||
|
import dev.usbharu.hideout.core.domain.exception.resource.UserNotFoundException
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
import dev.usbharu.hideout.core.domain.model.actor.Actor
|
||||||
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
import dev.usbharu.hideout.core.domain.model.deletedActor.DeletedActor
|
||||||
|
@ -11,14 +12,10 @@ import dev.usbharu.hideout.core.domain.model.reaction.ReactionRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
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.UserDetailRepository
|
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.query.DeletedActorQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.instance.InstanceService
|
import dev.usbharu.hideout.core.service.instance.InstanceService
|
||||||
import dev.usbharu.hideout.core.service.post.PostService
|
import dev.usbharu.hideout.core.service.post.PostService
|
||||||
import org.jetbrains.exposed.exceptions.ExposedSQLException
|
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@ -26,13 +23,11 @@ import java.time.Instant
|
||||||
class UserServiceImpl(
|
class UserServiceImpl(
|
||||||
private val actorRepository: ActorRepository,
|
private val actorRepository: ActorRepository,
|
||||||
private val userAuthService: UserAuthService,
|
private val userAuthService: UserAuthService,
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val actorBuilder: Actor.UserBuilder,
|
private val actorBuilder: Actor.UserBuilder,
|
||||||
private val applicationConfig: ApplicationConfig,
|
private val applicationConfig: ApplicationConfig,
|
||||||
private val instanceService: InstanceService,
|
private val instanceService: InstanceService,
|
||||||
private val userDetailRepository: UserDetailRepository,
|
private val userDetailRepository: UserDetailRepository,
|
||||||
private val deletedActorRepository: DeletedActorRepository,
|
private val deletedActorRepository: DeletedActorRepository,
|
||||||
private val deletedActorQueryService: DeletedActorQueryService,
|
|
||||||
private val reactionRepository: ReactionRepository,
|
private val reactionRepository: ReactionRepository,
|
||||||
private val relationshipRepository: RelationshipRepository,
|
private val relationshipRepository: RelationshipRepository,
|
||||||
private val postService: PostService,
|
private val postService: PostService,
|
||||||
|
@ -42,7 +37,7 @@ class UserServiceImpl(
|
||||||
UserService {
|
UserService {
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
val findByNameAndDomain = actorQueryService.findByNameAndDomain(username, applicationConfig.url.host)
|
val findByNameAndDomain = actorRepository.findByNameAndDomain(username, applicationConfig.url.host)
|
||||||
return findByNameAndDomain != null
|
return findByNameAndDomain != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,15 +68,14 @@ class UserServiceImpl(
|
||||||
return save
|
return save
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
override suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor {
|
override suspend fun createRemoteUser(user: RemoteUserCreateDto): Actor {
|
||||||
logger.info("START Create New remote user. name: {} url: {}", user.name, user.url)
|
logger.info("START Create New remote user. name: {} url: {}", user.name, user.url)
|
||||||
|
|
||||||
try {
|
val deletedActor = deletedActorRepository.findByNameAndDomain(user.name, user.domain)
|
||||||
deletedActorQueryService.findByNameAndDomain(user.name, user.domain)
|
|
||||||
|
if (deletedActor != null) {
|
||||||
logger.warn("FAILED Deleted actor. user: ${user.name} domain: ${user.domain}")
|
logger.warn("FAILED Deleted actor. user: ${user.name} domain: ${user.domain}")
|
||||||
throw IllegalStateException("Cannot create Deleted actor.")
|
throw IllegalStateException("Cannot create Deleted actor.")
|
||||||
} catch (_: FailedToGetResourcesException) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("TooGenericExceptionCaught")
|
@Suppress("TooGenericExceptionCaught")
|
||||||
|
@ -114,9 +108,8 @@ class UserServiceImpl(
|
||||||
val save = actorRepository.save(userEntity)
|
val save = actorRepository.save(userEntity)
|
||||||
logger.warn("SUCCESS Create New remote user. id: {} name: {} url: {}", userEntity.id, user.name, user.url)
|
logger.warn("SUCCESS Create New remote user. id: {} name: {} url: {}", userEntity.id, user.name, user.url)
|
||||||
save
|
save
|
||||||
} catch (_: ExposedSQLException) {
|
} catch (_: DuplicateException) {
|
||||||
logger.warn("FAILED User already exists. name: {} url: {}", user.name, user.url)
|
actorRepository.findByUrl(user.url)!!
|
||||||
actorQueryService.findByUrl(user.url)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +135,7 @@ class UserServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteRemoteActor(actorId: Long) {
|
override suspend fun deleteRemoteActor(actorId: Long) {
|
||||||
val actor = actorQueryService.findById(actorId)
|
val actor = actorRepository.findByIdWithLock(actorId) ?: throw UserNotFoundException.withId(actorId)
|
||||||
val deletedActor = DeletedActor(
|
val deletedActor = DeletedActor(
|
||||||
actor.id,
|
actor.id,
|
||||||
actor.name,
|
actor.name,
|
||||||
|
@ -161,7 +154,7 @@ class UserServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteLocalUser(userId: Long) {
|
override suspend fun deleteLocalUser(userId: Long) {
|
||||||
val actor = actorQueryService.findById(userId)
|
val actor = actorRepository.findByIdWithLock(userId) ?: throw UserNotFoundException.withId(userId)
|
||||||
apSendDeleteService.sendDeleteActor(actor)
|
apSendDeleteService.sendDeleteActor(actor)
|
||||||
val deletedActor = DeletedActor(
|
val deletedActor = DeletedActor(
|
||||||
actor.id,
|
actor.id,
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.config.ApplicationConfig
|
import dev.usbharu.hideout.application.config.ApplicationConfig
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
|
||||||
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Actors
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
||||||
import dev.usbharu.hideout.mastodon.query.AccountQueryService
|
import dev.usbharu.hideout.mastodon.query.AccountQueryService
|
||||||
import dev.usbharu.hideout.util.singleOr
|
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
import org.jetbrains.exposed.sql.ResultRow
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
@ -13,12 +11,12 @@ import java.time.Instant
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
|
class AccountQueryServiceImpl(private val applicationConfig: ApplicationConfig) : AccountQueryService {
|
||||||
override suspend fun findById(accountId: Long): Account {
|
override suspend fun findById(accountId: Long): Account? {
|
||||||
val query = Actors.select { Actors.id eq accountId }
|
val query = Actors.select { Actors.id eq accountId }
|
||||||
|
|
||||||
return query
|
return query
|
||||||
.singleOr { FailedToGetResourcesException("accountId: $accountId wad not exist or duplicate", it) }
|
.singleOrNull()
|
||||||
.let { toAccount(it) }
|
?.let { toAccount(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByIds(accountIds: List<Long>): List<Account> {
|
override suspend fun findByIds(accountIds: List<Long>): List<Account> {
|
||||||
|
|
|
@ -3,6 +3,6 @@ package dev.usbharu.hideout.mastodon.query
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Account
|
||||||
|
|
||||||
interface AccountQueryService {
|
interface AccountQueryService {
|
||||||
suspend fun findById(accountId: Long): Account
|
suspend fun findById(accountId: Long): Account?
|
||||||
suspend fun findByIds(accountIds: List<Long>): List<Account>
|
suspend fun findByIds(accountIds: List<Long>): List<Account>
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package dev.usbharu.hideout.mastodon.service.account
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
|
||||||
import dev.usbharu.hideout.core.query.RelationshipQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.media.MediaService
|
import dev.usbharu.hideout.core.service.media.MediaService
|
||||||
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
import dev.usbharu.hideout.core.service.relationship.RelationshipService
|
||||||
import dev.usbharu.hideout.core.service.user.UpdateUserDto
|
import dev.usbharu.hideout.core.service.user.UpdateUserDto
|
||||||
|
@ -71,8 +70,7 @@ class AccountApiServiceImpl(
|
||||||
private val statusQueryService: StatusQueryService,
|
private val statusQueryService: StatusQueryService,
|
||||||
private val relationshipService: RelationshipService,
|
private val relationshipService: RelationshipService,
|
||||||
private val relationshipRepository: RelationshipRepository,
|
private val relationshipRepository: RelationshipRepository,
|
||||||
private val mediaService: MediaService,
|
private val mediaService: MediaService
|
||||||
private val relationshipQueryService: RelationshipQueryService
|
|
||||||
) :
|
) :
|
||||||
AccountApiService {
|
AccountApiService {
|
||||||
override suspend fun accountsStatuses(
|
override suspend fun accountsStatuses(
|
||||||
|
@ -221,7 +219,7 @@ class AccountApiServiceImpl(
|
||||||
limit: Int,
|
limit: Int,
|
||||||
withIgnore: Boolean
|
withIgnore: Boolean
|
||||||
): List<Account> = transaction.transaction {
|
): List<Account> = transaction.transaction {
|
||||||
val actorIdList = relationshipQueryService
|
val actorIdList = relationshipRepository
|
||||||
.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
.findByTargetIdAndFollowRequestAndIgnoreFollowRequest(
|
||||||
maxId = maxId,
|
maxId = maxId,
|
||||||
sinceId = sinceId,
|
sinceId = sinceId,
|
||||||
|
|
|
@ -14,7 +14,8 @@ interface AccountService {
|
||||||
class AccountServiceImpl(
|
class AccountServiceImpl(
|
||||||
private val accountQueryService: AccountQueryService
|
private val accountQueryService: AccountQueryService
|
||||||
) : AccountService {
|
) : AccountService {
|
||||||
override suspend fun findById(id: Long): Account = accountQueryService.findById(id)
|
override suspend fun findById(id: Long): Account =
|
||||||
|
accountQueryService.findById(id) ?: throw IllegalArgumentException("Account $id not found.")
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<Account> = accountQueryService.findByIds(ids)
|
override suspend fun findByIds(ids: List<Long>): List<Account> = accountQueryService.findByIds(ids)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
package dev.usbharu.hideout.mastodon.service.status
|
package dev.usbharu.hideout.mastodon.service.status
|
||||||
|
|
||||||
import dev.usbharu.hideout.application.external.Transaction
|
import dev.usbharu.hideout.application.external.Transaction
|
||||||
import dev.usbharu.hideout.core.domain.exception.FailedToGetResourcesException
|
import dev.usbharu.hideout.core.domain.model.actor.ActorRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
import dev.usbharu.hideout.core.domain.model.media.MediaRepository
|
||||||
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
|
import dev.usbharu.hideout.core.domain.model.media.toMediaAttachments
|
||||||
import dev.usbharu.hideout.core.query.ActorQueryService
|
import dev.usbharu.hideout.core.domain.model.post.PostRepository
|
||||||
import dev.usbharu.hideout.core.query.PostQueryService
|
|
||||||
import dev.usbharu.hideout.core.service.post.PostCreateDto
|
import dev.usbharu.hideout.core.service.post.PostCreateDto
|
||||||
import dev.usbharu.hideout.core.service.post.PostService
|
import dev.usbharu.hideout.core.service.post.PostService
|
||||||
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
import dev.usbharu.hideout.domain.mastodon.model.generated.Status
|
||||||
|
@ -29,10 +28,10 @@ interface StatusesApiService {
|
||||||
class StatsesApiServiceImpl(
|
class StatsesApiServiceImpl(
|
||||||
private val postService: PostService,
|
private val postService: PostService,
|
||||||
private val accountService: AccountService,
|
private val accountService: AccountService,
|
||||||
private val postQueryService: PostQueryService,
|
|
||||||
private val actorQueryService: ActorQueryService,
|
|
||||||
private val mediaRepository: MediaRepository,
|
private val mediaRepository: MediaRepository,
|
||||||
private val transaction: Transaction
|
private val transaction: Transaction,
|
||||||
|
private val actorRepository: ActorRepository,
|
||||||
|
private val postRepository: PostRepository
|
||||||
) :
|
) :
|
||||||
StatusesApiService {
|
StatusesApiService {
|
||||||
override suspend fun postStatus(
|
override suspend fun postStatus(
|
||||||
|
@ -54,17 +53,18 @@ class StatsesApiServiceImpl(
|
||||||
val account = accountService.findById(userId)
|
val account = accountService.findById(userId)
|
||||||
|
|
||||||
val replyUser = if (post.replyId != null) {
|
val replyUser = if (post.replyId != null) {
|
||||||
try {
|
val findById = postRepository.findById(post.replyId)
|
||||||
actorQueryService.findById(postQueryService.findById(post.replyId).actorId).id
|
if (findById == null) {
|
||||||
} catch (ignore: FailedToGetResourcesException) {
|
|
||||||
null
|
null
|
||||||
|
} else {
|
||||||
|
actorRepository.findById(findById.actorId)?.id
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: n+1解消
|
// TODO: n+1解消
|
||||||
val mediaAttachment = post.mediaIds.map { mediaId ->
|
val mediaAttachment = post.mediaIds.mapNotNull { mediaId ->
|
||||||
mediaRepository.findById(mediaId)
|
mediaRepository.findById(mediaId)
|
||||||
}.map {
|
}.map {
|
||||||
it.toMediaAttachments()
|
it.toMediaAttachments()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
hideout:
|
hideout:
|
||||||
url: "https://test-hideout.usbharu.dev"
|
url: "https://test-hideout.usbharu.dev"
|
||||||
use-mongodb: false
|
use-mongodb: true
|
||||||
security:
|
security:
|
||||||
jwt:
|
jwt:
|
||||||
generate: true
|
generate: true
|
||||||
|
@ -22,14 +22,14 @@ spring:
|
||||||
url: "jdbc:postgresql:hideout2"
|
url: "jdbc:postgresql:hideout2"
|
||||||
username: "postgres"
|
username: "postgres"
|
||||||
password: ""
|
password: ""
|
||||||
# data:
|
data:
|
||||||
# mongodb:
|
mongodb:
|
||||||
# auto-index-creation: true
|
auto-index-creation: true
|
||||||
# host: localhost
|
host: localhost
|
||||||
# port: 27017
|
port: 27017
|
||||||
# database: hideout
|
database: hideout
|
||||||
# username: hideoutuser
|
# username: hideoutuser
|
||||||
# password: hideoutpass
|
# password: hideoutpass
|
||||||
servlet:
|
servlet:
|
||||||
multipart:
|
multipart:
|
||||||
max-file-size: 40MB
|
max-file-size: 40MB
|
||||||
|
|
|
@ -1,13 +1,28 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
|
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
<file>logFile.log</file>
|
||||||
|
<encoder>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id}] %logger{36} - %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||||
|
<!-- daily rollover -->
|
||||||
|
<fileNamePattern>logFile.%d{yyyy-MM-dd_HH}.log</fileNamePattern>
|
||||||
|
|
||||||
|
<!-- keep 30 days worth of history -->
|
||||||
|
<maxHistory>30</maxHistory>
|
||||||
|
</rollingPolicy>
|
||||||
|
</appender>
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id}] [%X{x-job-id}] %logger{36} -
|
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{x-request-id},%X{x-job-id}] %logger{36} -
|
||||||
%msg%n
|
%msg%n
|
||||||
</pattern>
|
</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
<root level="DEBUG">
|
<root level="DEBUG">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
|
<appender-ref ref="FILE"/>
|
||||||
</root>
|
</root>
|
||||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
<logger name="io.netty" level="INFO"/>
|
<logger name="io.netty" level="INFO"/>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue