All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.dv8tion.jda.api.interactions.commands.Command Maven / Gradle / Ivy

Go to download

Java wrapper for the popular chat & VOIP service: Discord https://discord.com

There is a newer version: 5.1.0
Show newest version
/*
 * Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.dv8tion.jda.api.interactions.commands;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.ISnowflake;
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.interactions.DiscordLocale;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.localization.LocalizationMap;
import net.dv8tion.jda.api.interactions.commands.privileges.IntegrationPrivilege;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.CommandEditAction;
import net.dv8tion.jda.api.utils.TimeUtil;
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.api.utils.data.DataType;
import net.dv8tion.jda.internal.interactions.command.CommandImpl;
import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EntityString;
import net.dv8tion.jda.internal.utils.localization.LocalizationUtils;
import org.jetbrains.annotations.Unmodifiable;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Represents a Discord slash-command.
 * 
This can be used to edit or delete the command. * * @see Guild#retrieveCommandById(String) * @see Guild#retrieveCommands() */ public interface Command extends ISnowflake, ICommandReference { /** * Delete this command. * * @throws IllegalStateException * If this command is not owned by this bot * * @return {@link RestAction} */ @Nonnull @CheckReturnValue RestAction delete(); /** * Edit this command. *
This can be used to change the command attributes such as name or description. * * @throws IllegalStateException * If this command is not owned by this bot * * @return {@link CommandEditAction} */ @Nonnull @CheckReturnValue CommandEditAction editCommand(); /** * Retrieves the {@link IntegrationPrivilege IntegrationPrivileges} for this command. *
This is a shortcut for {@link Guild#retrieveIntegrationPrivilegesById(String)}. * *

Moderators of a guild can modify these privileges through the Integrations Menu * *

If there is no command with the provided ID, * this RestAction fails with {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_COMMAND ErrorResponse.UNKNOWN_COMMAND} * * @param guild * The target guild from which to retrieve the privileges * * @throws IllegalArgumentException * If the guild is null * * @return {@link RestAction} - Type: {@link List} of {@link IntegrationPrivilege} */ @Nonnull @CheckReturnValue RestAction> retrievePrivileges(@Nonnull Guild guild); /** * Returns the {@link JDA JDA} instance of this Command * * @return the corresponding JDA instance */ @Nonnull JDA getJDA(); /** * The {@link Type} of command * * @return The command type */ @Nonnull Type getType(); /** * The name of this command. * * @return The name */ @Nonnull String getName(); /** * The localizations of this command's name for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized name */ @Nonnull LocalizationMap getNameLocalizations(); /** * The description of this command. * * @return The description, empty for context menu commands */ @Nonnull String getDescription(); /** * The localizations of this command's description for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized description */ @Nonnull LocalizationMap getDescriptionLocalizations(); /** * The {@link Option Options} of this command. * * @return Immutable list of command options */ @Nonnull @Unmodifiable List

    *
  • If the name is null, empty, or not between 1-{@value #MAX_NAME_LENGTH} characters long, * as defined by {@link #MAX_NAME_LENGTH}
  • *
  • If the value is null or longer than {@value #MAX_STRING_VALUE_LENGTH} characters long, * as defined by {@link #MAX_STRING_VALUE_LENGTH}
  • *
* */ public Choice(@Nonnull String name, @Nonnull String value) { setName(name); setStringValue(value); } /** * Create a Choice tuple * * @param json * The serialized choice instance with name and value mapping * * @throws IllegalArgumentException * If null is provided * @throws net.dv8tion.jda.api.exceptions.ParsingException * If the data is not formatted correctly or missing required parameters */ public Choice(@Nonnull DataObject json) { Checks.notNull(json, "DataObject"); this.name = json.getString("name"); if (json.isType("value", DataType.INT)) { setIntValue(json.getLong("value")); } else if (json.isType("value", DataType.FLOAT)) { setDoubleValue(json.getDouble("value")); } else { setStringValue(json.getString("value")); } setNameLocalizations(LocalizationUtils.mapFromProperty(json, "name_localizations")); } /** * The readable name of this choice. *
This is shown to the user in the official client. * * @return The choice name */ @Nonnull public String getName() { return name; } /** * Configure the choice name * * @param name * The choice name, {@link #MAX_NAME_LENGTH 1-100 characters long} * * @throws IllegalArgumentException * If the name is null, empty, or not between 1-{@value #MAX_NAME_LENGTH} characters long, * as defined by {@link #MAX_NAME_LENGTH} * * @return The Choice instance, for chaining */ public Choice setName(@Nonnull String name) { checkName(name); this.name = name; return this; } /** * The localizations of this choice's name for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized name */ @Nonnull public LocalizationMap getNameLocalizations() { return nameLocalizations; } /** * Sets the name localizations of this choice. * * @param locale * The locale to associate the translated name with * * @param name * The translated name to put * * @throws IllegalArgumentException *
    *
  • If the locale is null
  • *
  • If the name is null
  • *
  • If the locale is {@link DiscordLocale#UNKNOWN}
  • *
  • If the name does not pass the corresponding {@link #setName(String) name check}
  • *
* * @return This builder instance, for chaining */ @Nonnull public Choice setNameLocalization(@Nonnull DiscordLocale locale, @Nonnull String name) { nameLocalizations.setTranslation(locale, name); return this; } /** * Sets the name localizations of this choice. * * @param map * The map from which to transfer the translated names * * @throws IllegalArgumentException *
    *
  • If the map is null
  • *
  • If the map contains an {@link DiscordLocale#UNKNOWN} key
  • *
  • If the map contains a name which does not pass the corresponding {@link #setName(String) name check}
  • *
* * @return This builder instance, for chaining */ @Nonnull public Choice setNameLocalizations(@Nonnull Map map) { //Checks are done in LocalizationMap nameLocalizations.setTranslations(map); return this; } /** * The value of this choice. * * @return The double value, or NaN if this is not a numeric choice value */ public double getAsDouble() { return doubleValue; } /** * The value of this choice. * * @return The long value */ public long getAsLong() { return intValue; } /** * The value of this choice. * * @return The String value */ @Nonnull public String getAsString() { return stringValue; } /** * The {@link OptionType} this choice is for * * @return The option type of this choice */ @Nonnull public OptionType getType() { return type; } @Override public int hashCode() { return Objects.hash(name, stringValue); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof Choice)) return false; Choice other = (Choice) obj; return Objects.equals(other.name, name) && Objects.equals(other.stringValue, stringValue); } @Override public String toString() { return new EntityString(this) .setName(name) .addMetadata("value", stringValue) .toString(); } private void setIntValue(long value) { this.doubleValue = value; this.intValue = value; this.stringValue = Long.toString(value); this.type = OptionType.INTEGER; } private void setDoubleValue(double value) { this.doubleValue = value; this.intValue = (long) value; this.stringValue = Double.toString(value); this.type = OptionType.NUMBER; } private void setStringValue(@Nonnull String value) { Checks.notLonger(value, MAX_STRING_VALUE_LENGTH, "Choice string value"); this.doubleValue = Double.NaN; this.intValue = 0; this.stringValue = value; this.type = OptionType.STRING; } private void checkName(@Nonnull String name) { Checks.notEmpty(name, "Choice name"); Checks.notLonger(name, MAX_NAME_LENGTH, "Choice name"); } @Nonnull public DataObject toData(OptionType optionType) { final Object value; if (optionType == OptionType.INTEGER) value = getAsLong(); else if (optionType == OptionType.STRING) value = getAsString(); else if (optionType == OptionType.NUMBER) value = getAsDouble(); else throw new IllegalArgumentException("Cannot transform choice into data for type " + optionType); return DataObject.empty() .put("name", name) .put("value", value) .put("name_localizations", nameLocalizations); } } /** * An Option for a command. */ class Option { private final String name, description; private final LocalizationMap nameLocalizations; private final LocalizationMap descriptionLocalizations; private final int type; private final boolean required, autoComplete; private final Set channelTypes; private final List choices; private Number minValue; private Number maxValue; private Integer minLength, maxLength; public Option(@Nonnull DataObject json) { this.name = json.getString("name"); this.nameLocalizations = LocalizationUtils.unmodifiableFromProperty(json, "name_localizations"); this.description = json.getString("description"); this.descriptionLocalizations = LocalizationUtils.unmodifiableFromProperty(json, "description_localizations"); this.type = json.getInt("type"); this.required = json.getBoolean("required"); this.autoComplete = json.getBoolean("autocomplete"); this.channelTypes = Collections.unmodifiableSet(json.optArray("channel_types") .map(it -> it.stream(DataArray::getInt).map(ChannelType::fromId).collect(Collectors.toSet())) .orElse(Collections.emptySet())); this.choices = json.optArray("choices") .map(it -> it.stream(DataArray::getObject).map(Choice::new).collect(Collectors.toList())) .orElse(Collections.emptyList()); if (!json.isNull("min_value")) this.minValue = json.getDouble("min_value"); if (!json.isNull("max_value")) this.maxValue = json.getDouble("max_value"); if (!json.isNull("min_length")) this.minLength = json.getInt("min_length"); if (!json.isNull("max_length")) this.maxLength = json.getInt("max_length"); } /** * The name of this option, subcommand, or subcommand group. * * @return The name */ @Nonnull public String getName() { return name; } /** * The localizations of this option's name for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized name */ @Nonnull public LocalizationMap getNameLocalizations() { return nameLocalizations; } /** * The description of this option, subcommand, or subcommand group. * * @return The description */ @Nonnull public String getDescription() { return description; } /** * The localizations of this option's description for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized description */ @Nonnull public LocalizationMap getDescriptionLocalizations() { return descriptionLocalizations; } /** * The raw option type. * * @return The type */ public int getTypeRaw() { return type; } /** * Whether this option is required * * @return True if this option is required */ public boolean isRequired() { return required; } /** * Whether this option supports auto-complete * * @return True if this option supports auto-complete */ public boolean isAutoComplete() { return autoComplete; } /** * The {@link OptionType}. * * @return The type */ @Nonnull public OptionType getType() { return OptionType.fromKey(type); } /** * The {@link ChannelType ChannelTypes} this option is restricted to. *
This is empty if the option is not of type {@link OptionType#CHANNEL CHANNEL} or not restricted to specific types. * * @return Immutable {@link Set} of {@link ChannelType} */ @Nonnull @Unmodifiable public Set getChannelTypes() { return channelTypes; } /** * The minimum value which can be provided for this option. *
This returns {@code null} if the value is not set or if the option * is not of type {@link OptionType#INTEGER INTEGER} or {@link OptionType#NUMBER NUMBER}. * * @return The minimum value for this option or {@code null} */ @Nullable public Number getMinValue() { return minValue; } /** * The maximum value which can be provided for this option. *
This returns {@code null} if the value is not set or if the option * is not of type {@link OptionType#INTEGER INTEGER} or {@link OptionType#NUMBER NUMBER}. * * @return The maximum value for this option or {@code null} */ @Nullable public Number getMaxValue() { return maxValue; } /** * The minimum length for strings which can be provided for this option. *
This returns {@code null} if the value is not set or if the option * is not of type {@link OptionType#STRING STRING}. * * @return The minimum length for strings for this option or {@code null} */ @Nullable public Integer getMinLength() { return minLength; } /** * The maximum length for strings which can be provided for this option. *
This returns {@code null} if the value is not set or if the option * is not of type {@link OptionType#STRING STRING}. * * @return The maximum length for strings for this option or {@code null} */ @Nullable public Integer getMaxLength() { return maxLength; } /** * The predefined choices available for this option. *
If no choices are defined, this returns an empty list. * * @return Immutable {@link List} of {@link Choice} */ @Nonnull @Unmodifiable public List getChoices() { return choices; } @Override public int hashCode() { return Objects.hash(name, description, type, choices, channelTypes, minValue, maxValue, minLength, maxLength, required, autoComplete); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof Option)) return false; Option other = (Option) obj; return Objects.equals(other.name, name) && Objects.equals(other.description, description) && Objects.equals(other.choices, choices) && Objects.equals(other.channelTypes, channelTypes) && Objects.equals(other.minValue, minValue) && Objects.equals(other.maxValue, maxValue) && Objects.equals(other.minLength, minLength) && Objects.equals(other.maxLength, maxLength) && other.required == required && other.autoComplete == autoComplete && other.type == type; } @Override public String toString() { return new EntityString(this) .setType(getType()) .addMetadata("name", name) .toString(); } } /** * An Subcommand for a command. */ class Subcommand implements ICommandReference { private final ICommandReference parentCommand; //Could be Command or SubcommandGroup private final String name, description; private final LocalizationMap nameLocalizations; private final LocalizationMap descriptionLocalizations; private final List

This will return the ID of the top level command */ @Override public long getIdLong() { return parentCommand.getIdLong(); } /** * The name of this subcommand group. * * @return The name */ @Nonnull public String getName() { return name; } /** * The localizations of this subcommand group's name for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized name */ @Nonnull public LocalizationMap getNameLocalizations() { return nameLocalizations; } @Nonnull @Override public String getFullCommandName() { return parentCommand.getFullCommandName() + " " + getName(); } /** * The description of this subcommand group. * * @return The description */ @Nonnull public String getDescription() { return description; } /** * The localizations of this subcommand group's description for {@link DiscordLocale various languages}. * * @return The {@link LocalizationMap} containing the mapping from {@link DiscordLocale} to the localized description */ @Nonnull public LocalizationMap getDescriptionLocalizations() { return descriptionLocalizations; } /** * The {@link Subcommand Subcommands} in this group * * @return Immutable {@link List} of {@link Subcommand} */ @Nonnull @Unmodifiable public List getSubcommands() { return subcommands; } @Override public int hashCode() { return Objects.hash(name, description, subcommands); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof SubcommandGroup)) return false; SubcommandGroup other = (SubcommandGroup) obj; return Objects.equals(other.name, name) && Objects.equals(other.description, description) && Objects.equals(other.subcommands, subcommands); } @Override public String toString() { return new EntityString(this) .addMetadata("name", name) .toString(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy