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: &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.as_str(): 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 FieldsRole::Icon => "icon",
176 })
177 }
178}
179
180impl MongoDb {
181 pub async fn delete_associated_server_objects(&self, server_id: &str) -> Result<()> {
182 let channels: Vec<String> = self
184 .col::<Document>("channels")
185 .find(doc! {
186 "server": server_id
187 })
188 .await
189 .map_err(|_| create_database_error!("find", "channels"))?
190 .filter_map(|s| async {
191 s.map(|d| d.get_str("_id").map(|s| s.to_string()).ok())
192 .ok()
193 .flatten()
194 })
195 .collect()
196 .await;
197
198 self.delete_bulk_messages(doc! {
200 "channel": {
201 "$in": &channels
202 }
203 })
204 .await?;
205
206 self.col::<Document>("emojis")
208 .update_many(
209 doc! {
210 "parent.id": &server_id
211 },
212 doc! {
213 "$set": {
214 "parent": {
215 "type": "Detached"
216 }
217 }
218 },
219 )
220 .await
221 .map_err(|_| create_database_error!("update_many", "emojis"))?;
222
223 self.col::<Document>("channels")
225 .delete_many(doc! {
226 "server": &server_id
227 })
228 .await
229 .map_err(|_| create_database_error!("delete_many", "channels"))?;
230
231 self.delete_associated_channel_objects(Bson::Document(doc! { "$in": &channels }))
233 .await?;
234
235 for with in &["server_members", "server_bans"] {
237 self.col::<Document>(with)
238 .delete_many(doc! {
239 "_id.server": &server_id
240 })
241 .await
242 .map_err(|_| create_database_error!("delete_many", with))?;
243 }
244
245 self.delete_many_attachments(doc! {
247 "used_for.id": &server_id
248 })
249 .await?;
250
251 Ok(())
252 }
253}