feat: APIから投稿できるように

This commit is contained in:
usbharu 2023-04-21 18:24:13 +09:00
parent 8ccf2546b4
commit 42dc455873
10 changed files with 80 additions and 22 deletions

View File

@ -7,13 +7,13 @@ import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.config.ConfigData import dev.usbharu.hideout.config.ConfigData
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
import dev.usbharu.hideout.plugins.* import dev.usbharu.hideout.plugins.*
import dev.usbharu.hideout.repository.IUserAuthRepository import dev.usbharu.hideout.repository.*
import dev.usbharu.hideout.repository.IUserRepository
import dev.usbharu.hideout.repository.UserAuthRepository
import dev.usbharu.hideout.repository.UserRepository
import dev.usbharu.hideout.routing.register import dev.usbharu.hideout.routing.register
import dev.usbharu.hideout.service.IPostService
import dev.usbharu.hideout.service.IUserAuthService import dev.usbharu.hideout.service.IUserAuthService
import dev.usbharu.hideout.service.TwitterSnowflakeIdGenerateService
import dev.usbharu.hideout.service.activitypub.* import dev.usbharu.hideout.service.activitypub.*
import dev.usbharu.hideout.service.impl.PostService
import dev.usbharu.hideout.service.impl.UserAuthService import dev.usbharu.hideout.service.impl.UserAuthService
import dev.usbharu.hideout.service.impl.UserService import dev.usbharu.hideout.service.impl.UserService
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
@ -81,6 +81,8 @@ fun Application.parent() {
single<UserService> { UserService(get()) } single<UserService> { UserService(get()) }
single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) } single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) }
single<ActivityPubNoteService> { ActivityPubNoteServiceImpl(get(), get(), get()) } single<ActivityPubNoteService> { ActivityPubNoteServiceImpl(get(), get(), get()) }
single<IPostService> { PostService(get(), get()) }
single<IPostRepository> { PostRepositoryImpl(get(), TwitterSnowflakeIdGenerateService) }
} }
@ -94,7 +96,8 @@ fun Application.parent() {
inject<HttpSignatureVerifyService>().value, inject<HttpSignatureVerifyService>().value,
inject<ActivityPubService>().value, inject<ActivityPubService>().value,
inject<UserService>().value, inject<UserService>().value,
inject<ActivityPubUserService>().value inject<ActivityPubUserService>().value,
inject<IPostService>().value
) )
} }

View File

@ -13,6 +13,7 @@ object Posts : Table() {
val url = varchar("url", 500) val url = varchar("url", 500)
val repostId = long("repostId").references(id).nullable() val repostId = long("repostId").references(id).nullable()
val replyId = long("replyId").references(id).nullable() val replyId = long("replyId").references(id).nullable()
override val primaryKey: PrimaryKey = PrimaryKey(id)
} }
data class Post( data class Post(
@ -21,7 +22,6 @@ data class Post(
val text: String, val text: String,
val createdAt: Long, val createdAt: Long,
val visibility: Int, val visibility: Int,
val url: String,
val repostId: Long? = null, val repostId: Long? = null,
val replyId: Long? = null val replyId: Long? = null
) )

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.domain.model package dev.usbharu.hideout.domain.model
import org.jetbrains.exposed.dao.id.LongIdTable import org.jetbrains.exposed.dao.id.LongIdTable
import org.jetbrains.exposed.sql.ResultRow
data class User( data class User(
val name: String, val name: String,
@ -47,3 +48,16 @@ object Users : LongIdTable("users") {
uniqueIndex(name, domain) uniqueIndex(name, domain)
} }
} }
fun ResultRow.toUser(): User {
return User(
this[Users.name],
this[Users.domain],
this[Users.screenName],
this[Users.description],
this[Users.inbox],
this[Users.outbox],
this[Users.url]
)
}

View File

@ -0,0 +1,6 @@
package dev.usbharu.hideout.domain.model.api
data class StatusForPost(
val status:String,
val userId:Long
)

View File

