mirror of https://github.com/usbharu/Hideout.git
feat: ユーザーページをacceptヘッダーがactivityの状態でアクセスするとpersonを返すように
This commit is contained in:
parent
9644c284d7
commit
fd2060a5d6
|
@ -8,6 +8,8 @@ import dev.usbharu.hideout.repository.UserRepository
|
|||
import dev.usbharu.hideout.service.IUserAuthService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubServiceImpl
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserServiceImpl
|
||||
import dev.usbharu.hideout.service.impl.UserAuthService
|
||||
import dev.usbharu.hideout.service.impl.UserService
|
||||
import dev.usbharu.hideout.service.signature.HttpSignatureVerifyService
|
||||
|
@ -42,6 +44,7 @@ fun Application.module() {
|
|||
single<HttpSignatureVerifyService> { HttpSignatureVerifyServiceImpl(get()) }
|
||||
single<ActivityPubService> { ActivityPubServiceImpl() }
|
||||
single<UserService> { UserService(get()) }
|
||||
single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(),get()) }
|
||||
}
|
||||
|
||||
configureKoin(module)
|
||||
|
@ -52,6 +55,7 @@ fun Application.module() {
|
|||
configureRouting(
|
||||
inject<HttpSignatureVerifyService>().value,
|
||||
inject<ActivityPubService>().value,
|
||||
inject<UserService>().value
|
||||
inject<UserService>().value,
|
||||
inject<ActivityPubUserService>().value
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,4 +13,21 @@ open class Image : Object {
|
|||
this.url = url
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Image) return false
|
||||
if (!super.equals(other)) return false
|
||||
|
||||
if (mediaType != other.mediaType) return false
|
||||
return url == other.url
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = super.hashCode()
|
||||
result = 31 * result + (mediaType?.hashCode() ?: 0)
|
||||
result = 31 * result + (url?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -25,6 +25,19 @@ open class JsonLd {
|
|||
}
|
||||
|
||||
protected constructor()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is JsonLd) return false
|
||||
|
||||
return context == other.context
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return context.hashCode()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class ContextDeserializer : JsonDeserializer<String>() {
|
||||
|
|
|
@ -17,5 +17,23 @@ open class Key : Object{
|
|||
this.publicKeyPem = publicKeyPem
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Key) return false
|
||||
if (!super.equals(other)) return false
|
||||
|
||||
if (id != other.id) return false
|
||||
if (owner != other.owner) return false
|
||||
return publicKeyPem == other.publicKeyPem
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = super.hashCode()
|
||||
result = 31 * result + (id?.hashCode() ?: 0)
|
||||
result = 31 * result + (owner?.hashCode() ?: 0)
|
||||
result = 31 * result + (publicKeyPem?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,22 @@ open class Object : JsonLd {
|
|||
return toMutableList.distinct()
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Object) return false
|
||||
|
||||
if (type != other.type) return false
|
||||
return name == other.name
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = type.hashCode()
|
||||
result = 31 * result + (name?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class TypeSerializer : JsonSerializer<List<String>>() {
|
||||
|
|
|
@ -32,4 +32,31 @@ open class Person : Object {
|
|||
this.publicKey = publicKey
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is Person) return false
|
||||
|
||||
if (id != other.id) return false
|
||||
if (preferredUsername != other.preferredUsername) return false
|
||||
if (summary != other.summary) return false
|
||||
if (inbox != other.inbox) return false
|
||||
if (outbox != other.outbox) return false
|
||||
if (url != other.url) return false
|
||||
if (icon != other.icon) return false
|
||||
return publicKey == other.publicKey
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id?.hashCode() ?: 0
|
||||
result = 31 * result + (preferredUsername?.hashCode() ?: 0)
|
||||
result = 31 * result + (summary?.hashCode() ?: 0)
|
||||
result = 31 * result + (inbox?.hashCode() ?: 0)
|
||||
result = 31 * result + (outbox?.hashCode() ?: 0)
|
||||
result = 31 * result + (url?.hashCode() ?: 0)
|
||||
result = 31 * result + (icon?.hashCode() ?: 0)
|
||||
result = 31 * result + (publicKey?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import dev.usbharu.hideout.routing.activitypub.outbox
|
|||
import dev.usbharu.hideout.routing.activitypub.usersAP
|
||||
import dev.usbharu.hideout.routing.wellknown.webfinger
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||
import dev.usbharu.hideout.service.impl.UserService
|
||||
import dev.usbharu.hideout.service.signature.HttpSignatureVerifyService
|
||||
import io.ktor.server.application.*
|
||||
|
@ -14,13 +15,14 @@ import io.ktor.server.routing.*
|
|||
fun Application.configureRouting(
|
||||
httpSignatureVerifyService: HttpSignatureVerifyService,
|
||||
activityPubService: ActivityPubService,
|
||||
userService:UserService
|
||||
userService:UserService,
|
||||
activityPubUserService: ActivityPubUserService
|
||||
) {
|
||||
install(AutoHeadResponse)
|
||||
routing {
|
||||
inbox(httpSignatureVerifyService, activityPubService)
|
||||
outbox()
|
||||
usersAP(activityPubService)
|
||||
usersAP(activityPubUserService)
|
||||
webfinger(userService)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package dev.usbharu.hideout.plugins
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonSetter
|
||||
import com.fasterxml.jackson.annotation.Nulls
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||
import io.ktor.http.*
|
||||
import io.ktor.serialization.jackson.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
|
@ -8,6 +14,11 @@ import io.ktor.server.routing.*
|
|||
|
||||
fun Application.configureSerialization() {
|
||||
install(ContentNegotiation) {
|
||||
jackson()
|
||||
jackson {
|
||||
enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||
setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
|
||||
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
configOverride(List::class.java).setSetterInfo(JsonSetter.Value.forContentNulls(Nulls.AS_EMPTY))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package dev.usbharu.hideout.routing.activitypub
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.exception.ParameterNotExistException
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
|
@ -8,11 +11,13 @@ import io.ktor.server.request.*
|
|||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Routing.usersAP(activityPubService: ActivityPubService){
|
||||
fun Routing.usersAP(activityPubUserService:ActivityPubUserService){
|
||||
route("/users/{name}"){
|
||||
createChild(ContentTypeRouteSelector(ContentType.Application.Activity)).handle {
|
||||
|
||||
call.respond(HttpStatusCode.NotImplemented)
|
||||
val name = call.parameters["name"] ?: throw ParameterNotExistException("Parameter(name='name') does not exist.")
|
||||
val person = activityPubUserService.getPersonByName(name)
|
||||
call.response.header("Content-Type", ContentType.Application.Activity.toString())
|
||||
call.respond(HttpStatusCode.OK,Config.configData.objectMapper.writeValueAsString(person))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package dev.usbharu.hideout.service.activitypub
|
||||
|
||||
import dev.usbharu.hideout.ap.Person
|
||||
|
||||
interface ActivityPubUserService {
|
||||
suspend fun getPersonByName(name:String):Person
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package dev.usbharu.hideout.service.activitypub
|
||||
|
||||
import dev.usbharu.hideout.ap.Image
|
||||
import dev.usbharu.hideout.ap.Key
|
||||
import dev.usbharu.hideout.ap.Person
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.service.IUserAuthService
|
||||
import dev.usbharu.hideout.service.impl.UserService
|
||||
|
||||
class ActivityPubUserServiceImpl(private val userService: UserService, private val userAuthService: IUserAuthService) :
|
||||
ActivityPubUserService {
|
||||
override suspend fun getPersonByName(name: String): Person {
|
||||
val userEntity = userService.findByName(name)
|
||||
val userAuthEntity = userAuthService.findByUserId(userEntity.id)
|
||||
val userUrl = "${Config.configData.url}/users$name"
|
||||
return Person(
|
||||
type = emptyList(),
|
||||
name = userEntity.name,
|
||||
id = userUrl,
|
||||
preferredUsername = name,
|
||||
summary = userEntity.description,
|
||||
inbox = "$userUrl/inbox",
|
||||
outbox = "$userUrl/outbox",
|
||||
url = userUrl,
|
||||
icon = Image(
|
||||
type = emptyList(),
|
||||
name = "$userUrl/icon.png",
|
||||
mediaType = "image/png",
|
||||
url = "$userUrl/icon.png"
|
||||
),
|
||||
publicKey = Key(
|
||||
type = emptyList(),
|
||||
name = "Public Key",
|
||||
id = "$userUrl#pubkey",
|
||||
owner = userUrl,
|
||||
publicKeyPem = userAuthEntity.publicKey
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,16 +1,30 @@
|
|||
package dev.usbharu.hideout.routing.activitypub
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude
|
||||
import com.fasterxml.jackson.annotation.JsonSetter
|
||||
import com.fasterxml.jackson.annotation.Nulls
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import dev.usbharu.hideout.ap.Image
|
||||
import dev.usbharu.hideout.ap.Key
|
||||
import dev.usbharu.hideout.ap.Person
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||
import dev.usbharu.hideout.domain.model.User
|
||||
import dev.usbharu.hideout.domain.model.UserEntity
|
||||
import dev.usbharu.hideout.plugins.configureRouting
|
||||
import dev.usbharu.hideout.plugins.configureSerialization
|
||||
import dev.usbharu.hideout.repository.IUserRepository
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityPubUserService
|
||||
import dev.usbharu.hideout.service.activitypub.ActivityType
|
||||
import dev.usbharu.hideout.service.impl.UserService
|
||||
import dev.usbharu.hideout.service.signature.HttpSignatureVerifyService
|
||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||
import io.ktor.client.call.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.config.*
|
||||
import io.ktor.server.testing.*
|
||||
|
@ -25,7 +39,32 @@ class UsersAPTest {
|
|||
environment {
|
||||
config = ApplicationConfig("empty.conf")
|
||||
}
|
||||
val person = Person(
|
||||
type = emptyList(),
|
||||
name = "test",
|
||||
id = "http://example.com/users/test",
|
||||
preferredUsername = "test",
|
||||
summary = "test user",
|
||||
inbox = "http://example.com/users/test/inbox",
|
||||
outbox = "http://example.com/users/test/outbox",
|
||||
url = "http://example.com/users/test",
|
||||
icon = Image(
|
||||
type = emptyList(),
|
||||
name = "http://example.com/users/test/icon.png",
|
||||
mediaType = "image/png",
|
||||
url = "http://example.com/users/test/icon.png"
|
||||
),
|
||||
publicKey = Key(
|
||||
type = emptyList(),
|
||||
name = "Public Key",
|
||||
id = "http://example.com/users/test#pubkey",
|
||||
owner = "https://example.com/users/test",
|
||||
publicKeyPem = "-----BEGIN PUBLIC KEY-----\n\n-----END PUBLIC KEY-----"
|
||||
)
|
||||
)
|
||||
person.context = listOf("https://www.w3.org/ns/activitystreams")
|
||||
application {
|
||||
configureSerialization()
|
||||
configureRouting(object : HttpSignatureVerifyService {
|
||||
override fun verify(headers: Headers): Boolean {
|
||||
return true
|
||||
|
@ -38,7 +77,7 @@ class UsersAPTest {
|
|||
override fun processActivity(json: String, type: ActivityType): ActivityPubResponse? {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
},UserService(object : IUserRepository {
|
||||
}, UserService(object : IUserRepository {
|
||||
override suspend fun create(user: User): UserEntity {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
@ -78,12 +117,26 @@ class UsersAPTest {
|
|||
override suspend fun findFollowersById(id: Long): List<UserEntity> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}))
|
||||
}), object : ActivityPubUserService {
|
||||
override suspend fun getPersonByName(name: String): Person {
|
||||
return person
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
client.get("/users/test"){
|
||||
client.get("/users/test") {
|
||||
accept(ContentType.Application.Activity)
|
||||
}.let {
|
||||
assertEquals(HttpStatusCode.NotImplemented, it.status)
|
||||
val objectMapper = jacksonObjectMapper().enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
|
||||
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
|
||||
objectMapper.configOverride(List::class.java).setSetterInfo(JsonSetter.Value.forValueNulls(
|
||||
Nulls.AS_EMPTY))
|
||||
val actual = it.bodyAsText()
|
||||
val readValue = objectMapper.readValue<Person>(actual)
|
||||
println(objectMapper.writeValueAsString(person))
|
||||
println(objectMapper.writeValueAsString(readValue))
|
||||
assertEquals(person, readValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue