feat: DBにfollowing,followersとkeyidを追加

This commit is contained in:
usbharu 2023-10-19 12:17:02 +09:00
parent 72289625b4
commit 34ed98c82b
11 changed files with 142 additions and 63 deletions

View File

@ -9,6 +9,8 @@ open class Person : Object {
private var icon: Image? = null
var publicKey: Key? = null
var endpoints: Map<String, String> = emptyMap()
var following: String? = null
var followers: String? = null
protected constructor() : super()
@ -24,7 +26,9 @@ open class Person : Object {
url: String?,
icon: Image?,
publicKey: Key?,
endpoints: Map<String, String> = emptyMap()
endpoints: Map<String, String> = emptyMap(),
followers: String?,
following: String?
) : super(add(type, "Person"), name, id = id) {
this.preferredUsername = preferredUsername
this.summary = summary
@ -34,6 +38,8 @@ open class Person : Object {
this.icon = icon
this.publicKey = publicKey
this.endpoints = endpoints
this.followers = followers
this.following = following
}
override fun equals(other: Any?): Boolean {

View File

@ -9,4 +9,7 @@ data class RemoteUserCreateDto(
val outbox: String,
val url: String,
val publicKey: String,
val keyId: String,
val followers: String?,
val following: String?
)

View File

@ -16,15 +16,17 @@ data class User private constructor(
val url: String,
val publicKey: String,
val privateKey: String? = null,
val createdAt: Instant
val createdAt: Instant,
val keyId: String,
val followers: String? = null,
val following: String? = null
) {
override fun toString(): String {
return "User(id=$id, name='$name', domain='$domain', screenName='$screenName', description='$description'," +
" password=****, inbox='$inbox', outbox='$outbox', url='$url', publicKey='$publicKey'," +
" privateKey=****, createdAt=$createdAt)"
return "User(id=$id, name='$name', domain='$domain', screenName='$screenName', description='$description', password=$password, inbox='$inbox', outbox='$outbox', url='$url', publicKey='$publicKey', privateKey=$privateKey, createdAt=$createdAt, keyId='$keyId', followers=$followers, following=$following)"
}
companion object {
private val logger = LoggerFactory.getLogger(User::class.java)
@Suppress("LongParameterList", "FunctionMinLength")
@ -40,7 +42,10 @@ data class User private constructor(
url: String,
publicKey: String,
privateKey: String? = null,
createdAt: Instant
createdAt: Instant,
keyId: String,
following: String? = null,
followers: String? = null
): User {
val characterLimit = Config.configData.characterLimit
@ -115,6 +120,10 @@ data class User private constructor(
"outbox must not exceed ${characterLimit.general.url} characters."
}
require(keyId.isNotBlank()) {
"keyId must contain non-blank characters."
}
return User(
id = id,
name = limitedName,
@ -127,7 +136,10 @@ data class User private constructor(
url = url,
publicKey = publicKey,
privateKey = privateKey,
createdAt = createdAt
createdAt = createdAt,
keyId = keyId,
followers = followers,
following = following
)
}
}

View File

@ -34,7 +34,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
followers[Users.url],
followers[Users.publicKey],
followers[Users.privateKey],
followers[Users.createdAt]
followers[Users.createdAt],
followers[Users.keyId],
followers[Users.following],
followers[Users.followers]
)
.select { Users.id eq id }
.map {
@ -50,7 +53,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
url = it[followers[Users.url]],
publicKey = it[followers[Users.publicKey]],
privateKey = it[followers[Users.privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]]),
keyId = it[followers[Users.keyId]],
followers = it[followers[Users.followers]],
following = it[followers[Users.following]]
)
}
}
@ -79,7 +85,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
followers[Users.url],
followers[Users.publicKey],
followers[Users.privateKey],
followers[Users.createdAt]
followers[Users.createdAt],
followers[Users.keyId],
followers[Users.following],
followers[Users.followers]
)
.select { Users.name eq name and (Users.domain eq domain) }
.map {
@ -95,7 +104,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
url = it[followers[Users.url]],
publicKey = it[followers[Users.publicKey]],
privateKey = it[followers[Users.privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]]),
keyId = it[followers[Users.keyId]],
followers = it[followers[Users.followers]],
following = it[followers[Users.following]]
)
}
}
@ -124,7 +136,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
followers[Users.url],
followers[Users.publicKey],
followers[Users.privateKey],
followers[Users.createdAt]
followers[Users.createdAt],
followers[Users.keyId],
followers[Users.following],
followers[Users.followers]
)
.select { followers[Users.id] eq id }
.map {
@ -140,7 +155,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
url = it[followers[Users.url]],
publicKey = it[followers[Users.publicKey]],
privateKey = it[followers[Users.privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]]),
keyId = it[followers[Users.keyId]],
followers = it[followers[Users.followers]],
following = it[followers[Users.following]]
)
}
}
@ -169,7 +187,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
followers[Users.url],
followers[Users.publicKey],
followers[Users.privateKey],
followers[Users.createdAt]
followers[Users.createdAt],
followers[Users.keyId],
followers[Users.following],
followers[Users.followers]
)
.select { followers[Users.name] eq name and (followers[Users.domain] eq domain) }
.map {
@ -185,7 +206,10 @@ class FollowerQueryServiceImpl : FollowerQueryService {
url = it[followers[Users.url]],
publicKey = it[followers[Users.publicKey]],
privateKey = it[followers[Users.privateKey]],
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]])
createdAt = Instant.ofEpochMilli(it[followers[Users.createdAt]]),
keyId = it[followers[Users.keyId]],
followers = it[followers[Users.followers]],
following = it[followers[Users.following]]
)
}
}

