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, 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 invitable: Option<bool>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 locked: Option<bool>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 name: Option<&'a str>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 rate_limit_per_user: Option<u16>,
41}
42
43#[must_use = "requests must be configured and executed"]
48pub struct UpdateThread<'a> {
49 channel_id: Id<ChannelMarker>,
50 fields: Result<UpdateThreadFields<'a>, ChannelValidationError>,
51 http: &'a Client,
52 reason: Result<Option<&'a str>, ValidationError>,
53}
54
55impl<'a> UpdateThread<'a> {
56 pub(crate) const fn new(http: &'a Client, channel_id: Id<ChannelMarker>) -> Self {
57 Self {
58 channel_id,
59 fields: Ok(UpdateThreadFields {
60 applied_tags: None,
61 archived: None,
62 auto_archive_duration: None,
63 invitable: None,
64 locked: None,
65 name: None,
66 rate_limit_per_user: None,
67 }),
68 http,
69 reason: Ok(None),
70 }
71 }
72
73 pub const fn applied_tags(mut self, applied_tags: Option<&'a [Id<TagMarker>]>) -> Self {
75 if let Ok(fields) = self.fields.as_mut() {
76 fields.applied_tags = Some(Nullable(applied_tags));
77 }
78
79 self
80 }
81
82 pub const fn archived(mut self, archived: bool) -> Self {
90 if let Ok(fields) = self.fields.as_mut() {
91 fields.archived = Some(archived);
92 }
93
94 self
95 }
96
97 pub const fn auto_archive_duration(
102 mut self,
103 auto_archive_duration: AutoArchiveDuration,
104 ) -> Self {
105 if let Ok(fields) = self.fields.as_mut() {
106 fields.auto_archive_duration = Some(auto_archive_duration);
107 }
108
109 self
110 }
111
112 pub const fn invitable(mut self, invitable: bool) -> Self {
114 if let Ok(fields) = self.fields.as_mut() {
115 fields.invitable = Some(invitable);
116 }
117
118 self
119 }
120
121 pub const fn locked(mut self, locked: bool) -> Self {
128 if let Ok(fields) = self.fields.as_mut() {
129 fields.locked = Some(locked);
130 }
131
132 self
133 }
134
135 pub fn name(mut self, name: &'a str) -> Self {
145 self.fields = self.fields.and_then(|mut fields| {
146 validate_name(name)?;
147 fields.name = Some(name);
148
149 Ok(fields)
150 });
151
152 self
153 }
154
155 pub fn rate_limit_per_user(mut self, rate_limit_per_user: u16) -> Self {
169 self.fields = self.fields.and_then(|mut fields| {
170 validate_rate_limit_per_user(rate_limit_per_user)?;
171 fields.rate_limit_per_user = Some(rate_limit_per_user);
172
173 Ok(fields)
174 });
175
176 self
177 }
178}
179
180impl<'a> AuditLogReason<'a> for UpdateThread<'a> {
181 fn reason(mut self, reason: &'a str) -> Self {
182 self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
183
184 self
185 }
186}
187
188impl IntoFuture for UpdateThread<'_> {
189 type Output = Result<Response<Channel>, Error>;
190
191 type IntoFuture = ResponseFuture<Channel>;
192
193 fn into_future(self) -> Self::IntoFuture {
194 let http = self.http;
195
196 match self.try_into_request() {
197 Ok(request) => http.request(request),
198 Err(source) => ResponseFuture::error(source),
199 }
200 }
201}
202
203impl TryIntoRequest for UpdateThread<'_> {
204 fn try_into_request(self) -> Result<Request, Error> {
205 let fields = self.fields.map_err(Error::validation)?;
206 let mut request = Request::builder(&Route::UpdateChannel {
207 channel_id: self.channel_id.get(),
208 })
209 .json(&fields);
210
211 if let Some(reason) = self.reason.map_err(Error::validation)? {
212 request = request.headers(request::audit_header(reason)?);
213 }
214
215 request.build()
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::{UpdateThread, UpdateThreadFields};
222 use crate::{
223 Client,
224 request::{Request, TryIntoRequest},
225 routing::Route,
226 };
227 use std::error::Error;
228 use twilight_model::id::Id;
229
230 #[test]
231 fn request() -> Result<(), Box<dyn Error>> {
232 let client = Client::new("token".to_string());
233 let channel_id = Id::new(123);
234
235 let actual = UpdateThread::new(&client, channel_id)
236 .rate_limit_per_user(60)
237 .try_into_request()?;
238
239 let expected = Request::builder(&Route::UpdateChannel {
240 channel_id: channel_id.get(),
241 })
242 .json(&UpdateThreadFields {
243 applied_tags: None,
244 archived: None,
245 auto_archive_duration: None,
246 invitable: None,
247 locked: None,
248 name: None,
249 rate_limit_per_user: Some(60),
250 })
251 .build()?;
252
253 assert_eq!(expected.body(), actual.body());
254 assert_eq!(expected.path(), actual.path());
255
256 Ok(())
257 }
258}