Merge pull request #532 from usbharu/auth3

Mastodon APIから利用されるQuery Service等にも認可処理を追加
This commit is contained in:
usbharu 2024-08-11 18:13:51 +09:00 committed by GitHub
commit 42b9d4e64b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 321 additions and 123 deletions

View File

@ -23,7 +23,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import dev.usbharu.hideout.core.domain.service.relationship.RelationshipDomainService import dev.usbharu.hideout.core.domain.service.relationship.RelationshipDomainService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,14 +32,14 @@ class UserBlockApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
private val relationshipDomainService: RelationshipDomainService, private val relationshipDomainService: RelationshipDomainService,
) : ) :
LocalUserAbstractApplicationService<Block, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Block, Unit>(transaction, logger) {
override suspend fun internalExecute(command: Block, principal: FromApi) { override suspend fun internalExecute(command: Block, principal: FromApi) {
val userDetail = userDetailRepository.findById(principal.userDetailId)!!
val actor = actorRepository.findById(userDetail.actorId)!! val actor = actorRepository.findById(principal.actorId)
?: throw IllegalStateException("Actor ${principal.actorId} not found")
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.followrequest package dev.usbharu.hideout.core.application.relationship.followrequest
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorId
@ -23,7 +24,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -32,16 +32,14 @@ class UserFollowRequestApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : LocalUserAbstractApplicationService<FollowRequest, Unit>( ) : LocalUserAbstractApplicationService<FollowRequest, Unit>(
transaction, transaction,
logger logger
) { ) {
override suspend fun internalExecute(command: FollowRequest, principal: FromApi) { override suspend fun internalExecute(command: FollowRequest, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.get package dev.usbharu.hideout.core.application.relationship.get
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.actor.ActorId import dev.usbharu.hideout.core.domain.model.actor.ActorId
@ -24,7 +25,6 @@ import dev.usbharu.hideout.core.domain.model.actorinstancerelationship.ActorInst
import dev.usbharu.hideout.core.domain.model.actorinstancerelationship.ActorInstanceRelationshipRepository import dev.usbharu.hideout.core.domain.model.actorinstancerelationship.ActorInstanceRelationshipRepository
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.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -32,7 +32,6 @@ import org.springframework.stereotype.Service
class GetRelationshipApplicationService( class GetRelationshipApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
private val actorInstanceRelationshipRepository: ActorInstanceRelationshipRepository, private val actorInstanceRelationshipRepository: ActorInstanceRelationshipRepository,
transaction: Transaction, transaction: Transaction,
) : ) :
@ -41,19 +40,20 @@ class GetRelationshipApplicationService(
logger logger
) { ) {
override suspend fun internalExecute(command: GetRelationship, principal: FromApi): Relationship { override suspend fun internalExecute(command: GetRelationship, principal: FromApi): Relationship {
val userDetail = userDetailRepository.findById(principal.userDetailId)!! val actor = actorRepository.findById(principal.actorId)
val actor = actorRepository.findById(userDetail.actorId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val target = actorRepository.findById(targetId)!! val target = actorRepository.findById(targetId)
?: throw IllegalArgumentException("Actor ${command.targetActorId} not found.")
val relationship = ( val relationship = (
relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) relationshipRepository.findByActorIdAndTargetId(actor.id, targetId)
?: dev.usbharu.hideout.core.domain.model.relationship.Relationship.default(actor.id, targetId) ?: dev.usbharu.hideout.core.domain.model.relationship.Relationship.default(actor.id, targetId)
) )
val relationship1 = ( val relationship1 = (
relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) relationshipRepository.findByActorIdAndTargetId(targetId, actor.id)
?: dev.usbharu.hideout.core.domain.model.relationship.Relationship.default(targetId, actor.id) ?: dev.usbharu.hideout.core.domain.model.relationship.Relationship.default(targetId, actor.id)
) )
val actorInstanceRelationship = val actorInstanceRelationship =
actorInstanceRelationshipRepository.findByActorIdAndInstanceId(actor.id, target.instance) actorInstanceRelationshipRepository.findByActorIdAndInstanceId(actor.id, target.instance)

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.mute package dev.usbharu.hideout.core.application.relationship.mute
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -24,7 +25,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,13 +33,11 @@ class UserMuteApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<Mute, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Mute, Unit>(transaction, logger) {
override suspend fun internalExecute(command: Mute, principal: FromApi) { override suspend fun internalExecute(command: Mute, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.rejectfollowrequest package dev.usbharu.hideout.core.application.relationship.rejectfollowrequest
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -23,7 +24,6 @@ import dev.usbharu.hideout.core.domain.model.actor.ActorId
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.RelationshipRepository import dev.usbharu.hideout.core.domain.model.relationship.RelationshipRepository
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -32,13 +32,11 @@ class UserRejectFollowRequestApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<RejectFollowRequest, Unit>(transaction, logger) { LocalUserAbstractApplicationService<RejectFollowRequest, Unit>(transaction, logger) {
override suspend fun internalExecute(command: RejectFollowRequest, principal: FromApi) { override suspend fun internalExecute(command: RejectFollowRequest, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.sourceActorId) val targetId = ActorId(command.sourceActorId)

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.removefromfollowers package dev.usbharu.hideout.core.application.relationship.removefromfollowers
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -24,7 +25,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,13 +33,11 @@ class UserRemoveFromFollowersApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<RemoveFromFollowers, Unit>(transaction, logger) { LocalUserAbstractApplicationService<RemoveFromFollowers, Unit>(transaction, logger) {
override suspend fun internalExecute(command: RemoveFromFollowers, principal: FromApi) { override suspend fun internalExecute(command: RemoveFromFollowers, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(targetId, actor.id) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.unblock package dev.usbharu.hideout.core.application.relationship.unblock
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -24,7 +25,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,13 +33,11 @@ class UserUnblockApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<Unblock, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Unblock, Unit>(transaction, logger) {
override suspend fun internalExecute(command: Unblock, principal: FromApi) { override suspend fun internalExecute(command: Unblock, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.unfollow package dev.usbharu.hideout.core.application.relationship.unfollow
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -24,7 +25,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,13 +33,11 @@ class UserUnfollowApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<Unfollow, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Unfollow, Unit>(transaction, logger) {
override suspend fun internalExecute(command: Unfollow, principal: FromApi) { override suspend fun internalExecute(command: Unfollow, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.core.application.relationship.unmute package dev.usbharu.hideout.core.application.relationship.unmute
import dev.usbharu.hideout.core.application.exception.InternalServerException
import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService import dev.usbharu.hideout.core.application.relationship.block.UserBlockApplicationService
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
@ -24,7 +25,6 @@ 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.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -33,7 +33,6 @@ class UserUnmuteApplicationService(
private val relationshipRepository: RelationshipRepository, private val relationshipRepository: RelationshipRepository,
transaction: Transaction, transaction: Transaction,
private val actorRepository: ActorRepository, private val actorRepository: ActorRepository,
private val userDetailRepository: UserDetailRepository,
) : ) :
LocalUserAbstractApplicationService<Unmute, Unit>(transaction, logger) { LocalUserAbstractApplicationService<Unmute, Unit>(transaction, logger) {
companion object { companion object {
@ -41,9 +40,8 @@ class UserUnmuteApplicationService(
} }
override suspend fun internalExecute(command: Unmute, principal: FromApi) { override suspend fun internalExecute(command: Unmute, principal: FromApi) {
val actor = actorRepository.findById(principal.actorId)
val userDetail = userDetailRepository.findById(principal.userDetailId)!! ?: throw InternalServerException("Actor ${principal.actorId} not found.")
val actor = actorRepository.findById(userDetail.actorId)!!
val targetId = ActorId(command.targetActorId) val targetId = ActorId(command.targetActorId)
val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default( val relationship = relationshipRepository.findByActorIdAndTargetId(actor.id, targetId) ?: Relationship.default(

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.core.application.shared package dev.usbharu.hideout.core.application.shared
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.Principal
import org.slf4j.Logger import org.slf4j.Logger
@ -7,7 +8,9 @@ import org.slf4j.Logger
abstract class LocalUserAbstractApplicationService<T : Any, R>(transaction: Transaction, logger: Logger) : abstract class LocalUserAbstractApplicationService<T : Any, R>(transaction: Transaction, logger: Logger) :
AbstractApplicationService<T, R>(transaction, logger) { AbstractApplicationService<T, R>(transaction, logger) {
override suspend fun internalExecute(command: T, principal: Principal): R { override suspend fun internalExecute(command: T, principal: Principal): R {
require(principal is FromApi) if (principal !is FromApi) {
throw PermissionDeniedException()
}
return internalExecute(command, principal) return internalExecute(command, principal)
} }

View File

@ -1,8 +1,8 @@
package dev.usbharu.hideout.core.application.timeline package dev.usbharu.hideout.core.application.timeline
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository import dev.usbharu.hideout.core.domain.model.timelinerelationship.TimelineRelationshipRepository
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -12,12 +12,11 @@ class UserAddTimelineRelationshipApplicationService(
private val timelineRelationshipRepository: TimelineRelationshipRepository, private val timelineRelationshipRepository: TimelineRelationshipRepository,
transaction: Transaction transaction: Transaction
) : ) :
AbstractApplicationService<AddTimelineRelationship, Unit>( LocalUserAbstractApplicationService<AddTimelineRelationship, Unit>(
transaction, logger transaction, logger
) { ) {
override suspend fun internalExecute(command: AddTimelineRelationship, principal: Principal) { override suspend fun internalExecute(command: AddTimelineRelationship, principal: FromApi) {
timelineRelationshipRepository.save(command.timelineRelationship) timelineRelationshipRepository.save(command.timelineRelationship)
} }
companion object { companion object {

View File

@ -30,6 +30,7 @@ import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.createdAt
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.deleted import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.deleted
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.hide import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.hide
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.id import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.id
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.instanceId
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.moveTo import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.moveTo
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.overview import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.overview
import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.replyId import dev.usbharu.hideout.core.infrastructure.exposedrepository.Posts.replyId
@ -61,6 +62,7 @@ class ExposedPostRepository(
Posts.upsert { Posts.upsert {
it[id] = post.id.id it[id] = post.id.id
it[actorId] = post.actorId.id it[actorId] = post.actorId.id
it[instanceId] = post.instanceId.instanceId
it[overview] = post.overview?.overview it[overview] = post.overview?.overview
it[content] = post.content.content it[content] = post.content.content
it[text] = post.content.text it[text] = post.content.text
@ -106,6 +108,7 @@ class ExposedPostRepository(
Posts.batchUpsert(posts, id) { Posts.batchUpsert(posts, id) {
this[id] = it.id.id this[id] = it.id.id
this[actorId] = it.actorId.id this[actorId] = it.actorId.id
this[instanceId] = it.instanceId.instanceId
this[overview] = it.overview?.overview this[overview] = it.overview?.overview
this[content] = it.content.content this[content] = it.content.content
this[text] = it.content.text this[text] = it.content.text

View File

@ -1,7 +1,10 @@
package dev.usbharu.hideout.core.infrastructure.springframework.oauth2 package dev.usbharu.hideout.core.infrastructure.springframework.oauth2
import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.support.acct.Acct import dev.usbharu.hideout.core.domain.model.support.acct.Acct
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
import dev.usbharu.hideout.core.domain.model.support.principal.PrincipalContextHolder import dev.usbharu.hideout.core.domain.model.support.principal.PrincipalContextHolder
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import dev.usbharu.hideout.core.query.principal.PrincipalQueryService import dev.usbharu.hideout.core.query.principal.PrincipalQueryService
@ -10,18 +13,24 @@ import org.springframework.security.oauth2.jwt.Jwt
import org.springframework.stereotype.Component import org.springframework.stereotype.Component
@Component @Component
class SpringSecurityOauth2PrincipalContextHolder(private val principalQueryService: PrincipalQueryService) : class SpringSecurityOauth2PrincipalContextHolder(
private val principalQueryService: PrincipalQueryService,
private val transaction: Transaction
) :
PrincipalContextHolder { PrincipalContextHolder {
override suspend fun getPrincipal(): FromApi { override suspend fun getPrincipal(): Principal {
val principal = SecurityContextHolder.getContext().authentication?.principal as Jwt val principal =
SecurityContextHolder.getContext().authentication?.principal as? Jwt ?: return Anonymous
val id = principal.getClaim<String>("uid").toLong() return transaction.transaction {
val userDetail = principalQueryService.findByUserDetailId(UserDetailId(id)) val id = principal.getClaim<String>("uid").toLong()
val userDetail = principalQueryService.findByUserDetailId(UserDetailId(id))
return FromApi( return@transaction FromApi(
userDetail.actorId, userDetail.actorId,
userDetail.userDetailId, userDetail.userDetailId,
Acct(userDetail.username, userDetail.host) Acct(userDetail.username, userDetail.host)
) )
}
} }
} }

View File

@ -12,7 +12,9 @@ hideout:
private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ==" private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ=="
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"
private: true private: true
debug:
trace-query-exception: true
trace-query-call: true

View File

@ -71,6 +71,14 @@ create table if not exists actor_alsoknownas
constraint fk_actor_alsoknownas_actors__also_known_as foreign key ("also_known_as") references actors (id) on delete cascade on update cascade constraint fk_actor_alsoknownas_actors__also_known_as foreign key ("also_known_as") references actors (id) on delete cascade on update cascade
); );
create table timelines
(
id bigint primary key,
user_detail_id bigint not null,
name varchar(255) not null,
visibility varchar(100) not null,
is_system boolean not null default false
);
create table if not exists user_details create table if not exists user_details
( (
id bigserial primary key, id bigserial primary key,
@ -78,9 +86,14 @@ create table if not exists user_details
password varchar(255) not null, password varchar(255) not null,
auto_accept_followee_follow_request boolean not null, auto_accept_followee_follow_request boolean not null,
last_migration timestamp null default null, last_migration timestamp null default null,
constraint fk_user_details_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict home_timeline_id bigint null default null,
constraint fk_user_details_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict,
constraint fk_user_details_timelines_id__id foreign key (home_timeline_id) references timelines (id) on delete cascade on update cascade
); );
alter table timelines
add constraint fk_timelines_user_details__user_detail_id foreign key ("user_detail_id") references user_details (id) on delete cascade on update cascade;
create table if not exists media create table if not exists media
( (
id bigint primary key, id bigint primary key,
@ -104,6 +117,7 @@ create table if not exists posts
( (
id bigint primary key, id bigint primary key,
actor_id bigint not null, actor_id bigint not null,
instance_id bigint not null,
overview varchar(100) null, overview varchar(100) null,
content varchar(5000) not null, content varchar(5000) not null,
text varchar(3000) not null, text varchar(3000) not null,
@ -118,6 +132,8 @@ create table if not exists posts
hide boolean default false not null, hide boolean default false not null,
move_to bigint default null null move_to bigint default null null
); );
alter table posts
add constraint fk_posts_instance_id__id foreign key (instance_id) references instance (id) on delete cascade on update cascade;
alter table posts alter table posts
add constraint fk_posts_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict; add constraint fk_posts_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict;
alter table posts alter table posts
@ -172,8 +188,8 @@ create table if not exists relationships
following boolean not null, following boolean not null,
blocking boolean not null, blocking boolean not null,
muting boolean not null, muting boolean not null,
follow_request boolean not null, follow_requesting boolean not null,
ignore_follow_request boolean not null, muting_follow_request boolean not null,
constraint fk_relationships_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict, constraint fk_relationships_actor_id__id foreign key (actor_id) references actors (id) on delete restrict on update restrict,
constraint fk_relationships_target_actor_id__id foreign key (target_actor_id) references actors (id) on delete restrict on update restrict, constraint fk_relationships_target_actor_id__id foreign key (target_actor_id) references actors (id) on delete restrict on update restrict,
unique (actor_id, target_actor_id) unique (actor_id, target_actor_id)

View File

@ -12,5 +12,6 @@
<Logger name="dev.usbharu.owl.broker.service.QueuedTaskAssignerImpl" level="TRACE"/> <Logger name="dev.usbharu.owl.broker.service.QueuedTaskAssignerImpl" level="TRACE"/>
<Logger name="org.mongodb.driver.cluster" level="WARN"/> <Logger name="org.mongodb.driver.cluster" level="WARN"/>
<Logger name="org.apache.tomcat.util.net.NioEndpoint" level="INFO"/> <Logger name="org.apache.tomcat.util.net.NioEndpoint" level="INFO"/>
<Logger name="Exposed" level="DEBUG"/>
</Loggers> </Loggers>
</Configuration> </Configuration>

View File

@ -27,7 +27,7 @@
<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"/>
<logger name="kjob.core.internal.scheduler.JobServiceImpl" level="INFO"/> <logger name="kjob.core.internal.scheduler.JobServiceImpl" level="INFO"/>
<logger name="Exposed" level="INFO"/> <logger name="Exposed" level="DEBUG"/>
<logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/> <logger name="io.ktor.server.plugins.contentnegotiation" level="INFO"/>
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/> <logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
<logger name="org.mongodb.driver.protocol.command" level="INFO"/> <logger name="org.mongodb.driver.protocol.command" level="INFO"/>

View File

@ -1,5 +1,6 @@
package dev.usbharu.hideout.core.application.shared package dev.usbharu.hideout.core.application.shared
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous import dev.usbharu.hideout.core.domain.model.support.principal.Anonymous
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -17,7 +18,7 @@ class LocalUserAbstractApplicationServiceTest {
} }
} }
org.junit.jupiter.api.assertThrows<IllegalArgumentException> { org.junit.jupiter.api.assertThrows<PermissionDeniedException> {
value.execute(Unit, Anonymous) value.execute(Unit, Anonymous)
} }
} }

View File

@ -17,6 +17,27 @@ version = "1.0-SNAPSHOT"
repositories { repositories {
mavenCentral() mavenCentral()
maven {
url = uri("https://git.usbharu.dev/api/packages/usbharu/maven")
}
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/usbharu/http-signature")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
maven {
name = "GitHubPackages2"
url = uri("https://maven.pkg.github.com/multim-dev/emoji-kt")
credentials {
username = project.findProperty("gpr.user") as String? ?: System.getenv("USERNAME")
password = project.findProperty("gpr.key") as String? ?: System.getenv("TOKEN")
}
}
} }
configurations { configurations {
@ -42,8 +63,14 @@ dependencies {
implementation(libs.bundles.exposed) implementation(libs.bundles.exposed)
implementation(libs.bundles.openapi) implementation(libs.bundles.openapi)
implementation(libs.bundles.coroutines) implementation(libs.bundles.coroutines)
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation(libs.kotlin.junit)
testImplementation(libs.coroutines.test)
testImplementation(libs.h2db)
} }
tasks { tasks {
test { test {
useJUnitPlatform() useJUnitPlatform()

View File

@ -16,9 +16,9 @@
package dev.usbharu.hideout.mastodon.application.accounts package dev.usbharu.hideout.mastodon.application.accounts
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Account import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Account
import dev.usbharu.hideout.mastodon.query.AccountQueryService import dev.usbharu.hideout.mastodon.query.AccountQueryService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -26,11 +26,11 @@ import org.springframework.stereotype.Service
@Service @Service
class GetAccountApplicationService(private val accountQueryService: AccountQueryService, transaction: Transaction) : class GetAccountApplicationService(private val accountQueryService: AccountQueryService, transaction: Transaction) :
AbstractApplicationService<GetAccount, Account>( LocalUserAbstractApplicationService<GetAccount, Account>(
transaction, transaction,
logger logger
) { ) {
override suspend fun internalExecute(command: GetAccount, principal: Principal): Account { override suspend fun internalExecute(command: GetAccount, principal: FromApi): Account {
return accountQueryService.findById(command.accountId.toLong()) ?: throw Exception("Account not found") return accountQueryService.findById(command.accountId.toLong()) ?: throw Exception("Account not found")
} }

View File

@ -16,26 +16,30 @@
package dev.usbharu.hideout.mastodon.application.filter package dev.usbharu.hideout.mastodon.application.filter
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterKeywordId import dev.usbharu.hideout.core.domain.model.filter.FilterKeywordId
import dev.usbharu.hideout.core.domain.model.filter.FilterRepository import dev.usbharu.hideout.core.domain.model.filter.FilterRepository
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@Service @Service
class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) : class DeleteFilterV1ApplicationService(private val filterRepository: FilterRepository, transaction: Transaction) :
AbstractApplicationService<DeleteFilterV1, Unit>( LocalUserAbstractApplicationService<DeleteFilterV1, Unit>(
transaction, logger transaction, logger
) { ) {
override suspend fun internalExecute(command: DeleteFilterV1, principal: FromApi) {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
?: throw IllegalArgumentException("Filter ${command.filterKeywordId} not found")
if (principal.userDetailId != filter.userDetailId) {
throw PermissionDeniedException()
}
filterRepository.delete(filter)
}
companion object { companion object {
private val logger = LoggerFactory.getLogger(DeleteFilterV1ApplicationService::class.java) private val logger = LoggerFactory.getLogger(DeleteFilterV1ApplicationService::class.java)
} }
override suspend fun internalExecute(command: DeleteFilterV1, principal: Principal) {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
?: throw Exception("Not Found")
filterRepository.delete(filter)
}
} }

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.mastodon.application.filter package dev.usbharu.hideout.mastodon.application.filter
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.AbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.filter.FilterContext.* import dev.usbharu.hideout.core.domain.model.filter.FilterContext.*
@ -34,7 +35,11 @@ class GetFilterV1ApplicationService(private val filterRepository: FilterReposito
) { ) {
override suspend fun internalExecute(command: GetFilterV1, principal: Principal): V1Filter { override suspend fun internalExecute(command: GetFilterV1, principal: Principal): V1Filter {
val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId)) val filter = filterRepository.findByFilterKeywordId(FilterKeywordId(command.filterKeywordId))
?: throw Exception("Not Found") ?: throw IllegalArgumentException("Filter ${command.filterKeywordId} not found")
if (filter.userDetailId != principal.userDetailId) {
throw PermissionDeniedException()
}
val filterKeyword = filter.filterKeywords.find { it.id.id == command.filterKeywordId } val filterKeyword = filter.filterKeywords.find { it.id.id == command.filterKeywordId }
return V1Filter( return V1Filter(

View File

@ -16,9 +16,9 @@
package dev.usbharu.hideout.mastodon.application.status package dev.usbharu.hideout.mastodon.application.status
import dev.usbharu.hideout.core.application.shared.AbstractApplicationService import dev.usbharu.hideout.core.application.shared.LocalUserAbstractApplicationService
import dev.usbharu.hideout.core.application.shared.Transaction import dev.usbharu.hideout.core.application.shared.Transaction
import dev.usbharu.hideout.core.domain.model.support.principal.Principal import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status
import dev.usbharu.hideout.mastodon.query.StatusQueryService import dev.usbharu.hideout.mastodon.query.StatusQueryService
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
@ -28,7 +28,7 @@ import org.springframework.stereotype.Service
class GetStatusApplicationService( class GetStatusApplicationService(
private val statusQueryService: StatusQueryService, private val statusQueryService: StatusQueryService,
transaction: Transaction, transaction: Transaction,
) : AbstractApplicationService<GetStatus, Status>( ) : LocalUserAbstractApplicationService<GetStatus, Status>(
transaction, transaction,
logger logger
) { ) {
@ -36,7 +36,9 @@ class GetStatusApplicationService(
val logger = LoggerFactory.getLogger(GetStatusApplicationService::class.java)!! val logger = LoggerFactory.getLogger(GetStatusApplicationService::class.java)!!
} }
override suspend fun internalExecute(command: GetStatus, principal: Principal): Status { override suspend fun internalExecute(command: GetStatus, principal: FromApi): Status {
return statusQueryService.findByPostId(command.id.toLong()) ?: throw Exception("Not fount") return statusQueryService.findByPostId(command.id.toLong(), principal)
?: throw IllegalArgumentException("Post ${command.id} not found.")
} }
} }

View File

@ -19,6 +19,7 @@ package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji import dev.usbharu.hideout.core.domain.model.emoji.CustomEmoji
import dev.usbharu.hideout.core.domain.model.media.* import dev.usbharu.hideout.core.domain.model.media.*
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.support.principal.Principal
import dev.usbharu.hideout.core.infrastructure.exposedrepository.* import dev.usbharu.hideout.core.infrastructure.exposedrepository.*
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Account import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Account
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.MediaAttachment import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.MediaAttachment
@ -26,10 +27,7 @@ import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status.Visibility.* import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status.Visibility.*
import dev.usbharu.hideout.mastodon.query.StatusQuery import dev.usbharu.hideout.mastodon.query.StatusQuery
import dev.usbharu.hideout.mastodon.query.StatusQueryService import dev.usbharu.hideout.mastodon.query.StatusQueryService
import org.jetbrains.exposed.sql.ResultRow import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.andWhere
import org.jetbrains.exposed.sql.leftJoin
import org.jetbrains.exposed.sql.selectAll
import org.springframework.stereotype.Repository import org.springframework.stereotype.Repository
import java.net.URI import java.net.URI
import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia import dev.usbharu.hideout.core.domain.model.media.Media as EntityMedia
@ -38,6 +36,37 @@ import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.CustomEmoji a
@Suppress("IncompleteDestructuring") @Suppress("IncompleteDestructuring")
@Repository @Repository
class StatusQueryServiceImpl : StatusQueryService { class StatusQueryServiceImpl : StatusQueryService {
protected fun authorizedQuery(principal: Principal? = null): QueryAlias {
if (principal == null) {
return Posts
.selectAll()
.where {
Posts.visibility eq Visibility.PUBLIC.name or (Posts.visibility eq Visibility.UNLISTED.name)
}
.alias("authorized_table")
}
val relationshipsAlias = Relationships.alias("inverse_relationships")
return Posts
.leftJoin(PostsVisibleActors)
.leftJoin(Relationships, onColumn = { Posts.actorId }, otherColumn = { actorId })
.leftJoin(
relationshipsAlias,
onColumn = { Posts.actorId },
otherColumn = { relationshipsAlias[Relationships.targetActorId] })
.select(Posts.columns)
.where {
Posts.visibility eq Visibility.PUBLIC.name or
(Posts.visibility eq Visibility.UNLISTED.name) or
(Posts.visibility eq Visibility.DIRECT.name and (PostsVisibleActors.actorId eq principal.actorId.id)) or
(Posts.visibility eq Visibility.FOLLOWERS.name and (Relationships.blocking eq false and (relationshipsAlias[Relationships.following] eq true))) or
(Posts.actorId eq principal.actorId.id)
}
.alias("authorized_table")
}
override suspend fun findByPostIds(ids: List<Long>): List<Status> = findByPostIdsWithMedia(ids) override suspend fun findByPostIds(ids: List<Long>): List<Status> = findByPostIdsWithMedia(ids)
override suspend fun findByPostIdsWithMediaIds(statusQueries: List<StatusQuery>): List<Status> { override suspend fun findByPostIdsWithMediaIds(statusQueries: List<StatusQuery>): List<Status> {
@ -49,10 +78,12 @@ class StatusQueryServiceImpl : StatusQueryService {
val emojiIdSet = mutableSetOf<Long>() val emojiIdSet = mutableSetOf<Long>()
emojiIdSet.addAll(statusQueries.flatMap { it.emojiIds }) emojiIdSet.addAll(statusQueries.flatMap { it.emojiIds })
val qa = authorizedQuery()
val postMap = Posts val postMap = Posts
.leftJoin(Actors) .leftJoin(Actors)
.selectAll().where { Posts.id inList postIdSet } .selectAll().where { Posts.id inList postIdSet }
.associate { it[Posts.id] to toStatus(it) } .associate { it[Posts.id] to toStatus(it, qa) }
val mediaMap = Media.selectAll().where { Media.id inList mediaIdSet } val mediaMap = Media.selectAll().where { Media.id inList mediaIdSet }
.associate { .associate {
it[Media.id] to it.toMedia().toMediaAttachments() it[Media.id] to it.toMedia().toMediaAttachments()
@ -81,7 +112,8 @@ class StatusQueryServiceImpl : StatusQueryService {
tagged: String?, tagged: String?,
includeFollowers: Boolean, includeFollowers: Boolean,
): List<Status> { ): List<Status> {
val query = Posts val qa = authorizedQuery()
val query = qa
.leftJoin(PostsMedia) .leftJoin(PostsMedia)
.leftJoin(Actors) .leftJoin(Actors)
.leftJoin(Media) .leftJoin(Media)
@ -106,7 +138,7 @@ class StatusQueryServiceImpl : StatusQueryService {
.groupBy { it[Posts.id] } .groupBy { it[Posts.id] }
.map { it.value } .map { it.value }
.map { .map {
toStatus(it.first()).copy( toStatus(it.first(), qa).copy(
mediaAttachments = it.mapNotNull { resultRow -> mediaAttachments = it.mapNotNull { resultRow ->
resultRow.toMediaOrNull()?.toMediaAttachments() resultRow.toMediaOrNull()?.toMediaAttachments()
} }
@ -117,22 +149,23 @@ class StatusQueryServiceImpl : StatusQueryService {
return statuses return statuses
} }
override suspend fun findByPostId(id: Long): Status? { override suspend fun findByPostId(id: Long, principal: Principal?): Status? {
val map = Posts val aq = authorizedQuery(principal)
.leftJoin(PostsMedia) val map = aq
.leftJoin(Actors) .leftJoin(PostsMedia, { aq[Posts.id] }, { PostsMedia.postId })
.leftJoin(Media,{PostsMedia.mediaId},{Media.id}) .leftJoin(Actors, { aq[Posts.actorId] }, { Actors.id })
.leftJoin(Media, { PostsMedia.mediaId }, { Media.id })
.selectAll() .selectAll()
.where { Posts.id eq id } .where { aq[Posts.id] eq id }
.groupBy { it[Posts.id] } .groupBy { it[aq[Posts.id]] }
.map { it.value } .map { it.value }
.map { .map {
toStatus(it.first()).copy( toStatus(it.first(), aq).copy(
mediaAttachments = it.mapNotNull { resultRow -> mediaAttachments = it.mapNotNull { resultRow ->
resultRow.toMediaOrNull()?.toMediaAttachments() resultRow.toMediaOrNull()?.toMediaAttachments()
}, },
emojis = it.mapNotNull { resultRow -> resultRow.toCustomEmojiOrNull()?.toMastodonEmoji() } emojis = it.mapNotNull { resultRow -> resultRow.toCustomEmojiOrNull()?.toMastodonEmoji() }
) to it.first()[Posts.repostId] ) to it.first()[aq[Posts.repostId]]
} }
return resolveReplyAndRepost(map).singleOrNull() return resolveReplyAndRepost(map).singleOrNull()
} }
@ -159,6 +192,7 @@ class StatusQueryServiceImpl : StatusQueryService {
} }
private suspend fun findByPostIdsWithMedia(ids: List<Long>): List<Status> { private suspend fun findByPostIdsWithMedia(ids: List<Long>): List<Status> {
val qa = authorizedQuery()
val pairs = Posts val pairs = Posts
.leftJoin(PostsMedia) .leftJoin(PostsMedia)
.leftJoin(PostsEmojis) .leftJoin(PostsEmojis)
@ -169,7 +203,7 @@ class StatusQueryServiceImpl : StatusQueryService {
.groupBy { it[Posts.id] } .groupBy { it[Posts.id] }
.map { it.value } .map { it.value }
.map { .map {
toStatus(it.first()).copy( toStatus(it.first(), qa).copy(
mediaAttachments = it.mapNotNull { resultRow -> mediaAttachments = it.mapNotNull { resultRow ->
resultRow.toMediaOrNull()?.toMediaAttachments() resultRow.toMediaOrNull()?.toMediaAttachments()
}, },
@ -188,10 +222,10 @@ private fun CustomEmoji.toMastodonEmoji(): MastodonEmoji = MastodonEmoji(
category = this.category.orEmpty() category = this.category.orEmpty()
) )
private fun toStatus(it: ResultRow) = Status( private fun toStatus(it: ResultRow, queryAlias: QueryAlias) = Status(
id = it[Posts.id].toString(), id = it[queryAlias[Posts.id]].toString(),
uri = it[Posts.apId], uri = it[queryAlias[Posts.apId]],
createdAt = it[Posts.createdAt].toString(), createdAt = it[queryAlias[Posts.createdAt]].toString(),
account = Account( account = Account(
id = it[Actors.id].toString(), id = it[Actors.id].toString(),
username = it[Actors.name], username = it[Actors.name],
@ -219,15 +253,15 @@ private fun toStatus(it: ResultRow) = Status(
suspended = false, suspended = false,
limited = false limited = false
), ),
content = it[Posts.text], content = it[queryAlias[Posts.text]],
visibility = when (Visibility.valueOf(it[Posts.visibility])) { visibility = when (Visibility.valueOf(it[queryAlias[Posts.visibility]])) {
Visibility.PUBLIC -> public Visibility.PUBLIC -> public
Visibility.UNLISTED -> unlisted Visibility.UNLISTED -> unlisted
Visibility.FOLLOWERS -> private Visibility.FOLLOWERS -> private
Visibility.DIRECT -> direct Visibility.DIRECT -> direct
}, },
sensitive = it[Posts.sensitive], sensitive = it[queryAlias[Posts.sensitive]],
spoilerText = it[Posts.overview].orEmpty(), spoilerText = it[queryAlias[Posts.overview]].orEmpty(),
mediaAttachments = emptyList(), mediaAttachments = emptyList(),
mentions = emptyList(), mentions = emptyList(),
tags = emptyList(), tags = emptyList(),
@ -235,11 +269,11 @@ private fun toStatus(it: ResultRow) = Status(
reblogsCount = 0, reblogsCount = 0,
favouritesCount = 0, favouritesCount = 0,
repliesCount = 0, repliesCount = 0,
url = it[Posts.apId], url = it[queryAlias[Posts.apId]],
inReplyToId = it[Posts.replyId]?.toString(), inReplyToId = it[queryAlias[Posts.replyId]]?.toString(),
inReplyToAccountId = null, inReplyToAccountId = null,
language = null, language = null,
text = it[Posts.text], text = it[queryAlias[Posts.text]],
editedAt = null editedAt = null
) )

View File

@ -18,6 +18,7 @@ package dev.usbharu.hideout.mastodon.interfaces.api
import dev.usbharu.hideout.core.application.actor.GetUserDetail import dev.usbharu.hideout.core.application.actor.GetUserDetail
import dev.usbharu.hideout.core.application.actor.GetUserDetailApplicationService import dev.usbharu.hideout.core.application.actor.GetUserDetailApplicationService
import dev.usbharu.hideout.core.application.exception.PermissionDeniedException
import dev.usbharu.hideout.core.application.relationship.acceptfollowrequest.AcceptFollowRequest import dev.usbharu.hideout.core.application.relationship.acceptfollowrequest.AcceptFollowRequest
import dev.usbharu.hideout.core.application.relationship.acceptfollowrequest.UserAcceptFollowRequestApplicationService import dev.usbharu.hideout.core.application.relationship.acceptfollowrequest.UserAcceptFollowRequestApplicationService
import dev.usbharu.hideout.core.application.relationship.block.Block import dev.usbharu.hideout.core.application.relationship.block.Block
@ -160,7 +161,11 @@ class SpringAccountApi(
override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> { override suspend fun apiV1AccountsVerifyCredentialsGet(): ResponseEntity<CredentialAccount> {
val principal = principalContextHolder.getPrincipal() val principal = principalContextHolder.getPrincipal()
val localActor = val localActor =
getUserDetailApplicationService.execute(GetUserDetail(principal.userDetailId.id), principal) getUserDetailApplicationService.execute(
GetUserDetail(
principal.userDetailId?.id ?: throw PermissionDeniedException()
), principal
)
return ResponseEntity.ok( return ResponseEntity.ok(
CredentialAccount( CredentialAccount(

View File

@ -54,6 +54,7 @@ class SpringStatusApi(
override suspend fun apiV1StatusesPost(statusesRequest: StatusesRequest): ResponseEntity<Status> { override suspend fun apiV1StatusesPost(statusesRequest: StatusesRequest): ResponseEntity<Status> {
val principal = principalContextHolder.getPrincipal()
val execute = registerLocalPostApplicationService.execute( val execute = registerLocalPostApplicationService.execute(
RegisterLocalPost( RegisterLocalPost(
content = statusesRequest.status.orEmpty(), content = statusesRequest.status.orEmpty(),
@ -69,12 +70,12 @@ class SpringStatusApi(
replyId = statusesRequest.inReplyToId?.toLong(), replyId = statusesRequest.inReplyToId?.toLong(),
sensitive = statusesRequest.sensitive == true, sensitive = statusesRequest.sensitive == true,
mediaIds = statusesRequest.mediaIds.orEmpty().map { it.toLong() } mediaIds = statusesRequest.mediaIds.orEmpty().map { it.toLong() }
), principalContextHolder.getPrincipal() ), principal
) )
val status = val status =
getStatusApplicationService.execute(GetStatus(execute.toString()), principalContextHolder.getPrincipal()) getStatusApplicationService.execute(GetStatus(execute.toString()), principal)
return ResponseEntity.ok( return ResponseEntity.ok(
status status
) )

View File

@ -16,6 +16,7 @@
package dev.usbharu.hideout.mastodon.query package dev.usbharu.hideout.mastodon.query
import dev.usbharu.hideout.core.domain.model.support.principal.Principal
import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status import dev.usbharu.hideout.mastodon.interfaces.api.generated.model.Status
interface StatusQueryService { interface StatusQueryService {
@ -33,7 +34,7 @@ interface StatusQueryService {
includeFollowers: Boolean = false, includeFollowers: Boolean = false,
): List<Status> ): List<Status>
suspend fun findByPostId(id: Long): Status? suspend fun findByPostId(id: Long, principal: Principal? = null): Status?
} }
data class StatusQuery( data class StatusQuery(

View File

@ -0,0 +1,33 @@
package dev.usbharu.hideout.mastodon.infrastructure.exposedquery
import dev.usbharu.hideout.SpringApplication
import dev.usbharu.hideout.core.domain.model.actor.ActorId
import dev.usbharu.hideout.core.domain.model.support.acct.Acct
import dev.usbharu.hideout.core.domain.model.support.principal.FromApi
import dev.usbharu.hideout.core.domain.model.userdetails.UserDetailId
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.jdbc.Sql
import org.springframework.transaction.annotation.Transactional
@Sql("/sql/actors.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql("/sql/relationships.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Transactional
@SpringBootTest(classes = [SpringApplication::class])
class StatusQueryServiceImplTest {
@Autowired
lateinit var statusQueryServiceImpl: StatusQueryServiceImpl
@Test
fun フォロワー限定をフォロワー以外は見れない() = runTest {
val status =
statusQueryServiceImpl.findByPostId(4, FromApi(ActorId(1), UserDetailId(1), Acct("test", "example.com")))
assertNull(status)
}
}

View File

@ -0,0 +1,12 @@
spring:
datasource:
url: "jdbc:h2:mem:test;MODE=POSTGRESQL;DB_CLOSE_DELAY=-1;CASE_INSENSITIVE_IDENTIFIERS=true;TRACE_LEVEL_FILE=4;"
driver-class-name: org.h2.Driver
hideout:
url: "https://test-hideout-dev.usbharu.dev"
security:
jwt:
generate: true
key-id: a
private-key: "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC7VJTUt9Us8cKjMzEfYyjiWA4R4/M2bS1GB4t7NXp98C3SC6dVMvDuictGeurT8jNbvJZHtCSuYEvuNMoSfm76oqFvAp8Gy0iz5sxjZmSnXyCdPEovGhLa0VzMaQ8s+CLOyS56YyCFGeJZqgtzJ6GR3eqoYSW9b9UMvkBpZODSctWSNGj3P7jRFDO5VoTwCQAWbFnOjDfH5Ulgp2PKSQnSJP3AJLQNFNe7br1XbrhV//eO+t51mIpGSDCUv3E0DDFcWDTH9cXDTTlRZVEiR2BwpZOOkE/Z0/BVnhZYL71oZV34bKfWjQIt6V/isSMahdsAASACp4ZTGtwiVuNd9tybAgMBAAECggEBAKTmjaS6tkK8BlPXClTQ2vpz/N6uxDeS35mXpqasqskVlaAidgg/sWqpjXDbXr93otIMLlWsM+X0CqMDgSXKejLS2jx4GDjI1ZTXg++0AMJ8sJ74pWzVDOfmCEQ/7wXs3+cbnXhKriO8Z036q92Qc1+N87SI38nkGa0ABH9CN83HmQqt4fB7UdHzuIRe/me2PGhIq5ZBzj6h3BpoPGzEP+x3l9YmK8t/1cN0pqI+dQwYdgfGjackLu/2qH80MCF7IyQaseZUOJyKrCLtSD/Iixv/hzDEUPfOCjFDgTpzf3cwta8+oE4wHCo1iI1/4TlPkwmXx4qSXtmw4aQPz7IDQvECgYEA8KNThCO2gsC2I9PQDM/8Cw0O983WCDY+oi+7JPiNAJwv5DYBqEZB1QYdj06YD16XlC/HAZMsMku1na2TN0driwenQQWzoev3g2S7gRDoS/FCJSI3jJ+kjgtaA7Qmzlgk1TxODN+G1H91HW7t0l7VnL27IWyYo2qRRK3jzxqUiPUCgYEAx0oQs2reBQGMVZnApD1jeq7n4MvNLcPvt8b/eU9iUv6Y4Mj0Suo/AU8lYZXm8ubbqAlwz2VSVunD2tOplHyMUrtCtObAfVDUAhCndKaA9gApgfb3xw1IKbuQ1u4IF1FJl3VtumfQn//LiH1B3rXhcdyo3/vIttEk48RakUKClU8CgYEAzV7W3COOlDDcQd935DdtKBFRAPRPAlspQUnzMi5eSHMD/ISLDY5IiQHbIH83D4bvXq0X7qQoSBSNP7Dvv3HYuqMhf0DaegrlBuJllFVVq9qPVRnKxt1Il2HgxOBvbhOT+9in1BzA+YJ99UzC85O0Qz06A+CmtHEy4aZ2kj5hHjECgYEAmNS4+A8Fkss8Js1RieK2LniBxMgmYml3pfVLKGnzmng7H2+cwPLhPIzIuwytXywh2bzbsYEfYx3EoEVgMEpPhoarQnYPukrJO4gwE2o5Te6T5mJSZGlQJQj9q4ZB2Dfzet6INsK0oG8XVGXSpQvQh3RUYekCZQkBBFcpqWpbIEsCgYAnM3DQf3FJoSnXaMhrVBIovic5l0xFkEHskAjFTevO86Fsz1C2aSeRKSqGFoOQ0tmJzBEs1R6KqnHInicDTQrKhArgLXX4v3CddjfTRJkFWDbE/CkvKZNOrcf1nhaGCPspRJj2KUkj1Fhl9Cncdn/RsYEONbwQSjIfMPkvxF+8HQ=="
public-key: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu1SU1LfVLPHCozMxH2Mo4lgOEePzNm0tRgeLezV6ffAt0gunVTLw7onLRnrq0/IzW7yWR7QkrmBL7jTKEn5u+qKhbwKfBstIs+bMY2Zkp18gnTxKLxoS2tFczGkPLPgizskuemMghRniWaoLcyehkd3qqGElvW/VDL5AaWTg0nLVkjRo9z+40RQzuVaE8AkAFmxZzow3x+VJYKdjykkJ0iT9wCS0DRTXu269V264Vf/3jvredZiKRkgwlL9xNAwxXFg0x/XFw005UWVRIkdgcKWTjpBP2dPwVZ4WWC+9aGVd+Gyn1o0CLelf4rEjGoXbAAEgAqeGUxrcIlbjXfbcmwIDAQAB"

View File

@ -0,0 +1,35 @@
insert into instance(id, name, description, url, icon_url, shared_inbox, software, version, is_blocked, is_muted,
moderation_note, created_at)
VALUES (1, 'instance', 'description', 'https://example.com', 'https://example.com', 'https://example.com', 'software',
'version', false, false, 'note', current_timestamp)
, (2, 'instance', 'description', 'https://remote.example.com', 'https://example.com', 'https://remote.example.com',
'software',
'version', false, false, 'note', current_timestamp)
, (3, 'instance', 'description', 'https://remote2.example.com', 'https://example.com',
'https://remote2.example.com', 'software',
'version', false, false, 'note', current_timestamp);
insert into actors(id, name, domain, screen_name, description, inbox, outbox, url, public_key, private_key, created_at,
key_id, following, followers, instance, locked, following_count, followers_count, posts_count,
last_post_at, last_update_at, suspend, move_to, icon, banner)
VALUES (1, 'test', 'example.com', 'test-actor', 'actor_description', 'https://example.com/test/inbox',
'https://example.com/outbox', 'https://example.com/test', '---BEGIN PUBLIC KEY---', '---BEGIN PRIVATE KEY---',
current_timestamp, 'https://example.com/test#main-key', 'https://example.com/test/following',
'https://example.com/test/followers', 1, false, 1, 0, 0, null, current_timestamp, false, null, null, null),
(2, 'test', 'remote.example.com', 'test-actor', 'actor_description', 'https://remote.example.com/test/inbox',
'https://remote.example.com/outbox', 'https://remote.example.com', '---BEGIN PUBLIC KEY---',
'---BEGIN PRIVATE KEY---',
current_timestamp, 'https://remote.example.com/test#main-key', 'https://remote.example.com/test/following',
'https://remote.example.com/test/followers', 2, false, 1, 0, 0, null, current_timestamp, false, null, null,
null),
(3, 'test', 'remote2.example.com', 'test-actor', 'actor_description', 'https://remote2.example.com/test/inbox',
'https://remote2.example.com/test/outbox', 'https://remote2.example.com/test', '---BEGIN PUBLIC KEY---',
'---BEGIN PRIVATE KEY---',
current_timestamp, 'https://remote2.example.com/test#main-key', 'https://remote2.example.com/test/following',
'https://example.com/followers', 3, false, 1, 0, 0, null, current_timestamp, false, null, null, null),
(4, 'test2', 'remote2.example.com', 'test-actor', 'actor_description', 'https://example.com/inbox',
'https://remote2.example.com/test2/outbox', 'https://remote2.example.com/test2', '---BEGIN PUBLIC KEY---',
'---BEGIN PRIVATE KEY---',
current_timestamp, 'https://remote2.example.com/test2#main-key', 'https://remote2.example.com/test2/following',
'https://remote2.example.com/test2/followers', 3, false, 1, 0, 0, null, current_timestamp, false, null, null,
null);

View File

@ -0,0 +1,15 @@
insert into posts (id, actor_id, instance_id, overview, content, text, created_at, visibility, url, repost_id, reply_id,
sensitive, ap_id, deleted, hide, move_to)
values (1, 1, 1, null, 'content', 'text', current_timestamp, 'PUBLIC', 'https://example.com', null, null, false,
'https://example.com', false, false, null),
(2, 2, 2, null, 'content', 'text', current_timestamp, 'FOLLOWERS', 'https://example.com', null, null, false,
'https://example.com', false, false, null),
(3, 3, 1, null, 'content', 'text', current_timestamp, 'PUBLIC', 'https://example.com', null, null, false,
'https://example.com', false, false, null),
(4, 4, 1, null, 'content', 'text', current_timestamp, 'FOLLOWERS', 'https://example.com', null, null, false,
'https://example.com', false, false, null),
(5, 4, 1, null, 'content', 'text', current_timestamp, 'DIRECT', 'https://example.com', null, null, false,
'https://example.com', false, false, null);
insert into posts_visible_actors(post_id, actor_id)
VALUES (5, 2);

View File

@ -0,0 +1,5 @@
insert into relationships(id, actor_id, target_actor_id, following, blocking, muting, follow_requesting,
muting_follow_request)
VALUES (1, 1, 2, true, false, false, false, false),
(2, 2, 1, true, false, false, false, false),
(3, 1, 3, false, true, false, false, false);