Push role refactoring through RPC/client
This commit is contained in:
parent
690d9fb971
commit
540436a1f9
12 changed files with 178 additions and 89 deletions
|
@ -3,4 +3,4 @@ xtask = "run --package xtask --"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
# v0 mangling scheme provides more detailed backtraces around closures
|
# v0 mangling scheme provides more detailed backtraces around closures
|
||||||
rustflags = ["-C", "symbol-mangling-version=v0"]
|
rustflags = ["-C", "symbol-mangling-version=v0", "-C", "link-arg=-fuse-ld=/opt/homebrew/Cellar/llvm/16.0.6/bin/ld64.lld"]
|
||||||
|
|
|
@ -9,7 +9,7 @@ use db::RELEASE_CHANNEL;
|
||||||
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
|
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
|
||||||
use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle};
|
use gpui::{AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle};
|
||||||
use rpc::{
|
use rpc::{
|
||||||
proto::{self, ChannelEdge, ChannelPermission},
|
proto::{self, ChannelEdge, ChannelPermission, ChannelRole},
|
||||||
TypedEnvelope,
|
TypedEnvelope,
|
||||||
};
|
};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -79,7 +79,7 @@ pub struct ChannelPath(Arc<[ChannelId]>);
|
||||||
pub struct ChannelMembership {
|
pub struct ChannelMembership {
|
||||||
pub user: Arc<User>,
|
pub user: Arc<User>,
|
||||||
pub kind: proto::channel_member::Kind,
|
pub kind: proto::channel_member::Kind,
|
||||||
pub admin: bool,
|
pub role: proto::ChannelRole,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ChannelEvent {
|
pub enum ChannelEvent {
|
||||||
|
@ -436,7 +436,7 @@ impl ChannelStore {
|
||||||
insert_edge: parent_edge,
|
insert_edge: parent_edge,
|
||||||
channel_permissions: vec![ChannelPermission {
|
channel_permissions: vec![ChannelPermission {
|
||||||
channel_id,
|
channel_id,
|
||||||
is_admin: true,
|
role: ChannelRole::Admin.into(),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -512,7 +512,7 @@ impl ChannelStore {
|
||||||
&mut self,
|
&mut self,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
admin: bool,
|
role: proto::ChannelRole,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
if !self.outgoing_invites.insert((channel_id, user_id)) {
|
if !self.outgoing_invites.insert((channel_id, user_id)) {
|
||||||
|
@ -526,7 +526,7 @@ impl ChannelStore {
|
||||||
.request(proto::InviteChannelMember {
|
.request(proto::InviteChannelMember {
|
||||||
channel_id,
|
channel_id,
|
||||||
user_id,
|
user_id,
|
||||||
admin,
|
role: role.into(),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -570,11 +570,11 @@ impl ChannelStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_member_admin(
|
pub fn set_member_role(
|
||||||
&mut self,
|
&mut self,
|
||||||
channel_id: ChannelId,
|
channel_id: ChannelId,
|
||||||
user_id: UserId,
|
user_id: UserId,
|
||||||
admin: bool,
|
role: proto::ChannelRole,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
if !self.outgoing_invites.insert((channel_id, user_id)) {
|
if !self.outgoing_invites.insert((channel_id, user_id)) {
|
||||||
|
@ -585,10 +585,10 @@ impl ChannelStore {
|
||||||
let client = self.client.clone();
|
let client = self.client.clone();
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
let result = client
|
let result = client
|
||||||
.request(proto::SetChannelMemberAdmin {
|
.request(proto::SetChannelMemberRole {
|
||||||
channel_id,
|
channel_id,
|
||||||
user_id,
|
user_id,
|
||||||
admin,
|
role: role.into(),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
@ -676,8 +676,8 @@ impl ChannelStore {
|
||||||
.filter_map(|(user, member)| {
|
.filter_map(|(user, member)| {
|
||||||
Some(ChannelMembership {
|
Some(ChannelMembership {
|
||||||
user,
|
user,
|
||||||
admin: member.admin,
|
role: member.role(),
|
||||||
kind: proto::channel_member::Kind::from_i32(member.kind)?,
|
kind: member.kind(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect())
|
.collect())
|
||||||
|
@ -935,7 +935,7 @@ impl ChannelStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
for permission in payload.channel_permissions {
|
for permission in payload.channel_permissions {
|
||||||
if permission.is_admin {
|
if permission.role() == proto::ChannelRole::Admin {
|
||||||
self.channels_with_admin_privileges
|
self.channels_with_admin_privileges
|
||||||
.insert(permission.channel_id);
|
.insert(permission.channel_id);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,7 +26,7 @@ fn test_update_channels(cx: &mut AppContext) {
|
||||||
],
|
],
|
||||||
channel_permissions: vec![proto::ChannelPermission {
|
channel_permissions: vec![proto::ChannelPermission {
|
||||||
channel_id: 1,
|
channel_id: 1,
|
||||||
is_admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
@ -114,7 +114,7 @@ fn test_dangling_channel_paths(cx: &mut AppContext) {
|
||||||
],
|
],
|
||||||
channel_permissions: vec![proto::ChannelPermission {
|
channel_permissions: vec![proto::ChannelPermission {
|
||||||
channel_id: 0,
|
channel_id: 0,
|
||||||
is_admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
use rpc::proto;
|
||||||
use sea_orm::{entity::prelude::*, DbErr};
|
use sea_orm::{entity::prelude::*, DbErr};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
@ -91,3 +92,30 @@ pub enum ChannelRole {
|
||||||
#[sea_orm(string_value = "guest")]
|
#[sea_orm(string_value = "guest")]
|
||||||
Guest,
|
Guest,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<proto::ChannelRole> for ChannelRole {
|
||||||
|
fn from(value: proto::ChannelRole) -> Self {
|
||||||
|
match value {
|
||||||
|
proto::ChannelRole::Admin => ChannelRole::Admin,
|
||||||
|
proto::ChannelRole::Member => ChannelRole::Member,
|
||||||
|
proto::ChannelRole::Guest => ChannelRole::Guest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<proto::ChannelRole> for ChannelRole {
|
||||||
|
fn into(self) -> proto::ChannelRole {
|
||||||
|
match self {
|
||||||
|
ChannelRole::Admin => proto::ChannelRole::Admin,
|
||||||
|
ChannelRole::Member => proto::ChannelRole::Member,
|
||||||
|
ChannelRole::Guest => proto::ChannelRole::Guest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<i32> for ChannelRole {
|
||||||
|
fn into(self) -> i32 {
|
||||||
|
let proto: proto::ChannelRole = self.into();
|
||||||
|
proto.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -564,13 +564,18 @@ impl Database {
|
||||||
(false, true) => proto::channel_member::Kind::AncestorMember,
|
(false, true) => proto::channel_member::Kind::AncestorMember,
|
||||||
(false, false) => continue,
|
(false, false) => continue,
|
||||||
};
|
};
|
||||||
|
let channel_role = channel_role.unwrap_or(if is_admin {
|
||||||
|
ChannelRole::Admin
|
||||||
|
} else {
|
||||||
|
ChannelRole::Member
|
||||||
|
});
|
||||||
let user_id = user_id.to_proto();
|
let user_id = user_id.to_proto();
|
||||||
let kind = kind.into();
|
let kind = kind.into();
|
||||||
if let Some(last_row) = rows.last_mut() {
|
if let Some(last_row) = rows.last_mut() {
|
||||||
if last_row.user_id == user_id {
|
if last_row.user_id == user_id {
|
||||||
if is_direct_member {
|
if is_direct_member {
|
||||||
last_row.kind = kind;
|
last_row.kind = kind;
|
||||||
last_row.admin = channel_role == Some(ChannelRole::Admin) || is_admin;
|
last_row.role = channel_role.into()
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -578,7 +583,7 @@ impl Database {
|
||||||
rows.push(proto::ChannelMember {
|
rows.push(proto::ChannelMember {
|
||||||
user_id,
|
user_id,
|
||||||
kind,
|
kind,
|
||||||
admin: channel_role == Some(ChannelRole::Admin) || is_admin,
|
role: channel_role.into(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -851,10 +856,11 @@ impl Database {
|
||||||
&self,
|
&self,
|
||||||
user: UserId,
|
user: UserId,
|
||||||
channel: ChannelId,
|
channel: ChannelId,
|
||||||
to: ChannelId,
|
new_parent: ChannelId,
|
||||||
tx: &DatabaseTransaction,
|
tx: &DatabaseTransaction,
|
||||||
) -> Result<ChannelGraph> {
|
) -> Result<ChannelGraph> {
|
||||||
self.check_user_is_channel_admin(to, user, &*tx).await?;
|
self.check_user_is_channel_admin(new_parent, user, &*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let paths = channel_path::Entity::find()
|
let paths = channel_path::Entity::find()
|
||||||
.filter(channel_path::Column::IdPath.like(&format!("%/{}/%", channel)))
|
.filter(channel_path::Column::IdPath.like(&format!("%/{}/%", channel)))
|
||||||
|
@ -872,7 +878,7 @@ impl Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
let paths_to_new_parent = channel_path::Entity::find()
|
let paths_to_new_parent = channel_path::Entity::find()
|
||||||
.filter(channel_path::Column::ChannelId.eq(to))
|
.filter(channel_path::Column::ChannelId.eq(new_parent))
|
||||||
.all(tx)
|
.all(tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -906,7 +912,7 @@ impl Database {
|
||||||
if let Some(channel) = channel_descendants.get_mut(&channel) {
|
if let Some(channel) = channel_descendants.get_mut(&channel) {
|
||||||
// Remove the other parents
|
// Remove the other parents
|
||||||
channel.clear();
|
channel.clear();
|
||||||
channel.insert(to);
|
channel.insert(new_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
let channels = self
|
let channels = self
|
||||||
|
|
|
@ -328,17 +328,17 @@ async fn test_channel_invites(db: &Arc<Database>) {
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
user_id: user_1.to_proto(),
|
user_id: user_1.to_proto(),
|
||||||
kind: proto::channel_member::Kind::Member.into(),
|
kind: proto::channel_member::Kind::Member.into(),
|
||||||
admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
},
|
},
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
user_id: user_2.to_proto(),
|
user_id: user_2.to_proto(),
|
||||||
kind: proto::channel_member::Kind::Invitee.into(),
|
kind: proto::channel_member::Kind::Invitee.into(),
|
||||||
admin: false,
|
role: proto::ChannelRole::Member.into(),
|
||||||
},
|
},
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
user_id: user_3.to_proto(),
|
user_id: user_3.to_proto(),
|
||||||
kind: proto::channel_member::Kind::Invitee.into(),
|
kind: proto::channel_member::Kind::Invitee.into(),
|
||||||
admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -362,12 +362,12 @@ async fn test_channel_invites(db: &Arc<Database>) {
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
user_id: user_1.to_proto(),
|
user_id: user_1.to_proto(),
|
||||||
kind: proto::channel_member::Kind::Member.into(),
|
kind: proto::channel_member::Kind::Member.into(),
|
||||||
admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
},
|
},
|
||||||
proto::ChannelMember {
|
proto::ChannelMember {
|
||||||
user_id: user_2.to_proto(),
|
user_id: user_2.to_proto(),
|
||||||
kind: proto::channel_member::Kind::AncestorMember.into(),
|
kind: proto::channel_member::Kind::AncestorMember.into(),
|
||||||
admin: false,
|
role: proto::ChannelRole::Member.into(),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
|
@ -3,8 +3,8 @@ mod connection_pool;
|
||||||
use crate::{
|
use crate::{
|
||||||
auth,
|
auth,
|
||||||
db::{
|
db::{
|
||||||
self, BufferId, ChannelId, ChannelRole, ChannelsForUser, Database, MessageId, ProjectId,
|
self, BufferId, ChannelId, ChannelsForUser, Database, MessageId, ProjectId, RoomId,
|
||||||
RoomId, ServerId, User, UserId,
|
ServerId, User, UserId,
|
||||||
},
|
},
|
||||||
executor::Executor,
|
executor::Executor,
|
||||||
AppState, Result,
|
AppState, Result,
|
||||||
|
@ -254,7 +254,7 @@ impl Server {
|
||||||
.add_request_handler(delete_channel)
|
.add_request_handler(delete_channel)
|
||||||
.add_request_handler(invite_channel_member)
|
.add_request_handler(invite_channel_member)
|
||||||
.add_request_handler(remove_channel_member)
|
.add_request_handler(remove_channel_member)
|
||||||
.add_request_handler(set_channel_member_admin)
|
.add_request_handler(set_channel_member_role)
|
||||||
.add_request_handler(rename_channel)
|
.add_request_handler(rename_channel)
|
||||||
.add_request_handler(join_channel_buffer)
|
.add_request_handler(join_channel_buffer)
|
||||||
.add_request_handler(leave_channel_buffer)
|
.add_request_handler(leave_channel_buffer)
|
||||||
|
@ -2282,13 +2282,13 @@ async fn invite_channel_member(
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||||
let invitee_id = UserId::from_proto(request.user_id);
|
let invitee_id = UserId::from_proto(request.user_id);
|
||||||
let role = if request.admin {
|
db.invite_channel_member(
|
||||||
ChannelRole::Admin
|
channel_id,
|
||||||
} else {
|
invitee_id,
|
||||||
ChannelRole::Member
|
session.user_id,
|
||||||
};
|
request.role().into(),
|
||||||
db.invite_channel_member(channel_id, invitee_id, session.user_id, role)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let (channel, _) = db
|
let (channel, _) = db
|
||||||
.get_channel(channel_id, session.user_id)
|
.get_channel(channel_id, session.user_id)
|
||||||
|
@ -2339,21 +2339,21 @@ async fn remove_channel_member(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn set_channel_member_admin(
|
async fn set_channel_member_role(
|
||||||
request: proto::SetChannelMemberAdmin,
|
request: proto::SetChannelMemberRole,
|
||||||
response: Response<proto::SetChannelMemberAdmin>,
|
response: Response<proto::SetChannelMemberRole>,
|
||||||
session: Session,
|
session: Session,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let db = session.db().await;
|
let db = session.db().await;
|
||||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||||
let member_id = UserId::from_proto(request.user_id);
|
let member_id = UserId::from_proto(request.user_id);
|
||||||
let role = if request.admin {
|
db.set_channel_member_role(
|
||||||
ChannelRole::Admin
|
channel_id,
|
||||||
} else {
|
session.user_id,
|
||||||
ChannelRole::Member
|
member_id,
|
||||||
};
|
request.role().into(),
|
||||||
db.set_channel_member_role(channel_id, session.user_id, member_id, role)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let (channel, has_accepted) = db
|
let (channel, has_accepted) = db
|
||||||
.get_channel(channel_id, member_id)
|
.get_channel(channel_id, member_id)
|
||||||
|
@ -2364,7 +2364,7 @@ async fn set_channel_member_admin(
|
||||||
if has_accepted {
|
if has_accepted {
|
||||||
update.channel_permissions.push(proto::ChannelPermission {
|
update.channel_permissions.push(proto::ChannelPermission {
|
||||||
channel_id: channel.id.to_proto(),
|
channel_id: channel.id.to_proto(),
|
||||||
is_admin: request.admin,
|
role: request.role,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2603,7 +2603,7 @@ async fn respond_to_channel_invite(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|channel_id| proto::ChannelPermission {
|
.map(|channel_id| proto::ChannelPermission {
|
||||||
channel_id: channel_id.to_proto(),
|
channel_id: channel_id.to_proto(),
|
||||||
is_admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3106,7 +3106,7 @@ fn build_initial_channels_update(
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|id| proto::ChannelPermission {
|
.map(|id| proto::ChannelPermission {
|
||||||
channel_id: id.to_proto(),
|
channel_id: id.to_proto(),
|
||||||
is_admin: true,
|
role: proto::ChannelRole::Admin.into(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,12 @@ async fn test_core_channels(
|
||||||
.update(cx_a, |store, cx| {
|
.update(cx_a, |store, cx| {
|
||||||
assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
|
assert!(!store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
|
||||||
|
|
||||||
let invite = store.invite_member(channel_a_id, client_b.user_id().unwrap(), false, cx);
|
let invite = store.invite_member(
|
||||||
|
channel_a_id,
|
||||||
|
client_b.user_id().unwrap(),
|
||||||
|
proto::ChannelRole::Member,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
|
||||||
// Make sure we're synchronously storing the pending invite
|
// Make sure we're synchronously storing the pending invite
|
||||||
assert!(store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
|
assert!(store.has_pending_channel_invite(channel_a_id, client_b.user_id().unwrap()));
|
||||||
|
@ -103,12 +108,12 @@ async fn test_core_channels(
|
||||||
&[
|
&[
|
||||||
(
|
(
|
||||||
client_a.user_id().unwrap(),
|
client_a.user_id().unwrap(),
|
||||||
true,
|
proto::ChannelRole::Admin,
|
||||||
proto::channel_member::Kind::Member,
|
proto::channel_member::Kind::Member,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
client_b.user_id().unwrap(),
|
client_b.user_id().unwrap(),
|
||||||
false,
|
proto::ChannelRole::Member,
|
||||||
proto::channel_member::Kind::Invitee,
|
proto::channel_member::Kind::Invitee,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -183,7 +188,12 @@ async fn test_core_channels(
|
||||||
client_a
|
client_a
|
||||||
.channel_store()
|
.channel_store()
|
||||||
.update(cx_a, |store, cx| {
|
.update(cx_a, |store, cx| {
|
||||||
store.set_member_admin(channel_a_id, client_b.user_id().unwrap(), true, cx)
|
store.set_member_role(
|
||||||
|
channel_a_id,
|
||||||
|
client_b.user_id().unwrap(),
|
||||||
|
proto::ChannelRole::Admin,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -305,12 +315,12 @@ fn assert_participants_eq(participants: &[Arc<User>], expected_partitipants: &[u
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_members_eq(
|
fn assert_members_eq(
|
||||||
members: &[ChannelMembership],
|
members: &[ChannelMembership],
|
||||||
expected_members: &[(u64, bool, proto::channel_member::Kind)],
|
expected_members: &[(u64, proto::ChannelRole, proto::channel_member::Kind)],
|
||||||
) {
|
) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
members
|
members
|
||||||
.iter()
|
.iter()
|
||||||
.map(|member| (member.user.id, member.admin, member.kind))
|
.map(|member| (member.user.id, member.role, member.kind))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
expected_members
|
expected_members
|
||||||
);
|
);
|
||||||
|
@ -611,7 +621,12 @@ async fn test_permissions_update_while_invited(
|
||||||
client_a
|
client_a
|
||||||
.channel_store()
|
.channel_store()
|
||||||
.update(cx_a, |channel_store, cx| {
|
.update(cx_a, |channel_store, cx| {
|
||||||
channel_store.invite_member(rust_id, client_b.user_id().unwrap(), false, cx)
|
channel_store.invite_member(
|
||||||
|
rust_id,
|
||||||
|
client_b.user_id().unwrap(),
|
||||||
|
proto::ChannelRole::Member,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -634,7 +649,12 @@ async fn test_permissions_update_while_invited(
|
||||||
client_a
|
client_a
|
||||||
.channel_store()
|
.channel_store()
|
||||||
.update(cx_a, |channel_store, cx| {
|
.update(cx_a, |channel_store, cx| {
|
||||||
channel_store.set_member_admin(rust_id, client_b.user_id().unwrap(), true, cx)
|
channel_store.set_member_role(
|
||||||
|
rust_id,
|
||||||
|
client_b.user_id().unwrap(),
|
||||||
|
proto::ChannelRole::Admin,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -803,7 +823,12 @@ async fn test_lost_channel_creation(
|
||||||
client_a
|
client_a
|
||||||
.channel_store()
|
.channel_store()
|
||||||
.update(cx_a, |channel_store, cx| {
|
.update(cx_a, |channel_store, cx| {
|
||||||
channel_store.invite_member(channel_id, client_b.user_id().unwrap(), false, cx)
|
channel_store.invite_member(
|
||||||
|
channel_id,
|
||||||
|
client_b.user_id().unwrap(),
|
||||||
|
proto::ChannelRole::Member,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -17,7 +17,7 @@ use gpui::{executor::Deterministic, ModelHandle, Task, TestAppContext, WindowHan
|
||||||
use language::LanguageRegistry;
|
use language::LanguageRegistry;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project::{Project, WorktreeId};
|
use project::{Project, WorktreeId};
|
||||||
use rpc::RECEIVE_TIMEOUT;
|
use rpc::{proto::ChannelRole, RECEIVE_TIMEOUT};
|
||||||
use settings::SettingsStore;
|
use settings::SettingsStore;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell, RefMut},
|
cell::{Ref, RefCell, RefMut},
|
||||||
|
@ -325,7 +325,7 @@ impl TestServer {
|
||||||
channel_store.invite_member(
|
channel_store.invite_member(
|
||||||
channel_id,
|
channel_id,
|
||||||
member_client.user_id().unwrap(),
|
member_client.user_id().unwrap(),
|
||||||
false,
|
ChannelRole::Member,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -613,7 +613,12 @@ impl TestClient {
|
||||||
cx_self
|
cx_self
|
||||||
.read(ChannelStore::global)
|
.read(ChannelStore::global)
|
||||||
.update(cx_self, |channel_store, cx| {
|
.update(cx_self, |channel_store, cx| {
|
||||||
channel_store.invite_member(channel, other_client.user_id().unwrap(), true, cx)
|
channel_store.invite_member(
|
||||||
|
channel,
|
||||||
|
other_client.user_id().unwrap(),
|
||||||
|
ChannelRole::Admin,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
use channel::{ChannelId, ChannelMembership, ChannelStore};
|
use channel::{ChannelId, ChannelMembership, ChannelStore};
|
||||||
use client::{proto, User, UserId, UserStore};
|
use client::{
|
||||||
|
proto::{self, ChannelRole},
|
||||||
|
User, UserId, UserStore,
|
||||||
|
};
|
||||||
use context_menu::{ContextMenu, ContextMenuItem};
|
use context_menu::{ContextMenu, ContextMenuItem};
|
||||||
use fuzzy::{match_strings, StringMatchCandidate};
|
use fuzzy::{match_strings, StringMatchCandidate};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
|
@ -343,9 +346,11 @@ impl PickerDelegate for ChannelModalDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
|
fn confirm(&mut self, _: bool, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
if let Some((selected_user, admin)) = self.user_at_index(self.selected_index) {
|
if let Some((selected_user, role)) = self.user_at_index(self.selected_index) {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::ManageMembers => self.show_context_menu(admin.unwrap_or(false), cx),
|
Mode::ManageMembers => {
|
||||||
|
self.show_context_menu(role.unwrap_or(ChannelRole::Member), cx)
|
||||||
|
}
|
||||||
Mode::InviteMembers => match self.member_status(selected_user.id, cx) {
|
Mode::InviteMembers => match self.member_status(selected_user.id, cx) {
|
||||||
Some(proto::channel_member::Kind::Invitee) => {
|
Some(proto::channel_member::Kind::Invitee) => {
|
||||||
self.remove_selected_member(cx);
|
self.remove_selected_member(cx);
|
||||||
|
@ -373,7 +378,7 @@ impl PickerDelegate for ChannelModalDelegate {
|
||||||
let full_theme = &theme::current(cx);
|
let full_theme = &theme::current(cx);
|
||||||
let theme = &full_theme.collab_panel.channel_modal;
|
let theme = &full_theme.collab_panel.channel_modal;
|
||||||
let tabbed_modal = &full_theme.collab_panel.tabbed_modal;
|
let tabbed_modal = &full_theme.collab_panel.tabbed_modal;
|
||||||
let (user, admin) = self.user_at_index(ix).unwrap();
|
let (user, role) = self.user_at_index(ix).unwrap();
|
||||||
let request_status = self.member_status(user.id, cx);
|
let request_status = self.member_status(user.id, cx);
|
||||||
|
|
||||||
let style = tabbed_modal
|
let style = tabbed_modal
|
||||||
|
@ -409,15 +414,25 @@ impl PickerDelegate for ChannelModalDelegate {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.with_children(admin.and_then(|admin| {
|
.with_children(if in_manage && role == Some(ChannelRole::Admin) {
|
||||||
(in_manage && admin).then(|| {
|
Some(
|
||||||
Label::new("Admin", theme.member_tag.text.clone())
|
Label::new("Admin", theme.member_tag.text.clone())
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(theme.member_tag.container)
|
.with_style(theme.member_tag.container)
|
||||||
.aligned()
|
.aligned()
|
||||||
.left()
|
.left(),
|
||||||
})
|
)
|
||||||
}))
|
} else if in_manage && role == Some(ChannelRole::Guest) {
|
||||||
|
Some(
|
||||||
|
Label::new("Guest", theme.member_tag.text.clone())
|
||||||
|
.contained()
|
||||||
|
.with_style(theme.member_tag.container)
|
||||||
|
.aligned()
|
||||||
|
.left(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
.with_children({
|
.with_children({
|
||||||
let svg = match self.mode {
|
let svg = match self.mode {
|
||||||
Mode::ManageMembers => Some(
|
Mode::ManageMembers => Some(
|
||||||
|
@ -502,13 +517,13 @@ impl ChannelModalDelegate {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn user_at_index(&self, ix: usize) -> Option<(Arc<User>, Option<bool>)> {
|
fn user_at_index(&self, ix: usize) -> Option<(Arc<User>, Option<ChannelRole>)> {
|
||||||
match self.mode {
|
match self.mode {
|
||||||
Mode::ManageMembers => self.matching_member_indices.get(ix).and_then(|ix| {
|
Mode::ManageMembers => self.matching_member_indices.get(ix).and_then(|ix| {
|
||||||
let channel_membership = self.members.get(*ix)?;
|
let channel_membership = self.members.get(*ix)?;
|
||||||
Some((
|
Some((
|
||||||
channel_membership.user.clone(),
|
channel_membership.user.clone(),
|
||||||
Some(channel_membership.admin),
|
Some(channel_membership.role),
|
||||||
))
|
))
|
||||||
}),
|
}),
|
||||||
Mode::InviteMembers => Some((self.matching_users.get(ix).cloned()?, None)),
|
Mode::InviteMembers => Some((self.matching_users.get(ix).cloned()?, None)),
|
||||||
|
@ -516,17 +531,21 @@ impl ChannelModalDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_selected_member_admin(&mut self, cx: &mut ViewContext<Picker<Self>>) -> Option<()> {
|
fn toggle_selected_member_admin(&mut self, cx: &mut ViewContext<Picker<Self>>) -> Option<()> {
|
||||||
let (user, admin) = self.user_at_index(self.selected_index)?;
|
let (user, role) = self.user_at_index(self.selected_index)?;
|
||||||
let admin = !admin.unwrap_or(false);
|
let new_role = if role == Some(ChannelRole::Admin) {
|
||||||
|
ChannelRole::Member
|
||||||
|
} else {
|
||||||
|
ChannelRole::Admin
|
||||||
|
};
|
||||||
let update = self.channel_store.update(cx, |store, cx| {
|
let update = self.channel_store.update(cx, |store, cx| {
|
||||||
store.set_member_admin(self.channel_id, user.id, admin, cx)
|
store.set_member_role(self.channel_id, user.id, new_role, cx)
|
||||||
});
|
});
|
||||||
cx.spawn(|picker, mut cx| async move {
|
cx.spawn(|picker, mut cx| async move {
|
||||||
update.await?;
|
update.await?;
|
||||||
picker.update(&mut cx, |picker, cx| {
|
picker.update(&mut cx, |picker, cx| {
|
||||||
let this = picker.delegate_mut();
|
let this = picker.delegate_mut();
|
||||||
if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user.id) {
|
if let Some(member) = this.members.iter_mut().find(|m| m.user.id == user.id) {
|
||||||
member.admin = admin;
|
member.role = new_role;
|
||||||
}
|
}
|
||||||
cx.focus_self();
|
cx.focus_self();
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -572,7 +591,7 @@ impl ChannelModalDelegate {
|
||||||
|
|
||||||
fn invite_member(&mut self, user: Arc<User>, cx: &mut ViewContext<Picker<Self>>) {
|
fn invite_member(&mut self, user: Arc<User>, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
let invite_member = self.channel_store.update(cx, |store, cx| {
|
let invite_member = self.channel_store.update(cx, |store, cx| {
|
||||||
store.invite_member(self.channel_id, user.id, false, cx)
|
store.invite_member(self.channel_id, user.id, ChannelRole::Member, cx)
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.spawn(|this, mut cx| async move {
|
cx.spawn(|this, mut cx| async move {
|
||||||
|
@ -582,7 +601,7 @@ impl ChannelModalDelegate {
|
||||||
this.delegate_mut().members.push(ChannelMembership {
|
this.delegate_mut().members.push(ChannelMembership {
|
||||||
user,
|
user,
|
||||||
kind: proto::channel_member::Kind::Invitee,
|
kind: proto::channel_member::Kind::Invitee,
|
||||||
admin: false,
|
role: ChannelRole::Member,
|
||||||
});
|
});
|
||||||
cx.notify();
|
cx.notify();
|
||||||
})
|
})
|
||||||
|
@ -590,7 +609,7 @@ impl ChannelModalDelegate {
|
||||||
.detach_and_log_err(cx);
|
.detach_and_log_err(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_context_menu(&mut self, user_is_admin: bool, cx: &mut ViewContext<Picker<Self>>) {
|
fn show_context_menu(&mut self, role: ChannelRole, cx: &mut ViewContext<Picker<Self>>) {
|
||||||
self.context_menu.update(cx, |context_menu, cx| {
|
self.context_menu.update(cx, |context_menu, cx| {
|
||||||
context_menu.show(
|
context_menu.show(
|
||||||
Default::default(),
|
Default::default(),
|
||||||
|
@ -598,7 +617,7 @@ impl ChannelModalDelegate {
|
||||||
vec![
|
vec![
|
||||||
ContextMenuItem::action("Remove", RemoveMember),
|
ContextMenuItem::action("Remove", RemoveMember),
|
||||||
ContextMenuItem::action(
|
ContextMenuItem::action(
|
||||||
if user_is_admin {
|
if role == ChannelRole::Admin {
|
||||||
"Make non-admin"
|
"Make non-admin"
|
||||||
} else {
|
} else {
|
||||||
"Make admin"
|
"Make admin"
|
||||||
|
|
|
@ -144,7 +144,7 @@ message Envelope {
|
||||||
DeleteChannel delete_channel = 118;
|
DeleteChannel delete_channel = 118;
|
||||||
GetChannelMembers get_channel_members = 119;
|
GetChannelMembers get_channel_members = 119;
|
||||||
GetChannelMembersResponse get_channel_members_response = 120;
|
GetChannelMembersResponse get_channel_members_response = 120;
|
||||||
SetChannelMemberAdmin set_channel_member_admin = 121;
|
SetChannelMemberRole set_channel_member_role = 145;
|
||||||
RenameChannel rename_channel = 122;
|
RenameChannel rename_channel = 122;
|
||||||
RenameChannelResponse rename_channel_response = 123;
|
RenameChannelResponse rename_channel_response = 123;
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ message Envelope {
|
||||||
|
|
||||||
LinkChannel link_channel = 140;
|
LinkChannel link_channel = 140;
|
||||||
UnlinkChannel unlink_channel = 141;
|
UnlinkChannel unlink_channel = 141;
|
||||||
MoveChannel move_channel = 142; // current max: 144
|
MoveChannel move_channel = 142; // current max: 145
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -979,7 +979,7 @@ message ChannelEdge {
|
||||||
|
|
||||||
message ChannelPermission {
|
message ChannelPermission {
|
||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1;
|
||||||
bool is_admin = 2;
|
ChannelRole role = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChannelParticipants {
|
message ChannelParticipants {
|
||||||
|
@ -1005,8 +1005,8 @@ message GetChannelMembersResponse {
|
||||||
|
|
||||||
message ChannelMember {
|
message ChannelMember {
|
||||||
uint64 user_id = 1;
|
uint64 user_id = 1;
|
||||||
bool admin = 2;
|
|
||||||
Kind kind = 3;
|
Kind kind = 3;
|
||||||
|
ChannelRole role = 4;
|
||||||
|
|
||||||
enum Kind {
|
enum Kind {
|
||||||
Member = 0;
|
Member = 0;
|
||||||
|
@ -1028,7 +1028,7 @@ message CreateChannelResponse {
|
||||||
message InviteChannelMember {
|
message InviteChannelMember {
|
||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1;
|
||||||
uint64 user_id = 2;
|
uint64 user_id = 2;
|
||||||
bool admin = 3;
|
ChannelRole role = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RemoveChannelMember {
|
message RemoveChannelMember {
|
||||||
|
@ -1036,10 +1036,16 @@ message RemoveChannelMember {
|
||||||
uint64 user_id = 2;
|
uint64 user_id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetChannelMemberAdmin {
|
enum ChannelRole {
|
||||||
|
Admin = 0;
|
||||||
|
Member = 1;
|
||||||
|
Guest = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetChannelMemberRole {
|
||||||
uint64 channel_id = 1;
|
uint64 channel_id = 1;
|
||||||
uint64 user_id = 2;
|
uint64 user_id = 2;
|
||||||
bool admin = 3;
|
ChannelRole role = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message RenameChannel {
|
message RenameChannel {
|
||||||
|
|
|
@ -230,7 +230,7 @@ messages!(
|
||||||
(SaveBuffer, Foreground),
|
(SaveBuffer, Foreground),
|
||||||
(RenameChannel, Foreground),
|
(RenameChannel, Foreground),
|
||||||
(RenameChannelResponse, Foreground),
|
(RenameChannelResponse, Foreground),
|
||||||
(SetChannelMemberAdmin, Foreground),
|
(SetChannelMemberRole, Foreground),
|
||||||
(SearchProject, Background),
|
(SearchProject, Background),
|
||||||
(SearchProjectResponse, Background),
|
(SearchProjectResponse, Background),
|
||||||
(ShareProject, Foreground),
|
(ShareProject, Foreground),
|
||||||
|
@ -326,7 +326,7 @@ request_messages!(
|
||||||
(RemoveContact, Ack),
|
(RemoveContact, Ack),
|
||||||
(RespondToContactRequest, Ack),
|
(RespondToContactRequest, Ack),
|
||||||
(RespondToChannelInvite, Ack),
|
(RespondToChannelInvite, Ack),
|
||||||
(SetChannelMemberAdmin, Ack),
|
(SetChannelMemberRole, Ack),
|
||||||
(SendChannelMessage, SendChannelMessageResponse),
|
(SendChannelMessage, SendChannelMessageResponse),
|
||||||
(GetChannelMessages, GetChannelMessagesResponse),
|
(GetChannelMessages, GetChannelMessagesResponse),
|
||||||
(GetChannelMembers, GetChannelMembersResponse),
|
(GetChannelMembers, GetChannelMembersResponse),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue