From 122d083a5d43d64b794e102eb41167db881d26a4 Mon Sep 17 00:00:00 2001
From: freya02 <41875020+freya022@users.noreply.github.com>
Date: Fri, 1 Nov 2024 12:24:39 +0100
Subject: [PATCH 01/17] Fix links to LavaPlayer in AudioManager (#2761)
---
.../java/net/dv8tion/jda/api/managers/AudioManager.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/managers/AudioManager.java b/src/main/java/net/dv8tion/jda/api/managers/AudioManager.java
index 6016db1889..e355787f84 100644
--- a/src/main/java/net/dv8tion/jda/api/managers/AudioManager.java
+++ b/src/main/java/net/dv8tion/jda/api/managers/AudioManager.java
@@ -198,14 +198,14 @@ default void setSpeakingMode(@Nonnull SpeakingMode... mode)
/**
* Sets the {@link net.dv8tion.jda.api.audio.AudioSendHandler}
* that the manager will use to provide audio data to an audio connection.
- *
The handler provided here will persist between audio connection connect and disconnects.
+ *
The handler provided here will persist between audio connection connects and disconnects.
* Furthermore, you don't need to have an audio connection to set a handler.
- * When JDA sets up a new audio connection it will use the handler provided here.
+ * When JDA sets up a new audio connection, it will use the handler provided here.
*
Setting this to null will remove the audio handler.
*
- *
JDA recommends LavaPlayer
+ *
JDA recommends LavaPlayer
* as an {@link net.dv8tion.jda.api.audio.AudioSendHandler AudioSendHandler}.
- * It provides a demo targeted at JDA users.
+ * It provides a demo targeted at JDA users.
*
* @param handler
* The {@link net.dv8tion.jda.api.audio.AudioSendHandler AudioSendHandler} used to provide audio data.
From 8b45fc0a1cdf2b521916dce167bb2a63c8f188bf Mon Sep 17 00:00:00 2001
From: freya02 <41875020+freya022@users.noreply.github.com>
Date: Fri, 1 Nov 2024 12:25:43 +0100
Subject: [PATCH 02/17] Fix typo in RoleManager (#2757)
---
src/main/java/net/dv8tion/jda/api/managers/RoleManager.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/net/dv8tion/jda/api/managers/RoleManager.java b/src/main/java/net/dv8tion/jda/api/managers/RoleManager.java
index e89083d816..2e7f9b3bf3 100644
--- a/src/main/java/net/dv8tion/jda/api/managers/RoleManager.java
+++ b/src/main/java/net/dv8tion/jda/api/managers/RoleManager.java
@@ -135,7 +135,7 @@ default Guild getGuild()
/**
* Sets the name of the selected {@link net.dv8tion.jda.api.entities.Role Role}.
*
- *
A role name must not be {@code null} nor less than 1 characters or more than 32 characters long!
+ *
A role name must not be {@code null} nor less than 1 character or more than 100 characters long!
*
* @param name
* The new name for the selected {@link net.dv8tion.jda.api.entities.Role Role}
From e46bacb3ab6239522a9e242b885b9110f3941035 Mon Sep 17 00:00:00 2001
From: MrPowerGamerBR <9496359+MrPowerGamerBR@users.noreply.github.com>
Date: Fri, 1 Nov 2024 08:27:01 -0300
Subject: [PATCH 03/17] Fix typo in JDA#isAutoReconnect javadocs (#2758)
---
src/main/java/net/dv8tion/jda/api/JDA.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/net/dv8tion/jda/api/JDA.java b/src/main/java/net/dv8tion/jda/api/JDA.java
index f71d50dbb5..a0d9b978b5 100644
--- a/src/main/java/net/dv8tion/jda/api/JDA.java
+++ b/src/main/java/net/dv8tion/jda/api/JDA.java
@@ -1865,7 +1865,7 @@ default List getEmojisByName(@Nonnull String name, boolean igno
void setRequestTimeoutRetry(boolean retryOnTimeout);
/**
- * USed to determine whether or not autoReconnect is enabled for JDA.
+ * Used to determine whether or not autoReconnect is enabled for JDA.
*
* @return True if JDA will attempt to automatically reconnect when a connection-error is encountered.
*/
From 8ccfc564657f32553cef4abe464d334f14e4986f Mon Sep 17 00:00:00 2001
From: freya02 <41875020+freya022@users.noreply.github.com>
Date: Sun, 3 Nov 2024 14:35:53 +0100
Subject: [PATCH 04/17] Add premium buttons (#2752)
Deprecates replyWithPremiumRequired
---
.../jda/api/entities/SkuSnowflake.java | 61 ++++++
.../GenericCommandInteractionEvent.java | 1 +
...enericComponentInteractionCreateEvent.java | 1 +
.../jda/api/interactions/Interaction.java | 2 -
.../IPremiumRequiredReplyCallback.java | 13 +-
.../components/LayoutComponent.java | 6 +-
.../components/buttons/Button.java | 180 ++++++++++--------
.../components/buttons/ButtonStyle.java | 2 +
.../InteractionCallbackAction.java | 10 +-
.../PremiumRequiredCallbackAction.java | 6 +
.../internal/entities/SkuSnowflakeImpl.java | 58 ++++++
.../interactions/component/ButtonImpl.java | 65 ++++++-
.../jda/internal/utils/ComponentsUtil.java | 43 +++++
.../jda/test/interactions/ButtonTests.java | 141 ++++++++++++++
.../jda/test/util/ComponentsUtilTest.java | 48 +++++
15 files changed, 546 insertions(+), 91 deletions(-)
create mode 100644 src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java
create mode 100644 src/main/java/net/dv8tion/jda/internal/entities/SkuSnowflakeImpl.java
create mode 100644 src/main/java/net/dv8tion/jda/internal/utils/ComponentsUtil.java
create mode 100644 src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
create mode 100644 src/test/java/net/dv8tion/jda/test/util/ComponentsUtilTest.java
diff --git a/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java b/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java
new file mode 100644
index 0000000000..6cbb6191f5
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/api/entities/SkuSnowflake.java
@@ -0,0 +1,61 @@
+/*
+ * 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.entities;
+
+import net.dv8tion.jda.api.utils.MiscUtil;
+import net.dv8tion.jda.internal.entities.SkuSnowflakeImpl;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Represents an abstract SKU reference by only the SKU ID.
+ *
+ * This is used for methods which only need a SKU ID to function, you cannot use this for getting any properties.
+ */
+public interface SkuSnowflake extends ISnowflake
+{
+ /**
+ * Creates a SKU instance which only wraps an ID.
+ *
+ * @param id
+ * The SKU id
+ *
+ * @return A SKU snowflake instance
+ */
+ @Nonnull
+ static SkuSnowflake fromId(long id)
+ {
+ return new SkuSnowflakeImpl(id);
+ }
+
+ /**
+ * Creates a SKU instance which only wraps an ID.
+ *
+ * @param id
+ * The SKU id
+ *
+ * @throws IllegalArgumentException
+ * If the provided ID is not a valid snowflake
+ *
+ * @return A SKU snowflake instance
+ */
+ @Nonnull
+ static SkuSnowflake fromId(@Nonnull String id)
+ {
+ return fromId(MiscUtil.parseSnowflake(id));
+ }
+}
diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java
index b3bb9dc6d9..7a0c4ef531 100644
--- a/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/interaction/command/GenericCommandInteractionEvent.java
@@ -125,6 +125,7 @@ public ModalCallbackAction replyModal(@Nonnull Modal modal)
@Nonnull
@Override
+ @Deprecated
@CheckReturnValue
public PremiumRequiredCallbackAction replyWithPremiumRequired()
{
diff --git a/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java b/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java
index 7e766e76ef..a470852bea 100644
--- a/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/interaction/component/GenericComponentInteractionCreateEvent.java
@@ -132,6 +132,7 @@ public ModalCallbackAction replyModal(@Nonnull Modal modal)
@Nonnull
@Override
+ @Deprecated
@CheckReturnValue
public PremiumRequiredCallbackAction replyWithPremiumRequired()
{
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java b/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java
index 32fbb0d545..9f2e154d5e 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/Interaction.java
@@ -48,8 +48,6 @@
*
Which supports choice suggestions for auto-complete interactions via {@link IAutoCompleteCallback#replyChoices(Command.Choice...)}
*
{@link IModalCallback}
*
Which supports replying using a {@link Modal} via {@link IModalCallback#replyModal(Modal)}
- * {@link IPremiumRequiredReplyCallback}
- *
Which will reply stating that an {@link Entitlement Entitlement} is required
*
*
* Once the interaction is acknowledged, you can not reply with these methods again. If the interaction is a {@link IDeferrableCallback deferrable},
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java b/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java
index a25b923c94..03339af158 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/callbacks/IPremiumRequiredReplyCallback.java
@@ -16,8 +16,10 @@
package net.dv8tion.jda.api.interactions.callbacks;
-import net.dv8tion.jda.api.requests.restaction.interactions.PremiumRequiredCallbackAction;
import net.dv8tion.jda.api.entities.Entitlement;
+import net.dv8tion.jda.api.entities.SkuSnowflake;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.requests.restaction.interactions.PremiumRequiredCallbackAction;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;
@@ -28,10 +30,19 @@
*
Replying with {@link #replyWithPremiumRequired()} will automatically acknowledge this interaction.
*
*
Note:This interaction requires monetization to be enabled.
+ *
+ * @deprecated Replaced with {@link Button#premium(SkuSnowflake)},
+ * see the Discord change logs for more details.
*/
+@Deprecated
public interface IPremiumRequiredReplyCallback extends IDeferrableCallback
{
+ /**
+ * @deprecated Replaced with {@link Button#premium(SkuSnowflake)},
+ * see the Discord change logs for more details.
+ */
@Nonnull
+ @Deprecated
@CheckReturnValue
PremiumRequiredCallbackAction replyWithPremiumRequired();
}
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java b/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java
index 167c4868d6..15070e0271 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/LayoutComponent.java
@@ -20,6 +20,7 @@
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.api.utils.data.SerializableData;
import net.dv8tion.jda.internal.utils.Checks;
+import net.dv8tion.jda.internal.utils.ComponentsUtil;
import net.dv8tion.jda.internal.utils.Helpers;
import org.jetbrains.annotations.Unmodifiable;
@@ -207,7 +208,8 @@ default boolean isValid()
*
This will locate and replace the existing component with the specified ID. If you provide null it will be removed instead.
*
* @param id
- * The custom id of this component, can also be a URL for a {@link Button} with {@link ButtonStyle#LINK}
+ * The custom id of this component, can also be a URL for a {@link Button} with {@link ButtonStyle#LINK},
+ * or an SKU id for {@link ButtonStyle#PREMIUM}
* @param newComponent
* The new component or null to remove it
*
@@ -227,7 +229,7 @@ default ItemComponent updateComponent(@Nonnull String id, @Nullable ItemComponen
if (!(component instanceof ActionComponent))
continue;
ActionComponent action = (ActionComponent) component;
- if (id.equals(action.getId()) || (action instanceof Button && id.equals(((Button) action).getUrl())))
+ if (ComponentsUtil.isSameIdentifier(action, id))
{
if (newComponent == null)
it.remove();
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
index a13b6807e2..deddd28f0c 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
@@ -16,6 +16,7 @@
package net.dv8tion.jda.api.interactions.components.buttons;
+import net.dv8tion.jda.api.entities.SkuSnowflake;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.events.interaction.component.ButtonInteractionEvent;
@@ -91,7 +92,8 @@ public interface Button extends ActionComponent
int URL_MAX_LENGTH = 512;
/**
- * The visible text on the button.
+ * The visible text on the button,
+ * or an empty string if this is a {@link ButtonStyle#PREMIUM PREMIUM}-style button.
*
* @return The button label
*/
@@ -114,6 +116,14 @@ public interface Button extends ActionComponent
@Nullable
String getUrl();
+ /**
+ * The target SKU for this button, if it is a {@link ButtonStyle#PREMIUM PREMIUM}-style Button.
+ *
+ * @return The target SKU or {@code null}
+ */
+ @Nullable
+ SkuSnowflake getSku();
+
/**
* The emoji attached to this button.
*
This can be either {@link Emoji.Type#UNICODE unicode} or {@link Emoji.Type#CUSTOM custom}.
@@ -143,7 +153,7 @@ default Button asEnabled()
@CheckReturnValue
default Button withDisabled(boolean disabled)
{
- return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), disabled, getEmoji());
+ return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), getSku(), disabled, getEmoji()).checkValid();
}
/**
@@ -152,13 +162,16 @@ default Button withDisabled(boolean disabled)
* @param emoji
* The emoji to use
*
+ * @throws IllegalArgumentException
+ * If this is a {@link ButtonStyle#PREMIUM PREMIUM}-styled button
+ *
* @return New button with emoji
*/
@Nonnull
@CheckReturnValue
default Button withEmoji(@Nullable Emoji emoji)
{
- return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), isDisabled(), emoji);
+ return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), null, isDisabled(), emoji).checkValid();
}
/**
@@ -169,6 +182,7 @@ default Button withEmoji(@Nullable Emoji emoji)
*
* @throws IllegalArgumentException
*
+ * - If this is a {@link ButtonStyle#PREMIUM PREMIUM}-styled button
* - If the provided {@code label} is null or empty.
* - If the character limit for {@code label}, defined by {@link #LABEL_MAX_LENGTH} as {@value #LABEL_MAX_LENGTH},
* is exceeded.
@@ -180,9 +194,7 @@ default Button withEmoji(@Nullable Emoji emoji)
@CheckReturnValue
default Button withLabel(@Nonnull String label)
{
- Checks.notEmpty(label, "Label");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(getId(), label, getStyle(), getUrl(), isDisabled(), getEmoji());
+ return new ButtonImpl(getId(), label, getStyle(), getUrl(), getSku(), isDisabled(), getEmoji()).checkValid();
}
/**
@@ -193,6 +205,7 @@ default Button withLabel(@Nonnull String label)
*
* @throws IllegalArgumentException
*
+ * - If this is a {@link ButtonStyle#LINK LINK}-styled or {@link ButtonStyle#PREMIUM PREMIUM}-styled button
* - If the provided {@code id} is null or empty.
* - If the character limit for {@code id}, defined by {@link #ID_MAX_LENGTH} as {@value #ID_MAX_LENGTH},
* is exceeded.
@@ -204,9 +217,7 @@ default Button withLabel(@Nonnull String label)
@CheckReturnValue
default Button withId(@Nonnull String id)
{
- Checks.notEmpty(id, "ID");
- Checks.notLonger(id, ID_MAX_LENGTH, "ID");
- return new ButtonImpl(id, getLabel(), getStyle(), null, isDisabled(), getEmoji());
+ return new ButtonImpl(id, getLabel(), getStyle(), null, null, isDisabled(), getEmoji()).checkValid();
}
/**
@@ -217,6 +228,7 @@ default Button withId(@Nonnull String id)
*
* @throws IllegalArgumentException
*
+ * - If this is not a {@link ButtonStyle#LINK LINK}-styled button
* - If the provided {@code url} is null or empty.
* - If the character limit for {@code url}, defined by {@link #URL_MAX_LENGTH} as {@value #URL_MAX_LENGTH},
* is exceeded.
@@ -228,9 +240,25 @@ default Button withId(@Nonnull String id)
@CheckReturnValue
default Button withUrl(@Nonnull String url)
{
- Checks.notEmpty(url, "URL");
- Checks.notLonger(url, URL_MAX_LENGTH, "URL");
- return new ButtonImpl(null, getLabel(), ButtonStyle.LINK, url, isDisabled(), getEmoji());
+ return new ButtonImpl(null, getLabel(), getStyle(), url, null, isDisabled(), getEmoji()).checkValid();
+ }
+
+ /**
+ * Returns a copy of this button with the provided SKU.
+ *
+ * @param sku
+ * The SKU to use
+ *
+ * @throws IllegalArgumentException
+ * If the provided {@code sku} is null, or if the button is not a {@link ButtonStyle#PREMIUM PREMIUM} button
+ *
+ * @return New button with the changed url
+ */
+ @Nonnull
+ @CheckReturnValue
+ default Button withSku(@Nonnull SkuSnowflake sku)
+ {
+ return new ButtonImpl(null, "", getStyle(), null, sku, isDisabled(), null).checkValid();
}
/**
@@ -244,7 +272,7 @@ default Button withUrl(@Nonnull String url)
* @throws IllegalArgumentException
*
* - If the provided {@code style} is null.
- * - If the provided {@code style} tries to change whether this button is a {@link ButtonStyle#LINK LINK} button.
+ * - If the provided {@code style} tries to change whether this button is a {@link ButtonStyle#LINK LINK} or {@link ButtonStyle#PREMIUM PREMIUM} button.
*
*
* @return New button with the changed style
@@ -259,7 +287,11 @@ default Button withStyle(@Nonnull ButtonStyle style)
throw new IllegalArgumentException("You cannot change a link button to another style!");
if (getStyle() != ButtonStyle.LINK && style == ButtonStyle.LINK)
throw new IllegalArgumentException("You cannot change a styled button to a link button!");
- return new ButtonImpl(getId(), getLabel(), style, getUrl(), isDisabled(), getEmoji());
+ if (getStyle() == ButtonStyle.PREMIUM && style != ButtonStyle.PREMIUM)
+ throw new IllegalArgumentException("You cannot change a premium button to another style!");
+ if (getStyle() != ButtonStyle.PREMIUM && style == ButtonStyle.PREMIUM)
+ throw new IllegalArgumentException("You cannot change a styled button to a premium button!");
+ return new ButtonImpl(getId(), getLabel(), style, getUrl(), getSku(), isDisabled(), getEmoji()).checkValid();
}
/**
@@ -286,11 +318,7 @@ default Button withStyle(@Nonnull ButtonStyle style)
@Nonnull
static Button primary(@Nonnull String id, @Nonnull String label)
{
- Checks.notEmpty(id, "Id");
- Checks.notEmpty(label, "Label");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(id, label, ButtonStyle.PRIMARY, false, null);
+ return new ButtonImpl(id, label, ButtonStyle.PRIMARY, false, null).checkValid();
}
/**
@@ -317,10 +345,7 @@ static Button primary(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button primary(@Nonnull String id, @Nonnull Emoji emoji)
{
- Checks.notEmpty(id, "Id");
- Checks.notNull(emoji, "Emoji");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(id, "", ButtonStyle.PRIMARY, false, emoji);
+ return new ButtonImpl(id, "", ButtonStyle.PRIMARY, false, emoji).checkValid();
}
/**
@@ -347,11 +372,7 @@ static Button primary(@Nonnull String id, @Nonnull Emoji emoji)
@Nonnull
static Button secondary(@Nonnull String id, @Nonnull String label)
{
- Checks.notEmpty(id, "Id");
- Checks.notEmpty(label, "Label");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(id, label, ButtonStyle.SECONDARY, false, null);
+ return new ButtonImpl(id, label, ButtonStyle.SECONDARY, false, null).checkValid();
}
/**
@@ -378,10 +399,7 @@ static Button secondary(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button secondary(@Nonnull String id, @Nonnull Emoji emoji)
{
- Checks.notEmpty(id, "Id");
- Checks.notNull(emoji, "Emoji");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(id, "", ButtonStyle.SECONDARY, false, emoji);
+ return new ButtonImpl(id, "", ButtonStyle.SECONDARY, false, emoji).checkValid();
}
/**
@@ -408,11 +426,7 @@ static Button secondary(@Nonnull String id, @Nonnull Emoji emoji)
@Nonnull
static Button success(@Nonnull String id, @Nonnull String label)
{
- Checks.notEmpty(id, "Id");
- Checks.notEmpty(label, "Label");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(id, label, ButtonStyle.SUCCESS, false, null);
+ return new ButtonImpl(id, label, ButtonStyle.SUCCESS, false, null).checkValid();
}
/**
@@ -439,10 +453,7 @@ static Button success(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button success(@Nonnull String id, @Nonnull Emoji emoji)
{
- Checks.notEmpty(id, "Id");
- Checks.notNull(emoji, "Emoji");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(id, "", ButtonStyle.SUCCESS, false, emoji);
+ return new ButtonImpl(id, "", ButtonStyle.SUCCESS, false, emoji).checkValid();
}
/**
@@ -469,11 +480,7 @@ static Button success(@Nonnull String id, @Nonnull Emoji emoji)
@Nonnull
static Button danger(@Nonnull String id, @Nonnull String label)
{
- Checks.notEmpty(id, "Id");
- Checks.notEmpty(label, "Label");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(id, label, ButtonStyle.DANGER, false, null);
+ return new ButtonImpl(id, label, ButtonStyle.DANGER, false, null).checkValid();
}
/**
@@ -500,10 +507,7 @@ static Button danger(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button danger(@Nonnull String id, @Nonnull Emoji emoji)
{
- Checks.notEmpty(id, "Id");
- Checks.notNull(emoji, "Emoji");
- Checks.notLonger(id, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(id, "", ButtonStyle.DANGER, false, emoji);
+ return new ButtonImpl(id, "", ButtonStyle.DANGER, false, emoji).checkValid();
}
/**
@@ -533,11 +537,7 @@ static Button danger(@Nonnull String id, @Nonnull Emoji emoji)
@Nonnull
static Button link(@Nonnull String url, @Nonnull String label)
{
- Checks.notEmpty(url, "URL");
- Checks.notEmpty(label, "Label");
- Checks.notLonger(url, URL_MAX_LENGTH, "URL");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- return new ButtonImpl(null, label, ButtonStyle.LINK, url, false, null);
+ return new ButtonImpl(null, label, ButtonStyle.LINK, url, null, false, null).checkValid();
}
/**
@@ -567,10 +567,29 @@ static Button link(@Nonnull String url, @Nonnull String label)
@Nonnull
static Button link(@Nonnull String url, @Nonnull Emoji emoji)
{
- Checks.notEmpty(url, "URL");
- Checks.notNull(emoji, "Emoji");
- Checks.notLonger(url, URL_MAX_LENGTH, "URL");
- return new ButtonImpl(null, "", ButtonStyle.LINK, url, false, emoji);
+ return new ButtonImpl(null, "", ButtonStyle.LINK, url, null, false, emoji).checkValid();
+ }
+
+ /**
+ * Creates a button with {@link ButtonStyle#PREMIUM PREMIUM} Style.
+ *
The button is enabled by default, and cannot have emojis attached to it.
+ * You can use {@link #asDisabled()} to further configure it.
+ *
+ * Note that premium buttons never send a {@link ButtonInteractionEvent ButtonInteractionEvent}.
+ * These buttons only open a modal about the SKU.
+ *
+ * @param sku
+ * The target SKU for this button
+ *
+ * @throws IllegalArgumentException
+ * If the provided SKU is {@code null}
+ *
+ * @return The button instance
+ */
+ @Nonnull
+ static Button premium(@Nonnull SkuSnowflake sku)
+ {
+ return new ButtonImpl(null, "", ButtonStyle.PREMIUM, null, sku, false, null).checkValid();
}
/**
@@ -578,6 +597,8 @@ static Button link(@Nonnull String url, @Nonnull Emoji emoji)
*
The button is enabled and has no emoji attached by default.
* You can use {@link #asDisabled()} and {@link #withEmoji(Emoji)} to further configure it.
*
+ *
This does not support premium buttons, use {@link #of(ButtonStyle, String, String, Emoji)} instead.
+ *
*
See {@link #link(String, String)} or {@link #primary(String, String)} for more details.
*
* @param style
@@ -590,6 +611,7 @@ static Button link(@Nonnull String url, @Nonnull Emoji emoji)
* @throws IllegalArgumentException
*
* - If any provided argument is null or empty.
+ * - If the requested style is {@link ButtonStyle#PREMIUM PREMIUM}.
* - If the id is longer than {@value #ID_MAX_LENGTH}, as defined by {@link #ID_MAX_LENGTH}.
* - If the url is longer than {@value #URL_MAX_LENGTH}, as defined by {@link #URL_MAX_LENGTH}.
* - If the character limit for {@code label}, defined by {@link #LABEL_MAX_LENGTH} as {@value #LABEL_MAX_LENGTH},
@@ -601,15 +623,10 @@ static Button link(@Nonnull String url, @Nonnull Emoji emoji)
@Nonnull
static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull String label)
{
- Checks.check(style != ButtonStyle.UNKNOWN, "Cannot make button with unknown style!");
- Checks.notNull(style, "Style");
- Checks.notNull(label, "Label");
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
+ Checks.check(style != ButtonStyle.PREMIUM, "Premium buttons don't support labels");
if (style == ButtonStyle.LINK)
return link(idOrUrl, label);
- Checks.notEmpty(idOrUrl, "Id");
- Checks.notLonger(idOrUrl, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(idOrUrl, label, style, false, null);
+ return new ButtonImpl(idOrUrl, label, style, false, null).checkValid();
}
/**
@@ -617,6 +634,8 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull S
*
The button is enabled and has no text label.
* To use labels you can use {@code of(style, idOrUrl, label).withEmoji(emoji)}
*
+ * This does not support premium buttons, use {@link #of(ButtonStyle, String, String, Emoji)} instead.
+ *
*
See {@link #link(String, Emoji)} or {@link #primary(String, Emoji)} for more details.
*
* @param style
@@ -629,6 +648,7 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull S
* @throws IllegalArgumentException
*
* - If any provided argument is null or empty.
+ * - If the requested style is {@link ButtonStyle#PREMIUM PREMIUM}.
* - If the id is longer than {@value #ID_MAX_LENGTH}, as defined by {@link #ID_MAX_LENGTH}.
* - If the url is longer than {@value #URL_MAX_LENGTH}, as defined by {@link #URL_MAX_LENGTH}.
*
@@ -638,14 +658,10 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull S
@Nonnull
static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull Emoji emoji)
{
- Checks.check(style != ButtonStyle.UNKNOWN, "Cannot make button with unknown style!");
- Checks.notNull(style, "Style");
- Checks.notNull(emoji, "Emoji");
+ Checks.check(style != ButtonStyle.PREMIUM, "Premium buttons don't support emojis");
if (style == ButtonStyle.LINK)
return link(idOrUrl, emoji);
- Checks.notEmpty(idOrUrl, "Id");
- Checks.notLonger(idOrUrl, ID_MAX_LENGTH, "Id");
- return new ButtonImpl(idOrUrl, "", style, false, emoji);
+ return new ButtonImpl(idOrUrl, "", style, false, emoji).checkValid();
}
/**
@@ -653,12 +669,13 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull E
*
* You can use {@link #asDisabled()} to disable it.
*
- *
See {@link #link(String, String)} or {@link #primary(String, String)} for more details.
+ *
See {@link #link(String, String)}, {@link #premium(SkuSnowflake)}
+ * or {@link #primary(String, String)} for more details.
*
* @param style
* The button style
- * @param idOrUrl
- * Either the ID or URL for this button
+ * @param idOrUrlOrSku
+ * Either the ID, URL, or SKU for this button
* @param label
* The text to display on the button
* @param emoji
@@ -672,17 +689,18 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull E
* or you provide an ID that is null, empty or longer than {@value #ID_MAX_LENGTH} characters, as defined by {@link #ID_MAX_LENGTH}.
* - The {@code label} is non-null and longer than {@value #LABEL_MAX_LENGTH} characters, as defined by {@link #LABEL_MAX_LENGTH}.
* - The {@code label} is null/empty, and the {@code emoji} is also null.
+ * - A label or emoji was provided for a {@link ButtonStyle#PREMIUM PREMIUM}-style button
*
*
* @return The button instance
*/
@Nonnull
- static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nullable String label, @Nullable Emoji emoji)
+ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrlOrSku, @Nullable String label, @Nullable Emoji emoji)
{
- if (label != null)
- return of(style, idOrUrl, label).withEmoji(emoji);
- else if (emoji != null)
- return of(style, idOrUrl, emoji);
- throw new IllegalArgumentException("Cannot build a button without a label and emoji. At least one has to be provided as non-null.");
+ if (style == ButtonStyle.LINK)
+ return new ButtonImpl(null, label, style, idOrUrlOrSku, null, false, emoji).checkValid();
+ if (style == ButtonStyle.PREMIUM)
+ return new ButtonImpl(null, label, style, null, SkuSnowflake.fromId(idOrUrlOrSku), false, emoji).checkValid();
+ return new ButtonImpl(idOrUrlOrSku, label, style, null, null, false, emoji).checkValid();
}
}
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/ButtonStyle.java b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/ButtonStyle.java
index af228c73a6..9c06760906 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/ButtonStyle.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/ButtonStyle.java
@@ -40,6 +40,8 @@ public enum ButtonStyle
DANGER(4),
/** Link button style, usually in gray and has a link attached */
LINK(5),
+ /** Premium button style, usually in blurple and has a SKU attached */
+ PREMIUM(6),
;
private final int key;
diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/InteractionCallbackAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/InteractionCallbackAction.java
index 90d3b045bc..10c3363a8c 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/InteractionCallbackAction.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/InteractionCallbackAction.java
@@ -16,6 +16,8 @@
package net.dv8tion.jda.api.requests.restaction.interactions;
+import net.dv8tion.jda.api.entities.SkuSnowflake;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.RestAction;
import javax.annotation.CheckReturnValue;
@@ -55,7 +57,13 @@ enum ResponseType
COMMAND_AUTOCOMPLETE_CHOICES(8),
/** Respond with a modal */
MODAL(9),
- /** Respond with the "Premium required" default Discord message for premium App subscriptions **/
+ /**
+ * Respond with the "Premium required" default Discord message for premium App subscriptions
+ *
+ * @deprecated Replaced with {@link Button#premium(SkuSnowflake)},
+ * see the Discord change logs for more details.
+ */
+ @Deprecated
PREMIUM_REQUIRED(10),
;
private final int raw;
diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/PremiumRequiredCallbackAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/PremiumRequiredCallbackAction.java
index 4d2031865a..b882845c57 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/PremiumRequiredCallbackAction.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/interactions/PremiumRequiredCallbackAction.java
@@ -16,13 +16,19 @@
package net.dv8tion.jda.api.requests.restaction.interactions;
+import net.dv8tion.jda.api.entities.SkuSnowflake;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.requests.FluentRestAction;
/**
* An {@link InteractionCallbackAction} that can be used to send the "Premium required" interaction response.
*
* @see net.dv8tion.jda.api.interactions.callbacks.IPremiumRequiredReplyCallback
+ *
+ * @deprecated Replaced with {@link Button#premium(SkuSnowflake)}
+ * see the Discord change logs for more details.
*/
+@Deprecated
public interface PremiumRequiredCallbackAction extends InteractionCallbackAction, FluentRestAction
{
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/SkuSnowflakeImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/SkuSnowflakeImpl.java
new file mode 100644
index 0000000000..29ec08137f
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/entities/SkuSnowflakeImpl.java
@@ -0,0 +1,58 @@
+/*
+ * 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.entities;
+
+import net.dv8tion.jda.api.entities.SkuSnowflake;
+import net.dv8tion.jda.internal.utils.EntityString;
+
+public class SkuSnowflakeImpl implements SkuSnowflake
+{
+ protected final long id;
+
+ public SkuSnowflakeImpl(long id)
+ {
+ this.id = id;
+ }
+
+ @Override
+ public long getIdLong()
+ {
+ return this.id;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Long.hashCode(id);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof SkuSnowflakeImpl))
+ return false;
+ return ((SkuSnowflakeImpl) obj).getIdLong() == this.id;
+ }
+
+ @Override
+ public String toString()
+ {
+ return new EntityString(this).toString();
+ }
+}
diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
index 9a662de280..c2d81caa94 100644
--- a/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
@@ -16,12 +16,14 @@
package net.dv8tion.jda.internal.interactions.component;
+import net.dv8tion.jda.api.entities.SkuSnowflake;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.entities.EntityBuilder;
+import net.dv8tion.jda.internal.utils.Checks;
import net.dv8tion.jda.internal.utils.EntityString;
import javax.annotation.Nonnull;
@@ -34,6 +36,7 @@ public class ButtonImpl implements Button
private final String label;
private final ButtonStyle style;
private final String url;
+ private final SkuSnowflake sku;
private final boolean disabled;
private final EmojiUnion emoji;
@@ -44,25 +47,69 @@ public ButtonImpl(DataObject data)
data.getString("label", ""),
ButtonStyle.fromKey(data.getInt("style")),
data.getString("url", null),
+ data.hasKey("sku_id") ? SkuSnowflake.fromId(data.getLong("sku_id")) : null,
data.getBoolean("disabled"),
data.optObject("emoji").map(EntityBuilder::createEmoji).orElse(null));
}
public ButtonImpl(String id, String label, ButtonStyle style, boolean disabled, Emoji emoji)
{
- this(id, label, style, null, disabled, emoji);
+ this(id, label, style, null, null, disabled, emoji);
}
- public ButtonImpl(String id, String label, ButtonStyle style, String url, boolean disabled, Emoji emoji)
+ public ButtonImpl(String id, String label, ButtonStyle style, String url, SkuSnowflake sku, boolean disabled, Emoji emoji)
{
this.id = id;
this.label = label;
this.style = style;
this.url = url; // max length 512
+ this.sku = sku;
this.disabled = disabled;
this.emoji = (EmojiUnion) emoji;
}
+ public ButtonImpl checkValid()
+ {
+ Checks.notNull(style, "Style");
+ Checks.check(style != ButtonStyle.UNKNOWN, "Cannot make button with unknown style!");
+
+ switch (style)
+ {
+ case PRIMARY:
+ case SECONDARY:
+ case SUCCESS:
+ case DANGER:
+ Checks.check(url == null, "Cannot set an URL on action buttons");
+ Checks.check(sku == null, "Cannot set an SKU on action buttons");
+ Checks.check(emoji != null || (label != null && !label.isEmpty()), "Action buttons must have either an emoji or label");
+ Checks.notEmpty(id, "Id");
+ Checks.notLonger(id, ID_MAX_LENGTH, "Id");
+ break;
+ case LINK:
+ Checks.check(id == null, "Cannot set an ID on link buttons");
+ Checks.check(url != null, "You must set an URL on link buttons");
+ Checks.check(sku == null, "Cannot set an SKU on link buttons");
+ Checks.check(emoji != null || (label != null && !label.isEmpty()), "Link buttons must have either an emoji or label");
+ Checks.notEmpty(url, "URL");
+ Checks.notLonger(url, URL_MAX_LENGTH, "URL");
+ break;
+ case PREMIUM:
+ Checks.check(id == null, "Cannot set an ID on premium buttons");
+ Checks.check(url == null, "Cannot set an URL on premium buttons");
+ Checks.check(emoji == null, "Cannot set an emoji on premium buttons");
+ Checks.check(label == null || label.isEmpty(), "Cannot set a label on premium buttons");
+ Checks.notNull(sku, "SKU");
+ break;
+ }
+
+ if (label != null)
+ {
+ Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
+ }
+
+ return this;
+ }
+
@Nonnull
@Override
public Type getType()
@@ -98,6 +145,13 @@ public String getUrl()
return url;
}
+ @Nullable
+ @Override
+ public SkuSnowflake getSku()
+ {
+ return sku;
+ }
+
@Nullable
@Override
public EmojiUnion getEmoji()
@@ -117,15 +171,18 @@ public DataObject toData()
{
DataObject json = DataObject.empty();
json.put("type", 2);
- json.put("label", label);
+ if (!label.isEmpty())
+ json.put("label", label);
json.put("style", style.getKey());
json.put("disabled", disabled);
if (emoji != null)
json.put("emoji", emoji);
if (url != null)
json.put("url", url);
- else
+ else if (id != null)
json.put("custom_id", id);
+ else
+ json.put("sku_id", sku.getId());
return json;
}
diff --git a/src/main/java/net/dv8tion/jda/internal/utils/ComponentsUtil.java b/src/main/java/net/dv8tion/jda/internal/utils/ComponentsUtil.java
new file mode 100644
index 0000000000..6c24bd34b4
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/utils/ComponentsUtil.java
@@ -0,0 +1,43 @@
+/*
+ * 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.utils;
+
+import net.dv8tion.jda.api.interactions.components.ActionComponent;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+
+import javax.annotation.Nonnull;
+
+public class ComponentsUtil
+{
+ /** Checks whether the provided component has the {@code identifier} as its custom id, url or SKU id */
+ public static boolean isSameIdentifier(@Nonnull ActionComponent component, @Nonnull String identifier)
+ {
+ if (identifier.equals(component.getId()))
+ return true;
+
+ if (component instanceof Button)
+ {
+ final Button button = (Button) component;
+ if (identifier.equals(button.getUrl()))
+ return true;
+ if (button.getSku() != null)
+ return identifier.equals(button.getSku().getId());
+ }
+
+ return false;
+ }
+}
diff --git a/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
new file mode 100644
index 0000000000..e45fce90fe
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
@@ -0,0 +1,141 @@
+package net.dv8tion.jda.test.interactions;
+
+import net.dv8tion.jda.api.entities.SkuSnowflake;
+import net.dv8tion.jda.api.entities.emoji.Emoji;
+import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji;
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import net.dv8tion.jda.internal.interactions.component.ButtonImpl;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle.*;
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class ButtonTests
+{
+ private static final String EXAMPLE_ID = "id";
+ private static final String EXAMPLE_URL = "https://example.com";
+ private static final UnicodeEmoji EXAMPLE_EMOJI = Emoji.fromUnicode("🤔");
+ private static final String EXAMPLE_LABEL = "Label";
+ private static final SkuSnowflake EXAMPLE_SKU = SkuSnowflake.fromId(1234);
+
+ @MethodSource("testButtonValid")
+ @ParameterizedTest
+ void testButtonValid(ButtonStyle style, String id, String label, String url, SkuSnowflake sku, Emoji emoji)
+ {
+ ButtonImpl button = new ButtonImpl(id, label, style, url, sku, false, emoji);
+ assertDoesNotThrow(button::checkValid);
+ }
+
+ static Stream testButtonValid()
+ {
+ // The following button configurations are valid:
+ return Stream.of(
+ // Normal button; id, either label, emoji, label+emoji
+ Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, null, null),
+ Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, null, EXAMPLE_EMOJI),
+ Arguments.of(PRIMARY, "id", "", null, null, EXAMPLE_EMOJI),
+ // Link button; url, either label, emoji, label+emoji
+ Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, EXAMPLE_EMOJI),
+ Arguments.of(LINK, null, "", EXAMPLE_URL, null, EXAMPLE_EMOJI),
+ // Premium button doesn't have anything
+ Arguments.of(PREMIUM, null, "", null, EXAMPLE_SKU, null)
+ );
+ }
+
+ @MethodSource("testButtonInvalid")
+ @ParameterizedTest
+ void testButtonInvalid(ButtonStyle style, String id, String label, String url, SkuSnowflake sku, Emoji emoji)
+ {
+ ButtonImpl button = new ButtonImpl(id, label, style, url, sku, false, emoji);
+ assertThatIllegalArgumentException().isThrownBy(button::checkValid);
+ }
+
+ static Stream testButtonInvalid()
+ {
+ // The following button configuration will fail when:
+ return Stream.of(
+ // Normal button; has no id, has neither label/emoji, has url, has sku
+ Arguments.of(PRIMARY, null, EXAMPLE_LABEL, null, null, null),
+ Arguments.of(PRIMARY, "id", "", null, null, null),
+ Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
+ // Link button; has no url, has id, has sku
+ Arguments.of(LINK, null, EXAMPLE_LABEL, null, null, null),
+ Arguments.of(LINK, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, EXAMPLE_SKU, null),
+ // Premium button; has no sku, has id, has url, has label, has emoji
+ Arguments.of(PREMIUM, null, "", null, null, null),
+ Arguments.of(PREMIUM, "id", "", null, EXAMPLE_SKU, null),
+ Arguments.of(PREMIUM, null, "", "url", EXAMPLE_SKU, null),
+ Arguments.of(PREMIUM, null, EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
+ Arguments.of(PREMIUM, null, "", null, EXAMPLE_SKU, EXAMPLE_EMOJI)
+ );
+ }
+
+ @Test
+ void testPrimaryWithSku()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.primary("id", EXAMPLE_LABEL).withSku(EXAMPLE_SKU));
+ }
+
+ @Test
+ void testPrimaryWithUrl()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.primary("id", EXAMPLE_LABEL).withUrl(EXAMPLE_URL));
+ }
+
+ @Test
+ void linkWithId()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.link(EXAMPLE_URL, EXAMPLE_LABEL).withId(EXAMPLE_ID));
+ }
+
+ @Test
+ void linkWithSku()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.link(EXAMPLE_URL, EXAMPLE_LABEL).withSku(EXAMPLE_SKU));
+ }
+
+ @Test
+ void testPremiumWithId()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withLabel(EXAMPLE_ID));
+ }
+
+ @Test
+ void testPremiumWithLabel()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withLabel(EXAMPLE_LABEL));
+ }
+
+
+ @Test
+ void testPremiumWithEmoji()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withEmoji(EXAMPLE_EMOJI));
+ }
+
+
+ @Test
+ void testPremiumWithUrl()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withUrl(EXAMPLE_URL));
+ }
+}
diff --git a/src/test/java/net/dv8tion/jda/test/util/ComponentsUtilTest.java b/src/test/java/net/dv8tion/jda/test/util/ComponentsUtilTest.java
new file mode 100644
index 0000000000..534e648229
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/util/ComponentsUtilTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.test.util;
+
+import net.dv8tion.jda.api.interactions.components.buttons.Button;
+import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
+import net.dv8tion.jda.internal.utils.ComponentsUtil;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ComponentsUtilTest
+{
+ @MethodSource("testCustomId")
+ @ParameterizedTest
+ void testCustomId(String customId, ButtonStyle style, String label, boolean expected)
+ {
+ final Button button = Button.of(style, customId, label, null);
+ assertThat(ComponentsUtil.isSameIdentifier(button, "id")).isEqualTo(expected);
+ }
+
+ static Stream testCustomId()
+ {
+ return Stream.of(
+ Arguments.of("id", ButtonStyle.PRIMARY, "Label", true),
+ Arguments.of("http://localhost:8080", ButtonStyle.LINK, "Label", false),
+ Arguments.of("1234", ButtonStyle.PREMIUM, "", false)
+ );
+ }
+}
From 52c69c95cb97d2c3f4094006eccddbe644543bbb Mon Sep 17 00:00:00 2001
From: Jonas <46222147+yoyosource@users.noreply.github.com>
Date: Sun, 3 Nov 2024 15:11:37 +0100
Subject: [PATCH 05/17] Add support for Application Emoji (#2726)
---
src/main/java/net/dv8tion/jda/api/JDA.java | 60 ++++++
.../api/entities/emoji/ApplicationEmoji.java | 84 ++++++++
.../jda/api/entities/emoji/CustomEmoji.java | 2 +
.../dv8tion/jda/api/entities/emoji/Emoji.java | 3 +-
.../jda/api/entities/emoji/EmojiUnion.java | 25 ++-
.../api/managers/ApplicationEmojiManager.java | 105 ++++++++++
.../net/dv8tion/jda/api/requests/Route.java | 5 +
.../net/dv8tion/jda/internal/JDAImpl.java | 58 ++++++
.../jda/internal/entities/EntityBuilder.java | 10 +
.../jda/internal/entities/GuildImpl.java | 3 +-
.../entities/emoji/ApplicationEmojiImpl.java | 195 ++++++++++++++++++
.../entities/emoji/CustomEmojiImpl.java | 16 ++
.../entities/emoji/RichCustomEmojiImpl.java | 15 ++
.../entities/emoji/UnicodeEmojiImpl.java | 16 ++
.../managers/ApplicationEmojiManagerImpl.java | 90 ++++++++
.../CreateApplicationEmojiTest.java | 95 +++++++++
16 files changed, 779 insertions(+), 3 deletions(-)
create mode 100644 src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
create mode 100644 src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
create mode 100644 src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
create mode 100644 src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
create mode 100644 src/test/java/net/dv8tion/jda/test/restaction/CreateApplicationEmojiTest.java
diff --git a/src/main/java/net/dv8tion/jda/api/JDA.java b/src/main/java/net/dv8tion/jda/api/JDA.java
index a0d9b978b5..7f50e3b45c 100644
--- a/src/main/java/net/dv8tion/jda/api/JDA.java
+++ b/src/main/java/net/dv8tion/jda/api/JDA.java
@@ -23,6 +23,8 @@
import net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.sticker.*;
import net.dv8tion.jda.api.events.GenericEvent;
@@ -1750,6 +1752,64 @@ default List getEmojisByName(@Nonnull String name, boolean igno
return getEmojiCache().getElementsByName(name, ignoreCase);
}
+ /**
+ * Creates a new {@link ApplicationEmoji} for this bot.
+ *
+ * Note that the bot is limited to {@value ApplicationEmoji#APPLICATION_EMOJI_CAP} Application Emojis (normal and animated).
+ *
+ * @param name
+ * The name for the new emoji (2-{@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters)
+ * @param icon
+ * The {@link Icon} for the new emoji
+ *
+ * @throws IllegalArgumentException
+ * If null is provided or the name is not alphanumeric or not between 2 and {@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters long
+ *
+ * @return {@link RestAction} - Type: {@link ApplicationEmoji}
+ */
+ @Nonnull
+ @CheckReturnValue
+ RestAction createApplicationEmoji(@Nonnull String name, @Nonnull Icon icon);
+
+ /**
+ * Retrieves a list of Application Emojis together with their respective creators.
+ *
+ * @return {@link RestAction RestAction} - Type: List of {@link ApplicationEmoji}
+ */
+ @Nonnull
+ @CheckReturnValue
+ RestAction> retrieveApplicationEmojis();
+
+ /**
+ * Retrieves an application emoji together with its respective creator.
+ *
+ * @param emojiId
+ * The emoji id
+ *
+ * @return {@link RestAction RestAction} - Type: {@link ApplicationEmoji}
+ */
+ @Nonnull
+ @CheckReturnValue
+ default RestAction retrieveApplicationEmojiById(long emojiId)
+ {
+ return retrieveApplicationEmojiById(Long.toUnsignedString(emojiId));
+ }
+
+ /**
+ * Retrieves an application emoji together with its respective creator.
+ *
+ * @param emojiId
+ * The emoji id
+ *
+ * @throws IllegalArgumentException
+ * If the provided id is not a valid snowflake
+ *
+ * @return {@link RestAction RestAction} - Type: {@link ApplicationEmoji}
+ */
+ @Nonnull
+ @CheckReturnValue
+ RestAction retrieveApplicationEmojiById(@Nonnull String emojiId);
+
/**
* Attempts to retrieve a {@link Sticker} object based on the provided snowflake reference.
*
This works for both {@link StandardSticker} and {@link GuildSticker}, and you can resolve them using the provided {@link StickerUnion}.
diff --git a/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java b/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
new file mode 100644
index 0000000000..1b00e8c4fa
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2024 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.entities.emoji;
+
+import net.dv8tion.jda.api.JDA;
+import net.dv8tion.jda.api.entities.Icon;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.managers.ApplicationEmojiManager;
+import net.dv8tion.jda.api.requests.RestAction;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Represents a Custom Emoji hosted on the Bot Account.
+ *
+ * This does not represent unicode emojis like they are used in the official client!
+ * The format {@code :smiley:} is a client-side alias which is replaced by the unicode emoji, not a custom emoji.
+ *
+ * @see JDA#createApplicationEmoji(String, Icon)
+ * @see JDA#retrieveApplicationEmojiById(long)
+ * @see JDA#retrieveApplicationEmojis()
+ */
+public interface ApplicationEmoji extends CustomEmoji
+{
+ int APPLICATION_EMOJI_CAP = 2000;
+
+ /**
+ * The {@link net.dv8tion.jda.api.JDA JDA} instance of this emoji
+ *
+ * @return The JDA instance of this emoji
+ */
+ @Nonnull
+ JDA getJDA();
+
+ /**
+ * The user who created this emoji
+ *
+ * @return The user who created this emoji
+ */
+ @Nullable
+ User getOwner();
+
+ /**
+ * Deletes this emoji.
+ *
+ *
Possible ErrorResponses include:
+ *
+ * - {@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_EMOJI UNKNOWN_EMOJI}
+ *
If this emoji was already removed
+ *
+ *
+ * @return {@link net.dv8tion.jda.api.requests.RestAction RestAction}
+ * The RestAction to delete this emoji.
+ */
+ @Nonnull
+ @CheckReturnValue
+ RestAction delete();
+
+ /**
+ * The {@link ApplicationEmojiManager Manager} for this emoji, used to modify
+ * properties of the emoji like name.
+ *
+ * @return The ApplicationEmojiManager for this emoji
+ */
+ @Nonnull
+ @CheckReturnValue
+ ApplicationEmojiManager getManager();
+}
diff --git a/src/main/java/net/dv8tion/jda/api/entities/emoji/CustomEmoji.java b/src/main/java/net/dv8tion/jda/api/entities/emoji/CustomEmoji.java
index 3b4a7abc36..b3e1183d0f 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/emoji/CustomEmoji.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/emoji/CustomEmoji.java
@@ -38,6 +38,8 @@
*/
public interface CustomEmoji extends Emoji, IMentionable
{
+ int EMOJI_NAME_MAX_LENGTH = 32;
+
/** Template for {@link #getImageUrl()} */
String ICON_URL = "https://cdn.discordapp.com/emojis/%s.%s";
diff --git a/src/main/java/net/dv8tion/jda/api/entities/emoji/Emoji.java b/src/main/java/net/dv8tion/jda/api/entities/emoji/Emoji.java
index 542b7a87f0..8faeed59f6 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/emoji/Emoji.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/emoji/Emoji.java
@@ -233,8 +233,9 @@ enum Type
*/
UNICODE,
/**
- * Custom Guild Emoji.
+ * Custom Guild Emoji or Custom Application Emoji.
*
This represents emojis which were created by users and added to a guild.
+ *
This can also represent emojis which were created and owned by a specific application.
*/
CUSTOM,
}
diff --git a/src/main/java/net/dv8tion/jda/api/entities/emoji/EmojiUnion.java b/src/main/java/net/dv8tion/jda/api/entities/emoji/EmojiUnion.java
index 18ae0f55cb..9f487c90bb 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/emoji/EmojiUnion.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/emoji/EmojiUnion.java
@@ -22,7 +22,8 @@
* Represents possible {@link Emoji} types.
*
* This delegates the emoji methods for some concrete emoji type,
- * but can be converted to a concrete type using either {@link #asUnicode()} or {@link #asCustom()}.
+ * but can be converted to a concrete type using either {@link #asUnicode()},
+ * {@link #asCustom()}, {@link #asRich()} or {@link #asApplication()}.
*/
public interface EmojiUnion extends Emoji
{
@@ -47,4 +48,26 @@ public interface EmojiUnion extends Emoji
*/
@Nonnull
CustomEmoji asCustom();
+
+ /**
+ * Returns the underlying {@link RichCustomEmoji} if applicable.
+ *
+ * @throws IllegalStateException
+ * If this is not a {@link RichCustomEmoji}
+ *
+ * @return The {@link RichCustomEmoji}
+ */
+ @Nonnull
+ RichCustomEmoji asRich();
+
+ /**
+ * Returns the underlying {@link ApplicationEmoji} if applicable.
+ *
+ * @throws IllegalStateException
+ * If this is not a {@link ApplicationEmoji}
+ *
+ * @return The {@link ApplicationEmoji}
+ */
+ @Nonnull
+ ApplicationEmoji asApplication();
}
diff --git a/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java b/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
new file mode 100644
index 0000000000..1d8e1def62
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2024 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.managers;
+
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.Nonnull;
+
+/**
+ * Manager providing functionality to update the name field for an {@link ApplicationEmoji}.
+ *
+ *
Example
+ *
{@code
+ * manager.setName("minn")
+ * .queue();
+ * }
+ *
+ * @see ApplicationEmoji#getManager()
+ */
+public interface ApplicationEmojiManager extends Manager
+{
+ /** Used to reset the name field */
+ long NAME = 1;
+
+ /**
+ * Resets the fields specified by the provided bit-flag pattern.
+ * You can specify a combination by using a bitwise OR concat of the flag constants.
+ *
+ * Flag Constants:
+ *
+ *
+ * @param fields
+ * Integer value containing the flags to reset.
+ *
+ * @return ApplicationEmojiManager for chaining convenience.
+ */
+ @Nonnull
+ @Override
+ @CheckReturnValue
+ ApplicationEmojiManager reset(long fields);
+
+ /**
+ * Resets the fields specified by the provided bit-flag patterns.
+ *
+ * Flag Constants:
+ *
+ *
+ * @param fields
+ * Integer values containing the flags to reset.
+ *
+ * @return ApplicationEmojiManager for chaining convenience.
+ */
+ @Nonnull
+ @Override
+ @CheckReturnValue
+ ApplicationEmojiManager reset(long... fields);
+
+ /**
+ * The target {@link ApplicationEmoji} that will be modified by this Manager
+ *
+ * @return The target emoji
+ */
+ @Nonnull
+ ApplicationEmoji getEmoji();
+
+ /**
+ * Sets the name of the selected {@link ApplicationEmoji}.
+ *
+ * An emoji name must be between 2-{@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters long!
+ *
Emoji names may only be populated with alphanumeric (with underscore and dash).
+ *
+ *
Example: {@code tatDab} or {@code fmgSUP}
+ *
+ * @param name
+ * The new name for the selected {@link ApplicationEmoji}
+ *
+ * @throws IllegalArgumentException
+ * If the provided name is null, not alphanumeric, or not between 2 and {@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters long
+ *
+ * @return ApplicationEmojiManager for chaining convenience.
+ */
+ @Nonnull
+ @CheckReturnValue
+ ApplicationEmojiManager setName(@Nonnull String name);
+}
diff --git a/src/main/java/net/dv8tion/jda/api/requests/Route.java b/src/main/java/net/dv8tion/jda/api/requests/Route.java
index 0e165f9f85..b92d493cf2 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/Route.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/Route.java
@@ -50,6 +50,11 @@ public static class Applications
public static final Route CONSUME_ENTITLEMENT = new Route(POST, "applications/{application_id}/entitlements/{entitlement_id}/consume");
public static final Route CREATE_TEST_ENTITLEMENT = new Route(POST, "applications/{application_id}/entitlements");
public static final Route DELETE_TEST_ENTITLEMENT = new Route(DELETE, "applications/{application_id}/entitlements/{entitlement_id}");
+ public static final Route GET_APPLICATION_EMOJIS = new Route(GET, "applications/{application_id}/emojis");
+ public static final Route GET_APPLICATION_EMOJI = new Route(GET, "applications/{application_id}/emojis/{emoji_id}");
+ public static final Route CREATE_APPLICATION_EMOJI = new Route(POST, "applications/{application_id}/emojis");
+ public static final Route MODIFY_APPLICATION_EMOJI = new Route(PATCH, "applications/{application_id}/emojis/{emoji_id}");
+ public static final Route DELETE_APPLICATION_EMOJI = new Route(DELETE, "applications/{application_id}/emojis/{emoji_id}");
}
public static class Interactions
diff --git a/src/main/java/net/dv8tion/jda/internal/JDAImpl.java b/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
index 8ef202f4d3..9c1be36130 100644
--- a/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
@@ -29,6 +29,8 @@
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.entities.channel.concrete.*;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.sticker.StickerPack;
import net.dv8tion.jda.api.entities.sticker.StickerSnowflake;
@@ -675,6 +677,62 @@ public SnowflakeCacheView getEmojiCache()
return CacheView.allSnowflakes(() -> guildCache.stream().map(Guild::getEmojiCache));
}
+ @Nonnull
+ @Override
+ public RestAction createApplicationEmoji(@Nonnull String name, @Nonnull Icon icon)
+ {
+ Checks.inRange(name, 2, CustomEmoji.EMOJI_NAME_MAX_LENGTH, "Emoji name");
+ Checks.matches(name, Checks.ALPHANUMERIC_WITH_DASH, "Emoji name");
+ Checks.notNull(icon, "Emoji icon");
+
+ DataObject body = DataObject.empty();
+ body.put("name", name);
+ body.put("image", icon.getEncoding());
+
+ final Route.CompiledRoute route = Route.Applications.CREATE_APPLICATION_EMOJI.compile(getSelfUser().getApplicationId());
+ return new RestActionImpl<>(this, route, body, (response, request) ->
+ {
+ final DataObject obj = response.getObject();
+ return entityBuilder.createApplicationEmoji(this, obj);
+ });
+ }
+
+ @Nonnull
+ @Override
+ public RestAction> retrieveApplicationEmojis()
+ {
+ Route.CompiledRoute route = Route.Applications.GET_APPLICATION_EMOJIS.compile(getSelfUser().getApplicationId());
+ return new RestActionImpl<>(this, route, (response, request) ->
+ {
+ DataArray emojis = response.getObject().getArray("items");
+ List list = new ArrayList<>(emojis.length());
+ for (int i = 0; i < emojis.length(); i++)
+ {
+ try
+ {
+ list.add(entityBuilder.createApplicationEmoji(this, emojis.getObject(i)));
+ }
+ catch (ParsingException e)
+ {
+ LOG.error("Failed to parse application emoji with JSON: {}", emojis.getObject(i), e);
+ }
+ }
+
+ return Collections.unmodifiableList(list);
+ });
+ }
+
+ @Nonnull
+ @Override
+ public RestAction retrieveApplicationEmojiById(@Nonnull String emojiId)
+ {
+ Checks.isSnowflake(emojiId);
+ Route.CompiledRoute route = Route.Applications.GET_APPLICATION_EMOJI.compile(getSelfUser().getApplicationId(), emojiId);
+ return new RestActionImpl<>(this, route,
+ (response, request) -> entityBuilder.createApplicationEmoji(this, response.getObject())
+ );
+ }
+
@Nonnull
@Override
public RestAction retrieveSticker(@Nonnull StickerSnowflake sticker)
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 2a8341eb23..7fb94a3abe 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
@@ -66,6 +66,7 @@
import net.dv8tion.jda.internal.entities.channel.mixin.attribute.IPermissionContainerMixin;
import net.dv8tion.jda.internal.entities.channel.mixin.attribute.IPostContainerMixin;
import net.dv8tion.jda.internal.entities.channel.mixin.middleman.AudioChannelMixin;
+import net.dv8tion.jda.internal.entities.emoji.ApplicationEmojiImpl;
import net.dv8tion.jda.internal.entities.emoji.CustomEmojiImpl;
import net.dv8tion.jda.internal.entities.emoji.RichCustomEmojiImpl;
import net.dv8tion.jda.internal.entities.emoji.UnicodeEmojiImpl;
@@ -1020,6 +1021,15 @@ public RichCustomEmojiImpl createEmoji(GuildImpl guildObj, DataObject json)
.setAvailable(json.getBoolean("available", true));
}
+ public ApplicationEmojiImpl createApplicationEmoji(JDAImpl api, DataObject json)
+ {
+ final long emojiId = json.getUnsignedLong("id");
+ final User user = createUser(json.getObject("user"));
+ return new ApplicationEmojiImpl(emojiId, api, user)
+ .setAnimated(json.getBoolean("animated"))
+ .setName(json.getString("name"));
+ }
+
public ScheduledEvent createScheduledEvent(GuildImpl guild, DataObject json)
{
final long id = json.getLong("id");
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java
index 0afde36341..511ae41d7d 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/GuildImpl.java
@@ -33,6 +33,7 @@
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.unions.DefaultGuildChannelUnion;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.sticker.GuildSticker;
import net.dv8tion.jda.api.entities.sticker.StandardSticker;
@@ -1875,7 +1876,7 @@ public RoleAction createRole()
public AuditableRestAction createEmoji(@Nonnull String name, @Nonnull Icon icon, @Nonnull Role... roles)
{
checkPermission(Permission.MANAGE_GUILD_EXPRESSIONS);
- Checks.inRange(name, 2, 32, "Emoji name");
+ Checks.inRange(name, 2, CustomEmoji.EMOJI_NAME_MAX_LENGTH, "Emoji name");
Checks.notNull(icon, "Emoji icon");
Checks.notNull(roles, "Roles");
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
new file mode 100644
index 0000000000..b5a6c5782b
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2024 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.entities.emoji;
+
+import net.dv8tion.jda.api.JDA;
+import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
+import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji;
+import net.dv8tion.jda.api.managers.ApplicationEmojiManager;
+import net.dv8tion.jda.api.requests.RestAction;
+import net.dv8tion.jda.api.requests.Route;
+import net.dv8tion.jda.api.utils.data.DataObject;
+import net.dv8tion.jda.internal.JDAImpl;
+import net.dv8tion.jda.internal.managers.ApplicationEmojiManagerImpl;
+import net.dv8tion.jda.internal.requests.RestActionImpl;
+import net.dv8tion.jda.internal.utils.EntityString;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+public class ApplicationEmojiImpl implements ApplicationEmoji, EmojiUnion
+{
+ private final long id;
+ private final JDAImpl api;
+ private final User owner;
+
+ boolean animated = false;
+ private String name;
+
+ public ApplicationEmojiImpl(long id, JDAImpl api, User owner)
+ {
+ this.id = id;
+ this.api = api;
+ this.owner = owner;
+ }
+
+ @Nonnull
+ @Override
+ public Type getType()
+ {
+ return Type.CUSTOM;
+ }
+
+ @Nonnull
+ @Override
+ public String getAsReactionCode()
+ {
+ return name + ":" + id;
+ }
+
+ @Nonnull
+ @Override
+ public DataObject toData()
+ {
+ return DataObject.empty()
+ .put("name", name)
+ .put("animated", animated)
+ .put("id", id);
+ }
+
+ @Nonnull
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public long getIdLong()
+ {
+ return id;
+ }
+
+ @Nonnull
+ @Override
+ public JDA getJDA()
+ {
+ return api;
+ }
+
+ @Nullable
+ @Override
+ public User getOwner()
+ {
+ return owner;
+ }
+
+ @Nonnull
+ @Override
+ public ApplicationEmojiManager getManager()
+ {
+ return new ApplicationEmojiManagerImpl(this);
+ }
+
+ @Override
+ public boolean isAnimated()
+ {
+ return animated;
+ }
+
+ @Nonnull
+ @Override
+ public RestAction delete()
+ {
+ Route.CompiledRoute route = Route.Applications.DELETE_APPLICATION_EMOJI.compile(getJDA().getSelfUser().getApplicationId(), getId());
+ return new RestActionImpl<>(getJDA(), route);
+ }
+
+ // -- Setters --
+
+ public ApplicationEmojiImpl setName(String name)
+ {
+ this.name = name;
+ return this;
+ }
+
+ public ApplicationEmojiImpl setAnimated(boolean animated)
+ {
+ this.animated = animated;
+ return this;
+ }
+
+ // -- Object overrides --
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof ApplicationEmojiImpl))
+ return false;
+
+ ApplicationEmojiImpl other = (ApplicationEmojiImpl) obj;
+ return this.id == other.getIdLong();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Long.hashCode(id);
+ }
+
+ @Override
+ public String toString()
+ {
+ return new EntityString(this)
+ .setName(name)
+ .toString();
+ }
+
+ @Nonnull
+ @Override
+ public UnicodeEmoji asUnicode()
+ {
+ throw new IllegalStateException("Cannot convert ApplicationEmoji to UnicodeEmoji!");
+ }
+
+ @Nonnull
+ @Override
+ public CustomEmoji asCustom()
+ {
+ return this;
+ }
+
+ @Nonnull
+ @Override
+ public RichCustomEmoji asRich()
+ {
+ throw new IllegalStateException("Cannot convert ApplicationEmoji to RichCustomEmoji!");
+ }
+
+ @Nonnull
+ @Override
+ public ApplicationEmoji asApplication()
+ {
+ return this;
+ }
+}
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/emoji/CustomEmojiImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/emoji/CustomEmojiImpl.java
index 9f036acbc5..5ae051710a 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/emoji/CustomEmojiImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/emoji/CustomEmojiImpl.java
@@ -16,7 +16,9 @@
package net.dv8tion.jda.internal.entities.emoji;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji;
import net.dv8tion.jda.api.utils.data.DataObject;
@@ -125,4 +127,18 @@ public CustomEmoji asCustom()
{
return this;
}
+
+ @Nonnull
+ @Override
+ public RichCustomEmoji asRich()
+ {
+ throw new IllegalStateException("Cannot convert CustomEmoji to RichCustomEmoji!");
+ }
+
+ @Nonnull
+ @Override
+ public ApplicationEmoji asApplication()
+ {
+ throw new IllegalStateException("Cannot convert CustomEmoji to ApplicationEmoji!");
+ }
}
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/emoji/RichCustomEmojiImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/emoji/RichCustomEmojiImpl.java
index 28c2921847..3330e1d34e 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/emoji/RichCustomEmojiImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/emoji/RichCustomEmojiImpl.java
@@ -19,6 +19,7 @@
import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.User;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
@@ -279,4 +280,18 @@ public CustomEmoji asCustom()
{
return this;
}
+
+ @Nonnull
+ @Override
+ public RichCustomEmoji asRich()
+ {
+ return this;
+ }
+
+ @Nonnull
+ @Override
+ public ApplicationEmoji asApplication()
+ {
+ throw new IllegalStateException("Cannot convert RichCustomEmoji to ApplicationEmoji!");
+ }
}
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/emoji/UnicodeEmojiImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/emoji/UnicodeEmojiImpl.java
index 71eda48bcd..aecf0f63a7 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/emoji/UnicodeEmojiImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/emoji/UnicodeEmojiImpl.java
@@ -16,7 +16,9 @@
package net.dv8tion.jda.internal.entities.emoji;
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji;
import net.dv8tion.jda.api.utils.data.DataObject;
@@ -100,4 +102,18 @@ public CustomEmoji asCustom()
{
throw new IllegalStateException("Cannot convert UnicodeEmoji into CustomEmoji!");
}
+
+ @Nonnull
+ @Override
+ public RichCustomEmoji asRich()
+ {
+ throw new IllegalStateException("Cannot convert UnicodeEmoji into RichCustomEmoji!");
+ }
+
+ @Nonnull
+ @Override
+ public ApplicationEmoji asApplication()
+ {
+ throw new IllegalStateException("Cannot convert UnicodeEmoji to ApplicationEmoji!");
+ }
}
diff --git a/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java b/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
new file mode 100644
index 0000000000..1a57920104
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2024 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.managers;
+
+import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
+import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
+import net.dv8tion.jda.api.managers.ApplicationEmojiManager;
+import net.dv8tion.jda.api.requests.Route;
+import net.dv8tion.jda.api.utils.data.DataObject;
+import net.dv8tion.jda.internal.utils.Checks;
+import okhttp3.RequestBody;
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.CheckReturnValue;
+import javax.annotation.Nonnull;
+
+public class ApplicationEmojiManagerImpl extends ManagerBase implements ApplicationEmojiManager
+{
+ protected final ApplicationEmoji emoji;
+
+ protected String name;
+
+ public ApplicationEmojiManagerImpl(ApplicationEmoji emoji)
+ {
+ super(emoji.getJDA(), Route.Applications.MODIFY_APPLICATION_EMOJI.compile(emoji.getJDA().getSelfUser().getApplicationId(), emoji.getId()));
+ this.emoji = emoji;
+ }
+
+ @NotNull
+ @Override
+ public ApplicationEmoji getEmoji()
+ {
+ return emoji;
+ }
+
+ @Nonnull
+ @Override
+ @CheckReturnValue
+ public ApplicationEmojiManagerImpl reset(long fields)
+ {
+ super.reset(fields);
+ if ((fields & NAME) == NAME)
+ this.name = null;
+ return this;
+ }
+
+ @Nonnull
+ @Override
+ @CheckReturnValue
+ public ApplicationEmojiManagerImpl reset(long... fields)
+ {
+ super.reset(fields);
+ return this;
+ }
+
+ @NotNull
+ @Override
+ public ApplicationEmojiManager setName(@NotNull String name)
+ {
+ Checks.inRange(name, 2, CustomEmoji.EMOJI_NAME_MAX_LENGTH, "Emoji name");
+ Checks.matches(name, Checks.ALPHANUMERIC_WITH_DASH, "Emoji name");
+ this.name = name;
+ set |= NAME;
+ return this;
+ }
+
+ @Override
+ protected RequestBody finalizeData()
+ {
+ DataObject object = DataObject.empty();
+ if (shouldUpdate(NAME))
+ object.put("name", name);
+ reset();
+ return getRequestBody(object);
+ }
+}
diff --git a/src/test/java/net/dv8tion/jda/test/restaction/CreateApplicationEmojiTest.java b/src/test/java/net/dv8tion/jda/test/restaction/CreateApplicationEmojiTest.java
new file mode 100644
index 0000000000..7281970fbc
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/restaction/CreateApplicationEmojiTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.test.restaction;
+
+import net.dv8tion.jda.api.entities.Icon;
+import net.dv8tion.jda.api.requests.Method;
+import net.dv8tion.jda.api.utils.data.DataObject;
+import net.dv8tion.jda.internal.entities.SelfUserImpl;
+import net.dv8tion.jda.test.Constants;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("ResultOfMethodCallIgnored")
+public class CreateApplicationEmojiTest extends RestActionTest
+{
+ private static final String EXAMPLE_NAME = "thinking";
+ private static final Icon EXAMPLE_ICON = Icon.from(new byte[]{1, 2, 3});
+
+ @BeforeEach
+ void setupMocks()
+ {
+ when(jda.createApplicationEmoji(any(), any())).thenCallRealMethod();
+ when(jda.getSelfUser()).thenReturn(new SelfUserImpl(Constants.BUTLER_USER_ID, jda));
+ }
+
+ @MethodSource
+ @ParameterizedTest
+ void testNullArguments(String name, Icon icon)
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> jda.createApplicationEmoji(name, icon));
+ }
+
+ static Stream testNullArguments()
+ {
+ return Stream.of(
+ arguments(null, null),
+ arguments(null, EXAMPLE_ICON),
+ arguments(EXAMPLE_NAME, null)
+ );
+ }
+
+ @Test
+ void testWrongNameFormat()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> jda.createApplicationEmoji("test with spaces", EXAMPLE_ICON))
+ .withMessageContaining("must match regex");
+ }
+
+ @Test
+ void testWrongNameLength()
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> jda.createApplicationEmoji(StringUtils.repeat('a', 33), EXAMPLE_ICON))
+ .withMessageContaining("must be between 2 and 32 characters long");
+ }
+
+ @Test
+ void testValidEmoji()
+ {
+ assertThatRequestFrom(jda.createApplicationEmoji(EXAMPLE_NAME, EXAMPLE_ICON))
+ .hasMethod(Method.POST)
+ .hasCompiledRoute("applications/" + Constants.BUTLER_USER_ID + "/emojis")
+ .hasBodyEqualTo(DataObject.empty()
+ .put("name", EXAMPLE_NAME)
+ .put("image", EXAMPLE_ICON.getEncoding()))
+ .whenQueueCalled();
+ }
+}
From 53adaa1b5daa88fbbf9e8ea4009ea73c8532ceff Mon Sep 17 00:00:00 2001
From: freya02 <41875020+freya022@users.noreply.github.com>
Date: Sun, 3 Nov 2024 15:12:02 +0100
Subject: [PATCH 06/17] Replace `GatewayIntent#GUILD_EMOJIS_AND_STICKERS` with
`GUILD_EXPRESSIONS` (#2755)
---
.../jda/api/events/emoji/EmojiAddedEvent.java | 2 +-
.../jda/api/events/emoji/EmojiRemovedEvent.java | 2 +-
.../jda/api/events/emoji/GenericEmojiEvent.java | 2 +-
.../dv8tion/jda/api/events/emoji/package-info.java | 2 +-
.../events/emoji/update/EmojiUpdateNameEvent.java | 2 +-
.../events/emoji/update/EmojiUpdateRolesEvent.java | 2 +-
.../emoji/update/GenericEmojiUpdateEvent.java | 2 +-
.../jda/api/events/emoji/update/package-info.java | 2 +-
.../events/sticker/GenericGuildStickerEvent.java | 2 +-
.../api/events/sticker/GuildStickerAddedEvent.java | 2 +-
.../events/sticker/GuildStickerRemovedEvent.java | 2 +-
.../jda/api/events/sticker/package-info.java | 2 +-
.../update/GenericGuildStickerUpdateEvent.java | 2 +-
.../update/GuildStickerUpdateAvailableEvent.java | 2 +-
.../update/GuildStickerUpdateDescriptionEvent.java | 2 +-
.../sticker/update/GuildStickerUpdateNameEvent.java | 2 +-
.../sticker/update/GuildStickerUpdateTagsEvent.java | 2 +-
.../jda/api/events/sticker/update/package-info.java | 2 +-
.../net/dv8tion/jda/api/requests/GatewayIntent.java | 13 ++++++++++++-
.../net/dv8tion/jda/api/utils/cache/CacheFlag.java | 8 ++++----
20 files changed, 34 insertions(+), 23 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiAddedEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiAddedEvent.java
index 5af0d65207..8d0ae477f9 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiAddedEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiAddedEvent.java
@@ -27,7 +27,7 @@
* Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiRemovedEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiRemovedEvent.java
index 7a910f17bc..fb713c433d 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiRemovedEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/EmojiRemovedEvent.java
@@ -27,7 +27,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/GenericEmojiEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/GenericEmojiEvent.java
index efd55eeb28..5d49a6574b 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/GenericEmojiEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/GenericEmojiEvent.java
@@ -29,7 +29,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/package-info.java b/src/main/java/net/dv8tion/jda/api/events/emoji/package-info.java
index 4ddab90e8a..00ee5fa217 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/package-info.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/package-info.java
@@ -22,7 +22,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateNameEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateNameEvent.java
index 94e6095cbb..d9e1c08ba3 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateNameEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateNameEvent.java
@@ -29,7 +29,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateRolesEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateRolesEvent.java
index 4f45dafd69..4930d1bac1 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateRolesEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/update/EmojiUpdateRolesEvent.java
@@ -31,7 +31,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/update/GenericEmojiUpdateEvent.java b/src/main/java/net/dv8tion/jda/api/events/emoji/update/GenericEmojiUpdateEvent.java
index 1a50e129dc..e8e07af094 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/update/GenericEmojiUpdateEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/update/GenericEmojiUpdateEvent.java
@@ -30,7 +30,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/emoji/update/package-info.java b/src/main/java/net/dv8tion/jda/api/events/emoji/update/package-info.java
index afec8be948..189d3e4d77 100644
--- a/src/main/java/net/dv8tion/jda/api/events/emoji/update/package-info.java
+++ b/src/main/java/net/dv8tion/jda/api/events/emoji/update/package-info.java
@@ -20,7 +20,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#EMOJI EMOJI} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/GenericGuildStickerEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/GenericGuildStickerEvent.java
index 67b74471e2..4d2c9b68b3 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/GenericGuildStickerEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/GenericGuildStickerEvent.java
@@ -29,7 +29,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerAddedEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerAddedEvent.java
index 515f8d60dc..0678d3a499 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerAddedEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerAddedEvent.java
@@ -28,7 +28,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerRemovedEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerRemovedEvent.java
index df6d362409..c07b2260cf 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerRemovedEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/GuildStickerRemovedEvent.java
@@ -28,7 +28,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/package-info.java b/src/main/java/net/dv8tion/jda/api/events/sticker/package-info.java
index dbb24f662f..385403477e 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/package-info.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/package-info.java
@@ -21,7 +21,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GenericGuildStickerUpdateEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GenericGuildStickerUpdateEvent.java
index d995e71546..0f638f0160 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GenericGuildStickerUpdateEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GenericGuildStickerUpdateEvent.java
@@ -31,7 +31,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateAvailableEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateAvailableEvent.java
index a347a7c6ad..71703c70c3 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateAvailableEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateAvailableEvent.java
@@ -28,7 +28,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateDescriptionEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateDescriptionEvent.java
index 70c29a215f..541ba85eb6 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateDescriptionEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateDescriptionEvent.java
@@ -30,7 +30,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateNameEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateNameEvent.java
index 22c6cf89cf..91d9b69ead 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateNameEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateNameEvent.java
@@ -30,7 +30,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateTagsEvent.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateTagsEvent.java
index 3f37aa8534..6acd8ee86d 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateTagsEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/GuildStickerUpdateTagsEvent.java
@@ -31,7 +31,7 @@
*
Requirements
*
*
This event requires the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*
diff --git a/src/main/java/net/dv8tion/jda/api/events/sticker/update/package-info.java b/src/main/java/net/dv8tion/jda/api/events/sticker/update/package-info.java
index d51fac1c55..1cf54e1464 100644
--- a/src/main/java/net/dv8tion/jda/api/events/sticker/update/package-info.java
+++ b/src/main/java/net/dv8tion/jda/api/events/sticker/update/package-info.java
@@ -20,7 +20,7 @@
*
Requirements
*
*
These events require the {@link net.dv8tion.jda.api.utils.cache.CacheFlag#STICKER STICKER} CacheFlag to be enabled, which requires
- * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent.
+ * the {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent.
*
*
{@link net.dv8tion.jda.api.JDABuilder#createLight(String) createLight(String)} disables that CacheFlag by default!
*/
diff --git a/src/main/java/net/dv8tion/jda/api/requests/GatewayIntent.java b/src/main/java/net/dv8tion/jda/api/requests/GatewayIntent.java
index a2dcaf302e..1c60305220 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/GatewayIntent.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/GatewayIntent.java
@@ -16,6 +16,8 @@
package net.dv8tion.jda.api.requests;
+import net.dv8tion.jda.annotations.ForRemoval;
+import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.GenericEvent;
@@ -100,8 +102,17 @@ public enum GatewayIntent
GUILD_MODERATION(2),
/**
* Custom emoji and sticker add/update/delete events.
+ *
+ * @deprecated Replaced with {@link #GUILD_EXPRESSIONS}
*/
+ @ForRemoval(deadline = "5.3.0")
+ @ReplaceWith("GUILD_EXPRESSIONS")
+ @Deprecated
GUILD_EMOJIS_AND_STICKERS(3),
+ /**
+ * Custom emoji, sticker and soundboard sound add/update/delete events.
+ */
+ GUILD_EXPRESSIONS(3),
// /**
// * Integration events. (unused)
// */
@@ -407,7 +418,7 @@ else if (GenericUserUpdateEvent.class.isAssignableFrom(event) || GenericGuildMem
else if (GuildBanEvent.class.isAssignableFrom(event) || GuildUnbanEvent.class.isAssignableFrom(event) || GuildAuditLogEntryCreateEvent.class.isAssignableFrom(event))
intents.add(GUILD_MODERATION);
else if (GenericEmojiEvent.class.isAssignableFrom(event) || GenericGuildStickerEvent.class.isAssignableFrom(event))
- intents.add(GUILD_EMOJIS_AND_STICKERS);
+ intents.add(GUILD_EXPRESSIONS);
else if (GenericScheduledEventUpdateEvent.class.isAssignableFrom(event))
intents.add(SCHEDULED_EVENTS);
else if (GenericGuildInviteEvent.class.isAssignableFrom(event))
diff --git a/src/main/java/net/dv8tion/jda/api/utils/cache/CacheFlag.java b/src/main/java/net/dv8tion/jda/api/utils/cache/CacheFlag.java
index d00955ad78..b9121f8da6 100644
--- a/src/main/java/net/dv8tion/jda/api/utils/cache/CacheFlag.java
+++ b/src/main/java/net/dv8tion/jda/api/utils/cache/CacheFlag.java
@@ -49,15 +49,15 @@ public enum CacheFlag
/**
* Enables cache for {@link Guild#getEmojiCache()}
*
- *
Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent to be enabled.
+ *
Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent to be enabled.
*/
- EMOJI(GatewayIntent.GUILD_EMOJIS_AND_STICKERS),
+ EMOJI(GatewayIntent.GUILD_EXPRESSIONS),
/**
* Enables cache for {@link Guild#getStickerCache()}
*
- *
Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EMOJIS_AND_STICKERS GUILD_EMOJIS_AND_STICKERS} intent to be enabled.
+ *
Requires {@link net.dv8tion.jda.api.requests.GatewayIntent#GUILD_EXPRESSIONS GUILD_EXPRESSIONS} intent to be enabled.
*/
- STICKER(GatewayIntent.GUILD_EMOJIS_AND_STICKERS),
+ STICKER(GatewayIntent.GUILD_EXPRESSIONS),
/**
* Enables cache for {@link Member#getOnlineStatus(net.dv8tion.jda.api.entities.ClientType) Member.getOnlineStatus(ClientType)}
*
From 5d9e36c8bc735959b7a2ec84ff0c7f6122aef7bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 15:22:23 +0100
Subject: [PATCH 07/17] Add some tests for JDABuilder intents and cache flags
(#2762)
---
.../java/net/dv8tion/jda/api/JDABuilder.java | 10 +-
.../net/dv8tion/jda/test/JDABuilderTest.java | 211 ++++++++++++++++++
.../java/net/dv8tion/jda/test/TestHelper.java | 57 +++++
3 files changed, 273 insertions(+), 5 deletions(-)
create mode 100644 src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
create mode 100644 src/test/java/net/dv8tion/jda/test/TestHelper.java
diff --git a/src/main/java/net/dv8tion/jda/api/JDABuilder.java b/src/main/java/net/dv8tion/jda/api/JDABuilder.java
index deceb43870..85ec2396f2 100644
--- a/src/main/java/net/dv8tion/jda/api/JDABuilder.java
+++ b/src/main/java/net/dv8tion/jda/api/JDABuilder.java
@@ -98,7 +98,7 @@ public class JDABuilder
protected GatewayEncoding encoding = GatewayEncoding.JSON;
protected RestConfig restConfig = new RestConfig();
- private JDABuilder(@Nullable String token, int intents)
+ protected JDABuilder(@Nullable String token, int intents)
{
this.token = token;
this.intents = 1 | intents;
@@ -212,7 +212,7 @@ public static JDABuilder createDefault(@Nullable String token, @Nonnull Collecti
return create(token, intents).applyDefault();
}
- private JDABuilder applyDefault()
+ protected JDABuilder applyDefault()
{
return this.setMemberCachePolicy(MemberCachePolicy.DEFAULT)
.setChunkingFilter(ChunkingFilter.NONE)
@@ -322,7 +322,7 @@ public static JDABuilder createLight(@Nullable String token, @Nonnull Collection
return create(token, intents).applyLight();
}
- private JDABuilder applyLight()
+ protected JDABuilder applyLight()
{
return this.setMemberCachePolicy(MemberCachePolicy.NONE)
.setChunkingFilter(ChunkingFilter.NONE)
@@ -464,7 +464,7 @@ public static JDABuilder create(@Nullable String token, @Nonnull Collection disabledCache = EnumSet.allOf(CacheFlag.class);
for (CacheFlag flag : CacheFlag.values())
@@ -1859,7 +1859,7 @@ private JDABuilder setFlag(ConfigFlag flag, boolean enable)
return this;
}
- private void checkIntents()
+ protected void checkIntents()
{
boolean membersIntent = (intents & GatewayIntent.GUILD_MEMBERS.getRawValue()) != 0;
if (!membersIntent && memberCachePolicy == MemberCachePolicy.ALL)
diff --git a/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
new file mode 100644
index 0000000000..3bf2a7d194
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.test;
+
+import net.dv8tion.jda.api.JDABuilder;
+import net.dv8tion.jda.api.requests.GatewayIntent;
+import net.dv8tion.jda.api.utils.ChunkingFilter;
+import net.dv8tion.jda.api.utils.cache.CacheFlag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.EnumSource;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static net.dv8tion.jda.api.requests.GatewayIntent.ALL_INTENTS;
+import static net.dv8tion.jda.test.TestHelper.captureLogging;
+import static org.assertj.core.api.Assertions.*;
+
+public class JDABuilderTest
+{
+ private static final String TOKEN = "invalid.token.here";
+
+ @Test
+ void testCreateWithAllIntents()
+ {
+ TestJDABuilder builder = new TestJDABuilder(ALL_INTENTS);
+ builder.applyIntents();
+
+ List logs = captureLogging(builder::checkIntents);
+ assertThat(logs).isEmpty();
+ }
+
+ @Test
+ void testCreateWithMinimalIntents()
+ {
+ TestJDABuilder builder = new TestJDABuilder(0);
+ builder.applyIntents();
+
+ List logs = captureLogging(builder::checkIntents);
+
+ EnumSet flags = EnumSet.allOf(CacheFlag.class);
+ flags.removeIf(flag -> flag.getRequiredIntent() == null);
+ checkMissingIntentWarnings(logs, flags);
+ }
+
+ @Test
+ void testCreateWithAllCacheAllIntents()
+ {
+ TestJDABuilder builder = new TestJDABuilder(ALL_INTENTS);
+ builder.applyIntents();
+ builder.enableCache(EnumSet.allOf(CacheFlag.class));
+
+ List logs = captureLogging(builder::checkIntents);
+ assertThat(logs).isEmpty();
+ }
+
+ @Test
+ void testCreateWithAllCacheNoIntents()
+ {
+ TestJDABuilder builder = new TestJDABuilder(0);
+ builder.applyIntents();
+ builder.enableCache(EnumSet.allOf(CacheFlag.class));
+
+ assertThatIllegalArgumentException()
+ .isThrownBy(builder::checkIntents)
+ .withMessage("Cannot use CacheFlag.ACTIVITY without GatewayIntent.GUILD_PRESENCES!");
+ }
+
+ @ParameterizedTest
+ @EnumSource(CacheFlag.class)
+ void testRequiredIntentForCacheFlagMissing(CacheFlag cacheFlag)
+ {
+ TestJDABuilder builder = new TestJDABuilder(0);
+ builder.applyIntents();
+ builder.enableCache(cacheFlag);
+
+ if (cacheFlag.getRequiredIntent() != null)
+ {
+ assertThatIllegalArgumentException()
+ .isThrownBy(builder::checkIntents)
+ .withMessage(String.format("Cannot use CacheFlag.%s without GatewayIntent.%s!", cacheFlag, cacheFlag.getRequiredIntent()));
+ }
+ else
+ {
+ assertThatNoException().isThrownBy(builder::checkIntents);
+ }
+ }
+
+
+ @ParameterizedTest
+ @EnumSource(CacheFlag.class)
+ void testRequiredIntentForCacheFlagEnabled(CacheFlag cacheFlag)
+ {
+ GatewayIntent requiredIntent = cacheFlag.getRequiredIntent();
+ TestJDABuilder builder = new TestJDABuilder(requiredIntent != null ? requiredIntent.getRawValue() : 0);
+ builder.applyIntents();
+ builder.enableCache(cacheFlag);
+
+ assertThatNoException().isThrownBy(builder::checkIntents);
+ }
+
+ @Test
+ void testDefaultMinimal()
+ {
+ TestJDABuilder builder = new TestJDABuilder(0);
+ builder.applyIntents();
+ builder.applyDefault();
+
+ EnumSet defaultDisabled = CacheFlag.getPrivileged();
+ EnumSet flags = EnumSet.allOf(CacheFlag.class);
+ flags.removeIf(flag -> flag.getRequiredIntent() == null || defaultDisabled.contains(flag));
+
+ List logs = captureLogging(builder::checkIntents);
+ checkMissingIntentWarnings(logs, flags);
+ }
+
+ @Test
+ void testChunkingWithMissingIntent()
+ {
+ TestJDABuilder builder = new TestJDABuilder(0);
+ builder.applyIntents();
+ builder.setChunkingFilter(ChunkingFilter.ALL);
+
+ List logs = captureLogging(builder::checkIntents);
+ assertThat(logs).contains("Member chunking is disabled due to missing GUILD_MEMBERS intent.");
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ void testDeprecatedIntentDoesNotDisableCache()
+ {
+ TestJDABuilder builder = new TestJDABuilder(GatewayIntent.GUILD_EMOJIS_AND_STICKERS.getRawValue());
+ builder.applyIntents();
+
+ List logs = captureLogging(() ->
+ assertThatNoException().isThrownBy(builder::checkIntents)
+ );
+
+ assertThat(logs)
+ .isNotEmpty()
+ .noneMatch(log -> log.contains("CacheFlag." + CacheFlag.EMOJI))
+ .noneMatch(log -> log.contains("CacheFlag." + CacheFlag.STICKER));
+ }
+
+ private void checkMissingIntentWarnings(List logs, EnumSet cacheFlagsWithMissingIntents)
+ {
+ String commaSeparatedList = cacheFlagsWithMissingIntents.stream()
+ .map(CacheFlag::name)
+ .map(name -> "CacheFlag." + name)
+ .collect(Collectors.joining(", "));
+
+ String listOfWarnings = cacheFlagsWithMissingIntents.stream()
+ .map(flag -> String.format("Disabled CacheFlag.%s (missing GatewayIntent.%s)", flag.name(), flag.getRequiredIntent().name()))
+ .collect(Collectors.joining("\n"));
+
+ assertThat(String.join("\n", logs))
+ .isEqualToIgnoringWhitespace(
+ "Automatically disabled CacheFlags due to missing intents\n" +
+ listOfWarnings + "\n" +
+ "You can manually disable these flags to remove this warning by using disableCache(" + commaSeparatedList + ") on your JDABuilder"
+ );
+ }
+
+ static class TestJDABuilder extends JDABuilder
+ {
+ public TestJDABuilder(int intents)
+ {
+ super(TOKEN, intents);
+ }
+
+ @Override
+ public JDABuilder applyDefault()
+ {
+ return super.applyDefault();
+ }
+
+ @Override
+ public JDABuilder applyLight()
+ {
+ return super.applyLight();
+ }
+
+ @Override
+ public JDABuilder applyIntents()
+ {
+ return super.applyIntents();
+ }
+
+ @Override
+ public void checkIntents()
+ {
+ super.checkIntents();
+ }
+ }
+}
diff --git a/src/test/java/net/dv8tion/jda/test/TestHelper.java b/src/test/java/net/dv8tion/jda/test/TestHelper.java
new file mode 100644
index 0000000000..06a815eb47
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/TestHelper.java
@@ -0,0 +1,57 @@
+/*
+ * 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.test;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class TestHelper
+{
+ public static List captureLogging(Runnable task)
+ {
+ return captureLogging(LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME), task);
+ }
+
+ public static List captureLogging(Logger logger, Runnable task)
+ {
+ assertThat(logger).isInstanceOf(ch.qos.logback.classic.Logger.class);
+ ch.qos.logback.classic.Logger logbackLogger = (ch.qos.logback.classic.Logger) logger;
+
+ ListAppender listAppender = new ListAppender<>();
+ listAppender.start();
+ logbackLogger.addAppender(listAppender);
+ try
+ {
+ task.run();
+ return listAppender.list
+ .stream().map(ILoggingEvent::getFormattedMessage)
+ .collect(Collectors.toList());
+ }
+ finally
+ {
+ logbackLogger.detachAppender(listAppender);
+ listAppender.stop();
+ }
+ }
+}
From 820d56da0eeb1c56c613b8a7290b9f33c8d1c895 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 17:22:45 +0100
Subject: [PATCH 08/17] Remove deprecated symbols with deadline 5.1.0 (#2763)
---
.../java/net/dv8tion/jda/api/Permission.java | 93 -------------------
.../api/managers/StageInstanceManager.java | 28 ++----
.../restaction/StageInstanceAction.java | 21 -----
.../managers/StageInstanceManagerImpl.java | 15 ---
.../restaction/StageInstanceActionImpl.java | 13 ---
.../jda/internal/utils/PermissionUtil.java | 18 +++-
6 files changed, 20 insertions(+), 168 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/Permission.java b/src/main/java/net/dv8tion/jda/api/Permission.java
index 2e9471c459..c1c0d739fe 100644
--- a/src/main/java/net/dv8tion/jda/api/Permission.java
+++ b/src/main/java/net/dv8tion/jda/api/Permission.java
@@ -15,15 +15,11 @@
*/
package net.dv8tion.jda.api;
-import net.dv8tion.jda.annotations.ForRemoval;
-import net.dv8tion.jda.annotations.ReplaceWith;
import net.dv8tion.jda.internal.utils.Checks;
import javax.annotation.Nonnull;
-import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
-import java.util.stream.Collectors;
/**
* Represents the bit offsets used by Discord for Permissions.
@@ -85,10 +81,6 @@ public enum Permission
VOICE_DEAF_OTHERS( 23, true, true, "Deafen Members"),
VOICE_MOVE_OTHERS( 24, true, true, "Move Members"),
VOICE_USE_VAD( 25, true, true, "Use Voice Activity"),
- @Deprecated
- @ForRemoval(deadline="5.1.0")
- @ReplaceWith("USE_EMBEDDED_ACTIVITIES")
- VOICE_START_ACTIVITIES( 39, true, true, "Use Activities"),
VOICE_USE_SOUNDBOARD( 42, true, true, "Use Soundboard"),
VOICE_USE_EXTERNAL_SOUNDS(45, true, true, "Use External Sounds"),
VOICE_SET_STATUS( 48, true, true, "Set Voice Channel Status"),
@@ -108,63 +100,6 @@ public enum Permission
// This is an optimization suggested by Effective Java 3rd Edition - Item 54
public static final Permission[] EMPTY_PERMISSIONS = new Permission[0];
- /**
- * Represents a raw set of all permissions
- *
- * @deprecated To be removed in 5.1.0
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public static final long ALL_PERMISSIONS = Permission.getRaw(Permission.values());
-
- /**
- * All permissions that apply to a channel
- *
- * @deprecated To be removed in 5.1.0 (use {@link Permission#isChannel()} instead)
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public static final long ALL_CHANNEL_PERMISSIONS = Permission.getRaw(Arrays.stream(values())
- .filter(Permission::isChannel).collect(Collectors.toSet()));
-
- /**
- * All Guild specific permissions which are only available to roles
- *
- * @deprecated To be removed in 5.1.0 (use {@link Permission#isGuild()} instead)
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public static final long ALL_GUILD_PERMISSIONS = Permission.getRaw(Arrays.stream(values())
- .filter(Permission::isGuild).collect(Collectors.toSet()));
-
- /**
- * All text channel specific permissions which are only available in text channel permission overrides
- *
- * @deprecated To be removed in 5.1.0
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public static final long ALL_TEXT_PERMISSIONS
- = Permission.getRaw(MESSAGE_ADD_REACTION, MESSAGE_SEND, MESSAGE_TTS, MESSAGE_MANAGE,
- MESSAGE_EMBED_LINKS, MESSAGE_ATTACH_FILES, MESSAGE_EXT_EMOJI, MESSAGE_EXT_STICKER,
- MESSAGE_HISTORY, MESSAGE_MENTION_EVERYONE,
- USE_APPLICATION_COMMANDS, USE_EXTERNAL_APPLICATIONS, USE_EMBEDDED_ACTIVITIES,
- MANAGE_THREADS, CREATE_PUBLIC_THREADS, CREATE_PRIVATE_THREADS,
- MESSAGE_SEND_IN_THREADS, MESSAGE_ATTACH_VOICE_MESSAGE, MESSAGE_SEND_POLLS);
-
- /**
- * All voice channel specific permissions which are only available in voice channel permission overrides
- *
- * @deprecated To be removed in 5.1.0
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public static final long ALL_VOICE_PERMISSIONS
- = Permission.getRaw(VOICE_STREAM, VOICE_CONNECT, VOICE_SPEAK, VOICE_MUTE_OTHERS,
- VOICE_DEAF_OTHERS, VOICE_MOVE_OTHERS, VOICE_USE_VAD,
- PRIORITY_SPEAKER, REQUEST_TO_SPEAK, USE_EMBEDDED_ACTIVITIES,
- VOICE_USE_SOUNDBOARD, VOICE_USE_EXTERNAL_SOUNDS, VOICE_SET_STATUS);
-
private final int offset;
private final long raw;
private final boolean isGuild, isChannel;
@@ -235,34 +170,6 @@ public boolean isChannel()
return isChannel;
}
- /**
- * Whether this permission is specifically for {@link net.dv8tion.jda.api.entities.channel.concrete.TextChannel TextChannels}
- *
- * @return True, if and only if this permission can only be applied to text channels
- *
- * @deprecated To be removed in 5.1.0
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public boolean isText()
- {
- return (raw & ALL_TEXT_PERMISSIONS) == raw;
- }
-
- /**
- * Whether this permission is specifically for {@link net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel VoiceChannels}
- *
- * @return True, if and only if this permission can only be applied to voice channels
- *
- * @deprecated To be removed in 5.1.0
- */
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- public boolean isVoice()
- {
- return (raw & ALL_VOICE_PERMISSIONS) == raw;
- }
-
/**
* Gets the first {@link net.dv8tion.jda.api.Permission Permission} relating to the provided offset.
*
If there is no {@link net.dv8tion.jda.api.Permission Permssions} that matches the provided
diff --git a/src/main/java/net/dv8tion/jda/api/managers/StageInstanceManager.java b/src/main/java/net/dv8tion/jda/api/managers/StageInstanceManager.java
index 805231477b..5b7d0cbdf7 100644
--- a/src/main/java/net/dv8tion/jda/api/managers/StageInstanceManager.java
+++ b/src/main/java/net/dv8tion/jda/api/managers/StageInstanceManager.java
@@ -43,7 +43,13 @@ public interface StageInstanceManager extends Manager
{
/** Used to reset the topic field */
long TOPIC = 1;
- /** Used to reset the privacy level field */
+ /**
+ * Used to reset the privacy level field
+ *
+ * @deprecated Obsolete.
+ */
+ @Deprecated
+ @ForRemoval(deadline = "5.3.0")
long PRIVACY_LEVEL = 1 << 1;
/**
@@ -110,24 +116,4 @@ public interface StageInstanceManager extends Manager
@Nonnull
@CheckReturnValue
StageInstanceManager setTopic(@Nullable String topic);
-
- /**
- * Sets the {@link net.dv8tion.jda.api.entities.StageInstance.PrivacyLevel PrivacyLevel} for this stage instance.
- *
This indicates whether guild lurkers are allowed to join the stage instance or only guild members.
- *
- * @param level
- * The privacy level
- *
- * @throws IllegalArgumentException
- * If the privacy level is null, {@link net.dv8tion.jda.api.entities.StageInstance.PrivacyLevel#UNKNOWN UNKNOWN}.
- *
- * @return StageInstanceManager for chaining convenience
- *
- * @deprecated Obsolete.
- */
- @Nonnull
- @CheckReturnValue
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- StageInstanceManager setPrivacyLevel(@Nonnull StageInstance.PrivacyLevel level);
}
diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/StageInstanceAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/StageInstanceAction.java
index 9cfb457b2f..7b9c2256c6 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/restaction/StageInstanceAction.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/StageInstanceAction.java
@@ -16,7 +16,6 @@
package net.dv8tion.jda.api.requests.restaction;
-import net.dv8tion.jda.annotations.ForRemoval;
import net.dv8tion.jda.api.entities.StageInstance;
import net.dv8tion.jda.api.requests.RestAction;
@@ -63,24 +62,4 @@ public interface StageInstanceAction extends RestAction
@Nonnull
@CheckReturnValue
StageInstanceAction setTopic(@Nonnull String topic);
-
- /**
- * Sets the {@link net.dv8tion.jda.api.entities.StageInstance.PrivacyLevel PrivacyLevel} for the stage instance.
- *
This indicates whether guild lurkers are allowed to join the stage instance or only guild members.
- *
- * @param level
- * The {@link net.dv8tion.jda.api.entities.StageInstance.PrivacyLevel}
- *
- * @throws IllegalArgumentException
- * If the privacy level is null, {@link net.dv8tion.jda.api.entities.StageInstance.PrivacyLevel#UNKNOWN UNKNOWN}.
- *
- * @return The StageInstanceAction for chaining
- *
- * @deprecated Obsolete.
- */
- @Nonnull
- @CheckReturnValue
- @Deprecated
- @ForRemoval(deadline = "5.1.0")
- StageInstanceAction setPrivacyLevel(@Nonnull StageInstance.PrivacyLevel level);
}
diff --git a/src/main/java/net/dv8tion/jda/internal/managers/StageInstanceManagerImpl.java b/src/main/java/net/dv8tion/jda/internal/managers/StageInstanceManagerImpl.java
index a019a14d64..a05db8367d 100644
--- a/src/main/java/net/dv8tion/jda/internal/managers/StageInstanceManagerImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/managers/StageInstanceManagerImpl.java
@@ -31,7 +31,6 @@ public class StageInstanceManagerImpl extends ManagerBase
private final StageInstance instance;
private String topic;
- private StageInstance.PrivacyLevel privacyLevel;
public StageInstanceManagerImpl(StageInstance instance)
{
@@ -62,26 +61,12 @@ public StageInstanceManager setTopic(@Nullable String topic)
return this;
}
- @Nonnull
- @Override
- @Deprecated
- public StageInstanceManager setPrivacyLevel(@Nonnull StageInstance.PrivacyLevel level)
- {
- Checks.notNull(level, "PrivacyLevel");
- Checks.check(level != StageInstance.PrivacyLevel.UNKNOWN, "PrivacyLevel must not be UNKNOWN!");
- this.privacyLevel = level;
- set |= PRIVACY_LEVEL;
- return this;
- }
-
@Override
protected RequestBody finalizeData()
{
DataObject body = DataObject.empty();
if (shouldUpdate(TOPIC) && topic != null)
body.put("topic", topic);
- if (shouldUpdate(PRIVACY_LEVEL))
- body.put("privacy_level", privacyLevel.getKey());
return getRequestBody(body);
}
}
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/StageInstanceActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/StageInstanceActionImpl.java
index 0773ddbd60..89e2fcac35 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/StageInstanceActionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/StageInstanceActionImpl.java
@@ -36,7 +36,6 @@ public class StageInstanceActionImpl extends RestActionImpl imple
{
private final StageChannel channel;
private String topic;
- private StageInstance.PrivacyLevel level = StageInstance.PrivacyLevel.GUILD_ONLY;
public StageInstanceActionImpl(StageChannel channel)
{
@@ -75,24 +74,12 @@ public StageInstanceAction setTopic(@Nonnull String topic)
return this;
}
- @Nonnull
- @Override
- @Deprecated
- public StageInstanceAction setPrivacyLevel(@Nonnull StageInstance.PrivacyLevel level)
- {
- Checks.notNull(level, "PrivacyLevel");
- Checks.check(level != StageInstance.PrivacyLevel.UNKNOWN, "The PrivacyLevel must not be UNKNOWN!");
- this.level = level;
- return this;
- }
-
@Override
protected RequestBody finalizeData()
{
DataObject body = DataObject.empty();
body.put("channel_id", channel.getId());
body.put("topic", topic);
- body.put("privacy_level", level.getKey());
return getRequestBody(body);
}
diff --git a/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java b/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
index b085f5d19a..3f7da91f4e 100644
--- a/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
+++ b/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
@@ -26,11 +26,19 @@
import net.dv8tion.jda.internal.entities.GuildImpl;
import org.apache.commons.collections4.CollectionUtils;
+import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
public class PermissionUtil
{
+ private static final long ALL_PERMISSIONS = Permission.getRaw(Permission.values());
+ private static final long ALL_CHANNEL_PERMISSIONS = Permission.getRaw(
+ Arrays.stream(Permission.values())
+ .filter(Permission::isChannel)
+ .collect(Collectors.toList()));
+
/**
* Checks if one given Member can interact with a 2nd given Member - in a permission sense (kick/ban/modify perms).
* This only checks the Role-Position and does not check the actual permission (kick/ban/manage_role/...)
@@ -305,14 +313,14 @@ public static long getEffectivePermission(Member member)
Checks.notNull(member, "Member");
if (member.isOwner())
- return Permission.ALL_PERMISSIONS;
+ return ALL_PERMISSIONS;
//Default to binary OR of all global permissions in this guild
long permission = member.getGuild().getPublicRole().getPermissionsRaw();
for (Role role : member.getRoles())
{
permission |= role.getPermissionsRaw();
if (isApplied(permission, Permission.ADMINISTRATOR.getRawValue()))
- return Permission.ALL_PERMISSIONS;
+ return ALL_PERMISSIONS;
}
// See https://discord.com/developers/docs/topics/permissions#permissions-for-timed-out-members
if (member.isTimedOut())
@@ -349,13 +357,13 @@ public static long getEffectivePermission(GuildChannel channel, Member member)
if (member.isOwner())
{
// Owner effectively has all permissions
- return Permission.ALL_PERMISSIONS;
+ return ALL_PERMISSIONS;
}
long permission = getEffectivePermission(member);
final long admin = Permission.ADMINISTRATOR.getRawValue();
if (isApplied(permission, admin))
- return Permission.ALL_PERMISSIONS;
+ return ALL_PERMISSIONS;
// MANAGE_CHANNEL allows to delete channels within a category (this is undocumented behavior)
if (channel instanceof ICategorizableChannel) {
@@ -413,7 +421,7 @@ public static long getEffectivePermission(GuildChannel channel, Role role)
long permissions = getExplicitPermission(channel, role);
if (isApplied(permissions, Permission.ADMINISTRATOR.getRawValue()))
- return Permission.ALL_CHANNEL_PERMISSIONS;
+ return ALL_CHANNEL_PERMISSIONS;
else if (!isApplied(permissions, Permission.VIEW_CHANNEL.getRawValue()))
return 0;
return permissions;
From 29589601deff73bc5461004d663bd324a480de60 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 17:23:32 +0100
Subject: [PATCH 09/17] Add tests for PermissionUtil (#2764)
---
.../jda/internal/utils/PermissionUtil.java | 4 +-
.../jda/test/util/PermissionUtilTest.java | 188 ++++++++++++++++++
2 files changed, 189 insertions(+), 3 deletions(-)
create mode 100644 src/test/java/net/dv8tion/jda/test/util/PermissionUtilTest.java
diff --git a/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java b/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
index 3f7da91f4e..67fcf28e16 100644
--- a/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
+++ b/src/main/java/net/dv8tion/jda/internal/utils/PermissionUtil.java
@@ -23,7 +23,6 @@
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
-import net.dv8tion.jda.internal.entities.GuildImpl;
import org.apache.commons.collections4.CollectionUtils;
import java.util.Arrays;
@@ -283,8 +282,7 @@ public static boolean checkPermission(IPermissionContainer channel, Member membe
Checks.notNull(member, "Member");
Checks.notNull(permissions, "Permissions");
- GuildImpl guild = (GuildImpl) channel.getGuild();
- checkGuild(guild, member.getGuild(), "Member");
+ checkGuild(channel.getGuild(), member.getGuild(), "Member");
long effectivePerms = getEffectivePermission(channel, member);
return isApplied(effectivePerms, Permission.getRaw(permissions));
diff --git a/src/test/java/net/dv8tion/jda/test/util/PermissionUtilTest.java b/src/test/java/net/dv8tion/jda/test/util/PermissionUtilTest.java
new file mode 100644
index 0000000000..f6b56893c4
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/util/PermissionUtilTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.test.util;
+
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.PermissionOverride;
+import net.dv8tion.jda.api.entities.Role;
+import net.dv8tion.jda.api.entities.channel.ChannelType;
+import net.dv8tion.jda.api.entities.channel.attribute.IPermissionContainer;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
+import net.dv8tion.jda.internal.utils.PermissionUtil;
+import net.dv8tion.jda.test.IntegrationTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+public class PermissionUtilTest extends IntegrationTest
+{
+ private static final EnumSet ALL_PERMISSIONS =
+ Arrays.stream(Permission.values())
+ .filter(perm -> perm != Permission.UNKNOWN)
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(Permission.class)));
+
+ private static final EnumSet ALL_CHANNEL_PERMISSIONS =
+ Arrays.stream(Permission.values())
+ .filter(Permission::isChannel)
+ .collect(Collectors.toCollection(() -> EnumSet.noneOf(Permission.class)));
+
+ private static final long ALL_PERMISSIONS_RAW = Permission.getRaw(ALL_PERMISSIONS);
+ private static final long ALL_CHANNEL_PERMISSIONS_RAW = Permission.getRaw(ALL_CHANNEL_PERMISSIONS);
+
+ @Mock
+ private Guild guild;
+ @Mock
+ private Member member;
+ @Mock
+ private TextChannel textChannel;
+ @Mock
+ private VoiceChannel voiceChannel;
+ @Mock
+ private Role role;
+ @Mock
+ private Role publicRole;
+
+ @Mock
+ private PermissionOverride roleOverride;
+ @Mock
+ private PermissionOverride publicRoleOverride;
+ @Mock
+ private PermissionOverride memberOverride;
+
+ @BeforeEach
+ void setupMocks()
+ {
+ when(member.getGuild()).thenReturn(guild);
+ when(guild.getPublicRole()).thenReturn(publicRole);
+ when(member.getRoles()).thenReturn(Collections.singletonList(role));
+
+ mockChannel(textChannel, ChannelType.TEXT);
+ mockChannel(voiceChannel, ChannelType.VOICE);
+ }
+
+ private void mockChannel(IPermissionContainer channel, ChannelType type)
+ {
+ when(channel.getType()).thenReturn(type);
+ when(channel.getGuild()).thenReturn(guild);
+ when(channel.getPermissionContainer()).thenReturn(channel);
+ when(channel.getPermissionOverride(any(Member.class))).thenReturn(memberOverride);
+ when(channel.getPermissionOverride(any(Role.class))).thenReturn(roleOverride);
+ when(channel.getPermissionOverride(eq(publicRole))).thenReturn(publicRoleOverride);
+ }
+
+ @Test
+ void testNoPermissionHasNoPermission()
+ {
+ when(role.getPermissionsRaw()).thenReturn(0L);
+
+ assertThat(PermissionUtil.getExplicitPermission(member)).isEqualTo(0L);
+ }
+
+ @Test
+ void testPermissionInheritedFromPublicRole()
+ {
+ when(role.getPermissionsRaw()).thenReturn(Permission.MESSAGE_HISTORY.getRawValue());
+ when(publicRole.getPermissionsRaw()).thenReturn(Permission.MESSAGE_SEND.getRawValue());
+
+ assertThat(PermissionUtil.getExplicitPermission(member))
+ .isEqualTo(Permission.MESSAGE_HISTORY.getRawValue() | Permission.MESSAGE_SEND.getRawValue());
+ }
+
+ @Test
+ void testAdminHasAllEffectivePermissions()
+ {
+ when(role.getPermissionsRaw()).thenReturn(Permission.ADMINISTRATOR.getRawValue());
+ when(roleOverride.getDeniedRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+ when(memberOverride.getDeniedRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+ when(publicRoleOverride.getDeniedRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+
+ assertThat(PermissionUtil.getEffectivePermission(member)).isEqualTo(ALL_PERMISSIONS_RAW);
+ assertThat(PermissionUtil.getEffectivePermission(textChannel, member)).isEqualTo(ALL_PERMISSIONS_RAW);
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(member, permission)).isTrue()
+ );
+ assertThat(ALL_CHANNEL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(textChannel, member, permission)).isTrue()
+ );
+ }
+
+ @Test
+ void testOwnerHasAllEffectivePermissions()
+ {
+ when(member.isOwner()).thenReturn(true);
+
+ assertThat(PermissionUtil.getEffectivePermission(member)).isEqualTo(ALL_PERMISSIONS_RAW);
+ assertThat(PermissionUtil.getEffectivePermission(textChannel, member)).isEqualTo(ALL_PERMISSIONS_RAW);
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(member, permission)).isTrue()
+ );
+ assertThat(ALL_CHANNEL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(textChannel, member, permission)).isTrue()
+ );
+ }
+
+ @Test
+ void testMemberDoesNotHaveViewChannel()
+ {
+ when(publicRole.getPermissionsRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+ when(publicRoleOverride.getDeniedRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+
+ // denies permissions in all channels
+
+ assertThat(PermissionUtil.getEffectivePermission(textChannel, member)).isEqualTo(0L);
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(textChannel, member, permission)).isFalse()
+ );
+
+ assertThat(PermissionUtil.getEffectivePermission(voiceChannel, member)).isEqualTo(0L);
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(voiceChannel, member, permission)).isFalse()
+ );
+ }
+
+ @Test
+ void testMemberDoesNotHaveConnectChannel()
+ {
+ when(publicRole.getPermissionsRaw()).thenReturn(Permission.VIEW_CHANNEL.getRawValue());
+ when(publicRoleOverride.getDeniedRaw()).thenReturn(Permission.VOICE_CONNECT.getRawValue());
+
+ // denies permissions in voice channels
+ assertThat(PermissionUtil.getEffectivePermission(voiceChannel, member)).isEqualTo(0L);
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(voiceChannel, member, permission)).isFalse()
+ );
+
+ // but should not affect text channel
+ assertThat(PermissionUtil.getEffectivePermission(textChannel, member)).isEqualTo(Permission.VIEW_CHANNEL.getRawValue());
+ assertThat(ALL_PERMISSIONS).allSatisfy(
+ permission -> assertThat(PermissionUtil.checkPermission(textChannel, member, permission)).isEqualTo(permission == Permission.VIEW_CHANNEL)
+ );
+ }
+}
From 26e1ea2d83a9db17ac9b633f98d30375caec646b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 17:25:44 +0100
Subject: [PATCH 10/17] Bump version to 5.2.0
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 7ed995a3b3..e7125cb3ba 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,7 +40,7 @@ plugins {
val javaVersion = JavaVersion.current()
-val versionObj = Version(major = "5", minor = "1", revision = "2", classifier = null)
+val versionObj = Version(major = "5", minor = "2", revision = "0", classifier = null)
val isGithubAction = System.getProperty("GITHUB_ACTION") != null || System.getenv("GITHUB_ACTION") != null
val isCI = System.getProperty("BUILD_NUMBER") != null // jenkins
|| System.getenv("BUILD_NUMBER") != null
From edb7991f629dac8a5766d03ab25e694ddcac4a3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 18:24:49 +0100
Subject: [PATCH 11/17] Fix missing or incorrect copyright headers (#2766)
---
src/examples/java/LocalizationExample.java | 16 ++++++++++++++++
.../jda/api/entities/emoji/ApplicationEmoji.java | 2 +-
.../update/GenericScheduledEventUpdateEvent.java | 16 ++++++++++++++++
.../GuildUpdateSafetyAlertsChannelEvent.java | 16 ++++++++++++++++
.../api/managers/ApplicationEmojiManager.java | 2 +-
.../pagination/EntitlementPaginationAction.java | 16 ++++++++++++++++
.../entities/emoji/ApplicationEmojiImpl.java | 8 ++------
.../managers/ApplicationEmojiManagerImpl.java | 2 +-
.../managers/GuildStickerManagerImpl.java | 16 ++++++++++++++++
.../ThreadChannelPaginationActionImpl.java | 16 ++++++++++++++++
.../jda/test/interactions/ButtonTests.java | 16 ++++++++++++++++
11 files changed, 117 insertions(+), 9 deletions(-)
diff --git a/src/examples/java/LocalizationExample.java b/src/examples/java/LocalizationExample.java
index f701d3df9a..1213408f34 100644
--- a/src/examples/java/LocalizationExample.java
+++ b/src/examples/java/LocalizationExample.java
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.interactions.DiscordLocale;
diff --git a/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java b/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
index 1b00e8c4fa..a97743f621 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/emoji/ApplicationEmoji.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ * 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.
diff --git a/src/main/java/net/dv8tion/jda/api/events/guild/scheduledevent/update/GenericScheduledEventUpdateEvent.java b/src/main/java/net/dv8tion/jda/api/events/guild/scheduledevent/update/GenericScheduledEventUpdateEvent.java
index b0d1a97b55..5e3b7acde5 100644
--- a/src/main/java/net/dv8tion/jda/api/events/guild/scheduledevent/update/GenericScheduledEventUpdateEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/guild/scheduledevent/update/GenericScheduledEventUpdateEvent.java
@@ -1,3 +1,19 @@
+/*
+ * 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.events.guild.scheduledevent.update;
import net.dv8tion.jda.api.JDA;
diff --git a/src/main/java/net/dv8tion/jda/api/events/guild/update/GuildUpdateSafetyAlertsChannelEvent.java b/src/main/java/net/dv8tion/jda/api/events/guild/update/GuildUpdateSafetyAlertsChannelEvent.java
index aaf92ae8e7..8ff105726b 100644
--- a/src/main/java/net/dv8tion/jda/api/events/guild/update/GuildUpdateSafetyAlertsChannelEvent.java
+++ b/src/main/java/net/dv8tion/jda/api/events/guild/update/GuildUpdateSafetyAlertsChannelEvent.java
@@ -1,3 +1,19 @@
+/*
+ * 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.events.guild.update;
import net.dv8tion.jda.api.JDA;
diff --git a/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java b/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
index 1d8e1def62..6f28f502b3 100644
--- a/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
+++ b/src/main/java/net/dv8tion/jda/api/managers/ApplicationEmojiManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ * 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.
diff --git a/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/EntitlementPaginationAction.java b/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/EntitlementPaginationAction.java
index bb291e9ff6..22cc80deee 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/EntitlementPaginationAction.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/restaction/pagination/EntitlementPaginationAction.java
@@ -1,3 +1,19 @@
+/*
+ * 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.requests.restaction.pagination;
import net.dv8tion.jda.api.entities.Entitlement;
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
index b5a6c5782b..6592940d32 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/emoji/ApplicationEmojiImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ * 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.
@@ -18,11 +18,7 @@
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.User;
-import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
-import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
-import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
-import net.dv8tion.jda.api.entities.emoji.EmojiUnion;
-import net.dv8tion.jda.api.entities.emoji.UnicodeEmoji;
+import net.dv8tion.jda.api.entities.emoji.*;
import net.dv8tion.jda.api.managers.ApplicationEmojiManager;
import net.dv8tion.jda.api.requests.RestAction;
import net.dv8tion.jda.api.requests.Route;
diff --git a/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java b/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
index 1a57920104..be14fac7c6 100644
--- a/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/managers/ApplicationEmojiManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
+ * 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.
diff --git a/src/main/java/net/dv8tion/jda/internal/managers/GuildStickerManagerImpl.java b/src/main/java/net/dv8tion/jda/internal/managers/GuildStickerManagerImpl.java
index 3386ca839b..fbba86faa1 100644
--- a/src/main/java/net/dv8tion/jda/internal/managers/GuildStickerManagerImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/managers/GuildStickerManagerImpl.java
@@ -1,3 +1,19 @@
+/*
+ * 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.managers;
import net.dv8tion.jda.api.Permission;
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java
index 8a66407a37..014e79b05b 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/restaction/pagination/ThreadChannelPaginationActionImpl.java
@@ -1,3 +1,19 @@
+/*
+ * 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.requests.restaction.pagination;
import gnu.trove.map.TLongObjectMap;
diff --git a/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
index e45fce90fe..b83667ce39 100644
--- a/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
+++ b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
@@ -1,3 +1,19 @@
+/*
+ * 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.test.interactions;
import net.dv8tion.jda.api.entities.SkuSnowflake;
From 53272b69388b844bd97f52854b5478d122594070 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 3 Nov 2024 18:26:53 +0100
Subject: [PATCH 12/17] Fix GuildManager#setSafetyAlertsChannel (#2765)
* Fix GuildManager#setSafetyAlertsChannel
* Add GuildManagerTest to ensure finalizeData is implemented
---
.../internal/managers/GuildManagerImpl.java | 2 +
.../net/dv8tion/jda/test/IntegrationTest.java | 5 +
.../jda/test/managers/GuildManagerTest.java | 147 ++++++++++++++++++
3 files changed, 154 insertions(+)
create mode 100644 src/test/java/net/dv8tion/jda/test/managers/GuildManagerTest.java
diff --git a/src/main/java/net/dv8tion/jda/internal/managers/GuildManagerImpl.java b/src/main/java/net/dv8tion/jda/internal/managers/GuildManagerImpl.java
index b3c7751046..6604ba8c1d 100644
--- a/src/main/java/net/dv8tion/jda/internal/managers/GuildManagerImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/managers/GuildManagerImpl.java
@@ -362,6 +362,8 @@ protected RequestBody finalizeData()
body.put("rules_channel_id", rulesChannel);
if (shouldUpdate(COMMUNITY_UPDATES_CHANNEL))
body.put("public_updates_channel_id", communityUpdatesChannel);
+ if (shouldUpdate(SAFETY_ALERTS_CHANNEL))
+ body.put("safety_alerts_channel_id", safetyAlertsChannel);
if (shouldUpdate(VERIFICATION_LEVEL))
body.put("verification_level", verificationLevel);
if (shouldUpdate(NOTIFICATION_LEVEL))
diff --git a/src/test/java/net/dv8tion/jda/test/IntegrationTest.java b/src/test/java/net/dv8tion/jda/test/IntegrationTest.java
index ebb0952457..0a961ced66 100644
--- a/src/test/java/net/dv8tion/jda/test/IntegrationTest.java
+++ b/src/test/java/net/dv8tion/jda/test/IntegrationTest.java
@@ -87,6 +87,11 @@ protected RestActionAssertions assertThatRequestFrom(@Nonnull RestAction> acti
.withNormalizedBody(this::normalizeRequestBody);
}
+ protected void assertThatNoRequestsWereSent()
+ {
+ verify(requester, never()).request(any());
+ }
+
protected void whenSuccess(RestActionImpl action, DataArray array, Consumer assertion)
{
Response response = mock();
diff --git a/src/test/java/net/dv8tion/jda/test/managers/GuildManagerTest.java b/src/test/java/net/dv8tion/jda/test/managers/GuildManagerTest.java
new file mode 100644
index 0000000000..778f6bab39
--- /dev/null
+++ b/src/test/java/net/dv8tion/jda/test/managers/GuildManagerTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.test.managers;
+
+import net.dv8tion.jda.api.Permission;
+import net.dv8tion.jda.api.entities.Guild;
+import net.dv8tion.jda.api.entities.Member;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
+import net.dv8tion.jda.api.managers.GuildManager;
+import net.dv8tion.jda.api.utils.data.DataObject;
+import net.dv8tion.jda.internal.managers.GuildManagerImpl;
+import net.dv8tion.jda.test.Constants;
+import net.dv8tion.jda.test.IntegrationTest;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static net.dv8tion.jda.api.requests.Method.PATCH;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatNoException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class GuildManagerTest extends IntegrationTest
+{
+ @Mock
+ private Guild guild;
+ @Mock
+ private Member selfMember;
+ @Mock
+ private TextChannel textChannel;
+ @Mock
+ private VoiceChannel voiceChannel;
+
+ @BeforeEach
+ void setupMocks()
+ {
+ when(guild.getJDA()).thenReturn(jda);
+ when(guild.getId()).thenReturn(Long.toUnsignedString(Constants.GUILD_ID));
+ when(guild.getSelfMember()).thenReturn(selfMember);
+ when(selfMember.hasPermission(any(Permission[].class))).thenReturn(true);
+ when(textChannel.getGuild()).thenReturn(guild);
+ when(textChannel.getId()).thenReturn(Long.toUnsignedString(Constants.CHANNEL_ID));
+ when(voiceChannel.getGuild()).thenReturn(guild);
+ when(voiceChannel.getId()).thenReturn(Long.toUnsignedString(Constants.CHANNEL_ID));
+ }
+
+ @Test
+ void callNoSetters()
+ {
+ GuildManagerImpl manager = new GuildManagerImpl(guild);
+ manager.queue();
+ assertThatNoRequestsWereSent();
+ }
+
+ @Test
+ void callEverySetter()
+ {
+ Set features = new HashSet<>(Arrays.asList("BANNER", "VERIFIED", "INVITE_SPLASH"));
+ when(guild.getFeatures()).thenReturn(features);
+
+ Set ignoredSetters = new HashSet<>(Arrays.asList(
+ "setFeatures", "setInvitesDisabled"
+ ));
+
+ AtomicInteger calledSetters = new AtomicInteger(0);
+ GuildManagerImpl manager = new GuildManagerImpl(guild);
+ for (Method method : GuildManager.class.getDeclaredMethods())
+ {
+ if (ignoredSetters.contains(method.getName()))
+ continue;
+
+ if (method.getName().startsWith("set") && method.getParameterCount() == 1)
+ {
+ assertThatNoException().describedAs("call " + method.getName()).isThrownBy(() -> {
+ Object mocked = getParameterForSetter(method);
+ method.invoke(manager, mocked);
+ calledSetters.incrementAndGet();
+ });
+ }
+ }
+
+ DataObject expectedBody = DataObject.empty()
+ .put("afk_channel_id", "125227483518861312")
+ .put("afk_timeout", 0)
+ .put("banner", null)
+ .put("default_message_notifications", 0)
+ .put("description", "test")
+ .put("explicit_content_filter", 0)
+ .put("icon", null)
+ .put("mfa_level", 0)
+ .put("name", "test")
+ .put("premium_progress_bar_enabled", true)
+ .put("public_updates_channel_id", "125227483518861312")
+ .put("safety_alerts_channel_id", "125227483518861312")
+ .put("rules_channel_id", "125227483518861312")
+ .put("splash", null)
+ .put("system_channel_id", "125227483518861312")
+ .put("verification_level", 0);
+
+ assertThatRequestFrom(manager)
+ .hasMethod(PATCH)
+ .hasBodyEqualTo(expectedBody)
+ .whenQueueCalled();
+
+ // Every setter should result in a new key in the body, make sure you updated finalizeData
+ assertThat(expectedBody.keys()).hasSize(calledSetters.get());
+ }
+
+ private Object getParameterForSetter(Method setter)
+ {
+ Class> paramType = setter.getParameters()[0].getType();
+ if (paramType == String.class)
+ return "test";
+ if (paramType == Boolean.TYPE)
+ return true;
+ if (paramType == Integer.TYPE)
+ return 42;
+ if (TextChannel.class.isAssignableFrom(paramType))
+ return textChannel;
+ if (VoiceChannel.class.isAssignableFrom(paramType))
+ return voiceChannel;
+ return mock(paramType);
+ }
+}
From ee7b6b986b31ce5ae1e4fe1f02bb8154eadaeaf7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 10 Nov 2024 11:08:43 +0100
Subject: [PATCH 13/17] Correctly handle disabled intent in setEnabledIntents
(#2767)
* Correctly handle disabled intent in setEnabledIntents
* Add test coverage for setEnabledIntents
* Expand test for deprecated intent
---
.../java/net/dv8tion/jda/api/JDABuilder.java | 10 ++--
.../sharding/DefaultShardManagerBuilder.java | 10 ++--
.../net/dv8tion/jda/test/JDABuilderTest.java | 47 ++++++++++++++++---
3 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/JDABuilder.java b/src/main/java/net/dv8tion/jda/api/JDABuilder.java
index 85ec2396f2..7b77668415 100644
--- a/src/main/java/net/dv8tion/jda/api/JDABuilder.java
+++ b/src/main/java/net/dv8tion/jda/api/JDABuilder.java
@@ -1554,7 +1554,7 @@ public JDABuilder setDisabledIntents(@Nullable Collection intents
{
this.intents = GatewayIntent.ALL_INTENTS;
if (intents != null)
- this.intents &= ~GatewayIntent.getRaw(intents);
+ this.intents = 1 | (GatewayIntent.ALL_INTENTS & ~GatewayIntent.getRaw(intents));
return this;
}
@@ -1646,7 +1646,7 @@ public JDABuilder setEnabledIntents(@Nonnull GatewayIntent intent, @Nonnull Gate
Checks.notNull(intent, "Intents");
Checks.noneNull(intents, "Intents");
EnumSet set = EnumSet.of(intent, intents);
- return setDisabledIntents(EnumSet.complementOf(set));
+ return setEnabledIntents(set);
}
/**
@@ -1673,11 +1673,9 @@ public JDABuilder setEnabledIntents(@Nonnull GatewayIntent intent, @Nonnull Gate
public JDABuilder setEnabledIntents(@Nullable Collection intents)
{
if (intents == null || intents.isEmpty())
- setDisabledIntents(EnumSet.allOf(GatewayIntent.class));
- else if (intents instanceof EnumSet)
- setDisabledIntents(EnumSet.complementOf((EnumSet) intents));
+ this.intents = 1;
else
- setDisabledIntents(EnumSet.complementOf(EnumSet.copyOf(intents)));
+ this.intents = 1 | GatewayIntent.getRaw(intents);
return this;
}
diff --git a/src/main/java/net/dv8tion/jda/api/sharding/DefaultShardManagerBuilder.java b/src/main/java/net/dv8tion/jda/api/sharding/DefaultShardManagerBuilder.java
index 4a97b48894..175ab9ff24 100644
--- a/src/main/java/net/dv8tion/jda/api/sharding/DefaultShardManagerBuilder.java
+++ b/src/main/java/net/dv8tion/jda/api/sharding/DefaultShardManagerBuilder.java
@@ -2018,7 +2018,7 @@ public DefaultShardManagerBuilder setDisabledIntents(@Nullable Collection set = EnumSet.of(intent, intents);
- return setDisabledIntents(EnumSet.complementOf(set));
+ return setEnabledIntents(set);
}
/**
@@ -2137,11 +2137,9 @@ public DefaultShardManagerBuilder setEnabledIntents(@Nonnull GatewayIntent inten
public DefaultShardManagerBuilder setEnabledIntents(@Nullable Collection intents)
{
if (intents == null || intents.isEmpty())
- setDisabledIntents(EnumSet.allOf(GatewayIntent.class));
- else if (intents instanceof EnumSet)
- setDisabledIntents(EnumSet.complementOf((EnumSet) intents));
+ this.intents = 1;
else
- setDisabledIntents(EnumSet.complementOf(EnumSet.copyOf(intents)));
+ this.intents = 1 | GatewayIntent.getRaw(intents);
return this;
}
diff --git a/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
index 3bf2a7d194..34f833603a 100644
--- a/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
+++ b/src/test/java/net/dv8tion/jda/test/JDABuilderTest.java
@@ -102,7 +102,6 @@ void testRequiredIntentForCacheFlagMissing(CacheFlag cacheFlag)
}
}
-
@ParameterizedTest
@EnumSource(CacheFlag.class)
void testRequiredIntentForCacheFlagEnabled(CacheFlag cacheFlag)
@@ -113,6 +112,14 @@ void testRequiredIntentForCacheFlagEnabled(CacheFlag cacheFlag)
builder.enableCache(cacheFlag);
assertThatNoException().isThrownBy(builder::checkIntents);
+
+ builder = new TestJDABuilder(0);
+ builder.applyIntents();
+ if (requiredIntent != null)
+ builder.setEnabledIntents(requiredIntent);
+ builder.enableCache(cacheFlag);
+
+ assertThatNoException().isThrownBy(builder::checkIntents);
}
@Test
@@ -141,19 +148,40 @@ void testChunkingWithMissingIntent()
assertThat(logs).contains("Member chunking is disabled due to missing GUILD_MEMBERS intent.");
}
- @Test
+ @EnumSource
+ @ParameterizedTest
@SuppressWarnings("deprecation")
- void testDeprecatedIntentDoesNotDisableCache()
+ void testDeprecatedIntentDoesNotDisableCache(IntentTestCase testCase)
{
- TestJDABuilder builder = new TestJDABuilder(GatewayIntent.GUILD_EMOJIS_AND_STICKERS.getRawValue());
- builder.applyIntents();
+ TestJDABuilder builder;
+
+ switch (testCase)
+ {
+ case PASSED_TO_FACTORY:
+ builder = new TestJDABuilder(GatewayIntent.GUILD_EMOJIS_AND_STICKERS.getRawValue());
+ builder.applyIntents();
+ break;
+ case PASSED_TO_RELATIVE:
+ builder = new TestJDABuilder(0);
+ builder.applyLight();
+ builder.enableIntents(GatewayIntent.GUILD_EMOJIS_AND_STICKERS);
+ builder.enableCache(CacheFlag.EMOJI, CacheFlag.STICKER);
+ break;
+ case PASSED_TO_SETTER:
+ builder = new TestJDABuilder(0);
+ builder.applyLight();
+ builder.setEnabledIntents(GatewayIntent.GUILD_EMOJIS_AND_STICKERS);
+ builder.enableCache(CacheFlag.EMOJI, CacheFlag.STICKER);
+ break;
+ default:
+ throw new AssertionError("Unexpected test case " + testCase);
+ }
List logs = captureLogging(() ->
assertThatNoException().isThrownBy(builder::checkIntents)
);
assertThat(logs)
- .isNotEmpty()
.noneMatch(log -> log.contains("CacheFlag." + CacheFlag.EMOJI))
.noneMatch(log -> log.contains("CacheFlag." + CacheFlag.STICKER));
}
@@ -208,4 +236,11 @@ public void checkIntents()
super.checkIntents();
}
}
+
+ enum IntentTestCase
+ {
+ PASSED_TO_FACTORY,
+ PASSED_TO_RELATIVE,
+ PASSED_TO_SETTER;
+ }
}
From 466a66b6a7c9868feecfb356d2d0303860af2273 Mon Sep 17 00:00:00 2001
From: 7410 <85879080+O7410@users.noreply.github.com>
Date: Sun, 10 Nov 2024 12:09:37 +0200
Subject: [PATCH 14/17] Fix javadoc typos in MessageRequest (#2768)
---
.../net/dv8tion/jda/api/utils/messages/MessageRequest.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/utils/messages/MessageRequest.java b/src/main/java/net/dv8tion/jda/api/utils/messages/MessageRequest.java
index 8bd9db2f86..ef2708b70b 100644
--- a/src/main/java/net/dv8tion/jda/api/utils/messages/MessageRequest.java
+++ b/src/main/java/net/dv8tion/jda/api/utils/messages/MessageRequest.java
@@ -426,13 +426,13 @@ default R setFiles(@Nonnull FileUpload... files)
// Allowed Mentions Methods
/**
- * Whether to mention the used, when replying to a message.
+ * Whether to mention the user, when replying to a message.
*
This only matters in combination with {@link net.dv8tion.jda.api.requests.restaction.MessageCreateAction#setMessageReference(Message) MessageCreateAction.setMessageReference(...)}!
*
* This is true by default but can be configured using {@link #setDefaultMentionRepliedUser(boolean)}!
*
* @param mention
- * True, to mention the author if the referenced message
+ * True, to mention the author in the referenced message
*
* @return The same instance for chaining
*/
From 51f907c8305e30f4cfb81ec7058bf782919e209e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 10 Nov 2024 12:16:24 +0100
Subject: [PATCH 15/17] Ensure label cannot be null in ButtonImpl (#2771)
---
.../components/buttons/Button.java | 34 ++--
.../interactions/component/ButtonImpl.java | 16 +-
.../jda/test/interactions/ButtonTests.java | 192 +++++++++++++-----
3 files changed, 163 insertions(+), 79 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
index deddd28f0c..dcf7628394 100644
--- a/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
+++ b/src/main/java/net/dv8tion/jda/api/interactions/components/buttons/Button.java
@@ -171,7 +171,7 @@ default Button withDisabled(boolean disabled)
@CheckReturnValue
default Button withEmoji(@Nullable Emoji emoji)
{
- return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), null, isDisabled(), emoji).checkValid();
+ return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), getSku(), isDisabled(), emoji).checkValid();
}
/**
@@ -217,7 +217,7 @@ default Button withLabel(@Nonnull String label)
@CheckReturnValue
default Button withId(@Nonnull String id)
{
- return new ButtonImpl(id, getLabel(), getStyle(), null, null, isDisabled(), getEmoji()).checkValid();
+ return new ButtonImpl(id, getLabel(), getStyle(), getUrl(), getSku(), isDisabled(), getEmoji()).checkValid();
}
/**
@@ -240,7 +240,7 @@ default Button withId(@Nonnull String id)
@CheckReturnValue
default Button withUrl(@Nonnull String url)
{
- return new ButtonImpl(null, getLabel(), getStyle(), url, null, isDisabled(), getEmoji()).checkValid();
+ return new ButtonImpl(getId(), getLabel(), getStyle(), url, getSku(), isDisabled(), getEmoji()).checkValid();
}
/**
@@ -258,7 +258,7 @@ default Button withUrl(@Nonnull String url)
@CheckReturnValue
default Button withSku(@Nonnull SkuSnowflake sku)
{
- return new ButtonImpl(null, "", getStyle(), null, sku, isDisabled(), null).checkValid();
+ return new ButtonImpl(getId(), getLabel(), getStyle(), getUrl(), sku, isDisabled(), getEmoji()).checkValid();
}
/**
@@ -345,7 +345,7 @@ static Button primary(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button primary(@Nonnull String id, @Nonnull Emoji emoji)
{
- return new ButtonImpl(id, "", ButtonStyle.PRIMARY, false, emoji).checkValid();
+ return new ButtonImpl(id, null, ButtonStyle.PRIMARY, false, emoji).checkValid();
}
/**
@@ -399,7 +399,7 @@ static Button secondary(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button secondary(@Nonnull String id, @Nonnull Emoji emoji)
{
- return new ButtonImpl(id, "", ButtonStyle.SECONDARY, false, emoji).checkValid();
+ return new ButtonImpl(id, null, ButtonStyle.SECONDARY, false, emoji).checkValid();
}
/**
@@ -453,7 +453,7 @@ static Button success(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button success(@Nonnull String id, @Nonnull Emoji emoji)
{
- return new ButtonImpl(id, "", ButtonStyle.SUCCESS, false, emoji).checkValid();
+ return new ButtonImpl(id, null, ButtonStyle.SUCCESS, false, emoji).checkValid();
}
/**
@@ -507,7 +507,7 @@ static Button danger(@Nonnull String id, @Nonnull String label)
@Nonnull
static Button danger(@Nonnull String id, @Nonnull Emoji emoji)
{
- return new ButtonImpl(id, "", ButtonStyle.DANGER, false, emoji).checkValid();
+ return new ButtonImpl(id, null, ButtonStyle.DANGER, false, emoji).checkValid();
}
/**
@@ -567,7 +567,7 @@ static Button link(@Nonnull String url, @Nonnull String label)
@Nonnull
static Button link(@Nonnull String url, @Nonnull Emoji emoji)
{
- return new ButtonImpl(null, "", ButtonStyle.LINK, url, null, false, emoji).checkValid();
+ return new ButtonImpl(null, null, ButtonStyle.LINK, url, null, false, emoji).checkValid();
}
/**
@@ -589,7 +589,7 @@ static Button link(@Nonnull String url, @Nonnull Emoji emoji)
@Nonnull
static Button premium(@Nonnull SkuSnowflake sku)
{
- return new ButtonImpl(null, "", ButtonStyle.PREMIUM, null, sku, false, null).checkValid();
+ return new ButtonImpl(null, null, ButtonStyle.PREMIUM, null, sku, false, null).checkValid();
}
/**
@@ -661,7 +661,7 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull E
Checks.check(style != ButtonStyle.PREMIUM, "Premium buttons don't support emojis");
if (style == ButtonStyle.LINK)
return link(idOrUrl, emoji);
- return new ButtonImpl(idOrUrl, "", style, false, emoji).checkValid();
+ return new ButtonImpl(idOrUrl, null, style, false, emoji).checkValid();
}
/**
@@ -697,10 +697,16 @@ static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrl, @Nonnull E
@Nonnull
static Button of(@Nonnull ButtonStyle style, @Nonnull String idOrUrlOrSku, @Nullable String label, @Nullable Emoji emoji)
{
- if (style == ButtonStyle.LINK)
+ Checks.notNull(style, "ButtonStyle");
+
+ switch (style)
+ {
+ case LINK:
return new ButtonImpl(null, label, style, idOrUrlOrSku, null, false, emoji).checkValid();
- if (style == ButtonStyle.PREMIUM)
+ case PREMIUM:
return new ButtonImpl(null, label, style, null, SkuSnowflake.fromId(idOrUrlOrSku), false, emoji).checkValid();
- return new ButtonImpl(idOrUrlOrSku, label, style, null, null, false, emoji).checkValid();
+ default:
+ return new ButtonImpl(idOrUrlOrSku, label, style, null, null, false, emoji).checkValid();
+ }
}
}
diff --git a/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java b/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
index c2d81caa94..ab407c6ea6 100644
--- a/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/interactions/component/ButtonImpl.java
@@ -60,9 +60,9 @@ public ButtonImpl(String id, String label, ButtonStyle style, boolean disabled,
public ButtonImpl(String id, String label, ButtonStyle style, String url, SkuSnowflake sku, boolean disabled, Emoji emoji)
{
this.id = id;
- this.label = label;
+ this.label = label == null ? "" : label;
this.style = style;
- this.url = url; // max length 512
+ this.url = url;
this.sku = sku;
this.disabled = disabled;
this.emoji = (EmojiUnion) emoji;
@@ -71,6 +71,7 @@ public ButtonImpl(String id, String label, ButtonStyle style, String url, SkuSno
public ButtonImpl checkValid()
{
Checks.notNull(style, "Style");
+ Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
Checks.check(style != ButtonStyle.UNKNOWN, "Cannot make button with unknown style!");
switch (style)
@@ -81,7 +82,7 @@ public ButtonImpl checkValid()
case DANGER:
Checks.check(url == null, "Cannot set an URL on action buttons");
Checks.check(sku == null, "Cannot set an SKU on action buttons");
- Checks.check(emoji != null || (label != null && !label.isEmpty()), "Action buttons must have either an emoji or label");
+ Checks.check(emoji != null || !label.isEmpty(), "Action buttons must have either an emoji or label");
Checks.notEmpty(id, "Id");
Checks.notLonger(id, ID_MAX_LENGTH, "Id");
break;
@@ -89,7 +90,7 @@ public ButtonImpl checkValid()
Checks.check(id == null, "Cannot set an ID on link buttons");
Checks.check(url != null, "You must set an URL on link buttons");
Checks.check(sku == null, "Cannot set an SKU on link buttons");
- Checks.check(emoji != null || (label != null && !label.isEmpty()), "Link buttons must have either an emoji or label");
+ Checks.check(emoji != null || !label.isEmpty(), "Link buttons must have either an emoji or label");
Checks.notEmpty(url, "URL");
Checks.notLonger(url, URL_MAX_LENGTH, "URL");
break;
@@ -97,16 +98,11 @@ public ButtonImpl checkValid()
Checks.check(id == null, "Cannot set an ID on premium buttons");
Checks.check(url == null, "Cannot set an URL on premium buttons");
Checks.check(emoji == null, "Cannot set an emoji on premium buttons");
- Checks.check(label == null || label.isEmpty(), "Cannot set a label on premium buttons");
+ Checks.check(label.isEmpty(), "Cannot set a label on premium buttons");
Checks.notNull(sku, "SKU");
break;
}
- if (label != null)
- {
- Checks.notLonger(label, LABEL_MAX_LENGTH, "Label");
- }
-
return this;
}
diff --git a/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
index b83667ce39..7b25271072 100644
--- a/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
+++ b/src/test/java/net/dv8tion/jda/test/interactions/ButtonTests.java
@@ -22,9 +22,9 @@
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle;
import net.dv8tion.jda.internal.interactions.component.ButtonImpl;
-import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
@@ -32,6 +32,7 @@
import static net.dv8tion.jda.api.interactions.components.buttons.ButtonStyle.*;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class ButtonTests
@@ -42,28 +43,29 @@ public class ButtonTests
private static final String EXAMPLE_LABEL = "Label";
private static final SkuSnowflake EXAMPLE_SKU = SkuSnowflake.fromId(1234);
- @MethodSource("testButtonValid")
+ @MethodSource("validButtons")
@ParameterizedTest
void testButtonValid(ButtonStyle style, String id, String label, String url, SkuSnowflake sku, Emoji emoji)
{
ButtonImpl button = new ButtonImpl(id, label, style, url, sku, false, emoji);
assertDoesNotThrow(button::checkValid);
+ assertDoesNotThrow(button::toData);
}
- static Stream testButtonValid()
+ static Stream validButtons()
{
// The following button configurations are valid:
return Stream.of(
// Normal button; id, either label, emoji, label+emoji
- Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, null, null),
- Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, null, EXAMPLE_EMOJI),
- Arguments.of(PRIMARY, "id", "", null, null, EXAMPLE_EMOJI),
+ arguments(PRIMARY, "id", EXAMPLE_LABEL, null, null, null),
+ arguments(PRIMARY, "id", EXAMPLE_LABEL, null, null, EXAMPLE_EMOJI),
+ arguments(PRIMARY, "id", null, null, null, EXAMPLE_EMOJI),
// Link button; url, either label, emoji, label+emoji
- Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, null),
- Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, EXAMPLE_EMOJI),
- Arguments.of(LINK, null, "", EXAMPLE_URL, null, EXAMPLE_EMOJI),
+ arguments(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ arguments(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, null, EXAMPLE_EMOJI),
+ arguments(LINK, null, null, EXAMPLE_URL, null, EXAMPLE_EMOJI),
// Premium button doesn't have anything
- Arguments.of(PREMIUM, null, "", null, EXAMPLE_SKU, null)
+ arguments(PREMIUM, null, null, null, EXAMPLE_SKU, null)
);
}
@@ -80,78 +82,158 @@ static Stream testButtonInvalid()
// The following button configuration will fail when:
return Stream.of(
// Normal button; has no id, has neither label/emoji, has url, has sku
- Arguments.of(PRIMARY, null, EXAMPLE_LABEL, null, null, null),
- Arguments.of(PRIMARY, "id", "", null, null, null),
- Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
- Arguments.of(PRIMARY, "id", EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
+ arguments(PRIMARY, null, EXAMPLE_LABEL, null, null, null),
+ arguments(PRIMARY, "id", "", null, null, null),
+ arguments(PRIMARY, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ arguments(PRIMARY, "id", EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
// Link button; has no url, has id, has sku
- Arguments.of(LINK, null, EXAMPLE_LABEL, null, null, null),
- Arguments.of(LINK, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
- Arguments.of(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, EXAMPLE_SKU, null),
+ arguments(LINK, null, EXAMPLE_LABEL, null, null, null),
+ arguments(LINK, "id", EXAMPLE_LABEL, EXAMPLE_URL, null, null),
+ arguments(LINK, null, EXAMPLE_LABEL, EXAMPLE_URL, EXAMPLE_SKU, null),
// Premium button; has no sku, has id, has url, has label, has emoji
- Arguments.of(PREMIUM, null, "", null, null, null),
- Arguments.of(PREMIUM, "id", "", null, EXAMPLE_SKU, null),
- Arguments.of(PREMIUM, null, "", "url", EXAMPLE_SKU, null),
- Arguments.of(PREMIUM, null, EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
- Arguments.of(PREMIUM, null, "", null, EXAMPLE_SKU, EXAMPLE_EMOJI)
+ arguments(PREMIUM, null, "", null, null, null),
+ arguments(PREMIUM, "id", "", null, EXAMPLE_SKU, null),
+ arguments(PREMIUM, null, "", "url", EXAMPLE_SKU, null),
+ arguments(PREMIUM, null, EXAMPLE_LABEL, null, EXAMPLE_SKU, null),
+ arguments(PREMIUM, null, "", null, EXAMPLE_SKU, EXAMPLE_EMOJI)
);
}
- @Test
- void testPrimaryWithSku()
+
+ @MethodSource
+ @ParameterizedTest
+ void testWithId(Button button, boolean shouldThrow)
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.primary("id", EXAMPLE_LABEL).withSku(EXAMPLE_SKU));
+ if (shouldThrow)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withId("valid-id"));
+ else
+ assertDoesNotThrow(() -> button.withId("valid-id"));
}
- @Test
- void testPrimaryWithUrl()
+ static Stream testWithId()
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.primary("id", EXAMPLE_LABEL).withUrl(EXAMPLE_URL));
+ return Stream.of(
+ arguments(Button.primary(EXAMPLE_ID, "Primary"), false),
+ arguments(Button.link(EXAMPLE_URL, "Link"), true),
+ arguments(Button.premium(EXAMPLE_SKU), true)
+ );
}
- @Test
- void linkWithId()
+ @MethodSource
+ @ParameterizedTest
+ void testWithUrl(Button button, boolean shouldThrow)
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.link(EXAMPLE_URL, EXAMPLE_LABEL).withId(EXAMPLE_ID));
+ if (shouldThrow)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withUrl(EXAMPLE_URL));
+ else
+ assertDoesNotThrow(() -> button.withUrl(EXAMPLE_URL));
}
-
- @Test
- void linkWithSku()
+
+ static Stream testWithUrl()
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.link(EXAMPLE_URL, EXAMPLE_LABEL).withSku(EXAMPLE_SKU));
+ return Stream.of(
+ arguments(Button.primary(EXAMPLE_ID, "Primary"), true),
+ arguments(Button.link(EXAMPLE_URL, "Link"), false),
+ arguments(Button.premium(EXAMPLE_SKU), true)
+ );
}
- @Test
- void testPremiumWithId()
+ @MethodSource
+ @ParameterizedTest
+ void testWithSku(Button button, boolean shouldThrow)
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withLabel(EXAMPLE_ID));
+ if (shouldThrow)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withSku(EXAMPLE_SKU));
+ else
+ assertDoesNotThrow(() -> button.withSku(EXAMPLE_SKU));
}
- @Test
- void testPremiumWithLabel()
+ static Stream testWithSku()
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withLabel(EXAMPLE_LABEL));
+ return Stream.of(
+ arguments(Button.primary(EXAMPLE_ID, "Primary"), true),
+ arguments(Button.link(EXAMPLE_URL, "Link"), true),
+ arguments(Button.premium(EXAMPLE_SKU), false)
+ );
}
+ @MethodSource
+ @ParameterizedTest
+ void testWithLabel(Button button, boolean shouldThrow)
+ {
+ if (shouldThrow)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withLabel(EXAMPLE_LABEL));
+ else
+ assertDoesNotThrow(() -> button.withLabel(EXAMPLE_LABEL));
+ }
- @Test
- void testPremiumWithEmoji()
+ static Stream testWithLabel()
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withEmoji(EXAMPLE_EMOJI));
+ return Stream.of(
+ arguments(Button.primary(EXAMPLE_ID, "Primary"), false),
+ arguments(Button.link(EXAMPLE_URL, "Link"), false),
+ arguments(Button.premium(EXAMPLE_SKU), true)
+ );
}
+ @MethodSource
+ @ParameterizedTest
+ void testWithEmoji(Button button, boolean shouldThrow)
+ {
+ if (shouldThrow)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withEmoji(EXAMPLE_EMOJI));
+ else
+ assertDoesNotThrow(() -> button.withEmoji(EXAMPLE_EMOJI));
+ }
- @Test
- void testPremiumWithUrl()
+ static Stream testWithEmoji()
+ {
+ return Stream.of(
+ arguments(Button.primary(EXAMPLE_ID, "Primary"), false),
+ arguments(Button.link(EXAMPLE_URL, "Link"), false),
+ arguments(Button.premium(EXAMPLE_SKU), true)
+ );
+ }
+
+ @EnumSource
+ @ParameterizedTest
+ void testWithStyleLinkToOther(ButtonStyle style)
+ {
+ Button button = Button.link(EXAMPLE_URL, "Label");
+ if (style == LINK)
+ assertDoesNotThrow(() -> button.withStyle(style));
+ else
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withStyle(style));
+ }
+
+ @EnumSource
+ @ParameterizedTest
+ void testWithStylePremiumToOther(ButtonStyle style)
+ {
+ Button button = Button.premium(EXAMPLE_SKU);
+ if (style == PREMIUM)
+ assertDoesNotThrow(() -> button.withStyle(style));
+ else
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withStyle(style));
+ }
+
+ @EnumSource
+ @ParameterizedTest
+ void testWithStyleColorToOther(ButtonStyle style)
+ {
+ Button button = Button.primary(EXAMPLE_ID, EXAMPLE_LABEL);
+ if (style == PREMIUM || style == LINK || style == UNKNOWN)
+ assertThatIllegalArgumentException().isThrownBy(() -> button.withStyle(style));
+ else
+ assertDoesNotThrow(() -> button.withStyle(style));
+ }
+
+ @MethodSource("validButtons")
+ @ParameterizedTest
+ void testWithDisabled(ButtonStyle style, String id, String label, String url, SkuSnowflake sku, Emoji emoji)
{
- assertThatIllegalArgumentException()
- .isThrownBy(() -> Button.premium(EXAMPLE_SKU).withUrl(EXAMPLE_URL));
+ Button button = new ButtonImpl(id, label, style, url, sku, false, emoji);
+ assertDoesNotThrow(() -> button.withDisabled(true));
+ assertDoesNotThrow(() -> button.withDisabled(false));
}
}
From 411d0c58e3faa3b3eef2661ec2b336fd2ec2ee10 Mon Sep 17 00:00:00 2001
From: Marcel Korzonek
Date: Sun, 10 Nov 2024 12:18:08 +0100
Subject: [PATCH 16/17] Handle user in EntityBuilder#createApplicationEmoji as
optional (#2769)
---
.../net/dv8tion/jda/internal/JDAImpl.java | 22 ++++++++++++++-----
.../jda/internal/entities/EntityBuilder.java | 6 ++---
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/src/main/java/net/dv8tion/jda/internal/JDAImpl.java b/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
index 9c1be36130..c03cf9f8f7 100644
--- a/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/JDAImpl.java
@@ -693,7 +693,8 @@ public RestAction createApplicationEmoji(@Nonnull String name,
return new RestActionImpl<>(this, route, body, (response, request) ->
{
final DataObject obj = response.getObject();
- return entityBuilder.createApplicationEmoji(this, obj);
+ final User selfUser = getSelfUser();
+ return entityBuilder.createApplicationEmoji(this, obj, selfUser);
});
}
@@ -710,7 +711,12 @@ public RestAction> retrieveApplicationEmojis()
{
try
{
- list.add(entityBuilder.createApplicationEmoji(this, emojis.getObject(i)));
+ final DataObject emoji = emojis.getObject(i);
+ final User owner = emoji.optObject("user")
+ .map(entityBuilder::createUser)
+ .orElse(null);
+
+ list.add(entityBuilder.createApplicationEmoji(this, emoji, owner));
}
catch (ParsingException e)
{
@@ -728,9 +734,15 @@ public RestAction retrieveApplicationEmojiById(@Nonnull String
{
Checks.isSnowflake(emojiId);
Route.CompiledRoute route = Route.Applications.GET_APPLICATION_EMOJI.compile(getSelfUser().getApplicationId(), emojiId);
- return new RestActionImpl<>(this, route,
- (response, request) -> entityBuilder.createApplicationEmoji(this, response.getObject())
- );
+ return new RestActionImpl<>(this, route, (response, request) ->
+ {
+ final DataObject emoji = response.getObject();
+ final User owner = emoji.optObject("user")
+ .map(entityBuilder::createUser)
+ .orElse(null);
+
+ return entityBuilder.createApplicationEmoji(this, emoji, owner);
+ });
}
@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 7fb94a3abe..2f0cfd65a5 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
@@ -1021,11 +1021,11 @@ public RichCustomEmojiImpl createEmoji(GuildImpl guildObj, DataObject json)
.setAvailable(json.getBoolean("available", true));
}
- public ApplicationEmojiImpl createApplicationEmoji(JDAImpl api, DataObject json)
+ public ApplicationEmojiImpl createApplicationEmoji(JDAImpl api, DataObject json, User owner)
{
final long emojiId = json.getUnsignedLong("id");
- final User user = createUser(json.getObject("user"));
- return new ApplicationEmojiImpl(emojiId, api, user)
+
+ return new ApplicationEmojiImpl(emojiId, api, owner)
.setAnimated(json.getBoolean("animated"))
.setName(json.getString("name"));
}
From 39e1a6e9d2e388823ce4d97c6b1d1d97587357d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20Spie=C3=9F?=
Date: Sun, 10 Nov 2024 17:18:22 +0100
Subject: [PATCH 17/17] Bump version to 5.2.1
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index e7125cb3ba..f70c3cf18c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -40,7 +40,7 @@ plugins {
val javaVersion = JavaVersion.current()
-val versionObj = Version(major = "5", minor = "2", revision = "0", classifier = null)
+val versionObj = Version(major = "5", minor = "2", revision = "1", classifier = null)
val isGithubAction = System.getProperty("GITHUB_ACTION") != null || System.getenv("GITHUB_ACTION") != null
val isCI = System.getProperty("BUILD_NUMBER") != null // jenkins
|| System.getenv("BUILD_NUMBER") != null