diff options
| author | Austin Hellyer <[email protected]> | 2016-11-07 11:43:15 -0800 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-11-07 11:43:15 -0800 |
| commit | a114a55efb5b08f9e5f289203db2dfd4db82852a (patch) | |
| tree | 8522e8eb3e77534ecf5c8e0208746b587eae887b /src/model | |
| parent | Add Attachment::download{,to_directory} (diff) | |
| download | serenity-a114a55efb5b08f9e5f289203db2dfd4db82852a.tar.xz serenity-a114a55efb5b08f9e5f289203db2dfd4db82852a.zip | |
Add webhook support
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/channel.rs | 23 | ||||
| -rw-r--r-- | src/model/gateway.rs | 16 | ||||
| -rw-r--r-- | src/model/guild.rs | 20 | ||||
| -rw-r--r-- | src/model/id.rs | 29 | ||||
| -rw-r--r-- | src/model/mod.rs | 4 | ||||
| -rw-r--r-- | src/model/webhook.rs | 168 |
6 files changed, 259 insertions, 1 deletions
diff --git a/src/model/channel.rs b/src/model/channel.rs index 014442a..facb67a 100644 --- a/src/model/channel.rs +++ b/src/model/channel.rs @@ -16,7 +16,7 @@ use super::utils::{ }; use super::*; use super::utils; -use ::builder::{CreateInvite, EditChannel}; +use ::builder::{CreateEmbed, CreateInvite, EditChannel}; use ::client::{STATE, http}; use ::prelude_internal::*; use ::utils::decode_array; @@ -251,6 +251,18 @@ impl fmt::Display for Channel { } } +impl Embed { + /// Creates a fake Embed, giving back a `serde_json` map. + /// + /// This should only be useful in conjunction with [`Webhook::execute`]. + /// + /// [`Webhook::execute`]: struct.Webhook.html + #[inline(always)] + pub fn fake<F>(f: F) -> Value where F: FnOnce(CreateEmbed) -> CreateEmbed { + f(CreateEmbed::default()).0.build() + } +} + impl Group { /// Adds the given user to the group. If the user is already in the group, /// then nothing is done. @@ -764,6 +776,15 @@ impl PublicChannel { http::send_message(self.id.0, map) } + + /// Retrieves the channel's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + pub fn webhooks(&self) -> Result<Vec<Webhook>> { + http::get_channel_webhooks(self.id.0) + } } impl fmt::Display for PublicChannel { diff --git a/src/model/gateway.rs b/src/model/gateway.rs index 60c9566..5748302 100644 --- a/src/model/gateway.rs +++ b/src/model/gateway.rs @@ -302,6 +302,12 @@ pub struct VoiceStateUpdateEvent { pub voice_state: VoiceState, } +#[derive(Clone, Debug)] +pub struct WebhookUpdateEvent { + pub channel_id: ChannelId, + pub guild_id: GuildId, +} + #[derive(Debug, Clone)] pub enum GatewayEvent { Dispatch(u64, Event), @@ -483,6 +489,11 @@ pub enum Event { VoiceStateUpdate(VoiceStateUpdateEvent), /// Voice server information is available VoiceServerUpdate(VoiceServerUpdateEvent), + /// A webhook for a [channel][`PublicChannel`] was updated in a [`Guild`]. + /// + /// [`Guild`]: struct.Guild.html + /// [`PublicChannel`]: struct.PublicChannel.html + WebhookUpdate(WebhookUpdateEvent), /// An event type not covered by the above Unknown(UnknownEvent), } @@ -748,6 +759,11 @@ impl Event { guild_id: try!(opt(&mut value, "guild_id", GuildId::decode)), voice_state: try!(VoiceState::decode(Value::Object(value))), })) + } else if kind == "WEBHOOKS_UPDATE" { + Ok(Event::WebhookUpdate(WebhookUpdateEvent { + channel_id: try!(remove(&mut value, "channel_id").and_then(ChannelId::decode)), + guild_id: try!(remove(&mut value, "guild_id").and_then(GuildId::decode)), + })) } else { Ok(Event::Unknown(UnknownEvent { kind: kind, diff --git a/src/model/guild.rs b/src/model/guild.rs index a72a187..e8aff56 100644 --- a/src/model/guild.rs +++ b/src/model/guild.rs @@ -125,6 +125,16 @@ impl Guild { self.icon.as_ref().map(|icon| format!(cdn_concat!("/icons/{}/{}.jpg"), self.id, icon)) } + + /// Retrieves the guild's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + #[inline] + pub fn webhooks(&self) -> Result<Vec<Webhook>> { + http::get_guild_webhooks(self.id.0) + } } impl LiveGuild { @@ -674,6 +684,16 @@ impl LiveGuild { http::remove_ban(self.id.0, user.into().0) } + + /// Retrieves the guild's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + #[inline] + pub fn webhooks(&self) -> Result<Vec<Webhook>> { + http::get_guild_webhooks(self.id.0) + } } impl Member { diff --git a/src/model/id.rs b/src/model/id.rs index 967b18c..faeccd3 100644 --- a/src/model/id.rs +++ b/src/model/id.rs @@ -28,6 +28,15 @@ impl ChannelId { prefix: "<#", } } + + /// Retrieves the channel's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + pub fn webhooks(&self) -> Result<Vec<Webhook>> { + http::get_channel_webhooks(self.0) + } } impl From<Channel> for ChannelId { @@ -81,6 +90,15 @@ impl GuildId { prefix: "<#", } } + + /// Retrieves the guild's webhooks. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + pub fn webhooks(&self) -> Result<Vec<Webhook>> { + http::get_guild_webhooks(self.0) + } } impl From<Guild> for GuildId { @@ -181,3 +199,14 @@ impl UserId { } } } + +impl WebhookId { + /// Retrieves the webhook by the Id. + /// + /// **Note**: Requires the [Manage Webhooks] permission. + /// + /// [Manage Webhooks]: permissions/constant.MANAGE_WEBHOOKS.html + pub fn webhooks(&self) -> Result<Webhook> { + http::get_webhook(self.0) + } +} diff --git a/src/model/mod.rs b/src/model/mod.rs index 1e94d99..81750a0 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -11,6 +11,7 @@ mod invite; mod misc; mod user; mod voice; +mod webhook; pub use self::channel::*; pub use self::gateway::*; @@ -21,6 +22,7 @@ pub use self::misc::*; pub use self::permissions::Permissions; pub use self::user::*; pub use self::voice::*; +pub use self::webhook::*; use self::utils::*; use std::collections::HashMap; @@ -87,6 +89,8 @@ id! { RoleId; /// An identifier for a User UserId; + /// An identifier for a [`Webhook`](struct.Webhook.html). + WebhookId; } /// A container for any channel. diff --git a/src/model/webhook.rs b/src/model/webhook.rs new file mode 100644 index 0000000..70acd68 --- /dev/null +++ b/src/model/webhook.rs @@ -0,0 +1,168 @@ +use serde_json::builder::ObjectBuilder; +use std::mem; +use super::{Message, Webhook}; +use ::builder::ExecuteWebhook; +use ::client::http; +use ::prelude_internal::*; + +impl Webhook { + /// Deletes the webhook. + /// + /// As this calls the [`http::delete_webhook_with_token`] function, + /// authentication is not required. + /// + /// [`http::delete_webhook_with_token`]: ../client/http/fn.delete_webhook_with_token.html + pub fn delete(&self) -> Result<()> { + http::delete_webhook_with_token(self.id.0, &self.token) + } + + /// + /// Edits the webhook in-place. All fields are optional. + /// + /// To nullify the avatar, pass `Some("")`. Otherwise, passing `None` will + /// not modify the avatar. + /// + /// Refer to [`http::edit_webhook`] for restrictions on editing webhooks. + /// + /// As this calls the [`http::edit_webhook_with_token`] function, + /// authentication is not required. + /// + /// # Examples + /// + /// Editing a webhook's name: + /// + /// ```rust,no_run + /// use serenity::client::http; + /// + /// let id = 245037420704169985; + /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; + /// + /// let mut webhook = http::get_webhook_with_token(id, token) + /// .expect("valid webhook"); + /// + /// let _ = webhook.edit(Some("new name"), None).expect("err editing"); + /// ``` + /// + /// Setting a webhook's avatar: + /// + /// ```rust,no_run + /// use serenity::client::http; + /// + /// let id = 245037420704169985; + /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; + /// + /// let mut webhook = http::get_webhook_with_token(id, token) + /// .expect("valid webhook"); + /// + /// let image = serenity::utils::read_image("./webhook_img.png") + /// .expect("err reading image"); + /// + /// let _ = webhook.edit(None, Some(&image)).expect("err editing"); + /// ``` + /// + /// [`http::edit_webhook`]: ../client/http/fn.edit_webhook.html + /// [`http::edit_webhook_with_token`]: ../client/http/fn.edit_webhook_with_token.html + pub fn edit(&mut self, name: Option<&str>, avatar: Option<&str>) + -> Result<()> { + if name.is_none() && avatar.is_none() { + return Ok(()); + } + + let mut map = ObjectBuilder::new(); + + if let Some(avatar) = avatar { + map = map.insert("avatar", if avatar.len() == 0 { + Value::Null + } else { + Value::String(avatar.to_owned()) + }); + } + + if let Some(name) = name { + map = map.insert("name", name); + } + + let map = map.build(); + + match http::edit_webhook_with_token(self.id.0, &self.token, map) { + Ok(replacement) => { + mem::replace(self, replacement); + + Ok(()) + }, + Err(why) => Err(why), + } + } + + /// Executes a webhook with the fields set via the given builder. + /// + /// The builder provides a method of setting only the fields you need, + /// without needing to pass a long set of arguments. + /// + /// # Examples + /// + /// Execute a webhook with message content of `test`: + /// + /// ```rust,no_run + /// use serenity::client::http; + /// + /// let id = 245037420704169985; + /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; + /// + /// let mut webhook = http::get_webhook_with_token(id, token) + /// .expect("valid webhook"); + /// + /// let _ = webhook.execute(|w| w.content("test")).expect("err executing"); + /// ``` + /// + /// Execute a webhook with message content of `test`, overriding the + /// username to `serenity`, and sending an embed: + /// + /// ```rust,no_run + /// use serenity::client::http; + /// use serenity::model::Embed; + /// + /// let id = 245037420704169985; + /// let token = "ig5AO-wdVWpCBtUUMxmgsWryqgsW3DChbKYOINftJ4DCrUbnkedoYZD0VOH1QLr-S3sV"; + /// + /// let mut webhook = http::get_webhook_with_token(id, token) + /// .expect("valid webhook"); + /// + /// let embed = Embed::fake(|e| e + /// .title("Rust's website") + /// .description("Rust is a systems programming language that runs + /// blazingly fast, prevents segfaults, and guarantees + /// thread safety.") + /// .url("https://rust-lang.org")); + /// + /// let _ = webhook.execute(|w| w + /// .content("test") + /// .username("serenity") + /// .embeds(vec![embed])) + /// .expect("err executing"); + /// ``` + pub fn execute<F>(&self, f: F) -> Result<Message> + where F: FnOnce(ExecuteWebhook) -> ExecuteWebhook { + let map = f(ExecuteWebhook::default()).0.build(); + + http::execute_webhook(self.id.0, &self.token, map) + } + + /// Retrieves the latest information about the webhook, editing the + /// webhook in-place. + /// + /// As this calls the [`http::get_webhook_with_token`] function, + /// authentication is not required. + /// + /// [`http::get_webhook_with_token`]: ../client/http/fn.get_webhook_with_token.html + pub fn refresh(&mut self) -> Result<()> { + match http::get_webhook_with_token(self.id.0, &self.token) { + Ok(replacement) => { + mem::replace(self, replacement); + + Ok(()) + }, + Err(why) => Err(why), + } + } +} |