Support very large channel membership lists (#11939)
Fixes the channel membership dialogue for the zed channel by not downloading all 111k people in one go. Release Notes: - N/A
This commit is contained in:
parent
df3bd40c56
commit
57b5bff299
13 changed files with 270 additions and 261 deletions
|
@ -3,7 +3,7 @@ use rpc::{
|
|||
proto::{channel_member::Kind, ChannelBufferVersion, VectorClockEntry},
|
||||
ErrorCode, ErrorCodeExt,
|
||||
};
|
||||
use sea_orm::TryGetableMany;
|
||||
use sea_orm::{DbBackend, TryGetableMany};
|
||||
|
||||
impl Database {
|
||||
#[cfg(test)]
|
||||
|
@ -700,77 +700,73 @@ impl Database {
|
|||
pub async fn get_channel_participant_details(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
filter: &str,
|
||||
limit: u64,
|
||||
user_id: UserId,
|
||||
) -> Result<Vec<proto::ChannelMember>> {
|
||||
let (role, members) = self
|
||||
) -> Result<(Vec<proto::ChannelMember>, Vec<proto::User>)> {
|
||||
let members = self
|
||||
.transaction(move |tx| async move {
|
||||
let channel = self.get_channel_internal(channel_id, &tx).await?;
|
||||
let role = self
|
||||
.check_user_is_channel_participant(&channel, user_id, &tx)
|
||||
self.check_user_is_channel_participant(&channel, user_id, &tx)
|
||||
.await?;
|
||||
Ok((
|
||||
role,
|
||||
self.get_channel_participant_details_internal(&channel, &tx)
|
||||
.await?,
|
||||
))
|
||||
let mut query = channel_member::Entity::find()
|
||||
.find_also_related(user::Entity)
|
||||
.filter(channel_member::Column::ChannelId.eq(channel.root_id()));
|
||||
|
||||
if cfg!(any(test, sqlite)) && self.pool.get_database_backend() == DbBackend::Sqlite {
|
||||
query = query.filter(Expr::cust_with_values(
|
||||
"UPPER(github_login) LIKE ?",
|
||||
[Self::fuzzy_like_string(&filter.to_uppercase())],
|
||||
))
|
||||
} else {
|
||||
query = query.filter(Expr::cust_with_values(
|
||||
"github_login ILIKE $1",
|
||||
[Self::fuzzy_like_string(filter)],
|
||||
))
|
||||
}
|
||||
let members = query.order_by(
|
||||
Expr::cust(
|
||||
"not role = 'admin', not role = 'member', not role = 'guest', not accepted, github_login",
|
||||
),
|
||||
sea_orm::Order::Asc,
|
||||
)
|
||||
.limit(limit)
|
||||
.all(&*tx)
|
||||
.await?;
|
||||
|
||||
Ok(members)
|
||||
})
|
||||
.await?;
|
||||
|
||||
if role == ChannelRole::Admin {
|
||||
Ok(members
|
||||
.into_iter()
|
||||
.map(|channel_member| proto::ChannelMember {
|
||||
role: channel_member.role.into(),
|
||||
user_id: channel_member.user_id.to_proto(),
|
||||
kind: if channel_member.accepted {
|
||||
let mut users: Vec<proto::User> = Vec::with_capacity(members.len());
|
||||
|
||||
let members = members
|
||||
.into_iter()
|
||||
.map(|(member, user)| {
|
||||
if let Some(user) = user {
|
||||
users.push(proto::User {
|
||||
id: user.id.to_proto(),
|
||||
avatar_url: format!(
|
||||
"https://github.com/{}.png?size=128",
|
||||
user.github_login
|
||||
),
|
||||
github_login: user.github_login,
|
||||
})
|
||||
}
|
||||
proto::ChannelMember {
|
||||
role: member.role.into(),
|
||||
user_id: member.user_id.to_proto(),
|
||||
kind: if member.accepted {
|
||||
Kind::Member
|
||||
} else {
|
||||
Kind::Invitee
|
||||
}
|
||||
.into(),
|
||||
})
|
||||
.collect())
|
||||
} else {
|
||||
return Ok(members
|
||||
.into_iter()
|
||||
.filter_map(|member| {
|
||||
if !member.accepted {
|
||||
return None;
|
||||
}
|
||||
Some(proto::ChannelMember {
|
||||
role: member.role.into(),
|
||||
user_id: member.user_id.to_proto(),
|
||||
kind: Kind::Member.into(),
|
||||
})
|
||||
})
|
||||
.collect());
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
async fn get_channel_participant_details_internal(
|
||||
&self,
|
||||
channel: &channel::Model,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<channel_member::Model>> {
|
||||
Ok(channel_member::Entity::find()
|
||||
.filter(channel_member::Column::ChannelId.eq(channel.root_id()))
|
||||
.all(tx)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Returns the participants in the given channel.
|
||||
pub async fn get_channel_participants(
|
||||
&self,
|
||||
channel: &channel::Model,
|
||||
tx: &DatabaseTransaction,
|
||||
) -> Result<Vec<UserId>> {
|
||||
let participants = self
|
||||
.get_channel_participant_details_internal(channel, tx)
|
||||
.await?;
|
||||
Ok(participants
|
||||
.into_iter()
|
||||
.map(|member| member.user_id)
|
||||
.collect())
|
||||
Ok((members, users))
|
||||
}
|
||||
|
||||
/// Returns whether the given user is an admin in the specified channel.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue