mirror of https://github.com/usbharu/Hideout.git
feat: 投稿取得のAPIを追加
This commit is contained in:
parent
5b2d2956bd
commit
21ea966ca3
|
@ -0,0 +1,3 @@
|
||||||
|
package dev.usbharu.hideout.domain.model
|
||||||
|
|
||||||
|
data class Acct(val username: String, val domain: String? = null, val isRemote: Boolean = domain == null)
|
|
@ -1,3 +1,12 @@
|
||||||
package dev.usbharu.hideout.domain.model.hideout.dto
|
package dev.usbharu.hideout.domain.model.hideout.dto
|
||||||
|
|
||||||
data class PostCreateDto(val text: String, val userId: Long)
|
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||||
|
|
||||||
|
data class PostCreateDto(
|
||||||
|
val text: String,
|
||||||
|
val overview: String? = null,
|
||||||
|
val visibility: Visibility,
|
||||||
|
val repostId: Long? = null,
|
||||||
|
val repolyId: Long? = null,
|
||||||
|
val userId: Long
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.exception
|
||||||
|
|
||||||
|
class PostNotFoundException : IllegalArgumentException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(s: String?) : super(s)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ 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.internal.v1.posts
|
||||||
import dev.usbharu.hideout.routing.api.mastodon.v1.statuses
|
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.IPostService
|
import dev.usbharu.hideout.service.IPostService
|
||||||
|
@ -31,5 +32,8 @@ fun Application.configureRouting(
|
||||||
route("/api/v1") {
|
route("/api/v1") {
|
||||||
statuses(postService)
|
statuses(postService)
|
||||||
}
|
}
|
||||||
|
route("/api/internal/v1") {
|
||||||
|
posts(postService)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
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.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.PostNotFoundException
|
||||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||||
import dev.usbharu.hideout.service.IPostService
|
import dev.usbharu.hideout.service.IPostService
|
||||||
|
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.*
|
||||||
|
@ -21,7 +25,14 @@ 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(receive.text, userId)
|
val postCreateDto = PostCreateDto(
|
||||||
|
receive.text,
|
||||||
|
receive.overview,
|
||||||
|
receive.visibility,
|
||||||
|
receive.repostId,
|
||||||
|
receive.replyId,
|
||||||
|
userId
|
||||||
|
)
|
||||||
val create = postService.create(postCreateDto)
|
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)
|
||||||
|
@ -35,7 +46,46 @@ 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()
|
||||||
postService.findAll(since, until, minId, maxId, limit, userId)
|
call.respond(postService.findAll(since, until, minId, maxId, limit, userId))
|
||||||
|
}
|
||||||
|
get("/{id}") {
|
||||||
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
|
val id = call.parameters["id"]?.toLong()
|
||||||
|
?: throw ParameterNotExistException("Parameter(id='postsId') does not exist.")
|
||||||
|
val post = (postService.findByIdForUser(id, userId)
|
||||||
|
?: throw PostNotFoundException("$id was not found or is not authorized."))
|
||||||
|
call.respond(post)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route("/users/{name}/posts") {
|
||||||
|
authenticate(TOKEN_AUTH, optional = true) {
|
||||||
|
get {
|
||||||
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
|
val targetUserName = call.parameters["name"]
|
||||||
|
?: throw ParameterNotExistException("Parameter(name='userName@domain') does not exist.")
|
||||||
|
val targetUserId = targetUserName.toLongOrNull()
|
||||||
|
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)
|
||||||
|
|
||||||
|
}
|
||||||
|
get("/{id}") {
|
||||||
|
val userId = call.principal<JWTPrincipal>()?.payload?.getClaim("uid")?.asLong()
|
||||||
|
val id = call.parameters["id"]?.toLong()
|
||||||
|
?: throw ParameterNotExistException("Parameter(name='postsId' does not exist.")
|
||||||
|
val post = (postService.findByIdForUser(id, userId)
|
||||||
|
?: throw PostNotFoundException("$id was not found or is not authorized."))
|
||||||
|
call.response.header("Content-Location", post.url)
|
||||||
|
call.respond(post)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.service
|
package dev.usbharu.hideout.service
|
||||||
|
|
||||||
|
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
|
import java.time.Instant
|
||||||
|
@ -17,5 +18,43 @@ interface IPostService {
|
||||||
): List<Post>
|
): List<Post>
|
||||||
|
|
||||||
suspend fun findById(id: String): 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)
|
suspend fun delete(id: String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,10 @@ import dev.usbharu.hideout.repository.UsersFollowers
|
||||||
import dev.usbharu.hideout.repository.toPost
|
import dev.usbharu.hideout.repository.toPost
|
||||||
import dev.usbharu.hideout.service.IPostService
|
import dev.usbharu.hideout.service.IPostService
|
||||||
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
|
import dev.usbharu.hideout.service.activitypub.ActivityPubNoteService
|
||||||
|
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.orWhere
|
||||||
import org.jetbrains.exposed.sql.select
|
import org.jetbrains.exposed.sql.select
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
@ -71,6 +75,23 @@ class PostService(
|
||||||
TODO("Not yet implemented")
|
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 delete(id: String) {
|
override suspend fun delete(id: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package dev.usbharu.hideout.util
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.Acct
|
||||||
|
|
||||||
|
object AcctUtil {
|
||||||
|
fun parse(string: String): Acct {
|
||||||
|
if (string.isBlank()) {
|
||||||
|
throw IllegalArgumentException("Invalid acct.(Blank)")
|
||||||
|
}
|
||||||
|
return when (string.count { c -> c == '@' }) {
|
||||||
|
0 -> {
|
||||||
|
Acct(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
1 -> {
|
||||||
|
if (string.startsWith("@")) {
|
||||||
|
Acct(string.substring(1 until string.length))
|
||||||
|
} else {
|
||||||
|
Acct(string.substringBefore("@"), string.substringAfter("@"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
2 -> {
|
||||||
|
if (string.startsWith("@")) {
|
||||||
|
val substring = string.substring(1 until string.length)
|
||||||
|
val userName = substring.substringBefore("@")
|
||||||
|
val domain = substring.substringAfter("@")
|
||||||
|
Acct(
|
||||||
|
userName, domain.ifBlank { null }
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
throw IllegalArgumentException("Invalid acct.(@ are in the wrong position)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
throw IllegalArgumentException("Invalid acct.(Too many @)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue