getButtonsByLabel(@Nonnull String label, boolean ignoreCase
*
* @return {@link MessageAction MessageAction}
* The {@link net.dv8tion.jda.api.entities.Message Message} with the updated content
+ *
+ * @deprecated Use {@link #editMessageEmbeds(MessageEmbed...)} instead
+ */
+ @Nonnull
+ @CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline = "5.0.0")
+ @ReplaceWith("editMessageEmbeds(newEmbed)")
+ @DeprecatedSince("4.4.0")
+ default MessageAction editMessage(@Nonnull MessageEmbed newContent)
+ {
+ return editMessageEmbeds(newContent);
+ }
+
+ /**
+ * Edits this Message's content to the provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds}.
+ * Messages can only be edited by the account that sent them! .
+ *
+ * This message instance will not be updated by this operation, please use the response message instead.
+ *
+ *
The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The edit was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
+ * The edit was attempted after the account lost {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE} in
+ * the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The edit was attempted after the Message had been deleted.
+ *
+ *
+ * @param embeds
+ * the new embeds of the Message (up to 10)
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * If this is not a Received Message from {@link net.dv8tion.jda.api.entities.MessageType#DEFAULT MessageType.DEFAULT}
+ * @throws java.lang.IllegalStateException
+ * If the message attempting to be edited was not created by the currently logged in account, or
+ * if any of the passed-in embeds is {@code null}
+ * or not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}.
+ *
+ * @return {@link MessageAction MessageAction}
+ * The {@link net.dv8tion.jda.api.entities.Message Message} with the updated content
+ */
+ @Nonnull
+ @CheckReturnValue
+ MessageAction editMessageEmbeds(@Nonnull Collection extends MessageEmbed> embeds);
+
+ /**
+ * Edits this Message's content to the provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds}.
+ * Messages can only be edited by the account that sent them! .
+ *
+ * This message instance will not be updated by this operation, please use the response message instead.
+ *
+ *
The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The edit was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_PERMISSIONS MISSING_PERMISSIONS}
+ * The edit was attempted after the account lost {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE} in
+ * the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The edit was attempted after the Message had been deleted.
+ *
+ *
+ * @param embeds
+ * the new embeds of the Message (up to 10)
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * If this is not a Received Message from {@link net.dv8tion.jda.api.entities.MessageType#DEFAULT MessageType.DEFAULT}
+ * @throws java.lang.IllegalStateException
+ * If the message attempting to be edited was not created by the currently logged in account, or
+ * if any of the passed-in embeds is {@code null}
+ * or not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}.
+ *
+ * @return {@link MessageAction MessageAction}
+ * The {@link net.dv8tion.jda.api.entities.Message Message} with the updated content
*/
@Nonnull
@CheckReturnValue
- MessageAction editMessage(@Nonnull MessageEmbed newContent);
+ default MessageAction editMessageEmbeds(@Nonnull MessageEmbed... embeds)
+ {
+ Checks.noneNull(embeds, "MessageEmbeds");
+ return editMessageEmbeds(Arrays.asList(embeds));
+ }
/**
* Edits this Message's content to the provided format.
@@ -1125,7 +1215,7 @@ default MessageAction reply(@Nonnull CharSequence content)
* By default there won't be any error thrown if the referenced message does not exist.
* This behavior can be changed with {@link MessageAction#failOnInvalidReply(boolean)}.
*
- * For further info, see {@link MessageChannel#sendMessage(MessageEmbed)} and {@link MessageAction#reference(Message)}.
+ *
For further info, see {@link MessageChannel#sendMessageEmbeds(MessageEmbed, MessageEmbed...)} and {@link MessageAction#reference(Message)}.
*
* @param content
* The content of the reply message
@@ -1133,14 +1223,77 @@ default MessageAction reply(@Nonnull CharSequence content)
* @return {@link MessageAction} Providing the {@link Message} created from this upload.
*
* @since 4.2.1
+ *
+ * @deprecated Use {@link #replyEmbeds(MessageEmbed, MessageEmbed...)} instead
*/
@Nonnull
@CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline = "5.0.0")
+ @ReplaceWith("replyEmbeds(content)")
+ @DeprecatedSince("4.4.0")
default MessageAction reply(@Nonnull MessageEmbed content)
{
return getChannel().sendMessage(content).reference(this);
}
+ /**
+ * Replies and references this message.
+ * This is identical to {@code message.getChannel().sendMessageEmbeds(embeds).reference(message)}.
+ * You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
+ * By default there won't be any error thrown if the referenced message does not exist.
+ * This behavior can be changed with {@link MessageAction#failOnInvalidReply(boolean)}.
+ *
+ *
For further info, see {@link MessageChannel#sendMessageEmbeds(MessageEmbed, MessageEmbed...)} and {@link MessageAction#reference(Message)}.
+ *
+ * @param embed
+ * The embed to reply with
+ * @param other
+ * Additional embeds to reply with
+ *
+ * @throws IllegalArgumentException
+ * If null is provided, any of the embeds are not {@link MessageEmbed#isSendable() sendable}, more than 10 embeds are provided,
+ * or the sum of {@link MessageEmbed#getLength()} is greater than {@link MessageEmbed#EMBED_MAX_LENGTH_BOT}
+ *
+ * @return {@link MessageAction} Providing the {@link Message} created from this upload.
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction replyEmbeds(@Nonnull MessageEmbed embed, @Nonnull MessageEmbed... other)
+ {
+ Checks.notNull(embed, "MessageEmbeds");
+ Checks.noneNull(other, "MessageEmbeds");
+ List embeds = new ArrayList<>(1 + other.length);
+ embeds.add(embed);
+ Collections.addAll(embeds, other);
+ return replyEmbeds(embeds);
+ }
+
+ /**
+ * Replies and references this message.
+ * This is identical to {@code message.getChannel().sendMessageEmbeds(embeds).reference(message)}.
+ * You can use {@link MessageAction#mentionRepliedUser(boolean) mentionRepliedUser(false)} to not mention the author of the message.
+ * By default there won't be any error thrown if the referenced message does not exist.
+ * This behavior can be changed with {@link MessageAction#failOnInvalidReply(boolean)}.
+ *
+ * For further info, see {@link MessageChannel#sendMessageEmbeds(MessageEmbed, MessageEmbed...)} and {@link MessageAction#reference(Message)}.
+ *
+ * @param embeds
+ * The embeds to reply with
+ *
+ * @throws IllegalArgumentException
+ * If null is provided, any of the embeds are not {@link MessageEmbed#isSendable() sendable}, more than 10 embeds are provided,
+ * or the sum of {@link MessageEmbed#getLength()} is greater than {@link MessageEmbed#EMBED_MAX_LENGTH_BOT}
+ *
+ * @return {@link MessageAction} Providing the {@link Message} created from this upload.
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction replyEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
+ {
+ return getChannel().sendMessageEmbeds(embeds).reference(this);
+ }
+
/**
* Replies and references this message.
* This is identical to {@code message.getChannel().sendMessage(content).reference(message)}.
diff --git a/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java b/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java
index 56e041af38..40c26775b1 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/MessageChannel.java
@@ -15,6 +15,9 @@
*/
package net.dv8tion.jda.api.entities;
+import net.dv8tion.jda.annotations.DeprecatedSince;
+import net.dv8tion.jda.annotations.ForRemoval;
+import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.api.AccountType;
import net.dv8tion.jda.api.exceptions.AccountTypeException;
import net.dv8tion.jda.api.requests.RestAction;
@@ -312,11 +315,10 @@ default MessageAction sendMessage(@Nonnull CharSequence text)
Checks.notEmpty(text, "Provided text for message");
Checks.check(text.length() <= 2000, "Provided text for message must be less than 2000 characters in length");
- Route.CompiledRoute route = Route.Messages.SEND_MESSAGE.compile(getId());
if (text instanceof StringBuilder)
- return new MessageActionImpl(getJDA(), route, this, (StringBuilder) text);
+ return new MessageActionImpl(getJDA(), null, this, (StringBuilder) text);
else
- return new MessageActionImpl(getJDA(), route, this).append(text);
+ return new MessageActionImpl(getJDA(), null, this).append(text);
}
/**
@@ -400,17 +402,114 @@ default MessageAction sendMessageFormat(@Nonnull String format, @Nonnull Object.
*
* @see net.dv8tion.jda.api.MessageBuilder
* @see net.dv8tion.jda.api.EmbedBuilder
+ *
+ * @deprecated This is deprecated in favor of {@link #sendMessageEmbeds(MessageEmbed, MessageEmbed...)}
*/
@Nonnull
@CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline="5.0.0")
+ @ReplaceWith("sendMessageEmbeds(embed)")
+ @DeprecatedSince("4.4.0")
default MessageAction sendMessage(@Nonnull MessageEmbed embed)
{
Checks.notNull(embed, "Provided embed");
- Route.CompiledRoute route = Route.Messages.SEND_MESSAGE.compile(getId());
- return new MessageActionImpl(getJDA(), route, this).embed(embed);
+ return new MessageActionImpl(getJDA(), null, this).setEmbeds(embed);
}
+ /**
+ * Sends up to 10 specified {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} as a {@link net.dv8tion.jda.api.entities.Message Message}
+ * to this channel.
+ * This will fail if this channel is an instance of {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} and
+ * the currently logged in account does not have permissions to send a message to this channel.
+ * To determine if you are able to send a message in a {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} use
+ * {@link net.dv8tion.jda.api.entities.Member#hasPermission(GuildChannel, net.dv8tion.jda.api.Permission...)
+ * guild.getSelfMember().hasPermission(channel, Permission.MESSAGE_WRITE)}.
+ *
+ *
For {@link net.dv8tion.jda.api.requests.ErrorResponse} information, refer to {@link #sendMessage(Message)}.
+ *
+ * @param embed
+ * The {@link MessageEmbed MessageEmbed} to send
+ * @param other
+ * Additional {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to send
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} and the logged in account does
+ * not have
+ *
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_EMBED_LINKS Permission.MESSAGE_EMBED_LINKS}
+ *
+ * @throws java.lang.IllegalArgumentException
+ * If null is provided, any of the embeds are not {@link MessageEmbed#isSendable() sendable}, more than 10 embeds are provided,
+ * or the sum of {@link MessageEmbed#getLength()} is greater than {@link MessageEmbed#EMBED_MAX_LENGTH_BOT}
+ * @throws java.lang.UnsupportedOperationException
+ * If this is a {@link net.dv8tion.jda.api.entities.PrivateChannel PrivateChannel}
+ * and both the currently logged in account and the target user are bots.
+ *
+ * @return {@link MessageAction MessageAction}
+ * The newly created Message after it has been sent to Discord.
+ *
+ * @see net.dv8tion.jda.api.MessageBuilder
+ * @see net.dv8tion.jda.api.EmbedBuilder
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction sendMessageEmbeds(@Nonnull MessageEmbed embed, @Nonnull MessageEmbed... other)
+ {
+ Checks.notNull(embed, "MessageEmbeds");
+ Checks.noneNull(other, "MessageEmbeds");
+ List embeds = new ArrayList<>(1 + other.length);
+ embeds.add(embed);
+ Collections.addAll(embeds, other);
+ return new MessageActionImpl(getJDA(), null, this).setEmbeds(embeds);
+ }
+
+ /**
+ * Sends up to 10 specified {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} as a {@link net.dv8tion.jda.api.entities.Message Message}
+ * to this channel.
+ * This will fail if this channel is an instance of {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} and
+ * the currently logged in account does not have permissions to send a message to this channel.
+ * To determine if you are able to send a message in a {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} use
+ * {@link net.dv8tion.jda.api.entities.Member#hasPermission(GuildChannel, net.dv8tion.jda.api.Permission...)
+ * guild.getSelfMember().hasPermission(channel, Permission.MESSAGE_WRITE)}.
+ *
+ * For {@link net.dv8tion.jda.api.requests.ErrorResponse} information, refer to {@link #sendMessage(Message)}.
+ *
+ * @param embeds
+ * The {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} to send
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} and the logged in account does
+ * not have
+ *
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_EMBED_LINKS Permission.MESSAGE_EMBED_LINKS}
+ *
+ * @throws java.lang.IllegalArgumentException
+ * If any of the provided embeds is {@code null} or if the provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed}
+ * is not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}
+ * @throws java.lang.UnsupportedOperationException
+ * If this is a {@link net.dv8tion.jda.api.entities.PrivateChannel PrivateChannel}
+ * and both the currently logged in account and the target user are bots.
+ *
+ * @return {@link MessageAction MessageAction}
+ * The newly created Message after it has been sent to Discord.
+ *
+ * @see net.dv8tion.jda.api.MessageBuilder
+ * @see net.dv8tion.jda.api.EmbedBuilder
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction sendMessageEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
+ {
+ return new MessageActionImpl(getJDA(), null, this).setEmbeds(embeds);
+ }
+
+
/**
* Sends a specified {@link net.dv8tion.jda.api.entities.Message Message} to this channel.
* This will fail if this channel is an instance of {@link net.dv8tion.jda.api.entities.TextChannel TextChannel} and
@@ -467,9 +566,7 @@ default MessageAction sendMessage(@Nonnull MessageEmbed embed)
default MessageAction sendMessage(@Nonnull Message msg)
{
Checks.notNull(msg, "Message");
-
- Route.CompiledRoute route = Route.Messages.SEND_MESSAGE.compile(getId());
- return new MessageActionImpl(getJDA(), route, this).apply(msg);
+ return new MessageActionImpl(getJDA(), null, this).apply(msg);
}
/**
@@ -491,7 +588,7 @@ default MessageAction sendMessage(@Nonnull Message msg)
* File file = new File("cat.gif");
* embed.setImage("attachment://cat.gif")
* .setDescription("This is a cute cat :3");
- * channel.sendFile(file).embed(embed.build()).queue();
+ * channel.sendFile(file).setEmbeds(embed.build()).queue();
*
*
* For {@link net.dv8tion.jda.api.requests.ErrorResponse} information, refer to the documentation for {@link #sendFile(java.io.File, String, AttachmentOption...)}.
@@ -527,7 +624,6 @@ default MessageAction sendMessage(@Nonnull Message msg)
default MessageAction sendFile(@Nonnull File file, @Nonnull AttachmentOption... options)
{
Checks.notNull(file, "file");
-
return sendFile(file, file.getName(), options);
}
@@ -559,7 +655,7 @@ default MessageAction sendFile(@Nonnull File file, @Nonnull AttachmentOption...
* File file = new File("cat_01.gif");
* embed.setImage("attachment://cat.gif") // we specify this in sendFile as "cat.gif"
* .setDescription("This is a cute cat :3");
- * channel.sendFile(file, "cat.gif").embed(embed.build()).queue();
+ * channel.sendFile(file, "cat.gif").setEmbeds(embed.build()).queue();
*
*
*
The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
@@ -648,7 +744,7 @@ default MessageAction sendFile(@Nonnull File file, @Nonnull String fileName, @No
* InputStream file = new URL("https://http.cat/500").openStream();
* embed.setImage("attachment://cat.png") // we specify this in sendFile as "cat.png"
* .setDescription("This is a cute cat :3");
- * channel.sendFile(file, "cat.png").embed(embed.build()).queue();
+ * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue();
*
*
* @param data
@@ -681,9 +777,7 @@ default MessageAction sendFile(@Nonnull InputStream data, @Nonnull String fileNa
{
Checks.notNull(data, "data InputStream");
Checks.notNull(fileName, "fileName");
-
- Route.CompiledRoute route = Route.Messages.SEND_MESSAGE.compile(getId());
- return new MessageActionImpl(getJDA(), route, this).addFile(data, fileName, options);
+ return new MessageActionImpl(getJDA(), null, this).addFile(data, fileName, options);
}
/**
@@ -706,7 +800,7 @@ default MessageAction sendFile(@Nonnull InputStream data, @Nonnull String fileNa
* byte[] file = IOUtil.readFully(new URL("https://http.cat/500").openStream());
* embed.setImage("attachment://cat.png") // we specify this in sendFile as "cat.png"
* .setDescription("This is a cute cat :3");
- * channel.sendFile(file, "cat.png").embed(embed.build()).queue();
+ * channel.sendFile(file, "cat.png").setEmbeds(embed.build()).queue();
*
*
* @param data
@@ -2635,12 +2729,10 @@ default MessageAction editMessageById(@Nonnull String messageId, @Nonnull CharSe
Checks.isSnowflake(messageId, "Message ID");
Checks.notEmpty(newContent, "Provided message content");
Checks.check(newContent.length() <= 2000, "Provided newContent length must be 2000 or less characters.");
-
- Route.CompiledRoute route = Route.Messages.EDIT_MESSAGE.compile(getId(), messageId);
if (newContent instanceof StringBuilder)
- return new MessageActionImpl(getJDA(), route, this, (StringBuilder) newContent);
+ return new MessageActionImpl(getJDA(), messageId, this, (StringBuilder) newContent);
else
- return new MessageActionImpl(getJDA(), route, this).append(newContent);
+ return new MessageActionImpl(getJDA(), messageId, this).append(newContent);
}
/**
@@ -2739,9 +2831,7 @@ default MessageAction editMessageById(@Nonnull String messageId, @Nonnull Messag
{
Checks.isSnowflake(messageId, "Message ID");
Checks.notNull(newContent, "message");
-
- Route.CompiledRoute route = Route.Messages.EDIT_MESSAGE.compile(getId(), messageId);
- return new MessageActionImpl(getJDA(), route, this).apply(newContent);
+ return new MessageActionImpl(getJDA(), messageId, this).apply(newContent);
}
/**
@@ -2956,13 +3046,15 @@ default MessageAction editMessageFormatById(long messageId, @Nonnull String form
*/
@Nonnull
@CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline = "5.0.0")
+ @ReplaceWith("editMessageEmbedsById(messageId, newEmbed)")
+ @DeprecatedSince("4.4.0")
default MessageAction editMessageById(@Nonnull String messageId, @Nonnull MessageEmbed newEmbed)
{
Checks.isSnowflake(messageId, "Message ID");
Checks.notNull(newEmbed, "MessageEmbed");
-
- Route.CompiledRoute route = Route.Messages.EDIT_MESSAGE.compile(getId(), messageId);
- return new MessageActionImpl(getJDA(), route, this).embed(newEmbed);
+ return new MessageActionImpl(getJDA(), messageId, this).setEmbeds(newEmbed);
}
/**
@@ -3010,11 +3102,210 @@ default MessageAction editMessageById(@Nonnull String messageId, @Nonnull Messag
*/
@Nonnull
@CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline = "5.0.0")
+ @ReplaceWith("editMessageEmbedsById(messageId, newEmbed)")
+ @DeprecatedSince("4.4.0")
default MessageAction editMessageById(long messageId, @Nonnull MessageEmbed newEmbed)
{
return editMessageById(Long.toUnsignedString(messageId), newEmbed);
}
+ /**
+ * Attempts to edit a message by its id in this MessageChannel.
+ *
+ *
The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
+ * Attempted to edit a message that was not sent by the currently logged in account.
+ * Discord does not allow editing of other users' Messages!
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The request was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed, or after {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * was revoked in the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
+ * the message it referred to has already been deleted.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
+ * The request was attempted after the channel was deleted.
+ *
+ *
+ * @param messageId
+ * The id referencing the Message that should be edited
+ * @param newEmbeds
+ * Up to 10 new {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} for the edited message
+ *
+ * @throws IllegalArgumentException
+ *
+ * If provided {@code messageId} is {@code null} or empty.
+ * If provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed}
+ * is not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a TextChannel and this account does not have
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * or {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ *
+ * @return {@link MessageAction MessageAction}
+ * The modified Message after it has been sent to discord
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction editMessageEmbedsById(@Nonnull String messageId, @Nonnull MessageEmbed... newEmbeds)
+ {
+ Checks.noneNull(newEmbeds, "MessageEmbeds");
+ return editMessageEmbedsById(messageId, Arrays.asList(newEmbeds));
+ }
+
+ /**
+ * Attempts to edit a message by its id in this MessageChannel.
+ *
+ * The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
+ * Attempted to edit a message that was not sent by the currently logged in account.
+ * Discord does not allow editing of other users' Messages!
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The request was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed, or after {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * was revoked in the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
+ * the message it referred to has already been deleted.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
+ * The request was attempted after the channel was deleted.
+ *
+ *
+ * @param messageId
+ * The id referencing the Message that should be edited
+ * @param newEmbeds
+ * Up to 10 new {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} for the edited message
+ *
+ * @throws IllegalArgumentException
+ *
+ * If provided {@code messageId} is {@code null} or empty.
+ * If provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed}
+ * is not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a TextChannel and this account does not have
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * or {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ *
+ * @return {@link MessageAction MessageAction}
+ * The modified Message after it has been sent to discord
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction editMessageEmbedsById(long messageId, @Nonnull MessageEmbed... newEmbeds)
+ {
+ return editMessageEmbedsById(Long.toUnsignedString(messageId), newEmbeds);
+ }
+
+ /**
+ * Attempts to edit a message by its id in this MessageChannel.
+ *
+ * The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
+ * Attempted to edit a message that was not sent by the currently logged in account.
+ * Discord does not allow editing of other users' Messages!
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The request was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed, or after {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * was revoked in the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
+ * the message it referred to has already been deleted.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
+ * The request was attempted after the channel was deleted.
+ *
+ *
+ * @param messageId
+ * The id referencing the Message that should be edited
+ * @param newEmbeds
+ * Up to 10 new {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} for the edited message
+ *
+ * @throws IllegalArgumentException
+ *
+ * If provided {@code messageId} is {@code null} or empty.
+ * If provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed}
+ * is not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a TextChannel and this account does not have
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * or {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ *
+ * @return {@link MessageAction MessageAction}
+ * The modified Message after it has been sent to discord
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction editMessageEmbedsById(@Nonnull String messageId, @Nonnull Collection extends MessageEmbed> newEmbeds)
+ {
+ Checks.isSnowflake(messageId, "Message ID");
+ return new MessageActionImpl(getJDA(), messageId, this).setEmbeds(newEmbeds);
+ }
+
+ /**
+ * Attempts to edit a message by its id in this MessageChannel.
+ *
+ * The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
+ * Attempted to edit a message that was not sent by the currently logged in account.
+ * Discord does not allow editing of other users' Messages!
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#MISSING_ACCESS MISSING_ACCESS}
+ * The request was attempted after the account lost access to the {@link net.dv8tion.jda.api.entities.Guild Guild}
+ * typically due to being kicked or removed, or after {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * was revoked in the {@link net.dv8tion.jda.api.entities.TextChannel TextChannel}
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
+ * The provided {@code messageId} is unknown in this MessageChannel, either due to the id being invalid, or
+ * the message it referred to has already been deleted.
+ *
+ * {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
+ * The request was attempted after the channel was deleted.
+ *
+ *
+ * @param messageId
+ * The id referencing the Message that should be edited
+ * @param newEmbeds
+ * Up to 10 new {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} for the edited message
+ *
+ * @throws IllegalArgumentException
+ *
+ * If provided {@code messageId} is {@code null} or empty.
+ * If provided {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbed}
+ * is not {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() sendable}
+ *
+ * @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
+ * If this is a TextChannel and this account does not have
+ * {@link net.dv8tion.jda.api.Permission#MESSAGE_READ Permission.MESSAGE_READ}
+ * or {@link net.dv8tion.jda.api.Permission#MESSAGE_WRITE Permission.MESSAGE_WRITE}
+ *
+ * @return {@link MessageAction MessageAction}
+ * The modified Message after it has been sent to discord
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction editMessageEmbedsById(long messageId, @Nonnull Collection extends MessageEmbed> newEmbeds)
+ {
+ return editMessageEmbedsById(Long.toUnsignedString(messageId), newEmbeds);
+ }
+
+
@Override
default void formatTo(Formatter formatter, int flags, int width, int precision)
{
diff --git a/src/main/java/net/dv8tion/jda/api/entities/MessageEmbed.java b/src/main/java/net/dv8tion/jda/api/entities/MessageEmbed.java
index 9f5fb54851..8395cf2e90 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/MessageEmbed.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/MessageEmbed.java
@@ -352,17 +352,17 @@ public int getLength()
length = 0;
if (title != null)
- length += title.length();
+ length += Helpers.codePointLength(title);
if (description != null)
- length += description.length();
+ length += Helpers.codePointLength(description);
if (author != null)
- length += author.getName().length();
+ length += Helpers.codePointLength(author.getName());
if (footer != null)
- length += footer.getText().length();
+ length += Helpers.codePointLength(footer.getText());
if (fields != null)
{
for (Field f : fields)
- length += f.getName().length() + f.getValue().length();
+ length += Helpers.codePointLength(f.getName()) + Helpers.codePointLength(f.getValue());
}
return length;
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/InteractionHook.java b/src/main/java/net/dv8tion/jda/api/interactions/InteractionHook.java
index 815d403860..1baa27c466 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/InteractionHook.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/InteractionHook.java
@@ -32,6 +32,7 @@
import javax.annotation.Nonnull;
import java.io.File;
import java.io.InputStream;
+import java.time.temporal.ChronoUnit;
import java.util.Collection;
/**
@@ -64,6 +65,33 @@ public interface InteractionHook extends WebhookClient
@Nonnull
Interaction getInteraction();
+ /**
+ * The unix millisecond timestamp for the expiration of this interaction hook.
+ * An interaction hook expires after 15 minutes of its creation.
+ *
+ * @return The timestamp in millisecond precision
+ *
+ * @see System#currentTimeMillis()
+ * @see #isExpired()
+ */
+ default long getExpirationTimestamp()
+ {
+ return getInteraction().getTimeCreated().plus(15, ChronoUnit.MINUTES).toEpochSecond() * 1000;
+ }
+
+ /**
+ * Whether this interaction has expired.
+ * An interaction hook is only valid for 15 minutes.
+ *
+ * @return True, if this interaction hook has expired
+ *
+ * @see #getExpirationTimestamp()
+ */
+ default boolean isExpired()
+ {
+ return System.currentTimeMillis() > getExpirationTimestamp();
+ }
+
/**
* Whether messages sent from this interaction hook should be ephemeral by default.
* This does not affect message updates, including deferred replies sent with {@link #sendMessage(String) sendMessage(...)} methods.
diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/MessageAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/MessageAction.java
index 641c8560f1..72b91f1626 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/restaction/MessageAction.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/MessageAction.java
@@ -16,6 +16,9 @@
package net.dv8tion.jda.api.requests.restaction;
+import net.dv8tion.jda.annotations.DeprecatedSince;
+import net.dv8tion.jda.annotations.ForRemoval;
+import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.MessageChannel;
@@ -68,7 +71,7 @@
* MessageChannel channel = event.getChannel();
* channel.sendMessage("This has an embed with an image!")
* .addFile(new File("dog.png"))
- * .embed(new EmbedBuilder()
+ * .setEmbeds(new EmbedBuilder()
* .setImage("attachment://dog.png")
* .build())
* .queue(); // this actually sends the information to discord
@@ -79,11 +82,11 @@
*
* @see Message#editMessage(Message)
* @see Message#editMessage(CharSequence)
- * @see Message#editMessage(MessageEmbed)
+ * @see Message#editMessageEmbeds(MessageEmbed...)
* @see Message#editMessageFormat(String, Object...)
* @see net.dv8tion.jda.api.entities.MessageChannel#sendMessage(Message)
* @see net.dv8tion.jda.api.entities.MessageChannel#sendMessage(CharSequence)
- * @see net.dv8tion.jda.api.entities.MessageChannel#sendMessage(MessageEmbed)
+ * @see net.dv8tion.jda.api.entities.MessageChannel#sendMessageEmbeds(MessageEmbed, MessageEmbed...)
* @see net.dv8tion.jda.api.entities.MessageChannel#sendMessageFormat(String, Object...)
* @see net.dv8tion.jda.api.entities.MessageChannel#sendFile(File, AttachmentOption...)
* @see net.dv8tion.jda.api.entities.MessageChannel#sendFile(File, String, AttachmentOption...)
@@ -377,7 +380,7 @@ default MessageAction reference(@Nonnull Message message)
* {@link #isEmpty()} will result in {@code true} after this has been performed!
*
* Convenience over using
- * {@code content(null).nonce(null).embed(null).tts(false).override(false).clearFiles()}
+ * {@code content(null).nonce(null).setEmbeds(emptyList()).tts(false).override(false).clearFiles()}
*
* @return Updated MessageAction for chaining convenience
*/
@@ -436,11 +439,61 @@ default MessageAction reference(@Nonnull Message message)
* If the provided MessageEmbed is an unknown implementation this operation will fail as we are unable to deserialize it.
*
* @return Updated MessageAction for chaining convenience
+ *
+ * @deprecated This is deprecated in favor of {@link #setEmbeds(MessageEmbed...)}
*/
@Nonnull
@CheckReturnValue
+ @Deprecated
+ @ForRemoval(deadline="5.0.0")
+ @ReplaceWith("setEmbeds(embed)")
+ @DeprecatedSince("4.4.0")
MessageAction embed(@Nullable final MessageEmbed embed);
+ /**
+ * Sets up to 10 {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds}
+ * that should be used for this Message.
+ * Refer to {@link net.dv8tion.jda.api.EmbedBuilder EmbedBuilder} for more information.
+ *
+ * @param embeds
+ * The {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} that should
+ * be attached to this message, {@code Collections.emptyList()} to use no embed.
+ *
+ * @throws java.lang.IllegalArgumentException
+ * If any of the provided MessageEmbeds is not sendable according to
+ * {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() MessageEmbed.isSendable()}!
+ * If the provided MessageEmbed is an unknown implementation this operation will fail as we are unable to deserialize it.
+ *
+ * @return Updated MessageAction for chaining convenience
+ */
+ @Nonnull
+ @CheckReturnValue
+ MessageAction setEmbeds(@Nonnull Collection extends MessageEmbed> embeds);
+
+ /**
+ * Sets up to 10 {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds}
+ * that should be used for this Message.
+ * Refer to {@link net.dv8tion.jda.api.EmbedBuilder EmbedBuilder} for more information.
+ *
+ * @param embeds
+ * The {@link net.dv8tion.jda.api.entities.MessageEmbed MessageEmbeds} that should
+ * be attached to this message, {@code Collections.emptyList()} to use no embed.
+ *
+ * @throws java.lang.IllegalArgumentException
+ * If any of the provided MessageEmbeds is not sendable according to
+ * {@link net.dv8tion.jda.api.entities.MessageEmbed#isSendable() MessageEmbed.isSendable()}!
+ * If the provided MessageEmbed is an unknown implementation this operation will fail as we are unable to deserialize it.
+ *
+ * @return Updated MessageAction for chaining convenience
+ */
+ @Nonnull
+ @CheckReturnValue
+ default MessageAction setEmbeds(@Nonnull MessageEmbed... embeds)
+ {
+ Checks.noneNull(embeds, "MessageEmbeds");
+ return setEmbeds(Arrays.asList(embeds));
+ }
+
/**
* {@inheritDoc}
* @throws java.lang.IllegalArgumentException
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java b/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
index 744649e974..c64947c953 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/AbstractMessage.java
@@ -30,10 +30,7 @@
import java.io.IOException;
import java.io.UncheckedIOException;
import java.time.OffsetDateTime;
-import java.util.EnumSet;
-import java.util.FormattableFlags;
-import java.util.Formatter;
-import java.util.List;
+import java.util.*;
public abstract class AbstractMessage implements Message
{
@@ -387,7 +384,7 @@ public MessageAction editMessage(@Nonnull CharSequence newContent)
@Nonnull
@Override
- public MessageAction editMessage(@Nonnull MessageEmbed newContent)
+ public MessageAction editMessageEmbeds(@Nonnull Collection extends MessageEmbed> newContent)
{
unsupported();
return null;
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/DataMessage.java b/src/main/java/net/dv8tion/jda/internal/entities/DataMessage.java
index d5c3dfc17d..1147f48d7c 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/DataMessage.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/DataMessage.java
@@ -33,22 +33,22 @@ public class DataMessage extends AbstractMessage
private final String[] mentionedRoles;
private final String[] mentionedUsers;
private final ComponentLayout[] components;
- private MessageEmbed embed;
+ private Collection extends MessageEmbed> embeds;
- public DataMessage(boolean tts, String content, String nonce, MessageEmbed embed,
+ public DataMessage(boolean tts, String content, String nonce, Collection extends MessageEmbed> embeds,
EnumSet allowedMentions, String[] mentionedUsers, String[] mentionedRoles, ComponentLayout[] components)
{
super(content, nonce, tts);
- this.embed = embed;
+ this.embeds = embeds;
this.allowedMentions = allowedMentions;
this.mentionedUsers = mentionedUsers;
this.mentionedRoles = mentionedRoles;
this.components = components;
}
- public DataMessage(boolean tts, String content, String nonce, MessageEmbed embed)
+ public DataMessage(boolean tts, String content, String nonce, Collection extends MessageEmbed> embeds)
{
- this(tts, content, nonce, embed, null, new String[0], new String[0], new ComponentLayout[0]);
+ this(tts, content, nonce, embeds, null, new String[0], new String[0], new ComponentLayout[0]);
}
public EnumSet getAllowedMentions()
@@ -84,7 +84,7 @@ public boolean equals(Object o)
return isTTS == other.isTTS
&& other.content.equals(content)
&& Objects.equals(other.nonce, nonce)
- && Objects.equals(other.embed, embed);
+ && Objects.equals(other.embeds, embeds);
}
@Override
@@ -99,9 +99,9 @@ public String toString()
return String.format("DataMessage(%.30s)", getContentRaw());
}
- public DataMessage setEmbed(MessageEmbed embed)
+ public DataMessage setEmbeds(Collection extends MessageEmbed> embeds)
{
- this.embed = embed;
+ this.embeds = embeds;
return this;
}
@@ -109,7 +109,7 @@ public DataMessage setEmbed(MessageEmbed embed)
@Override
public List getEmbeds()
{
- return embed == null ? Collections.emptyList() : Collections.singletonList(embed);
+ return new ArrayList<>(embeds);
}
@Nonnull
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
index 6ed4677078..24d2766adc 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
@@ -26,10 +26,10 @@
import net.dv8tion.jda.api.audit.AuditLogChange;
import net.dv8tion.jda.api.audit.AuditLogEntry;
import net.dv8tion.jda.api.entities.*;
-import net.dv8tion.jda.api.entities.Guild.VerificationLevel;
-import net.dv8tion.jda.api.entities.Guild.NotificationLevel;
import net.dv8tion.jda.api.entities.Guild.ExplicitContentLevel;
+import net.dv8tion.jda.api.entities.Guild.NotificationLevel;
import net.dv8tion.jda.api.entities.Guild.Timeout;
+import net.dv8tion.jda.api.entities.Guild.VerificationLevel;
import net.dv8tion.jda.api.entities.MessageEmbed.*;
import net.dv8tion.jda.api.entities.templates.Template;
import net.dv8tion.jda.api.entities.templates.TemplateChannel;
@@ -1098,7 +1098,7 @@ public Message createMessage(DataObject jsonObject, boolean modifyCache)
return createMessage(jsonObject, chan, modifyCache);
}
- public Message createMessage(DataObject jsonObject, @Nullable MessageChannel channel, boolean modifyCache)
+ public ReceivedMessage createMessage(DataObject jsonObject, @Nullable MessageChannel channel, boolean modifyCache)
{
long channelId = jsonObject.getUnsignedLong("channel_id");
if (channel != null && channelId != channel.getIdLong())
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java b/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
index d9bd5cf4c0..f1113abaaf 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/ReceivedMessage.java
@@ -22,6 +22,7 @@
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.exceptions.MissingAccessException;
+import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
@@ -34,6 +35,7 @@
import net.dv8tion.jda.internal.requests.CompletedRestAction;
import net.dv8tion.jda.internal.requests.Route;
import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl;
+import net.dv8tion.jda.internal.requests.restaction.MessageActionImpl;
import net.dv8tion.jda.internal.utils.Checks;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.CollectionUtils;
@@ -72,6 +74,8 @@ public class ReceivedMessage extends AbstractMessage
protected final TLongSet mentionedRoles;
protected final int flags;
+ protected InteractionHook interactionHook = null; // late-init
+
// LAZY EVALUATED
protected String altContent = null;
protected String strippedContent = null;
@@ -112,6 +116,12 @@ public ReceivedMessage(
this.flags = flags;
}
+ public ReceivedMessage withHook(InteractionHook hook)
+ {
+ this.interactionHook = hook;
+ return this;
+ }
+
@Nonnull
@Override
public JDA getJDA()
@@ -798,15 +808,15 @@ public MessageActivity getActivity()
public MessageAction editMessage(@Nonnull CharSequence newContent)
{
checkUser();
- return channel.editMessageById(getId(), newContent);
+ return ((MessageActionImpl) channel.editMessageById(getId(), newContent)).withHook(interactionHook);
}
@Nonnull
@Override
- public MessageAction editMessage(@Nonnull MessageEmbed newContent)
+ public MessageAction editMessageEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
{
checkUser();
- return channel.editMessageById(getId(), newContent);
+ return ((MessageActionImpl) channel.editMessageEmbedsById(getId(), embeds)).withHook(interactionHook);
}
@Nonnull
@@ -814,7 +824,7 @@ public MessageAction editMessage(@Nonnull MessageEmbed newContent)
public MessageAction editMessageFormat(@Nonnull String format, @Nonnull Object... args)
{
checkUser();
- return channel.editMessageFormatById(getId(), format, args);
+ return ((MessageActionImpl) channel.editMessageFormatById(getId(), format, args)).withHook(interactionHook);
}
@Nonnull
@@ -822,7 +832,7 @@ public MessageAction editMessageFormat(@Nonnull String format, @Nonnull Object..
public MessageAction editMessage(@Nonnull Message newContent)
{
checkUser();
- return channel.editMessageById(getIdLong(), newContent);
+ return ((MessageActionImpl) channel.editMessageById(getId(), newContent)).withHook(interactionHook);
}
private void checkUser()
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/TextChannelImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/TextChannelImpl.java
index d52ca87edb..e45f783955 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/TextChannelImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/TextChannelImpl.java
@@ -585,6 +585,7 @@ public MessageAction editMessageById(@Nonnull String messageId, @Nonnull CharSeq
@Nonnull
@Override
+ @Deprecated
public MessageAction editMessageById(@Nonnull String messageId, @Nonnull MessageEmbed newEmbed)
{
checkPermission(Permission.MESSAGE_READ);
@@ -593,6 +594,16 @@ public MessageAction editMessageById(@Nonnull String messageId, @Nonnull Message
return TextChannel.super.editMessageById(messageId, newEmbed);
}
+ @Nonnull
+ @Override
+ public MessageAction editMessageEmbedsById(@Nonnull String messageId, @Nonnull Collection extends MessageEmbed> newEmbeds)
+ {
+ checkPermission(Permission.MESSAGE_READ);
+ checkPermission(Permission.MESSAGE_WRITE);
+ checkPermission(Permission.MESSAGE_EMBED_LINKS);
+ return TextChannel.super.editMessageEmbedsById(messageId, newEmbeds);
+ }
+
@Nonnull
@Override
public MessageAction editMessageById(@Nonnull String id, @Nonnull Message newContent)
diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/InteractionHookImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/InteractionHookImpl.java
index bae6d255a0..6d0a2a8315 100644
--- a/src/main/java/net/dv8tion/jda/internal/interactions/InteractionHookImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/interactions/InteractionHookImpl.java
@@ -152,7 +152,7 @@ public WebhookMessageActionImpl sendRequest()
{
Route.CompiledRoute route = Route.Interactions.CREATE_FOLLOWUP.compile(getJDA().getSelfUser().getApplicationId(), interaction.getToken());
route = route.withQueryParams("wait", "true");
- Function transform = (json) -> ((JDAImpl) api).getEntityBuilder().createMessage(json, getInteraction().getMessageChannel(), false);
+ Function transform = (json) -> ((JDAImpl) api).getEntityBuilder().createMessage(json, getInteraction().getMessageChannel(), false).withHook(this);
return onReady(new WebhookMessageActionImpl<>(getJDA(), interaction.getMessageChannel(), route, transform)).setEphemeral(ephemeral);
}
@@ -164,7 +164,7 @@ public WebhookMessageUpdateActionImpl editRequest(String messageId)
Checks.isSnowflake(messageId);
Route.CompiledRoute route = Route.Interactions.EDIT_FOLLOWUP.compile(getJDA().getSelfUser().getApplicationId(), interaction.getToken(), messageId);
route = route.withQueryParams("wait", "true");
- Function transform = (json) -> ((JDAImpl) api).getEntityBuilder().createMessage(json, getInteraction().getMessageChannel(), false);
+ Function transform = (json) -> ((JDAImpl) api).getEntityBuilder().createMessage(json, getInteraction().getMessageChannel(), false).withHook(this);
return onReady(new WebhookMessageUpdateActionImpl<>(getJDA(), route, transform));
}
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java
index 264a114a3b..4975a361d9 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/MessageActionImpl.java
@@ -21,6 +21,7 @@
import net.dv8tion.jda.api.entities.*;
import net.dv8tion.jda.api.exceptions.InsufficientPermissionException;
import net.dv8tion.jda.api.exceptions.MissingAccessException;
+import net.dv8tion.jda.api.interactions.InteractionHook;
import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.requests.Request;
import net.dv8tion.jda.api.requests.Response;
@@ -28,7 +29,6 @@
import net.dv8tion.jda.api.utils.AttachmentOption;
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.data.DataObject;
-import net.dv8tion.jda.internal.requests.Method;
import net.dv8tion.jda.internal.requests.Requester;
import net.dv8tion.jda.internal.requests.RestActionImpl;
import net.dv8tion.jda.internal.requests.Route;
@@ -61,12 +61,15 @@ public class MessageActionImpl extends RestActionImpl implements Messag
protected final AllowedMentionsImpl allowedMentions = new AllowedMentionsImpl();
protected List components;
protected List retainedAttachments;
- protected MessageEmbed embed = null;
+ protected List embeds = null;
protected String nonce = null;
protected boolean tts = false, override = false;
protected boolean failOnInvalidReply = defaultFailOnInvalidReply;
protected long messageReference;
+ protected final String messageId;
+ private InteractionHook hook = null;
+
public static void setDefaultFailOnInvalidReply(boolean fail)
{
defaultFailOnInvalidReply = fail;
@@ -77,20 +80,43 @@ public static boolean isDefaultFailOnInvalidReply()
return defaultFailOnInvalidReply;
}
- public MessageActionImpl(JDA api, Route.CompiledRoute route, MessageChannel channel)
+ public MessageActionImpl(JDA api, String messageId, MessageChannel channel)
{
- super(api, route);
+ super(api, messageId != null
+ ? Route.Messages.EDIT_MESSAGE.compile(channel.getId(), messageId)
+ : Route.Messages.SEND_MESSAGE.compile(channel.getId()));
this.content = new StringBuilder();
this.channel = channel;
+ this.messageId = messageId;
}
- public MessageActionImpl(JDA api, Route.CompiledRoute route, MessageChannel channel, StringBuilder contentBuilder)
+ public MessageActionImpl(JDA api, String messageId, MessageChannel channel, StringBuilder contentBuilder)
{
- super(api, route);
+ super(api, messageId != null
+ ? Route.Messages.EDIT_MESSAGE.compile(channel.getId(), messageId)
+ : Route.Messages.SEND_MESSAGE.compile(channel.getId()));
Checks.check(contentBuilder.length() <= Message.MAX_CONTENT_LENGTH,
"Cannot build a Message with more than %d characters. Please limit your input.", Message.MAX_CONTENT_LENGTH);
this.content = contentBuilder;
this.channel = channel;
+ this.messageId = messageId;
+ }
+
+ public MessageActionImpl withHook(InteractionHook hook)
+ {
+ this.hook = hook;
+ return this;
+ }
+
+ @Override
+ protected Route.CompiledRoute finalizeRoute()
+ {
+ if (hook == null || hook.isExpired())
+ return super.finalizeRoute(); // Try as a normal bot message
+ if (isEdit()) // Try with interaction hook if its not expired, these have different rate limits and scale better
+ return Route.Interactions.EDIT_FOLLOWUP.compile(api.getSelfUser().getApplicationId(), hook.getInteraction().getToken(), messageId);
+ else
+ return Route.Interactions.CREATE_FOLLOWUP.compile(api.getSelfUser().getApplicationId(), hook.getInteraction().getToken());
}
@Nonnull
@@ -126,13 +152,13 @@ public boolean isEmpty()
{
return !isEdit() // PATCH can be technically empty since you can update stuff like components or remove embeds etc
&& Helpers.isBlank(content)
- && (embed == null || embed.isEmpty() || !hasPermission(Permission.MESSAGE_EMBED_LINKS));
+ && (embeds == null || embeds.isEmpty() || !hasPermission(Permission.MESSAGE_EMBED_LINKS));
}
@Override
public boolean isEdit()
{
- return finalizeRoute().getMethod() == Method.PATCH;
+ return messageId != null;
}
@Nonnull
@@ -144,8 +170,8 @@ public MessageActionImpl apply(final Message message)
if (message == null || message.getType().isSystem())
return this;
final List embeds = message.getEmbeds();
- if (embeds != null && !embeds.isEmpty() && embeds.get(0).getType() == EmbedType.RICH)
- embed(embeds.get(0));
+ if (embeds != null && !embeds.isEmpty())
+ setEmbeds(embeds.stream().filter(e -> e.getType() == EmbedType.RICH).collect(Collectors.toList()));
files.clear();
components = new ArrayList<>();
@@ -165,7 +191,7 @@ public MessageActionImpl referenceById(long messageId)
@Nonnull
@Override
- public MessageAction failOnInvalidReply(boolean fail)
+ public MessageActionImpl failOnInvalidReply(boolean fail)
{
failOnInvalidReply = fail;
return this;
@@ -185,7 +211,7 @@ public MessageActionImpl tts(final boolean isTTS)
@CheckReturnValue
public MessageActionImpl reset()
{
- return content(null).nonce(null).embed(null).tts(false).override(false).clearFiles();
+ return content(null).nonce(null).setEmbeds(Collections.emptyList()).tts(false).override(false).clearFiles();
}
@Nonnull
@@ -213,6 +239,7 @@ else if (content.length() <= Message.MAX_CONTENT_LENGTH)
@Nonnull
@Override
+ @Deprecated
@CheckReturnValue
public MessageActionImpl embed(final MessageEmbed embed)
{
@@ -221,8 +248,33 @@ public MessageActionImpl embed(final MessageEmbed embed)
Checks.check(embed.isSendable(),
"Provided Message contains an empty embed or an embed with a length greater than %d characters, which is the max for bot accounts!",
MessageEmbed.EMBED_MAX_LENGTH_BOT);
+ if (this.embeds == null)
+ this.embeds = new ArrayList<>();
+ this.embeds.add(embed);
}
- this.embed = embed;
+ else
+ {
+ this.embeds = null;
+ }
+ return this;
+ }
+
+ @Nonnull
+ @Override
+ public MessageActionImpl setEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
+ {
+ Checks.noneNull(embeds, "MessageEmbeds");
+ embeds.forEach(embed ->
+ Checks.check(embed.isSendable(),
+ "Provided Message contains an empty embed or an embed with a length greater than %d characters, which is the max for bot accounts!",
+ MessageEmbed.EMBED_MAX_LENGTH_BOT)
+ );
+ Checks.check(embeds.size() <= 10, "Cannot have more than 10 embeds in a message!");
+ Checks.check(embeds.stream().mapToInt(MessageEmbed::getLength).sum() <= MessageEmbed.EMBED_MAX_LENGTH_BOT, "The sum of all MessageEmbeds may not exceed %d!", MessageEmbed.EMBED_MAX_LENGTH_BOT);
+ if (this.embeds == null)
+ this.embeds = new ArrayList<>();
+ this.embeds.clear();
+ this.embeds.addAll(embeds);
return this;
}
@@ -329,7 +381,7 @@ public MessageActionImpl clearFiles(@Nonnull Consumer finalizer)
@Nonnull
@Override
- public MessageAction retainFilesById(@Nonnull Collection ids)
+ public MessageActionImpl retainFilesById(@Nonnull Collection ids)
{
if (!isEdit()) return this; // You can't retain files for messages that don't exist lol
if (this.retainedAttachments == null)
@@ -363,7 +415,7 @@ public MessageActionImpl override(final boolean bool)
@Nonnull
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
- public MessageAction mentionRepliedUser(boolean mention)
+ public MessageActionImpl mentionRepliedUser(boolean mention)
{
allowedMentions.mentionRepliedUser(mention);
return this;
@@ -372,7 +424,7 @@ public MessageAction mentionRepliedUser(boolean mention)
@Nonnull
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
- public MessageAction allowedMentions(@Nullable Collection allowedMentions)
+ public MessageActionImpl allowedMentions(@Nullable Collection allowedMentions)
{
this.allowedMentions.allowedMentions(allowedMentions);
return this;
@@ -381,7 +433,7 @@ public MessageAction allowedMentions(@Nullable Collection a
@Nonnull
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
- public MessageAction mention(@Nonnull IMentionable... mentions)
+ public MessageActionImpl mention(@Nonnull IMentionable... mentions)
{
this.allowedMentions.mention(mentions);
return this;
@@ -390,7 +442,7 @@ public MessageAction mention(@Nonnull IMentionable... mentions)
@Nonnull
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
- public MessageAction mentionUsers(@Nonnull String... userIds)
+ public MessageActionImpl mentionUsers(@Nonnull String... userIds)
{
this.allowedMentions.mentionUsers(userIds);
return this;
@@ -399,7 +451,7 @@ public MessageAction mentionUsers(@Nonnull String... userIds)
@Nonnull
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
- public MessageAction mentionRoles(@Nonnull String... roleIds)
+ public MessageActionImpl mentionRoles(@Nonnull String... roleIds)
{
this.allowedMentions.mentionRoles(roleIds);
return this;
@@ -469,10 +521,10 @@ protected DataObject getJSON()
final DataObject obj = DataObject.empty();
if (override)
{
- if (embed == null)
- obj.putNull("embed");
+ if (embeds == null)
+ obj.putNull("embeds");
else
- obj.put("embed", embed);
+ obj.put("embeds", DataArray.fromCollection(embeds));
if (content.length() == 0)
obj.putNull("content");
else
@@ -495,8 +547,8 @@ protected DataObject getJSON()
}
else
{
- if (embed != null)
- obj.put("embed", embed);
+ if (embeds != null)
+ obj.put("embeds", DataArray.fromCollection(embeds));
if (content.length() > 0)
obj.put("content", content.toString());
if (nonce != null)
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageActionImpl.java
index 2e86ba3664..e14863edfc 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageActionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageActionImpl.java
@@ -41,6 +41,7 @@
import java.io.InputStream;
import java.util.*;
import java.util.function.Function;
+import java.util.stream.Stream;
public class WebhookMessageActionImpl
extends TriggerRestAction
@@ -128,8 +129,14 @@ public WebhookMessageActionImpl setTTS(boolean tts)
@Override
public WebhookMessageActionImpl addEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
{
- Checks.noneNull(embeds, "Message Embeds");
+ Checks.noneNull(embeds, "MessageEmbeds");
+ embeds.forEach(embed ->
+ Checks.check(embed.isSendable(),
+ "Provided Message contains an empty embed or an embed with a length greater than %d characters, which is the max for bot accounts!",
+ MessageEmbed.EMBED_MAX_LENGTH_BOT)
+ );
Checks.check(this.embeds.size() + embeds.size() <= 10, "Cannot have more than 10 embeds in a message!");
+ Checks.check(Stream.concat(embeds.stream(), this.embeds.stream()).mapToInt(MessageEmbed::getLength).sum() <= MessageEmbed.EMBED_MAX_LENGTH_BOT, "The sum of all MessageEmbeds may not exceed %d!", MessageEmbed.EMBED_MAX_LENGTH_BOT);
this.embeds.addAll(embeds);
return this;
}
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageUpdateActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageUpdateActionImpl.java
index 1e9d592d57..c6eb8d193a 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageUpdateActionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/WebhookMessageUpdateActionImpl.java
@@ -80,7 +80,13 @@ public WebhookMessageUpdateAction setContent(@Nullable String content)
public WebhookMessageUpdateAction setEmbeds(@Nonnull Collection extends MessageEmbed> embeds)
{
Checks.noneNull(embeds, "MessageEmbeds");
- Checks.check(embeds.size() <= 10, "Cannot have more than 10 embeds in one message!");
+ embeds.forEach(embed ->
+ Checks.check(embed.isSendable(),
+ "Provided Message contains an empty embed or an embed with a length greater than %d characters, which is the max for bot accounts!",
+ MessageEmbed.EMBED_MAX_LENGTH_BOT)
+ );
+ Checks.check(embeds.size() <= 10, "Cannot have more than 10 embeds in a message!");
+ Checks.check(embeds.stream().mapToInt(MessageEmbed::getLength).sum() <= MessageEmbed.EMBED_MAX_LENGTH_BOT, "The sum of all MessageEmbeds may not exceed %d!", MessageEmbed.EMBED_MAX_LENGTH_BOT);
this.embeds.clear();
this.embeds.addAll(embeds);
set |= EMBEDS;