Skip to content

Commit

Permalink
Increase the capabilities for creating a channel.
Browse files Browse the repository at this point in the history
  • Loading branch information
arqunis committed Jun 6, 2019
1 parent 7f9c4e1 commit f2ff97a
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 34 deletions.
145 changes: 145 additions & 0 deletions src/builder/create_channel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use crate::internal::prelude::*;
use crate::model::prelude::*;

use serde_json::{json, Value};

use std::collections::HashMap;

/// A builder for creating a new [`GuildChannel`] in a [`Guild`].
///
/// Except [`name`], all fields are optional.
///
/// [`GuildChannel`]: ../model/channel/struct.GuildChannel.html
/// [`Guild`]: ../model/guild/struct.Guild.html
/// [`name`]: #method.name
#[derive(Debug, Clone)]
pub struct CreateChannel(pub HashMap<&'static str, Value>);

impl CreateChannel {
/// Specify how to call this new channel.
///
/// **Note**: Must be between 2 and 100 characters long.
pub fn name<D: ToString>(&mut self, name: D) -> &mut Self {
self.0.insert("name", Value::String(name.to_string()));

self
}
/// Specify what type the channel is, whether it's a text, voice, category or news channel.
pub fn kind(&mut self, kind: ChannelType) -> &mut Self {
self.0.insert("type", Value::Number(Number::from(kind as u8)));

self
}

/// Specifiy the category, the "parent" of this channel.
pub fn category<I: Into<ChannelId>>(&mut self, id: I) -> &mut Self {
self.0.insert("parent_id", Value::Number(Number::from(id.into().0)));

self
}

/// Set an interesting topic.
///
/// **Note**: Must be between 0 and 1000 characters long.
pub fn topic<D: ToString>(&mut self, topic: D) -> &mut Self {
self.0.insert("topic", Value::String(topic.to_string()));

self
}

/// Specify if this channel will be inappropriate to browse while at work.
pub fn nsfw(&mut self, b: bool) -> &mut Self {
self.0.insert("nsfw", Value::Bool(b));

self
}

/// [Voice-only] Specify the bitrate at which sound plays in the voice channel.
pub fn bitrate(&mut self, rate: u32) -> &mut Self {
self.0.insert("bitrate", Value::Number(Number::from(rate)));

self
}

/// [Voice-only] Set how many users may occupy this voice channel.
pub fn user_limit(&mut self, limit: u32) -> &mut Self {
self.0.insert("user_limit", Value::Number(Number::from(limit)));

self
}

/// How many seconds must a user wait before sending another message.
///
/// Bots, or users with the `MANAGE_MESSAGES` and/or`MANAGE_CHANNEL` permissions are exempt
/// from this restriction.
///
/// **Note**: Must be between 0 and 21600 seconds (360 minutes or 6 hours).
pub fn rate_limit(&mut self, limit: u64) -> &mut Self {
self.0.insert("rate_limit_per_user", Value::Number(Number::from(limit)));

self
}

/// Specify where the channel should be located.
pub fn position(&mut self, pos: u32) -> &mut Self {
self.0.insert("position", Value::Number(Number::from(pos)));

self
}

/// A set of overwrites defining what a user or a user carrying a certain role can
/// and cannot do.
///
/// # Example
///
/// Inheriting permissions from an exisiting channel:
///
/// ```rust,ignore
/// // Assuming a channel and a guild have already been bound.
/// guild.create_channel(|c|
/// c.name("my_new_cool_channel")
/// .permissions(channel.permissions.clone()))
/// ```
pub fn permissions<I>(&mut self, perms: I) -> &mut Self
where I: IntoIterator<Item=PermissionOverwrite>
{
let overwrites = perms.into_iter().map(|perm| {
let (id, kind) = match perm.kind {
PermissionOverwriteType::Member(id) => (id.0, "member"),
PermissionOverwriteType::Role(id) => (id.0, "role"),
PermissionOverwriteType::__Nonexhaustive => unreachable!(),
};

json!({
"allow": perm.allow.bits(),
"deny": perm.deny.bits(),
"id": id,
"type": kind,
})
}).collect();

self.0.insert("permission_overwrites", Value::Array(overwrites));

self
}
}

impl Default for CreateChannel {
/// Creates a builder with default values, setting `kind` to `ChannelType::Text`.
///
/// # Examples
///
/// Create a default `CreateChannel` builder:
///
/// ```rust
/// use serenity::builder::CreateChannel;
///
/// let channel_builder = CreateChannel::default();
/// ```
fn default() -> Self {
let mut builder = CreateChannel(HashMap::new());
builder.kind(ChannelType::Text);

builder
}
}
2 changes: 2 additions & 0 deletions src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//! by a builder.
mod create_embed;
mod create_channel;
mod create_invite;
mod create_message;
mod edit_channel;
Expand All @@ -19,6 +20,7 @@ mod get_messages;

pub use self::{
create_embed::{CreateEmbed, CreateEmbedAuthor, CreateEmbedFooter},
create_channel::CreateChannel,
create_invite::CreateInvite,
create_message::CreateMessage,
edit_channel::EditChannel,
Expand Down
6 changes: 4 additions & 2 deletions src/http/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,9 +209,11 @@ impl Http {
/// [`GuildChannel`]: ../../model/channel/struct.GuildChannel.html
/// [docs]: https://discordapp.com/developers/docs/resources/guild#create-guild-channel
/// [Manage Channels]: ../../model/permissions/struct.Permissions.html#associatedconstant.MANAGE_CHANNELS
pub fn create_channel(&self, guild_id: u64, map: &Value) -> Result<GuildChannel> {
pub fn create_channel(&self, guild_id: u64, map: &JsonMap) -> Result<GuildChannel> {
let body = serde_json::to_vec(map)?;

self.fire(Request {
body: Some(map.to_string().as_bytes()),
body: Some(&body),
headers: None,
route: RouteInfo::CreateChannel { guild_id },
})
Expand Down
25 changes: 7 additions & 18 deletions src/model/guild/guild_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use crate::model::guild::BanOptions;
use crate::utils;
#[cfg(feature = "http")]
use crate::http::Http;
#[cfg(feature = "model")]
use crate::builder::CreateChannel;

#[cfg(feature = "model")]
impl GuildId {
Expand Down Expand Up @@ -120,32 +122,19 @@ impl GuildId {
/// use serenity::model::id::GuildId;
/// use serenity::model::channel::ChannelType;
///
/// let _channel = GuildId(7).create_channel("test", ChannelType::Voice, None);
/// let _channel = GuildId(7).create_channel(|c| c.name("test").kind(ChannelType::Voice));
/// ```
///
/// [`GuildChannel`]: ../channel/struct.GuildChannel.html
/// [`http::create_channel`]: ../../http/fn.create_channel.html
/// [Manage Channels]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_CHANNELS
#[cfg(feature = "http")]
#[inline]
pub fn create_channel<C>(self, http: impl AsRef<Http>, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
where C: Into<Option<ChannelId>> {
self._create_channel(&http, name, kind, category.into())
}
pub fn create_channel(self, http: impl AsRef<Http>, f: impl FnOnce(&mut CreateChannel) -> &mut CreateChannel) -> Result<GuildChannel> {
let mut builder = CreateChannel::default();
f(&mut builder);

#[cfg(feature = "http")]
fn _create_channel(
self,
http: impl AsRef<Http>,
name: &str,
kind: ChannelType,
category: Option<ChannelId>,
) -> Result<GuildChannel> {
let map = json!({
"name": name,
"type": kind as u8,
"parent_id": category.map(|c| c.0)
});
let map = utils::hashmap_to_json_map(builder.0);

http.as_ref().create_channel(self.0, &map)
}
Expand Down
15 changes: 6 additions & 9 deletions src/model/guild/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ pub use self::role::*;
pub use self::audit_log::*;

use chrono::{DateTime, FixedOffset};
use crate::{model::prelude::*};
use crate::model::prelude::*;
use serde::de::Error as DeError;
use serde_json::{json};
use serde_json::json;
use super::utils::*;
use log::{error, warn};

Expand All @@ -32,12 +32,10 @@ use parking_lot::RwLock;
#[cfg(all(feature = "cache", feature = "model"))]
use std::sync::Arc;
#[cfg(feature = "model")]
use crate::builder::{EditGuild, EditMember, EditRole};
use crate::builder::{CreateChannel, EditGuild, EditMember, EditRole};
#[cfg(feature = "model")]
use crate::constants::LARGE_THRESHOLD;
#[cfg(feature = "model")]
use std;
#[cfg(feature = "model")]
use std::borrow::Cow;
#[cfg(feature = "http")]
use crate::http::Http;
Expand Down Expand Up @@ -367,7 +365,7 @@ impl Guild {
///
/// // assuming a `guild` has already been bound
///
/// let _ = guild.create_channel("my-test-channel", ChannelType::Text, None);
/// let _ = guild.create_channel(|c| c.name("my-test-channel").kind(ChannelType::Text));
/// ```
///
/// # Errors
Expand All @@ -379,8 +377,7 @@ impl Guild {
/// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
/// [Manage Channels]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_CHANNELS
#[cfg(feature = "client")]
pub fn create_channel<C>(&self, context: &Context, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
where C: Into<Option<ChannelId>> {
pub fn create_channel(&self, context: &Context, f: impl FnOnce(&mut CreateChannel) -> &mut CreateChannel) -> Result<GuildChannel> {
#[cfg(feature = "cache")]
{
let req = Permissions::MANAGE_CHANNELS;
Expand All @@ -390,7 +387,7 @@ impl Guild {
}
}

self.id.create_channel(&context.http, name, kind, category)
self.id.create_channel(&context.http, f)
}

/// Creates an emoji in the guild with a name and base64-encoded image. The
Expand Down
9 changes: 4 additions & 5 deletions src/model/guild/partial_guild.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::super::utils::{deserialize_emojis, deserialize_roles};
#[cfg(feature = "client")]
use crate::client::Context;
#[cfg(feature = "model")]
use crate::builder::{EditGuild, EditMember, EditRole};
use crate::builder::{CreateChannel, EditGuild, EditMember, EditRole};
#[cfg(feature = "http")]
use crate::http::Http;

Expand Down Expand Up @@ -102,17 +102,16 @@ impl PartialGuild {
/// ```rust,ignore
/// use serenity::model::ChannelType;
///
/// guild.create_channel("test", ChannelType::Voice, None);
/// guild.create_channel(|c| c.name("test").kind(ChannelType::Voice));
/// ```
///
/// [`GuildChannel`]: ../channel/struct.GuildChannel.html
/// [`http::create_channel`]: ../../http/fn.create_channel.html
/// [Manage Channels]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_CHANNELS
#[cfg(feature = "http")]
#[inline]
pub fn create_channel<C>(&self, http: impl AsRef<Http>, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel>
where C: Into<Option<ChannelId>> {
self.id.create_channel(&http, name, kind, category)
pub fn create_channel(&self, http: impl AsRef<Http>, f: impl FnOnce(&mut CreateChannel) -> &mut CreateChannel) -> Result<GuildChannel> {
self.id.create_channel(&http, f)
}

/// Creates an emoji in the guild with a name and base64-encoded image.
Expand Down

0 comments on commit f2ff97a

Please sign in to comment.