mirror of https://github.com/usbharu/Hideout.git
Merge pull request #28 from usbharu/feature/refactor-query
Feature/refactor query
This commit is contained in:
commit
7a8c3c95ab
|
@ -12,22 +12,19 @@ import dev.usbharu.hideout.domain.model.job.DeliverReactionJob
|
||||||
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
|
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
|
||||||
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||||
import dev.usbharu.hideout.plugins.*
|
import dev.usbharu.hideout.plugins.*
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.routing.register
|
import dev.usbharu.hideout.routing.register
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.api.IPostApiService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
|
import dev.usbharu.hideout.service.api.WebFingerApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
import dev.usbharu.hideout.service.core.*
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
|
||||||
import dev.usbharu.hideout.service.core.IServerInitialiseService
|
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
|
||||||
import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
|
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import dev.usbharu.kjob.exposed.ExposedKJob
|
import dev.usbharu.kjob.exposed.ExposedKJob
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -79,7 +76,7 @@ fun Application.parent() {
|
||||||
level = LogLevel.INFO
|
level = LogLevel.INFO
|
||||||
}
|
}
|
||||||
install(httpSignaturePlugin) {
|
install(httpSignaturePlugin) {
|
||||||
keyMap = KtorKeyMap(get())
|
keyMap = KtorKeyMap(get(), get())
|
||||||
}
|
}
|
||||||
expectSuccess = true
|
expectSuccess = true
|
||||||
}
|
}
|
||||||
|
@ -95,6 +92,7 @@ fun Application.parent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configureKoin(module, HideoutModule().module)
|
configureKoin(module, HideoutModule().module)
|
||||||
|
configureStatusPages()
|
||||||
runBlocking {
|
runBlocking {
|
||||||
inject<IServerInitialiseService>().value.init()
|
inject<IServerInitialiseService>().value.init()
|
||||||
}
|
}
|
||||||
|
@ -103,7 +101,7 @@ fun Application.parent() {
|
||||||
configureStaticRouting()
|
configureStaticRouting()
|
||||||
configureMonitoring()
|
configureMonitoring()
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
register(inject<IUserService>().value)
|
register(inject<IUserApiService>().value)
|
||||||
configureSecurity(
|
configureSecurity(
|
||||||
|
|
||||||
inject<JwkProvider>().value,
|
inject<JwkProvider>().value,
|
||||||
|
@ -116,11 +114,11 @@ fun Application.parent() {
|
||||||
activityPubUserService = inject<ActivityPubUserService>().value,
|
activityPubUserService = inject<ActivityPubUserService>().value,
|
||||||
postService = inject<IPostApiService>().value,
|
postService = inject<IPostApiService>().value,
|
||||||
userApiService = inject<IUserApiService>().value,
|
userApiService = inject<IUserApiService>().value,
|
||||||
reactionService = inject<IReactionService>().value,
|
userQueryService = inject<UserQueryService>().value,
|
||||||
userAuthService = inject<IUserAuthService>().value,
|
followerQueryService = inject<FollowerQueryService>().value,
|
||||||
userRepository = inject<IUserRepository>().value,
|
userAuthApiService = inject<UserAuthApiService>().value,
|
||||||
jwtService = inject<IJwtService>().value,
|
webFingerApiService = inject<WebFingerApiService>().value,
|
||||||
metaService = inject<IMetaService>().value
|
transaction = inject<Transaction>().value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
|
class InvalidUsernameOrPasswordException : IllegalArgumentException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(s: String?) : super(s)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
|
@ -1,14 +1,8 @@
|
||||||
package dev.usbharu.hideout.exception
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
class NotInitException : Exception {
|
class NotInitException : IllegalStateException {
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
constructor(message: String?) : super(message)
|
constructor(s: String?) : super(s)
|
||||||
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
constructor(cause: Throwable?) : super(cause)
|
constructor(cause: Throwable?) : super(cause)
|
||||||
constructor(message: String?, cause: Throwable?, enableSuppression: Boolean, writableStackTrace: Boolean) : super(
|
|
||||||
message,
|
|
||||||
cause,
|
|
||||||
enableSuppression,
|
|
||||||
writableStackTrace
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
|
class UsernameAlreadyExistException : IllegalArgumentException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(s: String?) : super(s)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
|
@ -2,7 +2,8 @@ package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.user.UserAuthService
|
import dev.usbharu.hideout.service.user.UserAuthService
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -164,20 +165,22 @@ val httpSignaturePlugin = createClientPlugin("HttpSign", ::HttpSignaturePluginCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap {
|
class KtorKeyMap(private val userQueryService: UserQueryService, private val transaction: Transaction) : KeyMap {
|
||||||
override fun getPublicKey(keyId: String?): PublicKey = runBlocking {
|
override fun getPublicKey(keyId: String?): PublicKey = runBlocking {
|
||||||
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
||||||
.substringAfterLast("/")
|
.substringAfterLast("/")
|
||||||
val publicBytes = Base64.getDecoder().decode(
|
val publicBytes = Base64.getDecoder().decode(
|
||||||
userAuthRepository.findByNameAndDomain(
|
transaction.transaction {
|
||||||
|
userQueryService.findByNameAndDomain(
|
||||||
username,
|
username,
|
||||||
Config.configData.domain
|
Config.configData.domain
|
||||||
)?.run {
|
).run {
|
||||||
publicKey
|
publicKey
|
||||||
.replace("-----BEGIN PUBLIC KEY-----", "")
|
.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||||
.replace("-----END PUBLIC KEY-----", "")
|
.replace("-----END PUBLIC KEY-----", "")
|
||||||
.replace("\n", "")
|
.replace("\n", "")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
val x509EncodedKeySpec = X509EncodedKeySpec(publicBytes)
|
val x509EncodedKeySpec = X509EncodedKeySpec(publicBytes)
|
||||||
return@runBlocking KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec)
|
return@runBlocking KeyFactory.getInstance("RSA").generatePublic(x509EncodedKeySpec)
|
||||||
|
@ -187,14 +190,16 @@ class KtorKeyMap(private val userAuthRepository: IUserRepository) : KeyMap {
|
||||||
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
val username = (keyId ?: throw IllegalArgumentException("keyId is null")).substringBeforeLast("#pubkey")
|
||||||
.substringAfterLast("/")
|
.substringAfterLast("/")
|
||||||
val publicBytes = Base64.getDecoder().decode(
|
val publicBytes = Base64.getDecoder().decode(
|
||||||
userAuthRepository.findByNameAndDomain(
|
transaction.transaction {
|
||||||
|
userQueryService.findByNameAndDomain(
|
||||||
username,
|
username,
|
||||||
Config.configData.domain
|
Config.configData.domain
|
||||||
)?.privateKey?.run {
|
).privateKey?.run {
|
||||||
replace("-----BEGIN PRIVATE KEY-----", "")
|
replace("-----BEGIN PRIVATE KEY-----", "")
|
||||||
.replace("-----END PRIVATE KEY-----", "")
|
.replace("-----END PRIVATE KEY-----", "")
|
||||||
.replace("\n", "")
|
.replace("\n", "")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
val x509EncodedKeySpec = PKCS8EncodedKeySpec(publicBytes)
|
val x509EncodedKeySpec = PKCS8EncodedKeySpec(publicBytes)
|
||||||
return@runBlocking KeyFactory.getInstance("RSA").generatePrivate(x509EncodedKeySpec)
|
return@runBlocking KeyFactory.getInstance("RSA").generatePrivate(x509EncodedKeySpec)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.plugins
|
package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.routing.activitypub.inbox
|
import dev.usbharu.hideout.routing.activitypub.inbox
|
||||||
import dev.usbharu.hideout.routing.activitypub.outbox
|
import dev.usbharu.hideout.routing.activitypub.outbox
|
||||||
import dev.usbharu.hideout.routing.activitypub.usersAP
|
import dev.usbharu.hideout.routing.activitypub.usersAP
|
||||||
|
@ -12,11 +13,10 @@ import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.api.IPostApiService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
|
import dev.usbharu.hideout.service.api.WebFingerApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.plugins.autohead.*
|
import io.ktor.server.plugins.autohead.*
|
||||||
|
@ -30,22 +30,22 @@ fun Application.configureRouting(
|
||||||
activityPubUserService: ActivityPubUserService,
|
activityPubUserService: ActivityPubUserService,
|
||||||
postService: IPostApiService,
|
postService: IPostApiService,
|
||||||
userApiService: IUserApiService,
|
userApiService: IUserApiService,
|
||||||
reactionService: IReactionService,
|
userQueryService: UserQueryService,
|
||||||
userAuthService: IUserAuthService,
|
followerQueryService: FollowerQueryService,
|
||||||
userRepository: IUserRepository,
|
userAuthApiService: UserAuthApiService,
|
||||||
jwtService: IJwtService,
|
webFingerApiService: WebFingerApiService,
|
||||||
metaService: IMetaService
|
transaction: Transaction
|
||||||
) {
|
) {
|
||||||
install(AutoHeadResponse)
|
install(AutoHeadResponse)
|
||||||
routing {
|
routing {
|
||||||
inbox(httpSignatureVerifyService, activityPubService)
|
inbox(httpSignatureVerifyService, activityPubService)
|
||||||
outbox()
|
outbox()
|
||||||
usersAP(activityPubUserService, userService)
|
usersAP(activityPubUserService, userQueryService, followerQueryService, transaction)
|
||||||
webfinger(userService)
|
webfinger(webFingerApiService)
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, reactionService)
|
posts(postService)
|
||||||
users(userService, userApiService)
|
users(userService, userApiService)
|
||||||
auth(userAuthService, userRepository, jwtService)
|
auth(userAuthApiService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.plugins
|
package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.plugins.statuspages.*
|
import io.ktor.server.plugins.statuspages.*
|
||||||
|
@ -10,8 +11,12 @@ fun Application.configureStatusPages() {
|
||||||
exception<IllegalArgumentException> { call, cause ->
|
exception<IllegalArgumentException> { call, cause ->
|
||||||
call.respondText(text = "400: $cause", status = HttpStatusCode.BadRequest)
|
call.respondText(text = "400: $cause", status = HttpStatusCode.BadRequest)
|
||||||
}
|
}
|
||||||
|
exception<InvalidUsernameOrPasswordException> { call, _ ->
|
||||||
|
call.respond(HttpStatusCode.Unauthorized)
|
||||||
|
}
|
||||||
exception<Throwable> { call, cause ->
|
exception<Throwable> { call, cause ->
|
||||||
call.respondText(text = "500: $cause", status = HttpStatusCode.InternalServerError)
|
call.respondText(text = "500: ${cause.stackTraceToString()}", status = HttpStatusCode.InternalServerError)
|
||||||
|
cause.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
|
||||||
|
interface FollowerQueryService {
|
||||||
|
suspend fun findFollowersById(id: Long): List<User>
|
||||||
|
suspend fun findFollowersByNameAndDomain(name: String, domain: String): List<User>
|
||||||
|
suspend fun findFollowingById(id: Long): List<User>
|
||||||
|
suspend fun findFollowingByNameAndDomain(name: String, domain: String): List<User>
|
||||||
|
suspend fun appendFollower(user: Long, follower: Long)
|
||||||
|
suspend fun removeFollower(user: Long, follower: Long)
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
import dev.usbharu.hideout.repository.Users
|
||||||
|
import dev.usbharu.hideout.repository.UsersFollowers
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class FollowerQueryServiceImpl : FollowerQueryService {
|
||||||
|
override suspend fun findFollowersById(id: Long): List<User> {
|
||||||
|
val followers = Users.alias("FOLLOWERS")
|
||||||
|
return Users.innerJoin(
|
||||||
|
otherTable = UsersFollowers,
|
||||||
|
onColumn = { Users.id },
|
||||||
|
otherColumn = { userId }
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
otherTable = followers,
|
||||||
|
onColumn = { UsersFollowers.followerId },
|
||||||
|
otherColumn = { followers[Users.id] }
|
||||||
|
)
|
||||||
|
.slice(
|
||||||
|
followers[Users.id],
|
||||||
|
followers[Users.name],
|
||||||
|
followers[Users.domain],
|
||||||
|
followers[Users.screenName],
|
||||||
|
followers[Users.description],
|
||||||
|
followers[Users.password],
|
||||||
|
followers[Users.inbox],
|
||||||
|
followers[Users.outbox],
|
||||||
|
followers[Users.url],
|
||||||
|
followers[Users.publicKey],
|
||||||
|
followers[Users.privateKey],
|
||||||
|
followers[Users.createdAt]
|
||||||
|
)
|
||||||
|
.select { Users.id eq id }
|
||||||
|
.map {
|
||||||
|
User(
|
||||||
|
id = it[followers[Users.id]],
|
||||||
|
name = it[followers[Users.name]],
|
||||||
|
domain = it[followers[Users.domain]],
|
||||||
|
screenName = it[followers[Users.screenName]],
|
||||||
|
description = it[followers[Users.description]],
|
||||||
|
password = it[followers[Users.password]],
|
||||||
|
inbox = it[followers[Users.inbox]],
|
||||||
|
outbox = it[followers[Users.outbox]],
|
||||||
|
url = it[followers[Users.url]],
|
||||||
|
publicKey = it[followers[Users.publicKey]],
|
||||||
|
privateKey = it[followers[Users.privateKey]],
|
||||||
|
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findFollowersByNameAndDomain(name: String, domain: String): List<User> {
|
||||||
|
val followers = Users.alias("FOLLOWERS")
|
||||||
|
return Users.innerJoin(
|
||||||
|
otherTable = UsersFollowers,
|
||||||
|
onColumn = { Users.id },
|
||||||
|
otherColumn = { userId }
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
otherTable = followers,
|
||||||
|
onColumn = { UsersFollowers.followerId },
|
||||||
|
otherColumn = { followers[Users.id] }
|
||||||
|
)
|
||||||
|
.slice(
|
||||||
|
followers[Users.id],
|
||||||
|
followers[Users.name],
|
||||||
|
followers[Users.domain],
|
||||||
|
followers[Users.screenName],
|
||||||
|
followers[Users.description],
|
||||||
|
followers[Users.password],
|
||||||
|
followers[Users.inbox],
|
||||||
|
followers[Users.outbox],
|
||||||
|
followers[Users.url],
|
||||||
|
followers[Users.publicKey],
|
||||||
|
followers[Users.privateKey],
|
||||||
|
followers[Users.createdAt]
|
||||||
|
)
|
||||||
|
.select { Users.name eq name and (Users.domain eq domain) }
|
||||||
|
.map {
|
||||||
|
User(
|
||||||
|
id = it[followers[Users.id]],
|
||||||
|
name = it[followers[Users.name]],
|
||||||
|
domain = it[followers[Users.domain]],
|
||||||
|
screenName = it[followers[Users.screenName]],
|
||||||
|
description = it[followers[Users.description]],
|
||||||
|
password = it[followers[Users.password]],
|
||||||
|
inbox = it[followers[Users.inbox]],
|
||||||
|
outbox = it[followers[Users.outbox]],
|
||||||
|
url = it[followers[Users.url]],
|
||||||
|
publicKey = it[followers[Users.publicKey]],
|
||||||
|
privateKey = it[followers[Users.privateKey]],
|
||||||
|
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findFollowingById(id: Long): List<User> {
|
||||||
|
val followers = Users.alias("FOLLOWERS")
|
||||||
|
return Users.innerJoin(
|
||||||
|
otherTable = UsersFollowers,
|
||||||
|
onColumn = { Users.id },
|
||||||
|
otherColumn = { userId }
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
otherTable = followers,
|
||||||
|
onColumn = { UsersFollowers.followerId },
|
||||||
|
otherColumn = { followers[Users.id] }
|
||||||
|
)
|
||||||
|
.slice(
|
||||||
|
followers[Users.id],
|
||||||
|
followers[Users.name],
|
||||||
|
followers[Users.domain],
|
||||||
|
followers[Users.screenName],
|
||||||
|
followers[Users.description],
|
||||||
|
followers[Users.password],
|
||||||
|
followers[Users.inbox],
|
||||||
|
followers[Users.outbox],
|
||||||
|
followers[Users.url],
|
||||||
|
followers[Users.publicKey],
|
||||||
|
followers[Users.privateKey],
|
||||||
|
followers[Users.createdAt]
|
||||||
|
)
|
||||||
|
.select { followers[Users.id] eq id }
|
||||||
|
.map {
|
||||||
|
User(
|
||||||
|
id = it[followers[Users.id]],
|
||||||
|
name = it[followers[Users.name]],
|
||||||
|
domain = it[followers[Users.domain]],
|
||||||
|
screenName = it[followers[Users.screenName]],
|
||||||
|
description = it[followers[Users.description]],
|
||||||
|
password = it[followers[Users.password]],
|
||||||
|
inbox = it[followers[Users.inbox]],
|
||||||
|
outbox = it[followers[Users.outbox]],
|
||||||
|
url = it[followers[Users.url]],
|
||||||
|
publicKey = it[followers[Users.publicKey]],
|
||||||
|
privateKey = it[followers[Users.privateKey]],
|
||||||
|
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findFollowingByNameAndDomain(name: String, domain: String): List<User> {
|
||||||
|
val followers = Users.alias("FOLLOWERS")
|
||||||
|
return Users.innerJoin(
|
||||||
|
otherTable = UsersFollowers,
|
||||||
|
onColumn = { Users.id },
|
||||||
|
otherColumn = { userId }
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
otherTable = followers,
|
||||||
|
onColumn = { UsersFollowers.followerId },
|
||||||
|
otherColumn = { followers[Users.id] }
|
||||||
|
)
|
||||||
|
.slice(
|
||||||
|
followers[Users.id],
|
||||||
|
followers[Users.name],
|
||||||
|
followers[Users.domain],
|
||||||
|
followers[Users.screenName],
|
||||||
|
followers[Users.description],
|
||||||
|
followers[Users.password],
|
||||||
|
followers[Users.inbox],
|
||||||
|
followers[Users.outbox],
|
||||||
|
followers[Users.url],
|
||||||
|
followers[Users.publicKey],
|
||||||
|
followers[Users.privateKey],
|
||||||
|
followers[Users.createdAt]
|
||||||
|
)
|
||||||
|
.select { followers[Users.name] eq name and (followers[Users.domain] eq domain) }
|
||||||
|
.map {
|
||||||
|
User(
|
||||||
|
id = it[followers[Users.id]],
|
||||||
|
name = it[followers[Users.name]],
|
||||||
|
domain = it[followers[Users.domain]],
|
||||||
|
screenName = it[followers[Users.screenName]],
|
||||||
|
description = it[followers[Users.description]],
|
||||||
|
password = it[followers[Users.password]],
|
||||||
|
inbox = it[followers[Users.inbox]],
|
||||||
|
outbox = it[followers[Users.outbox]],
|
||||||
|
url = it[followers[Users.url]],
|
||||||
|
publicKey = it[followers[Users.publicKey]],
|
||||||
|
privateKey = it[followers[Users.privateKey]],
|
||||||
|
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun appendFollower(user: Long, follower: Long) {
|
||||||
|
UsersFollowers.insert {
|
||||||
|
it[userId] = user
|
||||||
|
it[followerId] = follower
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun removeFollower(user: Long, follower: Long) {
|
||||||
|
UsersFollowers.deleteWhere { Users.id eq user and (followerId eq follower) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
||||||
|
|
||||||
|
interface JwtRefreshTokenQueryService {
|
||||||
|
suspend fun findById(id: Long): JwtRefreshToken
|
||||||
|
suspend fun findByToken(token: String): JwtRefreshToken
|
||||||
|
suspend fun findByUserId(userId: Long): JwtRefreshToken
|
||||||
|
suspend fun deleteById(id: Long)
|
||||||
|
suspend fun deleteByToken(token: String)
|
||||||
|
suspend fun deleteByUserId(userId: Long)
|
||||||
|
suspend fun deleteAll()
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
||||||
|
import dev.usbharu.hideout.repository.JwtRefreshTokens
|
||||||
|
import dev.usbharu.hideout.repository.toJwtRefreshToken
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.jetbrains.exposed.sql.deleteAll
|
||||||
|
import org.jetbrains.exposed.sql.deleteWhere
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class JwtRefreshTokenQueryServiceImpl : JwtRefreshTokenQueryService {
|
||||||
|
override suspend fun findById(id: Long): JwtRefreshToken =
|
||||||
|
JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }.single().toJwtRefreshToken()
|
||||||
|
|
||||||
|
override suspend fun findByToken(token: String): JwtRefreshToken =
|
||||||
|
JwtRefreshTokens.select { JwtRefreshTokens.refreshToken.eq(token) }.single().toJwtRefreshToken()
|
||||||
|
|
||||||
|
override suspend fun findByUserId(userId: Long): JwtRefreshToken =
|
||||||
|
JwtRefreshTokens.select { JwtRefreshTokens.userId.eq(userId) }.single().toJwtRefreshToken()
|
||||||
|
|
||||||
|
override suspend fun deleteById(id: Long) {
|
||||||
|
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.id eq id }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteByToken(token: String) {
|
||||||
|
JwtRefreshTokens.deleteWhere { refreshToken eq token }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteByUserId(userId: Long) {
|
||||||
|
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.userId eq userId }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteAll() {
|
||||||
|
JwtRefreshTokens.deleteAll()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
|
||||||
|
interface PostQueryService {
|
||||||
|
suspend fun findById(id: Long): Post
|
||||||
|
suspend fun findByUrl(url: String): Post
|
||||||
|
suspend fun findByApId(string: String): Post
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
import dev.usbharu.hideout.repository.Posts
|
||||||
|
import dev.usbharu.hideout.repository.toPost
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class PostQueryServiceImpl : PostQueryService {
|
||||||
|
override suspend fun findById(id: Long): Post = Posts.select { Posts.id eq id }.single().toPost()
|
||||||
|
|
||||||
|
override suspend fun findByUrl(url: String): Post = Posts.select { Posts.url eq url }.single().toPost()
|
||||||
|
|
||||||
|
override suspend fun findByApId(string: String): Post = Posts.select { Posts.apId eq string }.single().toPost()
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
interface PostResponseQueryService {
|
||||||
|
suspend fun findById(id: Long, userId: Long?): PostResponse
|
||||||
|
suspend fun findAll(
|
||||||
|
since: Long? = null,
|
||||||
|
until: Long? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
maxId: Long? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
userId: Long? = null
|
||||||
|
): List<PostResponse>
|
||||||
|
|
||||||
|
suspend fun findByUserId(
|
||||||
|
userId: Long,
|
||||||
|
since: Long? = null,
|
||||||
|
until: Long? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
maxId: Long? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
userId2: Long? = null
|
||||||
|
): List<PostResponse>
|
||||||
|
|
||||||
|
suspend fun findByUserNameAndUserDomain(
|
||||||
|
name: String,
|
||||||
|
domain: String,
|
||||||
|
since: Long? = null,
|
||||||
|
until: Long? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
maxId: Long? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
userId: Long? = null
|
||||||
|
): List<PostResponse>
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||||
|
import dev.usbharu.hideout.repository.Posts
|
||||||
|
import dev.usbharu.hideout.repository.Users
|
||||||
|
import dev.usbharu.hideout.repository.toPost
|
||||||
|
import dev.usbharu.hideout.repository.toUser
|
||||||
|
import org.jetbrains.exposed.sql.and
|
||||||
|
import org.jetbrains.exposed.sql.innerJoin
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class PostResponseQueryServiceImpl : PostResponseQueryService {
|
||||||
|
override suspend fun findById(id: Long, userId: Long?): PostResponse {
|
||||||
|
return Posts
|
||||||
|
.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { Users.id })
|
||||||
|
.select { Posts.id eq id }
|
||||||
|
.single()
|
||||||
|
.let { PostResponse.from(it.toPost(), it.toUser()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findAll(
|
||||||
|
since: Long?,
|
||||||
|
until: Long?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<PostResponse> {
|
||||||
|
return Posts
|
||||||
|
.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id })
|
||||||
|
.selectAll()
|
||||||
|
.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUserId(
|
||||||
|
userId: Long,
|
||||||
|
since: Long?,
|
||||||
|
until: Long?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId2: Long?
|
||||||
|
): List<PostResponse> {
|
||||||
|
return Posts
|
||||||
|
.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id })
|
||||||
|
.select { Posts.userId eq userId }
|
||||||
|
.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUserNameAndUserDomain(
|
||||||
|
name: String,
|
||||||
|
domain: String,
|
||||||
|
since: Long?,
|
||||||
|
until: Long?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<PostResponse> {
|
||||||
|
return Posts
|
||||||
|
.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id })
|
||||||
|
.select { Users.name eq name and (Users.domain eq domain) }
|
||||||
|
.map { PostResponse.from(it.toPost(), it.toUser()) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
|
|
||||||
|
interface ReactionQueryService {
|
||||||
|
suspend fun findByPostId(postId: Long, userId: Long? = null): List<Reaction>
|
||||||
|
|
||||||
|
@Suppress("FunctionMaxLength")
|
||||||
|
suspend fun findByPostIdAndUserIdAndEmojiId(postId: Long, userId: Long, emojiId: Long): Reaction
|
||||||
|
|
||||||
|
suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean
|
||||||
|
|
||||||
|
suspend fun deleteByPostIdAndUserId(postId: Long, userId: Long)
|
||||||
|
|
||||||
|
suspend fun findByPostIdWithUsers(postId: Long, userId: Long? = null): List<ReactionResponse>
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.Account
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
|
import dev.usbharu.hideout.repository.Reactions
|
||||||
|
import dev.usbharu.hideout.repository.Users
|
||||||
|
import dev.usbharu.hideout.repository.toReaction
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class ReactionQueryServiceImpl : ReactionQueryService {
|
||||||
|
override suspend fun findByPostId(postId: Long, userId: Long?): List<Reaction> {
|
||||||
|
return Reactions.select {
|
||||||
|
Reactions.postId.eq(postId)
|
||||||
|
}.map { it.toReaction() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("FunctionMaxLength")
|
||||||
|
override suspend fun findByPostIdAndUserIdAndEmojiId(postId: Long, userId: Long, emojiId: Long): Reaction {
|
||||||
|
return Reactions
|
||||||
|
.select {
|
||||||
|
Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and(
|
||||||
|
Reactions.emojiId.eq(emojiId)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.single()
|
||||||
|
.toReaction()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean {
|
||||||
|
return Reactions.select {
|
||||||
|
Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and(
|
||||||
|
Reactions.emojiId.eq(emojiId)
|
||||||
|
)
|
||||||
|
}.empty().not()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun deleteByPostIdAndUserId(postId: Long, userId: Long) {
|
||||||
|
Reactions.deleteWhere { Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByPostIdWithUsers(postId: Long, userId: Long?): List<ReactionResponse> {
|
||||||
|
return Reactions
|
||||||
|
.leftJoin(Users, onColumn = { Reactions.userId }, otherColumn = { id })
|
||||||
|
.select { Reactions.postId.eq(postId) }
|
||||||
|
.groupBy { _: ResultRow -> ReactionResponse("❤", true, "", listOf()) }
|
||||||
|
.map { entry: Map.Entry<ReactionResponse, List<ResultRow>> ->
|
||||||
|
entry.key.copy(accounts = entry.value.map { Account(it[Users.screenName], "", it[Users.url]) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
|
||||||
|
interface UserQueryService {
|
||||||
|
suspend fun findAll(limit: Int, offset: Long): List<User>
|
||||||
|
suspend fun findById(id: Long): User
|
||||||
|
suspend fun findByName(name: String): List<User>
|
||||||
|
suspend fun findByNameAndDomain(name: String, domain: String): User
|
||||||
|
suspend fun findByUrl(url: String): User
|
||||||
|
suspend fun findByIds(ids: List<Long>): List<User>
|
||||||
|
suspend fun existByNameAndDomain(name: String, domain: String): Boolean
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package dev.usbharu.hideout.query
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
import dev.usbharu.hideout.repository.Users
|
||||||
|
import dev.usbharu.hideout.repository.toUser
|
||||||
|
import org.jetbrains.exposed.sql.and
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.selectAll
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class UserQueryServiceImpl : UserQueryService {
|
||||||
|
override suspend fun findAll(limit: Int, offset: Long): List<User> =
|
||||||
|
Users.selectAll().limit(limit, offset).map { it.toUser() }
|
||||||
|
|
||||||
|
override suspend fun findById(id: Long): User = Users.select { Users.id eq id }.single().toUser()
|
||||||
|
|
||||||
|
override suspend fun findByName(name: String): List<User> = Users.select { Users.name eq name }.map { it.toUser() }
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomain(name: String, domain: String): User =
|
||||||
|
Users.select { Users.name eq name and (Users.domain eq domain) }.single().toUser()
|
||||||
|
|
||||||
|
override suspend fun findByUrl(url: String): User = Users.select { Users.url eq url }.single().toUser()
|
||||||
|
|
||||||
|
override suspend fun findByIds(ids: List<Long>): List<User> =
|
||||||
|
Users.select { Users.id inList ids }.map { it.toUser() }
|
||||||
|
|
||||||
|
override suspend fun existByNameAndDomain(name: String, domain: String): Boolean =
|
||||||
|
Users.select { Users.name eq name and (Users.domain eq domain) }.empty().not()
|
||||||
|
}
|
|
@ -8,13 +8,6 @@ interface IJwtRefreshTokenRepository {
|
||||||
suspend fun save(token: JwtRefreshToken)
|
suspend fun save(token: JwtRefreshToken)
|
||||||
|
|
||||||
suspend fun findById(id: Long): JwtRefreshToken?
|
suspend fun findById(id: Long): JwtRefreshToken?
|
||||||
suspend fun findByToken(token: String): JwtRefreshToken?
|
|
||||||
suspend fun findByUserId(userId: Long): JwtRefreshToken?
|
|
||||||
|
|
||||||
suspend fun delete(token: JwtRefreshToken)
|
suspend fun delete(token: JwtRefreshToken)
|
||||||
suspend fun deleteById(id: Long)
|
|
||||||
suspend fun deleteByToken(token: String)
|
|
||||||
suspend fun deleteByUserId(userId: Long)
|
|
||||||
|
|
||||||
suspend fun deleteAll()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,11 @@
|
||||||
package dev.usbharu.hideout.repository
|
package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
interface IPostRepository {
|
interface IPostRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(post: Post): Post
|
suspend fun save(post: Post): Post
|
||||||
suspend fun findOneById(id: Long, userId: Long? = null): Post?
|
|
||||||
suspend fun findByUrl(url: String): Post?
|
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
suspend fun findAll(
|
suspend fun findById(id: Long): Post
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun findByUserNameAndDomain(
|
|
||||||
username: String,
|
|
||||||
s: String,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun findByUserId(
|
|
||||||
idOrNull: Long,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun findByApId(id: String): Post?
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,35 +8,10 @@ interface IUserRepository {
|
||||||
|
|
||||||
suspend fun findById(id: Long): User?
|
suspend fun findById(id: Long): User?
|
||||||
|
|
||||||
suspend fun findByIds(ids: List<Long>): List<User>
|
|
||||||
|
|
||||||
suspend fun findByName(name: String): List<User>
|
|
||||||
|
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String): User?
|
|
||||||
|
|
||||||
suspend fun findByDomain(domain: String): List<User>
|
|
||||||
|
|
||||||
suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User>
|
|
||||||
|
|
||||||
suspend fun findByUrl(url: String): User?
|
|
||||||
|
|
||||||
suspend fun findByUrls(urls: List<String>): List<User>
|
|
||||||
|
|
||||||
@Deprecated("", ReplaceWith("save(userEntity)"))
|
|
||||||
suspend fun update(userEntity: User) = save(userEntity)
|
|
||||||
|
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
|
|
||||||
suspend fun findAll(): List<User>
|
|
||||||
|
|
||||||
suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long = 0): List<User>
|
|
||||||
|
|
||||||
suspend fun createFollower(id: Long, follower: Long)
|
|
||||||
suspend fun deleteFollower(id: Long, follower: Long)
|
|
||||||
suspend fun findFollowersById(id: Long): List<User>
|
|
||||||
|
|
||||||
suspend fun addFollowRequest(id: Long, follower: Long)
|
|
||||||
suspend fun deleteFollowRequest(id: Long, follower: Long)
|
suspend fun deleteFollowRequest(id: Long, follower: Long)
|
||||||
|
|
||||||
suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean
|
suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean
|
||||||
|
|
||||||
suspend fun nextId(): Long
|
suspend fun nextId(): Long
|
||||||
|
|
|
@ -2,10 +2,8 @@ package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
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.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -24,14 +22,9 @@ class JwtRefreshTokenRepositoryImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
override suspend fun save(token: JwtRefreshToken) {
|
override suspend fun save(token: JwtRefreshToken) {
|
||||||
query {
|
|
||||||
if (JwtRefreshTokens.select { JwtRefreshTokens.id.eq(token.id) }.empty()) {
|
if (JwtRefreshTokens.select { JwtRefreshTokens.id.eq(token.id) }.empty()) {
|
||||||
JwtRefreshTokens.insert {
|
JwtRefreshTokens.insert {
|
||||||
it[id] = token.id
|
it[id] = token.id
|
||||||
|
@ -49,57 +42,15 @@ class JwtRefreshTokenRepositoryImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findById(id: Long): JwtRefreshToken? {
|
override suspend fun findById(id: Long): JwtRefreshToken? =
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }.singleOrNull()?.toJwtRefreshToken()
|
JwtRefreshTokens.select { JwtRefreshTokens.id.eq(id) }.singleOrNull()?.toJwtRefreshToken()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByToken(token: String): JwtRefreshToken? {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.select { JwtRefreshTokens.refreshToken.eq(token) }.singleOrNull()?.toJwtRefreshToken()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUserId(userId: Long): JwtRefreshToken? {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.select { JwtRefreshTokens.userId.eq(userId) }.singleOrNull()?.toJwtRefreshToken()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(token: JwtRefreshToken) {
|
override suspend fun delete(token: JwtRefreshToken) {
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.deleteWhere { id eq token.id }
|
JwtRefreshTokens.deleteWhere { id eq token.id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteById(id: Long) {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.id eq id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteByToken(token: String) {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.deleteWhere { refreshToken eq token }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteByUserId(userId: Long) {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.deleteWhere { JwtRefreshTokens.userId eq userId }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteAll() {
|
|
||||||
return query {
|
|
||||||
JwtRefreshTokens.deleteAll()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ResultRow.toJwtRefreshToken(): JwtRefreshToken {
|
fun ResultRow.toJwtRefreshToken(): JwtRefreshToken {
|
||||||
return JwtRefreshToken(
|
return JwtRefreshToken(
|
||||||
this[JwtRefreshTokens.id],
|
this[JwtRefreshTokens.id],
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package dev.usbharu.hideout.repository
|
package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
|
import dev.usbharu.hideout.domain.model.hideout.entity.Jwt
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -18,12 +16,7 @@ class MetaRepositoryImpl(private val database: Database) : IMetaRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
override suspend fun save(meta: dev.usbharu.hideout.domain.model.hideout.entity.Meta) {
|
override suspend fun save(meta: dev.usbharu.hideout.domain.model.hideout.entity.Meta) {
|
||||||
return query {
|
|
||||||
if (Meta.select { Meta.id eq 1 }.empty()) {
|
if (Meta.select { Meta.id eq 1 }.empty()) {
|
||||||
Meta.insert {
|
Meta.insert {
|
||||||
it[id] = 1
|
it[id] = 1
|
||||||
|
@ -41,11 +34,9 @@ class MetaRepositoryImpl(private val database: Database) : IMetaRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun get(): dev.usbharu.hideout.domain.model.hideout.entity.Meta? {
|
override suspend fun get(): dev.usbharu.hideout.domain.model.hideout.entity.Meta? {
|
||||||
return query {
|
return Meta.select { Meta.id eq 1 }.singleOrNull()?.let {
|
||||||
Meta.select { Meta.id eq 1 }.singleOrNull()?.let {
|
|
||||||
dev.usbharu.hideout.domain.model.hideout.entity.Meta(
|
dev.usbharu.hideout.domain.model.hideout.entity.Meta(
|
||||||
it[Meta.version],
|
it[Meta.version],
|
||||||
Jwt(UUID.fromString(it[Meta.kid]), it[Meta.jwtPrivateKey], it[Meta.jwtPublicKey])
|
Jwt(UUID.fromString(it[Meta.kid]), it[Meta.jwtPrivateKey], it[Meta.jwtPublicKey])
|
||||||
|
@ -53,7 +44,6 @@ class MetaRepositoryImpl(private val database: Database) : IMetaRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
object Meta : Table("meta_info") {
|
object Meta : Table("meta_info") {
|
||||||
val id = long("id")
|
val id = long("id")
|
||||||
|
|
|
@ -3,13 +3,10 @@ package dev.usbharu.hideout.repository
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
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.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : IPostRepository {
|
class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : IPostRepository {
|
||||||
|
@ -23,12 +20,7 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
||||||
|
|
||||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
override suspend fun save(post: Post): Post {
|
override suspend fun save(post: Post): Post {
|
||||||
return query {
|
|
||||||
val singleOrNull = Posts.select { Posts.id eq post.id }.singleOrNull()
|
val singleOrNull = Posts.select { Posts.id eq post.id }.singleOrNull()
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
Posts.insert {
|
Posts.insert {
|
||||||
|
@ -58,73 +50,16 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
||||||
it[apId] = post.apId
|
it[apId] = post.apId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@query post
|
return post
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findOneById(id: Long, userId: Long?): Post? {
|
override suspend fun findById(id: Long): Post = Posts.select { Posts.id eq id }.single().toPost()
|
||||||
return query {
|
|
||||||
Posts.select { Posts.id eq id }.singleOrNull()?.toPost()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): Post? {
|
|
||||||
return query {
|
|
||||||
Posts.select { Posts.url eq url }.singleOrNull()?.toPost()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
override suspend fun delete(id: Long) {
|
||||||
return query {
|
|
||||||
Posts.deleteWhere { Posts.id eq id }
|
Posts.deleteWhere { Posts.id eq id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findAll(
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
return query {
|
|
||||||
Posts.select { Posts.visibility eq Visibility.PUBLIC.ordinal }.map { it.toPost() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUserNameAndDomain(
|
|
||||||
username: String,
|
|
||||||
s: String,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUserId(
|
|
||||||
idOrNull: Long,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByApId(id: String): Post? {
|
|
||||||
return query {
|
|
||||||
Posts.select { Posts.apId eq id }.singleOrNull()?.toPost()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object Posts : Table() {
|
object Posts : Table() {
|
||||||
val id = long("id")
|
val id = long("id")
|
||||||
val userId = long("userId").references(Users.id)
|
val userId = long("userId").references(Users.id)
|
||||||
|
|
|
@ -5,11 +5,5 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
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 reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean
|
|
||||||
suspend fun findByPostId(postId: Long): List<Reaction>
|
|
||||||
suspend fun delete(reaction: Reaction): Reaction
|
suspend fun delete(reaction: Reaction): Reaction
|
||||||
suspend fun deleteById(id: Long)
|
|
||||||
suspend fun deleteByPostId(postId: Long)
|
|
||||||
suspend fun deleteByUserId(userId: Long)
|
|
||||||
suspend fun deleteByPostIdAndUserId(postId: Long, userId: Long)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,9 @@ package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
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.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@ -23,14 +21,9 @@ class ReactionRepositoryImpl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
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 }.empty()) {
|
||||||
Reactions.insert {
|
Reactions.insert {
|
||||||
it[id] = reaction.id
|
it[id] = reaction.id
|
||||||
|
@ -45,63 +38,18 @@ class ReactionRepositoryImpl(
|
||||||
it[userId] = reaction.userId
|
it[userId] = reaction.userId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return reaction
|
return reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun reactionAlreadyExist(postId: Long, userId: Long, emojiId: Long): Boolean {
|
|
||||||
return query {
|
|
||||||
Reactions.select {
|
|
||||||
Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)).and(
|
|
||||||
Reactions.emojiId.eq(emojiId)
|
|
||||||
)
|
|
||||||
}.empty().not()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByPostId(postId: Long): List<Reaction> {
|
|
||||||
return query {
|
|
||||||
Reactions.select {
|
|
||||||
Reactions.postId.eq(postId)
|
|
||||||
}.map { it.toReaction() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(postId.eq(reaction.postId))
|
||||||
.and(userId.eq(reaction.postId))
|
.and(userId.eq(reaction.postId))
|
||||||
.and(emojiId.eq(reaction.emojiId))
|
.and(emojiId.eq(reaction.emojiId))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return reaction
|
return reaction
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deleteById(id: Long) {
|
|
||||||
query {
|
|
||||||
Reactions.deleteWhere { Reactions.id.eq(id) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteByPostId(postId: Long) {
|
|
||||||
query {
|
|
||||||
Reactions.deleteWhere { Reactions.postId.eq(postId) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteByUserId(userId: Long) {
|
|
||||||
query {
|
|
||||||
Reactions.deleteWhere { Reactions.userId.eq(userId) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteByPostIdAndUserId(postId: Long, userId: Long) {
|
|
||||||
query {
|
|
||||||
Reactions.deleteWhere { Reactions.postId.eq(postId).and(Reactions.userId.eq(userId)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResultRow.toReaction(): Reaction {
|
fun ResultRow.toReaction(): Reaction {
|
||||||
|
|
|
@ -2,11 +2,9 @@ package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
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.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
@ -25,12 +23,7 @@ class UserRepository(private val database: Database, private val idGenerateServi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
override suspend fun save(user: User): User {
|
override suspend fun save(user: User): User {
|
||||||
return query {
|
|
||||||
val singleOrNull = Users.select { Users.id eq user.id }.singleOrNull()
|
val singleOrNull = Users.select { Users.id eq user.id }.singleOrNull()
|
||||||
if (singleOrNull == null) {
|
if (singleOrNull == null) {
|
||||||
Users.insert {
|
Users.insert {
|
||||||
|
@ -62,171 +55,27 @@ class UserRepository(private val database: Database, private val idGenerateServi
|
||||||
it[privateKey] = user.privateKey
|
it[privateKey] = user.privateKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return@query user
|
return user
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun createFollower(id: Long, follower: Long) {
|
|
||||||
return query {
|
|
||||||
UsersFollowers.insert {
|
|
||||||
it[userId] = id
|
|
||||||
it[followerId] = follower
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findById(id: Long): User? {
|
override suspend fun findById(id: Long): User? {
|
||||||
return query {
|
return Users.select { Users.id eq id }.map {
|
||||||
Users.select { Users.id eq id }.map {
|
|
||||||
it.toUser()
|
it.toUser()
|
||||||
}.singleOrNull()
|
}.singleOrNull()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.id inList ids }.map {
|
|
||||||
it.toUser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByName(name: String): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.name eq name }.map {
|
|
||||||
it.toUser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): User? {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.name eq name and (Users.domain eq domain) }.singleOrNull()?.toUser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByDomain(domain: String): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.domain eq domain }.map {
|
|
||||||
it.toUser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> {
|
|
||||||
return query {
|
|
||||||
val selectAll = Users.selectAll()
|
|
||||||
names.forEach { (name, domain) ->
|
|
||||||
selectAll.orWhere { Users.name eq name and (Users.domain eq domain) }
|
|
||||||
}
|
|
||||||
selectAll.map { it.toUser() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): User? {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.url eq url }.singleOrNull()?.toUser()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrls(urls: List<String>): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.select { Users.url inList urls }.map { it.toUser() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowersById(id: Long): List<User> {
|
|
||||||
return query {
|
|
||||||
val followers = Users.alias("FOLLOWERS")
|
|
||||||
Users.innerJoin(
|
|
||||||
otherTable = UsersFollowers,
|
|
||||||
onColumn = { Users.id },
|
|
||||||
otherColumn = { userId }
|
|
||||||
)
|
|
||||||
.innerJoin(
|
|
||||||
otherTable = followers,
|
|
||||||
onColumn = { UsersFollowers.followerId },
|
|
||||||
otherColumn = { followers[Users.id] }
|
|
||||||
)
|
|
||||||
.slice(
|
|
||||||
followers.get(Users.id),
|
|
||||||
followers.get(Users.name),
|
|
||||||
followers.get(Users.domain),
|
|
||||||
followers.get(Users.screenName),
|
|
||||||
followers.get(Users.description),
|
|
||||||
followers.get(Users.password),
|
|
||||||
followers.get(Users.inbox),
|
|
||||||
followers.get(Users.outbox),
|
|
||||||
followers.get(Users.url),
|
|
||||||
followers.get(Users.publicKey),
|
|
||||||
followers.get(Users.privateKey),
|
|
||||||
followers.get(Users.createdAt)
|
|
||||||
)
|
|
||||||
.select { Users.id eq id }
|
|
||||||
.map {
|
|
||||||
User(
|
|
||||||
id = it[followers[Users.id]],
|
|
||||||
name = it[followers[Users.name]],
|
|
||||||
domain = it[followers[Users.domain]],
|
|
||||||
screenName = it[followers[Users.screenName]],
|
|
||||||
description = it[followers[Users.description]],
|
|
||||||
password = it[followers[Users.password]],
|
|
||||||
inbox = it[followers[Users.inbox]],
|
|
||||||
outbox = it[followers[Users.outbox]],
|
|
||||||
url = it[followers[Users.url]],
|
|
||||||
publicKey = it[followers[Users.publicKey]],
|
|
||||||
privateKey = it[followers[Users.privateKey]],
|
|
||||||
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun addFollowRequest(id: Long, follower: Long) {
|
|
||||||
query {
|
|
||||||
FollowRequests.insert {
|
|
||||||
it[userId] = id
|
|
||||||
it[followerId] = follower
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollowRequest(id: Long, follower: Long) {
|
override suspend fun deleteFollowRequest(id: Long, follower: Long) {
|
||||||
query {
|
|
||||||
FollowRequests.deleteWhere { userId.eq(id) and followerId.eq(follower) }
|
FollowRequests.deleteWhere { userId.eq(id) and followerId.eq(follower) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean {
|
override suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean {
|
||||||
return query {
|
return FollowRequests.select { (FollowRequests.userId eq id) and (FollowRequests.followerId eq follower) }
|
||||||
FollowRequests.select { (FollowRequests.userId eq id) and (FollowRequests.followerId eq follower) }
|
|
||||||
.singleOrNull() != null
|
.singleOrNull() != null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
override suspend fun delete(id: Long) {
|
||||||
query {
|
|
||||||
Users.deleteWhere { Users.id.eq(id) }
|
Users.deleteWhere { Users.id.eq(id) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollower(id: Long, follower: Long) {
|
|
||||||
query {
|
|
||||||
UsersFollowers.deleteWhere { (userId eq id).and(followerId eq follower) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAll(): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.selectAll().map { it.toUser() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long): List<User> {
|
|
||||||
return query {
|
|
||||||
Users.selectAll().limit(limit, offset).map { it.toUser() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun nextId(): Long = idGenerateService.generateId()
|
override suspend fun nextId(): Long = idGenerateService.generateId()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package dev.usbharu.hideout.routing
|
package dev.usbharu.hideout.routing
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
|
@ -9,7 +8,7 @@ import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
fun Application.register(userService: IUserService) {
|
fun Application.register(userApiService: IUserApiService) {
|
||||||
routing {
|
routing {
|
||||||
get("/register") {
|
get("/register") {
|
||||||
val principal = call.principal<UserIdPrincipal>()
|
val principal = call.principal<UserIdPrincipal>()
|
||||||
|
@ -37,10 +36,7 @@ fun Application.register(userService: IUserService) {
|
||||||
val parameters = call.receiveParameters()
|
val parameters = call.receiveParameters()
|
||||||
val password = parameters["password"] ?: return@post call.respondRedirect("/register")
|
val password = parameters["password"] ?: return@post call.respondRedirect("/register")
|
||||||
val username = parameters["username"] ?: return@post call.respondRedirect("/register")
|
val username = parameters["username"] ?: return@post call.respondRedirect("/register")
|
||||||
if (userService.usernameAlreadyUse(username)) {
|
userApiService.createUser(username, password)
|
||||||
return@post call.respondRedirect("/register")
|
|
||||||
}
|
|
||||||
userService.createLocalUser(UserCreateDto(username, username, "", password))
|
|
||||||
call.respondRedirect("/users/$username")
|
call.respondRedirect("/users/$username")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package dev.usbharu.hideout.routing.activitypub
|
package dev.usbharu.hideout.routing.activitypub
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.exception.ParameterNotExistException
|
import dev.usbharu.hideout.exception.ParameterNotExistException
|
||||||
import dev.usbharu.hideout.plugins.respondAp
|
import dev.usbharu.hideout.plugins.respondAp
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
import dev.usbharu.hideout.util.HttpUtil.JsonLd
|
import dev.usbharu.hideout.util.HttpUtil.JsonLd
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
@ -12,7 +15,12 @@ import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
fun Routing.usersAP(activityPubUserService: ActivityPubUserService, userService: IUserService) {
|
fun Routing.usersAP(
|
||||||
|
activityPubUserService: ActivityPubUserService,
|
||||||
|
userQueryService: UserQueryService,
|
||||||
|
followerQueryService: FollowerQueryService,
|
||||||
|
transaction: Transaction
|
||||||
|
) {
|
||||||
route("/users/{name}") {
|
route("/users/{name}") {
|
||||||
createChild(ContentTypeRouteSelector(ContentType.Application.Activity, ContentType.Application.JsonLd)).handle {
|
createChild(ContentTypeRouteSelector(ContentType.Application.Activity, ContentType.Application.JsonLd)).handle {
|
||||||
call.application.log.debug("Signature: ${call.request.header("Signature")}")
|
call.application.log.debug("Signature: ${call.request.header("Signature")}")
|
||||||
|
@ -26,10 +34,15 @@ fun Routing.usersAP(activityPubUserService: ActivityPubUserService, userService:
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
val userEntity = userService.findByNameLocalUser(
|
// TODO: 暫定処置なので治す
|
||||||
call.parameters["name"] ?: throw ParameterNotExistException("Parameter(name='name') does not exist.")
|
transaction.transaction {
|
||||||
|
val userEntity = userQueryService.findByNameAndDomain(
|
||||||
|
call.parameters["name"]
|
||||||
|
?: throw ParameterNotExistException("Parameter(name='name') does not exist."),
|
||||||
|
Config.configData.domain
|
||||||
)
|
)
|
||||||
call.respondText(userEntity.toString() + "\n" + userService.findFollowersById(userEntity.id))
|
call.respondText(userEntity.toString() + "\n" + followerQueryService.findFollowersById(userEntity.id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
package dev.usbharu.hideout.routing.api.internal.v1
|
package dev.usbharu.hideout.routing.api.internal.v1
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
|
||||||
import io.ktor.http.*
|
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.auth.*
|
import io.ktor.server.auth.*
|
||||||
import io.ktor.server.auth.jwt.*
|
import io.ktor.server.auth.jwt.*
|
||||||
|
@ -16,27 +11,15 @@ import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
fun Route.auth(
|
fun Route.auth(userAuthApiService: UserAuthApiService) {
|
||||||
userAuthService: IUserAuthService,
|
|
||||||
userRepository: IUserRepository,
|
|
||||||
jwtService: IJwtService
|
|
||||||
) {
|
|
||||||
post("/login") {
|
post("/login") {
|
||||||
val loginUser = call.receive<UserLogin>()
|
val loginUser = call.receive<UserLogin>()
|
||||||
val check = userAuthService.verifyAccount(loginUser.username, loginUser.password)
|
return@post call.respond(userAuthApiService.login(loginUser.username, loginUser.password))
|
||||||
if (check.not()) {
|
|
||||||
return@post call.respond(HttpStatusCode.Unauthorized)
|
|
||||||
}
|
|
||||||
|
|
||||||
val user = userRepository.findByNameAndDomain(loginUser.username, Config.configData.domain)
|
|
||||||
?: throw UserNotFoundException("${loginUser.username} was not found.")
|
|
||||||
|
|
||||||
return@post call.respond(jwtService.createToken(user))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post("/refresh-token") {
|
post("/refresh-token") {
|
||||||
val refreshToken = call.receive<RefreshToken>()
|
val refreshToken = call.receive<RefreshToken>()
|
||||||
return@post call.respond(jwtService.refreshToken(refreshToken))
|
return@post call.respond(userAuthApiService.refreshToken(refreshToken))
|
||||||
}
|
}
|
||||||
authenticate(TOKEN_AUTH) {
|
authenticate(TOKEN_AUTH) {
|
||||||
get("/auth-check") {
|
get("/auth-check") {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import dev.usbharu.hideout.domain.model.hideout.form.Reaction
|
||||||
import dev.usbharu.hideout.exception.ParameterNotExistException
|
import dev.usbharu.hideout.exception.ParameterNotExistException
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.service.api.IPostApiService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
|
||||||
import dev.usbharu.hideout.util.InstantParseUtil
|
import dev.usbharu.hideout.util.InstantParseUtil
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
@ -16,7 +15,7 @@ import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
fun Route.posts(postApiService: IPostApiService, reactionService: IReactionService) {
|
fun Route.posts(postApiService: IPostApiService) {
|
||||||
route("/posts") {
|
route("/posts") {
|
||||||
authenticate(TOKEN_AUTH) {
|
authenticate(TOKEN_AUTH) {
|
||||||
post {
|
post {
|
||||||
|
@ -36,7 +35,7 @@ fun Route.posts(postApiService: IPostApiService, reactionService: IReactionServi
|
||||||
call.parameters["id"]?.toLong()
|
call.parameters["id"]?.toLong()
|
||||||
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
||||||
)
|
)
|
||||||
call.respond(reactionService.findByPostIdForUser(postId, userId))
|
call.respond(postApiService.getReactionByPostId(postId, userId))
|
||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
val jwtPrincipal = call.principal<JWTPrincipal>() ?: throw IllegalStateException("no principal")
|
val jwtPrincipal = call.principal<JWTPrincipal>() ?: throw IllegalStateException("no principal")
|
||||||
|
@ -45,11 +44,11 @@ fun Route.posts(postApiService: IPostApiService, reactionService: IReactionServi
|
||||||
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
||||||
val reaction = try {
|
val reaction = try {
|
||||||
call.receive<Reaction>()
|
call.receive<Reaction>()
|
||||||
} catch (e: ContentTransformationException) {
|
} catch (_: ContentTransformationException) {
|
||||||
Reaction(null)
|
Reaction(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
reactionService.sendReaction(reaction.reaction ?: "❤", userId, postId)
|
postApiService.appendReaction(reaction.reaction ?: "❤", userId, postId)
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
delete {
|
delete {
|
||||||
|
@ -57,7 +56,7 @@ fun Route.posts(postApiService: IPostApiService, reactionService: IReactionServi
|
||||||
val userId = jwtPrincipal.payload.getClaim("uid").asLong()
|
val userId = jwtPrincipal.payload.getClaim("uid").asLong()
|
||||||
val postId = call.parameters["id"]?.toLong()
|
val postId = call.parameters["id"]?.toLong()
|
||||||
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
||||||
reactionService.removeReaction(userId, postId)
|
postApiService.removeReaction(userId, postId)
|
||||||
call.respond(HttpStatusCode.NoContent)
|
call.respond(HttpStatusCode.NoContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ import io.ktor.server.request.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod", "CognitiveComplexMethod")
|
||||||
fun Route.users(userService: IUserService, userApiService: IUserApiService) {
|
fun Route.users(userService: IUserService, userApiService: IUserApiService) {
|
||||||
route("/users") {
|
route("/users") {
|
||||||
get {
|
get {
|
||||||
|
|
|
@ -4,14 +4,14 @@ import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.wellknown.WebFinger
|
import dev.usbharu.hideout.domain.model.wellknown.WebFinger
|
||||||
import dev.usbharu.hideout.exception.IllegalParameterException
|
import dev.usbharu.hideout.exception.IllegalParameterException
|
||||||
import dev.usbharu.hideout.exception.ParameterNotExistException
|
import dev.usbharu.hideout.exception.ParameterNotExistException
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.api.WebFingerApiService
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.response.*
|
import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
fun Routing.webfinger(userService: IUserService) {
|
fun Routing.webfinger(webFingerApiService: WebFingerApiService) {
|
||||||
route("/.well-known/webfinger") {
|
route("/.well-known/webfinger") {
|
||||||
get {
|
get {
|
||||||
val acct = call.request.queryParameters["resource"]?.decodeURLPart()
|
val acct = call.request.queryParameters["resource"]?.decodeURLPart()
|
||||||
|
@ -25,7 +25,7 @@ fun Routing.webfinger(userService: IUserService) {
|
||||||
.substringAfter("acct:")
|
.substringAfter("acct:")
|
||||||
.trimStart('@')
|
.trimStart('@')
|
||||||
|
|
||||||
val userEntity = userService.findByNameLocalUser(accountName)
|
val userEntity = webFingerApiService.findByNameAndDomain(accountName, Config.configData.domain)
|
||||||
|
|
||||||
val webFinger = WebFinger(
|
val webFinger = WebFinger(
|
||||||
subject = acct,
|
subject = acct,
|
||||||
|
|
|
@ -5,12 +5,16 @@ import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Accept
|
import dev.usbharu.hideout.domain.model.ap.Accept
|
||||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||||
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ActivityPubAcceptServiceImpl(private val userService: IUserService) : ActivityPubAcceptService {
|
class ActivityPubAcceptServiceImpl(
|
||||||
|
private val userService: IUserService,
|
||||||
|
private val userQueryService: UserQueryService
|
||||||
|
) : ActivityPubAcceptService {
|
||||||
override suspend fun receiveAccept(accept: Accept): ActivityPubResponse {
|
override suspend fun receiveAccept(accept: Accept): ActivityPubResponse {
|
||||||
val value = accept.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val value = accept.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
||||||
if (value.type.contains("Follow").not()) {
|
if (value.type.contains("Follow").not()) {
|
||||||
|
@ -20,8 +24,8 @@ class ActivityPubAcceptServiceImpl(private val userService: IUserService) : Acti
|
||||||
val follow = value as Follow
|
val follow = value as Follow
|
||||||
val userUrl = follow.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val userUrl = follow.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
||||||
val followerUrl = follow.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
val followerUrl = follow.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
||||||
val user = userService.findByUrl(userUrl)
|
val user = userQueryService.findByUrl(userUrl)
|
||||||
val follower = userService.findByUrl(followerUrl)
|
val follower = userQueryService.findByUrl(followerUrl)
|
||||||
userService.follow(user.id, follower.id)
|
userService.follow(user.id, follower.id)
|
||||||
return ActivityPubStringResponse(HttpStatusCode.OK, "accepted")
|
return ActivityPubStringResponse(HttpStatusCode.OK, "accepted")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,12 +5,14 @@ import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Create
|
import dev.usbharu.hideout.domain.model.ap.Create
|
||||||
import dev.usbharu.hideout.domain.model.ap.Note
|
import dev.usbharu.hideout.domain.model.ap.Note
|
||||||
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ActivityPubCreateServiceImpl(
|
class ActivityPubCreateServiceImpl(
|
||||||
private val activityPubNoteService: ActivityPubNoteService
|
private val activityPubNoteService: ActivityPubNoteService,
|
||||||
|
private val transaction: Transaction
|
||||||
) : ActivityPubCreateService {
|
) : ActivityPubCreateService {
|
||||||
override suspend fun receiveCreate(create: Create): ActivityPubResponse {
|
override suspend fun receiveCreate(create: Create): ActivityPubResponse {
|
||||||
val value = create.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
val value = create.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
||||||
|
@ -18,8 +20,10 @@ class ActivityPubCreateServiceImpl(
|
||||||
throw IllegalActivityPubObjectException("object is not Note")
|
throw IllegalActivityPubObjectException("object is not Note")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return transaction.transaction {
|
||||||
val note = value as Note
|
val note = value as Note
|
||||||
activityPubNoteService.fetchNote(note)
|
activityPubNoteService.fetchNote(note)
|
||||||
return ActivityPubStringResponse(HttpStatusCode.OK, "Created")
|
ActivityPubStringResponse(HttpStatusCode.OK, "Created")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ package dev.usbharu.hideout.service.activitypub
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Like
|
import dev.usbharu.hideout.domain.model.ap.Like
|
||||||
import dev.usbharu.hideout.exception.PostNotFoundException
|
|
||||||
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
import dev.usbharu.hideout.repository.IPostRepository
|
import dev.usbharu.hideout.query.PostQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.reaction.IReactionService
|
import dev.usbharu.hideout.service.reaction.IReactionService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@ -15,26 +15,28 @@ import org.koin.core.annotation.Single
|
||||||
class ActivityPubLikeServiceImpl(
|
class ActivityPubLikeServiceImpl(
|
||||||
private val reactionService: IReactionService,
|
private val reactionService: IReactionService,
|
||||||
private val activityPubUserService: ActivityPubUserService,
|
private val activityPubUserService: ActivityPubUserService,
|
||||||
private val userService: IUserService,
|
private val activityPubNoteService: ActivityPubNoteService,
|
||||||
private val postService: IPostRepository,
|
private val userQueryService: UserQueryService,
|
||||||
private val activityPubNoteService: ActivityPubNoteService
|
private val postQueryService: PostQueryService,
|
||||||
|
private val transaction: Transaction
|
||||||
) : ActivityPubLikeService {
|
) : ActivityPubLikeService {
|
||||||
override suspend fun receiveLike(like: Like): ActivityPubResponse {
|
override suspend fun receiveLike(like: Like): ActivityPubResponse {
|
||||||
val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
val actor = like.actor ?: throw IllegalActivityPubObjectException("actor is null")
|
||||||
val content = like.content ?: throw IllegalActivityPubObjectException("content is null")
|
val content = like.content ?: throw IllegalActivityPubObjectException("content is null")
|
||||||
like.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
like.`object` ?: throw IllegalActivityPubObjectException("object is null")
|
||||||
|
transaction.transaction {
|
||||||
val person = activityPubUserService.fetchPerson(actor)
|
val person = activityPubUserService.fetchPerson(actor)
|
||||||
activityPubNoteService.fetchNote(like.`object`!!)
|
activityPubNoteService.fetchNote(like.`object`!!)
|
||||||
|
|
||||||
val user = userService.findByUrl(
|
val user = userQueryService.findByUrl(
|
||||||
person.url
|
person.url
|
||||||
?: throw IllegalActivityPubObjectException("actor is not found")
|
?: throw IllegalActivityPubObjectException("actor is not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
val post = postService.findByUrl(like.`object`!!)
|
val post = postQueryService.findByUrl(like.`object`!!)
|
||||||
?: throw PostNotFoundException("${like.`object`} was not found")
|
|
||||||
|
|
||||||
reactionService.receiveReaction(content, actor.substringAfter("://").substringBefore("/"), user.id, post.id)
|
reactionService.receiveReaction(content, actor.substringAfter("://").substringBefore("/"), user.id, post.id)
|
||||||
|
}
|
||||||
return ActivityPubStringResponse(HttpStatusCode.OK, "")
|
return ActivityPubStringResponse(HttpStatusCode.OK, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,11 @@ import dev.usbharu.hideout.domain.model.job.DeliverPostJob
|
||||||
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
import dev.usbharu.hideout.plugins.getAp
|
import dev.usbharu.hideout.plugins.getAp
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.PostQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IPostRepository
|
import dev.usbharu.hideout.repository.IPostRepository
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
|
@ -24,16 +26,18 @@ import java.time.Instant
|
||||||
class ActivityPubNoteServiceImpl(
|
class ActivityPubNoteServiceImpl(
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val userService: IUserService,
|
|
||||||
private val postRepository: IPostRepository,
|
private val postRepository: IPostRepository,
|
||||||
private val activityPubUserService: ActivityPubUserService
|
private val activityPubUserService: ActivityPubUserService,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val followerQueryService: FollowerQueryService,
|
||||||
|
private val postQueryService: PostQueryService
|
||||||
) : ActivityPubNoteService {
|
) : ActivityPubNoteService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||||
|
|
||||||
override suspend fun createNote(post: Post) {
|
override suspend fun createNote(post: Post) {
|
||||||
val followers = userService.findFollowersById(post.userId)
|
val followers = followerQueryService.findFollowersById(post.userId)
|
||||||
val userEntity = userService.findById(post.userId)
|
val userEntity = userQueryService.findById(post.userId)
|
||||||
val note = Config.configData.objectMapper.writeValueAsString(post)
|
val note = Config.configData.objectMapper.writeValueAsString(post)
|
||||||
followers.forEach { followerEntity ->
|
followers.forEach { followerEntity ->
|
||||||
jobQueueParentService.schedule(DeliverPostJob) {
|
jobQueueParentService.schedule(DeliverPostJob) {
|
||||||
|
@ -70,7 +74,7 @@ class ActivityPubNoteServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchNote(url: String, targetActor: String?): Note {
|
override suspend fun fetchNote(url: String, targetActor: String?): Note {
|
||||||
val post = postRepository.findByUrl(url)
|
val post = postQueryService.findByUrl(url)
|
||||||
if (post != null) {
|
if (post != null) {
|
||||||
return postToNote(post)
|
return postToNote(post)
|
||||||
}
|
}
|
||||||
|
@ -83,8 +87,8 @@ class ActivityPubNoteServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun postToNote(post: Post): Note {
|
private suspend fun postToNote(post: Post): Note {
|
||||||
val user = userService.findById(post.userId)
|
val user = userQueryService.findById(post.userId)
|
||||||
val reply = post.replyId?.let { postRepository.findOneById(it) }
|
val reply = post.replyId?.let { postQueryService.findById(it) }
|
||||||
return Note(
|
return Note(
|
||||||
name = "Post",
|
name = "Post",
|
||||||
id = post.apId,
|
id = post.apId,
|
||||||
|
@ -98,21 +102,28 @@ class ActivityPubNoteServiceImpl(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ActivityPubNoteServiceImpl.note(
|
private suspend fun note(
|
||||||
note: Note,
|
note: Note,
|
||||||
targetActor: String?,
|
targetActor: String?,
|
||||||
url: String
|
url: String
|
||||||
): Note {
|
): Note {
|
||||||
val findByApId = postRepository.findByApId(url)
|
val findByApId = try {
|
||||||
if (findByApId != null) {
|
postQueryService.findByApId(url)
|
||||||
|
} catch (_: NoSuchElementException) {
|
||||||
|
return internalNote(note, targetActor, url)
|
||||||
|
} catch (_: IllegalArgumentException) {
|
||||||
|
return internalNote(note, targetActor, url)
|
||||||
|
}
|
||||||
return postToNote(findByApId)
|
return postToNote(findByApId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun internalNote(note: Note, targetActor: String?, url: String): Note {
|
||||||
val person = activityPubUserService.fetchPerson(
|
val person = activityPubUserService.fetchPerson(
|
||||||
note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"),
|
note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"),
|
||||||
targetActor
|
targetActor
|
||||||
)
|
)
|
||||||
val user =
|
val user =
|
||||||
userService.findByUrl(person.url ?: throw IllegalActivityPubObjectException("person.url is null"))
|
userQueryService.findByUrl(person.url ?: throw IllegalActivityPubObjectException("person.url is null"))
|
||||||
|
|
||||||
val visibility =
|
val visibility =
|
||||||
if (note.to.contains(public) && note.cc.contains(public)) {
|
if (note.to.contains(public) && note.cc.contains(public)) {
|
||||||
|
@ -127,7 +138,7 @@ class ActivityPubNoteServiceImpl(
|
||||||
|
|
||||||
val reply = note.inReplyTo?.let {
|
val reply = note.inReplyTo?.let {
|
||||||
fetchNote(it, targetActor)
|
fetchNote(it, targetActor)
|
||||||
postRepository.findByUrl(it)
|
postQueryService.findByUrl(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
postRepository.save(
|
postRepository.save(
|
||||||
|
|
|
@ -7,11 +7,12 @@ import dev.usbharu.hideout.domain.model.ap.Undo
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
import dev.usbharu.hideout.domain.model.job.DeliverReactionJob
|
import dev.usbharu.hideout.domain.model.job.DeliverReactionJob
|
||||||
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
|
import dev.usbharu.hideout.domain.model.job.DeliverRemoveReactionJob
|
||||||
import dev.usbharu.hideout.exception.PostNotFoundException
|
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.PostQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IPostRepository
|
import dev.usbharu.hideout.repository.IPostRepository
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
@ -19,16 +20,18 @@ import java.time.Instant
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ActivityPubReactionServiceImpl(
|
class ActivityPubReactionServiceImpl(
|
||||||
private val userService: IUserService,
|
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val iPostRepository: IPostRepository,
|
private val iPostRepository: IPostRepository,
|
||||||
private val httpClient: HttpClient
|
private val httpClient: HttpClient,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val followerQueryService: FollowerQueryService,
|
||||||
|
private val postQueryService: PostQueryService
|
||||||
) : ActivityPubReactionService {
|
) : ActivityPubReactionService {
|
||||||
override suspend fun reaction(like: Reaction) {
|
override suspend fun reaction(like: Reaction) {
|
||||||
val followers = userService.findFollowersById(like.userId)
|
val followers = followerQueryService.findFollowersById(like.userId)
|
||||||
val user = userService.findById(like.userId)
|
val user = userQueryService.findById(like.userId)
|
||||||
val post =
|
val post =
|
||||||
iPostRepository.findOneById(like.postId) ?: throw PostNotFoundException("${like.postId} was not found.")
|
postQueryService.findById(like.postId)
|
||||||
followers.forEach { follower ->
|
followers.forEach { follower ->
|
||||||
jobQueueParentService.schedule(DeliverReactionJob) {
|
jobQueueParentService.schedule(DeliverReactionJob) {
|
||||||
props[it.actor] = user.url
|
props[it.actor] = user.url
|
||||||
|
@ -41,10 +44,10 @@ class ActivityPubReactionServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeReaction(like: Reaction) {
|
override suspend fun removeReaction(like: Reaction) {
|
||||||
val followers = userService.findFollowersById(like.userId)
|
val followers = followerQueryService.findFollowersById(like.userId)
|
||||||
val user = userService.findById(like.userId)
|
val user = userQueryService.findById(like.userId)
|
||||||
val post =
|
val post =
|
||||||
iPostRepository.findOneById(like.postId) ?: throw PostNotFoundException("${like.postId} was not found.")
|
postQueryService.findById(like.postId)
|
||||||
followers.forEach { follower ->
|
followers.forEach { follower ->
|
||||||
jobQueueParentService.schedule(DeliverRemoveReactionJob) {
|
jobQueueParentService.schedule(DeliverRemoveReactionJob) {
|
||||||
props[it.actor] = user.url
|
props[it.actor] = user.url
|
||||||
|
|
|
@ -8,6 +8,8 @@ import dev.usbharu.hideout.domain.model.ap.Accept
|
||||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||||
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -20,7 +22,9 @@ class ActivityPubReceiveFollowServiceImpl(
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val activityPubUserService: ActivityPubUserService,
|
private val activityPubUserService: ActivityPubUserService,
|
||||||
private val userService: IUserService,
|
private val userService: IUserService,
|
||||||
private val httpClient: HttpClient
|
private val httpClient: HttpClient,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val transaction: Transaction
|
||||||
) : ActivityPubReceiveFollowService {
|
) : ActivityPubReceiveFollowService {
|
||||||
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
||||||
// TODO: Verify HTTP Signature
|
// TODO: Verify HTTP Signature
|
||||||
|
@ -33,6 +37,7 @@ class ActivityPubReceiveFollowServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>) {
|
override suspend fun receiveFollowJob(props: JobProps<ReceiveFollowJob>) {
|
||||||
|
transaction.transaction {
|
||||||
val actor = props[ReceiveFollowJob.actor]
|
val actor = props[ReceiveFollowJob.actor]
|
||||||
val targetActor = props[ReceiveFollowJob.targetActor]
|
val targetActor = props[ReceiveFollowJob.targetActor]
|
||||||
val person = activityPubUserService.fetchPerson(actor, targetActor)
|
val person = activityPubUserService.fetchPerson(actor, targetActor)
|
||||||
|
@ -46,9 +51,12 @@ class ActivityPubReceiveFollowServiceImpl(
|
||||||
actor = targetActor
|
actor = targetActor
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val users =
|
|
||||||
userService.findByUrls(listOf(targetActor, follow.actor ?: throw IllegalArgumentException("actor is null")))
|
|
||||||
|
|
||||||
userService.followRequest(users.first { it.url == targetActor }.id, users.first { it.url == follow.actor }.id)
|
val targetEntity = userQueryService.findByUrl(targetActor)
|
||||||
|
val followActorEntity =
|
||||||
|
userQueryService.findByUrl(follow.actor ?: throw java.lang.IllegalArgumentException("Actor is null"))
|
||||||
|
|
||||||
|
userService.followRequest(targetEntity.id, followActorEntity.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||||
import dev.usbharu.hideout.domain.model.ap.Undo
|
import dev.usbharu.hideout.domain.model.ap.Undo
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
@ -12,7 +14,9 @@ import org.koin.core.annotation.Single
|
||||||
@Suppress("UnsafeCallOnNullableType")
|
@Suppress("UnsafeCallOnNullableType")
|
||||||
class ActivityPubUndoServiceImpl(
|
class ActivityPubUndoServiceImpl(
|
||||||
private val userService: IUserService,
|
private val userService: IUserService,
|
||||||
private val activityPubUserService: ActivityPubUserService
|
private val activityPubUserService: ActivityPubUserService,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val transaction: Transaction
|
||||||
) : ActivityPubUndoService {
|
) : ActivityPubUndoService {
|
||||||
override suspend fun receiveUndo(undo: Undo): ActivityPubResponse {
|
override suspend fun receiveUndo(undo: Undo): ActivityPubResponse {
|
||||||
if (undo.actor == null) {
|
if (undo.actor == null) {
|
||||||
|
@ -31,12 +35,13 @@ class ActivityPubUndoServiceImpl(
|
||||||
if (follow.`object` == null) {
|
if (follow.`object` == null) {
|
||||||
return ActivityPubStringResponse(HttpStatusCode.BadRequest, "object.object is null")
|
return ActivityPubStringResponse(HttpStatusCode.BadRequest, "object.object is null")
|
||||||
}
|
}
|
||||||
|
transaction.transaction {
|
||||||
activityPubUserService.fetchPerson(undo.actor!!, follow.`object`)
|
activityPubUserService.fetchPerson(undo.actor!!, follow.`object`)
|
||||||
val follower = userService.findByUrl(undo.actor!!)
|
val follower = userQueryService.findByUrl(undo.actor!!)
|
||||||
val target = userService.findByUrl(follow.`object`!!)
|
val target = userQueryService.findByUrl(follow.`object`!!)
|
||||||
userService.unfollow(target.id, follower.id)
|
userService.unfollow(target.id, follower.id)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,10 @@ import dev.usbharu.hideout.domain.model.ap.Image
|
||||||
import dev.usbharu.hideout.domain.model.ap.Key
|
import dev.usbharu.hideout.domain.model.ap.Key
|
||||||
import dev.usbharu.hideout.domain.model.ap.Person
|
import dev.usbharu.hideout.domain.model.ap.Person
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.RemoteUserCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.RemoteUserCreateDto
|
||||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
|
||||||
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
import dev.usbharu.hideout.plugins.getAp
|
import dev.usbharu.hideout.plugins.getAp
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -20,13 +21,17 @@ import org.koin.core.annotation.Single
|
||||||
@Single
|
@Single
|
||||||
class ActivityPubUserServiceImpl(
|
class ActivityPubUserServiceImpl(
|
||||||
private val userService: IUserService,
|
private val userService: IUserService,
|
||||||
private val httpClient: HttpClient
|
private val httpClient: HttpClient,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val transaction: Transaction
|
||||||
) :
|
) :
|
||||||
ActivityPubUserService {
|
ActivityPubUserService {
|
||||||
|
|
||||||
override suspend fun getPersonByName(name: String): Person {
|
override suspend fun getPersonByName(name: String): Person {
|
||||||
|
val userEntity = transaction.transaction {
|
||||||
|
userQueryService.findByNameAndDomain(name, Config.configData.domain)
|
||||||
|
}
|
||||||
// TODO: JOINで書き直し
|
// TODO: JOINで書き直し
|
||||||
val userEntity = userService.findByNameLocalUser(name)
|
|
||||||
val userUrl = "${Config.configData.url}/users/$name"
|
val userUrl = "${Config.configData.url}/users/$name"
|
||||||
return Person(
|
return Person(
|
||||||
type = emptyList(),
|
type = emptyList(),
|
||||||
|
@ -55,7 +60,7 @@ class ActivityPubUserServiceImpl(
|
||||||
|
|
||||||
override suspend fun fetchPerson(url: String, targetActor: String?): Person {
|
override suspend fun fetchPerson(url: String, targetActor: String?): Person {
|
||||||
return try {
|
return try {
|
||||||
val userEntity = userService.findByUrl(url)
|
val userEntity = userQueryService.findByUrl(url)
|
||||||
return Person(
|
return Person(
|
||||||
type = emptyList(),
|
type = emptyList(),
|
||||||
name = userEntity.name,
|
name = userEntity.name,
|
||||||
|
@ -79,7 +84,7 @@ class ActivityPubUserServiceImpl(
|
||||||
publicKeyPem = userEntity.publicKey
|
publicKeyPem = userEntity.publicKey
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} catch (ignore: UserNotFoundException) {
|
} catch (ignore: NoSuchElementException) {
|
||||||
val httpResponse = if (targetActor != null) {
|
val httpResponse = if (targetActor != null) {
|
||||||
httpClient.getAp(url, "$targetActor#pubkey")
|
httpClient.getAp(url, "$targetActor#pubkey")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.api
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
|
@ -25,4 +26,8 @@ interface IPostApiService {
|
||||||
limit: Int? = null,
|
limit: Int? = null,
|
||||||
userId: Long? = null
|
userId: Long? = null
|
||||||
): List<PostResponse>
|
): List<PostResponse>
|
||||||
|
|
||||||
|
suspend fun getReactionByPostId(postId: Long, userId: Long? = null): List<ReactionResponse>
|
||||||
|
suspend fun appendReaction(reaction: String, userId: Long, postId: Long)
|
||||||
|
suspend fun removeReaction(userId: Long, postId: Long)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@ interface IUserApiService {
|
||||||
|
|
||||||
suspend fun findByAcct(acct: Acct): UserResponse
|
suspend fun findByAcct(acct: Acct): UserResponse
|
||||||
|
|
||||||
suspend fun findByAccts(accts: List<Acct>): List<UserResponse>
|
|
||||||
|
|
||||||
suspend fun findFollowers(userId: Long): List<UserResponse>
|
suspend fun findFollowers(userId: Long): List<UserResponse>
|
||||||
|
|
||||||
suspend fun findFollowings(userId: Long): List<UserResponse>
|
suspend fun findFollowings(userId: Long): List<UserResponse>
|
||||||
|
@ -21,4 +19,6 @@ interface IUserApiService {
|
||||||
suspend fun findFollowersByAcct(acct: Acct): List<UserResponse>
|
suspend fun findFollowersByAcct(acct: Acct): List<UserResponse>
|
||||||
|
|
||||||
suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse>
|
suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse>
|
||||||
|
|
||||||
|
suspend fun createUser(username: String, password: String): UserResponse
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,15 +3,14 @@ package dev.usbharu.hideout.service.api
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||||
import dev.usbharu.hideout.repository.*
|
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
||||||
|
import dev.usbharu.hideout.query.PostResponseQueryService
|
||||||
|
import dev.usbharu.hideout.query.ReactionQueryService
|
||||||
|
import dev.usbharu.hideout.repository.IUserRepository
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
import dev.usbharu.hideout.service.post.IPostService
|
||||||
|
import dev.usbharu.hideout.service.reaction.IReactionService
|
||||||
import dev.usbharu.hideout.util.AcctUtil
|
import dev.usbharu.hideout.util.AcctUtil
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.innerJoin
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.selectAll
|
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
||||||
|
@ -19,10 +18,14 @@ import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
||||||
@Single
|
@Single
|
||||||
class PostApiServiceImpl(
|
class PostApiServiceImpl(
|
||||||
private val postService: IPostService,
|
private val postService: IPostService,
|
||||||
private val postRepository: IPostRepository,
|
private val userRepository: IUserRepository,
|
||||||
private val userRepository: IUserRepository
|
private val postResponseQueryService: PostResponseQueryService,
|
||||||
|
private val reactionQueryService: ReactionQueryService,
|
||||||
|
private val reactionService: IReactionService,
|
||||||
|
private val transaction: Transaction
|
||||||
) : IPostApiService {
|
) : IPostApiService {
|
||||||
override suspend fun createPost(postForm: FormPost, userId: Long): PostResponse {
|
override suspend fun createPost(postForm: FormPost, userId: Long): PostResponse {
|
||||||
|
return transaction.transaction {
|
||||||
val createdPost = postService.createLocal(
|
val createdPost = postService.createLocal(
|
||||||
PostCreateDto(
|
PostCreateDto(
|
||||||
text = postForm.text,
|
text = postForm.text,
|
||||||
|
@ -34,20 +37,11 @@ class PostApiServiceImpl(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val creator = userRepository.findById(userId)
|
val creator = userRepository.findById(userId)
|
||||||
return PostResponse.from(createdPost, creator!!)
|
PostResponse.from(createdPost, creator!!)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("InjectDispatcher")
|
override suspend fun getById(id: Long, userId: Long?): PostResponse = postResponseQueryService.findById(id, userId)
|
||||||
suspend fun <T> query(block: suspend () -> T): T =
|
|
||||||
newSuspendedTransaction(Dispatchers.IO) { block() }
|
|
||||||
|
|
||||||
override suspend fun getById(id: Long, userId: Long?): PostResponse {
|
|
||||||
val query = query {
|
|
||||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { Users.id }).select { Posts.id eq id }
|
|
||||||
.single()
|
|
||||||
}
|
|
||||||
return PostResponse.from(query.toPost(), query.toUser())
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun getAll(
|
override suspend fun getAll(
|
||||||
since: Instant?,
|
since: Instant?,
|
||||||
|
@ -56,11 +50,15 @@ class PostApiServiceImpl(
|
||||||
maxId: Long?,
|
maxId: Long?,
|
||||||
limit: Int?,
|
limit: Int?,
|
||||||
userId: Long?
|
userId: Long?
|
||||||
): List<PostResponse> {
|
): List<PostResponse> = transaction.transaction {
|
||||||
return query {
|
postResponseQueryService.findAll(
|
||||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).selectAll()
|
since = since?.toEpochMilli(),
|
||||||
.map { PostResponse.from(it.toPost(), it.toUser()) }
|
until = until?.toEpochMilli(),
|
||||||
}
|
minId = minId,
|
||||||
|
maxId = maxId,
|
||||||
|
limit = limit,
|
||||||
|
userId = userId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getByUser(
|
override suspend fun getByUser(
|
||||||
|
@ -75,18 +73,24 @@ class PostApiServiceImpl(
|
||||||
val idOrNull = nameOrId.toLongOrNull()
|
val idOrNull = nameOrId.toLongOrNull()
|
||||||
return if (idOrNull == null) {
|
return if (idOrNull == null) {
|
||||||
val acct = AcctUtil.parse(nameOrId)
|
val acct = AcctUtil.parse(nameOrId)
|
||||||
query {
|
postResponseQueryService.findByUserNameAndUserDomain(acct.username, acct.domain ?: Config.configData.domain)
|
||||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).select {
|
|
||||||
Users.name.eq(acct.username)
|
|
||||||
.and(Users.domain eq (acct.domain ?: Config.configData.domain))
|
|
||||||
}.map { PostResponse.from(it.toPost(), it.toUser()) }
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
query {
|
postResponseQueryService.findByUserId(idOrNull)
|
||||||
Posts.innerJoin(Users, onColumn = { Posts.userId }, otherColumn = { id }).select {
|
}
|
||||||
Posts.userId eq idOrNull
|
}
|
||||||
}.map { PostResponse.from(it.toPost(), it.toUser()) }
|
|
||||||
}
|
override suspend fun getReactionByPostId(postId: Long, userId: Long?): List<ReactionResponse> =
|
||||||
|
transaction.transaction { reactionQueryService.findByPostIdWithUsers(postId, userId) }
|
||||||
|
|
||||||
|
override suspend fun appendReaction(reaction: String, userId: Long, postId: Long) {
|
||||||
|
transaction.transaction {
|
||||||
|
reactionService.sendReaction(reaction, userId, postId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun removeReaction(userId: Long, postId: Long) {
|
||||||
|
transaction.transaction {
|
||||||
|
reactionService.removeReaction(userId, postId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,37 +2,54 @@ package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.Acct
|
import dev.usbharu.hideout.domain.model.Acct
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
||||||
|
import dev.usbharu.hideout.exception.UsernameAlreadyExistException
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class UserApiServiceImpl(private val userService: IUserService) : IUserApiService {
|
class UserApiServiceImpl(
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val followerQueryService: FollowerQueryService,
|
||||||
|
private val userService: IUserService,
|
||||||
|
private val transaction: Transaction
|
||||||
|
) : IUserApiService {
|
||||||
override suspend fun findAll(limit: Int?, offset: Long): List<UserResponse> =
|
override suspend fun findAll(limit: Int?, offset: Long): List<UserResponse> =
|
||||||
userService.findAll(limit, offset).map { UserResponse.from(it) }
|
userQueryService.findAll(min(limit ?: 100, 100), offset).map { UserResponse.from(it) }
|
||||||
|
|
||||||
override suspend fun findById(id: Long): UserResponse = UserResponse.from(userService.findById(id))
|
override suspend fun findById(id: Long): UserResponse = UserResponse.from(userQueryService.findById(id))
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<UserResponse> =
|
override suspend fun findByIds(ids: List<Long>): List<UserResponse> =
|
||||||
userService.findByIds(ids).map { UserResponse.from(it) }
|
userQueryService.findByIds(ids).map { UserResponse.from(it) }
|
||||||
|
|
||||||
override suspend fun findByAcct(acct: Acct): UserResponse =
|
override suspend fun findByAcct(acct: Acct): UserResponse =
|
||||||
UserResponse.from(userService.findByNameAndDomain(acct.username, acct.domain))
|
UserResponse.from(userQueryService.findByNameAndDomain(acct.username, acct.domain ?: Config.configData.domain))
|
||||||
|
|
||||||
override suspend fun findByAccts(accts: List<Acct>): List<UserResponse> {
|
|
||||||
return userService.findByNameAndDomains(accts.map { it.username to (it.domain ?: Config.configData.domain) })
|
|
||||||
.map { UserResponse.from(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowers(userId: Long): List<UserResponse> =
|
override suspend fun findFollowers(userId: Long): List<UserResponse> =
|
||||||
userService.findFollowersById(userId).map { UserResponse.from(it) }
|
followerQueryService.findFollowersById(userId).map { UserResponse.from(it) }
|
||||||
|
|
||||||
override suspend fun findFollowings(userId: Long): List<UserResponse> =
|
override suspend fun findFollowings(userId: Long): List<UserResponse> =
|
||||||
userService.findFollowingById(userId).map { UserResponse.from(it) }
|
followerQueryService.findFollowingById(userId).map { UserResponse.from(it) }
|
||||||
|
|
||||||
override suspend fun findFollowersByAcct(acct: Acct): List<UserResponse> =
|
override suspend fun findFollowersByAcct(acct: Acct): List<UserResponse> =
|
||||||
userService.findFollowersByNameAndDomain(acct.username, acct.domain).map { UserResponse.from(it) }
|
followerQueryService.findFollowersByNameAndDomain(acct.username, acct.domain ?: Config.configData.domain)
|
||||||
|
.map { UserResponse.from(it) }
|
||||||
|
|
||||||
override suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse> =
|
override suspend fun findFollowingsByAcct(acct: Acct): List<UserResponse> =
|
||||||
userService.findFollowingByNameAndDomain(acct.username, acct.domain).map { UserResponse.from(it) }
|
followerQueryService.findFollowingByNameAndDomain(acct.username, acct.domain ?: Config.configData.domain)
|
||||||
|
.map { UserResponse.from(it) }
|
||||||
|
|
||||||
|
override suspend fun createUser(username: String, password: String): UserResponse {
|
||||||
|
return transaction.transaction {
|
||||||
|
if (userQueryService.existByNameAndDomain(username, Config.configData.domain)) {
|
||||||
|
throw UsernameAlreadyExistException()
|
||||||
|
}
|
||||||
|
UserResponse.from(userService.createLocalUser(UserCreateDto(username, username, "", password)))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
|
|
||||||
|
interface UserAuthApiService {
|
||||||
|
suspend fun login(username: String, password: String): JwtToken
|
||||||
|
suspend fun refreshToken(refreshToken: RefreshToken): JwtToken
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.config.Config
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.JwtToken
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
|
import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.auth.IJwtService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
import dev.usbharu.hideout.service.user.UserAuthService
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class UserAuthApiServiceImpl(
|
||||||
|
private val userAuthService: UserAuthService,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val jwtService: IJwtService,
|
||||||
|
private val transaction: Transaction
|
||||||
|
) : UserAuthApiService {
|
||||||
|
override suspend fun login(username: String, password: String): JwtToken {
|
||||||
|
return transaction.transaction {
|
||||||
|
if (userAuthService.verifyAccount(username, password).not()) {
|
||||||
|
throw InvalidUsernameOrPasswordException()
|
||||||
|
}
|
||||||
|
val user = userQueryService.findByNameAndDomain(username, Config.configData.domain)
|
||||||
|
jwtService.createToken(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun refreshToken(refreshToken: RefreshToken): JwtToken {
|
||||||
|
return transaction.transaction {
|
||||||
|
jwtService.refreshToken(refreshToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
|
||||||
|
interface WebFingerApiService {
|
||||||
|
suspend fun findByNameAndDomain(name: String, domain: String): User
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class WebFingerApiServiceImpl(private val transaction: Transaction, private val userQueryService: UserQueryService) :
|
||||||
|
WebFingerApiService {
|
||||||
|
override suspend fun findByNameAndDomain(name: String, domain: String): User {
|
||||||
|
return transaction.transaction {
|
||||||
|
userQueryService.findByNameAndDomain(name, domain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,19 @@
|
||||||
package dev.usbharu.hideout.service.auth
|
package dev.usbharu.hideout.service.auth
|
||||||
|
|
||||||
import dev.usbharu.hideout.plugins.KtorKeyMap
|
import dev.usbharu.hideout.plugins.KtorKeyMap
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import tech.barbero.http.message.signing.SignatureHeaderVerifier
|
import tech.barbero.http.message.signing.SignatureHeaderVerifier
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class HttpSignatureVerifyServiceImpl(private val userAuthService: IUserRepository) : HttpSignatureVerifyService {
|
class HttpSignatureVerifyServiceImpl(
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val transaction: Transaction
|
||||||
|
) : HttpSignatureVerifyService {
|
||||||
override fun verify(headers: Headers): Boolean {
|
override fun verify(headers: Headers): Boolean {
|
||||||
val build = SignatureHeaderVerifier.builder().keyMap(KtorKeyMap(userAuthService)).build()
|
val build = SignatureHeaderVerifier.builder().keyMap(KtorKeyMap(userQueryService, transaction)).build()
|
||||||
return true
|
return true
|
||||||
// build.verify(object : HttpMessage {
|
// build.verify(object : HttpMessage {
|
||||||
// override fun headerValues(name: String?): MutableList<String> {
|
// override fun headerValues(name: String?): MutableList<String> {
|
||||||
|
|
|
@ -8,13 +8,12 @@ import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
||||||
|
import dev.usbharu.hideout.query.JwtRefreshTokenQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
import dev.usbharu.hideout.service.core.IMetaService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import dev.usbharu.hideout.util.RsaUtil
|
import dev.usbharu.hideout.util.RsaUtil
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
|
@ -25,26 +24,19 @@ import java.util.*
|
||||||
class JwtServiceImpl(
|
class JwtServiceImpl(
|
||||||
private val metaService: IMetaService,
|
private val metaService: IMetaService,
|
||||||
private val refreshTokenRepository: IJwtRefreshTokenRepository,
|
private val refreshTokenRepository: IJwtRefreshTokenRepository,
|
||||||
private val userService: IUserService
|
private val userQueryService: UserQueryService,
|
||||||
|
private val refreshTokenQueryService: JwtRefreshTokenQueryService
|
||||||
) : IJwtService {
|
) : IJwtService {
|
||||||
|
|
||||||
private val privateKey by lazy {
|
private val privateKey = runBlocking {
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
|
||||||
RsaUtil.decodeRsaPrivateKey(metaService.getJwtMeta().privateKey)
|
RsaUtil.decodeRsaPrivateKey(metaService.getJwtMeta().privateKey)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private val publicKey by lazy {
|
private val publicKey = runBlocking {
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
|
||||||
RsaUtil.decodeRsaPublicKey(metaService.getJwtMeta().publicKey)
|
RsaUtil.decodeRsaPublicKey(metaService.getJwtMeta().publicKey)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private val keyId by lazy {
|
private val keyId = runBlocking { metaService.getJwtMeta().kid }
|
||||||
CoroutineScope(Dispatchers.IO).async {
|
|
||||||
metaService.getJwtMeta().kid
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("MagicNumber")
|
@Suppress("MagicNumber")
|
||||||
override suspend fun createToken(user: User): JwtToken {
|
override suspend fun createToken(user: User): JwtToken {
|
||||||
|
@ -52,10 +44,10 @@ class JwtServiceImpl(
|
||||||
val token = JWT.create()
|
val token = JWT.create()
|
||||||
.withAudience("${Config.configData.url}/users/${user.name}")
|
.withAudience("${Config.configData.url}/users/${user.name}")
|
||||||
.withIssuer(Config.configData.url)
|
.withIssuer(Config.configData.url)
|
||||||
.withKeyId(keyId.await().toString())
|
.withKeyId(keyId.toString())
|
||||||
.withClaim("uid", user.id)
|
.withClaim("uid", user.id)
|
||||||
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
.withExpiresAt(now.plus(30, ChronoUnit.MINUTES))
|
||||||
.sign(Algorithm.RSA256(publicKey.await(), privateKey.await()))
|
.sign(Algorithm.RSA256(publicKey, privateKey))
|
||||||
|
|
||||||
val jwtRefreshToken = JwtRefreshToken(
|
val jwtRefreshToken = JwtRefreshToken(
|
||||||
id = refreshTokenRepository.generateId(),
|
id = refreshTokenRepository.generateId(),
|
||||||
|
@ -69,10 +61,13 @@ class JwtServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun refreshToken(refreshToken: RefreshToken): JwtToken {
|
override suspend fun refreshToken(refreshToken: RefreshToken): JwtToken {
|
||||||
val token = refreshTokenRepository.findByToken(refreshToken.refreshToken)
|
val token = try {
|
||||||
?: throw InvalidRefreshTokenException("Invalid Refresh Token")
|
refreshTokenQueryService.findByToken(refreshToken.refreshToken)
|
||||||
|
} catch (_: NoSuchElementException) {
|
||||||
|
throw InvalidRefreshTokenException("Invalid Refresh Token")
|
||||||
|
}
|
||||||
|
|
||||||
val user = userService.findById(token.userId)
|
val user = userQueryService.findById(token.userId)
|
||||||
|
|
||||||
val now = Instant.now()
|
val now = Instant.now()
|
||||||
if (token.createdAt.isAfter(now)) {
|
if (token.createdAt.isAfter(now)) {
|
||||||
|
@ -87,14 +82,14 @@ class JwtServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun revokeToken(refreshToken: RefreshToken) {
|
override suspend fun revokeToken(refreshToken: RefreshToken) {
|
||||||
refreshTokenRepository.deleteByToken(refreshToken.refreshToken)
|
refreshTokenQueryService.deleteByToken(refreshToken.refreshToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun revokeToken(user: User) {
|
override suspend fun revokeToken(user: User) {
|
||||||
refreshTokenRepository.deleteByUserId(user.id)
|
refreshTokenQueryService.deleteByUserId(user.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun revokeAll() {
|
override suspend fun revokeAll() {
|
||||||
refreshTokenRepository.deleteAll()
|
refreshTokenQueryService.deleteAll()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package dev.usbharu.hideout.service.core
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class ExposedTransaction : Transaction {
|
||||||
|
override suspend fun <T> transaction(block: suspend () -> T): T {
|
||||||
|
return newSuspendedTransaction {
|
||||||
|
block()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,10 +7,12 @@ import dev.usbharu.hideout.repository.IMetaRepository
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class MetaServiceImpl(private val metaRepository: IMetaRepository) : IMetaService {
|
class MetaServiceImpl(private val metaRepository: IMetaRepository, private val transaction: Transaction) :
|
||||||
override suspend fun getMeta(): Meta = metaRepository.get() ?: throw NotInitException("Meta is null")
|
IMetaService {
|
||||||
|
override suspend fun getMeta(): Meta =
|
||||||
|
transaction.transaction { metaRepository.get() ?: throw NotInitException("Meta is null") }
|
||||||
|
|
||||||
override suspend fun updateMeta(meta: Meta) {
|
override suspend fun updateMeta(meta: Meta) = transaction.transaction {
|
||||||
metaRepository.save(meta)
|
metaRepository.save(meta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,18 +11,23 @@ import java.security.KeyPairGenerator
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) : IServerInitialiseService {
|
class ServerInitialiseServiceImpl(
|
||||||
|
private val metaRepository: IMetaRepository,
|
||||||
|
private val transaction: Transaction
|
||||||
|
) :
|
||||||
|
IServerInitialiseService {
|
||||||
|
|
||||||
val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java)
|
val logger: Logger = LoggerFactory.getLogger(ServerInitialiseServiceImpl::class.java)
|
||||||
|
|
||||||
override suspend fun init() {
|
override suspend fun init() {
|
||||||
|
transaction.transaction {
|
||||||
val savedMeta = metaRepository.get()
|
val savedMeta = metaRepository.get()
|
||||||
val implementationVersion = ServerUtil.getImplementationVersion()
|
val implementationVersion = ServerUtil.getImplementationVersion()
|
||||||
if (wasInitialised(savedMeta).not()) {
|
if (wasInitialised(savedMeta).not()) {
|
||||||
logger.info("Start Initialise")
|
logger.info("Start Initialise")
|
||||||
initialise(implementationVersion)
|
initialise(implementationVersion)
|
||||||
logger.info("Finish Initialise")
|
logger.info("Finish Initialise")
|
||||||
return
|
return@transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVersionChanged(requireNotNull(savedMeta))) {
|
if (isVersionChanged(requireNotNull(savedMeta))) {
|
||||||
|
@ -30,6 +35,7 @@ class ServerInitialiseServiceImpl(private val metaRepository: IMetaRepository) :
|
||||||
updateVersion(savedMeta, implementationVersion)
|
updateVersion(savedMeta, implementationVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun wasInitialised(meta: Meta?): Boolean {
|
private fun wasInitialised(meta: Meta?): Boolean {
|
||||||
logger.debug("Initialise checking...")
|
logger.debug("Initialise checking...")
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package dev.usbharu.hideout.service.core
|
||||||
|
|
||||||
|
interface Transaction {
|
||||||
|
suspend fun <T> transaction(block: suspend () -> T): T
|
||||||
|
}
|
|
@ -1,10 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.reaction
|
package dev.usbharu.hideout.service.reaction
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
|
||||||
|
|
||||||
interface IReactionService {
|
interface IReactionService {
|
||||||
suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long)
|
suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long)
|
||||||
suspend fun sendReaction(name: String, userId: Long, postId: Long)
|
suspend fun sendReaction(name: String, userId: Long, postId: Long)
|
||||||
suspend fun removeReaction(userId: Long, postId: Long)
|
suspend fun removeReaction(userId: Long, postId: Long)
|
||||||
suspend fun findByPostIdForUser(postId: Long, userId: Long): List<ReactionResponse>
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,19 @@
|
||||||
package dev.usbharu.hideout.service.reaction
|
package dev.usbharu.hideout.service.reaction
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.Account
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.ReactionResponse
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
import dev.usbharu.hideout.domain.model.hideout.entity.Reaction
|
||||||
|
import dev.usbharu.hideout.query.ReactionQueryService
|
||||||
import dev.usbharu.hideout.repository.ReactionRepository
|
import dev.usbharu.hideout.repository.ReactionRepository
|
||||||
import dev.usbharu.hideout.repository.Reactions
|
|
||||||
import dev.usbharu.hideout.repository.Users
|
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubReactionService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubReactionService
|
||||||
import org.jetbrains.exposed.sql.ResultRow
|
|
||||||
import org.jetbrains.exposed.sql.leftJoin
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ReactionServiceImpl(
|
class ReactionServiceImpl(
|
||||||
private val reactionRepository: ReactionRepository,
|
private val reactionRepository: ReactionRepository,
|
||||||
private val activityPubReactionService: ActivityPubReactionService
|
private val activityPubReactionService: ActivityPubReactionService,
|
||||||
|
private val reactionQueryService: ReactionQueryService
|
||||||
) : IReactionService {
|
) : IReactionService {
|
||||||
override suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) {
|
override suspend fun receiveReaction(name: String, domain: String, userId: Long, postId: Long) {
|
||||||
if (reactionRepository.reactionAlreadyExist(postId, userId, 0).not()) {
|
if (reactionQueryService.reactionAlreadyExist(postId, userId, 0).not()) {
|
||||||
reactionRepository.save(
|
reactionRepository.save(
|
||||||
Reaction(reactionRepository.generateId(), 0, postId, userId)
|
Reaction(reactionRepository.generateId(), 0, postId, userId)
|
||||||
)
|
)
|
||||||
|
@ -27,9 +21,9 @@ class ReactionServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendReaction(name: String, userId: Long, postId: Long) {
|
override suspend fun sendReaction(name: String, userId: Long, postId: Long) {
|
||||||
if (reactionRepository.reactionAlreadyExist(postId, userId, 0)) {
|
if (reactionQueryService.reactionAlreadyExist(postId, userId, 0)) {
|
||||||
// delete
|
// delete
|
||||||
reactionRepository.deleteByPostIdAndUserId(postId, userId)
|
reactionQueryService.deleteByPostIdAndUserId(postId, userId)
|
||||||
} else {
|
} else {
|
||||||
val reaction = Reaction(reactionRepository.generateId(), 0, postId, userId)
|
val reaction = Reaction(reactionRepository.generateId(), 0, postId, userId)
|
||||||
reactionRepository.save(reaction)
|
reactionRepository.save(reaction)
|
||||||
|
@ -38,18 +32,6 @@ class ReactionServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun removeReaction(userId: Long, postId: Long) {
|
override suspend fun removeReaction(userId: Long, postId: Long) {
|
||||||
reactionRepository.deleteByPostIdAndUserId(postId, userId)
|
reactionQueryService.deleteByPostIdAndUserId(postId, userId)
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByPostIdForUser(postId: Long, userId: Long): List<ReactionResponse> {
|
|
||||||
return newSuspendedTransaction {
|
|
||||||
Reactions
|
|
||||||
.leftJoin(Users, onColumn = { Reactions.userId }, otherColumn = { id })
|
|
||||||
.select { Reactions.postId.eq(postId) }
|
|
||||||
.groupBy { resultRow: ResultRow -> ReactionResponse("❤", true, "", listOf()) }
|
|
||||||
.map { entry: Map.Entry<ReactionResponse, List<ResultRow>> ->
|
|
||||||
entry.key.copy(accounts = entry.value.map { Account(it[Users.screenName], "", it[Users.url]) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,23 +6,6 @@ import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
|
|
||||||
@Suppress("TooManyFunctions")
|
@Suppress("TooManyFunctions")
|
||||||
interface IUserService {
|
interface IUserService {
|
||||||
suspend fun findAll(limit: Int? = 100, offset: Long? = 0): List<User>
|
|
||||||
|
|
||||||
suspend fun findById(id: Long): User
|
|
||||||
|
|
||||||
suspend fun findByIds(ids: List<Long>): List<User>
|
|
||||||
|
|
||||||
suspend fun findByName(name: String): List<User>
|
|
||||||
|
|
||||||
suspend fun findByNameLocalUser(name: String): User
|
|
||||||
|
|
||||||
suspend fun findByNameAndDomain(name: String, domain: String? = null): User
|
|
||||||
|
|
||||||
suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User>
|
|
||||||
|
|
||||||
suspend fun findByUrl(url: String): User
|
|
||||||
|
|
||||||
suspend fun findByUrls(urls: List<String>): List<User>
|
|
||||||
|
|
||||||
suspend fun usernameAlreadyUse(username: String): Boolean
|
suspend fun usernameAlreadyUse(username: String): Boolean
|
||||||
|
|
||||||
|
@ -30,14 +13,6 @@ interface IUserService {
|
||||||
|
|
||||||
suspend fun createRemoteUser(user: RemoteUserCreateDto): User
|
suspend fun createRemoteUser(user: RemoteUserCreateDto): User
|
||||||
|
|
||||||
suspend fun findFollowersById(id: Long): List<User>
|
|
||||||
|
|
||||||
suspend fun findFollowersByNameAndDomain(name: String, domain: String?): List<User>
|
|
||||||
|
|
||||||
suspend fun findFollowingById(id: Long): List<User>
|
|
||||||
|
|
||||||
suspend fun findFollowingByNameAndDomain(name: String, domain: String?): List<User>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* フォローリクエストを送信する
|
* フォローリクエストを送信する
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package dev.usbharu.hideout.service.user
|
package dev.usbharu.hideout.service.user
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import io.ktor.util.*
|
import io.ktor.util.*
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.security.*
|
import java.security.*
|
||||||
|
@ -9,7 +9,7 @@ import java.util.*
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class UserAuthService(
|
class UserAuthService(
|
||||||
val userRepository: IUserRepository
|
val userQueryService: UserQueryService
|
||||||
) : IUserAuthService {
|
) : IUserAuthService {
|
||||||
|
|
||||||
override fun hash(password: String): String {
|
override fun hash(password: String): String {
|
||||||
|
@ -18,13 +18,12 @@ class UserAuthService(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
userRepository.findByName(username)
|
userQueryService.findByName(username)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun verifyAccount(username: String, password: String): Boolean {
|
override suspend fun verifyAccount(username: String, password: String): Boolean {
|
||||||
val userEntity = userRepository.findByNameAndDomain(username, Config.configData.domain)
|
val userEntity = userQueryService.findByNameAndDomain(username, Config.configData.domain)
|
||||||
?: return false
|
|
||||||
return userEntity.password == hash(password)
|
return userEntity.password == hash(password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,55 +6,25 @@ import dev.usbharu.hideout.domain.model.hideout.dto.SendFollowDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.repository.IUserRepository
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubSendFollowService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubSendFollowService
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
import java.lang.Integer.min
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class UserService(
|
class UserService(
|
||||||
private val userRepository: IUserRepository,
|
private val userRepository: IUserRepository,
|
||||||
private val userAuthService: IUserAuthService,
|
private val userAuthService: IUserAuthService,
|
||||||
private val activityPubSendFollowService: ActivityPubSendFollowService
|
private val activityPubSendFollowService: ActivityPubSendFollowService,
|
||||||
|
private val userQueryService: UserQueryService,
|
||||||
|
private val followerQueryService: FollowerQueryService
|
||||||
) :
|
) :
|
||||||
IUserService {
|
IUserService {
|
||||||
|
|
||||||
private val maxLimit = 100
|
|
||||||
override suspend fun findAll(limit: Int?, offset: Long?): List<User> {
|
|
||||||
return userRepository.findAllByLimitAndByOffset(
|
|
||||||
min(limit ?: maxLimit, maxLimit),
|
|
||||||
offset ?: 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findById(id: Long): User =
|
|
||||||
userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<User> = userRepository.findByIds(ids)
|
|
||||||
|
|
||||||
override suspend fun findByName(name: String): List<User> = userRepository.findByName(name)
|
|
||||||
|
|
||||||
override suspend fun findByNameLocalUser(name: String): User {
|
|
||||||
return userRepository.findByNameAndDomain(name, Config.configData.domain)
|
|
||||||
?: throw UserNotFoundException("$name was not found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String?): User {
|
|
||||||
return userRepository.findByNameAndDomain(name, domain ?: Config.configData.domain)
|
|
||||||
?: throw UserNotFoundException("$name was not found.")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> =
|
|
||||||
userRepository.findByNameAndDomains(names)
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): User =
|
|
||||||
userRepository.findByUrl(url) ?: throw UserNotFoundException("$url was not found.")
|
|
||||||
|
|
||||||
override suspend fun findByUrls(urls: List<String>): List<User> = userRepository.findByUrls(urls)
|
|
||||||
|
|
||||||
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
override suspend fun usernameAlreadyUse(username: String): Boolean {
|
||||||
val findByNameAndDomain = userRepository.findByNameAndDomain(username, Config.configData.domain)
|
val findByNameAndDomain = userQueryService.findByNameAndDomain(username, Config.configData.domain)
|
||||||
return findByNameAndDomain != null
|
return findByNameAndDomain != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,19 +66,6 @@ class UserService(
|
||||||
return userRepository.save(userEntity)
|
return userRepository.save(userEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findFollowersById(id: Long): List<User> = userRepository.findFollowersById(id)
|
|
||||||
override suspend fun findFollowersByNameAndDomain(name: String, domain: String?): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowingById(id: Long): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowingByNameAndDomain(name: String, domain: String?): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO APのフォロー処理を作る
|
// TODO APのフォロー処理を作る
|
||||||
override suspend fun followRequest(id: Long, followerId: Long): Boolean {
|
override suspend fun followRequest(id: Long, followerId: Long): Boolean {
|
||||||
val user = userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
val user = userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
||||||
|
@ -127,14 +84,14 @@ class UserService(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun follow(id: Long, followerId: Long) {
|
override suspend fun follow(id: Long, followerId: Long) {
|
||||||
userRepository.createFollower(id, followerId)
|
followerQueryService.appendFollower(id, followerId)
|
||||||
if (userRepository.findFollowRequestsById(id, followerId)) {
|
if (userRepository.findFollowRequestsById(id, followerId)) {
|
||||||
userRepository.deleteFollowRequest(id, followerId)
|
userRepository.deleteFollowRequest(id, followerId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun unfollow(id: Long, followerId: Long): Boolean {
|
override suspend fun unfollow(id: Long, followerId: Long): Boolean {
|
||||||
userRepository.deleteFollower(id, followerId)
|
followerQueryService.removeFollower(id, followerId)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,6 +202,7 @@ class ExposedJobRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("CyclomaticComplexMethod")
|
||||||
private fun String?.parseJsonMap(): Map<String, Any> {
|
private fun String?.parseJsonMap(): Map<String, Any> {
|
||||||
this ?: return emptyMap()
|
this ?: return emptyMap()
|
||||||
return json.parseToJsonElement(this).jsonObject.mapValues { (_, el) ->
|
return json.parseToJsonElement(this).jsonObject.mapValues { (_, el) ->
|
||||||
|
@ -232,6 +233,7 @@ class ExposedJobRepository(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("CyclomaticComplexMethod")
|
||||||
private fun Map<String, Any>.stringify(): String? {
|
private fun Map<String, Any>.stringify(): String? {
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||||
</encoder>
|
</encoder>
|
||||||
</appender>
|
</appender>
|
||||||
<root level="TRACE">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT"/>
|
<appender-ref ref="STDOUT"/>
|
||||||
</root>
|
</root>
|
||||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
|
|
|
@ -2,41 +2,29 @@ package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
import dev.usbharu.hideout.domain.model.ap.JsonLd
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.user.toPem
|
import dev.usbharu.hideout.service.user.toPem
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.engine.mock.*
|
import io.ktor.client.engine.mock.*
|
||||||
import io.ktor.client.plugins.logging.*
|
import io.ktor.client.plugins.logging.*
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.mockito.kotlin.any
|
||||||
|
import org.mockito.kotlin.doAnswer
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import utils.TestTransaction
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class ActivityPubKtTest {
|
class ActivityPubKtTest {
|
||||||
@Test
|
@Test
|
||||||
fun HttpSignTest(): Unit = runBlocking {
|
fun HttpSignTest() {
|
||||||
val ktorKeyMap = KtorKeyMap(object : IUserRepository {
|
val userQueryService = mock<UserQueryService> {
|
||||||
override suspend fun save(user: User): User {
|
onBlocking { findByNameAndDomain(any(), any()) } doAnswer {
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findById(id: Long): User? {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByName(name: String): List<User> {
|
|
||||||
TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): User {
|
|
||||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
keyPairGenerator.initialize(1024)
|
keyPairGenerator.initialize(1024)
|
||||||
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
return User(
|
User(
|
||||||
1,
|
1,
|
||||||
"test",
|
"test",
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -51,63 +39,9 @@ class ActivityPubKtTest {
|
||||||
Instant.now()
|
Instant.now()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByDomain(domain: String): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
runBlocking {
|
||||||
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> {
|
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction)
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): User? {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrls(urls: List<String>): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAll(): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun createFollower(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollower(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowersById(id: Long): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun addFollowRequest(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollowRequest(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun nextId(): Long {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
val httpClient = HttpClient(
|
val httpClient = HttpClient(
|
||||||
MockEngine { httpRequestData ->
|
MockEngine { httpRequestData ->
|
||||||
|
@ -126,3 +60,4 @@ class ActivityPubKtTest {
|
||||||
httpClient.postAp("https://localhost", "test", JsonLd(emptyList()))
|
httpClient.postAp("https://localhost", "test", JsonLd(emptyList()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
package dev.usbharu.hideout.plugins
|
package dev.usbharu.hideout.plugins
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.user.toPem
|
import dev.usbharu.hideout.service.user.toPem
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.mockito.kotlin.any
|
||||||
|
import org.mockito.kotlin.doAnswer
|
||||||
|
import org.mockito.kotlin.mock
|
||||||
|
import utils.TestTransaction
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
|
@ -11,28 +15,12 @@ class KtorKeyMapTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun getPrivateKey() {
|
fun getPrivateKey() {
|
||||||
val ktorKeyMap = KtorKeyMap(object : IUserRepository {
|
val userQueryService = mock<UserQueryService> {
|
||||||
override suspend fun save(user: User): User {
|
onBlocking { findByNameAndDomain(any(), any()) } doAnswer {
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findById(id: Long): User? {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByIds(ids: List<Long>): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByName(name: String): List<User> {
|
|
||||||
TODO()
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByNameAndDomain(name: String, domain: String): User {
|
|
||||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
keyPairGenerator.initialize(1024)
|
keyPairGenerator.initialize(1024)
|
||||||
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
return User(
|
User(
|
||||||
1,
|
1,
|
||||||
"test",
|
"test",
|
||||||
"localhost",
|
"localhost",
|
||||||
|
@ -47,63 +35,8 @@ class KtorKeyMapTest {
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByDomain(domain: String): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
}
|
||||||
|
val ktorKeyMap = KtorKeyMap(userQueryService, TestTransaction)
|
||||||
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): User? {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUrls(urls: List<String>): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(id: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAll(): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAllByLimitAndByOffset(limit: Int, offset: Long): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun createFollower(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollower(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowersById(id: Long): List<User> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun addFollowRequest(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun deleteFollowRequest(id: Long, follower: Long) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findFollowRequestsById(id: Long, follower: Long): Boolean {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun nextId(): Long {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
ktorKeyMap.getPrivateKey("test")
|
ktorKeyMap.getPrivateKey("test")
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
import dev.usbharu.hideout.domain.model.hideout.form.UserLogin
|
||||||
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.exception.InvalidUsernameOrPasswordException
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.routing.api.internal.v1.auth
|
import dev.usbharu.hideout.routing.api.internal.v1.auth
|
||||||
|
import dev.usbharu.hideout.service.api.UserAuthApiService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
import dev.usbharu.hideout.service.auth.IJwtService
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
import dev.usbharu.hideout.service.core.IMetaService
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||||
|
@ -45,11 +47,12 @@ class SecurityKtTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||||
val userAuthService = mock<IUserAuthService> {
|
val jwtToken = JwtToken("Token", "RefreshToken")
|
||||||
onBlocking { verifyAccount(eq("testUser"), eq("password")) } doReturn true
|
val userAuthService = mock<UserAuthApiService> {
|
||||||
|
onBlocking { login(eq("testUser"), eq("password")) } doReturn jwtToken
|
||||||
}
|
}
|
||||||
val metaService = mock<IMetaService>()
|
val metaService = mock<IMetaService>()
|
||||||
val userRepository = mock<IUserRepository> {
|
val userQueryService = mock<UserQueryService> {
|
||||||
onBlocking { findByNameAndDomain(eq("testUser"), eq("example.com")) } doReturn User(
|
onBlocking { findByNameAndDomain(eq("testUser"), eq("example.com")) } doReturn User(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
name = "testUser",
|
name = "testUser",
|
||||||
|
@ -65,16 +68,12 @@ class SecurityKtTest {
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val jwtToken = JwtToken("Token", "RefreshToken")
|
|
||||||
val jwtService = mock<IJwtService> {
|
|
||||||
onBlocking { createToken(any()) } doReturn jwtToken
|
|
||||||
}
|
|
||||||
val jwkProvider = mock<JwkProvider>()
|
val jwkProvider = mock<JwkProvider>()
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(userAuthService, userRepository, jwtService)
|
auth(userAuthService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,23 +87,28 @@ class SecurityKtTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `login 存在しないユーザーのログインに失敗する`() = testApplication {
|
fun `login 存在しないユーザーのログインに失敗する`() {
|
||||||
|
testApplication {
|
||||||
environment {
|
environment {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||||
val userAuthService = mock<IUserAuthService> {
|
mock<IUserAuthService> {
|
||||||
onBlocking { verifyAccount(anyString(), anyString()) }.doReturn(false)
|
onBlocking { verifyAccount(anyString(), anyString()) }.doReturn(false)
|
||||||
}
|
}
|
||||||
val metaService = mock<IMetaService>()
|
val metaService = mock<IMetaService>()
|
||||||
val userRepository = mock<IUserRepository>()
|
mock<UserQueryService>()
|
||||||
val jwtService = mock<IJwtService>()
|
mock<IJwtService>()
|
||||||
val jwkProvider = mock<JwkProvider>()
|
val jwkProvider = mock<JwkProvider>()
|
||||||
|
val userAuthApiService = mock<UserAuthApiService> {
|
||||||
|
onBlocking { login(anyString(), anyString()) } doThrow InvalidUsernameOrPasswordException()
|
||||||
|
}
|
||||||
application {
|
application {
|
||||||
|
configureStatusPages()
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(userAuthService, userRepository, jwtService)
|
auth(userAuthApiService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.post("/login") {
|
client.post("/login") {
|
||||||
|
@ -114,6 +118,7 @@ class SecurityKtTest {
|
||||||
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
assertEquals(HttpStatusCode.Unauthorized, call.response.status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `login 不正なパスワードのログインに失敗する`() = testApplication {
|
fun `login 不正なパスワードのログインに失敗する`() = testApplication {
|
||||||
|
@ -121,18 +126,17 @@ class SecurityKtTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
Config.configData = ConfigData(url = "http://example.com", objectMapper = jacksonObjectMapper())
|
||||||
val userAuthService = mock<IUserAuthService> {
|
|
||||||
onBlocking { verifyAccount(anyString(), eq("InvalidPassword")) } doReturn false
|
|
||||||
}
|
|
||||||
val metaService = mock<IMetaService>()
|
val metaService = mock<IMetaService>()
|
||||||
val userRepository = mock<IUserRepository>()
|
|
||||||
val jwtService = mock<IJwtService>()
|
|
||||||
val jwkProvider = mock<JwkProvider>()
|
val jwkProvider = mock<JwkProvider>()
|
||||||
|
val userAuthApiService = mock<UserAuthApiService> {
|
||||||
|
onBlocking { login(anyString(), eq("InvalidPassword")) } doThrow InvalidUsernameOrPasswordException()
|
||||||
|
}
|
||||||
application {
|
application {
|
||||||
|
configureStatusPages()
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(userAuthService, userRepository, jwtService)
|
auth(userAuthApiService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.post("/login") {
|
client.post("/login") {
|
||||||
|
@ -153,7 +157,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check").apply {
|
client.get("/auth-check").apply {
|
||||||
|
@ -171,7 +175,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -191,7 +195,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -212,7 +216,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -271,7 +275,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +336,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -391,7 +395,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -450,7 +454,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -508,7 +512,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(jwkProvider, metaService)
|
configureSecurity(jwkProvider, metaService)
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), mock())
|
auth(mock())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/auth-check") {
|
client.get("/auth-check") {
|
||||||
|
@ -524,14 +528,14 @@ class SecurityKtTest {
|
||||||
environment {
|
environment {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val jwtService = mock<IJwtService> {
|
val jwtService = mock<UserAuthApiService> {
|
||||||
onBlocking { refreshToken(any()) }.doReturn(JwtToken("token", "refreshToken2"))
|
onBlocking { refreshToken(any()) }.doReturn(JwtToken("token", "refreshToken2"))
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), jwtService)
|
auth(jwtService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.post("/refresh-token") {
|
client.post("/refresh-token") {
|
||||||
|
@ -548,7 +552,7 @@ class SecurityKtTest {
|
||||||
environment {
|
environment {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val jwtService = mock<IJwtService> {
|
val jwtService = mock<UserAuthApiService> {
|
||||||
onBlocking { refreshToken(any()) } doThrow InvalidRefreshTokenException("Invalid Refresh Token")
|
onBlocking { refreshToken(any()) } doThrow InvalidRefreshTokenException("Invalid Refresh Token")
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
|
@ -556,7 +560,7 @@ class SecurityKtTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
auth(mock(), mock(), jwtService)
|
auth(jwtService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.post("/refresh-token") {
|
client.post("/refresh-token") {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import org.jetbrains.exposed.sql.Database
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils
|
import org.jetbrains.exposed.sql.SchemaUtils
|
||||||
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.transactions.TransactionManager
|
||||||
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
|
@ -37,6 +39,7 @@ class JwtRefreshTokenRepositoryImplTest {
|
||||||
transaction(db) {
|
transaction(db) {
|
||||||
SchemaUtils.drop(JwtRefreshTokens)
|
SchemaUtils.drop(JwtRefreshTokens)
|
||||||
}
|
}
|
||||||
|
TransactionManager.closeAndUnregister(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -53,10 +56,12 @@ class JwtRefreshTokenRepositoryImplTest {
|
||||||
val expiresAt = now.plus(10, ChronoUnit.MINUTES)
|
val expiresAt = now.plus(10, ChronoUnit.MINUTES)
|
||||||
|
|
||||||
val expect = JwtRefreshToken(1L, 2L, "refreshToken", now, expiresAt)
|
val expect = JwtRefreshToken(1L, 2L, "refreshToken", now, expiresAt)
|
||||||
|
newSuspendedTransaction {
|
||||||
repository.save(expect)
|
repository.save(expect)
|
||||||
val actual = repository.findById(1L)
|
val actual = repository.findById(1L)
|
||||||
assertEquals(expect, actual)
|
assertEquals(expect, actual)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `save 存在する場合はupdateする`() = runTest {
|
fun `save 存在する場合はupdateする`() = runTest {
|
||||||
|
@ -68,7 +73,7 @@ class JwtRefreshTokenRepositoryImplTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
transaction {
|
newSuspendedTransaction {
|
||||||
JwtRefreshTokens.insert {
|
JwtRefreshTokens.insert {
|
||||||
it[id] = 1L
|
it[id] = 1L
|
||||||
it[userId] = 2L
|
it[userId] = 2L
|
||||||
|
@ -76,8 +81,6 @@ class JwtRefreshTokenRepositoryImplTest {
|
||||||
it[createdAt] = Instant.now().toEpochMilli()
|
it[createdAt] = Instant.now().toEpochMilli()
|
||||||
it[expiresAt] = Instant.now().plus(10, ChronoUnit.MINUTES).toEpochMilli()
|
it[expiresAt] = Instant.now().plus(10, ChronoUnit.MINUTES).toEpochMilli()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
repository.save(
|
repository.save(
|
||||||
JwtRefreshToken(
|
JwtRefreshToken(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
|
@ -87,6 +90,8 @@ class JwtRefreshTokenRepositoryImplTest {
|
||||||
expiresAt = Instant.now().plus(10, ChronoUnit.MINUTES)
|
expiresAt = Instant.now().plus(10, ChronoUnit.MINUTES)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
transaction {
|
transaction {
|
||||||
val toJwtRefreshToken = JwtRefreshTokens.select { JwtRefreshTokens.id.eq(1L) }.single().toJwtRefreshToken()
|
val toJwtRefreshToken = JwtRefreshTokens.select { JwtRefreshTokens.id.eq(1L) }.single().toJwtRefreshToken()
|
||||||
assertEquals("refreshToken2", toJwtRefreshToken.refreshToken)
|
assertEquals("refreshToken2", toJwtRefreshToken.refreshToken)
|
||||||
|
|
|
@ -1,151 +0,0 @@
|
||||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
|
|
||||||
package dev.usbharu.hideout.repository
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
|
||||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.jetbrains.exposed.sql.Database
|
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.Assertions.assertIterableEquals
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import java.time.Clock
|
|
||||||
import java.time.Instant
|
|
||||||
import java.time.ZoneId
|
|
||||||
|
|
||||||
class UserRepositoryTest {
|
|
||||||
|
|
||||||
lateinit var db: Database
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun beforeEach() {
|
|
||||||
db = Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
|
|
||||||
transaction(db) {
|
|
||||||
SchemaUtils.create(Users)
|
|
||||||
SchemaUtils.create(UsersFollowers)
|
|
||||||
SchemaUtils.create(FollowRequests)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
transaction(db) {
|
|
||||||
SchemaUtils.drop(UsersFollowers)
|
|
||||||
SchemaUtils.drop(FollowRequests)
|
|
||||||
SchemaUtils.drop(Users)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `findFollowersById フォロワー一覧を取得`() = runTest {
|
|
||||||
val userRepository = UserRepository(
|
|
||||||
db,
|
|
||||||
object : IdGenerateService {
|
|
||||||
override suspend fun generateId(): Long {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val user = userRepository.save(
|
|
||||||
User(
|
|
||||||
id = 0L,
|
|
||||||
name = "test",
|
|
||||||
domain = "example.com",
|
|
||||||
screenName = "testUser",
|
|
||||||
description = "This user is test user.",
|
|
||||||
password = "https://example.com/inbox",
|
|
||||||
inbox = "",
|
|
||||||
outbox = "https://example.com/outbox",
|
|
||||||
url = "https://example.com",
|
|
||||||
publicKey = "",
|
|
||||||
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val follower = userRepository.save(
|
|
||||||
User(
|
|
||||||
id = 1L,
|
|
||||||
name = "follower",
|
|
||||||
domain = "follower.example.com",
|
|
||||||
screenName = "followerUser",
|
|
||||||
description = "This user is follower user.",
|
|
||||||
password = "",
|
|
||||||
inbox = "https://follower.example.com/inbox",
|
|
||||||
outbox = "https://follower.example.com/outbox",
|
|
||||||
url = "https://follower.example.com",
|
|
||||||
publicKey = "",
|
|
||||||
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val follower2 = userRepository.save(
|
|
||||||
User(
|
|
||||||
id = 3L,
|
|
||||||
name = "follower2",
|
|
||||||
domain = "follower2.example.com",
|
|
||||||
screenName = "followerUser2",
|
|
||||||
description = "This user is follower user 2.",
|
|
||||||
password = "",
|
|
||||||
inbox = "https://follower2.example.com/inbox",
|
|
||||||
outbox = "https://follower2.example.com/outbox",
|
|
||||||
url = "https://follower2.example.com",
|
|
||||||
publicKey = "",
|
|
||||||
createdAt = Instant.now(Clock.tickMillis(ZoneId.systemDefault()))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
userRepository.createFollower(user.id, follower.id)
|
|
||||||
userRepository.createFollower(user.id, follower2.id)
|
|
||||||
assertIterableEquals(listOf(follower, follower2), userRepository.findFollowersById(user.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `createFollower フォロワー追加`() = runTest {
|
|
||||||
val userRepository = UserRepository(
|
|
||||||
db,
|
|
||||||
object : IdGenerateService {
|
|
||||||
override suspend fun generateId(): Long {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val user = userRepository.save(
|
|
||||||
User(
|
|
||||||
0L,
|
|
||||||
"test",
|
|
||||||
"example.com",
|
|
||||||
"testUser",
|
|
||||||
"This user is test user.",
|
|
||||||
"https://example.com/inbox",
|
|
||||||
"",
|
|
||||||
"https://example.com/outbox",
|
|
||||||
"https://example.com",
|
|
||||||
publicKey = "",
|
|
||||||
createdAt = Instant.now()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val follower = userRepository.save(
|
|
||||||
User(
|
|
||||||
1L,
|
|
||||||
"follower",
|
|
||||||
"follower.example.com",
|
|
||||||
"followerUser",
|
|
||||||
"This user is follower user.",
|
|
||||||
"",
|
|
||||||
"https://follower.example.com/inbox",
|
|
||||||
"https://follower.example.com/outbox",
|
|
||||||
"https://follower.example.com",
|
|
||||||
publicKey = "",
|
|
||||||
createdAt = Instant.now()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
userRepository.createFollower(user.id, follower.id)
|
|
||||||
transaction {
|
|
||||||
val followerIds =
|
|
||||||
UsersFollowers.select { UsersFollowers.userId eq user.id }.map { it[UsersFollowers.followerId] }
|
|
||||||
assertIterableEquals(listOf(follower.id), followerIds)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,8 +11,8 @@ import dev.usbharu.hideout.domain.model.ap.Key
|
||||||
import dev.usbharu.hideout.domain.model.ap.Person
|
import dev.usbharu.hideout.domain.model.ap.Person
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.plugins.configureSerialization
|
import dev.usbharu.hideout.plugins.configureSerialization
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
import dev.usbharu.hideout.util.HttpUtil.JsonLd
|
import dev.usbharu.hideout.util.HttpUtil.JsonLd
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
|
@ -26,6 +26,7 @@ import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
import org.mockito.kotlin.eq
|
import org.mockito.kotlin.eq
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
|
import utils.TestTransaction
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
@ -62,8 +63,6 @@ class UsersAPTest {
|
||||||
)
|
)
|
||||||
person.context = listOf("https://www.w3.org/ns/activitystreams")
|
person.context = listOf("https://www.w3.org/ns/activitystreams")
|
||||||
|
|
||||||
val userService = mock<IUserService> {}
|
|
||||||
|
|
||||||
val activityPubUserService = mock<ActivityPubUserService> {
|
val activityPubUserService = mock<ActivityPubUserService> {
|
||||||
onBlocking { getPersonByName(anyString()) } doReturn person
|
onBlocking { getPersonByName(anyString()) } doReturn person
|
||||||
}
|
}
|
||||||
|
@ -71,7 +70,7 @@ class UsersAPTest {
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
routing {
|
routing {
|
||||||
usersAP(activityPubUserService, userService)
|
usersAP(activityPubUserService, mock(), mock(), TestTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/users/test") {
|
client.get("/users/test") {
|
||||||
|
@ -122,8 +121,6 @@ class UsersAPTest {
|
||||||
)
|
)
|
||||||
person.context = listOf("https://www.w3.org/ns/activitystreams")
|
person.context = listOf("https://www.w3.org/ns/activitystreams")
|
||||||
|
|
||||||
val userService = mock<IUserService> {}
|
|
||||||
|
|
||||||
val activityPubUserService = mock<ActivityPubUserService> {
|
val activityPubUserService = mock<ActivityPubUserService> {
|
||||||
onBlocking { getPersonByName(anyString()) } doReturn person
|
onBlocking { getPersonByName(anyString()) } doReturn person
|
||||||
}
|
}
|
||||||
|
@ -131,7 +128,7 @@ class UsersAPTest {
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
routing {
|
routing {
|
||||||
usersAP(activityPubUserService, userService)
|
usersAP(activityPubUserService, mock(), mock(), TestTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/users/test") {
|
client.get("/users/test") {
|
||||||
|
@ -174,8 +171,8 @@ class UsersAPTest {
|
||||||
environment {
|
environment {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val userService = mock<IUserService> {
|
val userService = mock<UserQueryService> {
|
||||||
onBlocking { findByNameLocalUser(eq("test")) } doReturn User(
|
onBlocking { findByNameAndDomain(eq("test"), anyString()) } doReturn User(
|
||||||
1L,
|
1L,
|
||||||
"test",
|
"test",
|
||||||
"example.com",
|
"example.com",
|
||||||
|
@ -192,7 +189,7 @@ class UsersAPTest {
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
routing {
|
routing {
|
||||||
usersAP(mock(), userService)
|
usersAP(mock(), userService, mock(), TestTransaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client.get("/users/test") {
|
client.get("/users/test") {
|
||||||
|
|
|
@ -6,7 +6,6 @@ import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostResponse
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
import dev.usbharu.hideout.domain.model.hideout.dto.UserResponse
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.plugins.configureSecurity
|
import dev.usbharu.hideout.plugins.configureSecurity
|
||||||
|
@ -78,7 +77,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +158,7 @@ class PostsTest {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,7 +199,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,7 +250,7 @@ class PostsTest {
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -308,7 +307,7 @@ class PostsTest {
|
||||||
}
|
}
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
@ -379,7 +378,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,7 +439,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -501,7 +500,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -562,7 +561,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -602,7 +601,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -642,7 +641,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,7 +681,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -722,7 +721,7 @@ class PostsTest {
|
||||||
configureSecurity(mock(), mock())
|
configureSecurity(mock(), mock())
|
||||||
routing {
|
routing {
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService, mock())
|
posts(postService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
import dev.usbharu.hideout.domain.model.job.DeliverPostJob
|
import dev.usbharu.hideout.domain.model.job.DeliverPostJob
|
||||||
|
import dev.usbharu.hideout.query.FollowerQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.client.engine.mock.*
|
import io.ktor.client.engine.mock.*
|
||||||
import kjob.core.job.JobProps
|
import kjob.core.job.JobProps
|
||||||
|
@ -55,7 +56,7 @@ class ActivityPubNoteServiceImplTest {
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val userService = mock<IUserService> {
|
val userQueryService = mock<UserQueryService> {
|
||||||
onBlocking { findById(eq(1L)) } doReturn User(
|
onBlocking { findById(eq(1L)) } doReturn User(
|
||||||
1L,
|
1L,
|
||||||
"test",
|
"test",
|
||||||
|
@ -69,11 +70,21 @@ class ActivityPubNoteServiceImplTest {
|
||||||
publicKey = "",
|
publicKey = "",
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
val followerQueryService = mock<FollowerQueryService> {
|
||||||
onBlocking { findFollowersById(eq(1L)) } doReturn followers
|
onBlocking { findFollowersById(eq(1L)) } doReturn followers
|
||||||
}
|
}
|
||||||
val jobQueueParentService = mock<JobQueueParentService>()
|
val jobQueueParentService = mock<JobQueueParentService>()
|
||||||
val activityPubNoteService =
|
val activityPubNoteService =
|
||||||
ActivityPubNoteServiceImpl(mock(), jobQueueParentService, userService, mock(), mock())
|
ActivityPubNoteServiceImpl(
|
||||||
|
mock(),
|
||||||
|
jobQueueParentService,
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
userQueryService,
|
||||||
|
followerQueryService,
|
||||||
|
mock()
|
||||||
|
)
|
||||||
val postEntity = Post(
|
val postEntity = Post(
|
||||||
1L,
|
1L,
|
||||||
1L,
|
1L,
|
||||||
|
@ -96,7 +107,15 @@ class ActivityPubNoteServiceImplTest {
|
||||||
respondOk()
|
respondOk()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
val activityPubNoteService = ActivityPubNoteServiceImpl(httpClient, mock(), mock(), mock(), mock())
|
val activityPubNoteService = ActivityPubNoteServiceImpl(
|
||||||
|
httpClient,
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
mock()
|
||||||
|
)
|
||||||
activityPubNoteService.createNoteJob(
|
activityPubNoteService.createNoteJob(
|
||||||
JobProps(
|
JobProps(
|
||||||
data = mapOf<String, Any>(
|
data = mapOf<String, Any>(
|
||||||
|
|
|
@ -9,6 +9,7 @@ import dev.usbharu.hideout.config.ConfigData
|
||||||
import dev.usbharu.hideout.domain.model.ap.*
|
import dev.usbharu.hideout.domain.model.ap.*
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
|
@ -23,6 +24,7 @@ import org.junit.jupiter.api.Test
|
||||||
import org.mockito.ArgumentMatchers.anyString
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
import utils.JsonObjectMapper
|
import utils.JsonObjectMapper
|
||||||
|
import utils.TestTransaction
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
||||||
class ActivityPubReceiveFollowServiceImplTest {
|
class ActivityPubReceiveFollowServiceImplTest {
|
||||||
|
@ -32,7 +34,7 @@ class ActivityPubReceiveFollowServiceImplTest {
|
||||||
onBlocking { schedule(eq(ReceiveFollowJob), any()) } doReturn Unit
|
onBlocking { schedule(eq(ReceiveFollowJob), any()) } doReturn Unit
|
||||||
}
|
}
|
||||||
val activityPubFollowService =
|
val activityPubFollowService =
|
||||||
ActivityPubReceiveFollowServiceImpl(jobQueueParentService, mock(), mock(), mock())
|
ActivityPubReceiveFollowServiceImpl(jobQueueParentService, mock(), mock(), mock(), mock(), TestTransaction)
|
||||||
activityPubFollowService.receiveFollow(
|
activityPubFollowService.receiveFollow(
|
||||||
Follow(
|
Follow(
|
||||||
emptyList(),
|
emptyList(),
|
||||||
|
@ -97,8 +99,8 @@ class ActivityPubReceiveFollowServiceImplTest {
|
||||||
val activityPubUserService = mock<ActivityPubUserService> {
|
val activityPubUserService = mock<ActivityPubUserService> {
|
||||||
onBlocking { fetchPerson(anyString(), any()) } doReturn person
|
onBlocking { fetchPerson(anyString(), any()) } doReturn person
|
||||||
}
|
}
|
||||||
val userService = mock<IUserService> {
|
val userQueryService = mock<UserQueryService> {
|
||||||
onBlocking { findByUrls(any()) } doReturn listOf(
|
onBlocking { findByUrl(eq("https://example.com")) } doReturn
|
||||||
User(
|
User(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
name = "test",
|
name = "test",
|
||||||
|
@ -110,7 +112,8 @@ class ActivityPubReceiveFollowServiceImplTest {
|
||||||
url = "https://example.com",
|
url = "https://example.com",
|
||||||
publicKey = "",
|
publicKey = "",
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
),
|
)
|
||||||
|
onBlocking { findByUrl(eq("https://follower.example.com")) } doReturn
|
||||||
User(
|
User(
|
||||||
id = 2L,
|
id = 2L,
|
||||||
name = "follower",
|
name = "follower",
|
||||||
|
@ -123,7 +126,9 @@ class ActivityPubReceiveFollowServiceImplTest {
|
||||||
publicKey = "",
|
publicKey = "",
|
||||||
createdAt = Instant.now()
|
createdAt = Instant.now()
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
val userService = mock<IUserService> {
|
||||||
onBlocking { followRequest(any(), any()) } doReturn false
|
onBlocking { followRequest(any(), any()) } doReturn false
|
||||||
}
|
}
|
||||||
val activityPubFollowService =
|
val activityPubFollowService =
|
||||||
|
@ -156,7 +161,9 @@ class ActivityPubReceiveFollowServiceImplTest {
|
||||||
)
|
)
|
||||||
respondOk()
|
respondOk()
|
||||||
}
|
}
|
||||||
)
|
),
|
||||||
|
userQueryService,
|
||||||
|
TestTransaction
|
||||||
)
|
)
|
||||||
activityPubFollowService.receiveFollowJob(
|
activityPubFollowService.receiveFollowJob(
|
||||||
JobProps(
|
JobProps(
|
||||||
|
|
|
@ -12,15 +12,17 @@ import dev.usbharu.hideout.domain.model.hideout.entity.JwtRefreshToken
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
import dev.usbharu.hideout.domain.model.hideout.form.RefreshToken
|
||||||
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
import dev.usbharu.hideout.exception.InvalidRefreshTokenException
|
||||||
|
import dev.usbharu.hideout.query.JwtRefreshTokenQueryService
|
||||||
|
import dev.usbharu.hideout.query.UserQueryService
|
||||||
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
import dev.usbharu.hideout.repository.IJwtRefreshTokenRepository
|
||||||
import dev.usbharu.hideout.service.core.IMetaService
|
import dev.usbharu.hideout.service.core.IMetaService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import dev.usbharu.hideout.util.Base64Util
|
import dev.usbharu.hideout.util.Base64Util
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertThrows
|
||||||
import org.mockito.kotlin.doReturn
|
import org.mockito.kotlin.doReturn
|
||||||
|
import org.mockito.kotlin.doThrow
|
||||||
import org.mockito.kotlin.mock
|
import org.mockito.kotlin.mock
|
||||||
import java.security.KeyPairGenerator
|
import java.security.KeyPairGenerator
|
||||||
import java.security.interfaces.RSAPrivateKey
|
import java.security.interfaces.RSAPrivateKey
|
||||||
|
@ -50,7 +52,7 @@ class JwtServiceImplTest {
|
||||||
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
||||||
onBlocking { generateId() } doReturn 1L
|
onBlocking { generateId() } doReturn 1L
|
||||||
}
|
}
|
||||||
val jwtService = JwtServiceImpl(metaService, refreshTokenRepository, mock())
|
val jwtService = JwtServiceImpl(metaService, refreshTokenRepository, mock(), mock())
|
||||||
val token = jwtService.createToken(
|
val token = jwtService.createToken(
|
||||||
User(
|
User(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
|
@ -93,6 +95,10 @@ class JwtServiceImplTest {
|
||||||
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
|
|
||||||
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
||||||
|
onBlocking { generateId() } doReturn 2L
|
||||||
|
}
|
||||||
|
|
||||||
|
val jwtRefreshTokenQueryService = mock<JwtRefreshTokenQueryService> {
|
||||||
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
userId = 1L,
|
userId = 1L,
|
||||||
|
@ -100,9 +106,8 @@ class JwtServiceImplTest {
|
||||||
createdAt = Instant.now().minus(60, ChronoUnit.MINUTES),
|
createdAt = Instant.now().minus(60, ChronoUnit.MINUTES),
|
||||||
expiresAt = Instant.now().plus(14, ChronoUnit.DAYS).minus(60, ChronoUnit.MINUTES)
|
expiresAt = Instant.now().plus(14, ChronoUnit.DAYS).minus(60, ChronoUnit.MINUTES)
|
||||||
)
|
)
|
||||||
onBlocking { generateId() } doReturn 2L
|
|
||||||
}
|
}
|
||||||
val userService = mock<IUserService> {
|
val userService = mock<UserQueryService> {
|
||||||
onBlocking { findById(1L) } doReturn User(
|
onBlocking { findById(1L) } doReturn User(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
name = "test",
|
name = "test",
|
||||||
|
@ -125,7 +130,7 @@ class JwtServiceImplTest {
|
||||||
Base64Util.encode(generateKeyPair.public.encoded)
|
Base64Util.encode(generateKeyPair.public.encoded)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val jwtService = JwtServiceImpl(metaService, refreshTokenRepository, userService)
|
val jwtService = JwtServiceImpl(metaService, refreshTokenRepository, userService, jwtRefreshTokenQueryService)
|
||||||
val refreshToken = jwtService.refreshToken(RefreshToken("refreshToken"))
|
val refreshToken = jwtService.refreshToken(RefreshToken("refreshToken"))
|
||||||
assertNotEquals("", refreshToken.token)
|
assertNotEquals("", refreshToken.token)
|
||||||
assertNotEquals("", refreshToken.refreshToken)
|
assertNotEquals("", refreshToken.refreshToken)
|
||||||
|
@ -147,16 +152,28 @@ class JwtServiceImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `refreshToken 無効なリフレッシュトークンは失敗する`() = runTest {
|
fun `refreshToken 無効なリフレッシュトークンは失敗する`() = runTest {
|
||||||
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
val refreshTokenRepository = mock<JwtRefreshTokenQueryService> {
|
||||||
onBlocking { findByToken("InvalidRefreshToken") } doReturn null
|
onBlocking { findByToken("InvalidRefreshToken") } doThrow NoSuchElementException()
|
||||||
}
|
}
|
||||||
val jwtService = JwtServiceImpl(mock(), refreshTokenRepository, mock())
|
val kid = UUID.randomUUID()
|
||||||
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
keyPairGenerator.initialize(2048)
|
||||||
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
|
|
||||||
|
val metaService = mock<IMetaService> {
|
||||||
|
onBlocking { getJwtMeta() } doReturn Jwt(
|
||||||
|
kid,
|
||||||
|
Base64Util.encode(generateKeyPair.private.encoded),
|
||||||
|
Base64Util.encode(generateKeyPair.public.encoded)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val jwtService = JwtServiceImpl(metaService, mock(), mock(), refreshTokenRepository)
|
||||||
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("InvalidRefreshToken")) }
|
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("InvalidRefreshToken")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `refreshToken 未来に作成されたリフレッシュトークンは失敗する`() = runTest {
|
fun `refreshToken 未来に作成されたリフレッシュトークンは失敗する`() = runTest {
|
||||||
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
val refreshTokenRepository = mock<JwtRefreshTokenQueryService> {
|
||||||
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
userId = 1L,
|
userId = 1L,
|
||||||
|
@ -165,13 +182,25 @@ class JwtServiceImplTest {
|
||||||
expiresAt = Instant.now().plus(10, ChronoUnit.MINUTES).plus(14, ChronoUnit.DAYS)
|
expiresAt = Instant.now().plus(10, ChronoUnit.MINUTES).plus(14, ChronoUnit.DAYS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val jwtService = JwtServiceImpl(mock(), refreshTokenRepository, mock())
|
val kid = UUID.randomUUID()
|
||||||
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
keyPairGenerator.initialize(2048)
|
||||||
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
|
|
||||||
|
val metaService = mock<IMetaService> {
|
||||||
|
onBlocking { getJwtMeta() } doReturn Jwt(
|
||||||
|
kid,
|
||||||
|
Base64Util.encode(generateKeyPair.private.encoded),
|
||||||
|
Base64Util.encode(generateKeyPair.public.encoded)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val jwtService = JwtServiceImpl(metaService, mock(), mock(), refreshTokenRepository)
|
||||||
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("refreshToken")) }
|
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("refreshToken")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `refreshToken 期限切れのリフレッシュトークンでは失敗する`() = runTest {
|
fun `refreshToken 期限切れのリフレッシュトークンでは失敗する`() = runTest {
|
||||||
val refreshTokenRepository = mock<IJwtRefreshTokenRepository> {
|
val refreshTokenRepository = mock<JwtRefreshTokenQueryService> {
|
||||||
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
onBlocking { findByToken("refreshToken") } doReturn JwtRefreshToken(
|
||||||
id = 1L,
|
id = 1L,
|
||||||
userId = 1L,
|
userId = 1L,
|
||||||
|
@ -180,7 +209,19 @@ class JwtServiceImplTest {
|
||||||
expiresAt = Instant.now().minus(16, ChronoUnit.DAYS)
|
expiresAt = Instant.now().minus(16, ChronoUnit.DAYS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val jwtService = JwtServiceImpl(mock(), refreshTokenRepository, mock())
|
val kid = UUID.randomUUID()
|
||||||
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
|
keyPairGenerator.initialize(2048)
|
||||||
|
val generateKeyPair = keyPairGenerator.generateKeyPair()
|
||||||
|
|
||||||
|
val metaService = mock<IMetaService> {
|
||||||
|
onBlocking { getJwtMeta() } doReturn Jwt(
|
||||||
|
kid,
|
||||||
|
Base64Util.encode(generateKeyPair.private.encoded),
|
||||||
|
Base64Util.encode(generateKeyPair.public.encoded)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val jwtService = JwtServiceImpl(metaService, mock(), mock(), refreshTokenRepository)
|
||||||
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("refreshToken")) }
|
assertThrows<InvalidRefreshTokenException> { jwtService.refreshToken(RefreshToken("refreshToken")) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertThrows
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
|
import utils.TestTransaction
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ class MetaServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { get() } doReturn meta
|
onBlocking { get() } doReturn meta
|
||||||
}
|
}
|
||||||
val metaService = MetaServiceImpl(metaRepository)
|
val metaService = MetaServiceImpl(metaRepository, TestTransaction)
|
||||||
val actual = metaService.getMeta()
|
val actual = metaService.getMeta()
|
||||||
assertEquals(meta, actual)
|
assertEquals(meta, actual)
|
||||||
}
|
}
|
||||||
|
@ -31,7 +32,7 @@ class MetaServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { get() } doReturn null
|
onBlocking { get() } doReturn null
|
||||||
}
|
}
|
||||||
val metaService = MetaServiceImpl(metaRepository)
|
val metaService = MetaServiceImpl(metaRepository, TestTransaction)
|
||||||
assertThrows<NotInitException> { metaService.getMeta() }
|
assertThrows<NotInitException> { metaService.getMeta() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ class MetaServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { save(any()) } doReturn Unit
|
onBlocking { save(any()) } doReturn Unit
|
||||||
}
|
}
|
||||||
val metaServiceImpl = MetaServiceImpl(metaRepository)
|
val metaServiceImpl = MetaServiceImpl(metaRepository, TestTransaction)
|
||||||
metaServiceImpl.updateMeta(meta)
|
metaServiceImpl.updateMeta(meta)
|
||||||
argumentCaptor<Meta> {
|
argumentCaptor<Meta> {
|
||||||
verify(metaRepository).save(capture())
|
verify(metaRepository).save(capture())
|
||||||
|
@ -55,7 +56,7 @@ class MetaServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { get() } doReturn meta
|
onBlocking { get() } doReturn meta
|
||||||
}
|
}
|
||||||
val metaService = MetaServiceImpl(metaRepository)
|
val metaService = MetaServiceImpl(metaRepository, TestTransaction)
|
||||||
val actual = metaService.getJwtMeta()
|
val actual = metaService.getJwtMeta()
|
||||||
assertEquals(meta.jwt, actual)
|
assertEquals(meta.jwt, actual)
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ class MetaServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { get() } doReturn null
|
onBlocking { get() } doReturn null
|
||||||
}
|
}
|
||||||
val metaService = MetaServiceImpl(metaRepository)
|
val metaService = MetaServiceImpl(metaRepository, TestTransaction)
|
||||||
assertThrows<NotInitException> { metaService.getJwtMeta() }
|
assertThrows<NotInitException> { metaService.getJwtMeta() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.mockito.kotlin.*
|
import org.mockito.kotlin.*
|
||||||
|
import utils.TestTransaction
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ class ServerInitialiseServiceImplTest {
|
||||||
onBlocking { get() } doReturn null
|
onBlocking { get() } doReturn null
|
||||||
onBlocking { save(any()) } doReturn Unit
|
onBlocking { save(any()) } doReturn Unit
|
||||||
}
|
}
|
||||||
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
|
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository, TestTransaction)
|
||||||
|
|
||||||
serverInitialiseServiceImpl.init()
|
serverInitialiseServiceImpl.init()
|
||||||
verify(metaRepository, times(1)).save(any())
|
verify(metaRepository, times(1)).save(any())
|
||||||
|
@ -32,7 +33,7 @@ class ServerInitialiseServiceImplTest {
|
||||||
val metaRepository = mock<IMetaRepository> {
|
val metaRepository = mock<IMetaRepository> {
|
||||||
onBlocking { get() } doReturn meta
|
onBlocking { get() } doReturn meta
|
||||||
}
|
}
|
||||||
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
|
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository, TestTransaction)
|
||||||
serverInitialiseServiceImpl.init()
|
serverInitialiseServiceImpl.init()
|
||||||
verify(metaRepository, times(0)).save(any())
|
verify(metaRepository, times(0)).save(any())
|
||||||
}
|
}
|
||||||
|
@ -45,7 +46,7 @@ class ServerInitialiseServiceImplTest {
|
||||||
onBlocking { save(any()) } doReturn Unit
|
onBlocking { save(any()) } doReturn Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository)
|
val serverInitialiseServiceImpl = ServerInitialiseServiceImpl(metaRepository, TestTransaction)
|
||||||
serverInitialiseServiceImpl.init()
|
serverInitialiseServiceImpl.init()
|
||||||
verify(metaRepository, times(1)).save(any())
|
verify(metaRepository, times(1)).save(any())
|
||||||
argumentCaptor<Meta> {
|
argumentCaptor<Meta> {
|
||||||
|
|
|
@ -28,7 +28,7 @@ class UserServiceTest {
|
||||||
onBlocking { hash(anyString()) } doReturn "hashedPassword"
|
onBlocking { hash(anyString()) } doReturn "hashedPassword"
|
||||||
onBlocking { generateKeyPair() } doReturn generateKeyPair
|
onBlocking { generateKeyPair() } doReturn generateKeyPair
|
||||||
}
|
}
|
||||||
val userService = UserService(userRepository, userAuthService, mock())
|
val userService = UserService(userRepository, userAuthService, mock(), mock(), mock())
|
||||||
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
||||||
verify(userRepository, times(1)).save(any())
|
verify(userRepository, times(1)).save(any())
|
||||||
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.entity.User> {
|
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.entity.User> {
|
||||||
|
@ -54,7 +54,7 @@ class UserServiceTest {
|
||||||
val userRepository = mock<IUserRepository> {
|
val userRepository = mock<IUserRepository> {
|
||||||
onBlocking { nextId() } doReturn 113345L
|
onBlocking { nextId() } doReturn 113345L
|
||||||
}
|
}
|
||||||
val userService = UserService(userRepository, mock(), mock())
|
val userService = UserService(userRepository, mock(), mock(), mock(), mock())
|
||||||
val user = RemoteUserCreateDto(
|
val user = RemoteUserCreateDto(
|
||||||
"test",
|
"test",
|
||||||
"example.com",
|
"example.com",
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Transaction
|
|
||||||
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
|
||||||
import org.junit.jupiter.api.extension.*
|
|
||||||
|
|
||||||
class DBResetInterceptor : BeforeAllCallback, AfterAllCallback, BeforeEachCallback, AfterEachCallback {
|
|
||||||
private lateinit var transactionAll: Transaction
|
|
||||||
private lateinit var transactionEach: Transaction
|
|
||||||
|
|
||||||
override fun beforeAll(context: ExtensionContext?) {
|
|
||||||
transactionAll = TransactionManager.manager.newTransaction()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterAll(context: ExtensionContext?) {
|
|
||||||
transactionAll.rollback()
|
|
||||||
transactionAll.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun beforeEach(context: ExtensionContext?) {
|
|
||||||
transactionEach = TransactionManager.manager.newTransaction(outerTransaction = transactionAll)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterEach(context: ExtensionContext?) {
|
|
||||||
transactionEach.rollback()
|
|
||||||
transactionEach.close()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package utils
|
|
||||||
|
|
||||||
import org.jetbrains.exposed.sql.Database
|
|
||||||
import org.jetbrains.exposed.sql.DatabaseConfig
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
|
||||||
|
|
||||||
@ExtendWith(DBResetInterceptor::class)
|
|
||||||
abstract class DatabaseTestBase {
|
|
||||||
companion object {
|
|
||||||
init {
|
|
||||||
Database.connect(
|
|
||||||
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1",
|
|
||||||
driver = "org.h2.Driver",
|
|
||||||
databaseConfig = DatabaseConfig { useNestedTransactions = true }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package utils
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.service.core.Transaction
|
||||||
|
|
||||||
|
object TestTransaction : Transaction {
|
||||||
|
override suspend fun <T> transaction(block: suspend () -> T): T = block()
|
||||||
|
}
|
Loading…
Reference in New Issue