Skip to content

Commit

Permalink
feat: 增加划词评论即帖子历史版本功能
Browse files Browse the repository at this point in the history
0. 启动时配置文件加载流程变化
1. 评论不在有单独的表而是通过树形帖子实现
2. 增加记录帖子历史版本
3. 增加划词评论功能
4. 修复bug/接口调整若干

BREAKING CHANGE:
0. 数据库结构更改
1. 诸多接口改变
  • Loading branch information
nullaqua committed Sep 8, 2024
1 parent baec3cb commit 74ce5e7
Show file tree
Hide file tree
Showing 60 changed files with 2,107 additions and 1,012 deletions.
5 changes: 3 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ val swagger_ui_version: String by project
val schema_kenerator_version: String by project

plugins {
kotlin("jvm") version "2.0.0"
kotlin("plugin.serialization") version "2.0.0"
kotlin("jvm") version "2.0.10"
kotlin("plugin.serialization") version "2.0.10"
id("io.ktor.plugin") version "2.3.11"
}

Expand Down Expand Up @@ -55,6 +55,7 @@ dependencies {
//postgresql
val pg_version: String by project
implementation("com.impossibl.pgjdbc-ng:pgjdbc-ng:$pg_version")
implementation("org.postgresql:postgresql:42.7.3")
//h2
val h2_version: String by project
implementation("com.h2database:h2:$h2_version")
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ktor_version=2.3.11
kotlin_version=2.0.0
logback_version=1.5.6
kotlin.code.style=official
exposed_version=0.51.1
exposed_version=0.53.0
hikaricp_version = 5.1.0
koin_version=3.5.6
jline_version=3.26.2
Expand Down
23 changes: 16 additions & 7 deletions src/main/kotlin/subit/ForumBackend.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import io.ktor.server.config.*
import io.ktor.server.config.ConfigLoader.Companion.load
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import net.mamoe.yamlkt.Yaml
import subit.console.command.CommandSet.startCommandThread
import subit.database.loadDatabaseImpl
import subit.logger.ForumLogger
Expand Down Expand Up @@ -42,13 +43,13 @@ private fun parseCommandLineArgs(args: Array<String>): Pair<Array<String>, File>
workDir.mkdirs()

// 是否开启debug模式
debug = argsMap["-debug"]?.toBoolean() ?: false
debug = argsMap["-debug"].toBoolean()
System.setProperty("io.ktor.development", "$debug")

// 去除命令行中的-config参数, 因为ktor会解析此参数进而不加载打包的application.yaml
// 其余参数还原为字符串数组
val resArgs = argsMap.entries
.filterNot { it.key == "-config" || it.key == "-workDir" || it.key == "-debug" }
.filterNot { it.key == "-config" || it.key == "-workDir" || it.key == "-debug" || it.key == "-youthwrite" }
.map { (k, v) -> "$k=$v" }
.toTypedArray()
// 命令行中输入的自定义配置文件
Expand Down Expand Up @@ -81,14 +82,22 @@ fun main(args: Array<String>)
return
}

// 加载主配置文件
val customConfig = ConfigLoader.load(configFile.path)
val defaultConfig = Loader.getResource("application.yaml") ?: error("application.yaml not found")
val customConfig = configFile.inputStream()

val resConfig = Loader.mergeConfigs(defaultConfig, customConfig)
// 创建一个临时文件, 用于存储合并后的配置文件
val tempFile = File.createTempFile("resConfig", ".yaml")
tempFile.writeText(Yaml.encodeToString(resConfig))
println(tempFile.readText())

val resArgs = args1 + "-config=${tempFile.absolutePath}"

// 生成环境
val environment = commandLineEnvironment(args = args1)
val environment = commandLineEnvironment(args = resArgs)
{
// 将打包的application.yaml与命令行中提供的配置文件(没提供某人config.yaml)合并
this.config = this.config.withFallback(customConfig)
ForumLogger.getLogger().info("rootPath: ${this.rootPath}")
ForumLogger.getLogger().info("port: ${this.config}")
}
// 启动服务器
embeddedServer(Netty, environment).start(wait = true)
Expand Down
34 changes: 34 additions & 0 deletions src/main/kotlin/subit/Loader.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package subit

import net.mamoe.yamlkt.Yaml
import net.mamoe.yamlkt.YamlElement
import net.mamoe.yamlkt.YamlMap
import java.io.File
import java.io.InputStream

object Loader
Expand All @@ -14,4 +18,34 @@ object Loader
if (path.startsWith("/")) return Loader::class.java.getResource(path)?.openStream()
return Loader::class.java.getResource("/$path")?.openStream()
}

fun mergeConfigs(vararg configs: File) =
configs.map { it.readText() }
.map { Yaml.decodeYamlFromString(it) }
.reduce { acc, element -> mergeConfig(acc, element) }
/**
* 合并多个配置文件(yaml)若有冲突以前者为准
*/
fun mergeConfigs(vararg configs: InputStream) =
configs.map { it.readAllBytes() }
.map { Yaml.decodeYamlFromString(it.decodeToString()) }
.reduce { acc, element -> mergeConfig(acc, element) }

