mirror of https://github.com/usbharu/Hideout.git
Merge pull request #19 from usbharu/feature/refactor-service
Feature/refactor service
This commit is contained in:
commit
3fb5c0e19a
|
@ -14,6 +14,7 @@ import dev.usbharu.hideout.repository.IUserRepository
|
||||||
import dev.usbharu.hideout.routing.register
|
import dev.usbharu.hideout.routing.register
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.auth.IJwtService
|
import dev.usbharu.hideout.service.auth.IJwtService
|
||||||
|
@ -23,7 +24,6 @@ import dev.usbharu.hideout.service.core.IdGenerateService
|
||||||
import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
|
import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
import dev.usbharu.hideout.service.job.KJobJobQueueParentService
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserAuthService
|
import dev.usbharu.hideout.service.user.IUserAuthService
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import dev.usbharu.kjob.exposed.ExposedKJob
|
import dev.usbharu.kjob.exposed.ExposedKJob
|
||||||
|
@ -107,12 +107,12 @@ fun Application.parent() {
|
||||||
inject<JwkProvider>().value,
|
inject<JwkProvider>().value,
|
||||||
)
|
)
|
||||||
configureRouting(
|
configureRouting(
|
||||||
httpSignatureVerifyService = inject<HttpSignatureVerifyService>().value,
|
httpSignatureVerifyService = inject<HttpSignatureVerifyService>().value,
|
||||||
activityPubService = inject<ActivityPubService>().value,
|
activityPubService = inject<ActivityPubService>().value,
|
||||||
userService = inject<IUserService>().value,
|
userService = inject<IUserService>().value,
|
||||||
activityPubUserService = inject<ActivityPubUserService>().value,
|
activityPubUserService = inject<ActivityPubUserService>().value,
|
||||||
postService = inject<IPostService>().value,
|
postService = inject<IPostApiService>().value,
|
||||||
userApiService = inject<IUserApiService>().value,
|
userApiService = inject<IUserApiService>().value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,12 @@ import dev.usbharu.hideout.routing.activitypub.outbox
|
||||||
import dev.usbharu.hideout.routing.activitypub.usersAP
|
import dev.usbharu.hideout.routing.activitypub.usersAP
|
||||||
import dev.usbharu.hideout.routing.api.internal.v1.posts
|
import dev.usbharu.hideout.routing.api.internal.v1.posts
|
||||||
import dev.usbharu.hideout.routing.api.internal.v1.users
|
import dev.usbharu.hideout.routing.api.internal.v1.users
|
||||||
import dev.usbharu.hideout.routing.api.mastodon.v1.statuses
|
|
||||||
import dev.usbharu.hideout.routing.wellknown.webfinger
|
import dev.usbharu.hideout.routing.wellknown.webfinger
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||||
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.service.api.IUserApiService
|
import dev.usbharu.hideout.service.api.IUserApiService
|
||||||
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
import dev.usbharu.hideout.service.auth.HttpSignatureVerifyService
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
import dev.usbharu.hideout.service.user.IUserService
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
import io.ktor.server.plugins.autohead.*
|
import io.ktor.server.plugins.autohead.*
|
||||||
|
@ -19,12 +18,12 @@ import io.ktor.server.routing.*
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList")
|
||||||
fun Application.configureRouting(
|
fun Application.configureRouting(
|
||||||
httpSignatureVerifyService: HttpSignatureVerifyService,
|
httpSignatureVerifyService: HttpSignatureVerifyService,
|
||||||
activityPubService: ActivityPubService,
|
activityPubService: ActivityPubService,
|
||||||
userService: IUserService,
|
userService: IUserService,
|
||||||
activityPubUserService: ActivityPubUserService,
|
activityPubUserService: ActivityPubUserService,
|
||||||
postService: IPostService,
|
postService: IPostApiService,
|
||||||
userApiService: IUserApiService
|
userApiService: IUserApiService
|
||||||
) {
|
) {
|
||||||
install(AutoHeadResponse)
|
install(AutoHeadResponse)
|
||||||
routing {
|
routing {
|
||||||
|
@ -32,10 +31,6 @@ fun Application.configureRouting(
|
||||||
outbox()
|
outbox()
|
||||||
usersAP(activityPubUserService, userService)
|
usersAP(activityPubUserService, userService)
|
||||||
webfinger(userService)
|
webfinger(userService)
|
||||||
|
|
||||||
route("/api/v1") {
|
|
||||||
statuses(postService)
|
|
||||||
}
|
|
||||||
route("/api/internal/v1") {
|
route("/api/internal/v1") {
|
||||||
posts(postService)
|
posts(postService)
|
||||||
users(userService, userApiService)
|
users(userService, userApiService)
|
||||||
|
|
|
@ -1,11 +1,44 @@
|
||||||
package dev.usbharu.hideout.repository
|
package dev.usbharu.hideout.repository
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Suppress("LongParameterList")
|
||||||
interface IPostRepository {
|
interface IPostRepository {
|
||||||
suspend fun generateId(): Long
|
suspend fun generateId(): Long
|
||||||
suspend fun save(post: Post): Post
|
suspend fun save(post: Post): Post
|
||||||
suspend fun findOneById(id: Long): Post?
|
suspend fun findOneById(id: Long, userId: Long? = null): Post?
|
||||||
suspend fun findByUrl(url: String): Post?
|
suspend fun findByUrl(url: String): Post?
|
||||||
suspend fun delete(id: Long)
|
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?
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||||
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.koin.core.annotation.Single
|
import org.koin.core.annotation.Single
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : IPostRepository {
|
class PostRepositoryImpl(database: Database, private val idGenerateService: IdGenerateService) : IPostRepository {
|
||||||
|
@ -28,27 +29,41 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
||||||
|
|
||||||
override suspend fun save(post: Post): Post {
|
override suspend fun save(post: Post): Post {
|
||||||
return query {
|
return query {
|
||||||
Posts.insert {
|
val singleOrNull = Posts.select { Posts.id eq post.id }.singleOrNull()
|
||||||
it[id] = post.id
|
if (singleOrNull == null) {
|
||||||
it[userId] = post.userId
|
Posts.insert {
|
||||||
it[overview] = post.overview
|
it[id] = post.id
|
||||||
it[text] = post.text
|
it[userId] = post.userId
|
||||||
it[createdAt] = post.createdAt
|
it[overview] = post.overview
|
||||||
it[visibility] = post.visibility.ordinal
|
it[text] = post.text
|
||||||
it[url] = post.url
|
it[createdAt] = post.createdAt
|
||||||
it[repostId] = post.repostId
|
it[visibility] = post.visibility.ordinal
|
||||||
it[replyId] = post.replyId
|
it[url] = post.url
|
||||||
it[sensitive] = post.sensitive
|
it[repostId] = post.repostId
|
||||||
it[apId] = post.apId
|
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@query post
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findOneById(id: Long): Post? {
|
override suspend fun findOneById(id: Long, userId: Long?): Post? {
|
||||||
return query {
|
TODO("Not yet implemented")
|
||||||
Posts.select { Posts.id eq id }.singleOrNull()?.toPost()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): Post? {
|
override suspend fun findByUrl(url: String): Post? {
|
||||||
|
@ -62,6 +77,48 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
|
||||||
Posts.deleteWhere { Posts.id eq id }
|
Posts.deleteWhere { Posts.id eq id }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findAll(
|
||||||
|
since: Instant?,
|
||||||
|
until: Instant?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<Post> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUserNameAndDomain(
|
||||||
|
username: String,
|
||||||
|
s: String,
|
||||||
|
since: Instant?,
|
||||||
|
until: Instant?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<Post> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUserId(
|
||||||
|
idOrNull: Long,
|
||||||
|
since: Instant?,
|
||||||
|
until: Instant?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<Post> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun findByApId(id: String): Post? {
|
||||||
|
return query {
|
||||||
|
Posts.select { Posts.apId eq id }.singleOrNull()?.toPost()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Posts : Table() {
|
object Posts : Table() {
|
||||||
|
@ -81,16 +138,16 @@ object Posts : Table() {
|
||||||
|
|
||||||
fun ResultRow.toPost(): Post {
|
fun ResultRow.toPost(): Post {
|
||||||
return Post(
|
return Post(
|
||||||
id = this[Posts.id],
|
id = this[Posts.id],
|
||||||
userId = this[Posts.userId],
|
userId = this[Posts.userId],
|
||||||
overview = this[Posts.overview],
|
overview = this[Posts.overview],
|
||||||
text = this[Posts.text],
|
text = this[Posts.text],
|
||||||
createdAt = this[Posts.createdAt],
|
createdAt = this[Posts.createdAt],
|
||||||
visibility = Visibility.values().first { visibility -> visibility.ordinal == this[Posts.visibility] },
|
visibility = Visibility.values().first { visibility -> visibility.ordinal == this[Posts.visibility] },
|
||||||
url = this[Posts.url],
|
url = this[Posts.url],
|
||||||
repostId = this[Posts.repostId],
|
repostId = this[Posts.repostId],
|
||||||
replyId = this[Posts.replyId],
|
replyId = this[Posts.replyId],
|
||||||
sensitive = this[Posts.sensitive],
|
sensitive = this[Posts.sensitive],
|
||||||
apId = this[Posts.apId]
|
apId = this[Posts.apId]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
package dev.usbharu.hideout.routing.api.internal.v1
|
package dev.usbharu.hideout.routing.api.internal.v1
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.form.Post
|
import dev.usbharu.hideout.domain.model.hideout.form.Post
|
||||||
import dev.usbharu.hideout.exception.ParameterNotExistException
|
import dev.usbharu.hideout.exception.ParameterNotExistException
|
||||||
import dev.usbharu.hideout.exception.PostNotFoundException
|
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import dev.usbharu.hideout.util.AcctUtil
|
|
||||||
import dev.usbharu.hideout.util.InstantParseUtil
|
import dev.usbharu.hideout.util.InstantParseUtil
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
import io.ktor.server.application.*
|
import io.ktor.server.application.*
|
||||||
|
@ -18,7 +14,7 @@ import io.ktor.server.response.*
|
||||||
import io.ktor.server.routing.*
|
import io.ktor.server.routing.*
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
fun Route.posts(postService: IPostService) {
|
fun Route.posts(postApiService: IPostApiService) {
|
||||||
route("/posts") {
|
route("/posts") {
|
||||||
authenticate(TOKEN_AUTH) {
|
authenticate(TOKEN_AUTH) {
|
||||||
post {
|
post {
|
||||||
|
@ -26,15 +22,7 @@ fun Route.posts(postService: IPostService) {
|
||||||
val userId = principal.payload.getClaim("uid").asLong()
|
val userId = principal.payload.getClaim("uid").asLong()
|
||||||
|
|
||||||
val receive = call.receive<Post>()
|
val receive = call.receive<Post>()
|
||||||
val postCreateDto = PostCreateDto(
|
val create = postApiService.createPost(receive, userId)
|
||||||
text = receive.text,
|
|
||||||
overview = receive.overview,
|
|
||||||
visibility = receive.visibility,
|
|
||||||
repostId = receive.repostId,
|
|
||||||
repolyId = receive.replyId,
|
|
||||||
userId = userId
|
|
||||||
)
|
|
||||||
val create = postService.create(postCreateDto)
|
|
||||||
call.response.header("Location", create.url)
|
call.response.header("Location", create.url)
|
||||||
call.respond(HttpStatusCode.OK)
|
call.respond(HttpStatusCode.OK)
|
||||||
}
|
}
|
||||||
|
@ -47,16 +35,13 @@ fun Route.posts(postService: IPostService) {
|
||||||
val minId = call.request.queryParameters["minId"]?.toLong()
|
val minId = call.request.queryParameters["minId"]?.toLong()
|
||||||
val maxId = call.request.queryParameters["maxId"]?.toLong()
|
val maxId = call.request.queryParameters["maxId"]?.toLong()
|
||||||
val limit = call.request.queryParameters["limit"]?.toInt()
|
val limit = call.request.queryParameters["limit"]?.toInt()
|
||||||
call.respond(HttpStatusCode.OK, postService.findAll(since, until, minId, maxId, limit, userId))
|
call.respond(HttpStatusCode.OK, postApiService.getAll(since, until, minId, maxId, limit, userId))
|
||||||
}
|
}
|
||||||
get("/{id}") {
|
get("/{id}") {
|
||||||
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
val id = call.parameters["id"]?.toLong()
|
val id = call.parameters["id"]?.toLong()
|
||||||
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
||||||
val post = (
|
val post = postApiService.getById(id, userId)
|
||||||
postService.findByIdForUser(id, userId)
|
|
||||||
?: throw PostNotFoundException("$id was not found or is not authorized.")
|
|
||||||
)
|
|
||||||
call.respond(post)
|
call.respond(post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,28 +51,15 @@ fun Route.posts(postService: IPostService) {
|
||||||
get {
|
get {
|
||||||
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
val targetUserName = call.parameters["name"]
|
val targetUserName = call.parameters["name"]
|
||||||
?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.")
|
?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.")
|
||||||
val targetUserId = targetUserName.toLongOrNull()
|
val posts = postApiService.getByUser(targetUserName, userId = userId)
|
||||||
val posts = if (targetUserId == null) {
|
|
||||||
val acct = AcctUtil.parse(targetUserName)
|
|
||||||
postService.findByUserNameAndDomainForUser(
|
|
||||||
acct.username,
|
|
||||||
acct.domain ?: Config.configData.domain,
|
|
||||||
forUserId = userId
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
postService.findByUserIdForUser(targetUserId, forUserId = userId)
|
|
||||||
}
|
|
||||||
call.respond(posts)
|
call.respond(posts)
|
||||||
}
|
}
|
||||||
get("/{id}") {
|
get("/{id}") {
|
||||||
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
val id = call.parameters["id"]?.toLong()
|
val id = call.parameters["id"]?.toLong()
|
||||||
?: throw ParameterNotExistException("Parameter(name='postsId' does not exist.")
|
?: throw ParameterNotExistException("Parameter(name='postsId' does not exist.")
|
||||||
val post = (
|
val post = postApiService.getById(id, userId)
|
||||||
postService.findByIdForUser(id, userId)
|
|
||||||
?: throw PostNotFoundException("$id was not found or is not authorized.")
|
|
||||||
)
|
|
||||||
call.respond(post)
|
call.respond(post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,9 @@ fun Route.users(userService: IUserService, userApiService: IUserApiService) {
|
||||||
get {
|
get {
|
||||||
val userParameter = (
|
val userParameter = (
|
||||||
call.parameters["name"]
|
call.parameters["name"]
|
||||||
?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.")
|
?: throw ParameterNotExistException(
|
||||||
|
"Parameter(name='userName@domain') does not exist."
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if (userParameter.toLongOrNull() != null) {
|
if (userParameter.toLongOrNull() != null) {
|
||||||
return@get call.respond(userApiService.findById(userParameter.toLong()))
|
return@get call.respond(userApiService.findById(userParameter.toLong()))
|
||||||
|
@ -91,7 +93,9 @@ fun Route.users(userService: IUserService, userApiService: IUserApiService) {
|
||||||
get {
|
get {
|
||||||
val userParameter = (
|
val userParameter = (
|
||||||
call.parameters["name"]
|
call.parameters["name"]
|
||||||
?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.")
|
?: throw ParameterNotExistException(
|
||||||
|
"Parameter(name='userName@domain') does not exist."
|
||||||
|
)
|
||||||
)
|
)
|
||||||
if (userParameter.toLongOrNull() != null) {
|
if (userParameter.toLongOrNull() != null) {
|
||||||
return@get call.respond(userApiService.findFollowings(userParameter.toLong()))
|
return@get call.respond(userApiService.findFollowings(userParameter.toLong()))
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
package dev.usbharu.hideout.routing.api.mastodon.v1
|
package dev.usbharu.hideout.routing.api.mastodon.v1
|
||||||
|
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
// @Suppress("UnusedPrivateMember")
|
||||||
import io.ktor.server.routing.*
|
// fun Route.statuses(postService: IPostService) {
|
||||||
|
// // route("/statuses") {
|
||||||
@Suppress("UnusedPrivateMember")
|
// // post {
|
||||||
fun Route.statuses(postService: IPostService) {
|
// // val status: StatusForPost = call.receive()
|
||||||
// route("/statuses") {
|
// // val post = dev.usbharu.hideout.domain.model.hideout.form.Post(
|
||||||
// post {
|
// // userId = status.userId,
|
||||||
// val status: StatusForPost = call.receive()
|
// // createdAt = System.currentTimeMillis(),
|
||||||
// val post = dev.usbharu.hideout.domain.model.hideout.form.Post(
|
// // text = status.status,
|
||||||
// userId = status.userId,
|
// // visibility = 1
|
||||||
// createdAt = System.currentTimeMillis(),
|
// // )
|
||||||
// text = status.status,
|
// // postService.create(post)
|
||||||
// visibility = 1
|
// // call.respond(status)
|
||||||
// )
|
// // }
|
||||||
// postService.create(post)
|
// // }
|
||||||
// call.respond(status)
|
// }
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,11 +22,11 @@ import java.time.Instant
|
||||||
|
|
||||||
@Single
|
@Single
|
||||||
class ActivityPubNoteServiceImpl(
|
class ActivityPubNoteServiceImpl(
|
||||||
private val httpClient: HttpClient,
|
private val httpClient: HttpClient,
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val userService: IUserService,
|
private val userService: IUserService,
|
||||||
private val postRepository: IPostRepository,
|
private val postRepository: IPostRepository,
|
||||||
private val activityPubUserService: ActivityPubUserService
|
private val activityPubUserService: ActivityPubUserService
|
||||||
) : ActivityPubNoteService {
|
) : ActivityPubNoteService {
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
private val logger = LoggerFactory.getLogger(this::class.java)
|
||||||
|
@ -48,33 +48,44 @@ class ActivityPubNoteServiceImpl(
|
||||||
val actor = props[DeliverPostJob.actor]
|
val actor = props[DeliverPostJob.actor]
|
||||||
val postEntity = Config.configData.objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
val postEntity = Config.configData.objectMapper.readValue<Post>(props[DeliverPostJob.post])
|
||||||
val note = Note(
|
val note = Note(
|
||||||
name = "Note",
|
name = "Note",
|
||||||
id = postEntity.url,
|
id = postEntity.url,
|
||||||
attributedTo = actor,
|
attributedTo = actor,
|
||||||
content = postEntity.text,
|
content = postEntity.text,
|
||||||
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
|
published = Instant.ofEpochMilli(postEntity.createdAt).toString(),
|
||||||
to = listOf(public, actor + "/follower")
|
to = listOf(public, actor + "/follower")
|
||||||
)
|
)
|
||||||
val inbox = props[DeliverPostJob.inbox]
|
val inbox = props[DeliverPostJob.inbox]
|
||||||
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
|
logger.debug("createNoteJob: actor={}, note={}, inbox={}", actor, postEntity, inbox)
|
||||||
httpClient.postAp(
|
httpClient.postAp(
|
||||||
urlString = inbox,
|
urlString = inbox,
|
||||||
username = "$actor#pubkey",
|
username = "$actor#pubkey",
|
||||||
jsonLd = Create(
|
jsonLd = Create(
|
||||||
name = "Create Note",
|
name = "Create Note",
|
||||||
`object` = note,
|
`object` = note,
|
||||||
actor = note.attributedTo,
|
actor = note.attributedTo,
|
||||||
id = "${Config.configData.url}/create/note/${postEntity.id}"
|
id = "${Config.configData.url}/create/note/${postEntity.id}"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchNote(url: String, targetActor: String?): Note {
|
override suspend fun fetchNote(url: String, targetActor: String?): Note {
|
||||||
val post = postRepository.findByUrl(url)
|
val post = postRepository.findByUrl(url)
|
||||||
if (post != null) {
|
if (post != null) {
|
||||||
val user = userService.findById(post.userId)
|
return postToNote(post)
|
||||||
val reply = post.replyId?.let { postRepository.findOneById(it) }
|
}
|
||||||
return Note(
|
val response = httpClient.getAp(
|
||||||
|
url,
|
||||||
|
"$targetActor#pubkey"
|
||||||
|
)
|
||||||
|
val note = response.body<Note>()
|
||||||
|
return note(note, targetActor, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun postToNote(post: Post): Note {
|
||||||
|
val user = userService.findById(post.userId)
|
||||||
|
val reply = post.replyId?.let { postRepository.findOneById(it) }
|
||||||
|
return Note(
|
||||||
name = "Post",
|
name = "Post",
|
||||||
id = post.apId,
|
id = post.apId,
|
||||||
attributedTo = user.url,
|
attributedTo = user.url,
|
||||||
|
@ -84,38 +95,35 @@ class ActivityPubNoteServiceImpl(
|
||||||
sensitive = post.sensitive,
|
sensitive = post.sensitive,
|
||||||
cc = listOf(public, user.url + "/follower"),
|
cc = listOf(public, user.url + "/follower"),
|
||||||
inReplyTo = reply?.url
|
inReplyTo = reply?.url
|
||||||
)
|
|
||||||
}
|
|
||||||
val response = httpClient.getAp(
|
|
||||||
url,
|
|
||||||
"$targetActor#pubkey"
|
|
||||||
)
|
)
|
||||||
val note = response.body<Note>()
|
|
||||||
return note(note, targetActor, url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun ActivityPubNoteServiceImpl.note(
|
private suspend fun ActivityPubNoteServiceImpl.note(
|
||||||
note: Note,
|
note: Note,
|
||||||
targetActor: String?,
|
targetActor: String?,
|
||||||
url: String
|
url: String
|
||||||
): Note {
|
): Note {
|
||||||
|
val findByApId = postRepository.findByApId(url)
|
||||||
|
if (findByApId != null) {
|
||||||
|
return postToNote(findByApId)
|
||||||
|
}
|
||||||
val person = activityPubUserService.fetchPerson(
|
val person = activityPubUserService.fetchPerson(
|
||||||
note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"),
|
note.attributedTo ?: throw IllegalActivityPubObjectException("note.attributedTo is null"),
|
||||||
targetActor
|
targetActor
|
||||||
)
|
)
|
||||||
val user =
|
val user =
|
||||||
userService.findByUrl(person.url ?: throw IllegalActivityPubObjectException("person.url is null"))
|
userService.findByUrl(person.url ?: throw IllegalActivityPubObjectException("person.url is null"))
|
||||||
|
|
||||||
val visibility =
|
val visibility =
|
||||||
if (note.to.contains(public) && note.cc.contains(public)) {
|
if (note.to.contains(public) && note.cc.contains(public)) {
|
||||||
Visibility.PUBLIC
|
Visibility.PUBLIC
|
||||||
} else if (note.to.find { it.endsWith("/followers") } != null && note.cc.contains(public)) {
|
} else if (note.to.find { it.endsWith("/followers") } != null && note.cc.contains(public)) {
|
||||||
Visibility.UNLISTED
|
Visibility.UNLISTED
|
||||||
} else if (note.to.find { it.endsWith("/followers") } != null) {
|
} else if (note.to.find { it.endsWith("/followers") } != null) {
|
||||||
Visibility.FOLLOWERS
|
Visibility.FOLLOWERS
|
||||||
} else {
|
} else {
|
||||||
Visibility.DIRECT
|
Visibility.DIRECT
|
||||||
}
|
}
|
||||||
|
|
||||||
val reply = note.inReplyTo?.let {
|
val reply = note.inReplyTo?.let {
|
||||||
fetchNote(it, targetActor)
|
fetchNote(it, targetActor)
|
||||||
|
@ -123,27 +131,27 @@ class ActivityPubNoteServiceImpl(
|
||||||
}
|
}
|
||||||
|
|
||||||
postRepository.save(
|
postRepository.save(
|
||||||
Post(
|
Post(
|
||||||
id = postRepository.generateId(),
|
id = postRepository.generateId(),
|
||||||
userId = user.id,
|
userId = user.id,
|
||||||
overview = null,
|
overview = null,
|
||||||
text = note.content.orEmpty(),
|
text = note.content.orEmpty(),
|
||||||
createdAt = Instant.parse(note.published).toEpochMilli(),
|
createdAt = Instant.parse(note.published).toEpochMilli(),
|
||||||
visibility = visibility,
|
visibility = visibility,
|
||||||
url = note.id ?: url,
|
url = note.id ?: url,
|
||||||
repostId = null,
|
repostId = null,
|
||||||
replyId = reply?.id,
|
replyId = reply?.id,
|
||||||
sensitive = note.sensitive,
|
sensitive = note.sensitive,
|
||||||
apId = note.id ?: url,
|
apId = note.id ?: url,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return note
|
return note
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
override suspend fun fetchNote(note: Note, targetActor: String?): Note =
|
||||||
note(note, targetActor, note.id ?: throw IllegalArgumentException("note.id is null"))
|
note(note, targetActor, note.id ?: throw IllegalArgumentException("note.id is null"))
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
const val public: String = "https://www.w3.org/ns/activitystreams#Public"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package dev.usbharu.hideout.service.api
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
interface IPostApiService {
|
||||||
|
suspend fun createPost(postForm: dev.usbharu.hideout.domain.model.hideout.form.Post, userId: Long): Post
|
||||||
|
suspend fun getById(id: Long, userId: Long?): Post
|
||||||
|
suspend fun getAll(
|
||||||
|
since: Instant? = null,
|
||||||
|
until: Instant? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
maxId: Long? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
userId: Long? = null
|
||||||
|
): List<Post>
|
||||||
|
|
||||||
|
suspend fun getByUser(
|
||||||
|
nameOrId: String,
|
||||||
|
since: Instant? = null,
|
||||||
|
until: Instant? = null,
|
||||||
|
minId: Long? = null,
|
||||||
|
maxId: Long? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
userId: Long? = null
|
||||||
|
): List<Post>
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
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.entity.Post
|
||||||
|
import dev.usbharu.hideout.exception.PostNotFoundException
|
||||||
|
import dev.usbharu.hideout.repository.IPostRepository
|
||||||
|
import dev.usbharu.hideout.service.post.IPostService
|
||||||
|
import dev.usbharu.hideout.util.AcctUtil
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
import java.time.Instant
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.form.Post as FormPost
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class PostApiServiceImpl(
|
||||||
|
private val postService: IPostService,
|
||||||
|
private val postRepository: IPostRepository
|
||||||
|
) : IPostApiService {
|
||||||
|
override suspend fun createPost(postForm: FormPost, userId: Long): Post {
|
||||||
|
return postService.createLocal(
|
||||||
|
PostCreateDto(
|
||||||
|
text = postForm.text,
|
||||||
|
overview = postForm.overview,
|
||||||
|
visibility = postForm.visibility,
|
||||||
|
repostId = postForm.repostId,
|
||||||
|
repolyId = postForm.replyId,
|
||||||
|
userId = userId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getById(id: Long, userId: Long?): Post {
|
||||||
|
return postRepository.findOneById(id, userId)
|
||||||
|
?: throw PostNotFoundException("$id was not found or is not authorized.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getAll(
|
||||||
|
since: Instant?,
|
||||||
|
until: Instant?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<Post> = postRepository.findAll(since, until, minId, maxId, limit, userId)
|
||||||
|
|
||||||
|
override suspend fun getByUser(
|
||||||
|
nameOrId: String,
|
||||||
|
since: Instant?,
|
||||||
|
until: Instant?,
|
||||||
|
minId: Long?,
|
||||||
|
maxId: Long?,
|
||||||
|
limit: Int?,
|
||||||
|
userId: Long?
|
||||||
|
): List<Post> {
|
||||||
|
val idOrNull = nameOrId.toLongOrNull()
|
||||||
|
return if (idOrNull == null) {
|
||||||
|
val acct = AcctUtil.parse(nameOrId)
|
||||||
|
postRepository.findByUserNameAndDomain(
|
||||||
|
acct.username,
|
||||||
|
acct.domain
|
||||||
|
?: Config.configData.domain,
|
||||||
|
since,
|
||||||
|
until,
|
||||||
|
minId,
|
||||||
|
maxId,
|
||||||
|
limit,
|
||||||
|
userId
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
postRepository.findByUserId(idOrNull, since, until, minId, maxId, limit, userId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +1,8 @@
|
||||||
package dev.usbharu.hideout.service.post
|
package dev.usbharu.hideout.service.post
|
||||||
|
|
||||||
import dev.usbharu.hideout.config.Config
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
interface IPostService {
|
interface IPostService {
|
||||||
suspend fun create(post: Post): Post
|
suspend fun createLocal(post: PostCreateDto): Post
|
||||||
suspend fun create(post: PostCreateDto): Post
|
|
||||||
suspend fun findAll(
|
|
||||||
since: Instant? = null,
|
|
||||||
until: Instant? = null,
|
|
||||||
minId: Long? = null,
|
|
||||||
maxId: Long? = null,
|
|
||||||
limit: Int? = 10,
|
|
||||||
userId: Long? = null
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun findById(id: String): Post
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 権限を考慮して投稿を取得します。
|
|
||||||
*
|
|
||||||
* @param id
|
|
||||||
* @param userId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
suspend fun findByIdForUser(id: Long, userId: Long?): Post?
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 権限を考慮してユーザーの投稿を取得します。
|
|
||||||
*
|
|
||||||
* @param userId
|
|
||||||
* @param forUserId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
suspend fun findByUserIdForUser(
|
|
||||||
userId: Long,
|
|
||||||
since: Instant? = null,
|
|
||||||
until: Instant? = null,
|
|
||||||
minId: Long? = null,
|
|
||||||
maxId: Long? = null,
|
|
||||||
limit: Int? = null,
|
|
||||||
forUserId: Long? = null
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun findByUserNameAndDomainForUser(
|
|
||||||
userName: String,
|
|
||||||
domain: String = Config.configData.domain,
|
|
||||||
since: Instant? = null,
|
|
||||||
until: Instant? = null,
|
|
||||||
minId: Long? = null,
|
|
||||||
maxId: Long? = null,
|
|
||||||
limit: Int? = null,
|
|
||||||
forUserId: Long? = null
|
|
||||||
): List<Post>
|
|
||||||
|
|
||||||
suspend fun delete(id: String)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,130 +0,0 @@
|
||||||
package dev.usbharu.hideout.service.post
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
|
||||||
import dev.usbharu.hideout.repository.IPostRepository
|
|
||||||
import dev.usbharu.hideout.repository.Posts
|
|
||||||
import dev.usbharu.hideout.repository.UsersFollowers
|
|
||||||
import dev.usbharu.hideout.repository.toPost
|
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
|
|
||||||
import dev.usbharu.hideout.service.user.IUserService
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|
||||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.inSubQuery
|
|
||||||
import org.jetbrains.exposed.sql.and
|
|
||||||
import org.jetbrains.exposed.sql.orIfNotNull
|
|
||||||
import org.jetbrains.exposed.sql.orWhere
|
|
||||||
import org.jetbrains.exposed.sql.select
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
|
||||||
import org.koin.core.annotation.Single
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
@Single
|
|
||||||
class PostService(
|
|
||||||
private val postRepository: IPostRepository,
|
|
||||||
private val activityPubNoteService: ActivityPubNoteService,
|
|
||||||
private val userService: IUserService
|
|
||||||
) : IPostService {
|
|
||||||
|
|
||||||
private val logger = LoggerFactory.getLogger(this::class.java)
|
|
||||||
|
|
||||||
override suspend fun create(post: Post): Post {
|
|
||||||
logger.debug("create post={}", post)
|
|
||||||
val postEntity = postRepository.save(post)
|
|
||||||
activityPubNoteService.createNote(postEntity)
|
|
||||||
return post
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun create(post: PostCreateDto): Post {
|
|
||||||
logger.debug("create post={}", post)
|
|
||||||
val user = userService.findById(post.userId)
|
|
||||||
val id = postRepository.generateId()
|
|
||||||
val postEntity = Post(
|
|
||||||
id = id,
|
|
||||||
userId = user.id,
|
|
||||||
overview = null,
|
|
||||||
text = post.text,
|
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
|
||||||
visibility = Visibility.PUBLIC,
|
|
||||||
url = "${user.url}/posts/$id",
|
|
||||||
repostId = null,
|
|
||||||
replyId = null
|
|
||||||
)
|
|
||||||
postRepository.save(postEntity)
|
|
||||||
return postEntity
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findAll(
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
userId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
return transaction {
|
|
||||||
val select = Posts.select {
|
|
||||||
Posts.visibility.eq(Visibility.PUBLIC.ordinal)
|
|
||||||
}
|
|
||||||
if (userId != null) {
|
|
||||||
select.orWhere {
|
|
||||||
Posts.userId.inSubQuery(
|
|
||||||
UsersFollowers.slice(UsersFollowers.userId).select(UsersFollowers.followerId eq userId)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
select.map { it.toPost() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findById(id: String): Post {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByIdForUser(id: Long, userId: Long?): Post? {
|
|
||||||
return transaction {
|
|
||||||
val select = Posts.select(
|
|
||||||
Posts.id.eq(id).and(
|
|
||||||
Posts.visibility.eq(Visibility.PUBLIC.ordinal).orIfNotNull(
|
|
||||||
userId?.let {
|
|
||||||
Posts.userId.inSubQuery(
|
|
||||||
UsersFollowers.slice(UsersFollowers.userId).select(UsersFollowers.followerId.eq(userId))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
select.singleOrNull()?.toPost()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUserIdForUser(
|
|
||||||
userId: Long,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
forUserId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun findByUserNameAndDomainForUser(
|
|
||||||
userName: String,
|
|
||||||
domain: String,
|
|
||||||
since: Instant?,
|
|
||||||
until: Instant?,
|
|
||||||
minId: Long?,
|
|
||||||
maxId: Long?,
|
|
||||||
limit: Int?,
|
|
||||||
forUserId: Long?
|
|
||||||
): List<Post> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun delete(id: String) {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package dev.usbharu.hideout.service.post
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
||||||
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
|
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.repository.IPostRepository
|
||||||
|
import dev.usbharu.hideout.repository.IUserRepository
|
||||||
|
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
|
||||||
|
import org.koin.core.annotation.Single
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Single
|
||||||
|
class PostServiceImpl(
|
||||||
|
private val postRepository: IPostRepository,
|
||||||
|
private val userRepository: IUserRepository,
|
||||||
|
private val activityPubNoteService: ActivityPubNoteService
|
||||||
|
) : IPostService {
|
||||||
|
override suspend fun createLocal(post: PostCreateDto): Post {
|
||||||
|
val user = userRepository.findById(post.userId) ?: throw UserNotFoundException("${post.userId} was not found")
|
||||||
|
val id = postRepository.generateId()
|
||||||
|
val createPost = Post(
|
||||||
|
id = id,
|
||||||
|
userId = post.userId,
|
||||||
|
overview = post.overview,
|
||||||
|
text = post.text,
|
||||||
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
|
visibility = post.visibility,
|
||||||
|
url = "${user.url}/posts/$id",
|
||||||
|
repostId = null,
|
||||||
|
replyId = null
|
||||||
|
)
|
||||||
|
activityPubNoteService.createNote(createPost)
|
||||||
|
return internalCreate(createPost)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun internalCreate(post: Post): Post = postRepository.save(post)
|
||||||
|
}
|
|
@ -4,13 +4,12 @@ import com.auth0.jwt.interfaces.Claim
|
||||||
import com.auth0.jwt.interfaces.Payload
|
import com.auth0.jwt.interfaces.Payload
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.hideout.dto.PostCreateDto
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.plugins.configureSecurity
|
import dev.usbharu.hideout.plugins.configureSecurity
|
||||||
import dev.usbharu.hideout.plugins.configureSerialization
|
import dev.usbharu.hideout.plugins.configureSerialization
|
||||||
import dev.usbharu.hideout.service.post.IPostService
|
import dev.usbharu.hideout.service.api.IPostApiService
|
||||||
import io.ktor.client.request.*
|
import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
@ -42,24 +41,24 @@ class PostsTest {
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
),
|
),
|
||||||
Post(
|
Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 4322,
|
userId = 4322,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findAll(
|
getAll(
|
||||||
since = anyOrNull(),
|
since = anyOrNull(),
|
||||||
until = anyOrNull(),
|
until = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
userId = isNull()
|
userId = isNull()
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -118,15 +117,15 @@ class PostsTest {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findAll(
|
getAll(
|
||||||
since = anyOrNull(),
|
since = anyOrNull(),
|
||||||
until = anyOrNull(),
|
until = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
userId = isNotNull()
|
userId = isNotNull()
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -158,15 +157,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
12345,
|
12345,
|
||||||
1234,
|
1234,
|
||||||
text = "aaa",
|
text = "aaa",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(any(), anyOrNull()) } doReturn post
|
onBlocking { getById(any(), anyOrNull()) } doReturn post
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
@ -189,15 +188,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
12345,
|
12345,
|
||||||
1234,
|
1234,
|
||||||
text = "aaa",
|
text = "aaa",
|
||||||
visibility = Visibility.FOLLOWERS,
|
visibility = Visibility.FOLLOWERS,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(any(), isNotNull()) } doReturn post
|
onBlocking { getById(any(), isNotNull()) } doReturn post
|
||||||
}
|
}
|
||||||
val claim = mock<Claim> {
|
val claim = mock<Claim> {
|
||||||
on { asLong() } doReturn 1234
|
on { asLong() } doReturn 1234
|
||||||
|
@ -239,17 +238,18 @@ class PostsTest {
|
||||||
val payload = mock<Payload> {
|
val payload = mock<Payload> {
|
||||||
on { getClaim(eq("uid")) } doReturn claim
|
on { getClaim(eq("uid")) } doReturn claim
|
||||||
}
|
}
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { create(any<PostCreateDto>()) } doAnswer {
|
onBlocking { createPost(any(), any()) } doAnswer {
|
||||||
val argument = it.getArgument<PostCreateDto>(0)
|
val argument = it.getArgument<dev.usbharu.hideout.domain.model.hideout.form.Post>(0)
|
||||||
|
val userId = it.getArgument<Long>(1)
|
||||||
Post(
|
Post(
|
||||||
123L,
|
123L,
|
||||||
argument.userId,
|
userId,
|
||||||
null,
|
null,
|
||||||
argument.text,
|
argument.text,
|
||||||
Instant.now().toEpochMilli(),
|
Instant.now().toEpochMilli(),
|
||||||
Visibility.PUBLIC,
|
Visibility.PUBLIC,
|
||||||
"https://example.com"
|
"https://example.com"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,9 +279,9 @@ class PostsTest {
|
||||||
assertEquals(HttpStatusCode.OK, status)
|
assertEquals(HttpStatusCode.OK, status)
|
||||||
assertEquals("https://example.com", headers["Location"])
|
assertEquals("https://example.com", headers["Location"])
|
||||||
}
|
}
|
||||||
argumentCaptor<PostCreateDto> {
|
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.form.Post> {
|
||||||
verify(postService).create(capture())
|
verify(postService).createPost(capture(), any())
|
||||||
assertEquals(PostCreateDto("test", userId = 1234), firstValue)
|
assertEquals(dev.usbharu.hideout.domain.model.hideout.form.Post("test"), firstValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,25 +299,25 @@ class PostsTest {
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
),
|
),
|
||||||
Post(
|
Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findByUserIdForUser(
|
getByUser(
|
||||||
userId = any(),
|
nameOrId = any(),
|
||||||
since = anyOrNull(),
|
since = anyOrNull(),
|
||||||
until = anyOrNull(),
|
until = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
forUserId = anyOrNull()
|
userId = anyOrNull()
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -351,26 +351,25 @@ class PostsTest {
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
),
|
),
|
||||||
Post(
|
Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findByUserNameAndDomainForUser(
|
getByUser(
|
||||||
userName = eq("test1"),
|
nameOrId = eq("test1"),
|
||||||
domain = eq(Config.configData.domain),
|
since = anyOrNull(),
|
||||||
since = anyOrNull(),
|
until = anyOrNull(),
|
||||||
until = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
userId = anyOrNull()
|
||||||
forUserId = anyOrNull()
|
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -404,26 +403,25 @@ class PostsTest {
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
),
|
),
|
||||||
Post(
|
Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findByUserNameAndDomainForUser(
|
getByUser(
|
||||||
userName = eq("test1"),
|
nameOrId = eq("test1@example.com"),
|
||||||
domain = eq("example.com"),
|
since = anyOrNull(),
|
||||||
since = anyOrNull(),
|
until = anyOrNull(),
|
||||||
until = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
userId = anyOrNull()
|
||||||
forUserId = anyOrNull()
|
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -457,26 +455,25 @@ class PostsTest {
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/1"
|
url = "https://example.com/posts/1"
|
||||||
),
|
),
|
||||||
Post(
|
Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking {
|
onBlocking {
|
||||||
findByUserNameAndDomainForUser(
|
getByUser(
|
||||||
userName = eq("test1"),
|
nameOrId = eq("@test1@example.com"),
|
||||||
domain = eq("example.com"),
|
since = anyOrNull(),
|
||||||
since = anyOrNull(),
|
until = anyOrNull(),
|
||||||
until = anyOrNull(),
|
minId = anyOrNull(),
|
||||||
minId = anyOrNull(),
|
maxId = anyOrNull(),
|
||||||
maxId = anyOrNull(),
|
limit = anyOrNull(),
|
||||||
limit = anyOrNull(),
|
userId = anyOrNull()
|
||||||
forUserId = anyOrNull()
|
|
||||||
)
|
)
|
||||||
} doReturn posts
|
} doReturn posts
|
||||||
}
|
}
|
||||||
|
@ -502,15 +499,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(eq(12345L), anyOrNull()) } doReturn post
|
onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
@ -534,15 +531,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(eq(12345L), anyOrNull()) } doReturn post
|
onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
@ -566,15 +563,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(eq(12345L), anyOrNull()) } doReturn post
|
onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
@ -598,15 +595,15 @@ class PostsTest {
|
||||||
config = ApplicationConfig("empty.conf")
|
config = ApplicationConfig("empty.conf")
|
||||||
}
|
}
|
||||||
val post = Post(
|
val post = Post(
|
||||||
id = 123456,
|
id = 123456,
|
||||||
userId = 1,
|
userId = 1,
|
||||||
text = "test2",
|
text = "test2",
|
||||||
visibility = Visibility.PUBLIC,
|
visibility = Visibility.PUBLIC,
|
||||||
createdAt = Instant.now().toEpochMilli(),
|
createdAt = Instant.now().toEpochMilli(),
|
||||||
url = "https://example.com/posts/2"
|
url = "https://example.com/posts/2"
|
||||||
)
|
)
|
||||||
val postService = mock<IPostService> {
|
val postService = mock<IPostApiService> {
|
||||||
onBlocking { findByIdForUser(eq(12345L), anyOrNull()) } doReturn post
|
onBlocking { getById(eq(12345L), anyOrNull()) } doReturn post
|
||||||
}
|
}
|
||||||
application {
|
application {
|
||||||
configureSerialization()
|
configureSerialization()
|
||||||
|
|
|
@ -1,166 +0,0 @@
|
||||||
@file:OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
|
|
||||||
package dev.usbharu.hideout.service.post
|
|
||||||
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
|
||||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
|
||||||
import dev.usbharu.hideout.repository.Posts
|
|
||||||
import dev.usbharu.hideout.repository.UsersFollowers
|
|
||||||
import dev.usbharu.hideout.service.core.TwitterSnowflakeIdGenerateService
|
|
||||||
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.batchInsert
|
|
||||||
import org.jetbrains.exposed.sql.insert
|
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
|
||||||
import org.junit.jupiter.api.AfterEach
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.mockito.kotlin.mock
|
|
||||||
import java.time.Instant
|
|
||||||
import kotlin.test.assertContentEquals
|
|
||||||
|
|
||||||
class PostServiceTest {
|
|
||||||
|
|
||||||
lateinit var db: Database
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
fun setUp() {
|
|
||||||
db = Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
|
|
||||||
transaction(db) {
|
|
||||||
SchemaUtils.create(Posts)
|
|
||||||
connection.prepareStatement("SET REFERENTIAL_INTEGRITY FALSE", false).executeUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
fun tearDown() {
|
|
||||||
transaction(db) {
|
|
||||||
SchemaUtils.drop(Posts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `findAll 公開投稿を取得できる`() = runTest {
|
|
||||||
val postService = PostService(mock(), mock(), mock())
|
|
||||||
|
|
||||||
suspend fun createPost(userId: Long, text: String, visibility: Visibility = Visibility.PUBLIC): Post {
|
|
||||||
return Post(
|
|
||||||
TwitterSnowflakeIdGenerateService.generateId(),
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
text,
|
|
||||||
Instant.now().toEpochMilli(),
|
|
||||||
visibility,
|
|
||||||
"https://example.com${(userId.toString() + text).hashCode()}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val userA: Long = 1
|
|
||||||
val userB: Long = 2
|
|
||||||
|
|
||||||
val posts = listOf(
|
|
||||||
createPost(userA, "hello"),
|
|
||||||
createPost(userA, "hello1"),
|
|
||||||
createPost(userA, "hello2"),
|
|
||||||
createPost(userA, "hello3"),
|
|
||||||
createPost(userA, "hello4"),
|
|
||||||
createPost(userA, "hello5"),
|
|
||||||
createPost(userA, "hello6"),
|
|
||||||
createPost(userB, "good bay ", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay1", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay2", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay3", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay4", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay5", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay6", Visibility.FOLLOWERS),
|
|
||||||
)
|
|
||||||
|
|
||||||
transaction {
|
|
||||||
Posts.batchInsert(posts) {
|
|
||||||
this[Posts.id] = it.id
|
|
||||||
this[Posts.userId] = it.userId
|
|
||||||
this[Posts.overview] = it.overview
|
|
||||||
this[Posts.text] = it.text
|
|
||||||
this[Posts.createdAt] = it.createdAt
|
|
||||||
this[Posts.visibility] = it.visibility.ordinal
|
|
||||||
this[Posts.url] = it.url
|
|
||||||
this[Posts.replyId] = it.replyId
|
|
||||||
this[Posts.repostId] = it.repostId
|
|
||||||
this[Posts.sensitive] = it.sensitive
|
|
||||||
this[Posts.apId] = it.apId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val expect = posts.filter { it.visibility == Visibility.PUBLIC }
|
|
||||||
|
|
||||||
val actual = postService.findAll()
|
|
||||||
assertContentEquals(expect, actual)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `findAll フォロー限定投稿を見れる`() = runTest {
|
|
||||||
val postService = PostService(mock(), mock(), mock())
|
|
||||||
|
|
||||||
suspend fun createPost(userId: Long, text: String, visibility: Visibility = Visibility.PUBLIC): Post {
|
|
||||||
return Post(
|
|
||||||
TwitterSnowflakeIdGenerateService.generateId(),
|
|
||||||
userId,
|
|
||||||
null,
|
|
||||||
text,
|
|
||||||
Instant.now().toEpochMilli(),
|
|
||||||
visibility,
|
|
||||||
"https://example.com${(userId.toString() + text).hashCode()}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val userA: Long = 1
|
|
||||||
val userB: Long = 2
|
|
||||||
|
|
||||||
val posts = listOf(
|
|
||||||
createPost(userA, "hello"),
|
|
||||||
createPost(userA, "hello1"),
|
|
||||||
createPost(userA, "hello2"),
|
|
||||||
createPost(userA, "hello3"),
|
|
||||||
createPost(userA, "hello4"),
|
|
||||||
createPost(userA, "hello5"),
|
|
||||||
createPost(userA, "hello6"),
|
|
||||||
createPost(userB, "good bay ", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay1", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay2", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay3", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay4", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay5", Visibility.FOLLOWERS),
|
|
||||||
createPost(userB, "good bay6", Visibility.FOLLOWERS),
|
|
||||||
)
|
|
||||||
|
|
||||||
transaction(db) {
|
|
||||||
SchemaUtils.create(UsersFollowers)
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction {
|
|
||||||
Posts.batchInsert(posts) {
|
|
||||||
this[Posts.id] = it.id
|
|
||||||
this[Posts.userId] = it.userId
|
|
||||||
this[Posts.overview] = it.overview
|
|
||||||
this[Posts.text] = it.text
|
|
||||||
this[Posts.createdAt] = it.createdAt
|
|
||||||
this[Posts.visibility] = it.visibility.ordinal
|
|
||||||
this[Posts.url] = it.url
|
|
||||||
this[Posts.replyId] = it.replyId
|
|
||||||
this[Posts.repostId] = it.repostId
|
|
||||||
this[Posts.sensitive] = it.sensitive
|
|
||||||
this[Posts.apId] = it.apId
|
|
||||||
}
|
|
||||||
UsersFollowers.insert {
|
|
||||||
it[id] = 100L
|
|
||||||
it[userId] = userB
|
|
||||||
it[followerId] = userA
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val actual = postService.findAll(userId = userA)
|
|
||||||
assertContentEquals(posts, actual)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue