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

This commit is contained in:
usbharu 2023-04-21 18:24:13 +09:00
parent bafd966909
commit ced1abe69c
Signed by: usbharu
GPG Key ID: 6556747BF94EEBC8
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.domain.model.job.ReceiveFollowJob
import dev.usbharu.hideout.plugins.*
import dev.usbharu.hideout.repository.IUserAuthRepository
import dev.usbharu.hideout.repository.IUserRepository
import dev.usbharu.hideout.repository.UserAuthRepository
import dev.usbharu.hideout.repository.UserRepository
import dev.usbharu.hideout.repository.*
import dev.usbharu.hideout.routing.register
import dev.usbharu.hideout.service.IPostService
import dev.usbharu.hideout.service.IUserAuthService
import dev.usbharu.hideout.service.TwitterSnowflakeIdGenerateService
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.UserService
import dev.usbharu.hideout.service.job.JobQueueParentService
@ -81,6 +81,8 @@ fun Application.parent() {
single<UserService> { UserService(get()) }
single<ActivityPubUserService> { ActivityPubUserServiceImpl(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<ActivityPubService>().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 repostId = long("repostId").references(id).nullable()
val replyId = long("replyId").references(id).nullable()
override val primaryKey: PrimaryKey = PrimaryKey(id)
}
data class Post(
@ -21,7 +22,6 @@ data class Post(
val text: String,
val createdAt: Long,
val visibility: Int,
val url: String,
val repostId: Long? = null,
val replyId: Long? = null
)

View File

@ -1,6 +1,7 @@
package dev.usbharu.hideout.domain.model
import org.jetbrains.exposed.dao.id.LongIdTable
import org.jetbrains.exposed.sql.ResultRow
data class User(
val name: String,
@ -47,3 +48,16 @@ object Users : LongIdTable("users") {
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.outbox
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.service.IPostService
import dev.usbharu.hideout.service.activitypub.ActivityPubService
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
import dev.usbharu.hideout.service.impl.UserService
@ -15,8 +17,9 @@ import io.ktor.server.routing.*
fun Application.configureRouting(
httpSignatureVerifyService: HttpSignatureVerifyService,
activityPubService: ActivityPubService,
userService:UserService,
activityPubUserService: ActivityPubUserService
userService: UserService,
activityPubUserService: ActivityPubUserService,
postService: IPostService
) {
install(AutoHeadResponse)
routing {
@ -24,5 +27,10 @@ fun Application.configureRouting(
outbox()
usersAP(activityPubUserService)
webfinger(userService)
route("api/v1") {
statuses(postService)
}
}
}

View File

@ -1,9 +1,7 @@
package dev.usbharu.hideout.repository
import dev.usbharu.hideout.domain.model.Post
import dev.usbharu.hideout.domain.model.PostEntity
import dev.usbharu.hideout.domain.model.Posts
import dev.usbharu.hideout.domain.model.toPost
import dev.usbharu.hideout.config.Config
import dev.usbharu.hideout.domain.model.*
import dev.usbharu.hideout.service.IdGenerateService
import kotlinx.coroutines.Dispatchers
import org.jetbrains.exposed.sql.*
@ -26,6 +24,8 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
return query {
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 {
it[id] = generateId
it[userId] = post.userId
@ -33,7 +33,7 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
it[text] = post.text
it[createdAt] = post.createdAt
it[visibility] = post.visibility
it[url] = post.url
it[url] = postUrl
it[repostId] = post.repostId
it[replyId] = post.replyId
}
@ -44,7 +44,7 @@ class PostRepositoryImpl(database: Database, private val idGenerateService: IdGe
post.text,
post.createdAt,
post.visibility,
post.url,
postUrl,
post.repostId,
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.repository.IPostRepository
import dev.usbharu.hideout.service.IPostService
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
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) {
postRepository.insert(post)
val postEntity = postRepository.insert(post)
activityPubNoteService.createNote(postEntity)
}
}

View File

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

View File

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