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

Feat: Polls #1

Merged
merged 62 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
5f6d76e
feat: poll object
Droid00000 Dec 5, 2024
e36fe4c
Appease da rubocop
Droid00000 Dec 6, 2024
002075b
Event handlers for polls.
Droid00000 Dec 10, 2024
b1db0f9
Cleanup.
Droid00000 Dec 10, 2024
168c1b5
Requirements>
Droid00000 Dec 10, 2024
88466a6
Fix namespace.
Droid00000 Dec 10, 2024
259d7ce
Try again.
Droid00000 Dec 10, 2024
12f48ca
Remove yield self.
Droid00000 Dec 10, 2024
431d037
Fix undefined variable.
Droid00000 Dec 10, 2024
0dcdd31
Minor fix.
Droid00000 Dec 10, 2024
5bfd536
Fix variable stuff.
Droid00000 Dec 10, 2024
59fb240
Simple debug.
Droid00000 Dec 10, 2024
4e51813
Fix some stuff with objects.
Droid00000 Dec 10, 2024
4182a10
t
Droid00000 Dec 10, 2024
bd1b9ca
Try to fix some answer stuff.
Droid00000 Dec 11, 2024
1de1097
Wah
Droid00000 Dec 11, 2024
2fabbab
Cleanup.
Droid00000 Dec 11, 2024
0182a86
More fixes.
Droid00000 Dec 11, 2024
d42ceea
Another fix.
Droid00000 Dec 11, 2024
a10b0a4
Another attempt at a fix.
Droid00000 Dec 11, 2024
9ee280e
Another debug.
Droid00000 Dec 11, 2024
defd376
c
Droid00000 Dec 11, 2024
0b59809
Fix.
Droid00000 Dec 11, 2024
eca6649
a.
Droid00000 Dec 11, 2024
2d9887c
a
Droid00000 Dec 11, 2024
e2ceb94
Fixup.
Droid00000 Dec 11, 2024
e25cf89
Some stuff for interactions.
Droid00000 Dec 11, 2024
df9f344
Minor touch ups.
Droid00000 Dec 11, 2024
8fa9656
Minor cleanup.
Droid00000 Dec 12, 2024
8d94140
New answer counts stuff.
Droid00000 Dec 12, 2024
90eef5a
mINOR FIX.
Droid00000 Dec 12, 2024
b67d969
Another fix.
Droid00000 Dec 12, 2024
d1c1313
Fixup answer counts.
Droid00000 Dec 12, 2024
83078b2
Cleanup.
Droid00000 Dec 12, 2024
cdba0f1
Minor refactoring.
Droid00000 Dec 12, 2024
1d57178
Minor fix.
Droid00000 Dec 12, 2024
e88464b
Minor fix.
Droid00000 Dec 12, 2024
d32c4ad
Minor touch ups.
Droid00000 Dec 12, 2024
2ec295b
Try for interactions.
Droid00000 Dec 12, 2024
4c7fc1c
minor mistake.
Droid00000 Dec 12, 2024
8a819b6
Another attempt fix.
Droid00000 Dec 12, 2024
785eea8
Prepare for polls.
Droid00000 Dec 13, 2024
6574e20
Cleanup.
Droid00000 Dec 13, 2024
95355ac
Fix some shitty specs.
Droid00000 Dec 13, 2024
1c94768
More stuff idk.
Droid00000 Dec 13, 2024
006a946
Safety.
Droid00000 Dec 13, 2024
6c6c081
Moar.
Droid00000 Dec 13, 2024
7ec36dc
Yard stuff.
Droid00000 Dec 13, 2024
2b78cbf
Rubocop.
Droid00000 Dec 13, 2024
cc2444f
Fixup yard.
Droid00000 Dec 13, 2024
27b574f
Fix docs again.
Droid00000 Dec 13, 2024
572de21
Consolidate.
Droid00000 Dec 13, 2024
d8a2404
Method signature.
Droid00000 Dec 13, 2024
fb857af
KWARGS.
Droid00000 Dec 13, 2024
8679f60
Fixup.
Droid00000 Dec 13, 2024
ec3c320
Fix the polls.
Droid00000 Dec 13, 2024
ed00687
Minor changes.
Droid00000 Dec 13, 2024
c5a1e45
Update webhooks.
Droid00000 Dec 13, 2024
7689d8c
Cleanup docs.
Droid00000 Dec 13, 2024
1d630a2
Add method #tied?
Droid00000 Dec 13, 2024
4e78964
Remove some aliases.
Droid00000 Dec 13, 2024
78811ce
One last thing.
Droid00000 Dec 13, 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
4 changes: 3 additions & 1 deletion lib/discordrb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ module Discordrb
server_message_typing: 1 << 11,
direct_messages: 1 << 12,
direct_message_reactions: 1 << 13,
direct_message_typing: 1 << 14
direct_message_typing: 1 << 14,
server_message_polls: 1 << 24,
direct_message_polls: 1 << 25
}.freeze

