revolt_database/models/servers/ops/
mongodb.rs1use bson::{to_document, Bson, Document};
2use futures::StreamExt;
3use revolt_result::Result;
4
5use crate::{FieldsRole, FieldsServer, PartialRole, PartialServer, Role, Server};
6use crate::{IntoDocumentPath, MongoDb};
7
8use super::AbstractServers;
9
10static COL: &str = "servers";
11
12#[async_trait]
13impl AbstractServers for MongoDb {
14 async fn insert_server(&self, server: &Server) -> Result<()> {
16 query!(self, insert_one, COL, &server).map(|_| ())
17 }
18
19 async fn fetch_server(&self, id: &str) -> Result<Server> {
21 query!(self, find_one_by_id, COL, id)?.ok_or_else(|| create_error!(NotFound))
22 }
23
24 async fn fetch_servers<'a>(&self, ids: &'a [String]) -> Result<Vec<Server>> {
26 Ok(self
27 .col::<Server>(COL)
28 .find(doc! {
29 "_id": {
30 "$in": ids
31 }
32 })
33 .await
34 .map_err(|_| create_database_error!("find", "servers"))?
35 .filter_map(|s| async {
36 if cfg!(debug_assertions) {
37 Some(s.unwrap())
38 } else {
39 s.ok()
40 }
41 })
42 .collect()
43 .await)
44 }
45
46 async fn update_server(
48 &self,
49 id: &str,
50 partial: &PartialServer,
51 remove: Vec<FieldsServer>,
52 ) -> Result<()> {
53 query!(
54 self,
55 update_one_by_id,
56 COL,
57 id,
58 partial,
59 remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
60 None
61 )
62 .map(|_| ())
63 }
64
65 async fn delete_server(&self, id: &str) -> Result<()> {
67 self.delete_associated_server_objects(id).await?;
68 query!(self, delete_one_by_id, COL, id).map(|_| ())
69 }
70
71 async fn insert_role(&self, server_id: &str, role_id: &str, role: &Role) -> Result<()> {
73 self.col::<Document>(COL)
74 .update_one(
75 doc! {
76 "_id": server_id
77 },
78 doc! {
79 "$set": {
80 "roles.".to_owned() + role_id: to_document(role)
81 .map_err(|_| create_database_error!("to_document", "role"))?
82 }
83 },
84 )
85 .await
86 .map(|_| ())
87 .map_err(|_| create_database_error!("update_one", "server"))
88 }
89
90 async fn update_role(
92 &self,
93 server_id: &str,
94 role_id: &str,
95 partial: &PartialRole,
96 remove: Vec<FieldsRole>,
97 ) -> Result<()> {
98 query!(
99 self,
100 update_one_by_id,
101 COL,
102 server_id,
103 partial,
104 remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
105 "roles.".to_owned() + role_id + "."
106 )
107 .map(|_| ())
108 }
109
110 async fn delete_role(&self, server_id: &str, role_id: &str) -> Result<()> {
114 self.col::<Document>("server_members")
115 .update_many(
116 doc! {
117 "_id.server": server_id
118 },
119 doc! {
120 "$pull": {
121 "roles": &role_id
122 }
123 },
124 )
125 .await
126 .map_err(|_| create_database_error!("update_many", "server_members"))?;
127
128 self.col::<Document>("channels")
129 .update_one(
130 doc! {
131 "server": server_id
132 },
133 doc! {
134 "$unset": {
135 "role_permissions.".to_owned() + role_id: 1_i32
136 }
137 },
138 )
139 .await
140 .map_err(|_| create_database_error!("update_one", "channels"))?;
141
142 self.col::<Document>("servers")
143 .update_one(
144 doc! {
145 "_id": server_id
146 },
147 doc! {
148 "$unset": {
149 "roles.".to_owned() + role_id: 1_i32
150 }
151 },
152 )
153 .await
154 .map(|_| ())
155 .map_err(|_| create_database_error!("update_one", "servers"))
156 }
157}
158
159impl IntoDocumentPath for FieldsServer {
160 fn as_path(&self) -> Option<&'static str> {
161 Some(match self {
162 FieldsServer::Banner => "banner",
163 FieldsServer::Categories => "categories",
164 FieldsServer::Description => "description",
165 FieldsServer::Icon => "icon",
166 FieldsServer::SystemMessages => "system_messages",
167 })
168 }
169}
170
171impl IntoDocumentPath for FieldsRole {
172 fn as_path(&self) -> Option<&'static str> {
173 Some(match self {
174 FieldsRole::Colour => "colour",
175 })
176 }
177}
178
179impl MongoDb {
180 pub async fn delete_associated_server_objects(&self, server_id: &str) -> Result<()> {
181 let channels: Vec<String> = self
183 .col::<Document>("channels")
184 .find(doc! {
185 "server": server_id
186 })
187 .await
188 .map_err(|_| create_database_error!("find", "channels"))?
189 .filter_map(|s| async {
190 s.map(|d| d.get_str("_id").map(|s| s.to_string()).ok())
191 .ok()
192 .flatten()
193 })
194 .collect()
195 .await;
196
197 self.delete_bulk_messages(doc! {
199 "channel": {
200 "$in": &channels
201 }
202 })
203 .await?;
204
205 self.col::<Document>("emojis")
207 .update_many(
208 doc! {
209 "parent.id": &server_id
210 },
211 doc! {
212 "$set": {
213 "parent": {
214 "type": "Detached"
215 }
216 }
217 },
218 )
219 .await
220 .map_err(|_| create_database_error!("update_many", "emojis"))?;
221
222 self.col::<Document>("channels")
224 .delete_many(doc! {
225 "server": &server_id
226 })
227 .await
228 .map_err(|_| create_database_error!("delete_many", "channels"))?;
229
230 self.delete_associated_channel_objects(Bson::Document(doc! { "$in": &channels }))
232 .await?;
233
234 for with in &["server_members", "server_bans"] {
236 self.col::<Document>(with)
237 .delete_many(doc! {
238 "_id.server": &server_id
239 })
240 .await
241 .map_err(|_| create_database_error!("delete_many", with))?;
242 }
243
244 self.delete_many_attachments(doc! {
246 "used_for.id": &server_id
247 })
248 .await?;
249
250 Ok(())
251 }
252}