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 fetch_owned_servers(&self, user_id: &str) -> Result<Vec<Server>> {
47 query!(
48 self,
49 find,
50 COL,
51 doc! {
52 "owner": user_id
53 }
54 )
55 }
56
57 async fn update_server(
59 &self,
60 id: &str,
61 partial: &PartialServer,
62 remove: Vec<FieldsServer>,
63 ) -> Result<()> {
64 query!(
65 self,
66 update_one_by_id,
67 COL,
68 id,
69 partial,
70 remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
71 None
72 )
73 .map(|_| ())
74 }
75
76 async fn delete_server(&self, id: &str) -> Result<()> {
78 self.delete_associated_server_objects(id).await?;
79 query!(self, delete_one_by_id, COL, id).map(|_| ())
80 }
81
82 async fn insert_role(&self, server_id: &str, role: &Role) -> Result<()> {
84 self.col::<Document>(COL)
85 .update_one(
86 doc! {
87 "_id": server_id
88 },
89 doc! {
90 "$set": {
91 "roles.".to_owned() + role.id.as_str(): to_document(role)
92 .map_err(|_| create_database_error!("to_document", "role"))?
93 }
94 },
95 )
96 .await
97 .map(|_| ())
98 .map_err(|_| create_database_error!("update_one", "server"))
99 }
100
101 async fn update_role(
103 &self,
104 server_id: &str,
105 role_id: &str,
106 partial: &PartialRole,
107 remove: Vec<FieldsRole>,
108 ) -> Result<()> {
109 query!(
110 self,
111 update_one_by_id,
112 COL,
113 server_id,
114 partial,
115 remove.iter().map(|x| x as &dyn IntoDocumentPath).collect(),
116 "roles.".to_owned() + role_id + "."
117 )
118 .map(|_| ())
119 }
120
121 async fn delete_role(&self, server_id: &str, role_id: &str) -> Result<()> {
125 self.col::<Document>("server_members")
126 .update_many(
127 doc! {
128 "_id.server": server_id
129 },
130 doc! {
131 "$pull": {
132 "roles": &role_id
133 }
134 },
135 )
136 .await
137 .map_err(|_| create_database_error!("update_many", "server_members"))?;
138
139 self.col::<Document>("channels")
140 .update_one(
141 doc! {
142 "server": server_id
143 },
144 doc! {
145 "$unset": {
146 "role_permissions.".to_owned() + role_id: 1_i32
147 }
148 },
149 )
150 .await
151 .map_err(|_| create_database_error!("update_one", "channels"))?;
152
153 self.col::<Document>("servers")
154 .update_one(
155 doc! {
156 "_id": server_id
157 },
158 doc! {
159 "$unset": {
160 "roles.".to_owned() + role_id: 1_i32
161 }
162 },
163 )
164 .await
165 .map(|_| ())
166 .map_err(|_| create_database_error!("update_one", "servers"))
167 }
168}
169
170impl IntoDocumentPath for FieldsServer {
171 fn as_path(&self) -> Option<&'static str> {
172 Some(match self {
173 FieldsServer::Banner => "banner",
174 FieldsServer::Categories => "categories",
175 FieldsServer::Description => "description",
176 FieldsServer::Icon => "icon",
177 FieldsServer::SystemMessages => "system_messages",
178 })
179 }
180}
181
182impl IntoDocumentPath for FieldsRole {
183 fn as_path(&self) -> Option<&'static str> {
184 Some(match self {
185 FieldsRole::Colour => "colour",
186 FieldsRole::Icon => "icon",
187 })
188 }
189}
190
191impl MongoDb {
192 pub async fn delete_associated_server_objects(&self, server_id: &str) -> Result<()> {
193 let channels: Vec<String> = self
195 .col::<Document>("channels")
196 .find(doc! {
197 "server": server_id
198 })
199 .await
200 .map_err(|_| create_database_error!("find", "channels"))?
201 .filter_map(|s| async {
202 s.map(|d| d.get_str("_id").map(|s| s.to_string()).ok())
203 .ok()
204 .flatten()
205 })
206 .collect()
207 .await;
208
209 self.delete_bulk_messages(doc! {
211 "channel": {
212 "$in": &channels
213 }
214 })
215 .await?;
216
217 self.col::<Document>("emojis")
219 .update_many(
220 doc! {
221 "parent.id": &server_id
222 },
223 doc! {
224 "$set": {
225 "parent": {
226 "type": "Detached"
227 }
228 }
229 },
230 )
231 .await
232 .map_err(|_| create_database_error!("update_many", "emojis"))?;
233
234 self.col::<Document>("channels")
236 .delete_many(doc! {
237 "server": &server_id
238 })
239 .await
240 .map_err(|_| create_database_error!("delete_many", "channels"))?;
241
242 self.delete_associated_channel_objects(Bson::Document(doc! { "$in": &channels }))
244 .await?;
245
246 for with in &["server_members", "server_bans"] {
248 self.col::<Document>(with)
249 .delete_many(doc! {
250 "_id.server": &server_id
251 })
252 .await
253 .map_err(|_| create_database_error!("delete_many", with))?;
254 }
255
256 self.delete_many_attachments(doc! {
258 "used_for.id": &server_id
259 })
260 .await?;
261
262 self.col::<Document>("audit_logs")
263 .delete_many(doc! {
264 "server": &server_id
265 })
266 .await
267 .map_err(|_| create_database_error!("delete_many", "audit_logs"))?;
268
269 Ok(())
270 }
271}