mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-24 17:28:40 +00:00
Add a role column to the database and start using it
We cannot yet stop using `admin` because stable will continue writing it.
This commit is contained in:
parent
be1800884e
commit
690d9fb971
10 changed files with 76 additions and 30 deletions
|
@ -226,6 +226,7 @@ CREATE TABLE "channel_members" (
|
|||
"channel_id" INTEGER NOT NULL REFERENCES channels (id) ON DELETE CASCADE,
|
||||
"user_id" INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
||||
"admin" BOOLEAN NOT NULL DEFAULT false,
|
||||
"role" VARCHAR,
|
||||
"accepted" BOOLEAN NOT NULL DEFAULT false,
|
||||
"updated_at" TIMESTAMP NOT NULL DEFAULT now
|
||||
);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
-- Add migration script here
|
||||
|
||||
ALTER TABLE channel_members ADD COLUMN role TEXT;
|
||||
UPDATE channel_members SET role = CASE WHEN admin THEN 'admin' ELSE 'member' END;
|
|
@ -80,3 +80,14 @@ id_type!(SignupId);
|
|||
id_type!(UserId);
|
||||
id_type!(ChannelBufferCollaboratorId);
|
||||
id_type!(FlagId);
|
||||
|
||||
#[derive(Eq, PartialEq, Copy, Clone, Debug, EnumIter, DeriveActiveEnum)]
|
||||
#[sea_orm(rs_type = "String", db_type = "String(None)")]
|
||||
pub enum ChannelRole {
|
||||
#[sea_orm(string_value = "admin")]
|
||||
Admin,
|
||||
#[sea_orm(string_value = "member")]
|
||||
Member,
|
||||
#[sea_orm(string_value = "guest")]
|
||||
Guest,
|
||||
}
|
||||
|
|
|
@ -74,11 +74,12 @@ impl Database {
|
|||
}
|
||||
|
||||
channel_member::ActiveModel {
|
||||
id: ActiveValue::NotSet,
|
||||
channel_id: ActiveValue::Set(channel.id),
|
||||
user_id: ActiveValue::Set(creator_id),
|
||||
accepted: ActiveValue::Set(true),
|
||||
admin: ActiveValue::Set(true),
|
||||
..Default::default()
|
||||
role: ActiveValue::Set(Some(ChannelRole::Admin)),
|
||||
}
|
||||
.insert(&*tx)
|
||||
.await?;
|
||||
|
@ -160,18 +161,19 @@ impl Database {
|
|||
channel_id: ChannelId,
|
||||
invitee_id: UserId,
|
||||
inviter_id: UserId,
|
||||
is_admin: bool,
|
||||
role: ChannelRole,
|
||||
) -> Result<()> {
|
||||
self.transaction(move |tx| async move {
|
||||
self.check_user_is_channel_admin(channel_id, inviter_id, &*tx)
|
||||
.await?;
|
||||
|
||||
channel_member::ActiveModel {
|
||||
id: ActiveValue::NotSet,
|
||||
channel_id: ActiveValue::Set(channel_id),
|
||||
user_id: ActiveValue::Set(invitee_id),
|
||||
accepted: ActiveValue::Set(false),
|
||||
admin: ActiveValue::Set(is_admin),
|
||||
..Default::default()
|
||||
admin: ActiveValue::Set(role == ChannelRole::Admin),
|
||||
role: ActiveValue::Set(Some(role)),
|
||||
}
|
||||
.insert(&*tx)
|
||||
.await?;
|
||||
|
@ -417,7 +419,13 @@ impl Database {
|
|||
|
||||
let channels_with_admin_privileges = channel_memberships
|
||||
.iter()
|
||||
.filter_map(|membership| membership.admin.then_some(membership.channel_id))
|
||||
.filter_map(|membership| {
|
||||
if membership.role == Some(ChannelRole::Admin) || membership.admin {
|
||||
Some(membership.channel_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let graph = self
|
||||
|
@ -470,12 +478,12 @@ impl Database {
|
|||
.await
|
||||
}
|
||||
|
||||
pub async fn set_channel_member_admin(
|
||||
pub async fn set_channel_member_role(
|
||||
&self,
|
||||
channel_id: ChannelId,
|
||||
from: UserId,
|
||||
for_user: UserId,
|
||||
admin: bool,
|
||||
role: ChannelRole,
|
||||
) -> Result<()> {
|
||||
self.transaction(|tx| async move {
|
||||
self.check_user_is_channel_admin(channel_id, from, &*tx)
|
||||
|
@ -488,7 +496,8 @@ impl Database {
|
|||
.and(channel_member::Column::UserId.eq(for_user)),
|
||||
)
|
||||
.set(channel_member::ActiveModel {
|
||||
admin: ActiveValue::set(admin),
|
||||
admin: ActiveValue::set(role == ChannelRole::Admin),
|
||||
role: ActiveValue::set(Some(role)),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&*tx)
|
||||
|
@ -516,6 +525,7 @@ impl Database {
|
|||
enum QueryMemberDetails {
|
||||
UserId,
|
||||
Admin,
|
||||
Role,
|
||||
IsDirectMember,
|
||||
Accepted,
|
||||
}
|
||||
|
@ -528,6 +538,7 @@ impl Database {
|
|||
.select_only()
|
||||
.column(channel_member::Column::UserId)
|
||||
.column(channel_member::Column::Admin)
|
||||
.column(channel_member::Column::Role)
|
||||
.column_as(
|
||||
channel_member::Column::ChannelId.eq(channel_id),
|
||||
QueryMemberDetails::IsDirectMember,
|
||||
|
@ -540,9 +551,10 @@ impl Database {
|
|||
|
||||
let mut rows = Vec::<proto::ChannelMember>::new();
|
||||
while let Some(row) = stream.next().await {
|
||||
let (user_id, is_admin, is_direct_member, is_invite_accepted): (
|
||||
let (user_id, is_admin, channel_role, is_direct_member, is_invite_accepted): (
|
||||
UserId,
|
||||
bool,
|
||||
Option<ChannelRole>,
|
||||
bool,
|
||||
bool,
|
||||
) = row?;
|
||||
|
@ -558,7 +570,7 @@ impl Database {
|
|||
if last_row.user_id == user_id {
|
||||
if is_direct_member {
|
||||
last_row.kind = kind;
|
||||
last_row.admin = is_admin;
|
||||
last_row.admin = channel_role == Some(ChannelRole::Admin) || is_admin;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -566,7 +578,7 @@ impl Database {
|
|||
rows.push(proto::ChannelMember {
|
||||
user_id,
|
||||
kind,
|
||||
admin: is_admin,
|
||||
admin: channel_role == Some(ChannelRole::Admin) || is_admin,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::db::{channel_member, ChannelId, ChannelMemberId, UserId};
|
||||
use crate::db::{channel_member, ChannelId, ChannelMemberId, ChannelRole, UserId};
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "channel_members")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
|
@ -10,6 +10,8 @@ pub struct Model {
|
|||
pub user_id: UserId,
|
||||
pub accepted: bool,
|
||||
pub admin: bool,
|
||||
// only optional while migrating
|
||||
pub role: Option<ChannelRole>,
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
|
|
@ -56,7 +56,7 @@ async fn test_channel_buffers(db: &Arc<Database>) {
|
|||
|
||||
let zed_id = db.create_root_channel("zed", a_id).await.unwrap();
|
||||
|
||||
db.invite_channel_member(zed_id, b_id, a_id, false)
|
||||
db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -211,7 +211,7 @@ async fn test_channel_buffers_last_operations(db: &Database) {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
db.invite_channel_member(channel, observer_id, user_id, false)
|
||||
db.invite_channel_member(channel, observer_id, user_id, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
db.respond_to_channel_invite(channel, observer_id, true)
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
|||
db::{
|
||||
queries::channels::ChannelGraph,
|
||||
tests::{graph, TEST_RELEASE_CHANNEL},
|
||||
ChannelId, Database, NewUserParams,
|
||||
ChannelId, ChannelRole, Database, NewUserParams,
|
||||
},
|
||||
test_both_dbs,
|
||||
};
|
||||
|
@ -50,7 +50,7 @@ async fn test_channels(db: &Arc<Database>) {
|
|||
// Make sure that people cannot read channels they haven't been invited to
|
||||
assert!(db.get_channel(zed_id, b_id).await.unwrap().is_none());
|
||||
|
||||
db.invite_channel_member(zed_id, b_id, a_id, false)
|
||||
db.invite_channel_member(zed_id, b_id, a_id, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -125,9 +125,13 @@ async fn test_channels(db: &Arc<Database>) {
|
|||
);
|
||||
|
||||
// Update member permissions
|
||||
let set_subchannel_admin = db.set_channel_member_admin(crdb_id, a_id, b_id, true).await;
|
||||
let set_subchannel_admin = db
|
||||
.set_channel_member_role(crdb_id, a_id, b_id, ChannelRole::Admin)
|
||||
.await;
|
||||
assert!(set_subchannel_admin.is_err());
|
||||
let set_channel_admin = db.set_channel_member_admin(zed_id, a_id, b_id, true).await;
|
||||
let set_channel_admin = db
|
||||
.set_channel_member_role(zed_id, a_id, b_id, ChannelRole::Admin)
|
||||
.await;
|
||||
assert!(set_channel_admin.is_ok());
|
||||
|
||||
let result = db.get_channels_for_user(b_id).await.unwrap();
|
||||
|
@ -284,13 +288,13 @@ async fn test_channel_invites(db: &Arc<Database>) {
|
|||
|
||||
let channel_1_2 = db.create_root_channel("channel_2", user_1).await.unwrap();
|
||||
|
||||
db.invite_channel_member(channel_1_1, user_2, user_1, false)
|
||||
db.invite_channel_member(channel_1_1, user_2, user_1, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
db.invite_channel_member(channel_1_2, user_2, user_1, false)
|
||||
db.invite_channel_member(channel_1_2, user_2, user_1, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
db.invite_channel_member(channel_1_1, user_3, user_1, true)
|
||||
db.invite_channel_member(channel_1_1, user_3, user_1, ChannelRole::Admin)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
db::{Database, MessageId, NewUserParams},
|
||||
db::{ChannelRole, Database, MessageId, NewUserParams},
|
||||
test_both_dbs,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
@ -155,7 +155,7 @@ async fn test_channel_message_new_notification(db: &Arc<Database>) {
|
|||
|
||||
let channel_2 = db.create_channel("channel-2", None, user).await.unwrap();
|
||||
|
||||
db.invite_channel_member(channel_1, observer, user, false)
|
||||
db.invite_channel_member(channel_1, observer, user, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -163,7 +163,7 @@ async fn test_channel_message_new_notification(db: &Arc<Database>) {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
db.invite_channel_member(channel_2, observer, user, false)
|
||||
db.invite_channel_member(channel_2, observer, user, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ mod connection_pool;
|
|||
use crate::{
|
||||
auth,
|
||||
db::{
|
||||
self, BufferId, ChannelId, ChannelsForUser, Database, MessageId, ProjectId, RoomId,
|
||||
ServerId, User, UserId,
|
||||
self, BufferId, ChannelId, ChannelRole, ChannelsForUser, Database, MessageId, ProjectId,
|
||||
RoomId, ServerId, User, UserId,
|
||||
},
|
||||
executor::Executor,
|
||||
AppState, Result,
|
||||
|
@ -2282,7 +2282,12 @@ async fn invite_channel_member(
|
|||
let db = session.db().await;
|
||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||
let invitee_id = UserId::from_proto(request.user_id);
|
||||
db.invite_channel_member(channel_id, invitee_id, session.user_id, request.admin)
|
||||
let role = if request.admin {
|
||||
ChannelRole::Admin
|
||||
} else {
|
||||
ChannelRole::Member
|
||||
};
|
||||
db.invite_channel_member(channel_id, invitee_id, session.user_id, role)
|
||||
.await?;
|
||||
|
||||
let (channel, _) = db
|
||||
|
@ -2342,7 +2347,12 @@ async fn set_channel_member_admin(
|
|||
let db = session.db().await;
|
||||
let channel_id = ChannelId::from_proto(request.channel_id);
|
||||
let member_id = UserId::from_proto(request.user_id);
|
||||
db.set_channel_member_admin(channel_id, session.user_id, member_id, request.admin)
|
||||
let role = if request.admin {
|
||||
ChannelRole::Admin
|
||||
} else {
|
||||
ChannelRole::Member
|
||||
};
|
||||
db.set_channel_member_role(channel_id, session.user_id, member_id, role)
|
||||
.await?;
|
||||
|
||||
let (channel, has_accepted) = db
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::db::ChannelRole;
|
||||
|
||||
use super::{run_randomized_test, RandomizedTest, TestClient, TestError, TestServer, UserTestPlan};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
|
@ -50,7 +52,7 @@ impl RandomizedTest for RandomChannelBufferTest {
|
|||
.await
|
||||
.unwrap();
|
||||
for user in &users[1..] {
|
||||
db.invite_channel_member(id, user.user_id, users[0].user_id, false)
|
||||
db.invite_channel_member(id, user.user_id, users[0].user_id, ChannelRole::Member)
|
||||
.await
|
||||
.unwrap();
|
||||
db.respond_to_channel_invite(id, user.user_id, true)
|
||||
|
|
Loading…
Reference in a new issue