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