mirror of
https://github.com/zed-industries/zed.git
synced 2024-09-19 02:17:35 +03:00
WIP: Add channel DAG related RPC messages, change update message
This commit is contained in:
parent
49fbb27ce9
commit
9e68d4a8ea
@ -323,6 +323,18 @@ impl ChannelStore {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
pub fn move_channel(&mut self, channel_id: ChannelId, from_parent: Option<ChannelId>, to: Option<ChannelId>, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
|
||||
let client = self.client.clone();
|
||||
cx.spawn(|_, _| async move {
|
||||
let _ = client
|
||||
.request(proto::MoveChannel { channel_id, from_parent, to })
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn invite_member(
|
||||
&mut self,
|
||||
channel_id: ChannelId,
|
||||
@ -502,7 +514,7 @@ impl ChannelStore {
|
||||
pub fn remove_channel(&self, channel_id: ChannelId) -> impl Future<Output = Result<()>> {
|
||||
let client = self.client.clone();
|
||||
async move {
|
||||
client.request(proto::RemoveChannel { channel_id }).await?;
|
||||
client.request(proto::DeleteChannel { channel_id }).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -690,17 +702,17 @@ impl ChannelStore {
|
||||
}
|
||||
}
|
||||
|
||||
let channels_changed = !payload.channels.is_empty() || !payload.remove_channels.is_empty();
|
||||
let channels_changed = !payload.channels.is_empty() || !payload.delete_channels.is_empty();
|
||||
if channels_changed {
|
||||
if !payload.remove_channels.is_empty() {
|
||||
if !payload.delete_channels.is_empty() {
|
||||
self.channels_by_id
|
||||
.retain(|channel_id, _| !payload.remove_channels.contains(channel_id));
|
||||
.retain(|channel_id, _| !payload.delete_channels.contains(channel_id));
|
||||
self.channel_participants
|
||||
.retain(|channel_id, _| !payload.remove_channels.contains(channel_id));
|
||||
.retain(|channel_id, _| !payload.delete_channels.contains(channel_id));
|
||||
self.channels_with_admin_privileges
|
||||
.retain(|channel_id| !payload.remove_channels.contains(channel_id));
|
||||
.retain(|channel_id| !payload.delete_channels.contains(channel_id));
|
||||
|
||||
for channel_id in &payload.remove_channels {
|
||||
for channel_id in &payload.delete_channels {
|
||||
let channel_id = *channel_id;
|
||||
if let Some(OpenedModelHandle::Open(buffer)) =
|
||||
self.opened_buffers.remove(&channel_id)
|
||||
|
@ -122,7 +122,7 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
|
||||
update_channels(
|
||||
&channel_store,
|
||||
proto::UpdateChannels {
|
||||
remove_channels: vec![1, 2],
|
||||
delete_channels: vec![1, 2],
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
|
@ -1,5 +1,7 @@
|
||||
use super::*;
|
||||
|
||||
type ChannelDescendants = HashMap<ChannelId, HashSet<ChannelId>>;
|
||||
|
||||
impl Database {
|
||||
#[cfg(test)]
|
||||
pub async fn all_channels(&self) -> Result<Vec<(ChannelId, String)>> {
|
||||
@ -68,7 +70,6 @@ impl Database {
|
||||
],
|
||||
);
|
||||
tx.execute(channel_paths_stmt).await?;
|
||||
|
||||
} else {
|
||||
channel_path::Entity::insert(channel_path::ActiveModel {
|
||||
channel_id: ActiveValue::Set(channel.id),
|
||||
@ -101,7 +102,7 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn remove_channel(
|
||||
pub async fn delete_channel(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
user_id: UserId,
|
||||
@ -159,9 +160,7 @@ impl Database {
|
||||
let channel_paths_stmt = Statement::from_sql_and_values(
|
||||
self.pool.get_database_backend(),
|
||||
sql,
|
||||
[
|
||||
channel_id.to_proto().into(),
|
||||
],
|
||||
[channel_id.to_proto().into()],
|
||||
);
|
||||
tx.execute(channel_paths_stmt).await?;
|
||||
|
||||
@ -335,6 +334,43 @@ impl Database {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_all_channels(
|
||||
&self,
|
||||
parents_by_child_id: ChannelDescendants,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<Channel>> {
|
||||
let mut channels = Vec::with_capacity(parents_by_child_id.len());
|
||||
{
|
||||
let mut rows = channel::Entity::find()
|
||||
.filter(channel::Column::Id.is_in(parents_by_child_id.keys().copied()))
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
while let Some(row) = rows.next().await {
|
||||
let row = row?;
|
||||
|
||||
// As these rows are pulled from the map's keys, this unwrap is safe.
|
||||
let parents = parents_by_child_id.get(&row.id).unwrap();
|
||||
if parents.len() > 0 {
|
||||
for parent in parents {
|
||||
channels.push(Channel {
|
||||
id: row.id,
|
||||
name: row.name.clone(),
|
||||
parent_id: Some(*parent),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
channels.push(Channel {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
parent_id: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(channels)
|
||||
}
|
||||
|
||||
pub async fn get_channels_for_user(&self, user_id: UserId) -> Result<ChannelsForUser> {
|
||||
self.transaction(|tx| async move {
|
||||
let tx = tx;
|
||||
@ -352,40 +388,12 @@ impl Database {
|
||||
.get_channel_descendants(channel_memberships.iter().map(|m| m.channel_id), &*tx)
|
||||
.await?;
|
||||
|
||||
|
||||
let channels_with_admin_privileges = channel_memberships
|
||||
.iter()
|
||||
.filter_map(|membership| membership.admin.then_some(membership.channel_id))
|
||||
.collect();
|
||||
|
||||
let mut channels = Vec::with_capacity(parents_by_child_id.len());
|
||||
{
|
||||
let mut rows = channel::Entity::find()
|
||||
.filter(channel::Column::Id.is_in(parents_by_child_id.keys().copied()))
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
while let Some(row) = rows.next().await {
|
||||
let row = row?;
|
||||
|
||||
// As these rows are pulled from the map's keys, this unwrap is safe.
|
||||
let parents = parents_by_child_id.get(&row.id).unwrap();
|
||||
if parents.len() > 0 {
|
||||
for parent in parents {
|
||||
channels.push(Channel {
|
||||
id: row.id,
|
||||
name: row.name.clone(),
|
||||
parent_id: Some(*parent),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
channels.push(Channel {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
parent_id: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
let channels = self.get_all_channels(parents_by_child_id, &tx).await?;
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
enum QueryUserIdsAndChannelIds {
|
||||
@ -632,7 +640,7 @@ impl Database {
|
||||
&self,
|
||||
channel_ids: impl IntoIterator<Item = ChannelId>,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<HashMap<ChannelId, HashSet<ChannelId>>> {
|
||||
) -> Result<ChannelDescendants> {
|
||||
let mut values = String::new();
|
||||
for id in channel_ids {
|
||||
if !values.is_empty() {
|
||||
@ -659,7 +667,7 @@ impl Database {
|
||||
|
||||
let stmt = Statement::from_string(self.pool.get_database_backend(), sql);
|
||||
|
||||
let mut parents_by_child_id: HashMap<ChannelId, HashSet<ChannelId>> = HashMap::default();
|
||||
let mut parents_by_child_id: ChannelDescendants = HashMap::default();
|
||||
let mut paths = channel_path::Entity::find()
|
||||
.from_raw_sql(stmt)
|
||||
.stream(tx)
|
||||
@ -758,7 +766,7 @@ impl Database {
|
||||
from: ChannelId,
|
||||
to: ChannelId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<()> {
|
||||
) -> Result<ChannelDescendants> {
|
||||
let to_ancestors = self.get_channel_ancestors(to, &*tx).await?;
|
||||
let from_descendants = self.get_channel_descendants([from], &*tx).await?;
|
||||
for ancestor in to_ancestors {
|
||||
@ -767,8 +775,6 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
let sql = r#"
|
||||
INSERT INTO channel_paths
|
||||
(id_path, channel_id)
|
||||
@ -806,8 +812,7 @@ impl Database {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
Ok(from_descendants)
|
||||
}
|
||||
|
||||
async fn remove_channel_from_parent(
|
||||
@ -816,8 +821,6 @@ impl Database {
|
||||
parent: ChannelId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<()> {
|
||||
|
||||
|
||||
let sql = r#"
|
||||
DELETE FROM channel_paths
|
||||
WHERE
|
||||
@ -826,14 +829,10 @@ impl Database {
|
||||
let channel_paths_stmt = Statement::from_sql_and_values(
|
||||
self.pool.get_database_backend(),
|
||||
sql,
|
||||
[
|
||||
parent.to_proto().into(),
|
||||
from.to_proto().into(),
|
||||
],
|
||||
[parent.to_proto().into(), from.to_proto().into()],
|
||||
);
|
||||
tx.execute(channel_paths_stmt).await?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -846,19 +845,22 @@ impl Database {
|
||||
/// - (`None`, `Some(id)`) Link the channel without removing it from any of it's parents
|
||||
/// - (`Some(id)`, `None`) Remove a channel from a given parent, and leave other parents
|
||||
/// - (`Some(id)`, `Some(id)`) Move channel from one parent to another, leaving other parents
|
||||
///
|
||||
/// Returns the channel that was moved + it's sub channels
|
||||
pub async fn move_channel(
|
||||
&self,
|
||||
user: UserId,
|
||||
from: ChannelId,
|
||||
from_parent: Option<ChannelId>,
|
||||
to: Option<ChannelId>,
|
||||
) -> Result<()> {
|
||||
) -> Result<Vec<Channel>> {
|
||||
self.transaction(|tx| async move {
|
||||
// Note that even with these maxed permissions, this linking operation
|
||||
// is still insecure because you can't remove someone's permissions to a
|
||||
// channel if they've linked the channel to one where they're an admin.
|
||||
self.check_user_is_channel_admin(from, user, &*tx).await?;
|
||||
|
||||
let mut channel_descendants = None;
|
||||
if let Some(from_parent) = from_parent {
|
||||
self.check_user_is_channel_admin(from_parent, user, &*tx)
|
||||
.await?;
|
||||
@ -870,10 +872,30 @@ impl Database {
|
||||
if let Some(to) = to {
|
||||
self.check_user_is_channel_admin(to, user, &*tx).await?;
|
||||
|
||||
self.link_channel(from, to, &*tx).await?;
|
||||
channel_descendants = Some(self.link_channel(from, to, &*tx).await?);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
let mut channel_descendants = match channel_descendants {
|
||||
Some(channel_descendants) => channel_descendants,
|
||||
None => self.get_channel_descendants([from], &*tx).await?,
|
||||
};
|
||||
|
||||
// Repair the parent ID of the channel in case it was from a cached call
|
||||
if let Some(channel) = channel_descendants.get_mut(&from) {
|
||||
if let Some(from_parent) = from_parent {
|
||||
channel.remove(&from_parent);
|
||||
}
|
||||
if let Some(to) = to {
|
||||
channel.insert(to);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let channels = self
|
||||
.get_all_channels(channel_descendants, &*tx)
|
||||
.await?;
|
||||
|
||||
Ok(channels)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
@ -181,11 +181,11 @@ async fn test_channels(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// Remove a single channel
|
||||
db.remove_channel(crdb_id, a_id).await.unwrap();
|
||||
db.delete_channel(crdb_id, a_id).await.unwrap();
|
||||
assert!(db.get_channel(crdb_id, a_id).await.unwrap().is_none());
|
||||
|
||||
// Remove a channel tree
|
||||
let (mut channel_ids, user_ids) = db.remove_channel(rust_id, a_id).await.unwrap();
|
||||
let (mut channel_ids, user_ids) = db.delete_channel(rust_id, a_id).await.unwrap();
|
||||
channel_ids.sort();
|
||||
assert_eq!(channel_ids, &[rust_id, cargo_id, cargo_ra_id]);
|
||||
assert_eq!(user_ids, &[a_id]);
|
||||
@ -647,7 +647,8 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// Make a link
|
||||
db.move_channel(a_id, livestreaming_dag_sub_id, None, Some(livestreaming_id))
|
||||
let channels = db
|
||||
.move_channel(a_id, livestreaming_dag_sub_id, None, Some(livestreaming_id))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -655,6 +656,24 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
// /- gpui2 /---------------------\
|
||||
// zed - crdb - livestreaming - livestreaming_dag - livestreaming_dag_sub_id
|
||||
// \--------/
|
||||
|
||||
// make sure we're getting the new link
|
||||
pretty_assertions::assert_eq!(
|
||||
channels,
|
||||
vec![
|
||||
Channel {
|
||||
id: livestreaming_dag_sub_id,
|
||||
name: "livestreaming_dag_sub".to_string(),
|
||||
parent_id: Some(livestreaming_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_dag_sub_id,
|
||||
name: "livestreaming_dag_sub".to_string(),
|
||||
parent_id: Some(livestreaming_dag_id),
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
let result = db.get_channels_for_user(a_id).await.unwrap();
|
||||
pretty_assertions::assert_eq!(
|
||||
result.channels,
|
||||
@ -703,7 +722,7 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// Make another link
|
||||
db.move_channel(a_id, livestreaming_id, None, Some(gpui2_id))
|
||||
let channels = db.move_channel(a_id, livestreaming_id, None, Some(gpui2_id))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -711,6 +730,40 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
// /- gpui2 -\ /---------------------\
|
||||
// zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub_id
|
||||
// \---------/
|
||||
|
||||
// Make sure that we're correctly getting the full sub-dag
|
||||
pretty_assertions::assert_eq!(channels,
|
||||
vec![Channel {
|
||||
id: livestreaming_id,
|
||||
name: "livestreaming".to_string(),
|
||||
parent_id: Some(gpui2_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_id,
|
||||
name: "livestreaming".to_string(),
|
||||
parent_id: Some(zed_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_id,
|
||||
name: "livestreaming".to_string(),
|
||||
parent_id: Some(crdb_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_dag_id,
|
||||
name: "livestreaming_dag".to_string(),
|
||||
parent_id: Some(livestreaming_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_dag_sub_id,
|
||||
name: "livestreaming_dag_sub".to_string(),
|
||||
parent_id: Some(livestreaming_id),
|
||||
},
|
||||
Channel {
|
||||
id: livestreaming_dag_sub_id,
|
||||
name: "livestreaming_dag_sub".to_string(),
|
||||
parent_id: Some(livestreaming_dag_id),
|
||||
}]);
|
||||
|
||||
let result = db.get_channels_for_user(a_id).await.unwrap();
|
||||
pretty_assertions::assert_eq!(
|
||||
result.channels,
|
||||
@ -764,7 +817,7 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// Remove that inner link
|
||||
db.move_channel(a_id, livestreaming_dag_sub_id, Some(livestreaming_id), None)
|
||||
let channels = db.move_channel(a_id, livestreaming_dag_sub_id, Some(livestreaming_id), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -772,6 +825,20 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
// /- gpui2 -\
|
||||
// zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub
|
||||
// \---------/
|
||||
|
||||
// Make sure the recently removed link isn't returned
|
||||
pretty_assertions::assert_eq!(
|
||||
channels,
|
||||
vec![
|
||||
Channel {
|
||||
id: livestreaming_dag_sub_id,
|
||||
name: "livestreaming_dag_sub".to_string(),
|
||||
parent_id: Some(livestreaming_dag_id),
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
let result = db.get_channels_for_user(a_id).await.unwrap();
|
||||
pretty_assertions::assert_eq!(
|
||||
result.channels,
|
||||
@ -824,24 +891,10 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
// DAG is now:
|
||||
// /- gpui2
|
||||
// zed - crdb -- livestreaming - livestreaming_dag - livestreaming_dag_sub
|
||||
// \---------/
|
||||
//
|
||||
// zed/gpui2
|
||||
// zed/crdb
|
||||
// zed/crdb/livestreaming
|
||||
//
|
||||
// zed/crdb/livestreaming
|
||||
// zed/crdb/livestreaming/livestreaming_dag
|
||||
// zed/crdb/livestreaming/livestreaming_dag/livestreaming_dag_sub
|
||||
|
||||
// zed/livestreaming
|
||||
// zed/livestreaming/livestreaming_dag
|
||||
// zed/livestreaming/livestreaming_dag/livestreaming_dag_sub
|
||||
//
|
||||
let result = db.get_channels_for_user(a_id).await.unwrap();
|
||||
pretty_assertions::assert_eq!(
|
||||
result.channels,
|
||||
@ -936,7 +989,7 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// Deleting a channel should not delete children that still have other parents
|
||||
db.remove_channel(gpui2_id, a_id).await.unwrap();
|
||||
db.delete_channel(gpui2_id, a_id).await.unwrap();
|
||||
|
||||
// DAG is now:
|
||||
// zed - crdb
|
||||
@ -974,12 +1027,14 @@ async fn test_channels_moving(db: &Arc<Database>) {
|
||||
);
|
||||
|
||||
// But deleting a parent of a DAG should delete the whole DAG:
|
||||
db.move_channel(a_id, livestreaming_id, None, Some(crdb_id)).await.unwrap();
|
||||
db.move_channel(a_id, livestreaming_id, None, Some(crdb_id))
|
||||
.await
|
||||
.unwrap();
|
||||
// DAG is now:
|
||||
// zed - crdb - livestreaming - livestreaming_dag - livestreaming_dag_sub
|
||||
// \--------/
|
||||
|
||||
db.remove_channel(zed_id, a_id).await.unwrap();
|
||||
db.delete_channel(zed_id, a_id).await.unwrap();
|
||||
let result = db.get_channels_for_user(a_id).await.unwrap();
|
||||
assert!(result.channels.is_empty())
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ impl Server {
|
||||
.add_request_handler(remove_contact)
|
||||
.add_request_handler(respond_to_contact_request)
|
||||
.add_request_handler(create_channel)
|
||||
.add_request_handler(remove_channel)
|
||||
.add_request_handler(delete_channel)
|
||||
.add_request_handler(invite_channel_member)
|
||||
.add_request_handler(remove_channel_member)
|
||||
.add_request_handler(set_channel_member_admin)
|
||||
@ -267,6 +267,7 @@ impl Server {
|
||||
.add_request_handler(send_channel_message)
|
||||
.add_request_handler(remove_channel_message)
|
||||
.add_request_handler(get_channel_messages)
|
||||
.add_request_handler(move_channel)
|
||||
.add_request_handler(follow)
|
||||
.add_message_handler(unfollow)
|
||||
.add_message_handler(update_followers)
|
||||
@ -2230,23 +2231,23 @@ async fn create_channel(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_channel(
|
||||
request: proto::RemoveChannel,
|
||||
response: Response<proto::RemoveChannel>,
|
||||
async fn delete_channel(
|
||||
request: proto::DeleteChannel,
|
||||
response: Response<proto::DeleteChannel>,
|
||||
session: Session,
|
||||
) -> Result<()> {
|
||||
let db = session.db().await;
|
||||
|
||||
let channel_id = request.channel_id;
|
||||
let (removed_channels, member_ids) = db
|
||||
.remove_channel(ChannelId::from_proto(channel_id), session.user_id)
|
||||
.delete_channel(ChannelId::from_proto(channel_id), session.user_id)
|
||||
.await?;
|
||||
response.send(proto::Ack {})?;
|
||||
|
||||
// Notify members of removed channels
|
||||
let mut update = proto::UpdateChannels::default();
|
||||
update
|
||||
.remove_channels
|
||||
.delete_channels
|
||||
.extend(removed_channels.into_iter().map(|id| id.to_proto()));
|
||||
|
||||
let connection_pool = session.connection_pool().await;
|
||||
@ -2306,7 +2307,7 @@ async fn remove_channel_member(
|
||||
.await?;
|
||||
|
||||
let mut update = proto::UpdateChannels::default();
|
||||
update.remove_channels.push(channel_id.to_proto());
|
||||
update.delete_channels.push(channel_id.to_proto());
|
||||
|
||||
for connection_id in session
|
||||
.connection_pool()
|
||||
@ -2390,6 +2391,66 @@ async fn rename_channel(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn move_channel(
|
||||
request: proto::MoveChannel,
|
||||
response: Response<proto::MoveChannel>,
|
||||
session: Session,
|
||||
) -> Result<()> {
|
||||
let db = session.db().await;
|
||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||
let from_parent = request.from_parent.map(ChannelId::from_proto);
|
||||
let to = request.to.map(ChannelId::from_proto);
|
||||
let channels = db
|
||||
.move_channel(
|
||||
session.user_id,
|
||||
channel_id,
|
||||
from_parent,
|
||||
to,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
if let Some(from_parent) = from_parent {
|
||||
let members = db.get_channel_members(from_parent).await?;
|
||||
let update = proto::UpdateChannels {
|
||||
delete_channel_edge: vec![proto::ChannelEdge {
|
||||
channel_id: channel_id.to_proto(),
|
||||
parent_id: from_parent.to_proto(),
|
||||
}],
|
||||
..Default::default()
|
||||
};
|
||||
let connection_pool = session.connection_pool().await;
|
||||
for member_id in members {
|
||||
for connection_id in connection_pool.user_connection_ids(member_id) {
|
||||
session.peer.send(connection_id, update.clone())?;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if let Some(to) = to {
|
||||
let members = db.get_channel_members(to).await?;
|
||||
let connection_pool = session.connection_pool().await;
|
||||
let update = proto::UpdateChannels {
|
||||
channels: channels.into_iter().map(|channel| proto::Channel {
|
||||
id: channel.id.to_proto(),
|
||||
name: channel.name,
|
||||
parent_id: channel.parent_id.map(ChannelId::to_proto),
|
||||
}).collect(),
|
||||
..Default::default()
|
||||
};
|
||||
for member_id in members {
|
||||
for connection_id in connection_pool.user_connection_ids(member_id) {
|
||||
session.peer.send(connection_id, update.clone())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.send(Ack {})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_channel_members(
|
||||
request: proto::GetChannelMembers,
|
||||
response: Response<proto::GetChannelMembers>,
|
||||
|
@ -874,6 +874,143 @@ async fn test_lost_channel_creation(
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_channel_moving(deterministic: Arc<Deterministic>, cx_a: &mut TestAppContext) {
|
||||
deterministic.forbid_parking();
|
||||
let mut server = TestServer::start(&deterministic).await;
|
||||
let client_a = server.create_client(cx_a, "user_a").await;
|
||||
|
||||
let channel_a_id = client_a
|
||||
.channel_store()
|
||||
.update(cx_a, |channel_store, cx| {
|
||||
channel_store.create_channel("channel-a", None, cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let channel_b_id = client_a
|
||||
.channel_store()
|
||||
.update(cx_a, |channel_store, cx| {
|
||||
channel_store.create_channel("channel-b", Some(channel_a_id), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
let channel_c_id = client_a
|
||||
.channel_store()
|
||||
.update(cx_a, |channel_store, cx| {
|
||||
channel_store.create_channel("channel-c", Some(channel_b_id), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Current shape:
|
||||
// a - b - c
|
||||
deterministic.run_until_parked();
|
||||
assert_channels(
|
||||
client_a.channel_store(),
|
||||
cx_a,
|
||||
&[
|
||||
ExpectedChannel {
|
||||
id: channel_a_id,
|
||||
name: "channel-a".to_string(),
|
||||
depth: 0,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_b_id,
|
||||
name: "channel-b".to_string(),
|
||||
depth: 1,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_c_id,
|
||||
name: "channel-c".to_string(),
|
||||
depth: 2,
|
||||
user_is_admin: true,
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
client_a
|
||||
.channel_store()
|
||||
.update(cx_a, |channel_store, cx| {
|
||||
channel_store.move_channel(channel_c_id, Some(channel_b_id), Some(channel_a_id), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Current shape:
|
||||
// /- c
|
||||
// a -- b
|
||||
deterministic.run_until_parked();
|
||||
assert_channels(
|
||||
client_a.channel_store(),
|
||||
cx_a,
|
||||
&[
|
||||
ExpectedChannel {
|
||||
id: channel_a_id,
|
||||
name: "channel-a".to_string(),
|
||||
depth: 0,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_b_id,
|
||||
name: "channel-b".to_string(),
|
||||
depth: 1,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_c_id,
|
||||
name: "channel-c".to_string(),
|
||||
depth: 1,
|
||||
user_is_admin: true,
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
client_a
|
||||
.channel_store()
|
||||
.update(cx_a, |channel_store, cx| {
|
||||
channel_store.move_channel(channel_c_id, None, Some(channel_b_id), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Current shape:
|
||||
// /------\
|
||||
// a -- b -- c
|
||||
deterministic.run_until_parked();
|
||||
assert_channels(
|
||||
client_a.channel_store(),
|
||||
cx_a,
|
||||
&[
|
||||
ExpectedChannel {
|
||||
id: channel_a_id,
|
||||
name: "channel-a".to_string(),
|
||||
depth: 0,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_b_id,
|
||||
name: "channel-b".to_string(),
|
||||
depth: 1,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_c_id,
|
||||
name: "channel-c".to_string(),
|
||||
depth: 2,
|
||||
user_is_admin: true,
|
||||
},
|
||||
ExpectedChannel {
|
||||
id: channel_c_id,
|
||||
name: "channel-c".to_string(),
|
||||
depth: 1,
|
||||
user_is_admin: true,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct ExpectedChannel {
|
||||
depth: usize,
|
||||
@ -920,5 +1057,5 @@ fn assert_channels(
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
assert_eq!(actual, expected_channels);
|
||||
pretty_assertions::assert_eq!(actual, expected_channels);
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ message Envelope {
|
||||
RespondToChannelInvite respond_to_channel_invite = 123;
|
||||
UpdateChannels update_channels = 124;
|
||||
JoinChannel join_channel = 125;
|
||||
RemoveChannel remove_channel = 126;
|
||||
DeleteChannel delete_channel = 126;
|
||||
GetChannelMembers get_channel_members = 127;
|
||||
GetChannelMembersResponse get_channel_members_response = 128;
|
||||
SetChannelMemberAdmin set_channel_member_admin = 129;
|
||||
@ -165,7 +165,9 @@ message Envelope {
|
||||
ChannelMessageSent channel_message_sent = 147;
|
||||
GetChannelMessages get_channel_messages = 148;
|
||||
GetChannelMessagesResponse get_channel_messages_response = 149;
|
||||
RemoveChannelMessage remove_channel_message = 150; // Current max
|
||||
RemoveChannelMessage remove_channel_message = 150;
|
||||
|
||||
MoveChannel move_channel = 151; // Current max
|
||||
}
|
||||
}
|
||||
|
||||
@ -955,11 +957,17 @@ message LspDiskBasedDiagnosticsUpdated {}
|
||||
|
||||
message UpdateChannels {
|
||||
repeated Channel channels = 1;
|
||||
repeated uint64 remove_channels = 2;
|
||||
repeated Channel channel_invitations = 3;
|
||||
repeated uint64 remove_channel_invitations = 4;
|
||||
repeated ChannelParticipants channel_participants = 5;
|
||||
repeated ChannelPermission channel_permissions = 6;
|
||||
repeated ChannelEdge delete_channel_edge = 2;
|
||||
repeated uint64 delete_channels = 3;
|
||||
repeated Channel channel_invitations = 4;
|
||||
repeated uint64 remove_channel_invitations = 5;
|
||||
repeated ChannelParticipants channel_participants = 6;
|
||||
repeated ChannelPermission channel_permissions = 7;
|
||||
}
|
||||
|
||||
message ChannelEdge {
|
||||
uint64 channel_id = 1;
|
||||
uint64 parent_id = 2;
|
||||
}
|
||||
|
||||
message ChannelPermission {
|
||||
@ -976,7 +984,7 @@ message JoinChannel {
|
||||
uint64 channel_id = 1;
|
||||
}
|
||||
|
||||
message RemoveChannel {
|
||||
message DeleteChannel {
|
||||
uint64 channel_id = 1;
|
||||
}
|
||||
|
||||
@ -1074,6 +1082,12 @@ message GetChannelMessagesResponse {
|
||||
bool done = 2;
|
||||
}
|
||||
|
||||
message MoveChannel {
|
||||
uint64 channel_id = 1;
|
||||
optional uint64 from_parent = 2;
|
||||
optional uint64 to = 3;
|
||||
}
|
||||
|
||||
message JoinChannelBuffer {
|
||||
uint64 channel_id = 1;
|
||||
}
|
||||
|
@ -246,7 +246,8 @@ messages!(
|
||||
(UpdateBuffer, Foreground),
|
||||
(UpdateBufferFile, Foreground),
|
||||
(UpdateContacts, Foreground),
|
||||
(RemoveChannel, Foreground),
|
||||
(DeleteChannel, Foreground),
|
||||
(MoveChannel, Foreground),
|
||||
(UpdateChannels, Foreground),
|
||||
(UpdateDiagnosticSummary, Foreground),
|
||||
(UpdateFollowers, Foreground),
|
||||
@ -329,8 +330,10 @@ request_messages!(
|
||||
(JoinChannel, JoinRoomResponse),
|
||||
(RemoveChannel, Ack),
|
||||
(RemoveChannelMessage, Ack),
|
||||
(DeleteChannel, Ack),
|
||||
(RenameProjectEntry, ProjectEntryResponse),
|
||||
(RenameChannel, ChannelResponse),
|
||||
(MoveChannel, Ack),
|
||||
(SaveBuffer, BufferSaved),
|
||||
(SearchProject, SearchProjectResponse),
|
||||
(ShareProject, ShareProjectResponse),
|
||||
|
Loading…
Reference in New Issue
Block a user