use crate::error::HttpError;
use crate::http::client::HttpClient;
use crate::http::routing::Route;
use crate::model::audit_log::AuditLog;
use crate::model::channel::{Channel, ChannelType};
use crate::model::guild::{Guild, Member};
use crate::model::id::{ChannelId, GuildId, RoleId, UserId};
use serde::{Deserialize, Serialize};
impl HttpClient {
pub async fn create_guild(&self, params: &CreateGuild) -> Result<Guild, HttpError> {
self.request(Route::CreateGuild, Some(params)).await
}
pub async fn delete_guild(
&self,
guild_id: GuildId,
sudo: &impl Serialize,
) -> Result<(), HttpError> {
self.request_empty(Route::DeleteGuild2 { guild_id }, Some(sudo))
.await
}
pub async fn transfer_guild_ownership(
&self,
guild_id: GuildId,
body: &impl Serialize,
) -> Result<Guild, HttpError> {
self.request(Route::TransferGuildOwnership { guild_id }, Some(body))
.await
}
pub async fn toggle_detached_banner(
&self,
guild_id: GuildId,
enabled: bool,
) -> Result<(), HttpError> {
#[derive(Serialize)]
struct Body {
enabled: bool,
}
self.request_empty(
Route::ToggleDetachedBanner { guild_id },
Some(&Body { enabled }),
)
.await
}
pub async fn toggle_text_channel_flexible_names(
&self,
guild_id: GuildId,
enabled: bool,
) -> Result<(), HttpError> {
#[derive(Serialize)]
struct Body {
enabled: bool,
}
self.request_empty(
Route::ToggleTextChannelFlexibleNames { guild_id },
Some(&Body { enabled }),
)
.await
}
pub async fn update_role_hoist_positions(
&self,
guild_id: GuildId,
positions: &[RoleHoistPosition],
) -> Result<(), HttpError> {
self.request_empty(
Route::UpdateRoleHoistPositions { guild_id },
Some(&positions),
)
.await
}
pub async fn reset_role_hoist_positions(&self, guild_id: GuildId) -> Result<(), HttpError> {
self.request_empty(Route::ResetRoleHoistPositions { guild_id }, None::<&()>)
.await
}
pub async fn get_guild(&self, guild_id: GuildId) -> Result<Guild, HttpError> {
self.request_no_body(Route::GetGuild { guild_id }).await
}
pub async fn get_guild_preview(&self, guild_id: GuildId) -> Result<Guild, HttpError> {
self.request_no_body(Route::GetGuildPreview { guild_id })
.await
}
pub async fn modify_guild(
&self,
guild_id: GuildId,
params: &ModifyGuild,
) -> Result<Guild, HttpError> {
self.request(Route::ModifyGuild { guild_id }, Some(params))
.await
}
pub async fn get_guild_channels(&self, guild_id: GuildId) -> Result<Vec<Channel>, HttpError> {
self.request_no_body(Route::GetGuildChannels { guild_id })
.await
}
pub async fn create_guild_channel(
&self,
guild_id: GuildId,
params: &CreateGuildChannel,
) -> Result<Channel, HttpError> {
self.request(Route::CreateGuildChannel { guild_id }, Some(params))
.await
}
pub async fn get_guild_members(&self, guild_id: GuildId) -> Result<Vec<Member>, HttpError> {
self.request_no_body(Route::GetGuildMembers { guild_id })
.await
}
pub async fn get_guild_member(
&self,
guild_id: GuildId,
user_id: UserId,
) -> Result<Member, HttpError> {
self.request_no_body(Route::GetGuildMember { guild_id, user_id })
.await
}
pub async fn modify_guild_member(
&self,
guild_id: GuildId,
user_id: UserId,
params: &ModifyGuildMember,
) -> Result<Member, HttpError> {
self.request(Route::ModifyGuildMember { guild_id, user_id }, Some(params))
.await
}
pub async fn modify_current_member(
&self,
guild_id: GuildId,
params: &ModifyCurrentMember,
) -> Result<Member, HttpError> {
self.request(Route::ModifyCurrentMember { guild_id }, Some(params))
.await
}
pub async fn get_current_guild_member(&self, guild_id: GuildId) -> Result<Member, HttpError> {
self.request_no_body(Route::GetCurrentGuildMember { guild_id })
.await
}
pub async fn list_current_user_guilds(
&self,
params: &ListCurrentUserGuilds,
) -> Result<Vec<Guild>, HttpError> {
self.request_no_body(Route::ListCurrentUserGuilds {
query: params.to_query(),
})
.await
}
pub async fn leave_guild(&self, guild_id: GuildId) -> Result<(), HttpError> {
self.request_empty(Route::LeaveGuild { guild_id }, None::<&()>)
.await
}
pub async fn list_guild_audit_logs(
&self,
guild_id: GuildId,
params: &ListAuditLogsParams,
) -> Result<AuditLog, HttpError> {
self.request_no_body(Route::ListGuildAuditLogs {
guild_id,
query: params.to_query(),
})
.await
}
pub async fn search_guild_members(
&self,
guild_id: GuildId,
params: &GuildMemberSearch,
) -> Result<GuildMemberSearchResponse, HttpError> {
self.request(Route::SearchGuildMembers { guild_id }, Some(params))
.await
}
pub async fn update_guild_channel_positions(
&self,
guild_id: GuildId,
positions: &[ChannelPositionUpdate],
) -> Result<(), HttpError> {
self.request_empty(
Route::UpdateGuildChannelPositions { guild_id },
Some(&positions),
)
.await
}
pub async fn get_guild_vanity_url(&self, guild_id: GuildId) -> Result<VanityUrl, HttpError> {
self.request_no_body(Route::GetGuildVanityUrl { guild_id })
.await
}
pub async fn update_guild_vanity_url(
&self,
guild_id: GuildId,
code: Option<&str>,
) -> Result<VanityUrl, HttpError> {
#[derive(Serialize)]
struct Body<'a> {
code: Option<&'a str>,
}
self.request(
Route::UpdateGuildVanityUrl { guild_id },
Some(&Body { code }),
)
.await
}
pub async fn update_guild_role_positions(
&self,
guild_id: GuildId,
positions: &[RolePositionUpdate],
) -> Result<Vec<crate::model::guild::Role>, HttpError> {
self.request(
Route::UpdateGuildRolePositions { guild_id },
Some(&positions),
)
.await
}
}
#[derive(Debug, serde::Serialize)]
pub struct CreateGuildChannel {
pub name: String,
#[serde(rename = "type")]
pub kind: ChannelType,
#[serde(skip_serializing_if = "Option::is_none")]
pub topic: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nsfw: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<ChannelId>,
}
impl CreateGuildChannel {
pub fn text(name: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: ChannelType::Text,
topic: None,
nsfw: None,
parent_id: None,
}
}
pub fn voice(name: impl Into<String>) -> Self {
Self {
name: name.into(),
kind: ChannelType::Voice,
topic: None,
nsfw: None,
parent_id: None,
}
}
}
#[derive(Debug, Default, serde::Serialize)]
pub struct ModifyGuild {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub afk_channel_id: Option<ChannelId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub afk_timeout: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_channel_id: Option<ChannelId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rules_channel_id: Option<ChannelId>,
}
#[derive(Debug, Default, serde::Serialize)]
pub struct ModifyGuildMember {
#[serde(skip_serializing_if = "Option::is_none")]
pub nick: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<RoleId>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mute: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deaf: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub channel_id: Option<ChannelId>,
#[serde(skip_serializing_if = "Option::is_none")]
pub communication_disabled_until: Option<String>,
}
impl ModifyGuildMember {
pub fn new() -> Self {
Self::default()
}
pub fn nick(mut self, nick: impl Into<String>) -> Self {
self.nick = Some(nick.into());
self
}
pub fn mute(mut self, mute: bool) -> Self {
self.mute = Some(mute);
self
}
pub fn deaf(mut self, deaf: bool) -> Self {
self.deaf = Some(deaf);
self
}
pub fn roles(mut self, roles: Vec<RoleId>) -> Self {
self.roles = Some(roles);
self
}
pub fn timeout(mut self, until: impl Into<String>) -> Self {
self.communication_disabled_until = Some(until.into());
self
}
}
#[derive(Debug, Default, serde::Serialize)]
pub struct ModifyCurrentMember {
#[serde(skip_serializing_if = "Option::is_none")]
pub nick: Option<String>,
}
impl ModifyCurrentMember {
pub fn nick(nick: impl Into<String>) -> Self {
Self {
nick: Some(nick.into()),
}
}
}
#[derive(Debug, Default, Clone)]
pub struct ListAuditLogsParams {
pub user_id: Option<UserId>,
pub action_type: Option<u32>,
pub before: Option<String>,
pub after: Option<String>,
pub limit: Option<u32>,
}
impl ListAuditLogsParams {
fn to_query(&self) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(v) = self.user_id {
parts.push(format!("user_id={v}"));
}
if let Some(v) = self.action_type {
parts.push(format!("action_type={v}"));
}
if let Some(v) = &self.before {
parts.push(format!("before={}", urlencoding::encode(v)));
}
if let Some(v) = &self.after {
parts.push(format!("after={}", urlencoding::encode(v)));
}
if let Some(v) = self.limit {
parts.push(format!("limit={v}"));
}
if parts.is_empty() {
String::new()
} else {
format!("?{}", parts.join("&"))
}
}
}
#[derive(Debug, Default, Clone)]
pub struct ListCurrentUserGuilds {
pub before: Option<GuildId>,
pub after: Option<GuildId>,
pub limit: Option<u32>,
}
impl ListCurrentUserGuilds {
fn to_query(&self) -> String {
let mut parts: Vec<String> = Vec::new();
if let Some(v) = self.before {
parts.push(format!("before={v}"));
}
if let Some(v) = self.after {
parts.push(format!("after={v}"));
}
if let Some(v) = self.limit {
parts.push(format!("limit={v}"));
}
if parts.is_empty() {
String::new()
} else {
format!("?{}", parts.join("&"))
}
}
}
#[derive(Debug, Default, Serialize)]
pub struct GuildMemberSearch {
#[serde(skip_serializing_if = "Option::is_none")]
pub query: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<u64>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub role_ids: Vec<RoleId>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GuildMemberSearchResponse {
pub guild_id: GuildId,
pub members: Vec<GuildMemberSearchResult>,
pub page_result_count: u64,
pub total_result_count: u64,
pub indexing: bool,
}
#[derive(Debug, Clone, Deserialize)]
pub struct GuildMemberSearchResult {
pub user_id: UserId,
pub username: String,
#[serde(default)]
pub global_name: Option<String>,
#[serde(default)]
pub nickname: Option<String>,
#[serde(default)]
pub role_ids: Vec<RoleId>,
#[serde(default)]
pub joined_at: Option<f64>,
}
#[derive(Debug, Clone, Serialize)]
pub struct ChannelPositionUpdate {
pub id: ChannelId,
#[serde(skip_serializing_if = "Option::is_none")]
pub position: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lock_permissions: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<ChannelId>,
}
#[derive(Debug, Clone, Serialize)]
pub struct RolePositionUpdate {
pub id: RoleId,
pub position: i32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct VanityUrl {
#[serde(default)]
pub code: Option<String>,
#[serde(default)]
pub uses: u32,
}
#[derive(Debug, Serialize)]
pub struct CreateGuild {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub icon: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub empty_features: Option<bool>,
}
impl CreateGuild {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
icon: None,
empty_features: None,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct RoleHoistPosition {
pub id: RoleId,
pub hoist_position: i64,
}