Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.freya022.botcommands.api.commands.application.slash.annotations

/**
* Sets the desired file types accepted by an [Attachment][net.dv8tion.jda.api.entities.Message.Attachment] [@SlashOption][SlashOption].
*
* @see net.dv8tion.jda.api.interactions.FileType FileType
*/
@Target(AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
annotation class FileTypes(
/**
* Extensions to filter for.
*/
vararg val extensions: String,
/**
* Accepts any kind of image file supported by the Discord client.
*/
val image: Boolean = false,
/**
* Accepts any kind of video file supported by the Discord client.
*/
val video: Boolean = false,
/**
* Accepts any kind of audio file supported by the Discord client.
*/
val audio: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import io.github.freya022.botcommands.api.commands.application.LengthRange
import io.github.freya022.botcommands.api.commands.application.ValueRange
import io.github.freya022.botcommands.api.commands.application.options.ApplicationCommandOption
import io.github.freya022.botcommands.api.parameters.resolvers.SlashParameterResolver
import net.dv8tion.jda.api.interactions.FileType
import net.dv8tion.jda.api.interactions.commands.Command
import net.dv8tion.jda.api.interactions.commands.OptionType

Expand Down Expand Up @@ -55,6 +56,11 @@ interface SlashCommandOption : ApplicationCommandOption {
*/
val length: LengthRange?

/**
* The file types this [Attachment][net.dv8tion.jda.api.entities.Message.Attachment] option is accepting, if it is one.
*/
val fileTypes: List<FileType>

/**
* Whether this option uses autocomplete
*/
Expand All @@ -66,4 +72,4 @@ interface SlashCommandOption : ApplicationCommandOption {
* @throws IllegalStateException If this option has [no autocomplete][hasAutocomplete]
*/
fun invalidateAutocomplete()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import io.github.freya022.botcommands.api.commands.application.slash.autocomplet
import io.github.freya022.botcommands.api.core.config.BApplicationConfigBuilder
import io.github.freya022.botcommands.api.parameters.resolvers.SlashParameterResolver
import io.github.freya022.botcommands.internal.core.annotations.SkipJavaReflectionOverload
import net.dv8tion.jda.api.interactions.FileType
import net.dv8tion.jda.api.interactions.IFilterableFileTypes
import net.dv8tion.jda.api.interactions.commands.Command.Choice
import net.dv8tion.jda.api.interactions.commands.build.OptionData
import net.dv8tion.jda.api.interactions.commands.localization.LocalizationFunction
Expand Down Expand Up @@ -85,6 +87,74 @@ interface SlashCommandOptionBuilder : ApplicationCommandOptionBuilder {
*/
var lengthRange: LengthRange?

/**
* The file types this [Attachment][net.dv8tion.jda.api.entities.Message.Attachment] option is accepting, if it is one;
* up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES].
*
* @see FileType
*/
val fileTypes: FileTypeAccumulator

/**
* Adds up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] file extensions to filter for.
*
* @param extensions The extensions, up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES]
*
* @throws IllegalArgumentException There are more than [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] extensions,
* or, an extension is empty or isn't alphanumeric
*
* @see FileType
*/
fun addFileTypeExtensions(extensions: List<String>) {
fileTypes += extensions
}

/**
* Adds up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] file extensions to filter for.
*
* @param extensions The extensions, up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES]
*
* @throws IllegalArgumentException There are more than [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] extensions,
* or, an extension is empty or isn't alphanumeric
*
* @see FileType
*/
fun addFileTypeExtensions(vararg extensions: String) {
fileTypes += extensions.asList()
}

/**
* Sets up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] file extensions to filter for.
* Leave the arguments empty to remove file type filtering.
*
* @param extensions The extensions, up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES]
*
* @throws IllegalArgumentException There are more than [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] extensions,
* or, an extension is empty or isn't alphanumeric
*
* @see FileType
*/
fun setFileTypeExtensions(extensions: List<String>) {
fileTypes.clear()
fileTypes += extensions
}

/**
* Sets up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] file extensions to filter for.
* Leave the arguments empty to remove file type filtering.
*
* @param extensions The extensions, up to [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES]
*
* @throws IllegalArgumentException There are more than [MAX_FILE_TYPES][IFilterableFileTypes.MAX_FILE_TYPES] extensions,
* or, an extension is empty or isn't alphanumeric
*
* @see FileType
*/
fun setFileTypeExtensions(vararg extensions: String) {
fileTypes.clear()
fileTypes += extensions.asList()
}

/**
* Uses an existing autocomplete handler with the specified [name][AutocompleteHandler.name].
*
Expand All @@ -103,4 +173,37 @@ interface SlashCommandOptionBuilder : ApplicationCommandOptionBuilder {
*/
@SkipJavaReflectionOverload
fun autocompleteByFunction(function: KFunction<Collection<Any>>)

class FileTypeAccumulator internal constructor() {
private val _fileTypes = arrayListOf<FileType>()
internal val list: List<FileType> get() = _fileTypes

@JvmName("plusAssignExtensions")
operator fun plusAssign(extensions: Collection<String>) {
require(list.size + extensions.size <= OptionData.MAX_FILE_TYPES) {
"Cannot filter with more than ${OptionData.MAX_FILE_TYPES} file types"
}
_fileTypes += extensions.map(FileType::ofExtension)
}

operator fun plusAssign(extension: String) {
this += listOf(extension)
}

@JvmName("plusAssignFileTypes")
operator fun plusAssign(extensions: Collection<FileType>) {
require(list.size + extensions.size <= OptionData.MAX_FILE_TYPES) {
"Cannot filter with more than ${OptionData.MAX_FILE_TYPES} file types"
}
_fileTypes += extensions
}

operator fun plusAssign(extension: FileType) {
this += listOf(extension)
}

fun clear() {
_fileTypes.clear()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import io.github.freya022.botcommands.internal.parameters.ResolverContainer
import io.github.freya022.botcommands.internal.utils.*
import io.github.freya022.botcommands.internal.utils.ReflectionUtils.nonInstanceParameters
import net.dv8tion.jda.api.entities.Guild
import net.dv8tion.jda.api.interactions.FileType
import net.dv8tion.jda.api.interactions.InteractionContextType
import net.dv8tion.jda.api.interactions.commands.Command as JDACommand
import kotlin.reflect.KClass
Expand Down Expand Up @@ -362,6 +363,16 @@ internal class SlashCommandAutoBuilder(
parameter.findAnnotation<DoubleRange>()?.let { range -> valueRange = ValueRange.ofDouble(range.from, range.to) }
parameter.findAnnotation<Length>()?.let { length -> lengthRange = LengthRange.of(length.min, length.max) }

parameter.findAnnotation<FileTypes>()?.let { fileTypes ->
if (fileTypes.image)
this.fileTypes += FileType.IMAGE
if (fileTypes.video)
this.fileTypes += FileType.VIDEO
if (fileTypes.audio)
this.fileTypes += FileType.AUDIO
this.fileTypes += fileTypes.extensions.asList()
}

processAutocomplete(optionAnnotation)

usePredefinedChoices = optionAnnotation.usePredefinedChoices
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ internal object SlashUtils {
}
}

data.setFileTypes(option.fileTypes)

data.isRequired = option.isRequired
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.github.freya022.botcommands.internal.commands.application.slash.autoco
import io.github.freya022.botcommands.internal.commands.application.slash.options.builder.SlashCommandOptionBuilderImpl
import io.github.freya022.botcommands.internal.utils.LocalizationUtils
import io.github.freya022.botcommands.internal.utils.classRef
import net.dv8tion.jda.api.interactions.FileType
import net.dv8tion.jda.api.interactions.commands.Command
import net.dv8tion.jda.api.interactions.commands.OptionType

Expand All @@ -35,6 +36,7 @@ internal class SlashCommandOptionImpl internal constructor(
override val choices: List<Command.Choice>? = optionBuilder.choices
override val range: ValueRange? = optionBuilder.valueRange
override val length: LengthRange? = optionBuilder.lengthRange
override val fileTypes: List<FileType> = optionBuilder.fileTypes.list

init {
choices?.forEach {
Expand Down Expand Up @@ -68,4 +70,4 @@ internal class SlashCommandOptionImpl internal constructor(
}
autocompleteHandler!!.invalidate()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import io.github.freya022.botcommands.internal.commands.application.slash.builde
import io.github.freya022.botcommands.internal.parameters.OptionParameter
import io.github.freya022.botcommands.internal.utils.shortSignatureNoSrc
import io.github.freya022.botcommands.internal.utils.throwArgument
import net.dv8tion.jda.api.interactions.FileType
import net.dv8tion.jda.api.interactions.commands.Command
import net.dv8tion.jda.api.interactions.commands.build.OptionData
import kotlin.reflect.KFunction

internal class SlashCommandOptionBuilderImpl internal constructor(
Expand Down Expand Up @@ -52,6 +54,8 @@ internal class SlashCommandOptionBuilderImpl internal constructor(

override var lengthRange: LengthRange? = null

override val fileTypes = SlashCommandOptionBuilder.FileTypeAccumulator()

internal var autocompleteInfo: AutocompleteInfoImpl? = null
private set

Expand All @@ -63,4 +67,4 @@ internal class SlashCommandOptionBuilderImpl internal constructor(
autocompleteInfo = context.getService<AutocompleteInfoContainer>()[function]
?: throwArgument("No autocomplete handler declared from: ${function.shortSignatureNoSrc}")
}
}
}
Loading