feat: config files, better docs, move towards DB
This commit is contained in:
@@ -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,5 +1,5 @@
|
||||
major=0
|
||||
minor=2
|
||||
minor=3
|
||||
patch=0
|
||||
|
||||
kotlin.code.style=official
|
||||
|
||||
@@ -3,7 +3,7 @@ package xyz.brettb.discord.ieeevents
|
||||
object Constants {
|
||||
|
||||
object Colors {
|
||||
val BLUE = 0x0066A1
|
||||
const val BLUE = 0x0066A1
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
@@ -76,6 +72,9 @@ fun main() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()
|
||||
config = ConfigLoader().loadConfigOrThrow(configFile)
|
||||
|
||||
val logLevel = output["log-level"]?.toString() ?: "INFO"
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ object Utils {
|
||||
val resCode = response.code
|
||||
if (resCode >= HttpURLConnection.HTTP_OK &&
|
||||
resCode < HttpURLConnection.HTTP_MULT_CHOICE &&
|
||||
body != null) {
|
||||
body != null
|
||||
) {
|
||||
return body.byteStream()
|
||||
} else {
|
||||
throw error("failed to download 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")
|
||||
}
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
Reference in New Issue
Block a user