use crate::{
client::Client,
error::Error as HttpError,
request::{self, validate, AuditLogReason, AuditLogReasonError, Pending, Request},
routing::Route,
};
use serde::Serialize;
use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
};
use twilight_model::{
id::{ApplicationId, ChannelId, UserId},
invite::{Invite, TargetType},
};
#[derive(Debug)]
pub struct CreateInviteError {
kind: CreateInviteErrorType,
}
impl CreateInviteError {
#[must_use = "retrieving the type has no effect if left unused"]
pub const fn kind(&self) -> &CreateInviteErrorType {
&self.kind
}
#[allow(clippy::unused_self)]
#[must_use = "consuming the error and retrieving the source has no effect if left unused"]
pub fn into_source(self) -> Option<Box<dyn Error + Send + Sync>> {
None
}
#[must_use = "consuming the error into its parts has no effect if left unused"]
pub fn into_parts(self) -> (CreateInviteErrorType, Option<Box<dyn Error + Send + Sync>>) {
(self.kind, None)
}
}
impl Display for CreateInviteError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match &self.kind {
CreateInviteErrorType::MaxAgeTooOld { .. } => f.write_str("max age is too long"),
CreateInviteErrorType::MaxUsesTooLarge { .. } => f.write_str("max uses is too many"),
}
}
}
impl Error for CreateInviteError {}
#[derive(Debug)]
#[non_exhaustive]
pub enum CreateInviteErrorType {
MaxAgeTooOld {
provided: u64,
},
MaxUsesTooLarge {
provided: u64,
},
}
#[derive(Default, Serialize)]
struct CreateInviteFields {
#[serde(skip_serializing_if = "Option::is_none")]
max_age: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
max_uses: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
temporary: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
target_application_id: Option<ApplicationId>,
#[serde(skip_serializing_if = "Option::is_none")]
target_user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
target_type: Option<TargetType>,
#[serde(skip_serializing_if = "Option::is_none")]
unique: Option<bool>,
}
pub struct CreateInvite<'a> {
channel_id: ChannelId,
fields: CreateInviteFields,
fut: Option<Pending<'a, Invite>>,
http: &'a Client,
reason: Option<String>,
}
impl<'a> CreateInvite<'a> {
pub(crate) fn new(http: &'a Client, channel_id: ChannelId) -> Self {
Self {
channel_id,
fields: CreateInviteFields::default(),
fut: None,
http,
reason: None,
}
}
pub fn max_age(mut self, max_age: u64) -> Result<Self, CreateInviteError> {
if !validate::invite_max_age(max_age) {
return Err(CreateInviteError {
kind: CreateInviteErrorType::MaxAgeTooOld { provided: max_age },
});
}
self.fields.max_age.replace(max_age);
Ok(self)
}
pub fn max_uses(mut self, max_uses: u64) -> Result<Self, CreateInviteError> {
if !validate::invite_max_uses(max_uses) {
return Err(CreateInviteError {
kind: CreateInviteErrorType::MaxUsesTooLarge { provided: max_uses },
});
}
self.fields.max_uses.replace(max_uses);
Ok(self)
}
pub fn target_application_id(mut self, target_application_id: ApplicationId) -> Self {
self.fields
.target_application_id
.replace(target_application_id);
self
}
pub fn target_user_id(mut self, target_user_id: UserId) -> Self {
self.fields
.target_user_id
.replace(target_user_id.0.to_string());
self
}
pub fn target_type(mut self, target_type: TargetType) -> Self {
self.fields.target_type.replace(target_type);
self
}
pub fn temporary(mut self, temporary: bool) -> Self {
self.fields.temporary.replace(temporary);
self
}
pub fn unique(mut self, unique: bool) -> Self {
self.fields.unique.replace(unique);
self
}
fn start(&mut self) -> Result<(), HttpError> {
let mut request = Request::builder(Route::CreateInvite {
channel_id: self.channel_id.0,
})
.json(&self.fields)?;
if let Some(reason) = &self.reason {
request = request.headers(request::audit_header(reason)?);
}
self.fut
.replace(Box::pin(self.http.request(request.build())));
Ok(())
}
}
impl<'a> AuditLogReason for CreateInvite<'a> {
fn reason(mut self, reason: impl Into<String>) -> Result<Self, AuditLogReasonError> {
self.reason
.replace(AuditLogReasonError::validate(reason.into())?);
Ok(self)
}
}
poll_req!(CreateInvite<'_>, Invite);
#[cfg(test)]
mod tests {
use super::CreateInvite;
use crate::Client;
use std::error::Error;
use twilight_model::id::ChannelId;
#[test]
fn test_max_age() -> Result<(), Box<dyn Error>> {
let client = Client::new("foo");
let mut builder = CreateInvite::new(&client, ChannelId(1)).max_age(0)?;
assert_eq!(Some(0), builder.fields.max_age);
builder = builder.max_age(604_800)?;
assert_eq!(Some(604_800), builder.fields.max_age);
assert!(builder.max_age(604_801).is_err());
Ok(())
}
#[test]
fn test_max_uses() -> Result<(), Box<dyn Error>> {
let client = Client::new("foo");
let mut builder = CreateInvite::new(&client, ChannelId(1)).max_uses(0)?;
assert_eq!(Some(0), builder.fields.max_uses);
builder = builder.max_uses(100)?;
assert_eq!(Some(100), builder.fields.max_uses);
assert!(builder.max_uses(101).is_err());
Ok(())
}
}