@ -3,7 +3,9 @@ package dev.usbharu.hideout.plugins
import dev.usbharu.hideout.routing.activitypub.inbox import dev.usbharu.hideout.routing.activitypub.inbox
import dev.usbharu.hideout.routing.activitypub.outbox import dev.usbharu.hideout.routing.activitypub.outbox
import dev.usbharu.hideout.routing.activitypub.usersAP import dev.usbharu.hideout.routing.activitypub.usersAP
import dev.usbharu.hideout.routing.api.v1.statuses
import dev.usbharu.hideout.routing.wellknown.webfinger import dev.usbharu.hideout.routing.wellknown.webfinger
import dev.usbharu.hideout.service.IPostService
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.impl.UserService import dev.usbharu.hideout.service.impl.UserService
@ -15,8 +17,9 @@ import io.ktor.server.routing.*
fun Application.configureRouting( fun Application.configureRouting(
httpSignatureVerifyService: HttpSignatureVerifyService, httpSignatureVerifyService: HttpSignatureVerifyService,
activityPubService: ActivityPubService, activityPubService: ActivityPubService,
userService:UserService, userService: UserService,
activityPubUserService: ActivityPubUserService activityPubUserService: ActivityPubUserService,
postService: IPostService
) { ) {
install(AutoHeadResponse) install(AutoHeadResponse)
routing { routing {
@ -24,5 +27,10 @@ fun Application.configureRouting(
outbox() outbox()
usersAP(activityPubUserService) usersAP(activityPubUserService)
webfinger(userService) webfinger(userService)
route("api/v1") {
statuses(postService)
}
} }
} }

View File

@ -1,9 +1,7 @@
package dev.usbharu.hideout.repository package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.Post import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.domain.model.PostEntity import dev.usbharu.hideout.domain.model.*
import dev.usbharu.hideout.domain.model.Posts
import dev.usbharu.hideout.domain.model.toPost
import dev.usbharu.hideout.service.IdGenerateService import dev.usbharu.hideout.service.IdGenerateService
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
@ -26,6 +24,8 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
return query { return query {
val generateId = idGenerateService.generateId() val generateId = idGenerateService.generateId()
val name = Users.select { Users.id eq post.userId }.single().toUser().name
val postUrl = Config.configData.url + "/users/$name/posts/$generateId"
Posts.insert { Posts.insert {
it[id] = generateId it[id] = generateId
it[userId] = post.userId it[userId] = post.userId
@ -33,7 +33,7 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
it[text] = post.text it[text] = post.text
it[createdAt] = post.createdAt it[createdAt] = post.createdAt
it[visibility] = post.visibility it[visibility] = post.visibility
it[url] = post.url it[url] = postUrl
it[repostId] = post.repostId it[repostId] = post.repostId
it[replyId] = post.replyId it[replyId] = post.replyId
} }
@ -44,7 +44,7 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
post.text, post.text,
post.createdAt, post.createdAt,
post.visibility, post.visibility,
post.url, postUrl,
post.repostId, post.repostId,
post.replyId post.replyId
) )

View File

@ -0,0 +1,26 @@
package dev.usbharu.hideout.routing.api.v1
import dev.usbharu.hideout.domain.model.Post
import dev.usbharu.hideout.domain.model.api.StatusForPost
import dev.usbharu.hideout.service.IPostService
import dev.usbharu.hideout.service.impl.PostService
import io.ktor.server.application.*
import io.ktor.server.request.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
fun Route.statuses(postService: IPostService) {
route("statuses") {
post {
val status: StatusForPost = call.receive()
val post = Post(
userId = status.userId,
createdAt = System.currentTimeMillis(),
text = status.status,
visibility = 1
)
postService.create(post)
call.respond(status)
}
}
}

View File

@ -3,11 +3,12 @@ package dev.usbharu.hideout.service.impl
import dev.usbharu.hideout.domain.model.Post import dev.usbharu.hideout.domain.model.Post
import dev.usbharu.hideout.repository.IPostRepository import dev.usbharu.hideout.repository.IPostRepository
import dev.usbharu.hideout.service.IPostService import dev.usbharu.hideout.service.IPostService
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
import dev.usbharu.hideout.service.job.JobQueueParentService import dev.usbharu.hideout.service.job.JobQueueParentService
class PostService(private val postRepository:IPostRepository,private val jobQueueParentService: JobQueueParentService) : IPostService { class PostService(private val postRepository:IPostRepository,private val activityPubNoteService: ActivityPubNoteService) : IPostService {
override suspend fun create(post: Post) { override suspend fun create(post: Post) {
postRepository.insert(post) val postEntity = postRepository.insert(post)
activityPubNoteService.createNote(postEntity)
} }
} }

View File

@ -27,7 +27,7 @@ class InboxRoutingKtTest {
} }
application { application {
configureSerialization() configureSerialization()
configureRouting(mock(), mock(), mock(), mock()) configureRouting(mock(), mock(), mock(), mock(),mock())
} }
client.get("/inbox").let { client.get("/inbox").let {
Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status) Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status)
@ -50,7 +50,7 @@ class InboxRoutingKtTest {
application { application {
configureStatusPages() configureStatusPages()
configureSerialization() configureSerialization()
configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService) configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService,mock())
} }
client.post("/inbox").let { client.post("/inbox").let {
Assertions.assertEquals(HttpStatusCode.BadRequest, it.status) Assertions.assertEquals(HttpStatusCode.BadRequest, it.status)
@ -64,7 +64,7 @@ class InboxRoutingKtTest {
} }
application { application {
configureSerialization() configureSerialization()
configureRouting(mock(), mock(), mock(), mock()) configureRouting(mock(), mock(), mock(), mock(),mock())
} }
client.get("/users/test/inbox").let { client.get("/users/test/inbox").let {
Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status) Assertions.assertEquals(HttpStatusCode.MethodNotAllowed, it.status)
@ -87,7 +87,7 @@ class InboxRoutingKtTest {
application { application {
configureStatusPages() configureStatusPages()
configureSerialization() configureSerialization()
configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService) configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService,mock())
} }
client.post("/users/test/inbox").let { client.post("/users/test/inbox").let {
Assertions.assertEquals(HttpStatusCode.BadRequest, it.status) Assertions.assertEquals(HttpStatusCode.BadRequest, it.status)

View File

@ -70,7 +70,7 @@ class UsersAPTest {
application { application {
configureSerialization() configureSerialization()
configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService) configureRouting(httpSignatureVerifyService, activityPubService, userService, activityPubUserService,mock())
} }
client.get("/users/test") { client.get("/users/test") {
accept(ContentType.Application.Activity) accept(ContentType.Application.Activity)