Browse Source

feat: config files, better docs, move towards DB

master
Brett Bender 3 years ago
parent
commit
7c0ef9a6e9
14 changed files with 161 additions and 59 deletions
  1. +2
    -2
      build.gradle.kts
  2. +1
    -1
      gradle.properties
  3. +1
    -1
      src/main/kotlin/xyz/brettb/discord/ieeevents/Constants.kt
  4. +19
    -44
      src/main/kotlin/xyz/brettb/discord/ieeevents/IEEEvents.kt
  5. +3
    -2
      src/main/kotlin/xyz/brettb/discord/ieeevents/Utils.kt
  6. +7
    -0
      src/main/kotlin/xyz/brettb/discord/ieeevents/commands/CommandCategories.kt
  7. +4
    -1
      src/main/kotlin/xyz/brettb/discord/ieeevents/commands/info/HelpCommand.kt
  8. +4
    -0
      src/main/kotlin/xyz/brettb/discord/ieeevents/commands/info/UpcomingEventsCommand.kt
  9. +4
    -0
      src/main/kotlin/xyz/brettb/discord/ieeevents/commands/settings/ChangePrefixCommand.kt
  10. +58
    -0
      src/main/kotlin/xyz/brettb/discord/ieeevents/data/settings/BotConfig.kt
  11. +27
    -3
      src/main/kotlin/xyz/brettb/discord/ieeevents/data/settings/IEEEventsGuildSettings.kt
  12. +7
    -2
      src/main/kotlin/xyz/brettb/discord/ieeevents/services/EventsService.kt
  13. +5
    -2
      src/main/kotlin/xyz/brettb/discord/ieeevents/services/StatusService.kt
  14. +19
    -1
      src/main/kotlin/xyz/brettb/discord/ieeevents/services/ToggleableService.kt

+ 2
- 2
build.gradle.kts View File

