Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poll support #2649

Merged
merged 31 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
168c291
First pass on poll handling
MinnDevelopment Apr 13, 2024
dc7afa1
Add poll expire endpoint
MinnDevelopment Apr 13, 2024
ce4dfc9
Add poll intents
MinnDevelopment Apr 13, 2024
99d760f
Add poll request data
MinnDevelopment Apr 13, 2024
0a6cc8a
Fix temporary issues
MinnDevelopment Apr 13, 2024
451dcdd
Add poll builder
MinnDevelopment Apr 13, 2024
c51ae8b
Adjust tests
MinnDevelopment Apr 13, 2024
7ae834f
Add some documentation
MinnDevelopment Apr 13, 2024
4c98757
More docs
MinnDevelopment Apr 13, 2024
452cd9e
Update error message
MinnDevelopment Apr 13, 2024
cdf047c
Add send shortcuts for polls
MinnDevelopment Apr 13, 2024
a9f85ee
Use correct setter for duration overload
MinnDevelopment Apr 13, 2024
a81987c
Update test case
MinnDevelopment Apr 13, 2024
6c7241c
Add new test case
MinnDevelopment Apr 13, 2024
cc2aac5
Add poll checks tests
MinnDevelopment Apr 13, 2024
1af1365
Adjust max duration error
MinnDevelopment Apr 13, 2024
540c018
Refactor assertions
MinnDevelopment Apr 13, 2024
b1b86b9
Refactor checks assertions
MinnDevelopment Apr 13, 2024
827de6c
Refactor duration checks
MinnDevelopment Apr 13, 2024
b336ec2
Add poll voters pagination
MinnDevelopment Apr 13, 2024
f6724eb
Make answer id read-only
MinnDevelopment Apr 13, 2024
1732d74
Cleanup MessageCreateActionTest#testPollOnly
MinnDevelopment Apr 13, 2024
a737645
Add commons lang3 as test dependency
MinnDevelopment Apr 14, 2024
24ffde1
Add docs for intents
MinnDevelopment Apr 15, 2024
5012349
Apply api changes
MinnDevelopment Apr 15, 2024
e757b74
Add new permission and uncomment intents
MinnDevelopment Apr 18, 2024
c7e7f9e
Add new events
MinnDevelopment Apr 20, 2024
38882fb
Merge remote-tracking branch 'origin/master' into feature/polls
MinnDevelopment Apr 20, 2024
6bfcaaa
Add event handler test
MinnDevelopment Apr 20, 2024
dfe5af9
Rename route to END_POLL
MinnDevelopment Apr 20, 2024
04c2336
Update ErrorResponse enum
MinnDevelopment Apr 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/Message.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import net.dv8tion.jda.api.entities.emoji.CustomEmoji;
import net.dv8tion.jda.api.entities.emoji.Emoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.messages.MessagePoll;
import net.dv8tion.jda.api.entities.sticker.GuildSticker;
import net.dv8tion.jda.api.entities.sticker.Sticker;
import net.dv8tion.jda.api.entities.sticker.StickerItem;
Expand All @@ -55,6 +56,7 @@
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import net.dv8tion.jda.api.utils.messages.MessageEditData;
import net.dv8tion.jda.api.utils.messages.MessagePollData;
import net.dv8tion.jda.api.utils.messages.MessageRequest;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.ReceivedMessage;
Expand Down Expand Up @@ -681,6 +683,28 @@ default String getGuildId()
@Nonnull
List<LayoutComponent> getComponents();

/**
* The {@link MessagePoll} attached to this message.
*
* @return Possibly-null poll instance for this message
*
* @see #expirePoll()
*/
@Nullable
MessagePoll getPoll();

/**
* Expire the poll attached to this message.
*
* @throws IllegalStateException
* If this poll was not sent by the currently logged in account or no poll was attached to this message
*
* @return {@link AuditableRestAction} - Type: {@link Message}
*/
@Nonnull
@CheckReturnValue
AuditableRestAction<Message> expirePoll();

