Skip to content

Commit

Permalink
Update to kordex 2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
DRSchlaubi committed Nov 5, 2024
1 parent 3cc797d commit 12cb8a4
Show file tree
Hide file tree
Showing 36 changed files with 462 additions and 386 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM --platform=$TARGETOS/$TARGETARCH eclipse-temurin:22-jre-alpine
FROM --platform=$TARGETOS/$TARGETARCH eclipse-temurin:23-jre-alpine

WORKDIR /usr/app
COPY plugin/build/install/bot-plugin .
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
alias(libs.plugins.kotlin.serialization) apply false
}
allprojects {
version = "5.7.2"
version = "5.8.0"
group = "space.votebot"

repositories {
Expand Down
9 changes: 4 additions & 5 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[versions]
kotlin = "2.0.21"
mikbot = "3.37.14"
ktor = "3.0.0"
mikbot = "4.1.1"
ktor = "3.0.1"

[libraries]
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version = "1.7.3" }
Expand All @@ -14,12 +14,11 @@ mikbot-gdpr = { group = "dev.schlaubi", name = "mikbot-gdpr" }
mikbot-kubernetes = { group = "dev.schlaubi", name = "mikbot-kubernetes" }
mikbot-ktor = { group = "dev.schlaubi", name = "mikbot-ktor" }

kordex-processor = { group = "com.kotlindiscord.kord.extensions", name = "annotation-processor", version = "1.9.1-mikbot-SNAPSHOT" }
java-string-similarity = { group = "info.debatty", name = "java-string-similarity", version = "2.0.0" }

[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
mikbot = { id = "dev.schlaubi.mikbot.gradle-plugin", version.ref = "mikbot" }
ksp = { id = "com.google.devtools.ksp", version = "2.0.21-1.0.25" }
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "5.4.0"}
ksp = { id = "com.google.devtools.ksp", version = "2.0.21-1.0.26" }
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "5.5.0"}
17 changes: 7 additions & 10 deletions plugin/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import dev.schlaubi.mikbot.gradle.mikbot
import java.io.ByteArrayOutputStream
import java.util.Locale

