From 35cd397a4042c64b40829fac9ca407f7a96c6704 Mon Sep 17 00:00:00 2001 From: Marshall Bowers Date: Fri, 16 Aug 2024 15:17:03 -0400 Subject: [PATCH] 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 --- .../20221109000000_test_schema.sql | 3 ++- ...8_add_enabled_for_all_to_feature_flags.sql | 1 + crates/collab/src/db/queries/users.rs | 18 +++++++++++--- crates/collab/src/db/tables/feature_flag.rs | 1 + .../collab/src/db/tests/feature_flag_tests.rs | 24 ++++++++++++------- 5 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 crates/collab/migrations/20240816181658_add_enabled_for_all_to_feature_flags.sql diff --git a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql index e2dd9cdf86..225971ec32 100644 --- a/crates/collab/migrations.sqlite/20221109000000_test_schema.sql +++ b/crates/collab/migrations.sqlite/20221109000000_test_schema.sql @@ -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"); diff --git a/crates/collab/migrations/20240816181658_add_enabled_for_all_to_feature_flags.sql b/crates/collab/migrations/20240816181658_add_enabled_for_all_to_feature_flags.sql new file mode 100644 index 0000000000..a56c87b97a --- /dev/null +++ b/crates/collab/migrations/20240816181658_add_enabled_for_all_to_feature_flags.sql @@ -0,0 +1 @@ +alter table feature_flags add column enabled_for_all boolean not null default false; diff --git a/crates/collab/src/db/queries/users.rs b/crates/collab/src/db/queries/users.rs index 6ae482c36b..251f5bec68 100644 --- a/crates/collab/src/db/queries/users.rs +++ b/crates/collab/src/db/queries/users.rs @@ -312,10 +312,11 @@ impl Database { } /// Creates a new feature flag. - pub async fn create_user_flag(&self, flag: &str) -> Result { + pub async fn create_user_flag(&self, flag: &str, enabled_for_all: bool) -> Result { 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 } diff --git a/crates/collab/src/db/tables/feature_flag.rs b/crates/collab/src/db/tables/feature_flag.rs index 41c1451c64..5bbfedd71e 100644 --- a/crates/collab/src/db/tables/feature_flag.rs +++ b/crates/collab/src/db/tables/feature_flag.rs @@ -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)] diff --git a/crates/collab/src/db/tests/feature_flag_tests.rs b/crates/collab/src/db/tests/feature_flag_tests.rs index 5269d5354f..972b45e1bc 100644 --- a/crates/collab/src/db/tests/feature_flag_tests.rs +++ b/crates/collab/src/db/tests/feature_flag_tests.rs @@ -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) { .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]); }