From 570040d5caf15b975e850e02a236f69c501149b4 Mon Sep 17 00:00:00 2001 From: Kallle Struik Date: Wed, 20 Apr 2022 20:32:12 +0200 Subject: [PATCH] Add quotes (#1) Quotes! Co-authored-by: Kalle Struik Reviewed-on: https://gitea.kallestruik.nl/kalle/discord-bot/pulls/1 --- .gitignore | 3 + .../kotlin/nl/kallestruik/discordbot/Bot.kt | 109 +++++++++++++++++- .../discordbot/data/quotes/QuoteData.kt | 9 ++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/nl/kallestruik/discordbot/data/quotes/QuoteData.kt diff --git a/.gitignore b/.gitignore index 525afc7..8e56f3f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # Don't leak secrets config.json +# And no test data either +quotes.json + .gradle build/ !gradle/wrapper/gradle-wrapper.jar diff --git a/src/main/kotlin/nl/kallestruik/discordbot/Bot.kt b/src/main/kotlin/nl/kallestruik/discordbot/Bot.kt index 2af38e4..f535931 100644 --- a/src/main/kotlin/nl/kallestruik/discordbot/Bot.kt +++ b/src/main/kotlin/nl/kallestruik/discordbot/Bot.kt @@ -7,22 +7,38 @@ import dev.kord.core.behavior.channel.createMessage import dev.kord.core.behavior.interaction.response.respond import dev.kord.core.builder.components.emoji import dev.kord.core.entity.channel.TextChannel +import dev.kord.core.entity.interaction.GuildChatInputCommandInteraction +import dev.kord.core.entity.interaction.InteractionCommand import dev.kord.core.event.interaction.GuildButtonInteractionCreateEvent +import dev.kord.core.event.interaction.GuildChatInputCommandInteractionCreateEvent import dev.kord.core.on +import dev.kord.rest.builder.interaction.string import dev.kord.rest.builder.message.create.actionRow import kotlinx.coroutines.flow.* import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import nl.kallestruik.discordbot.config.Config +import nl.kallestruik.discordbot.data.quotes.QuoteData import java.io.File +val prettyJson = Json { + prettyPrint = true +} + suspend fun main() { + val quoteFile = File("quotes.json") + if (!quoteFile.exists()) + quoteFile.writeText("[]") // Write an empty array if the file does not exist. + val config: Config = Json.decodeFromString(File("config.json").readText()) + val quotes: MutableList = Json.decodeFromString(quoteFile.readText()) val kord = Kord(config.token) val channel = kord.getChannel(Snowflake(config.roleChannelID)) as? TextChannel ?: return + // Delete old role selection messages val oldMessages = mutableSetOf() channel.messages .filter { it.author == kord.getSelf() } @@ -30,6 +46,7 @@ suspend fun main() { .toSet(oldMessages) channel.bulkDelete(oldMessages) + // Send the role selection message channel.createMessage { actionRow { for (role in config.roles) { @@ -43,6 +60,32 @@ suspend fun main() { } } + // Create the quotes command. Does discord get mad if this gets done on every startup? + kord.createGuildChatInputCommand(Snowflake(config.guildID), "quotes", "Get a quote") { + string("query", "What to search for.") + } + + kord.createGuildChatInputCommand(Snowflake(config.guildID), "quote", "Add a new quote") { + string("author", "The author of the quote.") { + required = true + } + + string("quote", "The quote.") { + required = true + } + } + + // Handle guild chat commands + kord.on { + val command = interaction.command + if (command.rootName == "quotes") + quotesCommandHandler(interaction, command, quotes) + + if (command.rootName == "quote") + quoteCommandHandler(interaction, command, quotes, quoteFile) + } + + // Handle guild chat buttons kord.on { val response = interaction.deferEphemeralResponse() val roleConfig = config.roles[interaction.data.data.customId.value] @@ -68,5 +111,69 @@ suspend fun main() { } } + // Start the bot kord.login() -} \ No newline at end of file +} + +suspend fun quoteCommandHandler( + interaction: GuildChatInputCommandInteraction, + command: InteractionCommand, + quotes: MutableList, + quoteFile: File +) { + val response = interaction.deferEphemeralResponse() + + val author = command.strings["author"]!! // These are required so they can't be null + val quote = command.strings["quote"]!!.replace("\\n", "\n") + quotes.add(QuoteData(author, quote)) + + quoteFile.writeText(prettyJson.encodeToString(quotes)) + + response.respond { + content = "Added quote successfully!" + } +} + +suspend fun quotesCommandHandler( + interaction: GuildChatInputCommandInteraction, + command: InteractionCommand, + quotes: MutableList +) { + val response = interaction.deferPublicResponse() + + val query = Regex(command.strings["query"] ?: "", RegexOption.IGNORE_CASE) + + val quotes = quotes.filter { + it.quote.contains(query) || it.author.contains(query) + } + + if (quotes.isEmpty()) { + response.respond { + content = "No quotes found!" + } + return + } + + response.respond { + content = "Search results for: $query" + } + + var content = "" + for (quote in quotes) { + val quoteString = "**${quote.author}:** ${quote.quote}\n" + if (content.length + quoteString.length >= 2000) { + interaction.channel.createMessage { + this.content = content + } + content = quoteString + continue + } + + content += quoteString + } + + interaction.channel.createMessage { + this.content = content + } +} + diff --git a/src/main/kotlin/nl/kallestruik/discordbot/data/quotes/QuoteData.kt b/src/main/kotlin/nl/kallestruik/discordbot/data/quotes/QuoteData.kt new file mode 100644 index 0000000..6d19e61 --- /dev/null +++ b/src/main/kotlin/nl/kallestruik/discordbot/data/quotes/QuoteData.kt @@ -0,0 +1,9 @@ +package nl.kallestruik.discordbot.data.quotes + +import kotlinx.serialization.Serializable + +@Serializable +data class QuoteData( + val author: String, + val quote: String, +)