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
|
||||
|
||||
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.outbox
|
||||
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.wellknown.webfinger
|
||||
import dev.usbharu.hideout.service.IPostService
|
||||
|
@ -31,5 +32,8 @@ fun Application.configureRouting(
|
|||
route("/api/v1") {
|
||||
statuses(postService)
|
||||
}
|
||||
route("/api/internal/v1") {
|
||||
posts(postService)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
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.exception.ParameterNotExistException
|
||||
import dev.usbharu.hideout.exception.PostNotFoundException
|
||||
import dev.usbharu.hideout.plugins.TOKEN_AUTH
|
||||
import dev.usbharu.hideout.service.IPostService
|
||||
import dev.usbharu.hideout.util.AcctUtil
|
||||
import dev.usbharu.hideout.util.InstantParseUtil
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
@ -21,7 +25,14 @@ fun Route.posts(postService: IPostService) {
|
|||
val userId = principal.payload.getClaim("uid").asLong()
|
||||
|
||||
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)
|
||||
call.response.header("Location", create.url)
|
||||
call.respond(HttpStatusCode.OK)
|
||||
|
@ -35,7 +46,46 @@ fun Route.posts(postService: IPostService) {
|
|||
val minId = call.request.queryParameters["minId"]?.toLong()
|
||||
val maxId = call.request.queryParameters["maxId"]?.toLong()
|
||||
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
|
||||
|
||||
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 java.time.Instant
|
||||
|
@ -17,5 +18,43 @@ interface IPostService {
|
|||
): 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)
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ import dev.usbharu.hideout.repository.UsersFollowers
|
|||
import dev.usbharu.hideout.repository.toPost
|
||||
import dev.usbharu.hideout.service.IPostService
|
||||
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.select
|
||||
import org.jetbrains.exposed.sql.transactions.transaction
|
||||
|
@ -71,6 +75,23 @@ class PostService(
|
|||
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) {
|
||||
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