@ -59,8 +59,8 @@ dependencies {
// Data
implementation("org.yaml:snakeyaml:1.31")
implementation("org.litote.kmongo:kmongo:4.7.2")
implementation("com.sksamuel.hoplite:hoplite-core:2.6.5")
implementation("com.sksamuel.hoplite:hoplite-yaml:2.6.5")
implementation("com.sksamuel.hoplite:hoplite-core:1.4.16")
implementation("com.sksamuel.hoplite:hoplite-yaml:1.4.16")
implementation(kotlin("stdlib-jdk8"))


+ 1
- 1
gradle.properties View File

@ -1,5 +1,5 @@
major=0
minor=2
minor=3
patch=0
kotlin.code.style=official

+ 1
- 1
src/main/kotlin/xyz/brettb/discord/ieeevents/Constants.kt View File

@ -3,7 +3,7 @@ package xyz.brettb.discord.ieeevents
object Constants {
object Colors {
val BLUE = 0x0066A1
const val BLUE = 0x0066A1
}
}

+ 19
- 44
src/main/kotlin/xyz/brettb/discord/ieeevents/IEEEvents.kt View File

@ -2,6 +2,7 @@ package xyz.brettb.discord.ieeevents
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import com.sksamuel.hoplite.ConfigLoader
import net.dv8tion.jda.api.JDA
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.Permission
@ -20,25 +21,20 @@ import net.fortuna.ical4j.model.Period
import net.fortuna.ical4j.model.component.VEvent
import org.reflections.Reflections
import org.slf4j.LoggerFactory
import org.yaml.snakeyaml.Yaml
import tech.junodevs.discord.kriess.impl.managers.CommandManager
import tech.junodevs.discord.kriess.menus.MenuListener
import tech.junodevs.discord.kriess.services.Service
import xyz.brettb.discord.ieeevents.commands.CommandBase
import xyz.brettb.discord.ieeevents.commands.info.HelpCommand
import xyz.brettb.discord.ieeevents.commands.info.UpcomingEventsCommand
import xyz.brettb.discord.ieeevents.commands.settings.ChangePrefixCommand
import xyz.brettb.discord.ieeevents.data.settings.BotConfig
import xyz.brettb.discord.ieeevents.data.settings.IEEEventsGuildSettings
import xyz.brettb.discord.ieeevents.data.settings.IEEEventsGuildSettingsManager
import xyz.brettb.discord.ieeevents.services.StatusService
import xyz.brettb.discord.ieeevents.services.ToggleableService
import java.io.File
import java.io.FileInputStream
import java.nio.file.Files
import java.time.Duration
import java.time.temporal.ChronoUnit
import kotlin.system.exitProcess
@Suppress("HasPlatformType")
val logger = LoggerFactory.getLogger(IEEEventsBot.javaClass)
fun main() {
@ -47,7 +43,7 @@ fun main() {
IEEEventsBot.load()
IEEEventsBot.JDA = JDABuilder
.createDefault(IEEEventsBot.token)
.createDefault(IEEEventsBot.config.token)
.enableIntents(GatewayIntent.GUILD_MESSAGES, GatewayIntent.GUILD_MEMBERS)
.addEventListeners(IEEEventsBot.commandManager, IEEEventsBot, MenuListener)
.setChunkingFilter(ChunkingFilter.ALL)
@ -69,13 +65,16 @@ fun main() {
// Ensure the StatusService stops correctly
Runtime.getRuntime().addShutdownHook(Thread {
IEEEventsBot.services.forEach{ service ->
IEEEventsBot.services.forEach { service ->
(service.getDeclaredField("INSTANCE")[null] as ToggleableService).shutdown()
}
})
}
/**
* The IEEE Event Mirroring Bot
*/
object IEEEventsBot : EventListener {
/**
* The [JDA] instance used by the bot.
@ -88,32 +87,18 @@ object IEEEventsBot : EventListener {
lateinit var commandManager: CommandManager<IEEEventsGuildSettings>
/**
* The YAML instance used.
* The bot [config]uration
*/
private val yaml = Yaml()
lateinit var config: BotConfig
/**
* The bot's default prefix.
*/
lateinit var prefix: String
/**
* The bot's login token.
*/
lateinit var token: String
/**
* The calendar url that we're attempting to mirror between discord + the source.
*/
lateinit var calendarUrl: String
/**
* The iCal [Calendar] object gotten from the [calendarUrl].
* The iCal [Calendar] object gotten from the [BotConfig.calendarUrl].
*/
@Suppress("MemberVisibilityCanBePrivate")
val calendar: Calendar?
get() =
try {
val inputStream = Utils.downloadCalendar(calendarUrl)
val inputStream = Utils.downloadCalendar(config.calendarUrl)
CalendarBuilder().build(inputStream)
} catch (t: Throwable) {
null
@ -137,13 +122,9 @@ object IEEEventsBot : EventListener {
}
/**
* Is the bot going to update its status?
*/
var updateStatus: Boolean = true
/**
* The commands the bot has.
* The [commands] the bot has.
*/
@Suppress("MemberVisibilityCanBePrivate")
val commands: List<Class<out CommandBase>> =
Reflections("xyz.brettb.discord.ieeevents.commands").getSubTypesOf(CommandBase::class.java)
.filterNot {
@ -159,7 +140,7 @@ object IEEEventsBot : EventListener {
.sortedBy { it.name }
/**
* The services the bot is using.
* The [services] the bot is using.
*/
val services: List<Class<out ToggleableService>> =
Reflections("xyz.brettb.discord.ieeevents.services").getSubTypesOf(ToggleableService::class.java)
@ -185,20 +166,14 @@ object IEEEventsBot : EventListener {
exitProcess(1)
}
val output = yaml.load(FileInputStream(configFile)) as Map<String, Any>
prefix = output["prefix"].toString()
token = output["token"].toString()
updateStatus = output["update-status"]?.toString()?.toBoolean() ?: true
calendarUrl = output["calendar-url"].toString()
val logLevel = output["log-level"]?.toString() ?: "INFO"
config = ConfigLoader().loadConfigOrThrow(configFile)
val level = Level.toLevel(logLevel, Level.INFO)
val level = Level.toLevel(config.logLevel, Level.INFO)
(LoggerFactory.getLogger("ROOT") as Logger).level = level
// Managers
IEEEventsGuildSettingsManager.start()
commandManager = CommandManager(IEEEventsGuildSettingsManager, prefix) { cEvent, t ->
commandManager = CommandManager(IEEEventsGuildSettingsManager, config.prefix) { cEvent, t ->
cEvent.replyError("An unknown error occurred!", { }, { })
logger.error("An uncaught exception occurred in a command: $t")
}


+ 3
- 2
src/main/kotlin/xyz/brettb/discord/ieeevents/Utils.kt View File

@ -23,8 +23,9 @@ object Utils {
val body = response.body
val resCode = response.code
if (resCode >= HttpURLConnection.HTTP_OK &&
resCode < HttpURLConnection.HTTP_MULT_CHOICE &&
body != null) {
resCode < HttpURLConnection.HTTP_MULT_CHOICE &&
body != null
) {
return body.byteStream()
} else {
throw error("failed to download file")


+ 7
- 0
src/main/kotlin/xyz/brettb/discord/ieeevents/commands/CommandCategories.kt View File

@ -3,6 +3,13 @@ package xyz.brettb.discord.ieeevents.commands
import tech.junodevs.discord.kriess.command.CommandCategory
object CommandCategories {
/**
* The Information Category
*/
val INFO = CommandCategory("Information")
/**
* The Settings Category
*/
val SETTINGS = CommandCategory("Settings")
}

+ 4
- 1
src/main/kotlin/xyz/brettb/discord/ieeevents/commands/info/HelpCommand.kt View File

@ -6,12 +6,15 @@ import tech.junodevs.discord.kriess.command.CommandEvent
import tech.junodevs.discord.kriess.menus.PaginationOptions
import tech.junodevs.discord.kriess.menus.PaginatorMenu
import xyz.brettb.discord.ieeevents.Constants
import xyz.brettb.discord.ieeevents.IEEEventsBot
import xyz.brettb.discord.ieeevents.commands.CommandBase
import xyz.brettb.discord.ieeevents.commands.CommandCategories
import xyz.brettb.discord.ieeevents.data.settings.settings
import java.util.concurrent.TimeUnit
/**
* The [HelpCommand] allows a user to check what commands exist
*/
@Suppress("unused")
object HelpCommand : CommandBase(
"help",
"Get some help on the bot",


+ 4
- 0
src/main/kotlin/xyz/brettb/discord/ieeevents/commands/info/UpcomingEventsCommand.kt View File

@ -14,6 +14,10 @@ import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.concurrent.TimeUnit
/**
* The [UpcomingEventsCommand] allows a user to check for upcoming events on the calendar.
*/
@Suppress("unused")
object UpcomingEventsCommand : CommandBase(
"upcoming",
"Get a list of upcoming events",


+ 4
- 0
src/main/kotlin/xyz/brettb/discord/ieeevents/commands/settings/ChangePrefixCommand.kt View File

@ -6,6 +6,10 @@ import xyz.brettb.discord.ieeevents.commands.CommandBase
import xyz.brettb.discord.ieeevents.commands.CommandCategories
import xyz.brettb.discord.ieeevents.data.settings.IEEEventsGuildSettingsManager
/**
* The [ChangePrefixCommand] allows you to change the bots' prefix in a given server.
*/
@Suppress("unused")
object ChangePrefixCommand : CommandBase(
"changeprefix",
"Change the bot prefix",


+ 58
- 0
src/main/kotlin/xyz/brettb/discord/ieeevents/data/settings/BotConfig.kt View File

@ -0,0 +1,58 @@
package xyz.brettb.discord.ieeevents.data.settings
/**
* The required values for the bot to run.
*/
data class BotConfig(
/**
* The Discord Log-In Token
*/
val token: String,
/**
* The calendar URL the bot should mirror to set channels
*/
val calendarUrl: String,
/**
* The bots' default prefix
*/
val prefix: String = "e.",
/**
* The minimum log level that should be logged
*/
val logLevel: String = "INFO",
/**
* If the bot should update its status
*/
val updateStatus: Boolean = true,
/**
* The list of user IDs that should ignore permissions
*/
val owners: List<String> = emptyList(),
/**
* The database the bot should connect to
*/
val database: DatabaseConfig = DatabaseConfig(),
) {
/**
* The required information to connect to the database
*/
data class DatabaseConfig(
/**
* The connection URL for the database
*/
val url: String = "mongodb://mongo",
/**
* The name of the database to use
*/
val name: String = "ieeebot"
)
}

+ 27
- 3
src/main/kotlin/xyz/brettb/discord/ieeevents/data/settings/IEEEventsGuildSettings.kt View File

@ -6,11 +6,32 @@ import tech.junodevs.discord.kriess.providers.GuildSettingsProvider
import xyz.brettb.discord.ieeevents.IEEEventsBot
import java.util.concurrent.CompletableFuture
class IEEEventsGuildSettings(val guildid: Long, var prefix: String? = null, val eventChannelID: Long? = null, var mirrorEvents: Boolean = false) : GuildSettingsProvider {
class IEEEventsGuildSettings(
/**
* The ID of the guild this settings object is tied to
*/
@Suppress("unused") val guildid: Long,
/**
* The guild's specific prefix
*/
var prefix: String? = null,
/**
* The ID of the channel where the events should be sent.
*/
@Suppress("MemberVisibilityCanBePrivate") val eventChannelID: Long? = null,
/**
* Should we mirror events to this guild from the calendar?
*/
var mirrorEvents: Boolean = false
) : GuildSettingsProvider {
override val realPrefix: String
get() = prefix ?: IEEEventsBot.prefix
get() = prefix ?: IEEEventsBot.config.prefix
/**
* The channel where the events should be sent
*/
@Suppress("unused")
val eventChannel: TextChannel?
get() = if (eventChannelID != null) IEEEventsBot.JDA.getTextChannelById(eventChannelID) else null
@ -24,5 +45,8 @@ class IEEEventsGuildSettings(val guildid: Long, var prefix: String? = null, val
}
/**
* Get the settings for a given guild
*/
val Guild.settings: CompletableFuture<IEEEventsGuildSettings>
get() = IEEEventsGuildSettingsManager.getSettingsFor(this)
get() = IEEEventsGuildSettingsManager.getSettingsFor(this)

+ 7
- 2
src/main/kotlin/xyz/brettb/discord/ieeevents/services/EventsService.kt View File

@ -1,16 +1,21 @@
package xyz.brettb.discord.ieeevents.services
import tech.junodevs.discord.kriess.services.Service
import xyz.brettb.discord.ieeevents.IEEEventsBot
import xyz.brettb.discord.ieeevents.data.settings.settings
import xyz.brettb.discord.ieeevents.logger
import java.util.concurrent.TimeUnit
/**
* Ensures Discord Events & Calendar events match every 30 minutes.
*/
@Suppress("unused")
object EventsService : ToggleableService(TimeUnit.MINUTES.toSeconds(30), 15) {
override fun execute() {
val events = IEEEventsBot.events
@Suppress("UNUSED_VARIABLE") val events = IEEEventsBot.events
IEEEventsBot.JDA.guilds.forEach { guild ->
if (guild.settings.get().mirrorEvents) {
logger.info("Mirroring events in guild ${guild.name}")
// Go through events in events
/// Ensure each event exists
//// If not, create + send announcement message


+ 5
- 2
src/main/kotlin/xyz/brettb/discord/ieeevents/services/StatusService.kt View File

@ -2,13 +2,16 @@ package xyz.brettb.discord.ieeevents.services
import net.dv8tion.jda.api.OnlineStatus
import net.dv8tion.jda.api.entities.Activity
import tech.junodevs.discord.kriess.services.Service
import xyz.brettb.discord.ieeevents.IEEEventsBot
/**
* Updates the bots' status every 60 seconds (if enabled)
*/
@Suppress("unused")
object StatusService : ToggleableService(60, 0) {
override fun execute() {
if (IEEEventsBot.updateStatus) {
if (IEEEventsBot.config.updateStatus) {
val events = IEEEventsBot.events
IEEEventsBot.JDA.presence.setPresence(
OnlineStatus.DO_NOT_DISTURB, Activity.watching(


+ 19
- 1
src/main/kotlin/xyz/brettb/discord/ieeevents/services/ToggleableService.kt View File

@ -2,6 +2,24 @@ package xyz.brettb.discord.ieeevents.services
import tech.junodevs.discord.kriess.services.Service
abstract class ToggleableService(period: Long, initial: Long = period, val enabled: Boolean = true) :
/**
* A service that can be prevented from being enabled
*/
abstract class ToggleableService(
/**
* The [period] (number of seconds) between each execution
*/
period: Long,
/**
* The [initial] delay before the service is executed for the first time
*/
initial: Long = period,
/**
* If the service should be [enabled] when it is initialized.
*/
val enabled: Boolean = true
) :
Service(initial, period) {
}

Loading…
Cancel
Save