/**
* Rows of interactive components such as {@link Button Buttons}.
* <br>You can use {@link MessageRequest#setComponents(LayoutComponent...)} to update these.
Expand Down Expand Up @@ -1359,6 +1383,48 @@ default MessageCreateAction reply(@Nonnull MessageCreateData msg)
return getChannel().sendMessage(msg).setMessageReference(this);
}

/**
* Shortcut for {@code getChannel().sendMessagePoll(data).setMessageReference(this)}.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} include:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
* <br>if this channel was deleted</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#CANNOT_SEND_TO_USER CANNOT_SEND_TO_USER}
* <br>If this is a {@link PrivateChannel} and the currently logged in account
* does not share any Guilds with the recipient User</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_AUTOMOD MESSAGE_BLOCKED_BY_AUTOMOD}
* <br>If this message was blocked by an {@link net.dv8tion.jda.api.entities.automod.AutoModRule AutoModRule}</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER}
* <br>If this message was blocked by the harmful link filter</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_INVALID_CHANNEL_TYPE POLL_INVALID_CHANNEL_TYPE}
* <br>This channel does not allow polls</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_WITH_UNUSABLE_EMOJI POLL_WITH_UNUSABLE_EMOJI}
* <br>This poll uses an external emoji that the bot is not allowed to use</li>
* </ul>
*
* @param poll
* The poll to send
*
* @throws InsufficientPermissionException
* If {@link MessageChannel#sendMessage(MessageCreateData)} throws
* @throws IllegalArgumentException
* If {@link MessageChannel#sendMessage(MessageCreateData)} throws
*
* @return {@link MessageCreateAction}
*/
@Nonnull
@CheckReturnValue
default MessageCreateAction replyPoll(@Nonnull MessagePollData poll)
{
return getChannel().sendMessagePoll(poll).setMessageReference(this);
}

/**
* Shortcut for {@code getChannel().sendMessageEmbeds(embed, other).setMessageReference(this)}.
*
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/net/dv8tion/jda/api/entities/WebhookClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import net.dv8tion.jda.api.utils.messages.MessageEditData;
import net.dv8tion.jda.api.utils.messages.MessagePollBuilder;
import net.dv8tion.jda.api.utils.messages.MessagePollData;
import net.dv8tion.jda.internal.requests.IncomingWebhookClientImpl;
import net.dv8tion.jda.internal.utils.Checks;

Expand Down Expand Up @@ -128,6 +130,43 @@ public interface WebhookClient<T> extends ISnowflake
@CheckReturnValue
WebhookMessageCreateAction<T> sendMessage(@Nonnull MessageCreateData message);

/**
* Send a message poll to this webhook.
*
* <p>If this is an {@link InteractionHook InteractionHook} this method will be delayed until the interaction is acknowledged.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} include:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_WEBHOOK UNKNOWN_WEBHOOK}
* <br>The webhook is no longer available, either it was deleted or in case of interactions it expired.</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_AUTOMOD MESSAGE_BLOCKED_BY_AUTOMOD}
* <br>If this message was blocked by an {@link net.dv8tion.jda.api.entities.automod.AutoModRule AutoModRule}</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER}
* <br>If this message was blocked by the harmful link filter</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_INVALID_CHANNEL_TYPE POLL_INVALID_CHANNEL_TYPE}
* <br>This channel does not allow polls</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_WITH_UNUSABLE_EMOJI POLL_WITH_UNUSABLE_EMOJI}
* <br>This poll uses an external emoji that the bot is not allowed to use</li>
* </ul>
*
* @param poll
* The {@link MessagePollData} to send
*
* @throws IllegalArgumentException
* If null is provided
*
* @return {@link net.dv8tion.jda.api.requests.restaction.WebhookMessageCreateAction}
*
* @see MessagePollBuilder
*/
@Nonnull
@CheckReturnValue
WebhookMessageCreateAction<T> sendMessagePoll(@Nonnull MessagePollData poll);