View File

@ -89,6 +89,9 @@ object Users : Table("users") {
length = Config.configData.characterLimit.general.privateKey
).nullable()
val createdAt: Column<Long> = long("created_at")
val keyId = varchar("key_id", length = Config.configData.characterLimit.general.url)
val following = varchar("following", length = Config.configData.characterLimit.general.url).nullable()
val followers = varchar("followers", length = Config.configData.characterLimit.general.url).nullable()
override val primaryKey: PrimaryKey = PrimaryKey(id)
@ -110,7 +113,10 @@ fun ResultRow.toUser(): User {
url = this[Users.url],
publicKey = this[Users.publicKey],
privateKey = this[Users.privateKey],
createdAt = Instant.ofEpochMilli((this[Users.createdAt]))
createdAt = Instant.ofEpochMilli((this[Users.createdAt])),
keyId = this[Users.keyId],
followers = this[Users.followers],
following = this[Users.following]
)
}

View File

@ -64,11 +64,13 @@ class APUserServiceImpl(
publicKey = Key(
type = emptyList(),
name = "Public Key",
id = "$userUrl#pubkey",
id = userEntity.keyId,
owner = userUrl,
publicKeyPem = userEntity.publicKey
),
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox")
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"),
followers = userEntity.followers,
following = userEntity.following
)
}
@ -96,11 +98,13 @@ class APUserServiceImpl(
publicKey = Key(
type = emptyList(),
name = "Public Key",
id = "$url#pubkey",
id = userEntity.keyId,
owner = url,
publicKeyPem = userEntity.publicKey
),
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox")
endpoints = mapOf("sharedInbox" to "${applicationConfig.url}/inbox"),
followers = userEntity.followers,
following = userEntity.following
) to userEntity
} catch (ignore: FailedToGetResourcesException) {
val person = apResourceResolveService.resolve<Person>(url, null as Long?)
@ -118,6 +122,9 @@ class APUserServiceImpl(
url = url,
publicKey = person.publicKey?.publicKeyPem
?: throw IllegalActivityPubObjectException("publicKey is null"),
keyId = person.publicKey?.id ?: throw IllegalActivityPubObjectException("publicKey keyId is null"),
following = person.following,
followers = person.followers
)
)
}

View File

@ -34,6 +34,7 @@ class UserServiceImpl(
val nextId = userRepository.nextId()
val hashedPassword = userAuthService.hash(user.password)
val keyPair = userAuthService.generateKeyPair()
val userUrl = "${applicationConfig.url}/users/${user.name}"
val userEntity = User.of(
id = nextId,
name = user.name,
@ -41,12 +42,15 @@ class UserServiceImpl(
screenName = user.screenName,
description = user.description,
password = hashedPassword,
inbox = "${applicationConfig.url}/users/${user.name}/inbox",
outbox = "${applicationConfig.url}/users/${user.name}/outbox",
url = "${applicationConfig.url}/users/${user.name}",
inbox = "$userUrl/inbox",
outbox = "$userUrl/outbox",
url = userUrl,
publicKey = keyPair.public.toPem(),
privateKey = keyPair.private.toPem(),
createdAt = Instant.now()
createdAt = Instant.now(),
following = "$userUrl/following",
followers = "$userUrl/followers",
keyId = "$userUrl#pubkey"
)
return userRepository.save(userEntity)
}
@ -63,7 +67,10 @@ class UserServiceImpl(
outbox = user.outbox,
url = user.url,
publicKey = user.publicKey,
createdAt = Instant.now()
createdAt = Instant.now(),
followers = user.followers,
following = user.following,
keyId = user.keyId
)
return try {
userRepository.save(userEntity)

View File

@ -48,7 +48,8 @@ class APNoteServiceImplTest {
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = "a"
),
User.of(
3L,
@ -61,7 +62,8 @@ class APNoteServiceImplTest {
"https://follower2.example.com",
"https://follower2.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = "a"
)
)
val userQueryService = mock<UserQueryService> {
@ -77,7 +79,8 @@ class APNoteServiceImplTest {
"https://example.com",
publicKey = "",
privateKey = "a",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = "a"
)
}
val followerQueryService = mock<FollowerQueryService> {

View File

@ -102,7 +102,9 @@ class APReceiveFollowServiceImplTest {
id = "https://follower.example.com#main-key",
owner = "https://follower.example.com",
publicKeyPem = "BEGIN PUBLIC KEY...END PUBLIC KEY",
)
),
followers = "",
following = ""
)
val apUserService = mock<APUserService> {
@ -120,7 +122,8 @@ class APReceiveFollowServiceImplTest {
outbox = "https://example.com/outbox",
url = "https://example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = "a"
)
onBlocking { findByUrl(eq("https://follower.example.com")) } doReturn
User.of(
@ -133,7 +136,8 @@ class APReceiveFollowServiceImplTest {
outbox = "https://follower.example.com/outbox",
url = "https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = "a"
)
}

View File

@ -47,7 +47,8 @@ class APResourceResolveServiceImplTest {
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = ""
)
)
@ -82,7 +83,8 @@ class APResourceResolveServiceImplTest {
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = ""
)
)
@ -120,7 +122,8 @@ class APResourceResolveServiceImplTest {
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = ""
)
)
@ -169,7 +172,8 @@ class APResourceResolveServiceImplTest {
"https://follower.example.com",
"https://follower.example.com",
publicKey = "",
createdAt = Instant.now()
createdAt = Instant.now(),
keyId = ""
)
)

View File

@ -58,14 +58,17 @@ class UserServiceTest {
}
val userService = UserServiceImpl(userRepository, mock(), mock(), mock(), mock(), testApplicationConfig)
val user = RemoteUserCreateDto(
"test",
"example.com",
"testUser",
"test user",
"https://example.com/inbox",
"https://example.com/outbox",
"https://example.com",
"-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"
name = "test",
domain = "example.com",
screenName = "testUser",
description = "test user",
inbox = "https://example.com/inbox",
outbox = "https://example.com/outbox",
url = "https://example.com",
publicKey = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----",
keyId = "a",
following = "",
followers = ""
)
userService.createRemoteUser(user)
verify(userRepository, times(1)).save(any())