mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-08-31 02:22:29 +00:00
fix: deleting newest message renders channels unackable until a new message is posted (#899)
fix: deleting messages renders channels unackable until a new message is posted Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
use crate::{Channel, FieldsChannel, PartialChannel, revolt_result::Result, util::ChunkedDatabaseGenerator};
|
||||
use crate::{
|
||||
revolt_result::Result, util::ChunkedDatabaseGenerator, Channel, FieldsChannel, PartialChannel,
|
||||
};
|
||||
use revolt_permissions::OverrideField;
|
||||
|
||||
#[cfg(feature = "mongodb")]
|
||||
@@ -20,7 +22,10 @@ pub trait AbstractChannels: Sync + Send {
|
||||
async fn find_direct_messages(&self, user_id: &str) -> Result<Vec<Channel>>;
|
||||
|
||||
// Fetch all group dms for a user
|
||||
async fn find_group_message_channels(&self, user_id: &str) -> Result<ChunkedDatabaseGenerator<Channel>>;
|
||||
async fn find_group_message_channels(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> Result<ChunkedDatabaseGenerator<Channel>>;
|
||||
|
||||
// Fetch saved messages channel
|
||||
async fn find_saved_messages_channel(&self, user_id: &str) -> Result<Channel>;
|
||||
@@ -55,4 +60,16 @@ pub trait AbstractChannels: Sync + Send {
|
||||
|
||||
// Delete a channel
|
||||
async fn delete_channel(&self, channel_id: &Channel) -> Result<()>;
|
||||
|
||||
// Fetch the last message in the channel
|
||||
// Used to update the last_message_id when the current last_message_id is deleted.
|
||||
async fn fetch_last_message(&self, channel_id: &str) -> Result<Option<String>>;
|
||||
|
||||
// Update the last_message_id on the channel
|
||||
// Setting this to None will remove the last_message_id
|
||||
async fn update_last_messsage_id(
|
||||
&self,
|
||||
channel_id: &str,
|
||||
message_id: Option<&str>,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use super::AbstractChannels;
|
||||
use crate::{AbstractServers, Channel, FieldsChannel, IntoDocumentPath, MongoDb, PartialChannel, util::ChunkedDatabaseGenerator};
|
||||
use crate::{
|
||||
util::ChunkedDatabaseGenerator, AbstractServers, Channel, FieldsChannel, IntoDocumentPath,
|
||||
MongoDb, PartialChannel,
|
||||
};
|
||||
use bson::{Bson, Document};
|
||||
use futures::StreamExt;
|
||||
use mongodb::options::ReadConcern;
|
||||
@@ -71,7 +74,10 @@ impl AbstractChannels for MongoDb {
|
||||
}
|
||||
|
||||
// Fetch all group dms for a user
|
||||
async fn find_group_message_channels(&self, user_id: &str) -> Result<ChunkedDatabaseGenerator<Channel>> {
|
||||
async fn find_group_message_channels(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> Result<ChunkedDatabaseGenerator<Channel>> {
|
||||
let mut session = self
|
||||
.start_session()
|
||||
.await
|
||||
@@ -83,7 +89,8 @@ impl AbstractChannels for MongoDb {
|
||||
.await
|
||||
.map_err(|_| create_database_error!("start_transaction", COL))?;
|
||||
|
||||
let cursor = self.col(COL)
|
||||
let cursor = self
|
||||
.col(COL)
|
||||
.find(doc! {
|
||||
"channel_type": "Group",
|
||||
"recipients": user_id
|
||||
@@ -304,6 +311,42 @@ impl AbstractChannels for MongoDb {
|
||||
// Delete the channel itself
|
||||
query!(self, delete_one_by_id, COL, channel.id()).map(|_| ())
|
||||
}
|
||||
|
||||
async fn fetch_last_message(&self, channel_id: &str) -> Result<Option<String>> {
|
||||
self.col::<Document>("messages")
|
||||
.find_one(doc! {"channel": channel_id})
|
||||
.sort(doc! {"_id": -1})
|
||||
.projection(doc! {"_id": 1})
|
||||
.await
|
||||
.map(|doc| doc.map(|d| d.get("_id").expect("Missing _id").to_string()))
|
||||
.map_err(|_| create_database_error!("find_one", "messages"))
|
||||
}
|
||||
|
||||
async fn update_last_messsage_id(
|
||||
&self,
|
||||
channel_id: &str,
|
||||
message_id: Option<&str>,
|
||||
) -> Result<()> {
|
||||
if let Some(message_id) = message_id {
|
||||
self.col::<Document>(COL)
|
||||
.update_one(
|
||||
doc! {"_id": channel_id},
|
||||
doc! {"$set": {"last_message_id": message_id}},
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", "channels"))
|
||||
} else {
|
||||
self.col::<Document>(COL)
|
||||
.update_one(
|
||||
doc! {"_id": channel_id},
|
||||
doc! {"$unset": {"last_message_id": ""}},
|
||||
)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|_| create_database_error!("update_one", "channels"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MongoDb {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use super::AbstractChannels;
|
||||
use crate::ReferenceDb;
|
||||
use crate::util::ChunkedDatabaseGenerator;
|
||||
use crate::ReferenceDb;
|
||||
use crate::{Channel, FieldsChannel, PartialChannel};
|
||||
use revolt_permissions::OverrideField;
|
||||
use revolt_result::Result;
|
||||
@@ -53,7 +53,10 @@ impl AbstractChannels for ReferenceDb {
|
||||
}
|
||||
|
||||
// Fetch all group dms for a user
|
||||
async fn find_group_message_channels(&self, user_id: &str) -> Result<ChunkedDatabaseGenerator<Channel>> {
|
||||
async fn find_group_message_channels(
|
||||
&self,
|
||||
user_id: &str,
|
||||
) -> Result<ChunkedDatabaseGenerator<Channel>> {
|
||||
let channels = self.channels.lock().await;
|
||||
let groups = channels
|
||||
.values()
|
||||
@@ -168,7 +171,7 @@ impl AbstractChannels for ReferenceDb {
|
||||
if let Some(Channel::Group { recipients, .. }) = channels.get_mut(&channel_id) {
|
||||
recipients.retain(|recipient| recipient != user_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -182,4 +185,41 @@ impl AbstractChannels for ReferenceDb {
|
||||
Err(create_error!(NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
async fn fetch_last_message(&self, channel_id: &str) -> Result<Option<String>> {
|
||||
let messages = self.messages.lock().await;
|
||||
let mut channel_messages: Vec<&crate::Message> = messages
|
||||
.iter()
|
||||
.filter(|(_, msg)| msg.channel == channel_id)
|
||||
.map(|(_, msg)| msg)
|
||||
.collect();
|
||||
|
||||
channel_messages.sort_unstable_by_key(|msg| &msg.id);
|
||||
Ok(channel_messages.last().map(|msg| msg.id.clone()).or(None))
|
||||
}
|
||||
|
||||
async fn update_last_messsage_id(
|
||||
&self,
|
||||
channel_id: &str,
|
||||
message_id: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let mut channels = self.channels.lock().await;
|
||||
let channel = channels
|
||||
.get_mut(channel_id)
|
||||
.ok_or_else(|| create_error!(NotFound))?;
|
||||
|
||||
match channel {
|
||||
Channel::DirectMessage {
|
||||
last_message_id, ..
|
||||
}
|
||||
| Channel::Group {
|
||||
last_message_id, ..
|
||||
}
|
||||
| Channel::TextChannel {
|
||||
last_message_id, ..
|
||||
} => *last_message_id = message_id.map(|id| id.to_string()),
|
||||
_ => (),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1012,6 +1012,42 @@ impl Message {
|
||||
|
||||
db.delete_message(&self.id).await?;
|
||||
|
||||
if let Ok(mut channel) = db.fetch_channel(&self.channel).await {
|
||||
match &channel {
|
||||
Channel::DirectMessage {
|
||||
last_message_id, ..
|
||||
}
|
||||
| Channel::Group {
|
||||
last_message_id, ..
|
||||
}
|
||||
| Channel::TextChannel {
|
||||
last_message_id, ..
|
||||
} => {
|
||||
if last_message_id.is_some() && last_message_id.as_ref().unwrap() == &self.id {
|
||||
let new_last_message_id =
|
||||
db.fetch_last_message(channel.id()).await.unwrap();
|
||||
|
||||
db.update_last_messsage_id(channel.id(), new_last_message_id.as_deref())
|
||||
.await?;
|
||||
|
||||
if new_last_message_id.is_some() {
|
||||
EventV1::ChannelUpdate {
|
||||
id: channel.id().to_string(),
|
||||
data: revolt_models::v0::PartialChannel {
|
||||
last_message_id: new_last_message_id,
|
||||
..Default::default()
|
||||
},
|
||||
clear: vec![],
|
||||
}
|
||||
.p(channel.id().to_string())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
EventV1::MessageDelete {
|
||||
id: self.id.clone(),
|
||||
channel: self.channel.clone(),
|
||||
|
||||
Reference in New Issue
Block a user