forked from jmug/stoatchat
Events: Distribute user updates to servers.
Fix: Deleting a server now correctly deletes all associated objects.
This commit is contained in:
@@ -4,6 +4,7 @@ use crate::database::*;
|
||||
use crate::notifications::events::ClientboundNotification;
|
||||
use crate::util::result::{Error, Result};
|
||||
use futures::StreamExt;
|
||||
use mongodb::bson::Bson;
|
||||
use mongodb::{
|
||||
bson::{doc, to_document, Document},
|
||||
options::FindOptions,
|
||||
@@ -150,11 +151,7 @@ impl Channel {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete(&self) -> Result<()> {
|
||||
let id = self.id();
|
||||
let messages = get_collection("messages");
|
||||
|
||||
// Delete any invites.
|
||||
pub async fn delete_associated_objects(id: Bson) -> Result<()> {
|
||||
get_collection("channel_invites")
|
||||
.delete_many(
|
||||
doc! {
|
||||
@@ -163,87 +160,103 @@ impl Channel {
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "channel_invites",
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn delete_messages(id: Bson) -> Result<()> {
|
||||
let messages = get_collection("messages");
|
||||
|
||||
// Delete any unreads.
|
||||
get_collection("channel_unreads")
|
||||
.delete_many(
|
||||
doc! {
|
||||
"_id.channel": &id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "channel_unreads",
|
||||
})?;
|
||||
|
||||
// Check if there are any attachments we need to delete.
|
||||
let message_ids = messages
|
||||
.find(
|
||||
doc! {
|
||||
"channel": &id,
|
||||
"attachment": {
|
||||
"$exists": 1
|
||||
}
|
||||
},
|
||||
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "fetch_many",
|
||||
with: "messages",
|
||||
})?
|
||||
.filter_map(async move |s| s.ok())
|
||||
.collect::<Vec<Document>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
// If we found any, mark them as deleted.
|
||||
if message_ids.len() > 0 {
|
||||
get_collection("attachments")
|
||||
.update_many(
|
||||
doc! {
|
||||
"message_id": {
|
||||
"$in": message_ids
|
||||
}
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"deleted": true
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "update_many",
|
||||
with: "attachments",
|
||||
})?;
|
||||
}
|
||||
|
||||
// And then delete said messages.
|
||||
messages
|
||||
.delete_many(
|
||||
doc! {
|
||||
"channel": id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "messages",
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn delete(&self) -> Result<()> {
|
||||
let id = self.id();
|
||||
|
||||
// Delete any invites.
|
||||
Channel::delete_associated_objects(Bson::String(id.to_string())).await?;
|
||||
|
||||
// Delete messages.
|
||||
match &self {
|
||||
Channel::VoiceChannel { .. } => {},
|
||||
_ => {
|
||||
// Delete any unreads.
|
||||
get_collection("channel_unreads")
|
||||
.delete_many(
|
||||
doc! {
|
||||
"_id.channel": id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "channel_unreads",
|
||||
})?;
|
||||
|
||||
// Check if there are any attachments we need to delete.
|
||||
let message_ids = messages
|
||||
.find(
|
||||
doc! {
|
||||
"channel": id,
|
||||
"attachment": {
|
||||
"$exists": 1
|
||||
}
|
||||
},
|
||||
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "fetch_many",
|
||||
with: "messages",
|
||||
})?
|
||||
.filter_map(async move |s| s.ok())
|
||||
.collect::<Vec<Document>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
|
||||
.collect::<Vec<String>>();
|
||||
|
||||
// If we found any, mark them as deleted.
|
||||
if message_ids.len() > 0 {
|
||||
get_collection("attachments")
|
||||
.update_many(
|
||||
doc! {
|
||||
"message_id": {
|
||||
"$in": message_ids
|
||||
}
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"deleted": true
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "update_many",
|
||||
with: "attachments",
|
||||
})?;
|
||||
}
|
||||
|
||||
// And then delete said messages.
|
||||
messages
|
||||
.delete_many(
|
||||
doc! {
|
||||
"channel": id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "messages",
|
||||
})?;
|
||||
Channel::delete_messages(Bson::String(id.to_string())).await?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ use crate::database::*;
|
||||
use crate::notifications::events::ClientboundNotification;
|
||||
use crate::util::result::{Error, Result};
|
||||
use futures::StreamExt;
|
||||
use mongodb::bson::doc;
|
||||
use mongodb::bson::{Bson, doc};
|
||||
use mongodb::bson::from_document;
|
||||
use mongodb::bson::to_document;
|
||||
use mongodb::bson::Document;
|
||||
use mongodb::options::FindOptions;
|
||||
use rocket_contrib::json::JsonValue;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -133,58 +132,11 @@ impl Server {
|
||||
}
|
||||
|
||||
pub async fn delete(&self) -> Result<()> {
|
||||
let messages = get_collection("messages");
|
||||
|
||||
// Check if there are any attachments we need to delete.
|
||||
// ! FIXME: make this generic and merge with channel delete
|
||||
// ! e.g. delete_channel(filter: doc!)
|
||||
let message_ids = messages
|
||||
.find(
|
||||
doc! {
|
||||
"server": &self.id,
|
||||
"attachment": {
|
||||
"$exists": 1
|
||||
}
|
||||
},
|
||||
FindOptions::builder().projection(doc! { "_id": 1 }).build(),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "fetch_many",
|
||||
with: "messages",
|
||||
})?
|
||||
.filter_map(async move |s| s.ok())
|
||||
.collect::<Vec<Document>>()
|
||||
.await
|
||||
.into_iter()
|
||||
.filter_map(|x| x.get_str("_id").ok().map(|x| x.to_string()))
|
||||
.collect::<Vec<String>>();
|
||||
Channel::delete_messages(Bson::Document(doc! { "$in": &self.channels })).await?;
|
||||
|
||||
// If we found any, mark them as deleted.
|
||||
if message_ids.len() > 0 {
|
||||
get_collection("attachments")
|
||||
.update_many(
|
||||
doc! {
|
||||
"message_id": {
|
||||
"$in": message_ids
|
||||
}
|
||||
},
|
||||
doc! {
|
||||
"$set": {
|
||||
"deleted": true
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "update_many",
|
||||
with: "attachments",
|
||||
})?;
|
||||
}
|
||||
|
||||
// And then delete said messages.
|
||||
messages
|
||||
// Delete all channels.
|
||||
get_collection("channels")
|
||||
.delete_many(
|
||||
doc! {
|
||||
"server": &self.id
|
||||
@@ -194,27 +146,13 @@ impl Server {
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with: "messages",
|
||||
with: "channels",
|
||||
})?;
|
||||
|
||||
// Delete all channels, members, bans and invites.
|
||||
for with in &["channels", "channel_invites"] {
|
||||
get_collection(with)
|
||||
.delete_many(
|
||||
doc! {
|
||||
"server": &self.id
|
||||
},
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|_| Error::DatabaseError {
|
||||
operation: "delete_many",
|
||||
with,
|
||||
})?;
|
||||
}
|
||||
|
||||
// ! FIXME: delete any unreads
|
||||
// Delete any associated objects, e.g. unreads and invites.
|
||||
Channel::delete_associated_objects(Bson::Document(doc! { "$in": &self.channels })).await?;
|
||||
|
||||
// Delete members and bans.
|
||||
for with in &["server_members", "server_bans"] {
|
||||
get_collection(with)
|
||||
.delete_many(
|
||||
@@ -230,6 +168,16 @@ impl Server {
|
||||
})?;
|
||||
}
|
||||
|
||||
// Delete server icon / banner.
|
||||
if let Some(attachment) = &self.icon {
|
||||
attachment.delete().await?;
|
||||
}
|
||||
|
||||
if let Some(attachment) = &self.banner {
|
||||
attachment.delete().await?;
|
||||
}
|
||||
|
||||
// Delete the server
|
||||
get_collection("servers")
|
||||
.delete_one(
|
||||
doc! {
|
||||
@@ -248,14 +196,6 @@ impl Server {
|
||||
}
|
||||
.publish(self.id.clone());
|
||||
|
||||
if let Some(attachment) = &self.icon {
|
||||
attachment.delete().await?;
|
||||
}
|
||||
|
||||
if let Some(attachment) = &self.banner {
|
||||
attachment.delete().await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -229,11 +229,11 @@ impl User {
|
||||
}
|
||||
|
||||
/// Utility function to get all the server IDs the user is in.
|
||||
pub async fn fetch_server_ids(&self) -> Result<Vec<String>> {
|
||||
pub async fn fetch_server_ids(id: &str) -> Result<Vec<String>> {
|
||||
Ok(get_collection("server_members")
|
||||
.find(
|
||||
doc! {
|
||||
"_id.user": &self.id
|
||||
"_id.user": id
|
||||
},
|
||||
None,
|
||||
)
|
||||
@@ -256,11 +256,11 @@ impl User {
|
||||
}
|
||||
|
||||
/// Utility function to fetch unread objects for user.
|
||||
pub async fn fetch_unreads(&self) -> Result<Vec<Document>> {
|
||||
pub async fn fetch_unreads(id: &str) -> Result<Vec<Document>> {
|
||||
Ok(get_collection("channel_unreads")
|
||||
.find(
|
||||
doc! {
|
||||
"_id.user": &self.id
|
||||
"_id.user": id
|
||||
},
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -70,7 +70,7 @@ impl<'a> PermissionCalculator<'a> {
|
||||
}
|
||||
|
||||
let check_server_overlap = async || {
|
||||
let server_ids = self.perspective.fetch_server_ids().await?;
|
||||
let server_ids = User::fetch_server_ids(&self.perspective.id).await?;
|
||||
|
||||
Ok(
|
||||
get_collection("server_members")
|
||||
|
||||
Reference in New Issue
Block a user