twilight_http/request/channel/webhook/
update_webhook.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::Webhook,
13 id::{
14 Id,
15 marker::{ChannelMarker, WebhookMarker},
16 },
17};
18use twilight_validate::request::{
19 ValidationError, audit_reason as validate_audit_reason,
20 webhook_username as validate_webhook_username,
21};
22
23#[derive(Serialize)]
24struct UpdateWebhookFields<'a> {
25 #[serde(skip_serializing_if = "Option::is_none")]
26 avatar: Option<Nullable<&'a str>>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 channel_id: Option<Id<ChannelMarker>>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 name: Option<&'a str>,
31}
32
33#[must_use = "requests must be configured and executed"]
35pub struct UpdateWebhook<'a> {
36 fields: Result<UpdateWebhookFields<'a>, ValidationError>,
37 http: &'a Client,
38 webhook_id: Id<WebhookMarker>,
39 reason: Result<Option<&'a str>, ValidationError>,
40}
41
42impl<'a> UpdateWebhook<'a> {
44 pub(crate) const fn new(http: &'a Client, webhook_id: Id<WebhookMarker>) -> Self {
45 Self {
46 fields: Ok(UpdateWebhookFields {
47 avatar: None,
48 channel_id: None,
49 name: None,
50 }),
51 http,
52 webhook_id,
53 reason: Ok(None),
54 }
55 }
56
57 pub const fn avatar(mut self, avatar: Option<&'a str>) -> Self {
65 if let Ok(fields) = self.fields.as_mut() {
66 fields.avatar = Some(Nullable(avatar));
67 }
68
69 self
70 }
71
72 pub const fn channel_id(mut self, channel_id: Id<ChannelMarker>) -> Self {
74 if let Ok(fields) = self.fields.as_mut() {
75 fields.channel_id = Some(channel_id);
76 }
77
78 self
79 }
80
81 pub fn name(mut self, name: &'a str) -> Self {
90 self.fields = self.fields.and_then(|mut fields| {
91 validate_webhook_username(name)?;
92 fields.name = Some(name);
93
94 Ok(fields)
95 });
96
97 self
98 }
99}
100
101impl<'a> AuditLogReason<'a> for UpdateWebhook<'a> {
102 fn reason(mut self, reason: &'a str) -> Self {
103 self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
104
105 self
106 }
107}
108
109#[cfg(not(target_os = "wasi"))]
110impl IntoFuture for UpdateWebhook<'_> {
111 type Output = Result<Response<Webhook>, Error>;
112
113 type IntoFuture = ResponseFuture<Webhook>;
114
115 fn into_future(self) -> Self::IntoFuture {
116 let http = self.http;
117
118 match self.try_into_request() {
119 Ok(request) => http.request(request),
120 Err(source) => ResponseFuture::error(source),
121 }
122 }
123}
124
125impl TryIntoRequest for UpdateWebhook<'_> {
126 fn try_into_request(self) -> Result<Request, Error> {
127 let fields = self.fields.map_err(Error::validation)?;
128 let mut request = Request::builder(&Route::UpdateWebhook {
129 token: None,
130 webhook_id: self.webhook_id.get(),
131 })
132 .json(&fields);
133
134 if let Some(reason) = self.reason.map_err(Error::validation)? {
135 request = request.headers(request::audit_header(reason)?);
136 }
137
138 request.build()
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use std::error::Error;
146
147 #[test]
148 fn test_update_webhook() -> Result<(), Box<dyn Error>> {
149 const WEBHOOK_ID: Id<WebhookMarker> = Id::new(1);
150 const CHANNEL_ID: Id<ChannelMarker> = Id::new(2);
151
152 let client = Client::new("token".into());
153
154 {
155 let expected = r"{}";
156 let actual = UpdateWebhook::new(&client, WEBHOOK_ID).try_into_request()?;
157
158 assert_eq!(Some(expected.as_bytes()), actual.body());
159 }
160
161 {
162 let expected = r#"{"avatar":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI"}"#;
163 let actual = UpdateWebhook::new(&client, WEBHOOK_ID)
164 .avatar(Some("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI"))
165 .try_into_request()?;
166
167 assert_eq!(Some(expected.as_bytes()), actual.body());
168
169 let expected = r#"{"avatar":null}"#;
170 let actual = UpdateWebhook::new(&client, WEBHOOK_ID)
171 .avatar(None)
172 .try_into_request()?;
173
174 assert_eq!(Some(expected.as_bytes()), actual.body());
175 }
176
177 {
178 let expected = r#"{"channel_id":"2"}"#;
179 let actual = UpdateWebhook::new(&client, WEBHOOK_ID)
180 .channel_id(CHANNEL_ID)
181 .try_into_request()?;
182
183 assert_eq!(Some(expected.as_bytes()), actual.body());
184 }
185
186 {
187 let expected = r#"{"name":"Captain Hook"}"#;
188 let actual = UpdateWebhook::new(&client, WEBHOOK_ID)
189 .name("Captain Hook")
190 .try_into_request()?;
191
192 assert_eq!(Some(expected.as_bytes()), actual.body());
193 }
194
195 {
196 let expected = r#"{"avatar":null,"channel_id":"2","name":"Captain Hook"}"#;
197 let actual = UpdateWebhook::new(&client, WEBHOOK_ID)
198 .avatar(None)
199 .channel_id(CHANNEL_ID)
200 .name("Captain Hook")
201 .try_into_request()?;
202
203 assert_eq!(Some(expected.as_bytes()), actual.body());
204 }
205 Ok(())
206 }
207}