diff --git a/src/main/kotlin/moe/kageru/kagebot/Globals.kt b/src/main/kotlin/moe/kageru/kagebot/Globals.kt index 612a65d..70ff614 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Globals.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Globals.kt @@ -1,19 +1,10 @@ package moe.kageru.kagebot -import moe.kageru.kagebot.command.Command -import moe.kageru.kagebot.config.Localization -import moe.kageru.kagebot.config.SystemConfig -import moe.kageru.kagebot.features.Features import org.javacord.api.DiscordApi -import org.javacord.api.entity.server.Server import java.util.concurrent.atomic.AtomicInteger + object Globals { - lateinit var server: Server lateinit var api: DiscordApi - lateinit var commands: List - lateinit var systemConfig: SystemConfig - lateinit var features: Features - lateinit var localization: Localization val commandCounter: AtomicInteger = AtomicInteger(0) } diff --git a/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt b/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt index 1eed6b1..7b980dc 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Kagebot.kt @@ -2,6 +2,7 @@ package moe.kageru.kagebot import moe.kageru.kagebot.Log.log import moe.kageru.kagebot.Util.checked +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.ConfigParser import moe.kageru.kagebot.config.RawConfig import org.javacord.api.DiscordApiBuilder @@ -22,7 +23,7 @@ object Kagebot { } return } - for (command in Globals.commands) { + for (command in Config.commands) { if (command.matches(event.readableMessageContent)) { command.execute(event) break @@ -31,7 +32,7 @@ object Kagebot { } fun welcomeUser(event: ServerMemberJoinEvent) { - Globals.features.welcome!!.let { welcome -> + Config.features.welcome!!.let { welcome -> val message = event.user.sendMessage(welcome.embed) // If the user disabled direct messages, try the fallback (if defined) if (!Util.wasSuccessful(message) && @@ -64,7 +65,7 @@ object Kagebot { }) log.info("kagebot Mk II running") Globals.api.addMessageCreateListener { checked { processMessage(it) } } - Globals.features.welcome?.let { + Config.features.welcome?.let { Globals.api.addServerMemberJoinListener { checked { welcomeUser(it) } } diff --git a/src/main/kotlin/moe/kageru/kagebot/MessageUtil.kt b/src/main/kotlin/moe/kageru/kagebot/MessageUtil.kt index c1c89f2..d90ba05 100644 --- a/src/main/kotlin/moe/kageru/kagebot/MessageUtil.kt +++ b/src/main/kotlin/moe/kageru/kagebot/MessageUtil.kt @@ -1,5 +1,6 @@ package moe.kageru.kagebot +import moe.kageru.kagebot.config.Config import org.javacord.api.entity.message.MessageAuthor import org.javacord.api.entity.message.embed.EmbedBuilder import org.javacord.api.entity.user.User @@ -15,8 +16,8 @@ object MessageUtil { fun getEmbedBuilder(): EmbedBuilder { val builder = EmbedBuilder() - Globals.server.icon.ifPresent { builder.setThumbnail(it) } - return builder.setColor(Globals.systemConfig.color).setTimestampToNow() + Config.server.icon.ifPresent { builder.setThumbnail(it) } + return builder.setColor(Config.systemConfig.color).setTimestampToNow() } /* diff --git a/src/main/kotlin/moe/kageru/kagebot/Util.kt b/src/main/kotlin/moe/kageru/kagebot/Util.kt index 8098852..ab43d76 100644 --- a/src/main/kotlin/moe/kageru/kagebot/Util.kt +++ b/src/main/kotlin/moe/kageru/kagebot/Util.kt @@ -1,8 +1,8 @@ package moe.kageru.kagebot -import moe.kageru.kagebot.Globals.api -import moe.kageru.kagebot.Globals.server import moe.kageru.kagebot.Log.log +import moe.kageru.kagebot.config.Config +import moe.kageru.kagebot.config.Config.server import org.javacord.api.entity.channel.TextChannel import org.javacord.api.entity.message.MessageAuthor import org.javacord.api.entity.message.embed.EmbedBuilder @@ -10,7 +10,7 @@ import org.javacord.api.entity.permission.Role import org.javacord.api.entity.user.User import org.javacord.api.event.message.MessageCreateEvent import java.awt.Color -import java.util.Optional +import java.util.* import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionException @@ -69,7 +69,7 @@ object Util { idOrName.isEntityId() -> server.getTextChannelById(idOrName).ifNotEmpty { it } ?: throw IllegalArgumentException("Channel ID $idOrName not found.") else -> if (idOrName.startsWith('@')) { - api.getCachedUserByDiscriminatedName(idOrName.removePrefix("@")).ifNotEmpty { user -> + Globals.api.getCachedUserByDiscriminatedName(idOrName.removePrefix("@")).ifNotEmpty { user -> val channelFuture = user.openPrivateChannel() val channel = channelFuture.join() if (channelFuture.isCompletedExceptionally) { @@ -111,7 +111,7 @@ object Util { fun userFromMessage(message: MessageCreateEvent): User? { return message.messageAuthor.id.let { id -> - Globals.server.getMemberById(id).orElse(null) + Config.server.getMemberById(id).orElse(null) } } } diff --git a/src/main/kotlin/moe/kageru/kagebot/command/Command.kt b/src/main/kotlin/moe/kageru/kagebot/command/Command.kt index d14dc0e..ec0aaa7 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/Command.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/Command.kt @@ -4,6 +4,7 @@ import moe.kageru.kagebot.Globals import moe.kageru.kagebot.Log.log import moe.kageru.kagebot.MessageUtil import moe.kageru.kagebot.Util.doIf +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.RawCommand import moe.kageru.kagebot.features.MessageFeature import org.javacord.api.entity.message.MessageAuthor @@ -33,15 +34,15 @@ class Command(cmd: RawCommand) { actions = cmd.actions?.let { MessageActions(it) } regex = if (matchType == MatchType.REGEX) Regex(trigger) else null embed = cmd.embed?.let(MessageUtil::listToEmbed) - feature = cmd.feature?.let { Globals.features.findByString(it) } + feature = cmd.feature?.let { Config.features.findByString(it) } } fun isAllowed(message: MessageCreateEvent) = permissions?.isAllowed(message) ?: true fun execute(message: MessageCreateEvent) { if (permissions?.isAllowed(message) == false) { - if (Globals.localization.permissionDenied.isNotBlank()) { - message.channel.sendMessage(Globals.localization.permissionDenied) + if (Config.localization.permissionDenied.isNotBlank()) { + message.channel.sendMessage(Config.localization.permissionDenied) } log.info("Denying command ${this.trigger} to user ${message.messageAuthor.discriminatedName} (ID: ${message.messageAuthor.id})") return diff --git a/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt b/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt index 7f058a0..7db0a22 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/MessageActions.kt @@ -1,6 +1,6 @@ package moe.kageru.kagebot.command -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.Log.log import moe.kageru.kagebot.MessageUtil import moe.kageru.kagebot.config.RawMessageActions @@ -25,7 +25,7 @@ class MessageActions(rawActions: RawMessageActions) { message.messageAuthor.asUser().ifPresent { user -> user.sendMessage( MessageUtil.getEmbedBuilder() - .addField("Blacklisted", Globals.localization.messageDeleted) + .addField("Blacklisted", Config.localization.messageDeleted) .addField("Original:", "“${message.readableMessageContent}”") ) } diff --git a/src/main/kotlin/moe/kageru/kagebot/command/MessageRedirect.kt b/src/main/kotlin/moe/kageru/kagebot/command/MessageRedirect.kt index e0d59a9..681a2b3 100644 --- a/src/main/kotlin/moe/kageru/kagebot/command/MessageRedirect.kt +++ b/src/main/kotlin/moe/kageru/kagebot/command/MessageRedirect.kt @@ -1,6 +1,6 @@ package moe.kageru.kagebot.command -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.Log.log import moe.kageru.kagebot.MessageUtil import moe.kageru.kagebot.Util @@ -16,7 +16,7 @@ internal class MessageRedirect(rawRedirect: RawRedirect) { fun execute(message: MessageCreateEvent, command: Command) { val embed = MessageUtil.getEmbedBuilder() .addField( - Globals.localization.redirectedMessage, + Config.localization.redirectedMessage, message.readableMessageContent.let { content -> when (command.matchType) { MatchType.PREFIX -> content.removePrefix(command.trigger).trim() diff --git a/src/main/kotlin/moe/kageru/kagebot/config/Config.kt b/src/main/kotlin/moe/kageru/kagebot/config/Config.kt index 55c0fff..c624a9b 100644 --- a/src/main/kotlin/moe/kageru/kagebot/config/Config.kt +++ b/src/main/kotlin/moe/kageru/kagebot/config/Config.kt @@ -1,52 +1,13 @@ package moe.kageru.kagebot.config -import moe.kageru.kagebot.Globals -import moe.kageru.kagebot.Globals.api import moe.kageru.kagebot.command.Command import moe.kageru.kagebot.features.Features -import java.awt.Color +import org.javacord.api.entity.server.Server -object ConfigParser { - fun initialLoad(rawConfig: RawConfig) { - val systemConfig = rawConfig.system?.let(::SystemConfig) - ?: throw IllegalArgumentException("No [system] block in config.") - Globals.server = api.getServerById(systemConfig.serverId).orElseThrow { IllegalArgumentException("Invalid server configured.") } - Globals.systemConfig = systemConfig - reloadLocalization(rawConfig) - reloadFeatures(rawConfig) - reloadCommands(rawConfig) - } - - fun reloadLocalization(rawConfig: RawConfig) { - Globals.localization = rawConfig.localization?.let(::Localization) - ?: throw IllegalArgumentException("No [localization] block in config.") - } - - fun reloadCommands(rawConfig: RawConfig) { - Globals.commands = rawConfig.commands?.map(::Command)?.toMutableList() - ?: throw IllegalArgumentException("No commands found in config.") - } - - fun reloadFeatures(rawConfig: RawConfig) { - Globals.features = rawConfig.features?.let(::Features) - ?: Features(RawFeatures(null)) - } -} - -class SystemConfig(val serverId: String, val color: Color) { - constructor(rawSystemConfig: RawSystemConfig) : this( - rawSystemConfig.serverId ?: throw IllegalArgumentException("No [system.server] defined."), - Color.decode(rawSystemConfig.color ?: "#1793d0") - ) -} - -class Localization(val permissionDenied: String, val redirectedMessage: String, val messageDeleted: 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") - ) +object Config { + lateinit var server: Server + lateinit var commands: List + lateinit var systemConfig: SystemConfig + lateinit var features: Features + lateinit var localization: Localization } diff --git a/src/main/kotlin/moe/kageru/kagebot/config/ConfigParser.kt b/src/main/kotlin/moe/kageru/kagebot/config/ConfigParser.kt new file mode 100644 index 0000000..85383de --- /dev/null +++ b/src/main/kotlin/moe/kageru/kagebot/config/ConfigParser.kt @@ -0,0 +1,51 @@ +package moe.kageru.kagebot.config + +import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.command.Command +import moe.kageru.kagebot.features.Features +import java.awt.Color + +object ConfigParser { + fun initialLoad(rawConfig: RawConfig) { + val systemConfig = rawConfig.system?.let(::SystemConfig) + ?: throw IllegalArgumentException("No [system] block in config.") + Config.server = Globals.api.getServerById(systemConfig.serverId).orElseThrow { IllegalArgumentException("Invalid server configured.") } + Config.systemConfig = systemConfig + reloadLocalization(rawConfig) + reloadFeatures(rawConfig) + reloadCommands(rawConfig) + } + + fun reloadLocalization(rawConfig: RawConfig) { + Config.localization = rawConfig.localization?.let(::Localization) + ?: throw IllegalArgumentException("No [localization] block in config.") + } + + fun reloadCommands(rawConfig: RawConfig) { + Config.commands = rawConfig.commands?.map(::Command)?.toMutableList() + ?: throw IllegalArgumentException("No commands found in config.") + } + + fun reloadFeatures(rawConfig: RawConfig) { + Config.features = rawConfig.features?.let(::Features) + ?: Features(RawFeatures(null)) + } +} + +class SystemConfig(val serverId: String, val color: Color) { + constructor(rawSystemConfig: RawSystemConfig) : this( + rawSystemConfig.serverId ?: throw IllegalArgumentException("No [system.server] defined."), + Color.decode(rawSystemConfig.color ?: "#1793d0") + ) +} + +class Localization(val permissionDenied: String, val redirectedMessage: String, val messageDeleted: 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") + ) +} diff --git a/src/main/kotlin/moe/kageru/kagebot/features/HelpFeature.kt b/src/main/kotlin/moe/kageru/kagebot/features/HelpFeature.kt index a2d9e38..b428df0 100644 --- a/src/main/kotlin/moe/kageru/kagebot/features/HelpFeature.kt +++ b/src/main/kotlin/moe/kageru/kagebot/features/HelpFeature.kt @@ -1,6 +1,6 @@ package moe.kageru.kagebot.features -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.MessageUtil import moe.kageru.kagebot.command.MatchType import org.javacord.api.event.message.MessageCreateEvent @@ -14,7 +14,7 @@ class HelpFeature : MessageFeature() { } } -private fun listCommands(message: MessageCreateEvent) = Globals.commands +private fun listCommands(message: MessageCreateEvent) = Config.commands .filter { it.matchType == MatchType.PREFIX && it.isAllowed(message) } .map { it.trigger } .joinToString("\n") diff --git a/src/test/kotlin/moe/kageru/kagebot/ConfigTest.kt b/src/test/kotlin/moe/kageru/kagebot/ConfigTest.kt index 890fca4..b56417c 100644 --- a/src/test/kotlin/moe/kageru/kagebot/ConfigTest.kt +++ b/src/test/kotlin/moe/kageru/kagebot/ConfigTest.kt @@ -3,13 +3,14 @@ package moe.kageru.kagebot import io.kotlintest.shouldBe import io.kotlintest.shouldNotBe import io.kotlintest.specs.ShouldSpec +import moe.kageru.kagebot.config.Config class ConfigTest : ShouldSpec({ TestUtil.prepareTestEnvironment() "should properly parse test config" { - Globals.systemConfig shouldNotBe null - Globals.localization shouldNotBe null - Globals.features shouldNotBe null - Globals.commands.size shouldBe 2 + Config.systemConfig shouldNotBe null + Config.localization shouldNotBe null + Config.features shouldNotBe null + Config.commands.size shouldBe 2 } }) diff --git a/src/test/kotlin/moe/kageru/kagebot/TestUtil.kt b/src/test/kotlin/moe/kageru/kagebot/TestUtil.kt index 31d3298..d1d9ab8 100644 --- a/src/test/kotlin/moe/kageru/kagebot/TestUtil.kt +++ b/src/test/kotlin/moe/kageru/kagebot/TestUtil.kt @@ -7,6 +7,7 @@ import io.mockk.Runs import io.mockk.every import io.mockk.just import io.mockk.mockk +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.config.ConfigParser import moe.kageru.kagebot.config.RawConfig import org.javacord.api.DiscordApi @@ -88,19 +89,19 @@ object TestUtil { } fun withCommands(config: String, test: (() -> R)) { - val oldCmds = Globals.commands + val oldCmds = Config.commands val rawConfig = RawConfig.readFromString(config) ConfigParser.reloadCommands(rawConfig) test() - Globals.commands = oldCmds + Config.commands = oldCmds } fun withLocalization(config: String, test: (() -> R)) { - val oldLoc = Globals.localization + val oldLoc = Config.localization val rawConfig = RawConfig.readFromString(config) ConfigParser.reloadLocalization(rawConfig) test() - Globals.localization = oldLoc + Config.localization = oldLoc } fun withReplyContents( diff --git a/src/test/kotlin/moe/kageru/kagebot/command/CommandTest.kt b/src/test/kotlin/moe/kageru/kagebot/command/CommandTest.kt index be6902e..c5ad97c 100644 --- a/src/test/kotlin/moe/kageru/kagebot/command/CommandTest.kt +++ b/src/test/kotlin/moe/kageru/kagebot/command/CommandTest.kt @@ -5,7 +5,7 @@ import io.kotlintest.shouldBe import io.kotlintest.specs.StringSpec import io.mockk.every import io.mockk.mockk -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.Kagebot import moe.kageru.kagebot.TestUtil import moe.kageru.kagebot.TestUtil.embedToString @@ -132,7 +132,7 @@ class CommandTest : StringSpec({ val replies = mutableListOf() val mockMessage = mockMessage("!restricted", replies = replies) Kagebot.processMessage(mockMessage) - replies shouldBe mutableListOf(Globals.localization.permissionDenied) + replies shouldBe mutableListOf(Config.localization.permissionDenied) withLocalization( """ [localization] @@ -182,7 +182,7 @@ class CommandTest : StringSpec({ val mockMessage = mockMessage("!restricted", replies = calls) every { mockMessage.messageAuthor.asUser() } returns Optional.of(mockk { every { getRoles(any()) } returns listOf( - Globals.server.getRolesByNameIgnoreCase("testrole")[0] + Config.server.getRolesByNameIgnoreCase("testrole")[0] ) }) Kagebot.processMessage(mockMessage) @@ -205,7 +205,7 @@ class CommandTest : StringSpec({ every { mockMessage.messageAuthor.asUser() } returns mockk { every { isPresent } returns true every { get().getRoles(any()) } returns listOf( - Globals.server.getRolesByNameIgnoreCase("testrole")[0] + Config.server.getRolesByNameIgnoreCase("testrole")[0] ) } Kagebot.processMessage(mockMessage) @@ -216,7 +216,7 @@ class CommandTest : StringSpec({ every { get().getRoles(any()) } returns emptyList() } Kagebot.processMessage(mockMessage) - calls shouldBe mutableListOf(Globals.localization.permissionDenied, "access granted") + calls shouldBe mutableListOf(Config.localization.permissionDenied, "access granted") } } "should refuse DM only message in server channel" { @@ -231,7 +231,7 @@ class CommandTest : StringSpec({ ) { val calls = mutableListOf() Kagebot.processMessage(mockMessage("!dm", replies = calls)) - calls shouldBe listOf(Globals.localization.permissionDenied) + calls shouldBe listOf(Config.localization.permissionDenied) } } /* @@ -270,7 +270,7 @@ class CommandTest : StringSpec({ val user = mockk { every { addRole(capture(roles), "Requested via command.") } returns mockk() } - every { Globals.server.getMemberById(1) } returns Optional.of(user) + every { Config.server.getMemberById(1) } returns Optional.of(user) Kagebot.processMessage(mockMessage("!assign")) roles shouldBe mutableListOf(Util.findRole("testrole")) } diff --git a/src/test/kotlin/moe/kageru/kagebot/features/HelpFeatureTest.kt b/src/test/kotlin/moe/kageru/kagebot/features/HelpFeatureTest.kt index 5a641aa..45b620f 100644 --- a/src/test/kotlin/moe/kageru/kagebot/features/HelpFeatureTest.kt +++ b/src/test/kotlin/moe/kageru/kagebot/features/HelpFeatureTest.kt @@ -3,7 +3,7 @@ package moe.kageru.kagebot.features import io.kotlintest.specs.StringSpec import io.mockk.every import io.mockk.mockk -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.Kagebot import moe.kageru.kagebot.TestUtil import moe.kageru.kagebot.TestUtil.mockMessage @@ -48,7 +48,7 @@ class HelpFeatureTest : StringSpec({ val message = mockMessage("!help", replyEmbeds = replies) every { message.messageAuthor.asUser() } returns Optional.of(mockk { every { getRoles(any()) } returns listOf( - Globals.server.getRolesByNameIgnoreCase("testrole")[0] + Config.server.getRolesByNameIgnoreCase("testrole")[0] ) }) Kagebot.processMessage(message) diff --git a/src/test/kotlin/moe/kageru/kagebot/features/WelcomeFeatureTest.kt b/src/test/kotlin/moe/kageru/kagebot/features/WelcomeFeatureTest.kt index d09d18b..07f19e9 100644 --- a/src/test/kotlin/moe/kageru/kagebot/features/WelcomeFeatureTest.kt +++ b/src/test/kotlin/moe/kageru/kagebot/features/WelcomeFeatureTest.kt @@ -4,7 +4,7 @@ import io.kotlintest.shouldBe import io.kotlintest.specs.StringSpec import io.mockk.every import io.mockk.mockk -import moe.kageru.kagebot.Globals +import moe.kageru.kagebot.config.Config import moe.kageru.kagebot.Kagebot import moe.kageru.kagebot.TestUtil import org.javacord.api.entity.message.embed.EmbedBuilder @@ -23,7 +23,7 @@ class WelcomeFeatureTest : StringSpec({ } } ) - sentMessages shouldBe mutableListOf(Globals.features.welcome!!.embed) + sentMessages shouldBe mutableListOf(Config.features.welcome!!.embed) } "should send welcome fallback if DMs are disabled" { val message = mutableListOf()