revolt_database/models/channels/ops/
mongodb.rs

1use super::AbstractChannels;
2use crate::{AbstractServers, Channel, FieldsChannel, IntoDocumentPath, MongoDb, PartialChannel};
3use bson::{Bson, Document};
4use futures::StreamExt;
5use revolt_permissions::OverrideField;
6use revolt_result::Result;
7
8static COL: &str = "channels";
9
10#[async_trait]
11impl AbstractChannels for MongoDb {
12    /// Insert a new channel in the database
13    async fn insert_channel(&self, channel: &Channel) -> Result<()> {
14        query!(self, insert_one, COL, &channel).map(|_| ())
15    }
16
17    /// Fetch a channel from the database
18    async fn fetch_channel(&self, channel_id: &str) -> Result<Channel> {
19        query!(self, find_one_by_id, COL, channel_id)?.ok_or_else(|| create_error!(NotFound))
20    }
21
22    /// Fetch all channels from the database
23    async fn fetch_channels<'a>(&self, ids: &'a [String]) -> Result<Vec<Channel>> {
24        Ok(self
25            .col::<Channel>(COL)
26            .find(doc! {
27                "_id": {
28                    "$in": ids
29                }
30            })
31            .await
32            .map_err(|_| create_database_error!("fetch", "channels"))?
33            .filter_map(|s| async {
34                if cfg!(debug_assertions) {
35                    Some(s.unwrap())
36                } else {
37                    s.ok()
38                }
39            })
40            .collect()
41            .await)
42    }
43
44    /// Fetch all direct messages for a user
45    async fn find_direct_messages(&self, user_id: &str) -> Result<Vec<Channel>> {
46        query!(
47            self,
48            find,
49            COL,
50            doc! {
51                "$or": [
52                    {
53                        "$or": [
54                            {
55                                "channel_type": "DirectMessage"
56                            },
57                            {
58                                "channel_type": "Group"
59                            }
60                        ],
61                        "recipients": user_id
62                    },
63                    {
64                        "channel_type": "SavedMessages",
65                        "user": user_id
66                    }
67                ]
68            }
69        )
70    }
71
72    // Fetch saved messages channel
73    async fn find_saved_messages_channel(&self, user_id: &str) -> Result<Channel> {
74        query!(
75            self,
76            find_one,
77            COL,
78            doc! {
79                "channel_type": "SavedMessages",
80                "user": user_id
81            }
82        )?
83        .ok_or_else(|| create_error!(InternalError))
84    }
85
86    // Fetch direct message channel (DM or Saved Messages)
87    async fn find_direct_message_channel(&self, user_a: &str, user_b: &str) -> Result<Channel> {
88        let doc = match (user_a, user_b) {
89            self_user if self_user.0 == self_user.1 => {
90                doc! {
91                    "channel_type": "SavedMessages",
92                    "user": self_user.0
93                }
94            }
95            users => {
96                doc! {
97                    "channel_type": "DirectMessage",
98                    "recipients": {
99                        "$all": [ users.0, users.1 ]
100                    }
101                }
102            }
103        };
104        query!(self, find_one, COL, doc)?.ok_or_else(|| create_error!(NotFound))
105    }
106
107    /// Insert a user to a group
108    async fn add_user_to_group(&self, channel: &str, user: &str) -> Result<()> {
109        self.col::<Document>(COL)
110            .update_one(
111                doc! {
112                    "_id": channel
113                },
114                doc! {
115                    "$push": {
116                        "recipients": user
117                    }
118                },
119            )
120            .await
121            .map(|_| ())
122            .map_err(|_| create_database_error!("update_one", "channel"))
123    }
124
125    /// Insert channel role permissions
126    async fn set_channel_role_permission(
127        &self,
128        channel: &str,
129        role: &str,
130        permissions: OverrideField,
131    ) -> Result<()> {
132        self.col::<Document>(COL)
133            .update_one(
134                doc! { "_id": channel },
135                doc! {
136                "$set": {
137                    "role_permissions.".to_owned() + role: permissions
138                }
139                },
140            )
141            .await
142            .map(|_| ())
143            .map_err(|_| create_database_error!("update_one", "channel"))
144    }
145
146    // Update channel
147    async fn update_channel(
148        &self,
149        id: &str,
150        channel: &PartialChannel,
151        remove: Vec<FieldsChannel>,
152    ) -> Result<()> {
153        query!(
154            self,
155            update_one_by_id,
156            COL,
157            id,
158            channel,
159            remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
160            None
161        )
162        .map(|_| ())
163    }
164
165    // Remove a user from a group
166    async fn remove_user_from_group(&self, channel: &str, user: &str) -> Result<()> {
167        self.col::<Document>(COL)
168            .update_one(
169                doc! {
170                    "_id": channel
171                },
172                doc! {
173                    "$pull": {
174                        "recipients": user
175                    }
176                },
177            )
178            .await
179            .map(|_| ())
180            .map_err(|_| create_database_error!("update_one", "channels"))
181    }
182
183    // Delete a channel
184    async fn delete_channel(&self, channel: &Channel) -> Result<()> {
185        let id = channel.id().to_string();
186        let server_id = match channel {
187            Channel::TextChannel { server, .. } => {
188                Some(server)
189            }
190            _ => None,
191        };
192
193        // Delete invites and unreads.
194        self.delete_associated_channel_objects(Bson::String(id.to_string()))
195            .await?;
196
197        // Delete messages.
198        self.delete_bulk_messages(doc! {
199            "channel": &id
200        })
201        .await?;
202
203        // Remove from server object.
204        if let Some(server) = server_id {
205            let server = self.fetch_server(server).await?;
206            let mut update = doc! {
207                "$pull": {
208                    "channels": &id
209                }
210            };
211
212            if let Some(sys) = &server.system_messages {
213                let mut unset = doc! {};
214
215                if let Some(cid) = &sys.user_joined {
216                    if &id == cid {
217                        unset.insert("system_messages.user_joined", 1_i32);
218                    }
219                }
220
221                if let Some(cid) = &sys.user_left {
222                    if &id == cid {
223                        unset.insert("system_messages.user_left", 1_i32);
224                    }
225                }
226
227                if let Some(cid) = &sys.user_kicked {
228                    if &id == cid {
229                        unset.insert("system_messages.user_kicked", 1_i32);
230                    }
231                }
232
233                if let Some(cid) = &sys.user_banned {
234                    if &id == cid {
235                        unset.insert("system_messages.user_banned", 1_i32);
236                    }
237                }
238
239                if !unset.is_empty() {
240                    update.insert("$unset", unset);
241                }
242            }
243
244            self.col::<Document>("servers")
245                .update_one(
246                    doc! {
247                        "_id": server.id
248                    },
249                    update,
250                )
251                .await
252                .map_err(|_| create_database_error!("update_one", "servers"))?;
253        }
254
255        // Delete associated attachments
256        self.delete_many_attachments(doc! {
257            "used_for.id": &id
258        })
259        .await?;
260
261        // Delete the channel itself
262        query!(self, delete_one_by_id, COL, channel.id()).map(|_| ())
263    }
264}
265
266impl MongoDb {
267    pub async fn delete_associated_channel_objects(&self, id: Bson) -> Result<()> {
268        // Delete all invites to these channels.
269        self.col::<Document>("channel_invites")
270            .delete_many(doc! {
271                "channel": &id
272            })
273            .await
274            .map_err(|_| create_database_error!("delete_many", "channel_invites"))?;
275
276        // Delete unread message objects on channels.
277        self.col::<Document>("channel_unreads")
278            .delete_many(doc! {
279                "_id.channel": &id
280            })
281            .await
282            .map_err(|_| create_database_error!("delete_many", "channel_unreads"))
283            .map(|_| ())?;
284
285        // update many attachments with parent id
286
287        // Delete all webhooks on this channel.
288        self.col::<Document>("webhooks")
289            .delete_many(doc! {
290                "channel": &id
291            })
292            .await
293            .map_err(|_| create_database_error!("delete_many", "webhooks"))
294            .map(|_| ())
295    }
296}