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