mirror of https://github.com/usbharu/Hideout.git
feat: フォローテーブルにフォロー情報を記録するように
This commit is contained in:
parent
a9200eaeef
commit
5846dde42f
|
@ -81,7 +81,7 @@ fun Application.parent() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
single<ActivityPubFollowService> { ActivityPubFollowServiceImpl(get(), get(), get()) }
|
single<ActivityPubFollowService> { ActivityPubFollowServiceImpl(get(), get(), get(),get()) }
|
||||||
single<ActivityPubService> { ActivityPubServiceImpl(get()) }
|
single<ActivityPubService> { ActivityPubServiceImpl(get()) }
|
||||||
single<UserService> { UserService(get()) }
|
single<UserService> { UserService(get()) }
|
||||||
single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) }
|
single<ActivityPubUserService> { ActivityPubUserServiceImpl(get(), get(), get()) }
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package dev.usbharu.hideout.ap
|
package dev.usbharu.hideout.ap
|
||||||
|
|
||||||
open class Key : Object{
|
open class Key : Object{
|
||||||
private var id:String? = null
|
var id:String? = null
|
||||||
private var owner:String? = null
|
var owner:String? = null
|
||||||
private var publicKeyPem:String? = null
|
var publicKeyPem:String? = null
|
||||||
protected constructor() : super()
|
protected constructor() : super()
|
||||||
constructor(
|
constructor(
|
||||||
type: List<String>,
|
type: List<String>,
|
||||||
|
|
|
@ -5,10 +5,10 @@ open class Person : Object {
|
||||||
var preferredUsername:String? = null
|
var preferredUsername:String? = null
|
||||||
var summary:String? = null
|
var summary:String? = null
|
||||||
var inbox:String? = null
|
var inbox:String? = null
|
||||||
private var outbox:String? = null
|
var outbox:String? = null
|
||||||
private var url:String? = null
|
private var url:String? = null
|
||||||
private var icon:Image? = null
|
private var icon:Image? = null
|
||||||
private var publicKey:Key? = null
|
var publicKey:Key? = null
|
||||||
protected constructor() : super()
|
protected constructor() : super()
|
||||||
constructor(
|
constructor(
|
||||||
type: List<String> = emptyList(),
|
type: List<String> = emptyList(),
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package dev.usbharu.hideout.exception.ap
|
||||||
|
|
||||||
|
class IllegalActivityPubObjectException : IllegalArgumentException {
|
||||||
|
constructor() : super()
|
||||||
|
constructor(s: String?) : super(s)
|
||||||
|
constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||||
|
constructor(cause: Throwable?) : super(cause)
|
||||||
|
}
|
|
@ -8,10 +8,16 @@ interface IUserRepository {
|
||||||
|
|
||||||
suspend fun findById(id: Long): UserEntity?
|
suspend fun findById(id: Long): UserEntity?
|
||||||
|
|
||||||
|
suspend fun findByIds(ids: List<Long>): List<UserEntity>
|
||||||
|
|
||||||
suspend fun findByName(name: String): UserEntity?
|
suspend fun findByName(name: String): UserEntity?
|
||||||
|
|
||||||
|
suspend fun findByNameAndDomains(names: List<Pair<String,String>>): List<UserEntity>
|
||||||
|
|
||||||
suspend fun findByUrl(url:String):UserEntity?
|
suspend fun findByUrl(url:String):UserEntity?
|
||||||
|
|
||||||
|
suspend fun findByUrls(urls: List<String>): List<UserEntity>
|
||||||
|
|
||||||
suspend fun update(userEntity: UserEntity)
|
suspend fun update(userEntity: UserEntity)
|
||||||
|
|
||||||
suspend fun delete(id: Long)
|
suspend fun delete(id: Long)
|
||||||
|
|
|
@ -79,6 +79,14 @@ class UserRepository(private val database: Database) : IUserRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByIds(ids: List<Long>): List<UserEntity> {
|
||||||
|
return query {
|
||||||
|
Users.select { Users.id inList ids }.map {
|
||||||
|
it.toUserEntity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByName(name: String): UserEntity? {
|
override suspend fun findByName(name: String): UserEntity? {
|
||||||
return query {
|
return query {
|
||||||
Users.select { Users.name eq name }.map {
|
Users.select { Users.name eq name }.map {
|
||||||
|
@ -87,12 +95,26 @@ class UserRepository(private val database: Database) : IUserRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<UserEntity> {
|
||||||
|
return query {
|
||||||
|
val selectAll = Users.selectAll()
|
||||||
|
names.forEach { (name, domain) ->
|
||||||
|
selectAll.orWhere { Users.name eq name and (Users.domain eq domain) }
|
||||||
|
}
|
||||||
|
selectAll.map { it.toUserEntity() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): UserEntity? {
|
override suspend fun findByUrl(url: String): UserEntity? {
|
||||||
return query {
|
return query {
|
||||||
Users.select { Users.url eq url }.singleOrNull()?.toUserEntity()
|
Users.select { Users.url eq url }.singleOrNull()?.toUserEntity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrls(urls: List<String>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findFollowersById(id: Long): List<UserEntity> {
|
override suspend fun findFollowersById(id: Long): List<UserEntity> {
|
||||||
return query {
|
return query {
|
||||||
val followers = Users.alias("FOLLOWERS")
|
val followers = Users.alias("FOLLOWERS")
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.usbharu.hideout.service
|
package dev.usbharu.hideout.service
|
||||||
|
|
||||||
|
import dev.usbharu.hideout.domain.model.UserAuthentication
|
||||||
import dev.usbharu.hideout.domain.model.UserAuthenticationEntity
|
import dev.usbharu.hideout.domain.model.UserAuthenticationEntity
|
||||||
|
|
||||||
interface IUserAuthService {
|
interface IUserAuthService {
|
||||||
|
@ -13,4 +14,5 @@ interface IUserAuthService {
|
||||||
suspend fun findByUserId(userId: Long): UserAuthenticationEntity
|
suspend fun findByUserId(userId: Long): UserAuthenticationEntity
|
||||||
|
|
||||||
suspend fun findByUsername(username: String): UserAuthenticationEntity
|
suspend fun findByUsername(username: String): UserAuthenticationEntity
|
||||||
|
suspend fun createAccount(userEntity: UserAuthentication): UserAuthenticationEntity
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import dev.usbharu.hideout.domain.model.ActivityPubResponse
|
||||||
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
import dev.usbharu.hideout.domain.model.ActivityPubStringResponse
|
||||||
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||||
import dev.usbharu.hideout.plugins.postAp
|
import dev.usbharu.hideout.plugins.postAp
|
||||||
|
import dev.usbharu.hideout.service.impl.UserService
|
||||||
import dev.usbharu.hideout.service.job.JobQueueParentService
|
import dev.usbharu.hideout.service.job.JobQueueParentService
|
||||||
import io.ktor.client.*
|
import io.ktor.client.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
@ -16,6 +17,7 @@ import kjob.core.job.JobProps
|
||||||
class ActivityPubFollowServiceImpl(
|
class ActivityPubFollowServiceImpl(
|
||||||
private val jobQueueParentService: JobQueueParentService,
|
private val jobQueueParentService: JobQueueParentService,
|
||||||
private val activityPubUserService: ActivityPubUserService,
|
private val activityPubUserService: ActivityPubUserService,
|
||||||
|
private val userService: UserService,
|
||||||
private val httpClient: HttpClient
|
private val httpClient: HttpClient
|
||||||
) : ActivityPubFollowService {
|
) : ActivityPubFollowService {
|
||||||
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
override suspend fun receiveFollow(follow: Follow): ActivityPubResponse {
|
||||||
|
@ -32,14 +34,19 @@ class ActivityPubFollowServiceImpl(
|
||||||
val actor = props[ReceiveFollowJob.actor]
|
val actor = props[ReceiveFollowJob.actor]
|
||||||
val person = activityPubUserService.fetchPerson(actor)
|
val person = activityPubUserService.fetchPerson(actor)
|
||||||
val follow = Config.configData.objectMapper.readValue<Follow>(props[ReceiveFollowJob.follow])
|
val follow = Config.configData.objectMapper.readValue<Follow>(props[ReceiveFollowJob.follow])
|
||||||
|
val targetActor = props[ReceiveFollowJob.targetActor]
|
||||||
httpClient.postAp(
|
httpClient.postAp(
|
||||||
urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found"),
|
urlString = person.inbox ?: throw IllegalArgumentException("inbox is not found"),
|
||||||
username = "${props[ReceiveFollowJob.targetActor]}#pubkey",
|
username = "$targetActor#pubkey",
|
||||||
jsonLd = Accept(
|
jsonLd = Accept(
|
||||||
name = "Follow",
|
name = "Follow",
|
||||||
`object` = follow,
|
`object` = follow,
|
||||||
actor = props[ReceiveFollowJob.targetActor]
|
actor = targetActor
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
val users =
|
||||||
|
userService.findByUrls(listOf(targetActor, follow.actor ?: throw IllegalArgumentException("actor is null")))
|
||||||
|
|
||||||
|
userService.addFollowers(users.first { it.url == targetActor }.id, users.first { it.url == follow.actor }.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,10 @@ import dev.usbharu.hideout.ap.Image
|
||||||
import dev.usbharu.hideout.ap.Key
|
import dev.usbharu.hideout.ap.Key
|
||||||
import dev.usbharu.hideout.ap.Person
|
import dev.usbharu.hideout.ap.Person
|
||||||
import dev.usbharu.hideout.config.Config
|
import dev.usbharu.hideout.config.Config
|
||||||
|
import dev.usbharu.hideout.domain.model.User
|
||||||
|
import dev.usbharu.hideout.domain.model.UserAuthentication
|
||||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||||
|
import dev.usbharu.hideout.exception.ap.IllegalActivityPubObjectException
|
||||||
import dev.usbharu.hideout.service.IUserAuthService
|
import dev.usbharu.hideout.service.IUserAuthService
|
||||||
import dev.usbharu.hideout.service.impl.UserService
|
import dev.usbharu.hideout.service.impl.UserService
|
||||||
import dev.usbharu.hideout.util.HttpUtil.Activity
|
import dev.usbharu.hideout.util.HttpUtil.Activity
|
||||||
|
@ -14,7 +17,11 @@ import io.ktor.client.request.*
|
||||||
import io.ktor.client.statement.*
|
import io.ktor.client.statement.*
|
||||||
import io.ktor.http.*
|
import io.ktor.http.*
|
||||||
|
|
||||||
class ActivityPubUserServiceImpl(private val userService: UserService, private val userAuthService: IUserAuthService,private val httpClient: HttpClient) :
|
class ActivityPubUserServiceImpl(
|
||||||
|
private val userService: UserService,
|
||||||
|
private val userAuthService: IUserAuthService,
|
||||||
|
private val httpClient: HttpClient
|
||||||
|
) :
|
||||||
ActivityPubUserService {
|
ActivityPubUserService {
|
||||||
override suspend fun getPersonByName(name: String): Person {
|
override suspend fun getPersonByName(name: String): Person {
|
||||||
// TODO: JOINで書き直し
|
// TODO: JOINで書き直し
|
||||||
|
@ -78,7 +85,28 @@ class ActivityPubUserServiceImpl(private val userService: UserService, private v
|
||||||
val httpResponse = httpClient.get(url) {
|
val httpResponse = httpClient.get(url) {
|
||||||
accept(ContentType.Application.Activity)
|
accept(ContentType.Application.Activity)
|
||||||
}
|
}
|
||||||
Config.configData.objectMapper.readValue<Person>(httpResponse.bodyAsText())
|
val person = Config.configData.objectMapper.readValue<Person>(httpResponse.bodyAsText())
|
||||||
|
val userEntity = userService.create(
|
||||||
|
User(
|
||||||
|
name = person.preferredUsername
|
||||||
|
?: throw IllegalActivityPubObjectException("preferredUsername is null"),
|
||||||
|
domain = url.substringAfter(":").substringBeforeLast("/"),
|
||||||
|
screenName = person.name ?: throw IllegalActivityPubObjectException("name is null"),
|
||||||
|
description = person.summary ?: throw IllegalActivityPubObjectException("summary is null"),
|
||||||
|
inbox = person.inbox ?: throw IllegalActivityPubObjectException("inbox is null"),
|
||||||
|
outbox = person.outbox ?: throw IllegalActivityPubObjectException("outbox is null"),
|
||||||
|
url = url
|
||||||
|
)
|
||||||
|
)
|
||||||
|
userAuthService.createAccount(
|
||||||
|
UserAuthentication(
|
||||||
|
userEntity.id,
|
||||||
|
null,
|
||||||
|
person.publicKey?.publicKeyPem ?: throw IllegalActivityPubObjectException("publicKey is null"),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
person
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import dev.usbharu.hideout.config.Config
|
||||||
import dev.usbharu.hideout.domain.model.User
|
import dev.usbharu.hideout.domain.model.User
|
||||||
import dev.usbharu.hideout.domain.model.UserAuthentication
|
import dev.usbharu.hideout.domain.model.UserAuthentication
|
||||||
import dev.usbharu.hideout.domain.model.UserAuthenticationEntity
|
import dev.usbharu.hideout.domain.model.UserAuthenticationEntity
|
||||||
|
import dev.usbharu.hideout.domain.model.UserEntity
|
||||||
import dev.usbharu.hideout.exception.UserNotFoundException
|
import dev.usbharu.hideout.exception.UserNotFoundException
|
||||||
import dev.usbharu.hideout.repository.IUserAuthRepository
|
import dev.usbharu.hideout.repository.IUserAuthRepository
|
||||||
import dev.usbharu.hideout.repository.IUserRepository
|
import dev.usbharu.hideout.repository.IUserRepository
|
||||||
|
@ -76,6 +77,10 @@ class UserAuthService(
|
||||||
?: throw UserNotFoundException("$username auth data was not found")
|
?: throw UserNotFoundException("$username auth data was not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun createAccount(userEntity: UserAuthentication): UserAuthenticationEntity {
|
||||||
|
return userAuthRepository.create(userEntity)
|
||||||
|
}
|
||||||
|
|
||||||
private fun generateKeyPair(): KeyPair {
|
private fun generateKeyPair(): KeyPair {
|
||||||
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
val keyPairGenerator = KeyPairGenerator.getInstance("RSA")
|
||||||
keyPairGenerator.initialize(1024)
|
keyPairGenerator.initialize(1024)
|
||||||
|
|
|
@ -21,15 +21,27 @@ class UserService(private val userRepository: IUserRepository) {
|
||||||
return userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
return userRepository.findById(id) ?: throw UserNotFoundException("$id was not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun findByIds(ids: List<Long>): List<UserEntity> {
|
||||||
|
return userRepository.findByIds(ids)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun findByName(name: String): UserEntity {
|
suspend fun findByName(name: String): UserEntity {
|
||||||
return userRepository.findByName(name)
|
return userRepository.findByName(name)
|
||||||
?: throw UserNotFoundException("$name was not found.")
|
?: throw UserNotFoundException("$name was not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun findByNameAndDomains(names: List<Pair<String,String>>): List<UserEntity> {
|
||||||
|
return userRepository.findByNameAndDomains(names)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun findByUrl(url: String): UserEntity {
|
suspend fun findByUrl(url: String): UserEntity {
|
||||||
return userRepository.findByUrl(url) ?: throw UserNotFoundException("$url was not found.")
|
return userRepository.findByUrl(url) ?: throw UserNotFoundException("$url was not found.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun findByUrls(urls: List<String>): List<UserEntity> {
|
||||||
|
return userRepository.findByUrls(urls)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun create(user: User): UserEntity {
|
suspend fun create(user: User): UserEntity {
|
||||||
return userRepository.create(user)
|
return userRepository.create(user)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,26 @@ class ActivityPubKtTest {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByIds(ids: List<Long>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByName(name: String): UserEntity? {
|
override suspend fun findByName(name: String): UserEntity? {
|
||||||
return UserEntity(1, "test", "localhost", "test", "","","","")
|
return UserEntity(1, "test", "localhost", "test", "","","","")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): UserEntity? {
|
override suspend fun findByUrl(url: String): UserEntity? {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrls(urls: List<String>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun update(userEntity: UserEntity) {
|
override suspend fun update(userEntity: UserEntity) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,14 +26,26 @@ class KtorKeyMapTest {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByIds(ids: List<Long>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByName(name: String): UserEntity? {
|
override suspend fun findByName(name: String): UserEntity? {
|
||||||
return UserEntity(1, "test", "localhost", "test", "","","","")
|
return UserEntity(1, "test", "localhost", "test", "","","","")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByNameAndDomains(names: List<Pair<String, String>>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun findByUrl(url: String): UserEntity? {
|
override suspend fun findByUrl(url: String): UserEntity? {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun findByUrls(urls: List<String>): List<UserEntity> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun update(userEntity: UserEntity) {
|
override suspend fun update(userEntity: UserEntity) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue