Skip to main content

stoat/ext/
channel.rs

1use std::{collections::HashMap, time::SystemTime};
2
3use crate::{
4    HttpClient, Identifiable, Result,
5    builders::{EditChannelBuilder, FetchMessagesBuilder, SendMessageBuilder},
6    context::Events,
7    created_at, utils,
8};
9use async_trait::async_trait;
10use stoat_models::v0::{
11    Channel, CreateWebhookBody, DataDefaultChannelPermissions, DataSetRolePermissions, File,
12    Message, OptionsBulkDelete, VoiceInformation, Webhook,
13};
14use stoat_permissions::{Override, OverrideField};
15
16#[async_trait]
17pub trait ChannelExt {
18    fn user(&self) -> Option<&str>;
19    fn active(&self) -> Option<bool>;
20    fn recipients(&self) -> Option<&Vec<String>>;
21    fn last_message_id(&self) -> Option<&str>;
22    fn owner(&self) -> Option<&str>;
23    fn description(&self) -> Option<&str>;
24    fn permissions(&self) -> Option<i64>;
25    fn nsfw(&self) -> Option<bool>;
26    fn default_permissions(&self) -> Option<&OverrideField>;
27    fn role_permissions(&self) -> Option<&HashMap<String, OverrideField>>;
28    fn voice(&self) -> Option<&VoiceInformation>;
29    fn server(&self) -> Option<&str>;
30    fn name(&self) -> Option<&str>;
31    fn icon(&self) -> Option<&File>;
32
33    fn supports_voice(&self) -> bool;
34    fn mention(&self) -> String;
35
36    async fn with_typing<Fut: Future<Output = R> + Send, R>(
37        &self,
38        events: impl AsRef<Events> + Send,
39        fut: Fut,
40    ) -> R;
41
42    fn send(&self, http: impl AsRef<HttpClient>) -> SendMessageBuilder;
43    async fn fetch_message(
44        &self,
45        http: impl AsRef<HttpClient> + Send,
46        message_id: &str,
47    ) -> Result<Message>;
48    fn fetch_messages(&self, http: impl AsRef<HttpClient>) -> FetchMessagesBuilder;
49    #[cfg(feature = "voice")]
50    async fn join_call(
51        &self,
52        http: impl AsRef<HttpClient> + Send,
53        cache: impl AsRef<crate::GlobalCache> + Send,
54        node: Option<String>,
55    ) -> Result<crate::VoiceConnection>;
56    async fn delete(&self, http: impl AsRef<HttpClient> + Send) -> Result<()>;
57    async fn edit(&self, http: impl AsRef<HttpClient> + Send) -> EditChannelBuilder;
58    async fn delete_messages(
59        &self,
60        http: impl AsRef<HttpClient> + Send,
61        options: &OptionsBulkDelete,
62    ) -> Result<()>;
63    async fn set_default_permissions(
64        &self,
65        http: impl AsRef<HttpClient> + Send,
66        data: &DataDefaultChannelPermissions,
67    ) -> Result<Channel>;
68    async fn set_role_permissions(
69        &self,
70        http: impl AsRef<HttpClient> + Send,
71        role_id: &str,
72        allow: u64,
73        deny: u64,
74    ) -> Result<Channel>;
75    async fn create_webhook(
76        &self,
77        http: impl AsRef<HttpClient> + Send,
78        data: &CreateWebhookBody,
79    ) -> Result<Webhook>;
80}
81
82#[async_trait]
83impl ChannelExt for Channel {
84    fn user(&self) -> Option<&str> {
85        match self {
86            Channel::SavedMessages { user, .. } => Some(user),
87            _ => None,
88        }
89    }
90
91    fn active(&self) -> Option<bool> {
92        match self {
93            Channel::DirectMessage { active, .. } => Some(*active),
94            _ => None,
95        }
96    }
97
98    fn recipients(&self) -> Option<&Vec<String>> {
99        match self {
100            Channel::DirectMessage { recipients, .. } | Channel::Group { recipients, .. } => {
101                Some(recipients)
102            }
103            _ => None,
104        }
105    }
106
107    fn last_message_id(&self) -> Option<&str> {
108        match self {
109            Channel::DirectMessage {
110                last_message_id, ..
111            }
112            | Channel::TextChannel {
113                last_message_id, ..
114            }
115            | Channel::Group {
116                last_message_id, ..
117            } => last_message_id.as_deref(),
118            _ => None,
119        }
120    }
121
122    fn owner(&self) -> Option<&str> {
123        match self {
124            Channel::Group { owner, .. } => Some(owner),
125            _ => None,
126        }
127    }
128
129    fn description(&self) -> Option<&str> {
130        match self {
131            Channel::TextChannel { description, .. } | Channel::Group { description, .. } => {
132                description.as_deref()
133            }
134            _ => None,
135        }
136    }
137
138    fn permissions(&self) -> Option<i64> {
139        match self {
140            Channel::Group { permissions, .. } => *permissions,
141            _ => None,
142        }
143    }
144
145    fn nsfw(&self) -> Option<bool> {
146        match self {
147            Channel::TextChannel { nsfw, .. } | Channel::Group { nsfw, .. } => Some(*nsfw),
148            _ => None,
149        }
150    }
151
152    fn default_permissions(&self) -> Option<&OverrideField> {
153        match self {
154            Channel::TextChannel {
155                default_permissions,
156                ..
157            } => default_permissions.as_ref(),
158            _ => None,
159        }
160    }
161
162    fn role_permissions(&self) -> Option<&HashMap<String, OverrideField>> {
163        match self {
164            Channel::TextChannel {
165                role_permissions, ..
166            } => Some(role_permissions),
167            _ => None,
168        }
169    }
170
171    fn voice(&self) -> Option<&VoiceInformation> {
172        match self {
173            Channel::TextChannel { voice, .. } => voice.as_ref(),
174            _ => None,
175        }
176    }
177
178    fn supports_voice(&self) -> bool {
179        match self {
180            Channel::DirectMessage { .. }
181            | Channel::Group { .. }
182            | Channel::SavedMessages { .. } => true,
183            Channel::TextChannel { voice, .. } => voice.is_some(),
184        }
185    }
186
187    fn server(&self) -> Option<&str> {
188        match self {
189            Channel::TextChannel { server, .. } => Some(server),
190            _ => None,
191        }
192    }
193
194    fn name(&self) -> Option<&str> {
195        match self {
196            Channel::SavedMessages { .. } => Some("Saved Messages"),
197            Channel::DirectMessage { .. } => None,
198            Channel::Group { name, .. } | Channel::TextChannel { name, .. } => Some(name),
199        }
200    }
201
202    fn icon(&self) -> Option<&File> {
203        match self {
204            Channel::Group { icon, .. } | Channel::TextChannel { icon, .. } => icon.as_ref(),
205            _ => None,
206        }
207    }
208
209    fn mention(&self) -> String {
210        format!("<#{}>", self.id())
211    }
212
213    async fn with_typing<Fut: Future<Output = R> + Send, R>(
214        &self,
215        events: impl AsRef<Events> + Send,
216        fut: Fut,
217    ) -> R {
218        utils::with_typing(events.as_ref(), self.id().to_string(), fut).await
219    }
220
221    fn send(&self, http: impl AsRef<HttpClient>) -> SendMessageBuilder {
222        SendMessageBuilder::new(http.as_ref().clone(), self.id().to_string())
223    }
224
225    async fn fetch_message(
226        &self,
227        http: impl AsRef<HttpClient> + Send,
228        message_id: &str,
229    ) -> Result<Message> {
230        http.as_ref().fetch_message(self.id(), message_id).await
231    }
232
233    fn fetch_messages(&self, http: impl AsRef<HttpClient>) -> FetchMessagesBuilder {
234        FetchMessagesBuilder::new(http.as_ref().clone(), self.id().to_string())
235    }
236
237    #[cfg(feature = "voice")]
238    async fn join_call(
239        &self,
240        http: impl AsRef<HttpClient> + Send,
241        cache: impl AsRef<crate::GlobalCache> + Send,
242        node: Option<String>,
243    ) -> Result<crate::VoiceConnection> {
244        let response = http
245            .as_ref()
246            .join_call(
247                self.id(),
248                &stoat_models::v0::DataJoinCall {
249                    node,
250                    force_disconnect: None,
251                    recipients: None,
252                },
253            )
254            .await?;
255
256        crate::VoiceConnection::connect(cache.as_ref(), &response.url, &response.token).await
257    }
258
259    async fn delete(&self, http: impl AsRef<HttpClient> + Send) -> Result<()> {
260        http.as_ref().delete_channel(self.id()).await
261    }
262
263    async fn edit(&self, http: impl AsRef<HttpClient> + Send) -> EditChannelBuilder {
264        EditChannelBuilder::new(http.as_ref().clone(), self.id().to_string())
265    }
266
267    async fn delete_messages(
268        &self,
269        http: impl AsRef<HttpClient> + Send,
270        options: &OptionsBulkDelete,
271    ) -> Result<()> {
272        http.as_ref().delete_messages(self.id(), options).await
273    }
274
275    async fn set_default_permissions(
276        &self,
277        http: impl AsRef<HttpClient> + Send,
278        data: &DataDefaultChannelPermissions,
279    ) -> Result<Channel> {
280        http.as_ref()
281            .set_default_channel_permissions(self.id(), data)
282            .await
283    }
284
285    async fn set_role_permissions(
286        &self,
287        http: impl AsRef<HttpClient> + Send,
288        role_id: &str,
289        allow: u64,
290        deny: u64,
291    ) -> Result<Channel> {
292        http.as_ref()
293            .set_role_channel_permissions(
294                self.id(),
295                role_id,
296                &DataSetRolePermissions {
297                    permissions: Override { allow, deny },
298                },
299            )
300            .await
301    }
302
303    async fn create_webhook(
304        &self,
305        http: impl AsRef<HttpClient> + Send,
306        data: &CreateWebhookBody,
307    ) -> Result<Webhook> {
308        http.as_ref().create_webhook(self.id(), data).await
309    }
310}
311
312impl Identifiable for Channel {
313    fn created_at(&self) -> SystemTime {
314        created_at(&self.id())
315    }
316}