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