Sync Role as part of channels
Begin to fix guest notifications
This commit is contained in:
parent
72ed8a6dd2
commit
70aed4a605
15 changed files with 323 additions and 266 deletions
|
@ -82,7 +82,7 @@ id_type!(UserId);
|
|||
id_type!(ChannelBufferCollaboratorId);
|
||||
id_type!(FlagId);
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug, EnumIter, DeriveActiveEnum, Default)]
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug, EnumIter, DeriveActiveEnum, Default, Hash)]
|
||||
#[sea_orm(rs_type = "String", db_type = "String(None)")]
|
||||
pub enum ChannelRole {
|
||||
#[sea_orm(string_value = "admin")]
|
||||
|
|
|
@ -16,7 +16,7 @@ impl Database {
|
|||
connection: ConnectionId,
|
||||
) -> Result<proto::JoinChannelBufferResponse> {
|
||||
self.transaction(|tx| async move {
|
||||
self.check_user_is_channel_member(channel_id, user_id, &tx)
|
||||
self.check_user_is_channel_participant(channel_id, user_id, &tx)
|
||||
.await?;
|
||||
|
||||
let buffer = channel::Model {
|
||||
|
@ -131,7 +131,7 @@ impl Database {
|
|||
for client_buffer in buffers {
|
||||
let channel_id = ChannelId::from_proto(client_buffer.channel_id);
|
||||
if self
|
||||
.check_user_is_channel_member(channel_id, user_id, &*tx)
|
||||
.check_user_is_channel_participant(channel_id, user_id, &*tx)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
|
|
|
@ -132,9 +132,12 @@ impl Database {
|
|||
&& channel.as_ref().map(|c| c.visibility) == Some(ChannelVisibility::Public)
|
||||
{
|
||||
let channel_id_to_join = self
|
||||
.most_public_ancestor_for_channel(channel_id, &*tx)
|
||||
.public_path_to_channel_internal(channel_id, &*tx)
|
||||
.await?
|
||||
.first()
|
||||
.cloned()
|
||||
.unwrap_or(channel_id);
|
||||
|
||||
role = Some(ChannelRole::Guest);
|
||||
joined_channel_id = Some(channel_id_to_join);
|
||||
|
||||
|
@ -306,7 +309,8 @@ impl Database {
|
|||
self.transaction(move |tx| async move {
|
||||
let new_name = Self::sanitize_channel_name(new_name)?.to_string();
|
||||
|
||||
self.check_user_is_channel_admin(channel_id, user_id, &*tx)
|
||||
let role = self
|
||||
.check_user_is_channel_admin(channel_id, user_id, &*tx)
|
||||
.await?;
|
||||
|
||||
let channel = channel::ActiveModel {
|
||||
|
@ -321,6 +325,7 @@ impl Database {
|
|||
id: channel.id,
|
||||
name: channel.name,
|
||||
visibility: channel.visibility,
|
||||
role,
|
||||
})
|
||||
})
|
||||
.await
|
||||
|
@ -398,6 +403,8 @@ impl Database {
|
|||
|
||||
pub async fn get_channel_invites_for_user(&self, user_id: UserId) -> Result<Vec<Channel>> {
|
||||
self.transaction(|tx| async move {
|
||||
let mut role_for_channel: HashMap<ChannelId, ChannelRole> = HashMap::default();
|
||||
|
||||
let channel_invites = channel_member::Entity::find()
|
||||
.filter(
|
||||
channel_member::Column::UserId
|
||||
|
@ -407,14 +414,12 @@ impl Database {
|
|||
.all(&*tx)
|
||||
.await?;
|
||||
|
||||
for invite in channel_invites {
|
||||
role_for_channel.insert(invite.channel_id, invite.role);
|
||||
}
|
||||
|
||||
let channels = channel::Entity::find()
|
||||
.filter(
|
||||
channel::Column::Id.is_in(
|
||||
channel_invites
|
||||
.into_iter()
|
||||
.map(|channel_member| channel_member.channel_id),
|
||||
),
|
||||
)
|
||||
.filter(channel::Column::Id.is_in(role_for_channel.keys().cloned()))
|
||||
.all(&*tx)
|
||||
.await?;
|
||||
|
||||
|
@ -424,6 +429,7 @@ impl Database {
|
|||
id: channel.id,
|
||||
name: channel.name,
|
||||
visibility: channel.visibility,
|
||||
role: role_for_channel[&channel.id],
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -458,19 +464,22 @@ impl Database {
|
|||
) -> Result<ChannelsForUser> {
|
||||
self.transaction(|tx| async move {
|
||||
let tx = tx;
|
||||
|
||||
let channel_membership = channel_member::Entity::find()
|
||||
.filter(
|
||||
channel_member::Column::UserId
|
||||
.eq(user_id)
|
||||
.and(channel_member::Column::ChannelId.eq(channel_id))
|
||||
.and(channel_member::Column::Accepted.eq(true)),
|
||||
)
|
||||
.all(&*tx)
|
||||
let role = self
|
||||
.check_user_is_channel_participant(channel_id, user_id, &*tx)
|
||||
.await?;
|
||||
|
||||
self.get_user_channels(user_id, channel_membership, &tx)
|
||||
.await
|
||||
self.get_user_channels(
|
||||
user_id,
|
||||
vec![channel_member::Model {
|
||||
id: Default::default(),
|
||||
channel_id,
|
||||
user_id,
|
||||
role,
|
||||
accepted: true,
|
||||
}],
|
||||
&tx,
|
||||
)
|
||||
.await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
@ -509,7 +518,6 @@ impl Database {
|
|||
}
|
||||
|
||||
let mut channels: Vec<Channel> = Vec::new();
|
||||
let mut channels_with_admin_privileges: HashSet<ChannelId> = HashSet::default();
|
||||
let mut channels_to_remove: HashSet<u64> = HashSet::default();
|
||||
|
||||
let mut rows = channel::Entity::find()
|
||||
|
@ -532,11 +540,8 @@ impl Database {
|
|||
id: channel.id,
|
||||
name: channel.name,
|
||||
visibility: channel.visibility,
|
||||
role: role,
|
||||
});
|
||||
|
||||
if role == ChannelRole::Admin {
|
||||
channels_with_admin_privileges.insert(channel.id);
|
||||
}
|
||||
}
|
||||
drop(rows);
|
||||
|
||||
|
@ -618,7 +623,6 @@ impl Database {
|
|||
Ok(ChannelsForUser {
|
||||
channels: ChannelGraph { channels, edges },
|
||||
channel_participants,
|
||||
channels_with_admin_privileges,
|
||||
unseen_buffer_changes: channel_buffer_changes,
|
||||
channel_messages: unseen_messages,
|
||||
})
|
||||
|
@ -787,9 +791,10 @@ impl Database {
|
|||
channel_id: ChannelId,
|
||||
user_id: UserId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<()> {
|
||||
match self.channel_role_for_user(channel_id, user_id, tx).await? {
|
||||
Some(ChannelRole::Admin) => Ok(()),
|
||||
) -> Result<ChannelRole> {
|
||||
let role = self.channel_role_for_user(channel_id, user_id, tx).await?;
|
||||
match role {
|
||||
Some(ChannelRole::Admin) => Ok(role.unwrap()),
|
||||
Some(ChannelRole::Member)
|
||||
| Some(ChannelRole::Banned)
|
||||
| Some(ChannelRole::Guest)
|
||||
|
@ -818,10 +823,11 @@ impl Database {
|
|||
channel_id: ChannelId,
|
||||
user_id: UserId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<()> {
|
||||
match self.channel_role_for_user(channel_id, user_id, tx).await? {
|
||||
) -> Result<ChannelRole> {
|
||||
let role = self.channel_role_for_user(channel_id, user_id, tx).await?;
|
||||
match role {
|
||||
Some(ChannelRole::Admin) | Some(ChannelRole::Member) | Some(ChannelRole::Guest) => {
|
||||
Ok(())
|
||||
Ok(role.unwrap())
|
||||
}
|
||||
Some(ChannelRole::Banned) | None => Err(anyhow!(
|
||||
"user is not a channel participant or channel does not exist"
|
||||
|
@ -847,12 +853,26 @@ impl Database {
|
|||
Ok(row)
|
||||
}
|
||||
|
||||
pub async fn most_public_ancestor_for_channel(
|
||||
// ordered from higher in tree to lower
|
||||
// only considers one path to a channel
|
||||
// includes the channel itself
|
||||
pub async fn public_path_to_channel(&self, channel_id: ChannelId) -> Result<Vec<ChannelId>> {
|
||||
self.transaction(move |tx| async move {
|
||||
Ok(self
|
||||
.public_path_to_channel_internal(channel_id, &*tx)
|
||||
.await?)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
// ordered from higher in tree to lower
|
||||
// only considers one path to a channel
|
||||
// includes the channel itself
|
||||
pub async fn public_path_to_channel_internal(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Option<ChannelId>> {
|
||||
// Note: if there are many paths to a channel, this will return just one
|
||||
) -> Result<Vec<ChannelId>> {
|
||||
let arbitary_path = channel_path::Entity::find()
|
||||
.filter(channel_path::Column::ChannelId.eq(channel_id))
|
||||
.order_by(channel_path::Column::IdPath, sea_orm::Order::Desc)
|
||||
|
@ -860,7 +880,7 @@ impl Database {
|
|||
.await?;
|
||||
|
||||
let Some(path) = arbitary_path else {
|
||||
return Ok(None);
|
||||
return Ok(vec![]);
|
||||
};
|
||||
|
||||
let ancestor_ids: Vec<ChannelId> = path
|
||||
|
@ -882,13 +902,10 @@ impl Database {
|
|||
visible_channels.insert(row.id);
|
||||
}
|
||||
|
||||
for ancestor in ancestor_ids {
|
||||
if visible_channels.contains(&ancestor) {
|
||||
return Ok(Some(ancestor));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
Ok(ancestor_ids
|
||||
.into_iter()
|
||||
.filter(|id| visible_channels.contains(id))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub async fn channel_role_for_user(
|
||||
|
@ -1059,7 +1076,8 @@ impl Database {
|
|||
/// Returns the channel with the given ID
|
||||
pub async fn get_channel(&self, channel_id: ChannelId, user_id: UserId) -> Result<Channel> {
|
||||
self.transaction(|tx| async move {
|
||||
self.check_user_is_channel_participant(channel_id, user_id, &*tx)
|
||||
let role = self
|
||||
.check_user_is_channel_participant(channel_id, user_id, &*tx)
|
||||
.await?;
|
||||
|
||||
let channel = channel::Entity::find_by_id(channel_id).one(&*tx).await?;
|
||||
|
@ -1070,6 +1088,7 @@ impl Database {
|
|||
Ok(Channel {
|
||||
id: channel.id,
|
||||
visibility: channel.visibility,
|
||||
role,
|
||||
name: channel.name,
|
||||
})
|
||||
})
|
||||
|
|
|
@ -149,17 +149,21 @@ impl Drop for TestDb {
|
|||
}
|
||||
|
||||
/// The second tuples are (channel_id, parent)
|
||||
fn graph(channels: &[(ChannelId, &'static str)], edges: &[(ChannelId, ChannelId)]) -> ChannelGraph {
|
||||
fn graph(
|
||||
channels: &[(ChannelId, &'static str, ChannelRole)],
|
||||
edges: &[(ChannelId, ChannelId)],
|
||||
) -> ChannelGraph {
|
||||
let mut graph = ChannelGraph {
|
||||
channels: vec![],
|
||||
edges: vec![],
|
||||
};
|
||||
|
||||
for (id, name) in channels {
|
||||
for (id, name, role) in channels {
|
||||
graph.channels.push(Channel {
|
||||
id: *id,
|
||||
name: name.to_string(),
|
||||
visibility: ChannelVisibility::Members,
|
||||
role: *role,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -8,45 +8,20 @@ use crate::{
|
|||
db::{
|
||||
queries::channels::ChannelGraph,
|
||||
tests::{graph, TEST_RELEASE_CHANNEL},
|
||||
ChannelId, ChannelRole, Database, NewUserParams, RoomId, UserId,
|
||||
ChannelId, ChannelRole, Database, NewUserParams, RoomId, ServerId, UserId,
|
||||
},
|
||||
test_both_dbs,
|
||||
};
|
||||
use std::sync::{
|
||||
atomic::{AtomicI32, Ordering},
|
||||
atomic::{AtomicI32, AtomicU32, Ordering},
|
||||
Arc,
|
||||
};
|
||||
|
||||
test_both_dbs!(test_channels, test_channels_postgres, test_channels_sqlite);
|
||||
|
||||
async fn test_channels(db: &Arc<Database>) {
|
||||
let a_id = db
|
||||
.create_user(
|
||||
"user1@example.com",
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user1".into(),
|
||||
github_user_id: 5,
|
||||
invite_count: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.user_id;
|
||||
|
||||
let b_id = db
|
||||
.create_user(
|
||||
"user2@example.com",
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user2".into(),
|
||||
github_user_id: 6,
|
||||
invite_count: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.user_id;
|
||||
let a_id = new_test_user(db, "user1@example.com").await;
|
||||
let b_id = new_test_user(db, "user2@example.com").await;
|
||||
|
||||
let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
|
||||
|
||||
|
@ -91,13 +66,13 @@ async fn test_channels(db: &Arc<Database>) {
|
|||
result.channels,
|
||||
graph(
|
||||
&[
|
||||
(zed_id, "zed"),
|
||||
(crdb_id, "crdb"),
|
||||
(livestreaming_id, "livestreaming"),
|
||||
(replace_id, "replace"),
|
||||
(rust_id, "rust"),
|
||||
(cargo_id, "cargo"),
|
||||
(cargo_ra_id, "cargo-ra")
|
||||
(zed_id, "zed", ChannelRole::Admin),
|
||||
(crdb_id, "crdb", ChannelRole::Admin),
|
||||
(livestreaming_id, "livestreaming", ChannelRole::Admin),
|
||||
(replace_id, "replace", ChannelRole::Admin),
|
||||
(rust_id, "rust", ChannelRole::Admin),
|
||||
(cargo_id, "cargo", ChannelRole::Admin),
|
||||
(cargo_ra_id, "cargo-ra", ChannelRole::Admin)
|
||||
],
|
||||
&[
|
||||
(crdb_id, zed_id),
|
||||
|
@ -114,10 +89,10 @@ async fn test_channels(db: &Arc<Database>) {
|
|||
result.channels,
|
||||
graph(
|
||||
&[
|
||||
(zed_id, "zed"),
|
||||
(crdb_id, "crdb"),
|
||||
(livestreaming_id, "livestreaming"),
|
||||
(replace_id, "replace")
|
||||
(zed_id, "zed", ChannelRole::Member),
|
||||
(crdb_id, "crdb", ChannelRole::Member),
|
||||
(livestreaming_id, "livestreaming", ChannelRole::Member),
|
||||
(replace_id, "replace", ChannelRole::Member)
|
||||
],
|
||||
&[
|
||||
(crdb_id, zed_id),
|
||||
|
@ -142,10 +117,10 @@ async fn test_channels(db: &Arc<Database>) {
|
|||
result.channels,
|
||||
graph(
|
||||
&[
|
||||
(zed_id, "zed"),
|
||||
(crdb_id, "crdb"),
|
||||
(livestreaming_id, "livestreaming"),
|
||||
(replace_id, "replace")
|
||||
(zed_id, "zed", ChannelRole::Admin),
|
||||
(crdb_id, "crdb", ChannelRole::Admin),
|
||||
(livestreaming_id, "livestreaming", ChannelRole::Admin),
|
||||
(replace_id, "replace", ChannelRole::Admin)
|
||||
],
|
||||
&[
|
||||
(crdb_id, zed_id),
|
||||
|
@ -179,32 +154,8 @@ test_both_dbs!(
|
|||
async fn test_joining_channels(db: &Arc<Database>) {
|
||||
let owner_id = db.create_server("test").await.unwrap().0 as u32;
|
||||
|
||||
let user_1 = db
|
||||
.create_user(
|
||||
"user1@example.com",
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user1".into(),
|
||||
github_user_id: 5,
|
||||
invite_count: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.user_id;
|
||||
let user_2 = db
|
||||
.create_user(
|
||||
"user2@example.com",
|
||||
false,
|
||||
NewUserParams {
|
||||
github_login: "user2".into(),
|
||||
github_user_id: 6,
|
||||
invite_count: 0,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
.user_id;
|
||||
let user_1 = new_test_user(db, "user1@example.com").await;
|
||||
let user_2 = new_test_user(db, "user2@example.com").await;
|
||||
|
||||
let channel_1 = db.create_root_channel("channel_1", user_1).await.unwrap();
|
||||
|
||||
|
@ -523,7 +474,11 @@ async fn test_db_channel_moving(db: &Arc<Database>) {
|
|||
pretty_assertions::assert_eq!(
|
||||
returned_channels,
|
||||
graph(
|
||||
&[(livestreaming_dag_sub_id, "livestreaming_dag_sub")],
|
||||
&[(
|
||||
livestreaming_dag_sub_id,
|
||||
"livestreaming_dag_sub",
|
||||
ChannelRole::Admin
|
||||
)],
|
||||
&[(livestreaming_dag_sub_id, livestreaming_id)]
|
||||
)
|
||||
);
|
||||
|
@ -560,9 +515,17 @@ async fn test_db_channel_moving(db: &Arc<Database>) {
|
|||
returned_channels,
|
||||
graph(
|
||||
&[
|
||||
(livestreaming_id, "livestreaming"),
|
||||
(livestreaming_dag_id, "livestreaming_dag"),
|
||||
(livestreaming_dag_sub_id, "livestreaming_dag_sub"),
|
||||
(livestreaming_id, "livestreaming", ChannelRole::Admin),
|
||||
(
|
||||
livestreaming_dag_id,
|
||||
"livestreaming_dag",
|
||||
ChannelRole::Admin
|
||||
),
|
||||
(
|
||||
livestreaming_dag_sub_id,
|
||||
"livestreaming_dag_sub",
|
||||
ChannelRole::Admin
|
||||
),
|
||||
],
|
||||
&[
|
||||
(livestreaming_id, gpui2_id),
|
||||
|
@ -1080,13 +1043,46 @@ async fn test_user_joins_correct_channel(db: &Arc<Database>) {
|
|||
.unwrap();
|
||||
|
||||
let most_public = db
|
||||
.transaction(
|
||||
|tx| async move { db.most_public_ancestor_for_channel(vim_channel, &*tx).await },
|
||||
)
|
||||
.public_path_to_channel(vim_channel)
|
||||
.await
|
||||
.unwrap()
|
||||
.first()
|
||||
.cloned();
|
||||
|
||||
assert_eq!(most_public, Some(zed_channel))
|
||||
}
|
||||
|
||||
test_both_dbs!(
|
||||
test_guest_access,
|
||||
test_guest_access_postgres,
|
||||
test_guest_access_sqlite
|
||||
);
|
||||
|
||||
async fn test_guest_access(db: &Arc<Database>) {
|
||||
let server = db.create_server("test").await.unwrap();
|
||||
|
||||
let admin = new_test_user(db, "admin@example.com").await;
|
||||
let guest = new_test_user(db, "guest@example.com").await;
|
||||
let guest_connection = new_test_connection(server);
|
||||
|
||||
let zed_channel = db.create_root_channel("zed", admin).await.unwrap();
|
||||
db.set_channel_visibility(zed_channel, crate::db::ChannelVisibility::Public, admin)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(most_public, Some(zed_channel))
|
||||
assert!(db
|
||||
.join_channel_chat(zed_channel, guest_connection, guest)
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
db.join_channel(zed_channel, guest, guest_connection, TEST_RELEASE_CHANNEL)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert!(db
|
||||
.join_channel_chat(zed_channel, guest_connection, guest)
|
||||
.await
|
||||
.is_ok())
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
@ -1130,3 +1126,11 @@ async fn new_test_user(db: &Arc<Database>, email: &str) -> UserId {
|
|||
.unwrap()
|
||||
.user_id
|
||||
}
|
||||
|
||||
static TEST_CONNECTION_ID: AtomicU32 = AtomicU32::new(1);
|
||||
fn new_test_connection(server: ServerId) -> ConnectionId {
|
||||
ConnectionId {
|
||||
id: TEST_CONNECTION_ID.fetch_add(1, Ordering::SeqCst),
|
||||
owner_id: server.0 as u32,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue