mirror of https://github.com/usbharu/Hideout.git
Merge pull request #94 from usbharu/feature/entity-builder
Feature/entity builder
This commit is contained in:
commit
8347bd7d0f
|
@ -1,64 +0,0 @@
|
|||
package dev.usbharu.hideout.config
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
object Config {
|
||||
var configData: ConfigData = ConfigData()
|
||||
}
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
data class ConfigData(
|
||||
val url: String = "",
|
||||
val domain: String = url.substringAfter("://").substringBeforeLast(":"),
|
||||
val objectMapper: ObjectMapper = jacksonObjectMapper(),
|
||||
val characterLimit: CharacterLimit = CharacterLimit()
|
||||
)
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
data class CharacterLimit(
|
||||
val general: General = General.of(),
|
||||
val post: Post = Post(),
|
||||
val account: Account = Account(),
|
||||
val instance: Instance = Instance()
|
||||
) {
|
||||
@Deprecated("Config is deprecated")
|
||||
data class General private constructor(
|
||||
val url: Int,
|
||||
val domain: Int,
|
||||
val publicKey: Int,
|
||||
val privateKey: Int
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("FunctionMinLength")
|
||||
fun of(url: Int? = null, domain: Int? = null, publicKey: Int? = null, privateKey: Int? = null): General {
|
||||
return General(
|
||||
url ?: 1000,
|
||||
domain ?: 1000,
|
||||
publicKey ?: 10000,
|
||||
privateKey ?: 10000
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
data class Post(
|
||||
val text: Int = 3000,
|
||||
val overview: Int = 3000
|
||||
)
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
data class Account(
|
||||
val id: Int = 300,
|
||||
val name: Int = 300,
|
||||
val description: Int = 10000
|
||||
)
|
||||
|
||||
@Deprecated("Config is deprecated")
|
||||
data class Instance(
|
||||
val name: Int = 600,
|
||||
val description: Int = 10000
|
||||
)
|
||||
}
|
|
@ -43,3 +43,35 @@ data class StorageConfig(
|
|||
val accessKey: String,
|
||||
val secretKey: String
|
||||
)
|
||||
|
||||
@ConfigurationProperties("hideout.character-limit")
|
||||
data class CharacterLimit(
|
||||
val general: General = General(),
|
||||
val post: Post = Post(),
|
||||
val account: Account = Account(),
|
||||
val instance: Instance = Instance()
|
||||
) {
|
||||
|
||||
data class General(
|
||||
val url: Int = 1000,
|
||||
val domain: Int = 1000,
|
||||
val publicKey: Int = 10000,
|
||||
val privateKey: Int = 10000
|
||||
)
|
||||
|
||||
data class Post(
|
||||
val text: Int = 3000,
|
||||
val overview: Int = 3000
|
||||
)
|
||||
|
||||
data class Account(
|
||||
val id: Int = 300,
|
||||
val name: Int = 300,
|
||||
val description: Int = 10000
|
||||
)
|
||||
|
||||
data class Instance(
|
||||
val name: Int = 600,
|
||||
val description: Int = 10000
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package dev.usbharu.hideout.domain.model.hideout.entity
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
data class Post private constructor(
|
||||
val id: Long,
|
||||
|
@ -16,7 +17,9 @@ data class Post private constructor(
|
|||
val apId: String = url,
|
||||
val mediaIds: List<Long> = emptyList()
|
||||
) {
|
||||
companion object {
|
||||
|
||||
@Component
|
||||
class PostBuilder(private val characterLimit: CharacterLimit) {
|
||||
@Suppress("FunctionMinLength", "LongParameterList")
|
||||
fun of(
|
||||
id: Long,
|
||||
|
@ -32,8 +35,6 @@ data class Post private constructor(
|
|||
apId: String = url,
|
||||
mediaIds: List<Long> = emptyList()
|
||||
): Post {
|
||||
val characterLimit = Config.configData.characterLimit
|
||||
|
||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
||||
|
||||
require(userId >= 0) { "userId must be greater than or equal to 0." }
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package dev.usbharu.hideout.domain.model.hideout.entity
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Instant
|
||||
|
||||
data class User private constructor(
|
||||
|
@ -27,9 +29,9 @@ data class User private constructor(
|
|||
" privateKey=$privateKey, createdAt=$createdAt, keyId='$keyId', followers=$followers," +
|
||||
" following=$following)"
|
||||
|
||||
companion object {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(User::class.java)
|
||||
@Component
|
||||
class UserBuilder(private val characterLimit: CharacterLimit, private val applicationConfig: ApplicationConfig) {
|
||||
private val logger = LoggerFactory.getLogger(UserBuilder::class.java)
|
||||
|
||||
@Suppress("LongParameterList", "FunctionMinLength", "LongMethod")
|
||||
fun of(
|
||||
|
@ -49,8 +51,6 @@ data class User private constructor(
|
|||
following: String? = null,
|
||||
followers: String? = null
|
||||
): User {
|
||||
val characterLimit = Config.configData.characterLimit
|
||||
|
||||
// idは0未満ではいけない
|
||||
require(id >= 0) { "id must be greater than or equal to 0." }
|
||||
|
||||
|
@ -93,7 +93,7 @@ data class User private constructor(
|
|||
}
|
||||
|
||||
// ローカルユーザーはpasswordとprivateKeyをnullにしてはいけない
|
||||
if (domain == Config.configData.domain) {
|
||||
if (domain == applicationConfig.url.host) {
|
||||
requireNotNull(password) { "password and privateKey must not be null for local users." }
|
||||
requireNotNull(privateKey) { "password and privateKey must not be null for local users." }
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import org.springframework.stereotype.Repository
|
|||
import java.time.Instant
|
||||
|
||||
@Repository
|
||||
class FollowerQueryServiceImpl : FollowerQueryService {
|
||||
class FollowerQueryServiceImpl(private val userBuilder: User.UserBuilder) : FollowerQueryService {
|
||||
override suspend fun findFollowersById(id: Long): List<User> {
|
||||
val followers = Users.alias("FOLLOWERS")
|
||||
return Users.innerJoin(
|
||||
|
@ -41,7 +41,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
|
|||
)
|
||||
.select { Users.id eq id }
|
||||
.map {
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = it[followers[Users.id]],
|
||||
name = it[followers[Users.name]],
|
||||
domain = it[followers[Users.domain]],
|
||||
|
@ -92,7 +92,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
|
|||
)
|
||||
.select { Users.name eq name and (Users.domain eq domain) }
|
||||
.map {
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = it[followers[Users.id]],
|
||||
name = it[followers[Users.name]],
|
||||
domain = it[followers[Users.domain]],
|
||||
|
@ -143,7 +143,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
|
|||
)
|
||||
.select { followers[Users.id] eq id }
|
||||
.map {
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = it[followers[Users.id]],
|
||||
name = it[followers[Users.name]],
|
||||
domain = it[followers[Users.domain]],
|
||||
|
@ -194,7 +194,7 @@ class FollowerQueryServiceImpl : FollowerQueryService {
|
|||
)
|
||||
.select { followers[Users.name] eq name and (followers[Users.domain] eq domain) }
|
||||
.map {
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = it[followers[Users.id]],
|
||||
name = it[followers[Users.name]],
|
||||
domain = it[followers[Users.domain]],
|
||||
|
|
|
@ -4,27 +4,32 @@ import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
|||
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
||||
import dev.usbharu.hideout.repository.Posts
|
||||
import dev.usbharu.hideout.repository.PostsMedia
|
||||
import dev.usbharu.hideout.repository.toPost
|
||||
import dev.usbharu.hideout.repository.QueryMapper
|
||||
import dev.usbharu.hideout.repository.ResultRowMapper
|
||||
import dev.usbharu.hideout.util.singleOr
|
||||
import org.jetbrains.exposed.sql.select
|
||||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class PostQueryServiceImpl : PostQueryService {
|
||||
class PostQueryServiceImpl(
|
||||
private val postResultRowMapper: ResultRowMapper<Post>,
|
||||
private val postQueryMapper: QueryMapper<Post>
|
||||
) : PostQueryService {
|
||||
override suspend fun findById(id: Long): Post =
|
||||
Posts.leftJoin(PostsMedia)
|
||||
.select { Posts.id eq id }
|
||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }.toPost()
|
||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }
|
||||
.let(postResultRowMapper::map)
|
||||
|
||||
override suspend fun findByUrl(url: String): Post =
|
||||
Posts.leftJoin(PostsMedia)
|
||||
.select { Posts.url eq url }
|
||||
.toPost()
|
||||
.let(postQueryMapper::map)
|
||||
.singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }
|
||||
|
||||
override suspend fun findByApId(string: String): Post =
|
||||
Posts.leftJoin(PostsMedia)
|
||||
.select { Posts.apId eq string }
|
||||
.toPost()
|
||||
.let(postQueryMapper::map)
|
||||
.singleOr { FailedToGetResourcesException("apId: $string is duplicate or does not exist.", it) }
|
||||
}
|
||||
|
|
|
@ -2,8 +2,9 @@ package dev.usbharu.hideout.query
|
|||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
||||
import dev.usbharu.hideout.repository.QueryMapper
|
||||
import dev.usbharu.hideout.repository.ResultRowMapper
|
||||
import dev.usbharu.hideout.repository.Users
|
||||
import dev.usbharu.hideout.repository.toUser
|
||||
import dev.usbharu.hideout.util.singleOr
|
||||
import org.jetbrains.exposed.sql.and
|
||||
import org.jetbrains.exposed.sql.select
|
||||
|
@ -12,17 +13,22 @@ import org.slf4j.LoggerFactory
|
|||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class UserQueryServiceImpl : UserQueryService {
|
||||
class UserQueryServiceImpl(
|
||||
private val userResultRowMapper: ResultRowMapper<User>,
|
||||
private val userQueryMapper: QueryMapper<User>
|
||||
) : UserQueryService {
|
||||
|
||||
private val logger = LoggerFactory.getLogger(UserQueryServiceImpl::class.java)
|
||||
|
||||
override suspend fun findAll(limit: Int, offset: Long): List<User> =
|
||||
Users.selectAll().limit(limit, offset).map { it.toUser() }
|
||||
Users.selectAll().limit(limit, offset).let(userQueryMapper::map)
|
||||
|
||||
override suspend fun findById(id: Long): User = Users.select { Users.id eq id }
|
||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }.toUser()
|
||||
.singleOr { FailedToGetResourcesException("id: $id is duplicate or does not exist.", it) }
|
||||
.let(userResultRowMapper::map)
|
||||
|
||||
override suspend fun findByName(name: String): List<User> = Users.select { Users.name eq name }.map { it.toUser() }
|
||||
override suspend fun findByName(name: String): List<User> =
|
||||
Users.select { Users.name eq name }.let(userQueryMapper::map)
|
||||
|
||||
override suspend fun findByNameAndDomain(name: String, domain: String): User =
|
||||
Users
|
||||
|
@ -30,17 +36,17 @@ class UserQueryServiceImpl : UserQueryService {
|
|||
.singleOr {
|
||||
FailedToGetResourcesException("name: $name,domain: $domain is duplicate or does not exist.", it)
|
||||
}
|
||||
.toUser()
|
||||
.let(userResultRowMapper::map)
|
||||
|
||||
override suspend fun findByUrl(url: String): User {
|
||||
logger.trace("findByUrl url: $url")
|
||||
return Users.select { Users.url eq url }
|
||||
.singleOr { FailedToGetResourcesException("url: $url is duplicate or does not exist.", it) }
|
||||
.toUser()
|
||||
.let(userResultRowMapper::map)
|
||||
}
|
||||
|
||||
override suspend fun findByIds(ids: List<Long>): List<User> =
|
||||
Users.select { Users.id inList ids }.map { it.toUser() }
|
||||
Users.select { Users.id inList ids }.let(userQueryMapper::map)
|
||||
|
||||
override suspend fun existByNameAndDomain(name: String, domain: String): Boolean =
|
||||
Users.select { Users.name eq name and (Users.domain eq domain) }.empty().not()
|
||||
|
@ -48,6 +54,6 @@ class UserQueryServiceImpl : UserQueryService {
|
|||
override suspend fun findByKeyId(keyId: String): User {
|
||||
return Users.select { Users.keyId eq keyId }
|
||||
.singleOr { FailedToGetResourcesException("keyId: $keyId is duplicate or does not exist.", it) }
|
||||
.toUser()
|
||||
.let(userResultRowMapper::map)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,14 +13,15 @@ import org.springframework.stereotype.Repository
|
|||
import java.time.Instant
|
||||
|
||||
@Repository
|
||||
class NoteQueryServiceImpl(private val postRepository: PostRepository) : NoteQueryService {
|
||||
class NoteQueryServiceImpl(private val postRepository: PostRepository, private val postQueryMapper: QueryMapper<Post>) :
|
||||
NoteQueryService {
|
||||
override suspend fun findById(id: Long): Pair<Note, Post> {
|
||||
return Posts
|
||||
.leftJoin(Users)
|
||||
.leftJoin(PostsMedia)
|
||||
.leftJoin(Media)
|
||||
.select { Posts.id eq id }
|
||||
.let { it.toNote() to it.toPost().first() }
|
||||
.let { it.toNote() to postQueryMapper.map(it).first() }
|
||||
}
|
||||
|
||||
private suspend fun ResultRow.toNote(mediaList: List<dev.usbharu.hideout.domain.model.hideout.entity.Media>): Note {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import org.jetbrains.exposed.sql.Query
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PostQueryMapper(private val postResultRowMapper: ResultRowMapper<Post>) : QueryMapper<Post> {
|
||||
override fun map(query: Query): List<Post> {
|
||||
return query.groupBy { it[Posts.id] }
|
||||
.map { it.value }
|
||||
.map {
|
||||
it.first().let(postResultRowMapper::map)
|
||||
.copy(mediaIds = it.mapNotNull { it.getOrNull(PostsMedia.mediaId) })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
import dev.usbharu.hideout.exception.FailedToGetResourcesException
|
||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||
import org.jetbrains.exposed.sql.*
|
||||
|
@ -9,7 +8,10 @@ import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
|||
import org.springframework.stereotype.Repository
|
||||
|
||||
@Repository
|
||||
class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : PostRepository {
|
||||
class PostRepositoryImpl(
|
||||
private val idGenerateService: IdGenerateService,
|
||||
private val postQueryMapper: QueryMapper<Post>
|
||||
) : PostRepository {
|
||||
|
||||
override suspend fun generateId(): Long = idGenerateService.generateId()
|
||||
|
||||
|
@ -65,7 +67,7 @@ class PostRepositoryImpl(private val idGenerateService: IdGenerateService) : Pos
|
|||
override suspend fun findById(id: Long): Post =
|
||||
Posts.innerJoin(PostsMedia, onColumn = { Posts.id }, otherColumn = { PostsMedia.postId })
|
||||
.select { Posts.id eq id }
|
||||
.toPost()
|
||||
.let(postQueryMapper::map)
|
||||
.singleOrNull()
|
||||
?: throw FailedToGetResourcesException("id: $id was not found.")
|
||||
|
||||
|
@ -94,25 +96,3 @@ object PostsMedia : Table() {
|
|||
val mediaId = long("media_id").references(Media.id, ReferenceOption.CASCADE, ReferenceOption.CASCADE)
|
||||
override val primaryKey = PrimaryKey(postId, mediaId)
|
||||
}
|
||||
|
||||
fun ResultRow.toPost(): Post {
|
||||
return Post.of(
|
||||
id = this[Posts.id],
|
||||
userId = this[Posts.userId],
|
||||
overview = this[Posts.overview],
|
||||
text = this[Posts.text],
|
||||
createdAt = this[Posts.createdAt],
|
||||
visibility = Visibility.values().first { visibility -> visibility.ordinal == this[Posts.visibility] },
|
||||
url = this[Posts.url],
|
||||
repostId = this[Posts.repostId],
|
||||
replyId = this[Posts.replyId],
|
||||
sensitive = this[Posts.sensitive],
|
||||
apId = this[Posts.apId],
|
||||
)
|
||||
}
|
||||
|
||||
fun Query.toPost(): List<Post> {
|
||||
return this.groupBy { it[Posts.id] }
|
||||
.map { it.value }
|
||||
.map { it.first().toPost().copy(mediaIds = it.mapNotNull { it.getOrNull(PostsMedia.mediaId) }) }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class PostResultRowMapper(private val postBuilder: Post.PostBuilder) : ResultRowMapper<Post> {
|
||||
override fun map(resultRow: ResultRow): Post {
|
||||
return postBuilder.of(
|
||||
id = resultRow[Posts.id],
|
||||
userId = resultRow[Posts.userId],
|
||||
overview = resultRow[Posts.overview],
|
||||
text = resultRow[Posts.text],
|
||||
createdAt = resultRow[Posts.createdAt],
|
||||
visibility = Visibility.values().first { visibility -> visibility.ordinal == resultRow[Posts.visibility] },
|
||||
url = resultRow[Posts.url],
|
||||
repostId = resultRow[Posts.repostId],
|
||||
replyId = resultRow[Posts.replyId],
|
||||
sensitive = resultRow[Posts.sensitive],
|
||||
apId = resultRow[Posts.apId],
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import org.jetbrains.exposed.sql.Query
|
||||
|
||||
interface QueryMapper<T> {
|
||||
fun map(query: Query): List<T>
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
|
||||
interface ResultRowMapper<T> {
|
||||
fun map(resultRow: ResultRow): T
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import org.jetbrains.exposed.sql.Query
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
class UserQueryMapper(private val userResultRowMapper: ResultRowMapper<User>) : QueryMapper<User> {
|
||||
override fun map(query: Query): List<User> {
|
||||
return query.map(userResultRowMapper::map)
|
||||
}
|
||||
}
|
|
@ -1,16 +1,17 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.service.core.IdGenerateService
|
||||
import org.jetbrains.exposed.dao.id.LongIdTable
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.time.Instant
|
||||
|
||||
@Repository
|
||||
class UserRepositoryImpl(private val idGenerateService: IdGenerateService) :
|
||||
class UserRepositoryImpl(
|
||||
private val idGenerateService: IdGenerateService,
|
||||
private val userResultRowMapper: ResultRowMapper<User>
|
||||
) :
|
||||
UserRepository {
|
||||
|
||||
override suspend fun save(user: User): User {
|
||||
|
@ -55,9 +56,7 @@ class UserRepositoryImpl(private val idGenerateService: IdGenerateService) :
|
|||
}
|
||||
|
||||
override suspend fun findById(id: Long): User? {
|
||||
return Users.select { Users.id eq id }.map {
|
||||
it.toUser()
|
||||
}.singleOrNull()
|
||||
return Users.select { Users.id eq id }.singleOrNull()?.let(userResultRowMapper::map)
|
||||
}
|
||||
|
||||
override suspend fun deleteFollowRequest(id: Long, follower: Long) {
|
||||
|
@ -78,26 +77,26 @@ class UserRepositoryImpl(private val idGenerateService: IdGenerateService) :
|
|||
|
||||
object Users : Table("users") {
|
||||
val id: Column<Long> = long("id")
|
||||
val name: Column<String> = varchar("name", length = Config.configData.characterLimit.account.id)
|
||||
val domain: Column<String> = varchar("domain", length = Config.configData.characterLimit.general.domain)
|
||||
val screenName: Column<String> = varchar("screen_name", length = Config.configData.characterLimit.account.name)
|
||||
val name: Column<String> = varchar("name", length = 300)
|
||||
val domain: Column<String> = varchar("domain", length = 1000)
|
||||
val screenName: Column<String> = varchar("screen_name", length = 300)
|
||||
val description: Column<String> = varchar(
|
||||
"description",
|
||||
length = Config.configData.characterLimit.account.description
|
||||
length = 10000
|
||||
)
|
||||
val password: Column<String?> = varchar("password", length = 255).nullable()
|
||||
val inbox: Column<String> = varchar("inbox", length = Config.configData.characterLimit.general.url).uniqueIndex()
|
||||
val outbox: Column<String> = varchar("outbox", length = Config.configData.characterLimit.general.url).uniqueIndex()
|
||||
val url: Column<String> = varchar("url", length = Config.configData.characterLimit.general.url).uniqueIndex()
|
||||
val publicKey: Column<String> = varchar("public_key", length = Config.configData.characterLimit.general.publicKey)
|
||||
val inbox: Column<String> = varchar("inbox", length = 1000).uniqueIndex()
|
||||
val outbox: Column<String> = varchar("outbox", length = 1000).uniqueIndex()
|
||||
val url: Column<String> = varchar("url", length = 1000).uniqueIndex()
|
||||
val publicKey: Column<String> = varchar("public_key", length = 10000)
|
||||
val privateKey: Column<String?> = varchar(
|
||||
"private_key",
|
||||
length = Config.configData.characterLimit.general.privateKey
|
||||
length = 10000
|
||||
).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()
|
||||
val keyId = varchar("key_id", length = 1000)
|
||||
val following = varchar("following", length = 1000).nullable()
|
||||
val followers = varchar("followers", length = 1000).nullable()
|
||||
|
||||
override val primaryKey: PrimaryKey = PrimaryKey(id)
|
||||
|
||||
|
@ -106,26 +105,6 @@ object Users : Table("users") {
|
|||
}
|
||||
}
|
||||
|
||||
fun ResultRow.toUser(): User {
|
||||
return User.of(
|
||||
id = this[Users.id],
|
||||
name = this[Users.name],
|
||||
domain = this[Users.domain],
|
||||
screenName = this[Users.screenName],
|
||||
description = this[Users.description],
|
||||
password = this[Users.password],
|
||||
inbox = this[Users.inbox],
|
||||
outbox = this[Users.outbox],
|
||||
url = this[Users.url],
|
||||
publicKey = this[Users.publicKey],
|
||||
privateKey = this[Users.privateKey],
|
||||
createdAt = Instant.ofEpochMilli((this[Users.createdAt])),
|
||||
keyId = this[Users.keyId],
|
||||
followers = this[Users.followers],
|
||||
following = this[Users.following]
|
||||
)
|
||||
}
|
||||
|
||||
object UsersFollowers : LongIdTable("users_followers") {
|
||||
val userId: Column<Long> = long("user_id").references(Users.id).index()
|
||||
val followerId: Column<Long> = long("follower_id").references(Users.id)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package dev.usbharu.hideout.repository
|
||||
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.Instant
|
||||
|
||||
@Component
|
||||
class UserResultRowMapper(private val userBuilder: User.UserBuilder) : ResultRowMapper<User> {
|
||||
override fun map(resultRow: ResultRow): User {
|
||||
return userBuilder.of(
|
||||
id = resultRow[Users.id],
|
||||
name = resultRow[Users.name],
|
||||
domain = resultRow[Users.domain],
|
||||
screenName = resultRow[Users.screenName],
|
||||
description = resultRow[Users.description],
|
||||
password = resultRow[Users.password],
|
||||
inbox = resultRow[Users.inbox],
|
||||
outbox = resultRow[Users.outbox],
|
||||
url = resultRow[Users.url],
|
||||
publicKey = resultRow[Users.publicKey],
|
||||
privateKey = resultRow[Users.privateKey],
|
||||
createdAt = Instant.ofEpochMilli((resultRow[Users.createdAt])),
|
||||
keyId = resultRow[Users.keyId],
|
||||
followers = resultRow[Users.followers],
|
||||
following = resultRow[Users.following]
|
||||
)
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ class APNoteServiceImpl(
|
|||
private val postService: PostService,
|
||||
private val apResourceResolveService: APResourceResolveService,
|
||||
private val apRequestService: APRequestService,
|
||||
private val postBuilder: Post.PostBuilder,
|
||||
private val transaction: Transaction
|
||||
|
||||
) : APNoteService, PostCreateInterceptor {
|
||||
|
@ -224,7 +225,7 @@ class APNoteServiceImpl(
|
|||
|
||||
// TODO: リモートのメディア処理を追加
|
||||
postService.createRemote(
|
||||
Post.of(
|
||||
postBuilder.of(
|
||||
id = postRepository.generateId(),
|
||||
userId = person.second.id,
|
||||
text = note.content.orEmpty(),
|
||||
|
|
|
@ -16,7 +16,8 @@ class PostServiceImpl(
|
|||
private val postRepository: PostRepository,
|
||||
private val userRepository: UserRepository,
|
||||
private val timelineService: TimelineService,
|
||||
private val postQueryService: PostQueryService
|
||||
private val postQueryService: PostQueryService,
|
||||
private val postBuilder: Post.PostBuilder
|
||||
) : PostService {
|
||||
private val interceptors = Collections.synchronizedList(mutableListOf<PostCreateInterceptor>())
|
||||
|
||||
|
@ -45,7 +46,7 @@ class PostServiceImpl(
|
|||
private suspend fun internalCreate(post: PostCreateDto, isLocal: Boolean): Post {
|
||||
val user = userRepository.findById(post.userId) ?: throw UserNotFoundException("${post.userId} was not found")
|
||||
val id = postRepository.generateId()
|
||||
val createPost = Post.of(
|
||||
val createPost = postBuilder.of(
|
||||
id = id,
|
||||
userId = post.userId,
|
||||
overview = post.overview,
|
||||
|
|
|
@ -21,6 +21,7 @@ class UserServiceImpl(
|
|||
private val apSendFollowService: APSendFollowService,
|
||||
private val userQueryService: UserQueryService,
|
||||
private val followerQueryService: FollowerQueryService,
|
||||
private val userBuilder: User.UserBuilder,
|
||||
private val applicationConfig: ApplicationConfig
|
||||
) :
|
||||
UserService {
|
||||
|
@ -35,7 +36,7 @@ class UserServiceImpl(
|
|||
val hashedPassword = userAuthService.hash(user.password)
|
||||
val keyPair = userAuthService.generateKeyPair()
|
||||
val userUrl = "${applicationConfig.url}/users/${user.name}"
|
||||
val userEntity = User.of(
|
||||
val userEntity = userBuilder.of(
|
||||
id = nextId,
|
||||
name = user.name,
|
||||
domain = applicationConfig.url.host,
|
||||
|
@ -57,7 +58,7 @@ class UserServiceImpl(
|
|||
|
||||
override suspend fun createRemoteUser(user: RemoteUserCreateDto): User {
|
||||
val nextId = userRepository.nextId()
|
||||
val userEntity = User.of(
|
||||
val userEntity = userBuilder.of(
|
||||
id = nextId,
|
||||
name = user.name,
|
||||
domain = user.domain,
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
package dev.usbharu.hideout.service.ap
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.config.ConfigData
|
||||
import dev.usbharu.hideout.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Visibility
|
||||
|
@ -23,21 +23,28 @@ import org.junit.jupiter.api.Test
|
|||
import org.mockito.Mockito.anyLong
|
||||
import org.mockito.Mockito.eq
|
||||
import org.mockito.kotlin.*
|
||||
import utils.JsonObjectMapper
|
||||
import utils.JsonObjectMapper.objectMapper
|
||||
import utils.TestApplicationConfig.testApplicationConfig
|
||||
import java.net.URL
|
||||
import java.time.Instant
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class APNoteServiceImplTest {
|
||||
|
||||
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
|
||||
val postBuilder = Post.PostBuilder(CharacterLimit())
|
||||
|
||||
@Test
|
||||
fun `createPost 新しい投稿`() {
|
||||
val mediaQueryService = mock<MediaQueryService> {
|
||||
onBlocking { findByPostId(anyLong()) } doReturn emptyList()
|
||||
}
|
||||
|
||||
|
||||
|
||||
runTest {
|
||||
val followers = listOf(
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
|
@ -51,7 +58,7 @@ class APNoteServiceImplTest {
|
|||
createdAt = Instant.now(),
|
||||
keyId = "a"
|
||||
),
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
3L,
|
||||
"follower2",
|
||||
"follower2.example.com",
|
||||
|
@ -67,7 +74,7 @@ class APNoteServiceImplTest {
|
|||
)
|
||||
)
|
||||
val userQueryService = mock<UserQueryService> {
|
||||
onBlocking { findById(eq(1L)) } doReturn User.of(
|
||||
onBlocking { findById(eq(1L)) } doReturn userBuilder.of(
|
||||
1L,
|
||||
"test",
|
||||
"example.com",
|
||||
|
@ -101,9 +108,10 @@ class APNoteServiceImplTest {
|
|||
postService = mock(),
|
||||
apResourceResolveService = mock(),
|
||||
apRequestService = mock(),
|
||||
transaction = mock()
|
||||
transaction = mock(),
|
||||
postBuilder = postBuilder
|
||||
)
|
||||
val postEntity = Post.of(
|
||||
val postEntity = postBuilder.of(
|
||||
1L,
|
||||
1L,
|
||||
null,
|
||||
|
@ -123,7 +131,7 @@ class APNoteServiceImplTest {
|
|||
val mediaQueryService = mock<MediaQueryService> {
|
||||
onBlocking { findByPostId(anyLong()) } doReturn emptyList()
|
||||
}
|
||||
Config.configData = ConfigData(objectMapper = JsonObjectMapper.objectMapper)
|
||||
|
||||
val httpClient = HttpClient(
|
||||
MockEngine { httpRequestData ->
|
||||
assertEquals("https://follower.example.com/inbox", httpRequestData.url.toString())
|
||||
|
@ -143,7 +151,8 @@ class APNoteServiceImplTest {
|
|||
postService = mock(),
|
||||
apResourceResolveService = mock(),
|
||||
apRequestService = mock(),
|
||||
transaction = mock()
|
||||
transaction = mock(),
|
||||
postBuilder = postBuilder
|
||||
)
|
||||
activityPubNoteService.createNoteJob(
|
||||
JobProps(
|
||||
|
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
package dev.usbharu.hideout.service.ap
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.config.ConfigData
|
||||
import dev.usbharu.hideout.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import dev.usbharu.hideout.domain.model.ap.Follow
|
||||
import dev.usbharu.hideout.domain.model.ap.Image
|
||||
import dev.usbharu.hideout.domain.model.ap.Key
|
||||
import dev.usbharu.hideout.domain.model.ap.Person
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.domain.model.job.ReceiveFollowJob
|
||||
import dev.usbharu.hideout.query.UserQueryService
|
||||
|
@ -23,12 +24,16 @@ import org.junit.jupiter.api.Assertions.assertEquals
|
|||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.kotlin.*
|
||||
import utils.JsonObjectMapper
|
||||
import utils.JsonObjectMapper.objectMapper
|
||||
import utils.TestTransaction
|
||||
import java.net.URL
|
||||
import java.time.Instant
|
||||
|
||||
class APReceiveFollowServiceImplTest {
|
||||
|
||||
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
|
||||
val postBuilder = Post.PostBuilder(CharacterLimit())
|
||||
|
||||
@Test
|
||||
fun `receiveFollow フォロー受付処理`() = runTest {
|
||||
val jobQueueParentService = mock<JobQueueParentService> {
|
||||
|
@ -80,7 +85,6 @@ class APReceiveFollowServiceImplTest {
|
|||
|
||||
@Test
|
||||
fun `receiveFollowJob フォロー受付処理のJob`() = runTest {
|
||||
Config.configData = ConfigData(objectMapper = JsonObjectMapper.objectMapper)
|
||||
val person = Person(
|
||||
type = emptyList(),
|
||||
name = "follower",
|
||||
|
@ -112,7 +116,7 @@ class APReceiveFollowServiceImplTest {
|
|||
}
|
||||
val userQueryService = mock<UserQueryService> {
|
||||
onBlocking { findByUrl(eq("https://example.com")) } doReturn
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = 1L,
|
||||
name = "test",
|
||||
domain = "example.com",
|
||||
|
@ -122,11 +126,13 @@ class APReceiveFollowServiceImplTest {
|
|||
outbox = "https://example.com/outbox",
|
||||
url = "https://example.com",
|
||||
publicKey = "",
|
||||
password = "a",
|
||||
privateKey = "a",
|
||||
createdAt = Instant.now(),
|
||||
keyId = "a"
|
||||
)
|
||||
onBlocking { findByUrl(eq("https://follower.example.com")) } doReturn
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
id = 2L,
|
||||
name = "follower",
|
||||
domain = "follower.example.com",
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package dev.usbharu.hideout.service.ap.resource
|
||||
|
||||
import dev.usbharu.hideout.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import dev.usbharu.hideout.domain.model.ap.Object
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.repository.UserRepository
|
||||
import io.ktor.client.*
|
||||
|
@ -16,6 +19,7 @@ import org.mockito.kotlin.any
|
|||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
import java.net.URL
|
||||
import java.time.Instant
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
@ -23,6 +27,9 @@ import kotlin.test.assertEquals
|
|||
@Disabled
|
||||
class APResourceResolveServiceImplTest {
|
||||
|
||||
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
|
||||
val postBuilder = Post.PostBuilder(CharacterLimit())
|
||||
|
||||
@Test
|
||||
fun `単純な一回のリクエスト`() = runTest {
|
||||
|
||||
|
@ -36,7 +43,7 @@ class APResourceResolveServiceImplTest {
|
|||
val userRepository = mock<UserRepository>()
|
||||
|
||||
whenever(userRepository.findById(any())).doReturn(
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
|
@ -72,7 +79,7 @@ class APResourceResolveServiceImplTest {
|
|||
val userRepository = mock<UserRepository>()
|
||||
|
||||
whenever(userRepository.findById(any())).doReturn(
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
|
@ -111,7 +118,7 @@ class APResourceResolveServiceImplTest {
|
|||
val userRepository = mock<UserRepository>()
|
||||
|
||||
whenever(userRepository.findById(any())).doReturn(
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
|
@ -161,7 +168,7 @@ class APResourceResolveServiceImplTest {
|
|||
val userRepository = mock<UserRepository>()
|
||||
|
||||
whenever(userRepository.findById(any())).doReturn(
|
||||
User.of(
|
||||
userBuilder.of(
|
||||
2L,
|
||||
"follower",
|
||||
"follower.example.com",
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
package dev.usbharu.hideout.service.user
|
||||
|
||||
import dev.usbharu.hideout.config.Config
|
||||
import dev.usbharu.hideout.config.ConfigData
|
||||
import dev.usbharu.hideout.config.ApplicationConfig
|
||||
import dev.usbharu.hideout.config.CharacterLimit
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.RemoteUserCreateDto
|
||||
import dev.usbharu.hideout.domain.model.hideout.dto.UserCreateDto
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.Post
|
||||
import dev.usbharu.hideout.domain.model.hideout.entity.User
|
||||
import dev.usbharu.hideout.repository.UserRepository
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
@ -13,14 +15,17 @@ import org.junit.jupiter.api.Test
|
|||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.kotlin.*
|
||||
import utils.TestApplicationConfig.testApplicationConfig
|
||||
import java.net.URL
|
||||
import java.security.KeyPairGenerator
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class UserServiceTest {
|
||||
val userBuilder = User.UserBuilder(CharacterLimit(), ApplicationConfig(URL("https://example.com")))
|
||||
val postBuilder = Post.PostBuilder(CharacterLimit())
|
||||
@Test
|
||||
fun `createLocalUser ローカルユーザーを作成できる`() = runTest {
|
||||
Config.configData = ConfigData(domain = "example.com", url = "https://example.com")
|
||||
|
||||
val userRepository = mock<UserRepository> {
|
||||
onBlocking { nextId() } doReturn 110001L
|
||||
}
|
||||
|
@ -30,7 +35,15 @@ class UserServiceTest {
|
|||
onBlocking { generateKeyPair() } doReturn generateKeyPair
|
||||
}
|
||||
val userService =
|
||||
UserServiceImpl(userRepository, userAuthService, mock(), mock(), mock(), testApplicationConfig)
|
||||
UserServiceImpl(
|
||||
userRepository,
|
||||
userAuthService,
|
||||
mock(),
|
||||
mock(),
|
||||
mock(),
|
||||
userBuilder,
|
||||
testApplicationConfig,
|
||||
)
|
||||
userService.createLocalUser(UserCreateDto("test", "testUser", "XXXXXXXXXXXXX", "test"))
|
||||
verify(userRepository, times(1)).save(any())
|
||||
argumentCaptor<dev.usbharu.hideout.domain.model.hideout.entity.User> {
|
||||
|
@ -51,20 +64,20 @@ class UserServiceTest {
|
|||
|
||||
@Test
|
||||
fun `createRemoteUser リモートユーザーを作成できる`() = runTest {
|
||||
Config.configData = ConfigData(domain = "remote.example.com", url = "https://remote.example.com")
|
||||
|
||||
val userRepository = mock<UserRepository> {
|
||||
onBlocking { nextId() } doReturn 113345L
|
||||
}
|
||||
val userService = UserServiceImpl(userRepository, mock(), mock(), mock(), mock(), testApplicationConfig)
|
||||
val userService =
|
||||
UserServiceImpl(userRepository, mock(), mock(), mock(), mock(), userBuilder, testApplicationConfig)
|
||||
val user = RemoteUserCreateDto(
|
||||
name = "test",
|
||||
domain = "example.com",
|
||||
domain = "remote.example.com",
|
||||
screenName = "testUser",
|
||||
description = "test user",
|
||||
inbox = "https://example.com/inbox",
|
||||
outbox = "https://example.com/outbox",
|
||||
url = "https://example.com",
|
||||
inbox = "https://remote.example.com/inbox",
|
||||
outbox = "https://remote.example.com/outbox",
|
||||
url = "https://remote.example.com",
|
||||
publicKey = "-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----",
|
||||
keyId = "a",
|
||||
following = "",
|
||||
|
@ -79,10 +92,10 @@ class UserServiceTest {
|
|||
assertEquals("test user", firstValue.description)
|
||||
assertNull(firstValue.password)
|
||||
assertEquals(113345L, firstValue.id)
|
||||
assertEquals("https://example.com", firstValue.url)
|
||||
assertEquals("example.com", firstValue.domain)
|
||||
assertEquals("https://example.com/inbox", firstValue.inbox)
|
||||
assertEquals("https://example.com/outbox", firstValue.outbox)
|
||||
assertEquals("https://remote.example.com", firstValue.url)
|
||||
assertEquals("remote.example.com", firstValue.domain)
|
||||
assertEquals("https://remote.example.com/inbox", firstValue.inbox)
|
||||
assertEquals("https://remote.example.com/outbox", firstValue.outbox)
|
||||
assertEquals("-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----", firstValue.publicKey)
|
||||
assertNull(firstValue.privateKey)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue