twilight_http/request/guild/ban/
create_ban.rs1use crate::{
2 client::Client,
3 error::Error,
4 request::{self, AuditLogReason, Request, TryIntoRequest},
5 response::{marker::EmptyBody, Response, ResponseFuture},
6 routing::Route,
7};
8use serde::Serialize;
9use std::future::IntoFuture;
10use twilight_model::id::{
11 marker::{GuildMarker, UserMarker},
12 Id,
13};
14use twilight_validate::request::{
15 audit_reason as validate_audit_reason,
16 create_guild_ban_delete_message_seconds as validate_create_guild_ban_delete_message_seconds,
17 ValidationError,
18};
19
20#[derive(Serialize)]
21struct CreateBanFields {
22 delete_message_seconds: Option<u32>,
24}
25
26#[must_use = "requests must be configured and executed"]
52pub struct CreateBan<'a> {
53 fields: Result<CreateBanFields, ValidationError>,
54 guild_id: Id<GuildMarker>,
55 http: &'a Client,
56 reason: Result<Option<&'a str>, ValidationError>,
57 user_id: Id<UserMarker>,
58}
59
60impl<'a> CreateBan<'a> {
61 pub(crate) const fn new(
62 http: &'a Client,
63 guild_id: Id<GuildMarker>,
64 user_id: Id<UserMarker>,
65 ) -> Self {
66 Self {
67 fields: Ok(CreateBanFields {
68 delete_message_seconds: None,
69 }),
70 guild_id,
71 http,
72 reason: Ok(None),
73 user_id,
74 }
75 }
76
77 pub fn delete_message_seconds(mut self, seconds: u32) -> Self {
88 self.fields = self.fields.and_then(|mut fields| {
89 validate_create_guild_ban_delete_message_seconds(seconds)?;
90 fields.delete_message_seconds = Some(seconds);
91
92 Ok(fields)
93 });
94
95 self
96 }
97}
98
99impl<'a> AuditLogReason<'a> for CreateBan<'a> {
100 fn reason(mut self, reason: &'a str) -> Self {
101 self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
102
103 self
104 }
105}
106
107impl IntoFuture for CreateBan<'_> {
108 type Output = Result<Response<EmptyBody>, Error>;
109
110 type IntoFuture = ResponseFuture<EmptyBody>;
111
112 fn into_future(self) -> Self::IntoFuture {
113 let http = self.http;
114
115 match self.try_into_request() {
116 Ok(request) => http.request(request),
117 Err(source) => ResponseFuture::error(source),
118 }
119 }
120}
121
122impl TryIntoRequest for CreateBan<'_> {
123 fn try_into_request(self) -> Result<Request, Error> {
124 let fields = self.fields.map_err(Error::validation)?;
125 let mut request = Request::builder(&Route::CreateBan {
126 guild_id: self.guild_id.get(),
127 user_id: self.user_id.get(),
128 })
129 .json(&fields);
130
131 if let Some(reason) = self.reason.map_err(Error::validation)? {
132 request = request.headers(request::audit_header(reason)?);
133 }
134
135 request.build()
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::{
142 client::Client,
143 request::{AuditLogReason, TryIntoRequest, REASON_HEADER_NAME},
144 };
145 use http::header::HeaderValue;
146 use std::error::Error;
147 use twilight_http_ratelimiting::Method;
148 use twilight_model::id::{
149 marker::{GuildMarker, UserMarker},
150 Id,
151 };
152
153 #[test]
154 fn request() -> Result<(), Box<dyn Error>> {
155 const GUILD_ID: Id<GuildMarker> = Id::new(1);
156 const REASON: &str = "spam";
157 const USER_ID: Id<UserMarker> = Id::new(2);
158
159 let client = Client::new(String::new());
160 let request = client
161 .create_ban(GUILD_ID, USER_ID)
162 .delete_message_seconds(100)
163 .reason(REASON)
164 .try_into_request()?;
165
166 assert!(request.body().is_some());
167 assert!(request.form().is_none());
168 assert_eq!(Method::Put, request.method());
169
170 let header = HeaderValue::from_static(REASON);
171 assert!(matches!(
172 request.headers(),
173 Some(map)
174 if map.len() == 1 && map.get(REASON_HEADER_NAME) == Some(&header)));
175 assert!(request.use_authorization_token());
176
177 Ok(())
178 }
179}