twilight_http/request/channel/thread/
update_thread.rs1use crate::{
2 client::Client,
3 error::Error,
4 request::{self, AuditLogReason, Nullable, Request, TryIntoRequest},
5 response::{Response, ResponseFuture},
6 routing::Route,
7};
8use serde::Serialize;
9use std::future::IntoFuture;
10use twilight_model::{
11 channel::{Channel, ChannelFlags, thread::AutoArchiveDuration},
12 id::{
13 Id,
14 marker::{ChannelMarker, TagMarker},
15 },
16};
17use twilight_validate::{
18 channel::{
19 ChannelValidationError, name as validate_name,
20 rate_limit_per_user as validate_rate_limit_per_user,
21 },
22 request::{ValidationError, audit_reason as validate_audit_reason},
23};
24
25#[derive(Serialize)]
26struct UpdateThreadFields<'a> {
27 #[serde(skip_serializing_if = "Option::is_none")]
28 applied_tags: Option<Nullable<&'a [Id<TagMarker>]>>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 archived: Option<bool>,
31 #[serde(skip_serializing_if = "Option::is_none")]
32 auto_archive_duration: Option<AutoArchiveDuration>,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 flags: Option<Nullable<ChannelFlags>>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 invitable: Option<bool>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 locked: Option<bool>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 name: Option<&'a str>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 rate_limit_per_user: Option<u16>,
43}
44
45#[must_use = "requests must be configured and executed"]
50pub struct UpdateThread<'a> {
51 channel_id: Id<ChannelMarker>,
52 fields: Result<UpdateThreadFields<'a>, ChannelValidationError>,
53 http: &'a Client,
54 reason: Result<Option<&'a str>, ValidationError>,
55}
56
57impl<'a> UpdateThread<'a> {
58 pub(crate) const fn new(http: &'a Client, channel_id: Id<ChannelMarker>) -> Self {
59 Self {
60 channel_id,
61 fields: Ok(UpdateThreadFields {
62 applied_tags: None,
63 archived: None,
64 auto_archive_duration: None,
65 flags: None,
66 invitable: None,
67 locked: None,
68 name: None,
69 rate_limit_per_user: None,
70 }),
71 http,
72 reason: Ok(None),
73 }
74 }
75
76 pub const fn applied_tags(mut self, applied_tags: Option<&'a [Id<TagMarker>]>) -> Self {
78 if let Ok(fields) = self.fields.as_mut() {
79 fields.applied_tags = Some(Nullable(applied_tags));
80 }
81
82 self
83 }
84
85 pub const fn archived(mut self, archived: bool) -> Self {
93 if let Ok(fields) = self.fields.as_mut() {
94 fields.archived = Some(archived);
95 }
96
97 self
98 }
99
100 pub const fn auto_archive_duration(
105 mut self,
106 auto_archive_duration: AutoArchiveDuration,
107 ) -> Self {
108 if let Ok(fields) = self.fields.as_mut() {
109 fields.auto_archive_duration = Some(auto_archive_duration);
110 }
111
112 self
113 }
114
115 pub const fn flags(mut self, flags: Option<ChannelFlags>) -> Self {
117 if let Ok(fields) = self.fields.as_mut() {
118 fields.flags = Some(Nullable(flags));
119 }
120
121 self
122 }
123
124 pub const fn invitable(mut self, invitable: bool) -> Self {
126 if let Ok(fields) = self.fields.as_mut() {
127 fields.invitable = Some(invitable);
128 }
129
130 self
131 }
132
133 pub const fn locked(mut self, locked: bool) -> Self {
140 if let Ok(fields) = self.fields.as_mut() {
141 fields.locked = Some(locked);
142 }
143
144 self
145 }
146
147 pub fn name(mut self, name: &'a str) -> Self {
157 self.fields = self.fields.and_then(|mut fields| {
158 validate_name(name)?;
159 fields.name = Some(name);
160
161 Ok(fields)
162 });
163
164 self
165 }
166
167 pub fn rate_limit_per_user(mut self, rate_limit_per_user: u16) -> Self {
181 self.fields = self.fields.and_then(|mut fields| {
182 validate_rate_limit_per_user(rate_limit_per_user)?;
183 fields.rate_limit_per_user = Some(rate_limit_per_user);
184
185 Ok(fields)
186 });
187
188 self
189 }
190}
191
192impl<'a> AuditLogReason<'a> for UpdateThread<'a> {
193 fn reason(mut self, reason: &'a str) -> Self {
194 self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
195
196 self
197 }
198}
199
200impl IntoFuture for UpdateThread<'_> {
201 type Output = Result<Response<Channel>, Error>;
202
203 type IntoFuture = ResponseFuture<Channel>;
204
205 fn into_future(self) -> Self::IntoFuture {
206 let http = self.http;
207
208 match self.try_into_request() {
209 Ok(request) => http.request(request),
210 Err(source) => ResponseFuture::error(source),
211 }
212 }
213}
214
215impl TryIntoRequest for UpdateThread<'_> {
216 fn try_into_request(self) -> Result<Request, Error> {
217 let fields = self.fields.map_err(Error::validation)?;
218 let mut request = Request::builder(&Route::UpdateChannel {
219 channel_id: self.channel_id.get(),
220 })
221 .json(&fields);
222
223 if let Some(reason) = self.reason.map_err(Error::validation)? {
224 request = request.headers(request::audit_header(reason)?);
225 }
226
227 request.build()
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::{UpdateThread, UpdateThreadFields};
234 use crate::{
235 Client,
236 request::{Request, TryIntoRequest},
237 routing::Route,
238 };
239 use std::error::Error;
240 use twilight_model::id::Id;
241
242 #[test]
243 fn request() -> Result<(), Box<dyn Error>> {
244 let client = Client::new("token".to_string());
245 let channel_id = Id::new(123);
246
247 let actual = UpdateThread::new(&client, channel_id)
248 .rate_limit_per_user(60)
249 .try_into_request()?;
250
251 let expected = Request::builder(&Route::UpdateChannel {
252 channel_id: channel_id.get(),
253 })
254 .json(&UpdateThreadFields {
255 applied_tags: None,
256 archived: None,
257 auto_archive_duration: None,
258 flags: None,
259 invitable: None,
260 locked: None,
261 name: None,
262 rate_limit_per_user: Some(60),
263 })
264 .build()?;
265
266 assert_eq!(expected.body(), actual.body());
267 assert_eq!(expected.path(), actual.path());
268
269 Ok(())
270 }
271}