/**
* Send a message to this webhook.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import net.dv8tion.jda.api.utils.data.DataArray;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import net.dv8tion.jda.api.utils.messages.MessageEditData;
import net.dv8tion.jda.api.utils.messages.MessagePollData;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.EntityBuilder;
import net.dv8tion.jda.internal.requests.RestActionImpl;
Expand Down Expand Up @@ -644,6 +645,52 @@ default MessageCreateAction sendMessageComponents(@Nonnull Collection<? extends
return new MessageCreateActionImpl(this).setComponents(components);
}

/**
* Send a message to this channel.
*
* <p>Possible {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} include:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_CHANNEL UNKNOWN_CHANNEL}
* <br>if this channel was deleted</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#CANNOT_SEND_TO_USER CANNOT_SEND_TO_USER}
* <br>If this is a {@link PrivateChannel} and the currently logged in account
* does not share any Guilds with the recipient User</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_AUTOMOD MESSAGE_BLOCKED_BY_AUTOMOD}
* <br>If this message was blocked by an {@link net.dv8tion.jda.api.entities.automod.AutoModRule AutoModRule}</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER MESSAGE_BLOCKED_BY_HARMFUL_LINK_FILTER}
* <br>If this message was blocked by the harmful link filter</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_INVALID_CHANNEL_TYPE POLL_INVALID_CHANNEL_TYPE}
* <br>This channel does not allow polls</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_WITH_UNUSABLE_EMOJI POLL_WITH_UNUSABLE_EMOJI}
* <br>This poll uses an external emoji that the bot is not allowed to use</li>
* </ul>
*
* @param poll
* The poll to send
*
* @throws UnsupportedOperationException
* If this is a {@link PrivateChannel} and the recipient is a bot
* @throws IllegalArgumentException
* If the poll is null
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* If this is a {@link GuildMessageChannel} and this account does not have
* {@link net.dv8tion.jda.api.Permission#VIEW_CHANNEL Permission.VIEW_CHANNEL} or {@link net.dv8tion.jda.api.Permission#MESSAGE_SEND Permission.MESSAGE_SEND}
*
* @return {@link MessageCreateAction}
*/
@Nonnull
@CheckReturnValue
default MessageCreateAction sendMessagePoll(@Nonnull MessagePollData poll)
{
Checks.notNull(poll, "Poll");
return new MessageCreateActionImpl(this).setPoll(poll);
}

/**
* Send a message to this channel.
*
Expand Down Expand Up @@ -972,6 +1019,77 @@ default AuditableRestAction<Void> deleteMessageById(long messageId)
return deleteMessageById(Long.toUnsignedString(messageId));
}

/**
* Expire the poll attached to this message.
*
* <p><b>A bot cannot expire the polls of other users.</b>
*
* <p>The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_ALREADY_EXPIRED POLL_ALREADY_EXPIRED}
* <br>If the poll has already expired</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
* <br>If the poll was sent by another user</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#CANNOT_EXPIRE_MISSING_POLL CANNOT_EXPIRE_MISSING_POLL}
* <br>The message did not have a poll attached</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
* <br>The message no longer exists</li>
* </ul>
*
* @param messageId
* The ID for the poll message
*
* @throws IllegalArgumentException
* If the provided messageId is not a valid snowflake
*
* @return {@link AuditableRestAction} - Type: {@link Message}
*/
@Nonnull
@CheckReturnValue
default AuditableRestAction<Message> expirePollById(@Nonnull String messageId)
{
Checks.isSnowflake(messageId, "Message ID");
return new AuditableRestActionImpl<>(getJDA(), Route.Messages.EXPIRE_POLL.compile(getId(), messageId), (response, request) -> {
JDAImpl jda = (JDAImpl) getJDA();
return jda.getEntityBuilder().createMessageWithChannel(response.getObject(), MessageChannel.this, false);
});
}

/**
* Expire the poll attached to this message.
*
* <p><b>A bot cannot expire the polls of other users.</b>
*
* <p>The following {@link net.dv8tion.jda.api.requests.ErrorResponse ErrorResponses} are possible:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#POLL_ALREADY_EXPIRED POLL_ALREADY_EXPIRED}
* <br>If the poll has already expired</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#INVALID_AUTHOR_EDIT INVALID_AUTHOR_EDIT}
* <br>If the poll was sent by another user</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#CANNOT_EXPIRE_MISSING_POLL CANNOT_EXPIRE_MISSING_POLL}
* <br>The message did not have a poll attached</li>
*
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_MESSAGE UNKNOWN_MESSAGE}
* <br>The message no longer exists</li>
* </ul>
*
* @param messageId
* The ID for the poll message
*
* @return {@link AuditableRestAction} - Type: {@link Message}
*/
@Nonnull
@CheckReturnValue
default AuditableRestAction<Message> expirePollById(long messageId)
{
return expirePollById(Long.toUnsignedString(messageId));
}

/**
* Creates a new {@link net.dv8tion.jda.api.entities.MessageHistory MessageHistory} object for each call of this method.
* <br>MessageHistory is <b>NOT</b> an internal message cache, but rather it queries the Discord servers for previously sent messages.
Expand Down
Loading
Loading