robespierre_models/
channels.rs

1use std::{collections::HashMap, fmt::Display};
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::{
7    autumn::{Attachment, AttachmentId},
8    id::{ChannelId, MessageId, RoleId, ServerId, UserId},
9    january::Embed,
10};
11
12/*
13Types
14*/
15
16/*
17Note: leave `channel_type`, and use that as the #[serde(tag=)] of `Channel`, but take the `nonce` from `Channel`
18*/
19
20// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L26-L41
21
22/// Saved Messages channel has only one participant, the user who created it.
23#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
24#[serde(deny_unknown_fields)]
25pub struct SavedMessagesChannel {
26    #[serde(rename = "_id")]
27    pub id: ChannelId,
28    pub user: UserId,
29
30    #[serde(default, skip_serializing_if = "Option::is_none")]
31    pub nonce: Option<String>,
32}
33
34// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L43-L62
35
36#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
37#[serde(deny_unknown_fields)]
38pub struct DirectMessageChannel {
39    #[serde(rename = "_id")]
40    pub id: ChannelId,
41    pub active: bool,
42    pub recipients: Vec<UserId>,
43    #[serde(default, skip_serializing_if = "Option::is_none")]
44    pub last_message_id: Option<MessageId>,
45
46    // from channel
47    #[serde(default, skip_serializing_if = "Option::is_none")]
48    pub nonce: Option<String>,
49}
50
51// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L64-L108
52
53#[derive(Deserialize, Serialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
54#[serde(deny_unknown_fields)]
55pub struct GroupChannel {
56    #[serde(rename = "_id")]
57    pub id: ChannelId,
58    /// List of user IDs who are participating in this group
59    pub recipients: Vec<UserId>,
60
61    /// Group name
62    pub name: String,
63
64    /// User ID of group owner
65    pub owner: UserId,
66
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub description: Option<String>,
69
70    #[serde(default, skip_serializing_if = "Option::is_none")]
71    pub last_message_id: Option<MessageId>,
72
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub icon: Option<Attachment>,
75
76    #[serde(default, skip_serializing_if = "Option::is_none")]
77    pub permissions: Option<ChannelPermissions>,
78
79    #[serde(default, skip_serializing_if = "Option::is_none")]
80    pub nsfw: Option<bool>,
81
82    // from channel
83    #[serde(default, skip_serializing_if = "Option::is_none")]
84    pub nonce: Option<String>,
85}
86
87// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L110-L149
88
89#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
90#[serde(deny_unknown_fields)]
91pub struct ServerChannel {
92    #[serde(rename = "_id")]
93    pub id: ChannelId,
94
95    pub server: ServerId,
96
97    pub name: String,
98
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    pub description: Option<String>,
101
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub icon: Option<Attachment>,
104
105    /// Permissions given to all users
106    #[serde(default, skip_serializing_if = "Option::is_none")]
107    pub default_permissions: Option<ChannelPermissions>,
108
109    /// Permissions given to roles
110    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
111    pub role_permissions: HashMap<RoleId, ChannelPermissions>,
112
113    #[serde(default, skip_serializing_if = "Option::is_none")]
114    pub nsfw: Option<bool>,
115}
116
117// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L151-L155
118
119#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
120#[serde(deny_unknown_fields)]
121pub struct TextChannel {
122    #[serde(flatten)]
123    pub server_channel: ServerChannel,
124
125    pub last_message_id: Option<MessageId>,
126
127    // from channel
128    #[serde(default, skip_serializing_if = "Option::is_none")]
129    pub nonce: Option<String>,
130}
131
132// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L157-L159
133
134#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
135#[serde(deny_unknown_fields)]
136pub struct VoiceChannel {
137    #[serde(flatten)]
138    pub server_channel: ServerChannel,
139
140    // from channel
141    #[serde(default, skip_serializing_if = "Option::is_none")]
142    pub nonce: Option<String>,
143}
144
145// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L161
146
147/// A channel
148#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
149#[serde(tag = "channel_type")]
150#[serde(deny_unknown_fields)]
151pub enum Channel {
152    SavedMessages(SavedMessagesChannel),
153    DirectMessage(DirectMessageChannel),
154    Group(GroupChannel),
155    TextChannel(TextChannel),
156    VoiceChannel(VoiceChannel),
157}
158
159// https://github.com/revoltchat/api/blob/097f40e37108cd3a1816b1c2cc69a137ae317069/types/Channels.ts#L163-L210
160/// A message
161#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
162#[serde(deny_unknown_fields)]
163pub struct Message {
164    #[serde(rename = "_id")]
165    pub id: MessageId,
166    #[serde(default, skip_serializing_if = "Option::is_none")]
167    pub nonce: Option<String>,
168    pub channel: ChannelId,
169    pub author: UserId,
170    pub content: MessageContent,
171    #[serde(default, skip_serializing_if = "Vec::is_empty")]
172    pub attachments: Vec<Attachment>,
173    #[serde(default, skip_serializing_if = "Option::is_none")]
174    pub edited: Option<Date>,
175    #[serde(default, skip_serializing_if = "Vec::is_empty")]
176    pub embeds: Vec<Embed>,
177    #[serde(default, skip_serializing_if = "Vec::is_empty")]
178    pub mentions: Vec<UserId>,
179    #[serde(default, skip_serializing_if = "Vec::is_empty")]
180    pub replies: Vec<MessageId>,
181}
182
183#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
184#[serde(untagged)]
185#[serde(deny_unknown_fields)]
186pub enum MessageContent {
187    Content(String),
188    SystemMessage(SystemMessage),
189}
190
191#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
192#[serde(tag = "type", rename_all = "snake_case")]
193#[serde(deny_unknown_fields)]
194pub enum SystemMessage {
195    Text { content: String },
196    UserAdded { id: UserId, by: UserId },
197    UserRemove { id: UserId, by: UserId },
198    UserJoined { id: UserId },
199    UserLeft { id: UserId },
200    UserKicked { id: UserId },
201    UserBanned { id: UserId },
202    ChannelRenamed { name: String, by: UserId },
203    ChannelDescriptionChanged { by: UserId },
204    ChannelIconChanged { by: UserId },
205}
206
207/*
208Extra
209*/
210
211/// Data about what messages to reply to
212#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
213#[serde(deny_unknown_fields)]
214pub struct ReplyData {
215    pub id: MessageId,
216    pub mention: bool,
217}
218
219bitflags::bitflags! {
220    #[derive(Serialize, Deserialize)]
221    #[serde(transparent)]
222    #[doc = "Channel permissions"]
223    pub struct ChannelPermissions: u32 {
224        const VIEW = 0b00000000000000000000000000000001;           // 1
225        const SEND_MESSAGE = 0b00000000000000000000000000000010;    // 2
226        const MANAGE_MESSAGES = 0b00000000000000000000000000000100; // 4
227        const MANAGE_CHANNEL = 0b00000000000000000000000000001000;  // 8
228        const VOICE_CALL =  0b00000000000000000000000000010000;      // 16
229        const INVITE_OTHERS = 0b00000000000000000000000000100000;   // 32
230        const EMBED_LINKS = 0b00000000000000000000000001000000;   // 64
231        const UPLOAD_FILES = 0b00000000000000000000000010000000;   // 128
232    }
233}
234
235impl Channel {
236    pub fn id(&self) -> ChannelId {
237        match self {
238            Self::SavedMessages(SavedMessagesChannel { id, .. }) => *id,
239            Self::DirectMessage(DirectMessageChannel { id, .. }) => *id,
240            Self::Group(GroupChannel { id, .. }) => *id,
241            Self::TextChannel(TextChannel {
242                server_channel: ServerChannel { id, .. },
243                ..
244            }) => *id,
245            Self::VoiceChannel(VoiceChannel {
246                server_channel: ServerChannel { id, .. },
247                ..
248            }) => *id,
249        }
250    }
251
252    pub fn server_id(&self) -> Option<ServerId> {
253        match self {
254            Channel::TextChannel(TextChannel {
255                server_channel: ServerChannel { server, .. },
256                ..
257            })
258            | Channel::VoiceChannel(VoiceChannel {
259                server_channel: ServerChannel { server, .. },
260                ..
261            }) => Some(*server),
262            _ => None,
263        }
264    }
265}
266
267#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
268pub enum ChannelType {
269    SavedMessages,
270    DirectMessage,
271    Group,
272    TextChannel,
273    VoiceChannel,
274}
275
276/// A channel where all the fields are optional, and can be treated as a patch that
277/// can be applied to a [`Channel`].
278#[derive(Deserialize, Serialize, Debug, Clone, Eq, PartialEq)]
279#[serde(deny_unknown_fields)]
280pub struct PartialChannel {
281    #[serde(default, skip_serializing_if = "Option::is_none")]
282    user: Option<UserId>,
283    #[serde(default, skip_serializing_if = "Option::is_none")]
284    nonce: Option<String>,
285
286    #[serde(default, skip_serializing_if = "Option::is_none")]
287    recipients: Option<Vec<UserId>>,
288    #[serde(default, skip_serializing_if = "Option::is_none")]
289    last_message_id: Option<MessageId>,
290
291    name: Option<String>,
292    #[serde(default, skip_serializing_if = "Option::is_none")]
293    owner: Option<UserId>,
294    #[serde(default, skip_serializing_if = "Option::is_none")]
295    description: Option<String>,
296    #[serde(default, skip_serializing_if = "Option::is_none")]
297    icon: Option<Attachment>,
298    #[serde(default, skip_serializing_if = "Option::is_none")]
299    permissions: Option<ChannelPermissions>,
300
301    #[serde(default, skip_serializing_if = "Option::is_none")]
302    server: Option<ServerId>,
303    #[serde(default, skip_serializing_if = "Option::is_none")]
304    default_permissions: Option<ChannelPermissions>,
305    #[serde(default, skip_serializing_if = "Option::is_none")]
306    role_permissions: Option<HashMap<RoleId, ChannelPermissions>>,
307
308    #[serde(default, skip_serializing_if = "Option::is_none")]
309    active: Option<bool>,
310
311    #[serde(default, skip_serializing_if = "Option::is_none")]
312    nsfw: Option<bool>,
313
314    #[serde(default, skip_serializing_if = "Option::is_none")]
315    channel_type: Option<ChannelType>,
316}
317
318impl PartialChannel {
319    /// Treats self as a patch and applies it to channel.
320    pub fn patch(self, ch: &mut Channel) {
321        match ch {
322            Channel::SavedMessages(SavedMessagesChannel { id: _, user, nonce }) => {
323                if let Some(puser) = self.user {
324                    *user = puser;
325                }
326                if let Some(pnonce) = self.nonce {
327                    *nonce = Some(pnonce);
328                }
329            }
330            Channel::DirectMessage(DirectMessageChannel {
331                id: _,
332                recipients,
333                last_message_id,
334                nonce,
335                active,
336            }) => {
337                if let Some(precipients) = self.recipients {
338                    *recipients = precipients;
339                }
340                if let Some(plast_message_id) = self.last_message_id {
341                    *last_message_id = Some(plast_message_id);
342                }
343                if let Some(pnonce) = self.nonce {
344                    *nonce = Some(pnonce);
345                }
346
347                if let Some(pactive) = self.active {
348                    *active = pactive;
349                }
350            }
351            Channel::Group(GroupChannel {
352                id: _,
353                recipients,
354                name,
355                owner,
356                description,
357                last_message_id,
358                icon,
359                permissions,
360                nsfw,
361                nonce,
362            }) => {
363                if let Some(precipients) = self.recipients {
364                    *recipients = precipients;
365                }
366                if let Some(pname) = self.name {
367                    *name = pname;
368                }
369                if let Some(powner) = self.owner {
370                    *owner = powner;
371                }
372                if let Some(pdescription) = self.description {
373                    *description = Some(pdescription);
374                }
375                if let Some(plast_message_id) = self.last_message_id {
376                    *last_message_id = Some(plast_message_id);
377                }
378                if let Some(picon) = self.icon {
379                    *icon = Some(picon);
380                }
381                if let Some(ppermissions) = self.permissions {
382                    *permissions = Some(ppermissions);
383                }
384                if let Some(pnsfw) = self.nsfw {
385                    *nsfw = Some(pnsfw);
386                }
387                if let Some(pnonce) = self.nonce {
388                    *nonce = Some(pnonce);
389                }
390            }
391            Channel::TextChannel(TextChannel {
392                server_channel:
393                    ServerChannel {
394                        id: _,
395                        server,
396                        name,
397                        description,
398                        icon,
399                        default_permissions,
400                        role_permissions,
401                        nsfw,
402                    },
403                last_message_id: _,
404                nonce,
405            }) => {
406                if let Some(pserver) = self.server {
407                    *server = pserver;
408                }
409                if let Some(pname) = self.name {
410                    *name = pname;
411                }
412                if let Some(pdescription) = self.description {
413                    *description = Some(pdescription);
414                }
415                if let Some(picon) = self.icon {
416                    *icon = Some(picon);
417                }
418                if let Some(pdefault_permissions) = self.default_permissions {
419                    *default_permissions = Some(pdefault_permissions);
420                }
421                if let Some(prole_permissions) = self.role_permissions {
422                    *role_permissions = prole_permissions;
423                }
424                if let Some(pnsfw) = self.nsfw {
425                    *nsfw = Some(pnsfw);
426                }
427                // if let Some(plast_message_id) = self.last_message_id {
428                //     *last_message_id = Some(plast_message_id);
429                // }
430                if let Some(pnonce) = self.nonce {
431                    *nonce = Some(pnonce);
432                }
433            }
434            Channel::VoiceChannel(VoiceChannel {
435                server_channel:
436                    ServerChannel {
437                        id: _,
438                        server,
439                        name,
440                        description,
441                        icon,
442                        default_permissions,
443                        role_permissions,
444                        nsfw,
445                    },
446                nonce,
447            }) => {
448                if let Some(pserver) = self.server {
449                    *server = pserver;
450                }
451                if let Some(pname) = self.name {
452                    *name = pname;
453                }
454                if let Some(pdescription) = self.description {
455                    *description = Some(pdescription);
456                }
457                if let Some(picon) = self.icon {
458                    *icon = Some(picon);
459                }
460                if let Some(pdefault_permissions) = self.default_permissions {
461                    *default_permissions = Some(pdefault_permissions);
462                }
463                if let Some(prole_permissions) = self.role_permissions {
464                    *role_permissions = prole_permissions;
465                }
466                if let Some(pnsfw) = self.nsfw {
467                    *nsfw = Some(pnsfw);
468                }
469                if let Some(pnonce) = self.nonce {
470                    *nonce = Some(pnonce);
471                }
472            }
473        }
474    }
475}
476
477/// A message where all the fields are optional, and can be treated as a patch
478/// that can be applied to a [`Message`].
479#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
480#[serde(deny_unknown_fields)]
481pub struct PartialMessage {
482    #[serde(rename = "_id", default, skip_serializing_if = "Option::is_none")]
483    pub id: Option<MessageId>,
484    #[serde(default, skip_serializing_if = "Option::is_none")]
485    pub nonce: Option<String>,
486    #[serde(default, skip_serializing_if = "Option::is_none")]
487    pub channel: Option<ChannelId>,
488    #[serde(default, skip_serializing_if = "Option::is_none")]
489    pub author: Option<UserId>,
490    #[serde(default, skip_serializing_if = "Option::is_none")]
491    pub content: Option<MessageContent>,
492    #[serde(default, skip_serializing_if = "Option::is_none")]
493    pub attachments: Option<Vec<Attachment>>,
494    #[serde(default, skip_serializing_if = "Option::is_none")]
495    pub edited: Option<Date>,
496    #[serde(default, skip_serializing_if = "Option::is_none")]
497    pub embeds: Option<Vec<Embed>>,
498    #[serde(default, skip_serializing_if = "Option::is_none")]
499    pub mentions: Option<Vec<UserId>>,
500    #[serde(default, skip_serializing_if = "Option::is_none")]
501    pub replies: Option<Vec<MessageId>>,
502}
503
504impl PartialMessage {
505    /// Treats self as a patch and applies it to message.
506    pub fn patch(self, m: &mut Message) {
507        let PartialMessage {
508            id: pid,
509            nonce: pnonce,
510            channel: pchannel,
511            author: pauthor,
512            content: pcontent,
513            attachments: pattachments,
514            edited: pedited,
515            embeds: pembeds,
516            mentions: pmentions,
517            replies: preplies,
518        } = self;
519        let Message {
520            id,
521            nonce,
522            channel,
523            author,
524            content,
525            attachments,
526            edited,
527            embeds,
528            mentions,
529            replies,
530        } = m;
531
532        if let Some(pid) = pid {
533            *id = pid;
534        }
535        if let Some(pnonce) = pnonce {
536            *nonce = Some(pnonce);
537        }
538        if let Some(pchannel) = pchannel {
539            *channel = pchannel;
540        }
541        if let Some(pauthor) = pauthor {
542            *author = pauthor;
543        }
544        if let Some(pcontent) = pcontent {
545            *content = pcontent;
546        }
547        if let Some(pattachments) = pattachments {
548            *attachments = pattachments;
549        }
550        if let Some(pedited) = pedited {
551            *edited = Some(pedited);
552        }
553        if let Some(pembeds) = pembeds {
554            *embeds = pembeds;
555        }
556        if let Some(pmentions) = pmentions {
557            *mentions = pmentions;
558        }
559        if let Some(preplies) = preplies {
560            *replies = preplies;
561        }
562    }
563}
564
565/// Helper to serialize / deserialize mongo dates
566#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
567#[serde(from = "WrappedDate", into = "WrappedDate")]
568pub struct Date(pub DateTime<Utc>);
569
570impl From<Date> for WrappedDate {
571    fn from(d: Date) -> Self {
572        Self { date: d.0 }
573    }
574}
575
576impl From<WrappedDate> for Date {
577    fn from(d: WrappedDate) -> Self {
578        Self(d.date)
579    }
580}
581
582#[derive(Serialize, Deserialize)]
583#[serde(deny_unknown_fields)]
584struct WrappedDate {
585    #[serde(rename = "$date")]
586    date: DateTime<Utc>,
587}
588
589/// A patch to a channel
590#[derive(Serialize, Debug, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
591pub struct ChannelEditPatch {
592    #[serde(skip_serializing_if = "Option::is_none")]
593    pub name: Option<String>,
594    #[serde(skip_serializing_if = "Option::is_none")]
595    pub description: Option<String>,
596    #[serde(skip_serializing_if = "Option::is_none")]
597    pub icon: Option<AttachmentId>,
598    #[serde(skip_serializing_if = "Option::is_none")]
599    pub remove: Option<ChannelField>,
600}
601
602/// A channel field that can be removed from a channel
603#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
604pub enum ChannelField {
605    Description,
606    Icon,
607}
608
609impl ChannelField {
610    /// Treats self as a patch and removes the field from the channel.
611    pub fn remove_patch(self, channel: &mut Channel) {
612        match self {
613            Self::Description => match channel {
614                Channel::Group(GroupChannel { description, .. })
615                | Channel::TextChannel(TextChannel {
616                    server_channel: ServerChannel { description, .. },
617                    ..
618                })
619                | Channel::VoiceChannel(VoiceChannel {
620                    server_channel: ServerChannel { description, .. },
621                    ..
622                }) => *description = None,
623                Channel::SavedMessages { .. } | Channel::DirectMessage { .. } => {}
624            },
625            Self::Icon => match channel {
626                Channel::Group(GroupChannel { icon, .. })
627                | Channel::TextChannel(TextChannel {
628                    server_channel: ServerChannel { icon, .. },
629                    ..
630                })
631                | Channel::VoiceChannel(VoiceChannel {
632                    server_channel: ServerChannel { icon, .. },
633                    ..
634                }) => *icon = None,
635                Channel::SavedMessages { .. } | Channel::DirectMessage { .. } => {}
636            },
637        }
638    }
639}
640
641/// An invite code
642#[derive(Serialize, Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
643#[serde(transparent)]
644pub struct ChannelInviteCode(String);
645
646impl Display for ChannelInviteCode {
647    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
648        self.0.fmt(f)
649    }
650}
651
652#[derive(Deserialize, Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
653#[serde(deny_unknown_fields)]
654pub struct CreateChannelInviteResponse {
655    code: ChannelInviteCode,
656}
657
658/// Message filter
659#[derive(Debug, Default, Serialize)]
660pub struct MessageFilter {
661    #[serde(skip_serializing_if = "Option::is_none")]
662    pub limit: Option<usize>,
663    #[serde(skip_serializing_if = "Option::is_none")]
664    pub before: Option<MessageId>,
665    #[serde(skip_serializing_if = "Option::is_none")]
666    pub after: Option<MessageId>,
667    pub sort: MessageFilterSortDirection,
668    #[serde(skip_serializing_if = "Option::is_none")]
669    pub nearby: Option<MessageId>,
670    #[serde(skip_serializing_if = "Option::is_none")]
671    pub include_users: Option<bool>,
672}
673
674/// THe direction of a message filter
675#[derive(Debug, Serialize)]
676pub enum MessageFilterSortDirection {
677    /// Tkae the latest messages first.
678    Latest,
679    /// Take the oldest messages first.
680    Oldest,
681}
682
683impl Default for MessageFilterSortDirection {
684    fn default() -> Self {
685        Self::Latest
686    }
687}
688
689/// Server channel type
690#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
691pub enum ServerChannelType {
692    Text,
693    Voice,
694}