twilight_http/request/channel/webhook/
update_webhook_with_token.rs1use crate::{
2 client::Client,
3 error::Error,
4 request::{Nullable, Request, TryIntoRequest},
5 response::{Response, ResponseFuture},
6 routing::Route,
7};
8use serde::Serialize;
9use std::future::IntoFuture;
10use twilight_model::{
11 channel::Webhook,
12 id::{marker::WebhookMarker, Id},
13};
14use twilight_validate::request::{webhook_username as validate_webhook_username, ValidationError};
15
16#[derive(Serialize)]
17struct UpdateWebhookWithTokenFields<'a> {
18 #[serde(skip_serializing_if = "Option::is_none")]
19 avatar: Option<Nullable<&'a str>>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 name: Option<&'a str>,
22}
23
24#[must_use = "requests must be configured and executed"]
26pub struct UpdateWebhookWithToken<'a> {
27 fields: Result<UpdateWebhookWithTokenFields<'a>, ValidationError>,
28 http: &'a Client,
29 token: &'a str,
30 webhook_id: Id<WebhookMarker>,
31}
32
33impl<'a> UpdateWebhookWithToken<'a> {
34 pub(crate) const fn new(
35 http: &'a Client,
36 webhook_id: Id<WebhookMarker>,
37 token: &'a str,
38 ) -> Self {
39 Self {
40 fields: Ok(UpdateWebhookWithTokenFields {
41 avatar: None,
42 name: None,
43 }),
44 http,
45 token,
46 webhook_id,
47 }
48 }
49
50 pub fn avatar(mut self, avatar: Option<&'a str>) -> Self {
58 if let Ok(fields) = self.fields.as_mut() {
59 fields.avatar = Some(Nullable(avatar));
60 }
61
62 self
63 }
64
65 pub fn name(mut self, name: &'a str) -> Self {
74 self.fields = self.fields.and_then(|mut fields| {
75 validate_webhook_username(name)?;
76 fields.name = Some(name);
77
78 Ok(fields)
79 });
80
81 self
82 }
83}
84
85impl IntoFuture for UpdateWebhookWithToken<'_> {
86 type Output = Result<Response<Webhook>, Error>;
87
88 type IntoFuture = ResponseFuture<Webhook>;
89
90 fn into_future(self) -> Self::IntoFuture {
91 let http = self.http;
92
93 match self.try_into_request() {
94 Ok(request) => http.request(request),
95 Err(source) => ResponseFuture::error(source),
96 }
97 }
98}
99
100impl TryIntoRequest for UpdateWebhookWithToken<'_> {
101 fn try_into_request(self) -> Result<Request, Error> {
102 let fields = self.fields.map_err(Error::validation)?;
103
104 Request::builder(&Route::UpdateWebhook {
105 token: Some(self.token),
106 webhook_id: self.webhook_id.get(),
107 })
108 .use_authorization_token(false)
109 .json(&fields)
110 .build()
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use std::error::Error;
118
119 #[test]
120 fn test_update_webhook_with_token() -> Result<(), Box<dyn Error>> {
121 const WEBHOOK_ID: Id<WebhookMarker> = Id::new(1);
122
123 let client = Client::new("token".into());
124
125 {
126 let expected = r"{}";
127 let actual =
128 UpdateWebhookWithToken::new(&client, WEBHOOK_ID, "token").try_into_request()?;
129
130 assert_eq!(Some(expected.as_bytes()), actual.body());
131 }
132
133 {
134 let expected = r#"{"avatar":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI"}"#;
135 let actual = UpdateWebhookWithToken::new(&client, WEBHOOK_ID, "token")
136 .avatar(Some("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI"))
137 .try_into_request()?;
138
139 assert_eq!(Some(expected.as_bytes()), actual.body());
140
141 let expected = r#"{"avatar":null}"#;
142 let actual = UpdateWebhookWithToken::new(&client, WEBHOOK_ID, "token")
143 .avatar(None)
144 .try_into_request()?;
145
146 assert_eq!(Some(expected.as_bytes()), actual.body());
147 }
148
149 {
150 let expected = r#"{"name":"Captain Hook"}"#;
151 let actual = UpdateWebhookWithToken::new(&client, WEBHOOK_ID, "token")
152 .name("Captain Hook")
153 .try_into_request()?;
154
155 assert_eq!(Some(expected.as_bytes()), actual.body());
156 }
157
158 {
159 let expected = r#"{"avatar":null,"name":"Captain Hook"}"#;
160 let actual = UpdateWebhookWithToken::new(&client, WEBHOOK_ID, "token")
161 .avatar(None)
162 .name("Captain Hook")
163 .try_into_request()?;
164
165 assert_eq!(Some(expected.as_bytes()), actual.body());
166 }
167 Ok(())
168 }
169}