mod attachment;
mod channel_id;
mod embed;
mod guild_channel;
mod message;
mod private_channel;
mod reaction;
mod channel_category;
pub use self::attachment::*;
pub use self::channel_id::*;
pub use self::embed::*;
pub use self::guild_channel::*;
pub use self::message::*;
pub use self::private_channel::*;
pub use self::reaction::*;
pub use self::channel_category::*;
use crate::model::prelude::*;
use serde::de::Error as DeError;
use serde::ser::{SerializeStruct, Serialize, Serializer};
use super::utils::deserialize_u64;
#[cfg(feature = "model")]
use std::fmt::{Display, Formatter, Result as FmtResult};
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::cache::FromStrAndCache;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::model::misc::ChannelParseError;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use crate::utils::parse_channel;
#[cfg(all(feature = "cache", feature = "model"))]
use crate::cache::Cache;
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
use async_trait::async_trait;
#[cfg(feature = "model")]
use crate::http::CacheHttp;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Channel {
Guild(GuildChannel),
Private(PrivateChannel),
Category(ChannelCategory),
}
#[cfg(feature = "model")]
impl Channel {
pub fn guild(self) -> Option<GuildChannel> {
match self {
Channel::Guild(lock) => Some(lock),
_ => None,
}
}
pub fn private(self) -> Option<PrivateChannel> {
match self {
Channel::Private(lock) => Some(lock),
_ => None,
}
}
pub fn category(self) -> Option<ChannelCategory> {
match self {
Channel::Category(lock) => Some(lock),
_ => None,
}
}
pub async fn delete(&self, cache_http: impl CacheHttp) -> Result<()> {
match self {
Channel::Guild(public_channel) => {
public_channel.delete(cache_http).await?;
},
Channel::Private(private_channel) => {
private_channel.delete(cache_http.http()).await?;
},
Channel::Category(category) => {
category.delete(cache_http).await?;
},
}
Ok(())
}
#[inline]
pub fn is_nsfw(&self) -> bool {
match self {
Channel::Guild(channel) => channel.is_nsfw(),
Channel::Category(category) => category.is_nsfw(),
Channel::Private(_) => false,
}
}
#[inline]
pub fn id(&self) -> ChannelId {
match self {
Channel::Guild(ch) => ch.id,
Channel::Private(ch) => ch.id,
Channel::Category(ch) => ch.id,
}
}
#[inline]
pub fn position(&self) -> Option<i64> {
match self {
Channel::Guild(channel) => Some(channel.position),
Channel::Category(catagory) => Some(catagory.position),
_ => None
}
}
}
impl<'de> Deserialize<'de> for Channel {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
let v = JsonMap::deserialize(deserializer)?;
let kind = {
let kind = v.get("type").ok_or_else(|| DeError::missing_field("type"))?;
kind.as_u64().unwrap()
};
match kind {
0 | 2 | 5 | 6 => serde_json::from_value::<GuildChannel>(Value::Object(v))
.map(Channel::Guild)
.map_err(DeError::custom),
1 => serde_json::from_value::<PrivateChannel>(Value::Object(v))
.map(Channel::Private)
.map_err(DeError::custom),
4 => serde_json::from_value::<ChannelCategory>(Value::Object(v))
.map(Channel::Category)
.map_err(DeError::custom),
_ => Err(DeError::custom("Unknown channel type")),
}
}
}
impl Serialize for Channel {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where S: Serializer {
match self {
Channel::Category(c) => ChannelCategory::serialize(c, serializer),
Channel::Guild(c) => GuildChannel::serialize(c, serializer),
Channel::Private(c) => PrivateChannel::serialize(c, serializer),
}
}
}
impl Display for Channel {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Channel::Guild(ch) => Display::fmt(&ch.id.mention(), f),
Channel::Private(ch) => Display::fmt(&ch.recipient.name, f),
Channel::Category(ch) => Display::fmt(&ch.name, f),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
pub enum ChannelType {
Text = 0,
Private = 1,
Voice = 2,
Category = 4,
News = 5,
Store = 6,
}
enum_number!(
ChannelType {
Text,
Private,
Voice,
Category,
News,
Store,
}
);
impl ChannelType {
#[inline]
pub fn name(&self) -> &str {
match *self {
ChannelType::Private => "private",
ChannelType::Text => "text",
ChannelType::Voice => "voice",
ChannelType::Category => "category",
ChannelType::News => "news",
ChannelType::Store => "store",
}
}
#[inline]
pub fn num(self) -> u64 {
match self {
ChannelType::Text => 0,
ChannelType::Private => 1,
ChannelType::Voice => 2,
ChannelType::Category => 4,
ChannelType::News => 5,
ChannelType::Store => 6,
}
}
}
#[derive(Deserialize, Serialize)]
struct PermissionOverwriteData {
allow: Permissions,
deny: Permissions,
#[serde(serialize_with = "serialize_u64", deserialize_with = "deserialize_u64")] id: u64,
#[serde(rename = "type")] kind: String,
}
#[derive(Clone, Debug)]
pub struct PermissionOverwrite {
pub allow: Permissions,
pub deny: Permissions,
pub kind: PermissionOverwriteType,
}
impl<'de> Deserialize<'de> for PermissionOverwrite {
fn deserialize<D: Deserializer<'de>>(deserializer: D)
-> StdResult<PermissionOverwrite, D::Error> {
let data = PermissionOverwriteData::deserialize(deserializer)?;
let kind = match &data.kind[..] {
"member" => PermissionOverwriteType::Member(UserId(data.id)),
"role" => PermissionOverwriteType::Role(RoleId(data.id)),
_ => return Err(DeError::custom("Unknown PermissionOverwriteType")),
};
Ok(PermissionOverwrite {
allow: data.allow,
deny: data.deny,
kind,
})
}
}
impl Serialize for PermissionOverwrite {
fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
where S: Serializer {
let (id, kind) = match self.kind {
PermissionOverwriteType::Member(id) => (id.0, "member"),
PermissionOverwriteType::Role(id) => (id.0, "role"),
};
let mut state = serializer.serialize_struct("PermissionOverwrite", 4)?;
state.serialize_field("allow", &self.allow.bits())?;
state.serialize_field("deny", &self.deny.bits())?;
state.serialize_field("id", &id)?;
state.serialize_field("type", kind)?;
state.end()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum PermissionOverwriteType {
Member(UserId),
Role(RoleId),
}
#[cfg(test)]
mod test {
#[cfg(all(feature = "model", feature = "utils"))]
mod model_utils {
use crate::model::prelude::*;
fn guild_channel() -> GuildChannel {
GuildChannel {
id: ChannelId(1),
bitrate: None,
category_id: None,
guild_id: GuildId(2),
kind: ChannelType::Text,
last_message_id: None,
last_pin_timestamp: None,
name: "nsfw-stuff".to_string(),
permission_overwrites: vec![],
position: 0,
topic: None,
user_limit: None,
nsfw: false,
slow_mode_rate: Some(0),
_nonexhaustive: (),
}
}
fn private_channel() -> PrivateChannel {
PrivateChannel {
id: ChannelId(1),
last_message_id: None,
last_pin_timestamp: None,
kind: ChannelType::Private,
recipient: User {
id: UserId(2),
avatar: None,
bot: false,
discriminator: 1,
name: "ab".to_string(),
_nonexhaustive: (),
},
_nonexhaustive: (),
}
}
#[test]
fn nsfw_checks() {
let mut channel = guild_channel();
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Voice;
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Text;
channel.name = "nsfw-".to_string();
assert!(!channel.is_nsfw());
channel.name = "nsfw".to_string();
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Voice;
assert!(!channel.is_nsfw());
channel.kind = ChannelType::Text;
channel.name = "nsf".to_string();
channel.nsfw = true;
assert!(channel.is_nsfw());
channel.nsfw = false;
assert!(!channel.is_nsfw());
let channel = Channel::Guild(channel);
assert!(!channel.is_nsfw());
let private_channel = private_channel();
assert!(!private_channel.is_nsfw());
}
}
}
#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
#[async_trait]
impl FromStrAndCache for Channel {
type Err = ChannelParseError;
async fn from_str<C>(cache: C, s: &str) -> StdResult<Self, Self::Err>
where C: AsRef<Cache> + Send + Sync
{
match parse_channel(s) {
Some(x) => match ChannelId(x).to_channel_cached(&cache).await {
Some(channel) => Ok(channel),
_ => Err(ChannelParseError::NotPresentInCache),
},
_ => Err(ChannelParseError::InvalidChannel),
}
}
}