use crate::{models::PermissionPair, Error};
use serde::{Deserialize, Serialize};
use std::str::FromStr;
#[cfg(feature = "openapi")]
use utoipa::{
openapi::{Array, ArrayBuilder, KnownFormat, ObjectBuilder, SchemaFormat, SchemaType},
ToSchema,
};
#[derive(Clone, Debug, Default, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct TextBasedGuildChannelInfo {
pub topic: Option<String>,
pub nsfw: bool,
pub locked: bool,
pub slowmode: u32,
}
#[derive(Copy, Clone, Debug, Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "client", derive(Serialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "snake_case")]
pub enum ChannelType {
Text,
Announcement,
Voice,
Category,
Dm,
Group,
}
impl FromStr for ChannelType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"text" => Ok(Self::Text),
"announcement" => Ok(Self::Announcement),
"voice" => Ok(Self::Voice),
"category" => Ok(Self::Category),
"dm" => Ok(Self::Dm),
"group" => Ok(Self::Group),
_ => Err(Error::InternalError {
what: None,
message: "Database returned invalid channel type".to_string(),
debug: None,
}),
}
}
}
impl ChannelType {
#[inline]
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::Text => "text",
Self::Announcement => "announcement",
Self::Voice => "voice",
Self::Category => "category",
Self::Dm => "dm",
Self::Group => "group",
}
}
#[inline]
#[must_use]
pub const fn is_guild_text_based(&self) -> bool {
matches!(self, Self::Text | Self::Announcement)
}
#[inline]
#[must_use]
pub const fn is_text_based(&self) -> bool {
self.is_guild_text_based() || self.is_dm()
}
#[inline]
#[must_use]
pub const fn is_guild(&self) -> bool {
matches!(
self,
Self::Text | Self::Announcement | Self::Voice | Self::Category
)
}
#[inline]
#[must_use]
pub const fn is_dm(&self) -> bool {
matches!(self, Self::Dm | Self::Group)
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum GuildChannelInfo {
Text(TextBasedGuildChannelInfo),
Announcement(TextBasedGuildChannelInfo),
Voice {
user_limit: u16,
},
Category,
}
impl GuildChannelInfo {
#[inline]
#[must_use]
pub const fn channel_type(&self) -> ChannelType {
match self {
Self::Text { .. } => ChannelType::Text,
Self::Announcement { .. } => ChannelType::Announcement,
Self::Voice { .. } => ChannelType::Voice,
Self::Category => ChannelType::Category,
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct PermissionOverwrite {
pub id: u64,
#[serde(flatten)]
pub permissions: PermissionPair,
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct GuildChannel {
pub id: u64,
pub guild_id: u64,
#[serde(flatten)]
pub info: GuildChannelInfo,
pub name: String,
pub position: u16,
pub overwrites: Vec<PermissionOverwrite>,
pub parent_id: Option<u64>,
}
impl Default for GuildChannel {
fn default() -> Self {
Self {
id: 0,
guild_id: 0,
info: GuildChannelInfo::Text(TextBasedGuildChannelInfo::default()),
name: "general".to_string(),
position: 0,
overwrites: Vec::new(),
parent_id: None,
}
}
}
#[cfg(feature = "openapi")]
fn tuple_u64_u64() -> Array {
ArrayBuilder::new()
.items(
ObjectBuilder::new()
.schema_type(SchemaType::Integer)
.format(Some(SchemaFormat::KnownFormat(KnownFormat::Int64))),
)
.min_items(Some(2))
.max_items(Some(2))
.build()
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum DmChannelInfo {
Dm {
#[cfg_attr(feature = "openapi", schema(schema_with = tuple_u64_u64))]
recipient_ids: (u64, u64),
},
Group {
name: String,
topic: Option<String>,
icon: Option<String>,
owner_id: u64,
recipient_ids: Vec<u64>,
},
}
impl DmChannelInfo {
#[inline]
#[must_use]
pub const fn channel_type(&self) -> ChannelType {
match self {
Self::Dm { .. } => ChannelType::Dm,
Self::Group { .. } => ChannelType::Group,
}
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct DmChannel {
pub id: u64,
#[serde(flatten)]
pub info: DmChannelInfo,
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(untagged)]
pub enum Channel {
Guild(GuildChannel),
Dm(DmChannel),
}
impl Channel {
#[must_use]
pub fn name(&self) -> Option<&str> {
match self {
Self::Guild(channel) => Some(&channel.name),
Self::Dm(channel) => {
if let DmChannelInfo::Group { ref name, .. } = channel.info {
Some(name)
} else {
None
}
}
}
}
pub fn set_name(&mut self, name: String) {
match self {
Self::Guild(channel) => channel.name = name,
Self::Dm(channel) => {
if let DmChannelInfo::Group {
name: ref mut group_name,
..
} = channel.info
{
*group_name = name;
}
}
}
}
#[must_use]
pub fn topic(&self) -> Option<&str> {
match self {
Self::Guild(channel) => {
if let GuildChannelInfo::Text(ref info) | GuildChannelInfo::Announcement(ref info) =
channel.info
{
info.topic.as_deref()
} else {
None
}
}
Self::Dm(channel) => {
if let DmChannelInfo::Group { ref topic, .. } = channel.info {
topic.as_deref()
} else {
None
}
}
}
}
pub fn set_topic(&mut self, topic: Option<String>) {
match self {
Self::Guild(channel) => {
if let GuildChannelInfo::Text(ref mut info)
| GuildChannelInfo::Announcement(ref mut info) = channel.info
{
info.topic = topic;
}
}
Self::Dm(channel) => {
if let DmChannelInfo::Group {
topic: ref mut group_topic,
..
} = channel.info
{
*group_topic = topic;
}
}
}
}
#[must_use]
pub fn icon(&self) -> Option<&str> {
match self {
Self::Guild(_) => None, Self::Dm(channel) => {
if let DmChannelInfo::Group { ref icon, .. } = channel.info {
icon.as_deref()
} else {
None
}
}
}
}
pub fn set_icon(&mut self, icon: Option<String>) {
match self {
Self::Guild(_) => (), Self::Dm(channel) => {
if let DmChannelInfo::Group {
icon: ref mut group_icon,
..
} = channel.info
{
*group_icon = icon;
}
}
}
}
}
#[derive(Clone, Debug, Serialize)]
#[cfg_attr(feature = "client", derive(Deserialize))]
#[serde(untagged)]
pub enum ChannelInfo {
Guild(GuildChannelInfo),
Dm(DmChannelInfo),
}