private fun mergeConfig(a: YamlElement, b: YamlElement): YamlElement
{
if (a is YamlMap && b is YamlMap)
{
val map = mutableMapOf<YamlElement, YamlElement>()
a.entries.forEach { (k, v) ->
val bk = b[k]
if (bk != null) map[k] = mergeConfig(v, bk)
else map[k] = v
}
b.entries.forEach { (k, v) ->
if (a[k] == null) map[k] = v
}
return YamlMap(map)
}
return a
}
}
2 changes: 1 addition & 1 deletion src/main/kotlin/subit/config/SystemConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ data class SystemConfig(

var systemConfig: SystemConfig by config(
"system.yml",
SystemConfig(false, "https://ssubito.subit.org.cn/api")
SystemConfig(false, "https://ssubito.subit.org.cn/api"),
)
2 changes: 1 addition & 1 deletion src/main/kotlin/subit/console/command/CommandSet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ object CommandSet: TreeCommand(
Shell,
Color,
Maintain,
TestDatabase
TestDatabase,
)
{
private val logger = ForumLogger.getLogger()
Expand Down
13 changes: 11 additions & 2 deletions src/main/kotlin/subit/console/command/TestDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ object TestDatabase: Command, KoinComponent
mapOf(
"BannedWords" to dao<BannedWords>(),
"Blocks" to dao<Blocks>(),
"Comments" to dao<Comments>(),
"Likes" to dao<Likes>(),
"Notices" to dao<Notices>(),
"Operations" to dao<Operations>(),
"Permissions" to dao<Permissions>(),
"Posts" to dao<Posts>(),
"PostVersions" to dao<PostVersions>(),
"PrivateChats" to dao<PrivateChats>(),
"Prohibits" to dao<Prohibits>(),
"Reports" to dao<Reports>(),
"Stars" to dao<Stars>(),
"Users" to dao<Users>(),
"WordMarkings" to dao<WordMarkings>(),
)
}

Expand Down Expand Up @@ -151,7 +152,15 @@ object TestDatabase: Command, KoinComponent
return emptyList()

// 注意计算, 例如第一个参数, 此时args.size是3, 而我们需要读取method.parameters[1](这里排除掉了this所以是1), 所以这里是-2
listOf("<${method.parameters[args.size - 2].name}>")
val param = method.parameters[args.size - 2]

if (param.type.classifier is KClass<*> && (param.type.classifier as KClass<*>).isSubclassOf(Enum::class))
{
@Suppress("UNCHECKED_CAST")
return (param.type.classifier as KClass<Enum<*>>).java.enumConstants.map { Candidate(it.name) }
}

listOf("<${param.name}>")
}
}.map { Candidate(it) }
}
Expand Down
22 changes: 18 additions & 4 deletions src/main/kotlin/subit/dataClasses/Aliases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,29 @@ value class PostId(override val value: Long): Id<PostId, Long>

@JvmInline
@Serializable
value class CommentId(override val value: Long): Id<CommentId, Long>
value class PostVersionId(override val value: Long): Id<PostVersionId, Long>
{
override fun toString(): String = value.toString()

companion object
{
fun String.toCommentId() = CommentId(toLong())
fun String.toCommentIdOrNull() = toLongOrNull()?.let(::CommentId)
fun Number.toCommentId() = CommentId(toLong())
fun String.toPostVersionId() = PostVersionId(toLong())
fun String.toPostVersionIdOrNull() = toLongOrNull()?.let(::PostVersionId)
fun Number.toPostVersionId() = PostVersionId(toLong())
}
}

@JvmInline
@Serializable
value class WordMarkingId(override val value: Long): Id<WordMarkingId, Long>
{
override fun toString(): String = value.toString()

companion object
{
fun String.toWordMarkingId() = WordMarkingId(toLong())
fun String.toWordMarkingIdOrNull() = toLongOrNull()?.let(::WordMarkingId)
fun Number.toWordMarkingId() = WordMarkingId(toLong())
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable
* @property reading 阅读权限
*/
@Serializable
data class BlockFull(
data class Block(
val id: BlockId,
val name: String,
val description: String,
Expand All @@ -29,7 +29,7 @@ data class BlockFull(
{
companion object
{
val example = BlockFull(
val example = Block(
BlockId(1),
"板块名称",
"板块描述",
Expand Down
38 changes: 0 additions & 38 deletions src/main/kotlin/subit/dataClasses/Comment.kt

This file was deleted.

7 changes: 3 additions & 4 deletions src/main/kotlin/subit/dataClasses/Notice.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package subit.dataClasses

import kotlinx.serialization.Serializable
import subit.dataClasses.CommentId.Companion.toCommentId
import subit.dataClasses.PostId.Companion.toPostId

/**
Expand Down Expand Up @@ -55,7 +54,7 @@ sealed interface Notice
): ObjectNotice = when (type)
{
Type.POST_COMMENT -> PostCommentNotice(id, user, obj.value.toPostId(), count)
Type.COMMENT_REPLY -> CommentReplyNotice(id, user, obj.value.toCommentId(), count)
Type.COMMENT_REPLY -> CommentReplyNotice(id, user, obj.value.toPostId(), count)
Type.LIKE -> LikeNotice(id, user, obj.value.toPostId(), count)
Type.STAR -> StarNotice(id, user, obj.value.toPostId(), count)
else -> throw IllegalArgumentException("Invalid type: $type")
Expand Down Expand Up @@ -118,15 +117,15 @@ sealed interface Notice
data class CommentReplyNotice(
override val id: NoticeId,
override val user: UserId,
val comment: CommentId,
val comment: PostId,
override val count: Long
): ObjectNotice
{
override val type: Type get() = Type.COMMENT_REPLY
override val obj: Id<*, *> get() = comment
companion object
{
val example = CommentReplyNotice(NoticeId(1), UserId(1), CommentId(1), 1)
val example = CommentReplyNotice(NoticeId(1), UserId(1), PostId(1), 1)
}
}

Expand Down
Loading

0 comments on commit 74ce5e7

Please sign in to comment.