use crate::context::{Context, Response};
use crate::error::Error;
use crate::types::timestamp::Timestamp;
use crate::types::user::{AvatarDecorationData, User};
use anyhow::Result;
use http::Method;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use serde_repr::{Deserialize_repr, Serialize_repr};
use tokio::sync::MutexGuard;
use super::{
channel::{welcome_screen::WelcomeScreen, Channel},
common::Emoji,
role::Role,
sticker::Sticker,
Snowflake,
};
#[derive(Serialize_repr, Deserialize_repr, Debug, Eq, PartialEq, Clone)]
#[repr(u8)]
pub enum MFALevel {
None = 0, Elevated = 1, }
#[derive(Serialize_repr, Deserialize_repr, Debug, Eq, PartialEq, Clone)]
#[repr(u8)]
pub enum NSFWLevel {
Default = 0,
Explicit = 1,
Safe = 2,
AgeRestricted = 3,
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Eq, PartialEq, Clone)]
#[repr(u8)]
pub enum VerificationLevel {
None = 0, Low = 1, Medium = 2, High = 3, VeryHigh = 4, }
#[derive(Serialize_repr, Deserialize_repr, Debug, Eq, PartialEq, Clone)]
#[repr(u8)]
pub enum MessageNotificationLevel {
AllMessages = 0,
OnlyMentions = 1,
}
#[derive(Serialize_repr, Deserialize_repr, Debug, Eq, PartialEq, Clone)]
#[repr(u8)]
pub enum ExplicitContentFilterLevel {
Disabled = 0, MembersWithoutRoles = 1,
AllMembers = 2,
}
#[derive(Debug)]
#[repr(u8)]
pub enum SystemChannelFlags {
SuppressJoinNotifications = 1 << 0,
SuppressPremiumSubscriptions = 1 << 1,
SuppressGuildReminders = 1 << 2,
SuppressJoinReplies = 1 << 3,
SuppressRoleSubPurchases = 1 << 4,
SuppressRoleSubPurchaseReplies = 1 << 5,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Guild {
pub id: Snowflake,
pub name: String,
pub owner_id: Snowflake,
pub icon: Option<String>,
pub icon_hash: Option<String>,
#[serde(rename = "vanity_url_code")]
pub vanity_invite: Option<String>,
pub description: Option<String>,
pub banner: Option<String>,
#[serde(rename = "discovery_splash")]
pub splash_discovery: Option<String>,
pub splash: Option<String>,
#[serde(rename = "preferred_locale")]
pub locale: String,
pub mfa_level: MFALevel,
pub nsfw_level: NSFWLevel,
pub verification_level: VerificationLevel,
#[serde(rename = "default_message_notifications")]
pub default_notification_level: MessageNotificationLevel,
#[serde(rename = "explicit_content_filter")]
pub explicit_content_filter_level: ExplicitContentFilterLevel,
pub roles: Option<Vec<Role>>,
pub emojis: Option<Vec<Emoji>>,
pub stickers: Option<Vec<Sticker>>,
pub features: Vec<String>,
pub application_id: Option<Snowflake>,
pub welcome_screen: Option<WelcomeScreen>,
pub public_updates_channel_id: Option<Snowflake>,
pub safety_alerts_channel_id: Option<Snowflake>,
pub system_channel_id: Option<Snowflake>,
pub rules_channel_id: Option<Snowflake>,
pub system_channel_flags: u8,
pub afk_channel_id: Option<Snowflake>,
pub afk_timeout: i32,
pub widget_channel_id: Option<Snowflake>,
pub widget_enabled: Option<bool>,
pub max_presences: Option<u64>, pub max_members: Option<u64>,
#[serde(rename = "premium_tier")]
pub boost_tier: u8, #[serde(rename = "premium_subscription_count")]
pub boosts: Option<u64>,
#[serde(rename = "premium_progress_bar_enabled")]
pub boost_bar_enabled: bool,
pub max_video_channel_users: u64,
pub max_stage_video_channel_users: u64,
pub owner: Option<bool>,
pub permissions: Option<String>,
pub member_count: Option<u64>,
pub presence_count: Option<u64>,
}
impl Guild {
pub fn icon_url(&self) -> Option<String> {
self.icon_hash
.as_ref()
.map(|hash| format!("https://cdn.discordapp.com/icons/{}/{}.png", self.id, hash))
}
pub fn banner_url(&self) -> Option<String> {
self.banner.as_ref().map(|hash| {
format!(
"https://cdn.discordapp.com/banners/{}/{}.png",
self.id, hash
)
})
}
pub fn splash_url(&self) -> Option<String> {
self.splash.as_ref().map(|hash| {
format!(
"https://cdn.discordapp.com/splashes/{}/{}.png",
self.id, hash
)
})
}
pub fn discovery_splash_url(&self) -> Option<String> {
self.splash_discovery.as_ref().map(|hash| {
format!(
"https://cdn.discordapp.com/splashes/{}/{}.png",
self.id, hash
)
})
}
pub async fn fetch_guild(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(Method::GET, &format!("/v9/guilds/{}", id), None)
.await
}
pub async fn delete_guild(self, ctx: &mut MutexGuard<'_, Context>) -> Result<Response> {
ctx.request(
Method::DELETE,
&format!("/v9/guilds/{}", self.id),
None,
)
.await
}
pub async fn fetch_channels_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/channels", id),
None,
)
.await
}
pub async fn fetch_channels(
&self,
ctx: &mut MutexGuard<'_, Context>,
) -> Result<Response> {
Self::fetch_channels_static(ctx, self.id).await
}
pub async fn create_channel_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
channel: Value,
) -> Result<Response> {
ctx.request(
Method::POST,
&format!("/v9/guilds/{}/channels", id),
Some(channel),
)
.await
}
pub async fn create_channel(
&self,
ctx: &mut MutexGuard<'_, Context>,
channel: Value,
) -> Result<Response> {
Self::create_channel_static(ctx, self.id, channel).await
}
pub async fn fetch_members_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
limit: u64,
) -> Result<Response> {
if limit == 0 || limit > 1000 {
return Err(
Error::InvalidApiRequest("limit must be between 1 and 1000".to_string()).into(),
);
}
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/members?limit={}", id, limit),
None,
)
.await
}
pub async fn fetch_members(
&self,
ctx: &mut MutexGuard<'_, Context>,
limit: u64,
) -> Result<Response> {
Self::fetch_members_static(ctx, self.id, limit).await
}
pub async fn fetch_member_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/members/{}", id, user_id),
None,
)
.await
}
pub async fn fetch_member(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
) -> Result<Response> {
Self::fetch_member_static(ctx, self.id, user_id).await
}
pub async fn search_members_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
query: String,
limit: u64,
) -> Result<Response> {
if limit == 0 || limit > 1000 {
return Err(
Error::InvalidApiRequest("limit must be between 1 and 1000".to_string()).into(),
);
}
ctx.request(
Method::GET,
&format!(
"/v9/guilds/{}/members/search?query={}&limit={}",
id, query, limit
),
None,
)
.await
}
pub async fn search_members(
&self,
ctx: &mut MutexGuard<'_, Context>,
query: String,
limit: u64,
) -> Result<Response> {
Self::search_members_static(ctx, self.id, query, limit).await
}
pub async fn edit_member_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
member: Value,
) -> Result<Response> {
ctx.request(
Method::PATCH,
&format!("/v9/guilds/{}/members/{}", id, user_id),
Some(member),
)
.await
}
pub async fn edit_member(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
member: Value,
) -> Result<Response> {
Self::edit_member_static(ctx, self.id, user_id, member).await
}
pub async fn kick_member_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::DELETE,
&format!("/v9/guilds/{}/members/{}", id, user_id),
None,
)
.await
}
pub async fn kick_member(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
) -> Result<Response> {
Self::kick_member_static(ctx, self.id, user_id).await
}
pub async fn ban_member_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::PUT,
&format!("/v9/guilds/{}/bans/{}", id, user_id),
None,
)
.await
}
pub async fn ban_member(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
) -> Result<Response> {
Self::ban_member_static(ctx, self.id, user_id).await
}
pub async fn unban_member_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::DELETE,
&format!("/v9/guilds/{}/bans/{}", id, user_id),
None,
)
.await
}
pub async fn unban_member(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
) -> Result<Response> {
Self::unban_member_static(ctx, self.id, user_id).await
}
pub async fn get_bans_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(Method::GET, &format!("/v9/guilds/{}/bans", id), None)
.await
}
pub async fn get_bans(&self, ctx: &mut MutexGuard<'_, Context>) -> Result<Response> {
Self::get_bans_static(ctx, self.id).await
}
pub async fn get_ban_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
user_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/bans/{}", id, user_id),
None,
)
.await
}
pub async fn get_ban(
&self,
ctx: &mut MutexGuard<'_, Context>,
user_id: Snowflake,
) -> Result<Response> {
Self::get_ban_static(ctx, self.id, user_id).await
}
pub async fn fetch_roles_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(Method::GET, &format!("/v9/guilds/{}/roles", id), None)
.await
}
pub async fn fetch_roles(&self, ctx: &mut MutexGuard<'_, Context>) -> Result<Response> {
Self::fetch_roles_static(ctx, self.id).await
}
pub async fn create_role_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
role: Value,
) -> Result<Response> {
ctx.request(
Method::POST,
&format!("/v9/guilds/{}/roles", id),
Some(role),
)
.await
}
pub async fn create_role(
&self,
ctx: &mut MutexGuard<'_, Context>,
role: Value,
) -> Result<Response> {
Self::create_role_static(ctx, self.id, role).await
}
pub async fn edit_role_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
role_id: Snowflake,
role: Value,
) -> Result<Response> {
ctx.request(
Method::PATCH,
&format!("/v9/guilds/{}/roles/{}", id, role_id),
Some(role),
)
.await
}
pub async fn edit_role(
&self,
ctx: &mut MutexGuard<'_, Context>,
role_id: Snowflake,
role: Value,
) -> Result<Response> {
Self::edit_role_static(ctx, self.id, role_id, role).await
}
pub async fn delete_role_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
role_id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::DELETE,
&format!("/v9/guilds/{}/roles/{}", id, role_id),
None,
)
.await
}
pub async fn delete_role(
&self,
ctx: &mut MutexGuard<'_, Context>,
role_id: Snowflake,
) -> Result<Response> {
Self::delete_role_static(ctx, self.id, role_id).await
}
pub async fn edit_role_positions_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
roles: Value,
) -> Result<Response> {
ctx.request(
Method::PATCH,
&format!("/v9/guilds/{}/roles", id),
Some(roles),
)
.await
}
pub async fn edit_role_positions(
&self,
ctx: &mut MutexGuard<'_, Context>,
roles: Value,
) -> Result<Response> {
Self::edit_role_positions_static(ctx, self.id, roles).await
}
pub async fn fetch_invites_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/invites", id),
None,
)
.await
}
pub async fn fetch_invites(
&self,
ctx: &mut MutexGuard<'_, Context>,
) -> Result<Response> {
Self::fetch_invites_static(ctx, self.id).await
}
pub async fn fetch_welcome_screen_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/welcome-screen", id),
None,
)
.await
}
pub async fn fetch_welcome_screen(
&self,
ctx: &mut MutexGuard<'_, Context>,
) -> Result<Response> {
Self::fetch_welcome_screen_static(ctx, self.id).await
}
pub async fn fetch_onboarding_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/onboarding", id),
None,
)
.await
}
pub async fn fetch_onboarding(
&self,
ctx: &mut MutexGuard<'_, Context>,
) -> Result<Response> {
Self::fetch_onboarding_static(ctx, self.id).await
}
pub async fn fetch_vanity_url_static(
ctx: &mut MutexGuard<'_, Context>,
id: Snowflake,
) -> Result<Response> {
ctx.request(
Method::GET,
&format!("/v9/guilds/{}/vanity-url", id),
None,
)
.await
}
pub async fn fetch_vanity_url(
&self,
ctx: &mut MutexGuard<'_, Context>,
) -> Result<Response> {
Self::fetch_vanity_url_static(ctx, self.id).await
}
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct CachedGuild {
pub id: Snowflake,
pub joined_at: Timestamp,
pub properties: Guild,
pub large: bool,
pub lazy: bool,
pub member_count: u64,
#[serde(rename = "premium_subscription_count")]
pub boosts: u64,
#[serde(skip)]
pub activity_instances: Option<()>, #[serde(skip)]
pub application_command_counts: Option<()>,
#[serde(skip)]
pub stage_instances: Vec<()>, pub channels: Vec<Channel>,
pub threads: Vec<Channel>,
pub stickers: Vec<Sticker>,
pub emojis: Vec<Emoji>,
pub roles: Vec<Role>,
pub data_mode: String,
#[serde(skip)]
pub guild_scheduled_events: Vec<()>,
pub version: u64,
}
impl CachedGuild {
pub async fn into_guild(self, ctx: &mut MutexGuard<'_, Context>) -> Result<Guild> {
Ok(serde_json::from_value(
Guild::fetch_guild(ctx, self.id).await?.body,
)?)
}
}
#[derive(Serialize_repr, Deserialize_repr, Debug)]
#[repr(u8)]
pub enum GuildMemberFlags {
DidRejoin = 1 << 0,
CompletedOnboarding = 1 << 1,
BypassesVerification = 1 << 2,
StartedOnboarding = 1 << 3,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct GuildMember {
pub user: Option<User>,
pub nick: Option<String>,
pub avatar: Option<String>,
pub roles: Vec<Snowflake>,
pub joined_at: Timestamp,
pub premium_since: Option<Timestamp>,
pub deaf: bool,
pub mute: bool,
pub flags: u8,
pub pending: bool,
pub permissions: String,
pub communication_disabled_until: Option<Timestamp>,
pub avatar_decoration_data: Option<AvatarDecorationData>,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct GuildMemberEditBuilder {
value: Value,
}
impl GuildMemberEditBuilder {
pub fn new() -> Self {
Self { value: json!({}) }
}
pub fn set_nick(&mut self, nick: String) {
self.value["nick"] = json!(nick);
}
pub fn set_roles(&mut self, roles: Vec<Snowflake>) {
self.value["roles"] = json!(roles);
}
pub fn set_deaf(&mut self, deaf: bool) {
self.value["deaf"] = json!(deaf);
}
pub fn set_mute(&mut self, mute: bool) {
self.value["mute"] = json!(mute);
}
pub fn set_voice_channel(&mut self, channel_id: Snowflake) {
self.value["channel_id"] = json!(channel_id);
}
pub fn set_timeout(&mut self, timeout: Option<String>) {
self.value["communication_disabled_until"] = json!(timeout);
}
pub fn build(self) -> Value {
self.value
}
}