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(model, cache, http): add support for polls #2341

Merged
merged 8 commits into from
Jul 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions twilight-cache-inmemory/src/event/interaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ mod tests {
mention_roles: Vec::new(),
mentions: Vec::new(),
pinned: false,
poll: None,
reactions: Vec::new(),
reference: None,
role_subscription_data: None,
Expand Down
1 change: 1 addition & 0 deletions twilight-cache-inmemory/src/event/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod tests {
mention_roles: Vec::new(),
mentions: Vec::new(),
pinned: false,
poll: None,
reactions: Vec::new(),
reference: None,
role_subscription_data: None,
Expand Down
2 changes: 2 additions & 0 deletions twilight-cache-inmemory/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,8 @@ impl<CacheModels: CacheableModels> UpdateCache<CacheModels> for Event {
| Event::GuildScheduledEventUserRemove(_)
| Event::InviteCreate(_)
| Event::InviteDelete(_)
| Event::MessagePollVoteAdd(_)
| Event::MessagePollVoteRemove(_)
| Event::Resumed
| Event::ThreadMembersUpdate(_)
| Event::ThreadMemberUpdate(_)
Expand Down
4 changes: 4 additions & 0 deletions twilight-cache-inmemory/src/model/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use twilight_model::{
},
Id,
},
poll::Poll,
util::Timestamp,
};

Expand Down Expand Up @@ -114,6 +115,7 @@ pub struct CachedMessage {
pub(crate) mention_roles: Vec<Id<RoleMarker>>,
pub(crate) mentions: Vec<Id<UserMarker>>,
pub(crate) pinned: bool,
pub(crate) poll: Option<Poll>,
pub(crate) reactions: Vec<Reaction>,
reference: Option<MessageReference>,
role_subscription_data: Option<RoleSubscriptionData>,
Expand Down Expand Up @@ -320,6 +322,7 @@ impl From<Message> for CachedMessage {
mention_roles,
mentions,
pinned,
poll,
reactions,
reference,
referenced_message: _,
Expand Down Expand Up @@ -353,6 +356,7 @@ impl From<Message> for CachedMessage {
mention_roles,
mentions: mentions.into_iter().map(|mention| mention.id).collect(),
pinned,
poll,
reactions,
reference,
role_subscription_data,
Expand Down
1 change: 1 addition & 0 deletions twilight-cache-inmemory/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ pub fn cache_with_message_and_reactions() -> DefaultInMemoryCache {
mention_roles: Vec::new(),
mentions: Vec::new(),
pinned: false,
poll: None,
reactions: Vec::new(),
reference: None,
role_subscription_data: None,
Expand Down
12 changes: 12 additions & 0 deletions twilight-gateway/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ bitflags! {
const MESSAGE_DELETE = 1 << 20;
/// Multiple messages have been deleted in a channel.
const MESSAGE_DELETE_BULK = 1 << 21;
/// Message poll vote has been added.
const MESSAGE_POLL_VOTE_ADD = 1 << 28;
/// Message poll vote has been removed.
const MESSAGE_POLL_VOTE_REMOVE = 1 << 29;
/// Message in a channel has been updated.
const MESSAGE_UPDATE = 1 << 22;
/// User's presence details are updated.
Expand Down Expand Up @@ -282,6 +286,12 @@ bitflags! {
| Self::MESSAGE_DELETE_BULK.bits()
| Self::MESSAGE_UPDATE.bits();

/// All [`EventTypeFlags`] in [`Intents::DIRECT_MESSAGE_POLLS`] and [`Intents::GUILD_MESSAGE_POLLS`].
///
/// [`Intents::DIRECT_MESSAGE_POLLS`]: crate::Intents::DIRECT_MESSAGE_POLLS
/// [`Intents::GUILD_MESSAGE_POLLS`]: crate::Intents::GUILD_MESSAGE_POLLS
const MESSAGE_POLLS = Self::MESSAGE_POLL_VOTE_ADD.bits() | Self::MESSAGE_POLL_VOTE_REMOVE.bits();

/// All [`EventTypeFlags`] in [`Intents::GUILD_MESSAGE_REACTIONS`].
///
/// [`Intents::GUILD_MESSAGE_REACTIONS`]: crate::Intents::GUILD_MESSAGE_REACTIONS
Expand Down Expand Up @@ -370,6 +380,8 @@ impl From<EventType> for EventTypeFlags {
EventType::MessageCreate => Self::MESSAGE_CREATE,
EventType::MessageDelete => Self::MESSAGE_DELETE,
EventType::MessageDeleteBulk => Self::MESSAGE_DELETE_BULK,
EventType::MessagePollVoteAdd => Self::MESSAGE_POLL_VOTE_ADD,
EventType::MessagePollVoteRemove => Self::MESSAGE_POLL_VOTE_REMOVE,
EventType::MessageUpdate => Self::MESSAGE_UPDATE,
EventType::PresenceUpdate => Self::PRESENCE_UPDATE,
EventType::ReactionAdd => Self::REACTION_ADD,
Expand Down
2 changes: 2 additions & 0 deletions twilight-http-ratelimiting/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ pub enum Path {
ChannelsIdPins(u64),
/// Operating on a channel's individual pinned message.
ChannelsIdPinsMessageId(u64),
/// Operating on a channel's polls.
ChannelsIdPolls(u64),
/// Operating on a group DM's recipients.
ChannelsIdRecipients(u64),
/// Operating on a thread's members.
Expand Down
56 changes: 56 additions & 0 deletions twilight-http/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ use crate::{
UpdateCurrentMember, UpdateGuild, UpdateGuildChannelPositions, UpdateGuildMfa,
UpdateGuildWelcomeScreen, UpdateGuildWidgetSettings,
},
poll::{EndPoll, GetAnswerVoters},
scheduled_event::{
CreateGuildScheduledEvent, DeleteGuildScheduledEvent, GetGuildScheduledEvent,
GetGuildScheduledEventUsers, GetGuildScheduledEvents, UpdateGuildScheduledEvent,
Expand Down Expand Up @@ -2621,6 +2622,32 @@ impl Client {
CreateTestEntitlement::new(self, application_id, sku_id, owner)
}

/// Ends a poll in a channel.
///
/// # Examples
///
/// ```no_run
/// use twilight_http::Client;
/// use twilight_model::id::Id;
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = Client::new("my token".to_owned());
///
/// let channel_id = Id::new(1);
/// let message_id = Id::new(2);
///
/// client.end_poll(channel_id, message_id).await?;
/// # Ok(()) }
/// ```
pub const fn end_poll(
&self,
channel_id: Id<ChannelMarker>,
message_id: Id<MessageMarker>,
) -> EndPoll<'_> {
EndPoll::new(self, channel_id, message_id)
}

/// Deletes a currently-active test entitlement. Discord will act as though that user or
/// guild no longer has entitlement to your premium offering.
///
Expand Down Expand Up @@ -2651,6 +2678,35 @@ impl Client {
DeleteTestEntitlement::new(self, application_id, entitlement_id)
}

/// /// Get the voters for an answer in a poll.
///
/// # Examples
///
/// ```no_run
/// use twilight_http::Client;
/// use twilight_model::id::Id;
///
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = Client::new("my token".to_owned());
///
/// let channel_id = Id::new(1);
/// let message_id = Id::new(2);
/// let answer_id = 1;
///
/// let voters = client.get_answer_voters(channel_id, message_id, answer_id).await?;
///
/// println!("{:?}", voters);
/// # Ok(()) }
pub const fn get_answer_voters(
&self,
channel_id: Id<ChannelMarker>,
message_id: Id<MessageMarker>,
answer_id: u8,
) -> GetAnswerVoters<'_> {
GetAnswerVoters::new(self, channel_id, message_id, answer_id)
}

/// Returns all SKUs for a given application.
///
/// # Examples
Expand Down
13 changes: 13 additions & 0 deletions twilight-http/src/request/channel/message/create_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use twilight_model::{
marker::{ChannelMarker, MessageMarker, StickerMarker},
Id,
},
poll::Poll,
};
use twilight_validate::message::{
attachment as validate_attachment, components as validate_components,
Expand Down Expand Up @@ -47,6 +48,8 @@ pub(crate) struct CreateMessageFields<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
payload_json: Option<&'a [u8]>,
#[serde(skip_serializing_if = "Option::is_none")]
poll: Option<&'a Poll>,
#[serde(skip_serializing_if = "Option::is_none")]
sticker_ids: Option<&'a [Id<StickerMarker>]>,
#[serde(skip_serializing_if = "Option::is_none")]
tts: Option<bool>,
Expand Down Expand Up @@ -102,6 +105,7 @@ impl<'a> CreateMessage<'a> {
message_reference: None,
nonce: None,
payload_json: None,
poll: None,
allowed_mentions: None,
sticker_ids: None,
tts: None,
Expand Down Expand Up @@ -222,6 +226,15 @@ impl<'a> CreateMessage<'a> {
self
}

/// Specify if this message is a poll.
pub fn poll(mut self, poll: &'a Poll) -> Self {
if let Ok(fields) = self.fields.as_mut() {
fields.poll = Some(poll);
}

self
}

/// Whether to fail sending if the reply no longer exists.
///
/// Defaults to [`true`].
Expand Down
1 change: 1 addition & 0 deletions twilight-http/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub mod application;
pub mod attachment;
pub mod channel;
pub mod guild;
pub mod poll;
pub mod scheduled_event;
pub mod sticker;
pub mod template;
Expand Down
68 changes: 68 additions & 0 deletions twilight-http/src/request/poll/end_poll.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use crate::{
client::Client,
error::Error,
request::{Request, TryIntoRequest},
response::{Response, ResponseFuture},
routing::Route,
};
use serde::Serialize;
use std::future::IntoFuture;
use twilight_model::{
channel::Message,
id::{
marker::{ChannelMarker, MessageMarker},
Id,
},
};

#[derive(Serialize)]
struct EndPollFields {
channel_id: Id<ChannelMarker>,
message_id: Id<MessageMarker>,
}

// Ends a poll in a channel.
#[must_use = "requests must be configured and executed"]
pub struct EndPoll<'a> {
fields: EndPollFields,
http: &'a Client,
}

impl<'a> EndPoll<'a> {
pub(crate) const fn new(
http: &'a Client,
channel_id: Id<ChannelMarker>,
message_id: Id<MessageMarker>,
) -> Self {
Self {
fields: EndPollFields {
channel_id,
message_id,
},
http,
}
}
}

impl IntoFuture for EndPoll<'_> {
type Output = Result<Response<Message>, Error>;
type IntoFuture = ResponseFuture<Message>;

fn into_future(self) -> Self::IntoFuture {
let http = self.http;

match self.try_into_request() {
Ok(request) => http.request(request),
Err(source) => ResponseFuture::error(source),
}
}
}

impl TryIntoRequest for EndPoll<'_> {
fn try_into_request(self) -> Result<Request, Error> {
Ok(Request::from_route(&Route::EndPoll {
channel_id: self.fields.channel_id.get(),
message_id: self.fields.message_id.get(),
}))
}
}
Loading