# All available intents
Expand Down
29 changes: 27 additions & 2 deletions lib/discordrb/api/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def message(token, channel_id, message_id)
# https://discord.com/developers/docs/resources/channel#create-message
# @param attachments [Array<File>, nil] Attachments to use with `attachment://` in embeds. See
# https://discord.com/developers/docs/resources/channel#create-message-using-attachments-within-embeds
def create_message(token, channel_id, message, tts = false, embeds = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
body = { content: message, tts: tts, embeds: embeds, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference, components: components&.to_a }
def create_message(token, channel_id, message, tts = false, embeds = nil, nonce = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
body = { content: message, tts: tts, embeds: embeds, nonce: nonce, allowed_mentions: allowed_mentions, message_reference: message_reference, components: components&.to_a, poll: poll }
body = if attachments
files = [*0...attachments.size].zip(attachments).to_h
{ **files, payload_json: body.to_json }
Expand Down Expand Up @@ -608,4 +608,29 @@ def list_joined_private_archived_threads(token, channel_id, before = nil, limit
Authorization: token
)
end

# Immediately ends a poll the bot has made.
# https://discord.com/developers/docs/resources/poll#end-poll
def end_poll(token, channel_id, message_id)
Discordrb::API.request(
:channels_cid_messages_mid_expire,
channel_id,
:post,
"#{Discordrb::API.api_base}/channels/#{channel_id}/polls/#{message_id}/expire",
Authorization: token
)
end

# Gets the members that have voted for a specific poll answer.
# https://discord.com/developers/docs/resources/poll#end-poll
def get_answer_voters(token, channel_id, message_id, answer_id, after, limit)
query = URI.encode_www_form({ after: after, limit: limit }.compact)
Discordrb::API.request(
:channels_cid_messages_mid_answers_aid,
channel_id,
:get,
"#{Discordrb::API.api_base}/channels/#{channel_id}/polls/#{message_id}/answers/#{answer_id}?#{query}",
Authorization: token
)
end
end
8 changes: 4 additions & 4 deletions lib/discordrb/api/interaction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ module Discordrb::API::Interaction

# Respond to an interaction.
# https://discord.com/developers/docs/interactions/slash-commands#create-interaction-response
def create_interaction_response(interaction_token, interaction_id, type, content = nil, tts = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil)
data = { tts: tts, content: content, embeds: embeds, allowed_mentions: allowed_mentions, flags: flags, components: components }.compact
def create_interaction_response(interaction_token, interaction_id, type, content = nil, tts = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil, poll = nil)
data = { tts: tts, content: content, embeds: embeds, allowed_mentions: allowed_mentions, flags: flags, components: components, poll: poll }.compact

Discordrb::API.request(
:interactions_iid_token_callback,
Expand Down Expand Up @@ -42,8 +42,8 @@ def get_original_interaction_response(interaction_token, application_id)

# Edit the original response to an interaction.
# https://discord.com/developers/docs/interactions/slash-commands#edit-original-interaction-response
def edit_original_interaction_response(interaction_token, application_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil)
Discordrb::API::Webhook.token_edit_message(interaction_token, application_id, '@original', content, embeds, allowed_mentions, components)
def edit_original_interaction_response(interaction_token, application_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, poll = nil)
Discordrb::API::Webhook.token_edit_message(interaction_token, application_id, '@original', content, embeds, allowed_mentions, components, poll)
end

# Delete the original response to an interaction.
Expand Down
8 changes: 4 additions & 4 deletions lib/discordrb/api/webhook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ def token_webhook(webhook_token, webhook_id)

# Execute a webhook via token.
# https://discord.com/developers/docs/resources/webhook#execute-webhook
def token_execute_webhook(webhook_token, webhook_id, wait = false, content = nil, username = nil, avatar_url = nil, tts = nil, file = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil)
body = { content: content, username: username, avatar_url: avatar_url, tts: tts, embeds: embeds&.map(&:to_hash), allowed_mentions: allowed_mentions, flags: flags, components: components }
def token_execute_webhook(webhook_token, webhook_id, wait = false, content = nil, username = nil, avatar_url = nil, tts = nil, file = nil, embeds = nil, allowed_mentions = nil, flags = nil, components = nil, poll = nil)
body = { content: content, username: username, avatar_url: avatar_url, tts: tts, embeds: embeds&.map(&:to_hash), allowed_mentions: allowed_mentions, flags: flags, components: components, poll: poll }
body = if file
{ file: file, payload_json: body.to_json }
else
Expand Down Expand Up @@ -116,13 +116,13 @@ def token_get_message(webhook_token, webhook_id, message_id)

# Edit a webhook message via webhook token
# https://discord.com/developers/docs/resources/webhook#edit-webhook-message
def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil)
def token_edit_message(webhook_token, webhook_id, message_id, content = nil, embeds = nil, allowed_mentions = nil, components = nil, poll = nil)
Discordrb::API.request(
:webhooks_wid_messages,
webhook_id,
:patch,
"#{Discordrb::API.api_base}/webhooks/#{webhook_id}/#{webhook_token}/messages/#{message_id}",
{ content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components }.to_json,
{ content: content, embeds: embeds, allowed_mentions: allowed_mentions, components: components, poll: poll }.to_json,
content_type: :json
)
end
Expand Down
19 changes: 15 additions & 4 deletions lib/discordrb/bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
require 'discordrb/events/invites'
require 'discordrb/events/interactions'
require 'discordrb/events/threads'
require 'discordrb/events/polls'

require 'discordrb/api'
require 'discordrb/api/channel'
Expand Down Expand Up @@ -401,15 +402,16 @@ def delete_invite(code)
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
# @param poll [Hash] A poll request object to include. If you just need to send a poll refer to Channel#send_poll.
# @return [Message] The message that was sent.
def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
def send_message(channel, content, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
channel = channel.resolve_id
debug("Sending message to #{channel} with content '#{content}'")
allowed_mentions = { parse: [] } if allowed_mentions == false
message_reference = { message_id: message_reference.id } if message_reference.respond_to?(:id)
embeds = (embeds.instance_of?(Array) ? embeds.map(&:to_hash) : [embeds&.to_hash]).compact

response = API::Channel.create_message(token, channel, content, tts, embeds, nil, attachments, allowed_mentions&.to_hash, message_reference, components)
response = API::Channel.create_message(token, channel, content, tts, embeds, nil, attachments, allowed_mentions&.to_hash, message_reference, components, poll)
Message.new(JSON.parse(response), self)
end

Expand All @@ -424,11 +426,12 @@ def send_message(channel, content, tts = false, embeds = nil, attachments = nil,
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
# @param poll [Hash] A poll request object to include. If you just need to send a poll refer to Channel#send_poll.
def send_temporary_message(channel, content, timeout, tts = false, embeds = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
Thread.new do
Thread.current[:discordrb_name] = "#{@current_thread}-temp-msg"

message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components)
message = send_message(channel, content, tts, embeds, attachments, allowed_mentions, message_reference, components, poll)
sleep(timeout)
message.delete
end
Expand Down Expand Up @@ -1638,6 +1641,14 @@ def handle_dispatch(type, data)

event = ThreadMembersUpdateEvent.new(data, self)
raise_event(event)

when :MESSAGE_POLL_VOTE_ADD
event = PollVoteAddEvent.new(data, self)
raise_event(event)

when :MESSAGE_POLL_VOTE_REMOVE
event = PollVoteRemoveEvent.new(data, self)
raise_event(event)
else
# another event that we don't support yet
debug "Event #{type} has been received but is unsupported. Raising UnknownEvent"
Expand Down
26 changes: 26 additions & 0 deletions lib/discordrb/container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,32 @@ def channel_select(attributes = {}, &block)
register_event(ChannelSelectEvent, attributes, block)
end

# This **event** is raised whenever a user votes for a poll.
# @param attributes [Hash] The event's attributes.
# @option attributes [String, Integer, User] :user A user to match against.
# @option attributes [String, Integer, Channel] :channel A channel to match against.
# @option attributes [String, Integer, Message] :message A message to match against.
# @option attributes [String, Integer] :answer_id Custom_id of an answer to match against.
# @yield The block is executed when the event is raised.
# @yieldparam event [PollVoteAddEvent] The event that was raised.
# @return [PollVoteAddEventHandler] The event handler that was registered.
def poll_vote_add(attributes = {}, &block)
register_event(PollVoteAddEvent, attributes, block)
end

# This **event** is raised whenever a user removes a vote for a poll.
# @param attributes [Hash] The event's attributes.
# @option attributes [String, Integer, User] :user_id A user to match against.
# @option attributes [String, Integer, Channel] :channel_id A channel to match against.
# @option attributes [String, Integer, Message] :message_id A message to match against.
# @option attributes [String, Integer] :answer_id Custom_id of an answer to match against.
# @yield The block is executed when the event is raised.
# @yieldparam event [PollVoteRemoveEvent] The event that was raised.
# @return [PollVoteRemoveEventHandler] The event handler that was registered.
def poll_vote_remove(attributes = {}, &block)
register_event(PollVoteRemoveEvent, attributes, block)
end

# This **event** is raised for every dispatch received over the gateway, whether supported by discordrb or not.
# @param attributes [Hash] The event's attributes.
# @option attributes [String, Symbol, Regexp] :type Matches the event type of the dispatch.
Expand Down
1 change: 1 addition & 0 deletions lib/discordrb/data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@
require 'discordrb/data/audit_logs'
require 'discordrb/data/interaction'
require 'discordrb/data/component'
require 'discordrb/data/poll'
42 changes: 36 additions & 6 deletions lib/discordrb/data/channel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,10 @@ def slowmode?
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
# @param poll [Hash] A poll request object to include. If you just need to send a poll refer to Channel#send_poll.
# @return [Message] the message that was sent.
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
@bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components)
def send_message(content, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
@bot.send_message(@id, content, tts, embed, attachments, allowed_mentions, message_reference, components, poll)
end

alias_method :send, :send_message
Expand All @@ -444,8 +445,9 @@ def send_message(content, tts = false, embed = nil, attachments = nil, allowed_m
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil)
@bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components)
# @param poll [Hash] A poll request object to include. If you just need to send a poll refer to Channel#send_poll.
def send_temporary_message(content, timeout, tts = false, embed = nil, attachments = nil, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
@bot.send_temporary_message(@id, content, timeout, tts, embed, attachments, allowed_mentions, message_reference, components, poll)
end

# Convenience method to send a message with an embed.
Expand All @@ -461,16 +463,44 @@ def send_temporary_message(content, timeout, tts = false, embed = nil, attachmen
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
# @param poll [Hash] A poll request object to include. If you just need to send a poll refer to Channel#send_poll.
# @yield [embed] Yields the embed to allow for easy building inside a block.
# @yieldparam embed [Discordrb::Webhooks::Embed] The embed from the parameters, or a new one.
# @return [Message] The resulting message.
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil)
def send_embed(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
embed ||= Discordrb::Webhooks::Embed.new
view = Discordrb::Webhooks::View.new

yield(embed, view) if block_given?

send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a)
send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a, poll)
end

# Convenience method to send a message with a poll.
# @example Send a message with a poll
# channel.send_poll do |poll|
# poll.question = 'Cops?'
# poll.duration = 56
# poll.add_answer(name: 'Hell Yea', emoji: nil)
# poll.add_answer(name: 'Hell Na', emoji: nil)
# end
# @param message [String] The message that should be sent along with the embed. If this is the empty string, only the embed will be shown.
# @param embed [Discordrb::Webhooks::Embed, nil] The embed to start the building process with, or nil if one should be created anew.
# @param attachments [Array<File>] Files that can be referenced in embeds via `attachment://file.png`
# @param tts [true, false] Whether or not this message should be sent using Discord text-to-speech.
# @param allowed_mentions [Hash, Discordrb::AllowedMentions, false, nil] Mentions that are allowed to ping on this message. `false` disables all pings
# @param message_reference [Message, String, Integer, nil] The message, or message ID, to reply to if any.
# @param components [View, Array<Hash>] Interaction components to associate with this message.
# @param poll [Hash] A poll request object to include with this message.
# @yieldparam poll [Discordrb::Poll::Builder] The poll from the parameters, or a new one.
# @return [Message] The resulting message.
def send_poll(message = '', embed = nil, attachments = nil, tts = false, allowed_mentions = nil, message_reference = nil, components = nil, poll = nil)
view = Discordrb::Webhooks::View.new
builder ||= Discordrb::Poll::Builder.new

yield(builder, view) if block_given?

send_message(message, tts, embed, attachments, allowed_mentions, message_reference, components || view.to_a, poll || builder.to_hash)
end

# Sends multiple messages to a channel
Expand Down
Loading