revolt_database/models/channel_webhooks/
model.rs1use revolt_result::Result;
2
3use crate::events::client::EventV1;
4use crate::{Database, File};
5
6auto_derived_partial!(
7 pub struct Webhook {
9 #[serde(rename = "_id")]
11 pub id: String,
12
13 pub name: String,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub avatar: Option<File>,
19
20 pub creator_id: String,
22
23 pub channel_id: String,
25
26 pub permissions: u64,
28
29 pub token: Option<String>,
31 },
32 "PartialWebhook"
33);
34
35auto_derived!(
36 pub enum FieldsWebhook {
38 Avatar,
39 }
40);
41
42#[allow(clippy::derivable_impls)]
43impl Default for Webhook {
44 fn default() -> Self {
45 Self {
46 id: Default::default(),
47 name: Default::default(),
48 avatar: None,
49 creator_id: Default::default(),
50 channel_id: Default::default(),
51 permissions: Default::default(),
52 token: Default::default(),
53 }
54 }
55}
56
57#[allow(clippy::disallowed_methods)]
58impl Webhook {
59 pub async fn create(&self, db: &Database) -> Result<()> {
60 db.insert_webhook(self).await?;
61
62 let mut webhook = self.clone();
64 webhook.token = None;
65
66 EventV1::WebhookCreate(webhook.into())
67 .p(self.channel_id.clone())
68 .await;
69
70 Ok(())
71 }
72
73 pub fn assert_token(&self, token: &str) -> Result<()> {
74 if self.token.as_deref() == Some(token) {
75 Ok(())
76 } else {
77 Err(create_error!(NotAuthenticated))
78 }
79 }
80
81 pub async fn update(
82 &mut self,
83 db: &Database,
84 mut partial: PartialWebhook,
85 remove: Vec<FieldsWebhook>,
86 ) -> Result<()> {
87 for field in &remove {
88 self.remove_field(field)
89 }
90
91 self.apply_options(partial.clone());
92
93 db.update_webhook(&self.id, &partial, &remove).await?;
94
95 partial.token = None; EventV1::WebhookUpdate {
98 id: self.id.clone(),
99 data: partial.into(),
100 remove: remove.into_iter().map(|v| v.into()).collect(),
101 }
102 .p(self.channel_id.clone())
103 .await;
104
105 Ok(())
106 }
107
108 pub fn remove_field(&mut self, field: &FieldsWebhook) {
109 match field {
110 FieldsWebhook::Avatar => self.avatar = None,
111 }
112 }
113
114 pub async fn delete(&self, db: &Database) -> Result<()> {
115 db.delete_webhook(&self.id).await?;
116
117 EventV1::WebhookDelete {
118 id: self.id.clone(),
119 }
120 .p(self.channel_id.clone())
121 .await;
122
123 Ok(())
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use crate::{FieldsWebhook, PartialWebhook, Webhook};
130
131 #[async_std::test]
132 async fn crud() {
133 database_test!(|db| async move {
134 let webhook_id = "webhook";
135 let channel_id = "channel";
136
137 let webhook = Webhook {
138 id: webhook_id.to_string(),
139 name: "Webhook Name".to_string(),
140 channel_id: channel_id.to_string(),
141 avatar: None,
142 ..Default::default()
143 };
144
145 webhook.create(&db).await.unwrap();
146
147 let mut updated_webhook = webhook.clone();
148 updated_webhook
149 .update(
150 &db,
151 PartialWebhook {
152 name: Some("New Name".to_string()),
153 ..Default::default()
154 },
155 vec![FieldsWebhook::Avatar],
156 )
157 .await
158 .unwrap();
159
160 let fetched_webhook = db.fetch_webhook(webhook_id).await.unwrap();
161 let fetched_webhooks = db.fetch_webhooks_for_channel(channel_id).await.unwrap();
162
163 assert_eq!(updated_webhook, fetched_webhook);
164 assert_ne!(webhook, fetched_webhook);
165 assert_eq!(1, fetched_webhooks.len());
166 assert_eq!(fetched_webhook, fetched_webhooks[0]);
167
168 webhook.delete(&db).await.unwrap();
169 assert!(db.fetch_webhook(webhook_id).await.is_err());
170 assert_eq!(
171 0,
172 db.fetch_webhooks_for_channel(channel_id)
173 .await
174 .unwrap()
175 .len()
176 )
177 });
178 }
179}