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