plugins {
kotlin("jvm")
Expand All @@ -14,7 +13,6 @@ dependencies {
api(projects.common)
implementation(projects.chartServiceClient)
implementation(libs.java.string.similarity)
ksp(libs.kordex.processor)
optionalPlugin(mikbot(libs.mikbot.gdpr))
optionalPlugin(mikbot(libs.mikbot.kubernetes))
optionalPlugin(mikbot(libs.mikbot.ktor))
Expand All @@ -26,7 +24,13 @@ mikbotPlugin {
pluginId = "votebot"
provider = "votebot.space"
license = "MIT"
enableKordexProcessor = false
enableKordexProcessor = true

i18n {
classPackage = "space.votebot.translations"
translationBundle = "votebot"
className = "VoteBotTranslations"
}
}

buildConfig {
Expand All @@ -45,13 +49,6 @@ sourceSets {
}
}

tasks {
generateDefaultTranslationBundle {
outputs.upToDateWhen { false }
defaultLocale = Locale.Builder().setLanguage("en").setRegion("GB").build()
}
}

fun Project.getGitCommit(): String {
return execCommand(arrayOf("git", "rev-parse", "--short", "HEAD"))
?: System.getenv("GITHUB_SHA") ?: "<unknown>"
Expand Down
62 changes: 30 additions & 32 deletions plugin/src/main/kotlin/space/votebot/command/PollArgument.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
package space.votebot.command

import com.kotlindiscord.kord.extensions.DiscordRelayedException
import com.kotlindiscord.kord.extensions.checks.interactionFor
import com.kotlindiscord.kord.extensions.commands.Argument
import com.kotlindiscord.kord.extensions.commands.CommandContext
import com.kotlindiscord.kord.extensions.commands.converters.SingleConverter
import com.kotlindiscord.kord.extensions.commands.converters.Validator
import com.kotlindiscord.kord.extensions.commands.converters.builders.ConverterBuilder
import com.kotlindiscord.kord.extensions.modules.annotations.converters.Converter
import com.kotlindiscord.kord.extensions.modules.annotations.converters.ConverterType
import com.kotlindiscord.kord.extensions.parser.StringParser
import com.kotlindiscord.kord.extensions.utils.hasPermission
import com.mongodb.client.model.Filters.and
import dev.kord.common.entity.Permission
import dev.kord.common.entity.Snowflake
Expand All @@ -20,8 +9,24 @@ import dev.kord.core.behavior.interaction.suggestString
import dev.kord.core.entity.interaction.AutoCompleteInteraction
import dev.kord.core.entity.interaction.OptionValue
import dev.kord.core.entity.interaction.StringOptionValue
import dev.kord.rest.builder.interaction.OptionsBuilder
import dev.kord.rest.builder.interaction.StringChoiceBuilder
import dev.kordex.core.DiscordRelayedException
import dev.kordex.core.annotations.InternalAPI
import dev.kordex.core.annotations.converters.Converter
import dev.kordex.core.annotations.converters.ConverterType
import dev.kordex.core.checks.interactionFor
import dev.kordex.core.commands.Argument
import dev.kordex.core.commands.CommandContext
import dev.kordex.core.commands.OptionWrapper
import dev.kordex.core.commands.converters.SingleConverter
import dev.kordex.core.commands.converters.Validator
import dev.kordex.core.commands.converters.builders.ConverterBuilder
import dev.kordex.core.i18n.EMPTY_KEY
import dev.kordex.core.i18n.toKey
import dev.kordex.core.i18n.types.Key
import dev.kordex.core.i18n.withContext
import dev.kordex.core.utils.hasPermission
import dev.kordex.parser.StringParser
import dev.schlaubi.mikbot.plugin.api.util.discordError
import dev.schlaubi.mikbot.plugin.api.util.safeInput
import dev.schlaubi.stdx.core.limit
Expand All @@ -31,6 +36,7 @@ import org.litote.kmongo.eq
import space.votebot.common.models.Poll
import space.votebot.core.VoteBotDatabase
import space.votebot.core.findOneByMessage
import space.votebot.translations.VoteBotTranslations
import space.votebot.util.jumpUrl

private val levenshtein = Levenshtein()
Expand All @@ -47,7 +53,7 @@ private val LOG = KotlinLogging.logger { }
)
// This is a modified version of: https://github.com/Kord-Extensions/kord-extensions/blob/f0334b7025d23874b37b2f9c82a1b12eb57efb0d/kord-extensions/src/main/kotlin/com/kotlindiscord/kord/extensions/commands/converters/impl/MessageConverter.kt
class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(validator) {
override val signatureTypeString: String = "Poll"
override val signatureType: Key = EMPTY_KEY

override fun withBuilder(builder: ConverterBuilder<Poll>): SingleConverter<Poll> {
val builderWithAutoComplete = builder.apply { autoComplete { onAutoComplete() } }
Expand All @@ -70,21 +76,22 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
val message = findMessage(text, context)

val poll = VoteBotDatabase.polls.findOneByMessage(message)
?: discordError(context.translate("commands.generic.poll_not_found"))
?: discordError(VoteBotTranslations.Commands.Generic.pollNotFound)
val user = context.getUser()
if (user?.id?.value != poll.authorId &&
context.getMember()?.run { asMember().hasPermission(Permission.ManageGuild) } != true
) {
discordError(context.translate("commands.generic.no_permission"))
discordError(VoteBotTranslations.Commands.Generic.noPermission)
}

parsed = poll

return true
}

override suspend fun toSlashOption(arg: Argument<*>): OptionsBuilder =
StringChoiceBuilder(arg.displayName, arg.description).apply { required = true }
@OptIn(InternalAPI::class)
override suspend fun toSlashOption(arg: Argument<*>) =
OptionWrapper(arg.displayName, arg.description, { required = true }, StringChoiceBuilder::class)

private suspend fun AutoCompleteInteraction.onAutoComplete() {
val safeInput = focusedOption.safeInput
Expand Down Expand Up @@ -120,7 +127,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
@Suppress("MagicNumber")
if (split.size < 3) {
throw DiscordRelayedException(
context.translate("converters.message.error.invalidUrl", replacements = arrayOf(arg))
"converters.message.error.invalidUrl".toKey().withOrdinalPlaceholders(arg)
)
}

Expand All @@ -129,7 +136,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
split.first().takeIf { it != "@me" }?.let(::Snowflake)
} catch (_: NumberFormatException) {
throw DiscordRelayedException(
context.translate("converters.message.error.invalidGuildId", replacements = arrayOf(split[0]))
"converters.message.error.invalidGuildId".toKey().withOrdinalPlaceholders(split[0])
)
}

Expand All @@ -138,10 +145,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
Snowflake(split[1])
} catch (_: NumberFormatException) {
throw DiscordRelayedException(
context.translate(
"converters.message.error.invalidChannelId",
replacements = arrayOf(split[1])
)
"converters.message.error.invalidChannelId".toKey().withOrdinalPlaceholders(split[1])
)
}

Expand All @@ -154,10 +158,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
Snowflake(split[2])
} catch (_: NumberFormatException) {
throw DiscordRelayedException(
context.translate(
"converters.message.error.invalidMessageId",
replacements = arrayOf(split[2])
)
"converters.message.error.invalidMessageId".toKey().withOrdinalPlaceholders(split[2])
)
}

Expand All @@ -176,10 +177,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v
arg.toULong()
} catch (e: NumberFormatException) {
throw DiscordRelayedException(
context.translate(
"converters.message.error.invalidMessageId",
replacements = arrayOf(arg)
)
"converters.message.error.invalidMessageId".toKey().withOrdinalPlaceholders(arg)
)
}

