Aggressively simplify channel permissions:
- Only allow setting permissions on the root channel - Only allow public channels to be children of public channels
This commit is contained in:
parent
716221cd38
commit
4b672621d3
18 changed files with 477 additions and 970 deletions
|
@ -61,11 +61,12 @@ impl ChannelBuffer {
|
|||
.map(language::proto::deserialize_operation)
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let buffer = cx.new_model(|_| {
|
||||
let buffer = cx.new_model(|cx| {
|
||||
let capability = channel_store.read(cx).channel_capability(channel.id);
|
||||
language::Buffer::remote(
|
||||
response.buffer_id,
|
||||
response.replica_id as u16,
|
||||
channel.channel_buffer_capability(),
|
||||
capability,
|
||||
base_text,
|
||||
)
|
||||
})?;
|
||||
|
|
|
@ -13,11 +13,11 @@ use gpui::{
|
|||
};
|
||||
use language::Capability;
|
||||
use rpc::{
|
||||
proto::{self, ChannelVisibility},
|
||||
proto::{self, ChannelRole, ChannelVisibility},
|
||||
TypedEnvelope,
|
||||
};
|
||||
use std::{mem, sync::Arc, time::Duration};
|
||||
use util::{async_maybe, ResultExt};
|
||||
use util::{async_maybe, maybe, ResultExt};
|
||||
|
||||
pub fn init(client: &Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
|
||||
let channel_store =
|
||||
|
@ -58,7 +58,6 @@ pub struct Channel {
|
|||
pub id: ChannelId,
|
||||
pub name: SharedString,
|
||||
pub visibility: proto::ChannelVisibility,
|
||||
pub role: proto::ChannelRole,
|
||||
pub parent_path: Vec<u64>,
|
||||
}
|
||||
|
||||
|
@ -68,6 +67,7 @@ pub struct ChannelState {
|
|||
latest_notes_versions: Option<NotesVersion>,
|
||||
observed_chat_message: Option<u64>,
|
||||
observed_notes_versions: Option<NotesVersion>,
|
||||
role: Option<ChannelRole>,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
|
@ -90,11 +90,12 @@ impl Channel {
|
|||
}
|
||||
|
||||
pub fn channel_buffer_capability(&self) -> Capability {
|
||||
if self.role == proto::ChannelRole::Member || self.role == proto::ChannelRole::Admin {
|
||||
Capability::ReadWrite
|
||||
} else {
|
||||
Capability::ReadOnly
|
||||
}
|
||||
todo!() // go ask the channel store
|
||||
// if self.role == proto::ChannelRole::Member || self.role == proto::ChannelRole::Admin {
|
||||
// Capability::ReadWrite
|
||||
// } else {
|
||||
// Capability::ReadOnly
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,8 +115,7 @@ impl ChannelMembership {
|
|||
},
|
||||
kind_order: match self.kind {
|
||||
proto::channel_member::Kind::Member => 0,
|
||||
proto::channel_member::Kind::AncestorMember => 1,
|
||||
proto::channel_member::Kind::Invitee => 2,
|
||||
proto::channel_member::Kind::Invitee => 1,
|
||||
},
|
||||
username_order: self.user.github_login.as_str(),
|
||||
}
|
||||
|
@ -479,10 +479,25 @@ impl ChannelStore {
|
|||
}
|
||||
|
||||
pub fn is_channel_admin(&self, channel_id: ChannelId) -> bool {
|
||||
let Some(channel) = self.channel_for_id(channel_id) else {
|
||||
return false;
|
||||
};
|
||||
channel.role == proto::ChannelRole::Admin
|
||||
self.channel_role(channel_id) == proto::ChannelRole::Admin
|
||||
}
|
||||
|
||||
pub fn channel_capability(&self, channel_id: ChannelId) -> Capability {
|
||||
match self.channel_role(channel_id) {
|
||||
ChannelRole::Admin | ChannelRole::Member => Capability::ReadWrite,
|
||||
_ => Capability::ReadOnly,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn channel_role(&self, channel_id: ChannelId) -> proto::ChannelRole {
|
||||
maybe!({
|
||||
let channel = self.channel_for_id(channel_id)?;
|
||||
let root_channel_id = channel.parent_path.first()?;
|
||||
let root_channel_state = self.channel_states.get(&root_channel_id);
|
||||
debug_assert!(root_channel_state.is_some());
|
||||
root_channel_state?.role
|
||||
})
|
||||
.unwrap_or(proto::ChannelRole::Guest)
|
||||
}
|
||||
|
||||
pub fn channel_participants(&self, channel_id: ChannelId) -> &[Arc<User>] {
|
||||
|
@ -533,7 +548,7 @@ impl ChannelStore {
|
|||
pub fn move_channel(
|
||||
&mut self,
|
||||
channel_id: ChannelId,
|
||||
to: Option<ChannelId>,
|
||||
to: ChannelId,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let client = self.client.clone();
|
||||
|
@ -791,6 +806,14 @@ impl ChannelStore {
|
|||
for message_id in message.payload.observed_channel_message_id {
|
||||
this.acknowledge_message_id(message_id.channel_id, message_id.message_id, cx);
|
||||
}
|
||||
for membership in message.payload.channel_memberships {
|
||||
if let Some(role) = ChannelRole::from_i32(membership.role) {
|
||||
this.channel_states
|
||||
.entry(membership.channel_id)
|
||||
.or_insert_with(|| ChannelState::default())
|
||||
.set_role(role)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -956,7 +979,6 @@ impl ChannelStore {
|
|||
Arc::new(Channel {
|
||||
id: channel.id,
|
||||
visibility: channel.visibility(),
|
||||
role: channel.role(),
|
||||
name: channel.name.into(),
|
||||
parent_path: channel.parent_path,
|
||||
}),
|
||||
|
@ -1071,6 +1093,10 @@ impl ChannelStore {
|
|||
}
|
||||
|
||||
impl ChannelState {
|
||||
fn set_role(&mut self, role: ChannelRole) {
|
||||
self.role = Some(role);
|
||||
}
|
||||
|
||||
fn has_channel_buffer_changed(&self) -> bool {
|
||||
if let Some(latest_version) = &self.latest_notes_versions {
|
||||
if let Some(observed_version) = &self.observed_notes_versions {
|
||||
|
|
|
@ -54,19 +54,18 @@ impl<'a> ChannelPathsInsertGuard<'a> {
|
|||
let existing_channel = Arc::make_mut(existing_channel);
|
||||
|
||||
ret = existing_channel.visibility != channel_proto.visibility()
|
||||
|| existing_channel.role != channel_proto.role()
|
||||
|| existing_channel.name != channel_proto.name;
|
||||
|| existing_channel.name != channel_proto.name
|
||||
|| existing_channel.parent_path != channel_proto.parent_path;
|
||||
|
||||
existing_channel.visibility = channel_proto.visibility();
|
||||
existing_channel.role = channel_proto.role();
|
||||
existing_channel.name = channel_proto.name.into();
|
||||
existing_channel.parent_path = channel_proto.parent_path.into();
|
||||
} else {
|
||||
self.channels_by_id.insert(
|
||||
channel_proto.id,
|
||||
Arc::new(Channel {
|
||||
id: channel_proto.id,
|
||||
visibility: channel_proto.visibility(),
|
||||
role: channel_proto.role(),
|
||||
name: channel_proto.name.into(),
|
||||
parent_path: channel_proto.parent_path,
|
||||
}),
|
||||
|
|
|
@ -19,14 +19,12 @@ fn test_update_channels(cx: &mut AppContext) {
|
|||
id: 1,
|
||||
name: "b".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Admin.into(),
|
||||
parent_path: Vec::new(),
|
||||
},
|
||||
proto::Channel {
|
||||
id: 2,
|
||||
name: "a".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Member.into(),
|
||||
parent_path: Vec::new(),
|
||||
},
|
||||
],
|
||||
|
@ -38,8 +36,8 @@ fn test_update_channels(cx: &mut AppContext) {
|
|||
&channel_store,
|
||||
&[
|
||||
//
|
||||
(0, "a".to_string(), proto::ChannelRole::Member),
|
||||
(0, "b".to_string(), proto::ChannelRole::Admin),
|
||||
(0, "a".to_string()),
|
||||
(0, "b".to_string()),
|
||||
],
|
||||
cx,
|
||||
);
|
||||
|
@ -52,14 +50,12 @@ fn test_update_channels(cx: &mut AppContext) {
|
|||
id: 3,
|
||||
name: "x".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Admin.into(),
|
||||
parent_path: vec![1],
|
||||
},
|
||||
proto::Channel {
|
||||
id: 4,
|
||||
name: "y".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Member.into(),
|
||||
parent_path: vec![2],
|
||||
},
|
||||
],
|
||||
|
@ -70,10 +66,10 @@ fn test_update_channels(cx: &mut AppContext) {
|
|||
assert_channels(
|
||||
&channel_store,
|
||||
&[
|
||||
(0, "a".to_string(), proto::ChannelRole::Member),
|
||||
(1, "y".to_string(), proto::ChannelRole::Member),
|
||||
(0, "b".to_string(), proto::ChannelRole::Admin),
|
||||
(1, "x".to_string(), proto::ChannelRole::Admin),
|
||||
(0, "a".to_string()),
|
||||
(1, "y".to_string()),
|
||||
(0, "b".to_string()),
|
||||
(1, "x".to_string()),
|
||||
],
|
||||
cx,
|
||||
);
|
||||
|
@ -91,21 +87,18 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
|
|||
id: 0,
|
||||
name: "a".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Admin.into(),
|
||||
parent_path: vec![],
|
||||
},
|
||||
proto::Channel {
|
||||
id: 1,
|
||||
name: "b".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Admin.into(),
|
||||
parent_path: vec![0],
|
||||
},
|
||||
proto::Channel {
|
||||
id: 2,
|
||||
name: "c".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Admin.into(),
|
||||
parent_path: vec![0, 1],
|
||||
},
|
||||
],
|
||||
|
@ -118,9 +111,9 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
|
|||
&channel_store,
|
||||
&[
|
||||
//
|
||||
(0, "a".to_string(), proto::ChannelRole::Admin),
|
||||
(1, "b".to_string(), proto::ChannelRole::Admin),
|
||||
(2, "c".to_string(), proto::ChannelRole::Admin),
|
||||
(0, "a".to_string()),
|
||||
(1, "b".to_string()),
|
||||
(2, "c".to_string()),
|
||||
],
|
||||
cx,
|
||||
);
|
||||
|
@ -135,11 +128,7 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
|
|||
);
|
||||
|
||||
// Make sure that the 1/2/3 path is gone
|
||||
assert_channels(
|
||||
&channel_store,
|
||||
&[(0, "a".to_string(), proto::ChannelRole::Admin)],
|
||||
cx,
|
||||
);
|
||||
assert_channels(&channel_store, &[(0, "a".to_string())], cx);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -156,18 +145,13 @@ async fn test_channel_messages(cx: &mut TestAppContext) {
|
|||
id: channel_id,
|
||||
name: "the-channel".to_string(),
|
||||
visibility: proto::ChannelVisibility::Members as i32,
|
||||
role: proto::ChannelRole::Member.into(),
|
||||
parent_path: vec![],
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
cx.update(|cx| {
|
||||
assert_channels(
|
||||
&channel_store,
|
||||
&[(0, "the-channel".to_string(), proto::ChannelRole::Member)],
|
||||
cx,
|
||||
);
|
||||
assert_channels(&channel_store, &[(0, "the-channel".to_string())], cx);
|
||||
});
|
||||
|
||||
let get_users = server.receive::<proto::GetUsers>().await.unwrap();
|
||||
|
@ -368,13 +352,13 @@ fn update_channels(
|
|||
#[track_caller]
|
||||
fn assert_channels(
|
||||
channel_store: &Model<ChannelStore>,
|
||||
expected_channels: &[(usize, String, proto::ChannelRole)],
|
||||
expected_channels: &[(usize, String)],
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
let actual = channel_store.update(cx, |store, _| {
|
||||
store
|
||||
.ordered_channels()
|
||||
.map(|(depth, channel)| (depth, channel.name.to_string(), channel.role))
|
||||
.map(|(depth, channel)| (depth, channel.name.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
assert_eq!(actual, expected_channels);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue