diff --git a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java index 04cf7247d9..94626efff1 100644 --- a/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java +++ b/src/main/java/net/dv8tion/jda/api/components/attachmentupload/AttachmentUpload.java @@ -19,8 +19,15 @@ import net.dv8tion.jda.api.components.Component; import net.dv8tion.jda.api.components.attribute.ICustomId; import net.dv8tion.jda.api.components.label.LabelChildComponent; +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.interactions.IFilterableFileTypes; import net.dv8tion.jda.internal.components.attachmentupload.AttachmentUploadImpl; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.utils.Checks; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.Collection; +import java.util.List; import javax.annotation.CheckReturnValue; import javax.annotation.Nonnull; @@ -28,7 +35,8 @@ /** * Component accepting files from users. * - *

The user can send up to {@value #MAX_UPLOADS} files, the requested number of files can be adjusted or be completely optional. + *

The user can send up to {@value #MAX_UPLOADS} files, the requested number of files can be adjusted or be completely optional, + * additionally, the accepted file types can be configured. * *

Can only be used inside {@link net.dv8tion.jda.api.components.label.Label Labels}! */ @@ -92,6 +100,16 @@ static AttachmentUpload of(@Nonnull String customId) { */ int getMaxValues(); + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if any file is accepted. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + List getFileTypes(); + /** * Whether the user must send attachments. * @@ -106,11 +124,12 @@ static AttachmentUpload of(@Nonnull String customId) { /** * Builder for {@link AttachmentUpload AttachmentUploads}. */ - class Builder { + class Builder implements IFilterableFileTypes { protected int uniqueId = -1; protected String customId; protected int minValues = 1; protected int maxValues = 1; + protected final FileTypesImpl fileTypes = FileTypesImpl.empty(); protected boolean required = true; protected Builder(@Nonnull String customId) { @@ -206,6 +225,20 @@ public Builder setRequiredRange(int min, int max) { return setMinValues(min).setMaxValues(max); } + @Nonnull + @Override + public Builder addFileTypes(@Nonnull Collection fileTypes) { + this.fileTypes.addAll(fileTypes); + return this; + } + + @Nonnull + @Override + public Builder setFileTypes(@Nonnull Collection fileTypes) { + this.fileTypes.setAll(fileTypes); + return this; + } + /** * Changes whether the user must upload files. *
Default: {@code true} @@ -264,6 +297,18 @@ public int getMaxValues() { return maxValues; } + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if any file is accepted. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + public List getFileTypes() { + return fileTypes.asView(); + } + /** * Whether the user must send attachments. * @@ -288,7 +333,7 @@ public boolean isRequired() { @Nonnull public AttachmentUpload build() { Checks.check(maxValues >= minValues, "Max (%s) must be higher or equal to min (%s)", maxValues, minValues); - return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, required); + return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, fileTypes, required); } } } diff --git a/src/main/java/net/dv8tion/jda/api/interactions/FileType.java b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java new file mode 100644 index 0000000000..1a687860e0 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/FileType.java @@ -0,0 +1,133 @@ +/* + * 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; + +import net.dv8tion.jda.internal.utils.Checks; +import net.dv8tion.jda.internal.utils.EntityString; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Objects; +import java.util.regex.Pattern; + +import javax.annotation.Nonnull; + +/** + * Represents a type of file, you can use presets such as {@link #IMAGE}, + * or specify an extension using {@link #ofExtension(String)}. + * + *

Remember that this only checks the extension, Discord does not check for any file signature/MIME type, + * and thus does not guarantee receiving a valid file. + */ +public final class FileType { + private static final Pattern EXTENSION_PATTERN = Pattern.compile("[\\w\\-.]+"); + + /** Matches any image supported by the Discord client. */ + public static final FileType IMAGE = new FileType("image"); + /** Matches any video supported by the Discord client. */ + public static final FileType VIDEO = new FileType("video"); + /** Matches any audio supported by the Discord client. */ + public static final FileType AUDIO = new FileType("audio"); + + private final String value; + + @ApiStatus.Internal + public FileType(String value) { + this.value = value; + } + + /** + * Creates a {@link FileType} matching the provided extension. + * + * @param extension + * The extension to match against. + * + * @throws IllegalArgumentException + *

+ * + * @return The new {@link FileType} + */ + @Nonnull + public static FileType ofExtension(@Nonnull String extension) { + Checks.matches(extension, EXTENSION_PATTERN, "Extension"); + return new FileType("." + extension); + } + + /** + * Whether this file type accepts all image formats supported by Discord. + * + * @return {@code true} if this file type accepts all image formats supported by Discord, {@code false} if not + */ + public boolean isImage() { + return value.equals("image"); + } + + /** + * Whether this file type accepts all video formats supported by Discord. + * + * @return {@code true} if this file type accepts all video formats supported by Discord, {@code false} if not + */ + public boolean isVideo() { + return value.equals("video"); + } + + /** + * Whether this file type accepts all audio formats supported by Discord. + * + * @return {@code true} if this file type accepts all audio formats supported by Discord, {@code false} if not + */ + public boolean isAudio() { + return value.equals("audio"); + } + + /** + * The raw value of this file type. + * + * @return The raw value + */ + @Nonnull + public String getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FileType)) { + return false; + } + FileType that = (FileType) o; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } + + @Override + public String toString() { + return new EntityString(this) + .setName("FileType") + .addMetadata("value", value) + .toString(); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java new file mode 100644 index 0000000000..7119b9064d --- /dev/null +++ b/src/main/java/net/dv8tion/jda/api/interactions/IFilterableFileTypes.java @@ -0,0 +1,191 @@ +/* + * 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; + +import net.dv8tion.jda.internal.utils.Checks; + +import java.util.Arrays; +import java.util.Collection; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +/** + * Enables configuring a file type filter. + */ +public interface IFilterableFileTypes> { + /** The number of file type filters that can be applied at once. */ + int MAX_FILE_TYPES = 10; + + /** + * Adds up to {@value #MAX_FILE_TYPES} file types to filter for. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + T addFileTypes(@Nonnull Collection fileTypes); + + /** + * Adds up to {@value #MAX_FILE_TYPES} file types to filter for. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypes(@Nonnull FileType... fileTypes) { + Checks.noneNull(fileTypes, "File types"); + return addFileTypes(Arrays.asList(fileTypes)); + } + + /** + * Adds up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

+ * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypeExtensions(@Nonnull Collection extensions) { + Checks.noneNull(extensions, "Extensions"); + return addFileTypes(extensions.stream().map(FileType::ofExtension).collect(Collectors.toList())); + } + + /** + * Adds up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T addFileTypeExtensions(@Nonnull String... extensions) { + Checks.noneNull(extensions, "Extensions"); + return addFileTypeExtensions(Arrays.asList(extensions)); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file types to filter for. + * Pass an empty collection to remove file type filtering. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + T setFileTypes(@Nonnull Collection fileTypes); + + /** + * Sets up to {@value #MAX_FILE_TYPES} file types to filter for. + * Leave the arguments empty to remove file type filtering. + * + * @param fileTypes + * The file types, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + * If {@code null} is provided, or there are more than {@value #MAX_FILE_TYPES} file types + * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypes(@Nonnull FileType... fileTypes) { + Checks.noneNull(fileTypes, "File types"); + return setFileTypes(Arrays.asList(fileTypes)); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * Pass an empty collection to remove file type filtering. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypeExtensions(@Nonnull Collection extensions) { + Checks.noneNull(extensions, "Extensions"); + return setFileTypes(extensions.stream().map(FileType::ofExtension).collect(Collectors.toList())); + } + + /** + * Sets up to {@value #MAX_FILE_TYPES} file extensions to filter for. + * Leave the arguments empty to remove file type filtering. + * + *

This is the same as {@link #addFileTypes(Collection)} with {@link FileType#ofExtension(String)}. + * + * @param extensions + * The extensions, up to {@value #MAX_FILE_TYPES} + * + * @throws IllegalArgumentException + *

    + *
  • If there are more than {@value #MAX_FILE_TYPES} extensions
  • + *
  • If an extension is {@code null} or empty
  • + *
  • If the extension does not match {@code [\w\-.]+} (latin letters, digits, dashes or dots)
  • + *
+ * + * @return This instance for chaining + */ + @Nonnull + default T setFileTypeExtensions(@Nonnull String... extensions) { + Checks.noneNull(extensions, "Extensions"); + return setFileTypeExtensions(Arrays.asList(extensions)); + } +} diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java index 61718c7c19..96139a8db7 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/Command.java @@ -21,6 +21,7 @@ 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.FileType; import net.dv8tion.jda.api.interactions.IntegrationType; import net.dv8tion.jda.api.interactions.InteractionContextType; import net.dv8tion.jda.api.interactions.commands.build.CommandData; @@ -32,6 +33,7 @@ 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.FileTypesImpl; import net.dv8tion.jda.internal.interactions.command.CommandImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.EntityString; @@ -606,6 +608,7 @@ class Option { private Number minValue; private Number maxValue; private Integer minLength, maxLength; + private final FileTypesImpl fileTypes; public Option(@Nonnull DataObject json) { this.name = json.getString("name"); @@ -636,6 +639,8 @@ public Option(@Nonnull DataObject json) { if (!json.isNull("max_length")) { this.maxLength = json.getInt("max_length"); } + this.fileTypes = + json.optArray("file_types").map(FileTypesImpl::fromArray).orElse(FileTypesImpl.EMPTY_AND_IMMUTABLE); } /** @@ -775,6 +780,20 @@ public Integer getMaxLength() { return maxLength; } + /** + * The immutable list of file types accepted by this option. + * Returns an empty list if any file is accepted, + * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. + * + * @return Immutable list of file types accepted by this option + */ + @Nonnull + @Unmodifiable + public List getFileTypes() { + // No need for an extra copy + return fileTypes.asView(); + } + /** * The predefined choices available for this option. *
If no choices are defined, this returns an empty list. diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java index 911fc17240..f98a62d9f8 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/OptionType.java @@ -16,6 +16,7 @@ package net.dv8tion.jda.api.interactions.commands; +import net.dv8tion.jda.api.interactions.FileType; import net.dv8tion.jda.api.interactions.commands.build.SlashCommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandGroupData; @@ -82,7 +83,10 @@ public enum OptionType { */ NUMBER(10, true), /** - * Options which accept a file attachment + * Options which accept a file attachment. + * + *

File types accepted by these can be filtered, such as with {@link net.dv8tion.jda.api.interactions.commands.build.OptionData#addFileTypes(FileType...) OptionData.addFileTypes(FileType...)} + * or {@link net.dv8tion.jda.api.interactions.commands.build.OptionData#setFileTypes(FileType...) OptionData.setFileTypes(FileType...)} * @see OptionMapping#getAsAttachment() */ ATTACHMENT(11), diff --git a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java index 9d8068d50c..3517d7c8c3 100644 --- a/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java +++ b/src/main/java/net/dv8tion/jda/api/interactions/commands/build/OptionData.java @@ -19,6 +19,8 @@ import net.dv8tion.jda.api.entities.channel.ChannelType; import net.dv8tion.jda.api.events.interaction.command.CommandAutoCompleteInteractionEvent; import net.dv8tion.jda.api.interactions.DiscordLocale; +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.interactions.IFilterableFileTypes; import net.dv8tion.jda.api.interactions.commands.Command; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.localization.LocalizationMap; @@ -26,9 +28,11 @@ import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.api.utils.data.DataType; import net.dv8tion.jda.api.utils.data.SerializableData; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.localization.LocalizationUtils; import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.annotations.UnmodifiableView; import java.util.*; import java.util.stream.Collectors; @@ -39,7 +43,7 @@ /** * Builder for a Slash-Command option. */ -public class OptionData implements SerializableData { +public class OptionData implements SerializableData, IFilterableFileTypes { /** * The highest positive amount Discord allows the {@link OptionType#NUMBER NUMBER} type to be. */ @@ -90,6 +94,7 @@ public class OptionData implements SerializableData { private Number maxValue; private Integer minLength, maxLength; private List choices; + private final FileTypesImpl fileTypes = FileTypesImpl.empty(); /** * Create an option builder. @@ -332,6 +337,19 @@ public Integer getMaxLength() { return maxLength; } + /** + * The unmodifiable list view of file types to filter for. + * Returns an empty list if any file is accepted, + * or this isn't an {@link OptionType#ATTACHMENT ATTACHMENT} option. + * + * @return Unmodifiable list view of file types + */ + @Nonnull + @UnmodifiableView + public List getFileTypes() { + return fileTypes.asView(); + } + /** * The choices for this option. *
This is empty by default and can only be configured for specific option types. @@ -826,6 +844,20 @@ public OptionData setRequiredLength(int minLength, int maxLength) { return this; } + @Nonnull + @Override + public OptionData addFileTypes(@Nonnull Collection fileTypes) { + this.fileTypes.addAll(fileTypes); + return this; + } + + @Nonnull + @Override + public OptionData setFileTypes(@Nonnull Collection fileTypes) { + this.fileTypes.setAll(fileTypes); + return this; + } + /** * Add a predefined choice for this option. *
The user can only provide one of the choices and cannot specify any other value. @@ -1041,6 +1073,11 @@ public DataObject toData() { json.put("max_length", maxLength); } } + if (type == OptionType.ATTACHMENT) { + if (!fileTypes.isEmpty()) { + json.put("file_types", fileTypes.toData()); + } + } return json; } @@ -1097,6 +1134,12 @@ public static OptionData fromData(@Nonnull DataObject json) { option.setMaxLength(json.getInt("max_length")); } } + if (type == OptionType.ATTACHMENT) { + if (!json.isNull("file_types")) { + option.setFileTypes( + FileTypesImpl.fromArray(json.getArray("file_types")).asView()); + } + } json.optArray("choices") .ifPresent(choices1 -> option.addChoices(choices1.stream(DataArray::getObject) .map(Command.Choice::new) @@ -1156,6 +1199,9 @@ public static OptionData fromOption(@Nonnull Command.Option option) { data.setMaxLength(maxLength); } break; + case ATTACHMENT: + data.setFileTypes(option.getFileTypes()); + break; default: break; } diff --git a/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java b/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java index 18f6334d59..7f9d099130 100644 --- a/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java +++ b/src/main/java/net/dv8tion/jda/internal/components/attachmentupload/AttachmentUploadImpl.java @@ -18,11 +18,14 @@ import net.dv8tion.jda.api.components.attachmentupload.AttachmentUpload; import net.dv8tion.jda.api.components.label.LabelChildComponentUnion; +import net.dv8tion.jda.api.interactions.FileType; import net.dv8tion.jda.api.utils.data.DataObject; import net.dv8tion.jda.internal.components.AbstractComponentImpl; +import net.dv8tion.jda.internal.interactions.FileTypesImpl; import net.dv8tion.jda.internal.utils.Checks; import net.dv8tion.jda.internal.utils.EntityString; +import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; @@ -32,6 +35,7 @@ public class AttachmentUploadImpl extends AbstractComponentImpl implements Attac protected final String customId; protected final int minValues; protected final int maxValues; + protected final FileTypesImpl fileTypes; protected final boolean required; public AttachmentUploadImpl(DataObject data) { @@ -40,14 +44,17 @@ public AttachmentUploadImpl(DataObject data) { data.getString("custom_id"), data.getInt("min_values", 1), data.getInt("max_values", 1), + data.optArray("file_types").map(FileTypesImpl::fromArray).orElse(FileTypesImpl.empty()), data.getBoolean("required", true)); } - public AttachmentUploadImpl(int uniqueId, String customId, int minValues, int maxValues, boolean required) { + public AttachmentUploadImpl( + int uniqueId, String customId, int minValues, int maxValues, FileTypesImpl fileTypes, boolean required) { this.uniqueId = uniqueId; this.customId = customId; this.minValues = minValues; this.maxValues = maxValues; + this.fileTypes = fileTypes.copy(); this.required = required; } @@ -61,7 +68,7 @@ public Type getType() { @Override public AttachmentUploadImpl withUniqueId(int uniqueId) { Checks.positive(uniqueId, "Unique ID"); - return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, required); + return new AttachmentUploadImpl(uniqueId, customId, minValues, maxValues, fileTypes, required); } @Override @@ -85,6 +92,12 @@ public int getMaxValues() { return maxValues; } + @Nonnull + @Override + public List getFileTypes() { + return fileTypes.asView(); + } + @Override public boolean isRequired() { return required; @@ -98,7 +111,8 @@ public DataObject toData() { .put("custom_id", customId) .put("required", required) .put("min_values", minValues) - .put("max_values", maxValues); + .put("max_values", maxValues) + .put("file_types", fileTypes.toData()); if (uniqueId >= 0) { json.put("id", uniqueId); @@ -112,6 +126,7 @@ public String toString() { return new EntityString(this) .addMetadata("custom_id", customId) .addMetadata("required", required) + .addMetadata("file_types", fileTypes) .toString(); } diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java new file mode 100644 index 0000000000..c491079109 --- /dev/null +++ b/src/main/java/net/dv8tion/jda/internal/interactions/FileTypesImpl.java @@ -0,0 +1,118 @@ +/* + * 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.internal.interactions; + +import net.dv8tion.jda.api.interactions.FileType; +import net.dv8tion.jda.api.utils.data.DataArray; +import net.dv8tion.jda.internal.utils.Checks; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.*; +import java.util.stream.Collectors; + +import javax.annotation.Nonnull; + +import static net.dv8tion.jda.api.interactions.IFilterableFileTypes.MAX_FILE_TYPES; + +public final class FileTypesImpl { + public static final FileTypesImpl EMPTY_AND_IMMUTABLE = new FileTypesImpl(Collections.emptyList()); + + private final List fileTypes; + + private FileTypesImpl(List fileTypes) { + this.fileTypes = fileTypes; + } + + @Nonnull + public static FileTypesImpl empty() { + return new FileTypesImpl(new ArrayList<>()); + } + + @Nonnull + public static FileTypesImpl fromArray(@Nonnull DataArray array) { + return new FileTypesImpl( + array.stream(DataArray::getString).map(FileType::new).collect(Collectors.toList())); + } + + @Nonnull + public FileTypesImpl copy() { + return new FileTypesImpl(new ArrayList<>(fileTypes)); + } + + @Nonnull + @UnmodifiableView + public List asView() { + return Collections.unmodifiableList(fileTypes); + } + + public boolean isEmpty() { + return fileTypes.isEmpty(); + } + + public void addAll(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + Checks.check( + this.fileTypes.size() + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d + %d)", + MAX_FILE_TYPES, + this.fileTypes.size(), + fileTypes.size()); + this.fileTypes.addAll(fileTypes); + } + + public void setAll(@Nonnull Collection fileTypes) { + Checks.noneNull(fileTypes, "File types"); + Checks.check( + fileTypes.size() <= MAX_FILE_TYPES, + "Cannot have more than %d file types (provided: %d)", + MAX_FILE_TYPES, + fileTypes.size()); + this.fileTypes.clear(); + this.fileTypes.addAll(fileTypes); + } + + @Nonnull + public DataArray toData() { + DataArray array = DataArray.empty(); + for (FileType fileType : fileTypes) { + array.add(fileType.getValue()); + } + return array; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FileTypesImpl)) { + return false; + } + FileTypesImpl that = (FileTypesImpl) o; + return fileTypes.equals(that.fileTypes); + } + + @Override + public int hashCode() { + return fileTypes.hashCode(); + } + + @Override + public String toString() { + return fileTypes.toString(); + } +} diff --git a/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testSerializer_FILE_UPLOAD-data.json b/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testSerializer_FILE_UPLOAD-data.json index 2a6dc16220..de1ae728b3 100644 --- a/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testSerializer_FILE_UPLOAD-data.json +++ b/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testSerializer_FILE_UPLOAD-data.json @@ -1,5 +1,6 @@ [ { "custom_id" : "file-upload", + "file_types" : [ ], "max_values" : 1, "min_values" : 1, "required" : true, diff --git a/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testToStringMethods_FILE_UPLOAD.txt b/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testToStringMethods_FILE_UPLOAD.txt index 033f5c7c84..27e739150e 100644 --- a/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testToStringMethods_FILE_UPLOAD.txt +++ b/src/test/resources/net/dv8tion/jda/test/components/ComponentSerializerTest/testToStringMethods_FILE_UPLOAD.txt @@ -1 +1 @@ -AttachmentUpload(custom_id=file-upload, required=true) \ No newline at end of file +AttachmentUpload(custom_id=file-upload, required=true, file_types=[]) \ No newline at end of file