Expand All @@ -189,7 +187,7 @@ class PollConverter(validator: Validator<Poll> = null) : SingleConverter<Poll>(v

private suspend fun errorNoMessage(arg: String, context: CommandContext): Nothing {
throw DiscordRelayedException(
context.translate("converters.message.error.missing", replacements = arrayOf(arg))
"converters.message.error.missing".toKey().withContext(context).withOrdinalPlaceholders(arg)
)
}
}
Original file line number Diff line number Diff line change
@@ -1,74 +1,78 @@
package space.votebot.command

import com.kotlindiscord.kord.extensions.commands.Arguments
import com.kotlindiscord.kord.extensions.commands.application.slash.converters.ChoiceEnum
import com.kotlindiscord.kord.extensions.commands.application.slash.converters.impl.optionalEnumChoice
import com.kotlindiscord.kord.extensions.commands.converters.impl.optionalBoolean
import com.kotlindiscord.kord.extensions.commands.converters.impl.optionalDuration
import com.kotlindiscord.kord.extensions.commands.converters.impl.optionalInt
import dev.kordex.core.commands.Arguments
import dev.kordex.core.commands.application.slash.converters.ChoiceEnum
import dev.kordex.core.commands.application.slash.converters.impl.optionalEnumChoice
import dev.kordex.core.commands.converters.impl.optionalBoolean
import dev.kordex.core.commands.converters.impl.optionalDuration
import dev.kordex.core.commands.converters.impl.optionalInt
import dev.kordex.core.i18n.EMPTY_KEY
import dev.kordex.core.i18n.types.Key
import dev.kordex.core.utils.toDuration
import dev.schlaubi.mikbot.plugin.api.util.IKnowWhatIAmDoing
import dev.schlaubi.mikbot.plugin.api.util.SortedArguments
import dev.schlaubi.mikbot.plugin.api.util.discordError
import dev.schlaubi.mikbot.plugin.api.util.toDuration
import kotlinx.datetime.DateTimePeriod
import kotlinx.datetime.TimeZone
import space.votebot.common.models.PollSettings
import space.votebot.translations.VoteBotTranslations
import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes

interface PollSettingsArguments : PollSettings, PollSettingsArgumentsMixin {
val deleteAfterPeriod: DateTimePeriod?
override val deleteAfter: Duration?
get() = deleteAfterPeriod?.toDuration()
get() = deleteAfterPeriod?.toDuration(TimeZone.UTC)
}

interface PollSettingsArgumentsMixin {
fun Arguments.voteDuration(description: String) = optionalDuration {
name = "duration"
fun Arguments.voteDuration(description: Key) = optionalDuration {
name = VoteBotTranslations.Common.Duration.name
this.description = description

validate {
if (value != null && value!!.toDuration() < 1.minutes) {
discordError(translate("vote.create.too_short", "votebot"))
if (value != null && value!!.toDuration(TimeZone.UTC) < 1.minutes) {
discordError(VoteBotTranslations.Vote.Create.tooShort)
}
}
}

fun Arguments.maxVotes(description: String) = optionalInt {
name = "max-votes"
fun Arguments.maxVotes(description: Key) = optionalInt {
name = VoteBotTranslations.Common.MaxVotes.name
this.description = description
}

fun Arguments.maxChanges(description: String) = optionalInt {
name = "max-changes"
fun Arguments.maxChanges(description: Key) = optionalInt {
name = VoteBotTranslations.Common.MaxChanges.name
this.description = description
}

fun Arguments.showChart(description: String) = optionalBoolean {
name = "show-chart"
fun Arguments.showChart(description: Key) = optionalBoolean {
name = VoteBotTranslations.Common.ShowChart.name
this.description = description
}

fun Arguments.hideResults(description: String) = optionalBoolean {
name = "hide-results"
fun Arguments.hideResults(description: Key) = optionalBoolean {
name = VoteBotTranslations.Common.HideResults.name
this.description = description
}

fun Arguments.publicResults(description: String) = optionalBoolean {
name = "public-results"
fun Arguments.publicResults(description: Key) = optionalBoolean {
name = VoteBotTranslations.Common.PublicResults.name
this.description = description
}

fun Arguments.emojiMode(description: String) = optionalEnumChoice<ChoiceEmojiMode> {
name = "emoji-mode"
fun Arguments.emojiMode(description: Key) = optionalEnumChoice<ChoiceEmojiMode> {
name = VoteBotTranslations.Common.EmojiMode.name
this.description = description
typeName = "EmojiMode"
typeName = EMPTY_KEY
}
}

enum class ChoiceEmojiMode(override val readableName: String, val mode: PollSettings.EmojiMode) : ChoiceEnum {
ON("vote.emoji_mode.on", PollSettings.EmojiMode.ON),
OFF("vote.emoji_mode.off", PollSettings.EmojiMode.OFF),
CUSTOM("vote.emoji_mode.custom", PollSettings.EmojiMode.CUSTOM)
enum class ChoiceEmojiMode(override val readableName: Key, val mode: PollSettings.EmojiMode) : ChoiceEnum {
ON(VoteBotTranslations.Vote.EmojiMode.on, PollSettings.EmojiMode.ON),
OFF(VoteBotTranslations.Vote.EmojiMode.off, PollSettings.EmojiMode.OFF),
CUSTOM(VoteBotTranslations.Vote.EmojiMode.custom, PollSettings.EmojiMode.CUSTOM)
}

fun PollSettings.EmojiMode.toChoiceEmoji() = when (this) {
Expand All @@ -77,15 +81,16 @@ fun PollSettings.EmojiMode.toChoiceEmoji() = when (this) {
PollSettings.EmojiMode.CUSTOM -> ChoiceEmojiMode.CUSTOM
}

@Suppress("LeakingThis")
@OptIn(IKnowWhatIAmDoing::class)
abstract class AbstractPollSettingsArguments : SortedArguments(), PollSettingsArguments {
override val maxVotes by maxVotes("poll.create.arguments.max_votes")
override val maxChanges by maxChanges("poll.create.arguments.max_changes")
override val hideResults: Boolean? by hideResults("poll.create.arguments.hide_results")
override val publicResults: Boolean? by publicResults("poll.create.arguments.public_results")
override val deleteAfterPeriod by voteDuration("poll.create.arguments.delete_after_period")
override val showChartAfterClose: Boolean? by showChart("poll.create.arguments.show_chart_after_close")
private val emojiModeOption by emojiMode("poll.create.arguments.emoji_mode_option")
override val maxVotes by maxVotes(VoteBotTranslations.Poll.Create.Arguments.maxVotes)
override val maxChanges by maxChanges(VoteBotTranslations.Poll.Create.Arguments.maxChanges)
override val hideResults: Boolean? by hideResults(VoteBotTranslations.Poll.Create.Arguments.hideResults)
override val publicResults: Boolean? by publicResults(VoteBotTranslations.Poll.Create.Arguments.publicResults)
override val deleteAfterPeriod by voteDuration(VoteBotTranslations.Poll.Create.Arguments.deleteAfterPeriod)
override val showChartAfterClose: Boolean? by showChart(VoteBotTranslations.Poll.Create.Arguments.showChartAfterClose)
private val emojiModeOption by emojiMode(VoteBotTranslations.Poll.Create.Arguments.emojiModeOption)
override val emojiMode: PollSettings.EmojiMode?
get() = emojiModeOption?.mode
}
Expand Down
2 changes: 1 addition & 1 deletion plugin/src/main/kotlin/space/votebot/commands/Commands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ suspend fun VoteBotModule.commands() {
addOptionCommand()
removeOptionCommand()

infoCommand()
// infoCommand()
}
Loading

0 comments on commit 12cb8a4

Please sign in to comment.