mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-24 17:28:40 +00:00
Rewrite get_user_channels with new permissions
This commit is contained in:
parent
65a0ebf975
commit
a8e352a473
2 changed files with 160 additions and 18 deletions
|
@ -3,7 +3,7 @@ use crate::channel_chat::ChannelChatEvent;
|
|||
use super::*;
|
||||
use client::{test::FakeServer, Client, UserStore};
|
||||
use gpui::{AppContext, ModelHandle, TestAppContext};
|
||||
use rpc::proto::{self, ChannelRole};
|
||||
use rpc::proto::{self};
|
||||
use settings::SettingsStore;
|
||||
use util::http::FakeHttpClient;
|
||||
|
||||
|
|
|
@ -439,25 +439,108 @@ impl Database {
|
|||
channel_memberships: Vec<channel_member::Model>,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<ChannelsForUser> {
|
||||
let parents_by_child_id = self
|
||||
.get_channel_descendants(channel_memberships.iter().map(|m| m.channel_id), &*tx)
|
||||
let mut edges = self
|
||||
.get_channel_descendants_2(channel_memberships.iter().map(|m| m.channel_id), &*tx)
|
||||
.await?;
|
||||
|
||||
let channels_with_admin_privileges = channel_memberships
|
||||
.iter()
|
||||
.filter_map(|membership| {
|
||||
if membership.role == Some(ChannelRole::Admin) || membership.admin {
|
||||
Some(membership.channel_id)
|
||||
let mut role_for_channel: HashMap<ChannelId, ChannelRole> = HashMap::default();
|
||||
|
||||
for membership in channel_memberships.iter() {
|
||||
role_for_channel.insert(
|
||||
membership.channel_id,
|
||||
membership.role.unwrap_or(if membership.admin {
|
||||
ChannelRole::Admin
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
ChannelRole::Member
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let graph = self
|
||||
.get_channel_graph(parents_by_child_id, true, &tx)
|
||||
for ChannelEdge {
|
||||
parent_id,
|
||||
channel_id,
|
||||
} in edges.iter()
|
||||
{
|
||||
let parent_id = ChannelId::from_proto(*parent_id);
|
||||
let channel_id = ChannelId::from_proto(*channel_id);
|
||||
debug_assert!(role_for_channel.get(&parent_id).is_some());
|
||||
let parent_role = role_for_channel[&parent_id];
|
||||
if let Some(existing_role) = role_for_channel.get(&channel_id) {
|
||||
if existing_role.should_override(parent_role) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
role_for_channel.insert(channel_id, parent_role);
|
||||
}
|
||||
|
||||
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()
|
||||
.filter(channel::Column::Id.is_in(role_for_channel.keys().cloned()))
|
||||
.stream(&*tx)
|
||||
.await?;
|
||||
|
||||
while let Some(row) = rows.next().await {
|
||||
let channel = row?;
|
||||
let role = role_for_channel[&channel.id];
|
||||
|
||||
if role == ChannelRole::Banned
|
||||
|| role == ChannelRole::Guest && channel.visibility != ChannelVisibility::Public
|
||||
{
|
||||
channels_to_remove.insert(channel.id.0 as u64);
|
||||
continue;
|
||||
}
|
||||
|
||||
channels.push(Channel {
|
||||
id: channel.id,
|
||||
name: channel.name,
|
||||
});
|
||||
|
||||
if role == ChannelRole::Admin {
|
||||
channels_with_admin_privileges.insert(channel.id);
|
||||
}
|
||||
}
|
||||
drop(rows);
|
||||
|
||||
if !channels_to_remove.is_empty() {
|
||||
// Note: this code assumes each channel has one parent.
|
||||
let mut replacement_parent: HashMap<u64, u64> = HashMap::default();
|
||||
for ChannelEdge {
|
||||
parent_id,
|
||||
channel_id,
|
||||
} in edges.iter()
|
||||
{
|
||||
if channels_to_remove.contains(channel_id) {
|
||||
replacement_parent.insert(*channel_id, *parent_id);
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_edges: Vec<ChannelEdge> = Vec::new();
|
||||
'outer: for ChannelEdge {
|
||||
mut parent_id,
|
||||
channel_id,
|
||||
} in edges.iter()
|
||||
{
|
||||
if channels_to_remove.contains(channel_id) {
|
||||
continue;
|
||||
}
|
||||
while channels_to_remove.contains(&parent_id) {
|
||||
if let Some(new_parent_id) = replacement_parent.get(&parent_id) {
|
||||
parent_id = *new_parent_id;
|
||||
} else {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
new_edges.push(ChannelEdge {
|
||||
parent_id,
|
||||
channel_id: *channel_id,
|
||||
})
|
||||
}
|
||||
edges = new_edges;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||
enum QueryUserIdsAndChannelIds {
|
||||
ChannelId,
|
||||
|
@ -468,7 +551,7 @@ impl Database {
|
|||
{
|
||||
let mut rows = room_participant::Entity::find()
|
||||
.inner_join(room::Entity)
|
||||
.filter(room::Column::ChannelId.is_in(graph.channels.iter().map(|c| c.id)))
|
||||
.filter(room::Column::ChannelId.is_in(channels.iter().map(|c| c.id)))
|
||||
.select_only()
|
||||
.column(room::Column::ChannelId)
|
||||
.column(room_participant::Column::UserId)
|
||||
|
@ -481,7 +564,7 @@ impl Database {
|
|||
}
|
||||
}
|
||||
|
||||
let channel_ids = graph.channels.iter().map(|c| c.id).collect::<Vec<_>>();
|
||||
let channel_ids = channels.iter().map(|c| c.id).collect::<Vec<_>>();
|
||||
let channel_buffer_changes = self
|
||||
.unseen_channel_buffer_changes(user_id, &channel_ids, &*tx)
|
||||
.await?;
|
||||
|
@ -491,7 +574,7 @@ impl Database {
|
|||
.await?;
|
||||
|
||||
Ok(ChannelsForUser {
|
||||
channels: graph,
|
||||
channels: ChannelGraph { channels, edges },
|
||||
channel_participants,
|
||||
channels_with_admin_privileges,
|
||||
unseen_buffer_changes: channel_buffer_changes,
|
||||
|
@ -842,7 +925,7 @@ impl Database {
|
|||
})
|
||||
}
|
||||
|
||||
/// Returns the channel ancestors, deepest first
|
||||
/// Returns the channel ancestors, include itself, deepest first
|
||||
pub async fn get_channel_ancestors(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
|
@ -867,6 +950,65 @@ impl Database {
|
|||
Ok(channel_ids)
|
||||
}
|
||||
|
||||
// Returns the channel desendants as a sorted list of edges for further processing.
|
||||
// The edges are sorted such that you will see unknown channel ids as children
|
||||
// before you see them as parents.
|
||||
async fn get_channel_descendants_2(
|
||||
&self,
|
||||
channel_ids: impl IntoIterator<Item = ChannelId>,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<ChannelEdge>> {
|
||||
let mut values = String::new();
|
||||
for id in channel_ids {
|
||||
if !values.is_empty() {
|
||||
values.push_str(", ");
|
||||
}
|
||||
write!(&mut values, "({})", id).unwrap();
|
||||
}
|
||||
|
||||
if values.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let sql = format!(
|
||||
r#"
|
||||
SELECT
|
||||
descendant_paths.*
|
||||
FROM
|
||||
channel_paths parent_paths, channel_paths descendant_paths
|
||||
WHERE
|
||||
parent_paths.channel_id IN ({values}) AND
|
||||
descendant_paths.id_path != parent_paths.id_path AND
|
||||
descendant_paths.id_path LIKE (parent_paths.id_path || '%')
|
||||
ORDER BY
|
||||
descendant_paths.id_path
|
||||
"#
|
||||
);
|
||||
|
||||
let stmt = Statement::from_string(self.pool.get_database_backend(), sql);
|
||||
|
||||
let mut paths = channel_path::Entity::find()
|
||||
.from_raw_sql(stmt)
|
||||
.stream(tx)
|
||||
.await?;
|
||||
|
||||
let mut results: Vec<ChannelEdge> = Vec::new();
|
||||
while let Some(path) = paths.next().await {
|
||||
let path = path?;
|
||||
let ids: Vec<&str> = path.id_path.trim_matches('/').split('/').collect();
|
||||
|
||||
debug_assert!(ids.len() >= 2);
|
||||
debug_assert!(ids[ids.len() - 1] == path.channel_id.to_string());
|
||||
|
||||
results.push(ChannelEdge {
|
||||
parent_id: ids[ids.len() - 2].parse().unwrap(),
|
||||
channel_id: ids[ids.len() - 1].parse().unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
/// Returns the channel descendants,
|
||||
/// Structured as a map from child ids to their parent ids
|
||||
/// For example, the descendants of 'a' in this DAG:
|
||||
|
|
Loading…
Reference in a new issue