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}