collab: Allow enabling feature flags for all users (#16372)

This PR adds a new `enabled_for_all` column to the `feature_flags` table
to allow enabling a feature flag for all users.

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-08-16 15:17:03 -04:00 committed by GitHub
parent 2180dbdb50
commit 35cd397a40
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 34 additions and 13 deletions

View file

@ -295,7 +295,8 @@ CREATE UNIQUE INDEX "index_channel_buffer_collaborators_on_channel_id_connection
CREATE TABLE "feature_flags" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
"flag" TEXT NOT NULL UNIQUE
"flag" TEXT NOT NULL UNIQUE,
"enabled_for_all" BOOLEAN NOT NULL DEFAULT false
);
CREATE INDEX "index_feature_flags" ON "feature_flags" ("id");

View file

@ -0,0 +1 @@
alter table feature_flags add column enabled_for_all boolean not null default false;

View file

@ -312,10 +312,11 @@ impl Database {
}
/// Creates a new feature flag.
pub async fn create_user_flag(&self, flag: &str) -> Result<FlagId> {
pub async fn create_user_flag(&self, flag: &str, enabled_for_all: bool) -> Result<FlagId> {
self.transaction(|tx| async move {
let flag = feature_flag::Entity::insert(feature_flag::ActiveModel {
flag: ActiveValue::set(flag.to_string()),
enabled_for_all: ActiveValue::set(enabled_for_all),
..Default::default()
})
.exec(&*tx)
@ -350,7 +351,15 @@ impl Database {
Flag,
}
let flags = user::Model {
let flags_enabled_for_all = feature_flag::Entity::find()
.filter(feature_flag::Column::EnabledForAll.eq(true))
.select_only()
.column(feature_flag::Column::Flag)
.into_values::<_, QueryAs>()
.all(&*tx)
.await?;
let flags_enabled_for_user = user::Model {
id: user,
..Default::default()
}
@ -361,7 +370,10 @@ impl Database {
.all(&*tx)
.await?;
Ok(flags)
let mut all_flags = HashSet::from_iter(flags_enabled_for_all);
all_flags.extend(flags_enabled_for_user);
Ok(all_flags.into_iter().collect())
})
.await
}

View file

@ -8,6 +8,7 @@ pub struct Model {
#[sea_orm(primary_key)]
pub id: FlagId,
pub flag: String,
pub enabled_for_all: bool,
}
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View file

@ -2,6 +2,7 @@ use crate::{
db::{Database, NewUserParams},
test_both_dbs,
};
use pretty_assertions::assert_eq;
use std::sync::Arc;
test_both_dbs!(
@ -37,22 +38,27 @@ async fn test_get_user_flags(db: &Arc<Database>) {
.unwrap()
.user_id;
const CHANNELS_ALPHA: &str = "channels-alpha";
const NEW_SEARCH: &str = "new-search";
const FEATURE_FLAG_ONE: &str = "brand-new-ux";
const FEATURE_FLAG_TWO: &str = "cool-feature";
const FEATURE_FLAG_THREE: &str = "feature-enabled-for-everyone";
let channels_flag = db.create_user_flag(CHANNELS_ALPHA).await.unwrap();
let search_flag = db.create_user_flag(NEW_SEARCH).await.unwrap();
let feature_flag_one = db.create_user_flag(FEATURE_FLAG_ONE, false).await.unwrap();
let feature_flag_two = db.create_user_flag(FEATURE_FLAG_TWO, false).await.unwrap();
db.create_user_flag(FEATURE_FLAG_THREE, true).await.unwrap();
db.add_user_flag(user_1, channels_flag).await.unwrap();
db.add_user_flag(user_1, search_flag).await.unwrap();
db.add_user_flag(user_1, feature_flag_one).await.unwrap();
db.add_user_flag(user_1, feature_flag_two).await.unwrap();
db.add_user_flag(user_2, channels_flag).await.unwrap();
db.add_user_flag(user_2, feature_flag_one).await.unwrap();
let mut user_1_flags = db.get_user_flags(user_1).await.unwrap();
user_1_flags.sort();
assert_eq!(user_1_flags, &[CHANNELS_ALPHA, NEW_SEARCH]);
assert_eq!(
user_1_flags,
&[FEATURE_FLAG_ONE, FEATURE_FLAG_TWO, FEATURE_FLAG_THREE]
);
let mut user_2_flags = db.get_user_flags(user_2).await.unwrap();
user_2_flags.sort();
assert_eq!(user_2_flags, &[CHANNELS_ALPHA]);
assert_eq!(user_2_flags, &[FEATURE_FLAG_ONE, FEATURE_FLAG_THREE]);
}