Rewrite config to use Konf (2): Localization

This commit is contained in:
kageru 2019-10-18 19:34:41 +02:00
parent e31d46ceb5
commit 17c7120796
Signed by: kageru
GPG Key ID: 8282A2BEA4ADA3D2
12 changed files with 47 additions and 61 deletions

View File

@ -5,6 +5,7 @@ import moe.kageru.kagebot.Log
import moe.kageru.kagebot.MessageUtil import moe.kageru.kagebot.MessageUtil
import moe.kageru.kagebot.Util.applyIf import moe.kageru.kagebot.Util.applyIf
import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.config.RawCommand import moe.kageru.kagebot.config.RawCommand
import moe.kageru.kagebot.features.MessageFeature import moe.kageru.kagebot.features.MessageFeature
import org.javacord.api.entity.message.MessageAuthor import org.javacord.api.entity.message.MessageAuthor
@ -41,8 +42,8 @@ class Command(cmd: RawCommand) {
fun execute(message: MessageCreateEvent): Boolean { fun execute(message: MessageCreateEvent): Boolean {
if (permissions?.isAllowed(message) == false) { if (permissions?.isAllowed(message) == false) {
if (Config.localization.permissionDenied.isNotBlank()) { if (Config.localization[LocalizationSpec.permissionDenied].isNotBlank()) {
message.channel.sendMessage(Config.localization.permissionDenied) message.channel.sendMessage(Config.localization[LocalizationSpec.permissionDenied])
} }
Log.info("Denying command ${this.trigger} to user ${message.messageAuthor.discriminatedName} (ID: ${message.messageAuthor.id})") Log.info("Denying command ${this.trigger} to user ${message.messageAuthor.discriminatedName} (ID: ${message.messageAuthor.id})")
return false return false
@ -62,9 +63,10 @@ class Command(cmd: RawCommand) {
fun matches(msg: String) = this.matchType.matches(msg, this) fun matches(msg: String) = this.matchType.matches(msg, this)
private fun respond(author: MessageAuthor, response: String) = response.applyIf(response.contains(AUTHOR_PLACEHOLDER)) { private fun respond(author: MessageAuthor, response: String) =
it.replace(AUTHOR_PLACEHOLDER, MessageUtil.mention(author)) response.applyIf(response.contains(AUTHOR_PLACEHOLDER)) {
} it.replace(AUTHOR_PLACEHOLDER, MessageUtil.mention(author))
}
} }
enum class MatchType { enum class MatchType {

View File

@ -3,6 +3,7 @@ package moe.kageru.kagebot.command
import moe.kageru.kagebot.Log import moe.kageru.kagebot.Log
import moe.kageru.kagebot.MessageUtil.sendEmbed import moe.kageru.kagebot.MessageUtil.sendEmbed
import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.config.RawMessageActions import moe.kageru.kagebot.config.RawMessageActions
import org.javacord.api.event.message.MessageCreateEvent import org.javacord.api.event.message.MessageCreateEvent
@ -24,7 +25,7 @@ class MessageActions(rawActions: RawMessageActions) {
message.deleteMessage() message.deleteMessage()
message.messageAuthor.asUser().ifPresent { user -> message.messageAuthor.asUser().ifPresent { user ->
user.sendEmbed { user.sendEmbed {
addField("__Blacklisted__", Config.localization.messageDeleted) addField("__Blacklisted__", Config.localization[LocalizationSpec.messageDeleted])
addField("Original:", "${message.readableMessageContent}") addField("Original:", "${message.readableMessageContent}")
} }
} }

View File

@ -6,6 +6,7 @@ import moe.kageru.kagebot.Util
import moe.kageru.kagebot.Util.applyIf import moe.kageru.kagebot.Util.applyIf
import moe.kageru.kagebot.Util.failed import moe.kageru.kagebot.Util.failed
import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.config.RawRedirect import moe.kageru.kagebot.config.RawRedirect
import org.javacord.api.entity.channel.TextChannel import org.javacord.api.entity.channel.TextChannel
import org.javacord.api.event.message.MessageCreateEvent import org.javacord.api.event.message.MessageCreateEvent
@ -21,7 +22,7 @@ internal class MessageRedirect(rawRedirect: RawRedirect) {
.applyIf(command.matchType == MatchType.PREFIX) { content -> .applyIf(command.matchType == MatchType.PREFIX) { content ->
content.removePrefix(command.trigger).trim() content.removePrefix(command.trigger).trim()
} }
addField(Config.localization.redirectedMessage, redirectedText) addField(Config.localization[LocalizationSpec.redirectedMessage], redirectedText)
Log.info("Redirected message: $redirectedText") Log.info("Redirected message: $redirectedText")
} }
// No inlined if/else because the types are different. // No inlined if/else because the types are different.

View File

@ -7,10 +7,11 @@ import moe.kageru.kagebot.features.Features
import org.javacord.api.entity.server.Server import org.javacord.api.entity.server.Server
object Config { object Config {
val specs = Config { addSpec(SystemSpec) }.from.toml val systemSpec = Config { addSpec(SystemSpec) }.from.toml
lateinit var config: Config val localeSpec = Config { addSpec(LocalizationSpec) }.from.toml
lateinit var system: Config
lateinit var localization: Config
lateinit var server: Server lateinit var server: Server
lateinit var commands: List<Command> lateinit var commands: List<Command>
lateinit var features: Features lateinit var features: Features
lateinit var localization: Localization
} }

View File

@ -11,21 +11,16 @@ object ConfigParser {
fun initialLoad(file: String) { fun initialLoad(file: String) {
val rawConfig = RawConfig.read(file) val rawConfig = RawConfig.read(file)
val config = Config.specs.file(RawConfig.getFile(file)) val configFile = RawConfig.getFile(file)
Config.config = config val config = Config.systemSpec.file(configFile)
Config.system = config
Config.server = Globals.api.getServerById(config[serverId]) Config.server = Globals.api.getServerById(config[serverId])
.orElseThrow { IllegalArgumentException("Invalid server configured.") } .orElseThrow { IllegalArgumentException("Invalid server configured.") }
reloadLocalization(rawConfig) Config.localization = Config.localeSpec.file(configFile)
reloadFeatures(rawConfig) reloadFeatures(rawConfig)
reloadCommands(rawConfig) reloadCommands(rawConfig)
} }
fun reloadLocalization(rawConfig: RawConfig) {
Config.localization = rawConfig.localization?.let(::Localization)
?: throw IllegalArgumentException("No [localization] block in config.")
}
fun reloadCommands(rawConfig: RawConfig) { fun reloadCommands(rawConfig: RawConfig) {
Config.commands = rawConfig.commands?.map(::Command)?.toMutableList() Config.commands = rawConfig.commands?.map(::Command)?.toMutableList()
?: throw IllegalArgumentException("No commands found in config.") ?: throw IllegalArgumentException("No commands found in config.")
@ -36,22 +31,3 @@ object ConfigParser {
?: Features(RawFeatures(null, null)) ?: Features(RawFeatures(null, null))
} }
} }
class Localization(
val permissionDenied: String,
val redirectedMessage: String,
val messageDeleted: String,
val timeout: String
) {
constructor(rawLocalization: RawLocalization) : this(
permissionDenied = rawLocalization.permissionDenied
?: throw IllegalArgumentException("No [localization.permissionDenied] defined"),
redirectedMessage = rawLocalization.redirectedMessage
?: throw IllegalArgumentException("No [localization.redirectMessage] defined"),
messageDeleted = rawLocalization.messageDeleted
?: throw IllegalArgumentException("No [localization.messageDeleted] defined"),
timeout = rawLocalization.timeout
?: throw IllegalArgumentException("No [localization.timeout] defined")
)
}

View File

@ -3,12 +3,11 @@ package moe.kageru.kagebot.config
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import com.moandjiezana.toml.Toml import com.moandjiezana.toml.Toml
import com.uchuhimo.konf.ConfigSpec import com.uchuhimo.konf.ConfigSpec
import moe.kageru.kagebot.config.Config.config import moe.kageru.kagebot.config.Config.system
import java.awt.Color import java.awt.Color
import java.io.File import java.io.File
class RawConfig( class RawConfig(
val localization: RawLocalization?,
@SerializedName("command") @SerializedName("command")
val commands: List<RawCommand>?, val commands: List<RawCommand>?,
@SerializedName("feature") @SerializedName("feature")
@ -38,12 +37,12 @@ class RawConfig(
object SystemSpec : ConfigSpec() { object SystemSpec : ConfigSpec() {
private val rawColor by optional("#1793d0", name = "color") private val rawColor by optional("#1793d0", name = "color")
val serverId by required<String>() val serverId by required<String>()
val color by kotlin.lazy { Color.decode(config[rawColor])!! } val color by kotlin.lazy { Color.decode(system[rawColor])!! }
} }
class RawLocalization( object LocalizationSpec : ConfigSpec() {
val permissionDenied: String?, val permissionDenied by optional("You do not have the permission to use this command.")
val redirectedMessage: String?, val redirectedMessage by optional("says")
val messageDeleted: String?, val messageDeleted by optional("Your message was deleted.")
val timeout: String? val timeout by optional("You have been timed out for @@ minutes.")
) }

View File

@ -2,6 +2,7 @@ package moe.kageru.kagebot.features
import moe.kageru.kagebot.Log import moe.kageru.kagebot.Log
import moe.kageru.kagebot.MessageUtil.sendEmbed import moe.kageru.kagebot.MessageUtil.sendEmbed
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.ConfigParser import moe.kageru.kagebot.config.ConfigParser
import moe.kageru.kagebot.config.RawConfig import moe.kageru.kagebot.config.RawConfig
import org.javacord.api.entity.channel.TextChannel import org.javacord.api.entity.channel.TextChannel
@ -22,7 +23,7 @@ class SetConfigFeature : MessageFeature {
return return
} }
try { try {
ConfigParser.reloadLocalization(rawConfig) Config.localization = Config.localeSpec.string(newConfig)
ConfigParser.reloadFeatures(rawConfig) ConfigParser.reloadFeatures(rawConfig)
ConfigParser.reloadCommands(rawConfig) ConfigParser.reloadCommands(rawConfig)
ConfigParser.configFile.writeText(newConfig) ConfigParser.configFile.writeText(newConfig)

View File

@ -6,6 +6,7 @@ import moe.kageru.kagebot.Util.findRole
import moe.kageru.kagebot.Util.findUser import moe.kageru.kagebot.Util.findUser
import moe.kageru.kagebot.Util.ifNotEmpty import moe.kageru.kagebot.Util.ifNotEmpty
import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.config.RawTimeoutFeature import moe.kageru.kagebot.config.RawTimeoutFeature
import moe.kageru.kagebot.persistence.Dao import moe.kageru.kagebot.persistence.Dao
import org.javacord.api.entity.permission.Role import org.javacord.api.entity.permission.Role
@ -41,7 +42,10 @@ class TimeoutFeature(raw: RawTimeoutFeature) : MessageFeature {
val releaseTime = Instant.now().plus(Duration.ofMinutes(timeout.duration)).epochSecond val releaseTime = Instant.now().plus(Duration.ofMinutes(timeout.duration)).epochSecond
Dao.saveTimeout(releaseTime, listOf(user.id) + oldRoles) Dao.saveTimeout(releaseTime, listOf(user.id) + oldRoles)
user.sendEmbed { user.sendEmbed {
addField("Timeout", Config.localization.timeout.replace("@@", timeout.duration.toString())) addField(
"Timeout",
Config.localization[LocalizationSpec.timeout].replace("@@", timeout.duration.toString())
)
timeout.reason?.let { timeout.reason?.let {
addField("Reason", it) addField("Reason", it)
} }

View File

@ -6,6 +6,7 @@ import io.kotlintest.specs.ShouldSpec
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.LocalizationSpec
import moe.kageru.kagebot.config.SystemSpec import moe.kageru.kagebot.config.SystemSpec
import moe.kageru.kagebot.features.SetConfigFeature import moe.kageru.kagebot.features.SetConfigFeature
import java.awt.Color import java.awt.Color
@ -14,9 +15,8 @@ import java.awt.Color
class ConfigTest : ShouldSpec({ class ConfigTest : ShouldSpec({
TestUtil.prepareTestEnvironment() TestUtil.prepareTestEnvironment()
"should properly parse test config" { "should properly parse test config" {
Config.config[SystemSpec.serverId] shouldNotBe null Config.system[SystemSpec.serverId] shouldNotBe null
SystemSpec.color shouldBe Color.decode("#1793d0") SystemSpec.color shouldBe Color.decode("#1793d0")
Config.localization shouldNotBe null
Config.features shouldNotBe null Config.features shouldNotBe null
Config.commands.size shouldBe 3 Config.commands.size shouldBe 3
} }
@ -38,6 +38,6 @@ class ConfigTest : ShouldSpec({
every { url.openStream().readAllBytes() } returns testConfig.toByteArray() every { url.openStream().readAllBytes() } returns testConfig.toByteArray()
}) })
SetConfigFeature().handle(message) SetConfigFeature().handle(message)
Config.localization.permissionDenied shouldBe denied Config.localization[LocalizationSpec.permissionDenied] shouldBe denied
} }
}) })

View File

@ -116,7 +116,7 @@ object TestUtil {
return (embed.delegate as EmbedBuilderDelegateImpl).toJsonNode().toString() return (embed.delegate as EmbedBuilderDelegateImpl).toJsonNode().toString()
} }
fun <R> withCommands(config: String, test: (() -> R)) { fun withCommands(config: String, test: (() -> Unit)) {
val oldCmds = Config.commands val oldCmds = Config.commands
val rawConfig = RawConfig.readFromString(config) val rawConfig = RawConfig.readFromString(config)
ConfigParser.reloadCommands(rawConfig) ConfigParser.reloadCommands(rawConfig)
@ -124,10 +124,9 @@ object TestUtil {
Config.commands = oldCmds Config.commands = oldCmds
} }
fun <R> withLocalization(config: String, test: (() -> R)) { fun withLocalization(config: String, test: (() -> Unit)) {
val oldLoc = Config.localization val oldLoc = Config.localization
val rawConfig = RawConfig.readFromString(config) Config.localization = Config.localeSpec.string(config)
ConfigParser.reloadLocalization(rawConfig)
test() test()
Config.localization = oldLoc Config.localization = oldLoc
} }

View File

@ -5,7 +5,6 @@ import io.kotlintest.shouldBe
import io.kotlintest.specs.StringSpec import io.kotlintest.specs.StringSpec
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.Globals import moe.kageru.kagebot.Globals
import moe.kageru.kagebot.Kagebot.process import moe.kageru.kagebot.Kagebot.process
import moe.kageru.kagebot.TestUtil import moe.kageru.kagebot.TestUtil
@ -17,6 +16,9 @@ import moe.kageru.kagebot.TestUtil.testMessageSuccess
import moe.kageru.kagebot.TestUtil.withCommands import moe.kageru.kagebot.TestUtil.withCommands
import moe.kageru.kagebot.TestUtil.withLocalization import moe.kageru.kagebot.TestUtil.withLocalization
import moe.kageru.kagebot.Util import moe.kageru.kagebot.Util
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.config.Config.localization
import moe.kageru.kagebot.config.LocalizationSpec
import org.javacord.api.entity.message.embed.EmbedBuilder import org.javacord.api.entity.message.embed.EmbedBuilder
import org.javacord.api.entity.permission.Role import org.javacord.api.entity.permission.Role
import org.javacord.api.entity.user.User import org.javacord.api.entity.user.User
@ -146,7 +148,7 @@ class CommandTest : StringSpec({
val replies = mutableListOf<String>() val replies = mutableListOf<String>()
val mockMessage = mockMessage("!restricted", replies = replies) val mockMessage = mockMessage("!restricted", replies = replies)
mockMessage.process() mockMessage.process()
replies shouldBe mutableListOf(Config.localization.permissionDenied) replies shouldBe mutableListOf(localization[LocalizationSpec.permissionDenied])
withLocalization( withLocalization(
""" """
[localization] [localization]
@ -231,7 +233,7 @@ class CommandTest : StringSpec({
every { get().getRoles(any()) } returns emptyList() every { get().getRoles(any()) } returns emptyList()
} }
mockMessage.process() mockMessage.process()
calls shouldBe mutableListOf(Config.localization.permissionDenied, "access granted") calls shouldBe mutableListOf(localization[LocalizationSpec.permissionDenied], "access granted")
} }
} }
"should refuse DM only message in server channel" { "should refuse DM only message in server channel" {
@ -246,7 +248,7 @@ class CommandTest : StringSpec({
) { ) {
val calls = mutableListOf<String>() val calls = mutableListOf<String>()
mockMessage("!dm", replies = calls).process() mockMessage("!dm", replies = calls).process()
calls shouldBe listOf(Config.localization.permissionDenied) calls shouldBe listOf(localization[LocalizationSpec.permissionDenied])
} }
} }
/* /*

View File

@ -3,12 +3,12 @@ package moe.kageru.kagebot.features
import io.kotlintest.specs.StringSpec import io.kotlintest.specs.StringSpec
import io.mockk.every import io.mockk.every
import io.mockk.mockk import io.mockk.mockk
import moe.kageru.kagebot.config.Config
import moe.kageru.kagebot.Kagebot.process import moe.kageru.kagebot.Kagebot.process
import moe.kageru.kagebot.TestUtil import moe.kageru.kagebot.TestUtil
import moe.kageru.kagebot.TestUtil.mockMessage import moe.kageru.kagebot.TestUtil.mockMessage
import moe.kageru.kagebot.TestUtil.withCommands import moe.kageru.kagebot.TestUtil.withCommands
import moe.kageru.kagebot.TestUtil.withReplyContents import moe.kageru.kagebot.TestUtil.withReplyContents
import moe.kageru.kagebot.config.Config
import org.javacord.api.entity.message.embed.EmbedBuilder import org.javacord.api.entity.message.embed.EmbedBuilder
import java.util.* import java.util.*