aboutsummaryrefslogtreecommitdiff
path: root/src/model
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-11-07 11:43:15 -0800
committerAustin Hellyer <[email protected]>2016-11-07 11:43:15 -0800
commita114a55efb5b08f9e5f289203db2dfd4db82852a (patch)
tree8522e8eb3e77534ecf5c8e0208746b587eae887b /src/model
parentAdd Attachment::download{,to_directory} (diff)
downloadserenity-a114a55efb5b08f9e5f289203db2dfd4db82852a.tar.xz
serenity-a114a55efb5b08f9e5f289203db2dfd4db82852a.zip
Add webhook support
Diffstat (limited to 'src/model')
-rw-r--r--src/model/channel.rs23
-rw-r--r--src/model/gateway.rs16
-rw-r--r--src/model/guild.rs20
-rw-r--r--src/model/id.rs29
-rw-r--r--src/model/mod.rs4
-rw-r--r--src/model/webhook.rs168
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),
+ }
+ }
+}