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 Slowmode,
165 }
166);
167
168#[allow(clippy::disallowed_methods)]
169impl Channel {
170 pub async fn create_server_channel(
192 db: &Database,
193 server: &mut Server,
194 data: v0::DataCreateServerChannel,
195 update_server: bool,
196 ) -> Result<Channel> {
197 let config = config().await;
198 if server.channels.len() > config.features.limits.global.server_channels {
199 return Err(create_error!(TooManyChannels {
200 max: config.features.limits.global.server_channels,
201 }));
202 };
203
204 let id = ulid::Ulid::new().to_string();
205 let channel = match data.channel_type {
206 v0::LegacyServerChannelType::Text => Channel::TextChannel {
207 id: id.clone(),
208 server: server.id.to_owned(),
209 name: data.name,
210 description: data.description,
211 icon: None,
212 last_message_id: None,
213 default_permissions: None,
214 role_permissions: HashMap::new(),
215 nsfw: data.nsfw.unwrap_or(false),
216 voice: data.voice.map(|voice| voice.into()),
217 slowmode: None,
218 },
219 v0::LegacyServerChannelType::Voice => Channel::TextChannel {
220 id: id.clone(),
221 server: server.id.to_owned(),
222 name: data.name,
223 description: data.description,
224 icon: None,
225 last_message_id: None,
226 default_permissions: None,
227 role_permissions: HashMap::new(),
228 nsfw: data.nsfw.unwrap_or(false),
229 voice: Some(data.voice.unwrap_or_default().into()),
230 slowmode: None,
231 },
232 };
233
234 db.insert_channel(&channel).await?;
235
236 if update_server {
237 server
238 .update(
239 db,
240 PartialServer {
241 channels: Some([server.channels.clone(), [id].into()].concat()),
242 ..Default::default()
243 },
244 vec![],
245 )
246 .await?;
247
248 EventV1::ChannelCreate(channel.clone().into())
249 .p(server.id.clone())
250 .await;
251 }
252
253 Ok(channel)
254 }
255
256 pub async fn create_group(
258 db: &Database,
259 mut data: v0::DataCreateGroup,
260 owner_id: String,
261 ) -> Result<Channel> {
262 data.users.insert(owner_id.to_string());
263
264 let config = config().await;
265 if data.users.len() > config.features.limits.global.group_size {
266 return Err(create_error!(GroupTooLarge {
267 max: config.features.limits.global.group_size,
268 }));
269 }
270
271 let id = ulid::Ulid::new().to_string();
272
273 let icon = if let Some(icon_id) = data.icon {
274 Some(File::use_channel_icon(db, &icon_id, &id, &owner_id).await?)
275 } else {
276 None
277 };
278
279 let recipients = data.users.into_iter().collect::<Vec<String>>();
280 let channel = Channel::Group {
281 id,
282
283 name: data.name,
284 owner: owner_id,
285 description: data.description,
286 recipients: recipients.clone(),
287
288 icon,
289 last_message_id: None,
290
291 permissions: None,
292
293 nsfw: data.nsfw.unwrap_or(false),
294 };
295
296 db.insert_channel(&channel).await?;
297
298 let event = EventV1::ChannelCreate(channel.clone().into());
299 for recipient in recipients {
300 event.clone().private(recipient).await;
301 }
302
303 Ok(channel)
304 }
305
306 pub async fn create_dm(db: &Database, user_a: &User, user_b: &User) -> Result<Channel> {
308 if let Ok(channel) = db.find_direct_message_channel(&user_a.id, &user_b.id).await {
310 Ok(channel)
311 } else {
312 let channel = if user_a.id == user_b.id {
313 Channel::SavedMessages {
315 id: Ulid::new().to_string(),
316 user: user_a.id.to_string(),
317 }
318 } else {
319 Channel::DirectMessage {
321 id: Ulid::new().to_string(),
322 active: true, recipients: vec![user_a.id.clone(), user_b.id.clone()],
324 last_message_id: None,
325 }
326 };
327
328 db.insert_channel(&channel).await?;
329
330 if let Channel::DirectMessage { .. } = &channel {
331 let event = EventV1::ChannelCreate(channel.clone().into());
332 event.clone().private(user_a.id.clone()).await;
333 event.private(user_b.id.clone()).await;
334 };
335
336 Ok(channel)
337 }
338 }
339
340 pub async fn add_user_to_group(
342 &mut self,
343 db: &Database,
344 amqp: &AMQP,
345 user: &User,
346 by_id: &str,
347 ) -> Result<()> {
348 if let Channel::Group { recipients, .. } = self {
349 if recipients.contains(&String::from(&user.id)) {
350 return Err(create_error!(AlreadyInGroup));
351 }
352
353 let config = config().await;
354 if recipients.len() >= config.features.limits.global.group_size {
355 return Err(create_error!(GroupTooLarge {
356 max: config.features.limits.global.group_size
357 }));
358 }
359
360 recipients.push(String::from(&user.id));
361 }
362
363 match &self {
364 Channel::Group { id, .. } => {
365 db.add_user_to_group(id, &user.id).await?;
366
367 EventV1::ChannelGroupJoin {
368 id: id.to_string(),
369 user: user.id.to_string(),
370 }
371 .p(id.to_string())
372 .await;
373
374 SystemMessage::UserAdded {
375 id: user.id.to_string(),
376 by: by_id.to_string(),
377 }
378 .into_message(id.to_string())
379 .send(
380 db,
381 Some(amqp),
382 MessageAuthor::System {
383 username: &user.username,
384 avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
385 },
386 None,
387 None,
388 self,
389 false,
390 )
391 .await
392 .ok();
393
394 EventV1::ChannelCreate(self.clone().into())
395 .private(user.id.to_string())
396 .await;
397
398 Ok(())
399 }
400 _ => Err(create_error!(InvalidOperation)),
401 }
402 }
403
404 pub fn is_direct_dm(&self) -> bool {
406 matches!(self, Channel::DirectMessage { .. })
407 }
408
409 pub fn contains_user(&self, user_id: &str) -> bool {
411 match self {
412 Channel::Group { recipients, .. } | Channel::DirectMessage { recipients, .. } => {
413 recipients.iter().any(|recipient| recipient == user_id)
414 }
415 Channel::SavedMessages { user, .. } => user == user_id,
416 _ => false,
417 }
418 }
419
420 pub fn users(&self) -> Result<Vec<String>> {
422 match self {
423 Channel::Group { recipients, .. } | Channel::DirectMessage { recipients, .. } => {
424 Ok(recipients.to_owned())
425 }
426 _ => Err(create_error!(NotFound)),
427 }
428 }
429
430 pub fn id(&self) -> &str {
432 match self {
433 Channel::DirectMessage { id, .. }
434 | Channel::Group { id, .. }
435 | Channel::SavedMessages { id, .. }
436 | Channel::TextChannel { id, .. } => id,
437 }
438 }
439
440 pub fn server(&self) -> Option<&str> {
442 match self {
443 Channel::TextChannel { server, .. } => Some(server),
444 _ => None,
445 }
446 }
447
448 pub fn voice(&self) -> Option<Cow<VoiceInformation>> {
450 match self {
451 Self::DirectMessage { .. } | Self::Group { .. } => {
452 Some(Cow::Owned(VoiceInformation::default()))
453 }
454 Self::TextChannel {
455 voice: Some(voice), ..
456 } => Some(Cow::Borrowed(voice)),
457 _ => None,
458 }
459 }
460
461 pub async fn set_role_permission(
463 &mut self,
464 db: &Database,
465 role_id: &str,
466 permissions: OverrideField,
467 ) -> Result<()> {
468 match self {
469 Channel::TextChannel {
470 id,
471 server,
472 role_permissions,
473 ..
474 } => {
475 db.set_channel_role_permission(id, role_id, permissions)
476 .await?;
477
478 role_permissions.insert(role_id.to_string(), permissions);
479
480 EventV1::ChannelUpdate {
481 id: id.clone(),
482 data: PartialChannel {
483 role_permissions: Some(role_permissions.clone()),
484 ..Default::default()
485 }
486 .into(),
487 clear: vec![],
488 }
489 .p(server.clone())
490 .await;
491
492 Ok(())
493 }
494 _ => Err(create_error!(InvalidOperation)),
495 }
496 }
497
498 pub async fn update(
500 &mut self,
501 db: &Database,
502 partial: PartialChannel,
503 remove: Vec<FieldsChannel>,
504 ) -> Result<()> {
505 for field in &remove {
506 self.remove_field(field);
507 }
508
509 self.apply_options(partial.clone());
510
511 let id = self.id().to_string();
512 db.update_channel(&id, &partial, remove.clone()).await?;
513
514 EventV1::ChannelUpdate {
515 id: id.clone(),
516 data: partial.into(),
517 clear: remove.into_iter().map(|v| v.into()).collect(),
518 }
519 .p(match self {
520 Self::TextChannel { server, .. } => server.clone(),
521 _ => id,
522 })
523 .await;
524
525 Ok(())
526 }
527
528 pub fn remove_field(&mut self, field: &FieldsChannel) {
530 match field {
531 FieldsChannel::Description => match self {
532 Self::Group { description, .. } | Self::TextChannel { description, .. } => {
533 description.take();
534 }
535 _ => {}
536 },
537 FieldsChannel::Icon => match self {
538 Self::Group { icon, .. } | Self::TextChannel { icon, .. } => {
539 icon.take();
540 }
541 _ => {}
542 },
543 FieldsChannel::DefaultPermissions => match self {
544 Self::TextChannel {
545 default_permissions,
546 ..
547 } => {
548 default_permissions.take();
549 }
550 _ => {}
551 },
552 FieldsChannel::Voice => match self {
553 Self::TextChannel { voice, .. } => {
554 voice.take();
555 }
556 _ => {}
557 },
558 FieldsChannel::Slowmode => match self {
559 Self::TextChannel { slowmode, .. } => {
560 slowmode.take();
561 }
562 _ => {}
563 }
564 }
565 }
566
567 pub fn remove_fields(&mut self, partial: Vec<FieldsChannel>) {
569 for field in partial {
570 self.remove_field(&field)
571 }
572 }
573
574 #[allow(deprecated)]
576 pub fn apply_options(&mut self, partial: PartialChannel) {
577 match self {
578 Self::SavedMessages { .. } => {}
579 Self::DirectMessage { active, .. } => {
580 if let Some(v) = partial.active {
581 *active = v;
582 }
583 }
584 Self::Group {
585 name,
586 owner,
587 description,
588 icon,
589 nsfw,
590 permissions,
591 ..
592 } => {
593 if let Some(v) = partial.name {
594 *name = v;
595 }
596
597 if let Some(v) = partial.owner {
598 *owner = v;
599 }
600
601 if let Some(v) = partial.description {
602 description.replace(v);
603 }
604
605 if let Some(v) = partial.icon {
606 icon.replace(v);
607 }
608
609 if let Some(v) = partial.nsfw {
610 *nsfw = v;
611 }
612
613 if let Some(v) = partial.permissions {
614 permissions.replace(v);
615 }
616 }
617 Self::TextChannel {
618 name,
619 description,
620 icon,
621 nsfw,
622 default_permissions,
623 role_permissions,
624 voice,
625 ..
626 } => {
627 if let Some(v) = partial.name {
628 *name = v;
629 }
630
631 if let Some(v) = partial.description {
632 description.replace(v);
633 }
634
635 if let Some(v) = partial.icon {
636 icon.replace(v);
637 }
638
639 if let Some(v) = partial.nsfw {
640 *nsfw = v;
641 }
642
643 if let Some(v) = partial.role_permissions {
644 *role_permissions = v;
645 }
646
647 if let Some(v) = partial.default_permissions {
648 default_permissions.replace(v);
649 }
650
651 if let Some(v) = partial.voice {
652 voice.replace(v);
653 }
654 }
655 }
656 }
657
658 pub fn generate_diff(
660 &self,
661 partial: &PartialChannel,
662 remove: &[FieldsChannel],
663 ) -> PartialChannel {
664 let mut before = PartialChannel::default();
665
666 match self {
667 Channel::SavedMessages { .. } => {}
668 Channel::DirectMessage {
669 active,
670 last_message_id,
671 ..
672 } => {
673 if partial.active.is_some() {
674 before.active = Some(*active);
675 };
676
677 if partial.last_message_id.is_some() {
678 before.last_message_id = last_message_id.clone()
679 };
680 }
681 Channel::Group {
682 name,
683 owner,
684 description,
685 icon,
686 last_message_id,
687 permissions,
688 nsfw,
689 ..
690 } => {
691 if partial.name.is_some() {
692 before.name = Some(name.clone());
693 };
694
695 if partial.owner.is_some() {
696 before.owner = Some(owner.clone());
697 };
698
699 if partial.description.is_some() || remove.contains(&FieldsChannel::Description) {
700 before.description = description.clone();
701 };
702
703 if partial.icon.is_some() || remove.contains(&FieldsChannel::Icon) {
704 before.icon = icon.clone();
705 };
706
707 if partial.last_message_id.is_some() {
708 before.last_message_id = last_message_id.clone()
709 };
710
711 if partial.permissions.is_some() {
712 before.permissions = *permissions;
713 };
714
715 if partial.nsfw.is_some() {
716 before.nsfw = Some(*nsfw);
717 };
718 }
719 Channel::TextChannel {
720 name,
721 description,
722 icon,
723 last_message_id,
724 default_permissions,
725 role_permissions,
726 nsfw,
727 voice,
728 slowmode,
729 ..
730 } => {
731 if partial.name.is_some() {
732 before.name = Some(name.clone());
733 };
734
735 if partial.description.is_some() || remove.contains(&FieldsChannel::Description) {
736 before.description = description.clone();
737 };
738
739 if partial.icon.is_some() || remove.contains(&FieldsChannel::Icon) {
740 before.icon = icon.clone();
741 };
742
743 if partial.last_message_id.is_some() {
744 before.last_message_id = last_message_id.clone()
745 };
746
747 if partial.default_permissions.is_some()
748 || remove.contains(&FieldsChannel::DefaultPermissions)
749 {
750 before.default_permissions = *default_permissions;
751 };
752
753 if partial.role_permissions.is_some() {
754 before.role_permissions = Some(role_permissions.clone());
755 };
756
757 if partial.nsfw.is_some() {
758 before.nsfw = Some(*nsfw);
759 };
760
761 if partial.voice.is_some() || remove.contains(&FieldsChannel::Voice) {
762 before.voice = voice.clone();
763 };
764
765 if partial.slowmode.is_some() {
766 before.slowmode = *slowmode;
767 }
768 }
769 }
770
771 before
772 }
773
774 pub async fn ack(&self, user: &str, message: &str, amqp: &AMQP) -> Result<()> {
776 EventV1::ChannelAck {
777 id: self.id().to_string(),
778 user: user.to_string(),
779 message_id: message.to_string(),
780 }
781 .private(user.to_string())
782 .await;
783
784 crate::util::acker::ack_channel(user, self.id(), message, amqp).await
785 }
786
787 pub async fn remove_user_from_group(
789 &self,
790 db: &Database,
791 amqp: &AMQP,
792 user: &User,
793 by_id: Option<&str>,
794 silent: bool,
795 ) -> Result<()> {
796 match &self {
797 Channel::Group {
798 id,
799 name,
800 owner,
801 recipients,
802 ..
803 } => {
804 if &user.id == owner {
805 if let Some(new_owner) = recipients.iter().find(|x| *x != &user.id) {
806 db.update_channel(
807 id,
808 &PartialChannel {
809 owner: Some(new_owner.into()),
810 ..Default::default()
811 },
812 vec![],
813 )
814 .await?;
815
816 SystemMessage::ChannelOwnershipChanged {
817 from: owner.to_string(),
818 to: new_owner.to_string(),
819 }
820 .into_message(id.to_string())
821 .send(
822 db,
823 Some(amqp),
824 MessageAuthor::System {
825 username: name,
826 avatar: None,
827 },
828 None,
829 None,
830 self,
831 false,
832 )
833 .await
834 .ok();
835 } else {
836 return self.delete(db).await;
837 }
838 }
839
840 db.remove_user_from_group(id, &user.id).await?;
841
842 EventV1::ChannelGroupLeave {
843 id: id.to_string(),
844 user: user.id.to_string(),
845 }
846 .p(id.to_string())
847 .await;
848
849 if !silent {
850 if let Some(by) = by_id {
851 SystemMessage::UserRemove {
852 id: user.id.to_string(),
853 by: by.to_string(),
854 }
855 } else {
856 SystemMessage::UserLeft {
857 id: user.id.to_string(),
858 }
859 }
860 .into_message(id.to_string())
861 .send(
862 db,
863 Some(amqp),
864 MessageAuthor::System {
865 username: &user.username,
866 avatar: user.avatar.as_ref().map(|file| file.id.as_ref()),
867 },
868 None,
869 None,
870 self,
871 false,
872 )
873 .await
874 .ok();
875 }
876
877 Ok(())
878 }
879
880 _ => Err(create_error!(InvalidOperation)),
881 }
882 }
883
884 pub async fn delete(&self, db: &Database) -> Result<()> {
886 let id = self.id().to_string();
887 EventV1::ChannelDelete { id: id.clone() }.p(id).await;
888 db.delete_channel(self).await
892 }
893}
894
895#[cfg(feature = "mongodb")]
896impl IntoDocumentPath for FieldsChannel {
897 fn as_path(&self) -> Option<&'static str> {
898 Some(match self {
899 FieldsChannel::Description => "description",
900 FieldsChannel::Icon => "icon",
901 FieldsChannel::DefaultPermissions => "default_permissions",
902 FieldsChannel::Voice => "voice",
903 FieldsChannel::Slowmode => "slowmode",
904 })
905 }
906}
907
908#[cfg(test)]
909mod tests {
910 use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
911
912 use crate::{fixture, util::permissions::DatabasePermissionQuery};
913
914 #[tokio::test]
915 async fn permissions_group_channel() {
916 database_test!(|db| async move {
917 fixture!(db, "group_with_members",
918 owner user 0
919 member1 user 1
920 member2 user 2
921 channel channel 3);
922
923 let mut query = DatabasePermissionQuery::new(&db, &owner).channel(&channel);
924 assert!(calculate_channel_permissions(&mut query)
925 .await
926 .has_channel_permission(ChannelPermission::SendMessage));
927
928 let mut query = DatabasePermissionQuery::new(&db, &member1).channel(&channel);
929 assert!(calculate_channel_permissions(&mut query)
930 .await
931 .has_channel_permission(ChannelPermission::SendMessage));
932
933 let mut query = DatabasePermissionQuery::new(&db, &member2).channel(&channel);
934 assert!(!calculate_channel_permissions(&mut query)
935 .await
936 .has_channel_permission(ChannelPermission::SendMessage));
937 });
938 }
939
940 #[tokio::test]
941 async fn permissions_text_channel() {
942 database_test!(|db| async move {
943 fixture!(db, "server_with_roles",
944 owner user 0
945 moderator user 1
946 user user 2
947 channel channel 3);
948
949 let mut query = DatabasePermissionQuery::new(&db, &owner).channel(&channel);
950 assert!(calculate_channel_permissions(&mut query)
951 .await
952 .has_channel_permission(ChannelPermission::SendMessage));
953
954 let mut query = DatabasePermissionQuery::new(&db, &moderator).channel(&channel);
955 assert!(calculate_channel_permissions(&mut query)
956 .await
957 .has_channel_permission(ChannelPermission::SendMessage));
958
959 let mut query = DatabasePermissionQuery::new(&db, &user).channel(&channel);
960 assert!(!calculate_channel_permissions(&mut query)
961 .await
962 .has_channel_permission(ChannelPermission::SendMessage));
963 });
964 }
965}