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