1#![allow(deprecated)]
2use std::{borrow::Cow, collections::HashMap};
3
4use redis_kiss::get_connection;
5use revolt_config::config;
6use revolt_models::v0::{self, MessageAuthor};
7use revolt_permissions::OverrideField;
8use revolt_result::Result;
9use serde::{Deserialize, Serialize};
10use ulid::Ulid;
11
12use crate::{
13 events::client::EventV1, Database, File, PartialServer, Server, SystemMessage, User, AMQP,
14};
15
16#[cfg(feature = "mongodb")]
17use crate::IntoDocumentPath;
18
19auto_derived!(
20 #[serde(tag = "channel_type")]
21 pub enum Channel {
22 SavedMessages {
24 #[serde(rename = "_id")]
26 id: String,
27 user: String,
29 },
30 DirectMessage {
32 #[serde(rename = "_id")]
34 id: String,
35
36 active: bool,
38 recipients: Vec<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
42 last_message_id: Option<String>,
43 },
44 Group {
46 #[serde(rename = "_id")]
48 id: String,
49
50 name: String,
52 owner: String,
54 #[serde(skip_serializing_if = "Option::is_none")]
56 description: Option<String>,
57 recipients: Vec<String>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 icon: Option<File>,
63 #[serde(skip_serializing_if = "Option::is_none")]
65 last_message_id: Option<String>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
70 permissions: Option<i64>,
71
72 #[serde(skip_serializing_if = "crate::if_false", default)]
74 nsfw: bool,
75 },
76 TextChannel {
78 #[serde(rename = "_id")]
80 id: String,
81 server: String,
83
84 name: String,
86 #[serde(skip_serializing_if = "Option::is_none")]
88 description: Option<String>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 icon: Option<File>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 last_message_id: Option<String>,
96
97 #[serde(skip_serializing_if = "Option::is_none")]
99 default_permissions: Option<OverrideField>,
100 #[serde(
102 default = "HashMap::<String, OverrideField>::new",
103 skip_serializing_if = "HashMap::<String, OverrideField>::is_empty"
104 )]
105 role_permissions: HashMap<String, OverrideField>,
106
107 #[serde(skip_serializing_if = "crate::if_false", default)]
109 nsfw: bool,
110
111 #[serde(skip_serializing_if = "Option::is_none")]
113 voice: Option<VoiceInformation>,
114
115 #[serde(skip_serializing_if = "Option::is_none")]
117 slowmode: Option<u64>,
118 },
119 }
120
121 #[derive(Default)]
122 pub struct VoiceInformation {
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub max_users: Option<usize>,
126 }
127);
128
129auto_derived!(
130 #[derive(Default)]
131 pub struct PartialChannel {
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub name: Option<String>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub owner: Option<String>,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub description: Option<String>,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub icon: Option<File>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub nsfw: Option<bool>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub active: Option<bool>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub permissions: Option<i64>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub role_permissions: Option<HashMap<String, OverrideField>>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub default_permissions: Option<OverrideField>,
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub last_message_id: Option<String>,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub voice: Option<VoiceInformation>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub slowmode: Option<u64>,
156 }
157
158 pub enum FieldsChannel {
160 Description,
161 Icon,
162 DefaultPermissions,
163 Voice,
164 }
165);
166
167#[allow(clippy::disallowed_methods)]
168impl Channel {
169 pub async fn create_server_channel(
191 db: &Database,
192 server: &mut Server,
193 data: v0::DataCreateServerChannel,
194 update_server: bool,
195 ) -> Result<Channel> {
196 let config = config().await;
197 if server.channels.len() > config.features.limits.global.server_channels {
198 return Err(create_error!(TooManyChannels {
199 max: config.features.limits.global.server_channels,
200 }));
201 };
202
203 let id = ulid::Ulid::new().to_string();
204 let channel = match data.channel_type {
205 v0::LegacyServerChannelType::Text => Channel::TextChannel {
206 id: id.clone(),
207 server: server.id.to_owned(),
208 name: data.name,
209 description: data.description,
210 icon: None,
211 last_message_id: None,
212 default_permissions: None,
213 role_permissions: HashMap::new(),
214 nsfw: data.nsfw.unwrap_or(false),
215 voice: data.voice.map(|voice| voice.into()),
216 slowmode: None,
217 },
218 v0::LegacyServerChannelType::Voice => Channel::TextChannel {
219 id: id.clone(),
220 server: server.id.to_owned(),
221 name: data.name,
222 description: data.description,
223 icon: None,
224 last_message_id: None,
225 default_permissions: None,
226 role_permissions: HashMap::new(),
227 nsfw: data.nsfw.unwrap_or(false),
228 voice: Some(data.voice.unwrap_or_default().into()),
229 slowmode: None,
230 },
231 };
232
233 db.insert_channel(&channel).await?;
234
235 if update_server {
236 server
237 .update(
238 db,
239 PartialServer {
240 channels: Some([server.channels.clone(), [id].into()].concat()),
241 ..Default::default()
242 },
243 vec![],
244 )
245 .await?;
246
247 EventV1::ChannelCreate(channel.clone().into())
248 .p(server.id.clone())
249 .await;
250 }
251
252 Ok(channel)
253 }
254
255 pub async fn create_group(
257 db: &Database,
258 mut data: v0::DataCreateGroup,
259 owner_id: String,
260 ) -> Result<Channel> {
261 data.users.insert(owner_id.to_string());
262
263 let config = config().await;
264 if data.users.len() > config.features.limits.global.group_size {
265 return Err(create_error!(GroupTooLarge {
266 max: config.features.limits.global.group_size,
267 }));
268 }
269
270 let id = ulid::Ulid::new().to_string();
271
272 let icon = if let Some(icon_id) = data.icon {
273 Some(File::use_channel_icon(db, &icon_id, &id, &owner_id).await?)
274 } else {
275 None
276 };
277
278 let recipients = data.users.into_iter().collect::<Vec<String>>();
279 let channel = Channel::Group {
280 id,
281
282 name: data.name,
283 owner: owner_id,
284 description: data.description,
285 recipients: recipients.clone(),
286
287 icon,
288 last_message_id: None,
289
290 permissions: None,
291
292 nsfw: data.nsfw.unwrap_or(false),
293 };
294
295 db.insert_channel(&channel).await?;
296
297 let event = EventV1::ChannelCreate(channel.clone().into());
298 for recipient in recipients {
299 event.clone().private(recipient).await;
300 }
301
302 Ok(channel)
303 }
304
305 pub async fn create_dm(db: &Database, user_a: &User, user_b: &User) -> Result<Channel> {
307 if let Ok(channel) = db.find_direct_message_channel(&user_a.id, &user_b.id).await {
309 Ok(channel)
310 } else {
311 let channel = if user_a.id == user_b.id {
312 Channel::SavedMessages {
314 id: Ulid::new().to_string(),
315 user: user_a.id.to_string(),
316 }
317 } else {
318 Channel::DirectMessage {
320 id: Ulid::new().to_string(),
321 active: true, recipients: vec![user_a.id.clone(), user_b.id.clone()],
323 last_message_id: None,
324 }
325 };
326
327 db.insert_channel(&channel).await?;
328
329 if let Channel::DirectMessage { .. } = &channel {
330 let event = EventV1::ChannelCreate(channel.clone().into());
331 event.clone().private(user_a.id.clone()).await;
332 event.private(user_b.id.clone()).await;
333 };
334
335 Ok(channel)
336 }
337 }
338
339 pub async fn add_user_to_group(
341 &mut self,
342 db: &Database,
343 amqp: &AMQP,
344 user: &User,
345 by_id: &str,
346 ) -> Result<()> {
347 if let Channel::Group { recipients, .. } = self {
348 if recipients.contains(&String::from(&user.id)) {
349 return Err(create_error!(AlreadyInGroup));
350 }
351
352 let config = config().await;
353 if recipients.len() >= config.features.limits.global.group_size {
354 return Err(create_error!(GroupTooLarge {
355 max: config.features.limits.global.group_size
356 }));
357 }
358
359 recipients.push(String::from(&user.id));
360 }
361
362 match &self {
363 Channel::Group { id, .. } => {
364 db.add_user_to_group(id, &user.id).await?;
365
366 EventV1::ChannelGroupJoin {
367 id: id.to_string(),
368 user: user.id.to_string(),
369 }
370 .p(id.to_string())
371 .await;
372
373 SystemMessage::UserAdded {
374 id: user.id.to_string(),
375 by: by_id.to_string(),
376 }
377 .into_message(id.to_string())
378 .send(
379 db,
380 Some(amqp),
381 MessageAuthor::System {
382 username: &user.username,
383 avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
384 },
385 None,
386 None,
387 self,
388 false,
389 )
390 .await
391 .ok();
392
393 EventV1::ChannelCreate(self.clone().into())
394 .private(user.id.to_string())
395 .await;
396
397 Ok(())
398 }
399 _ => Err(create_error!(InvalidOperation)),
400 }
401 }
402
403 pub fn is_direct_dm(&self) -> bool {
405 matches!(self, Channel::DirectMessage { .. })
406 }
407
408 pub fn contains_user(&self, user_id: &str) -> bool {
410 match self {
411 Channel::Group { recipients, .. } => recipients.contains(&String::from(user_id)),
412 _ => false,
413 }
414 }
415
416 pub fn users(&self) -> Result<Vec<String>> {
418 match self {
419 Channel::Group { recipients, .. } => Ok(recipients.to_owned()),
420 _ => Err(create_error!(NotFound)),
421 }
422 }
423
424 pub fn id(&self) -> &str {
426 match self {
427 Channel::DirectMessage { id, .. }
428 | Channel::Group { id, .. }
429 | Channel::SavedMessages { id, .. }
430 | Channel::TextChannel { id, .. } => id,
431 }
432 }
433
434 pub fn server(&self) -> Option<&str> {
436 match self {
437 Channel::TextChannel { server, .. } => Some(server),
438 _ => None,
439 }
440 }
441
442 pub fn voice(&self) -> Option<Cow<VoiceInformation>> {
444 match self {
445 Self::DirectMessage { .. } | Self::Group { .. } => {
446 Some(Cow::Owned(VoiceInformation::default()))
447 }
448 Self::TextChannel {
449 voice: Some(voice), ..
450 } => Some(Cow::Borrowed(voice)),
451 _ => None,
452 }
453 }
454
455 pub async fn set_role_permission(
457 &mut self,
458 db: &Database,
459 role_id: &str,
460 permissions: OverrideField,
461 ) -> Result<()> {
462 match self {
463 Channel::TextChannel {
464 id,
465 server,
466 role_permissions,
467 ..
468 } => {
469 db.set_channel_role_permission(id, role_id, permissions)
470 .await?;
471
472 role_permissions.insert(role_id.to_string(), permissions);
473
474 EventV1::ChannelUpdate {
475 id: id.clone(),
476 data: PartialChannel {
477 role_permissions: Some(role_permissions.clone()),
478 ..Default::default()
479 }
480 .into(),
481 clear: vec![],
482 }
483 .p(server.clone())
484 .await;
485
486 Ok(())
487 }
488 _ => Err(create_error!(InvalidOperation)),
489 }
490 }
491
492 pub async fn update(
494 &mut self,
495 db: &Database,
496 partial: PartialChannel,
497 remove: Vec<FieldsChannel>,
498 ) -> Result<()> {
499 for field in &remove {
500 self.remove_field(field);
501 }
502
503 self.apply_options(partial.clone());
504
505 let id = self.id().to_string();
506 db.update_channel(&id, &partial, remove.clone()).await?;
507
508 EventV1::ChannelUpdate {
509 id: id.clone(),
510 data: partial.into(),
511 clear: remove.into_iter().map(|v| v.into()).collect(),
512 }
513 .p(match self {
514 Self::TextChannel { server, .. } => server.clone(),
515 _ => id,
516 })
517 .await;
518
519 Ok(())
520 }
521
522 pub fn remove_field(&mut self, field: &FieldsChannel) {
524 match field {
525 FieldsChannel::Description => match self {
526 Self::Group { description, .. } | Self::TextChannel { description, .. } => {
527 description.take();
528 }
529 _ => {}
530 },
531 FieldsChannel::Icon => match self {
532 Self::Group { icon, .. } | Self::TextChannel { icon, .. } => {
533 icon.take();
534 }
535 _ => {}
536 },
537 FieldsChannel::DefaultPermissions => match self {
538 Self::TextChannel {
539 default_permissions,
540 ..
541 } => {
542 default_permissions.take();
543 }
544 _ => {}
545 },
546 FieldsChannel::Voice => match self {
547 Self::TextChannel { voice, .. } => {
548 voice.take();
549 }
550 _ => {}
551 },
552 }
553 }
554
555 pub fn remove_fields(&mut self, partial: Vec<FieldsChannel>) {
557 for field in partial {
558 self.remove_field(&field)
559 }
560 }
561
562 #[allow(deprecated)]
564 pub fn apply_options(&mut self, partial: PartialChannel) {
565 match self {
566 Self::SavedMessages { .. } => {}
567 Self::DirectMessage { active, .. } => {
568 if let Some(v) = partial.active {
569 *active = v;
570 }
571 }
572 Self::Group {
573 name,
574 owner,
575 description,
576 icon,
577 nsfw,
578 permissions,
579 ..
580 } => {
581 if let Some(v) = partial.name {
582 *name = v;
583 }
584
585 if let Some(v) = partial.owner {
586 *owner = v;
587 }
588
589 if let Some(v) = partial.description {
590 description.replace(v);
591 }
592
593 if let Some(v) = partial.icon {
594 icon.replace(v);
595 }
596
597 if let Some(v) = partial.nsfw {
598 *nsfw = v;
599 }
600
601 if let Some(v) = partial.permissions {
602 permissions.replace(v);
603 }
604 }
605 Self::TextChannel {
606 name,
607 description,
608 icon,
609 nsfw,
610 default_permissions,
611 role_permissions,
612 voice,
613 ..
614 } => {
615 if let Some(v) = partial.name {
616 *name = v;
617 }
618
619 if let Some(v) = partial.description {
620 description.replace(v);
621 }
622
623 if let Some(v) = partial.icon {
624 icon.replace(v);
625 }
626
627 if let Some(v) = partial.nsfw {
628 *nsfw = v;
629 }
630
631 if let Some(v) = partial.role_permissions {
632 *role_permissions = v;
633 }
634
635 if let Some(v) = partial.default_permissions {
636 default_permissions.replace(v);
637 }
638
639 if let Some(v) = partial.voice {
640 voice.replace(v);
641 }
642 }
643 }
644 }
645
646 pub async fn ack(&self, user: &str, message: &str, amqp: &AMQP) -> Result<()> {
648 EventV1::ChannelAck {
649 id: self.id().to_string(),
650 user: user.to_string(),
651 message_id: message.to_string(),
652 }
653 .private(user.to_string())
654 .await;
655
656 crate::util::acker::ack_channel(user, self.id(), message, amqp).await
657 }
658
659 pub async fn remove_user_from_group(
661 &self,
662 db: &Database,
663 amqp: &AMQP,
664 user: &User,
665 by_id: Option<&str>,
666 silent: bool,
667 ) -> Result<()> {
668 match &self {
669 Channel::Group {
670 id,
671 name,
672 owner,
673 recipients,
674 ..
675 } => {
676 if &user.id == owner {
677 if let Some(new_owner) = recipients.iter().find(|x| *x != &user.id) {
678 db.update_channel(
679 id,
680 &PartialChannel {
681 owner: Some(new_owner.into()),
682 ..Default::default()
683 },
684 vec![],
685 )
686 .await?;
687
688 SystemMessage::ChannelOwnershipChanged {
689 from: owner.to_string(),
690 to: new_owner.to_string(),
691 }
692 .into_message(id.to_string())
693 .send(
694 db,
695 Some(amqp),
696 MessageAuthor::System {
697 username: name,
698 avatar: None,
699 },
700 None,
701 None,
702 self,
703 false,
704 )
705 .await
706 .ok();
707 } else {
708 return self.delete(db).await;
709 }
710 }
711
712 db.remove_user_from_group(id, &user.id).await?;
713
714 EventV1::ChannelGroupLeave {
715 id: id.to_string(),
716 user: user.id.to_string(),
717 }
718 .p(id.to_string())
719 .await;
720
721 if !silent {
722 if let Some(by) = by_id {
723 SystemMessage::UserRemove {
724 id: user.id.to_string(),
725 by: by.to_string(),
726 }
727 } else {
728 SystemMessage::UserLeft {
729 id: user.id.to_string(),
730 }
731 }
732 .into_message(id.to_string())
733 .send(
734 db,
735 Some(amqp),
736 MessageAuthor::System {
737 username: &user.username,
738 avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
739 },
740 None,
741 None,
742 self,
743 false,
744 )
745 .await
746 .ok();
747 }
748
749 Ok(())
750 }
751
752 _ => Err(create_error!(InvalidOperation)),
753 }
754 }
755
756 pub async fn delete(&self, db: &Database) -> Result<()> {
758 let id = self.id().to_string();
759 EventV1::ChannelDelete { id: id.clone() }.p(id).await;
760 db.delete_channel(self).await
764 }
765}
766
767#[cfg(feature = "mongodb")]
768impl IntoDocumentPath for FieldsChannel {
769 fn as_path(&self) -> Option<&'static str> {
770 Some(match self {
771 FieldsChannel::Description => "description",
772 FieldsChannel::Icon => "icon",
773 FieldsChannel::DefaultPermissions => "default_permissions",
774 FieldsChannel::Voice => "voice",
775 })
776 }
777}
778
779#[cfg(test)]
780mod tests {
781 use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
782
783 use crate::{fixture, util::permissions::DatabasePermissionQuery};
784
785 #[async_std::test]
786 async fn permissions_group_channel() {
787 database_test!(|db| async move {
788 fixture!(db, "group_with_members",
789 owner user 0
790 member1 user 1
791 member2 user 2
792 channel channel 3);
793
794 let mut query = DatabasePermissionQuery::new(&db, &owner).channel(&channel);
795 assert!(calculate_channel_permissions(&mut query)
796 .await
797 .has_channel_permission(ChannelPermission::SendMessage));
798
799 let mut query = DatabasePermissionQuery::new(&db, &member1).channel(&channel);
800 assert!(calculate_channel_permissions(&mut query)
801 .await
802 .has_channel_permission(ChannelPermission::SendMessage));
803
804 let mut query = DatabasePermissionQuery::new(&db, &member2).channel(&channel);
805 assert!(!calculate_channel_permissions(&mut query)
806 .await
807 .has_channel_permission(ChannelPermission::SendMessage));
808 });
809 }
810
811 #[async_std::test]
812 async fn permissions_text_channel() {
813 database_test!(|db| async move {
814 fixture!(db, "server_with_roles",
815 owner user 0
816 moderator user 1
817 user user 2
818 channel channel 3);
819
820 let mut query = DatabasePermissionQuery::new(&db, &owner).channel(&channel);
821 assert!(calculate_channel_permissions(&mut query)
822 .await
823 .has_channel_permission(ChannelPermission::SendMessage));
824
825 let mut query = DatabasePermissionQuery::new(&db, &moderator).channel(&channel);
826 assert!(calculate_channel_permissions(&mut query)
827 .await
828 .has_channel_permission(ChannelPermission::SendMessage));
829
830 let mut query = DatabasePermissionQuery::new(&db, &user).channel(&channel);
831 assert!(!calculate_channel_permissions(&mut query)
832 .await
833 .has_channel_permission(ChannelPermission::SendMessage));
834 });
835 }
836}