Skip to content

Commit

Permalink
Conference calling flag should be locked by default
Browse files Browse the repository at this point in the history
  • Loading branch information
pcapriotti committed Jul 31, 2024
1 parent accf1ba commit 4af90ec
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 36 deletions.
8 changes: 8 additions & 0 deletions integration/test/API/GalleyInternal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ setTeamFeatureConfig domain team featureName payload = do
req <- baseRequest domain Galley Unversioned $ joinHttpPath ["i", "teams", tid, "features", fn]
submit "PUT" $ req & addJSON p

patchTeamFeatureConfig :: (HasCallStack, MakesValue domain, MakesValue team, MakesValue featureName, MakesValue payload) => domain -> team -> featureName -> payload -> App Response
patchTeamFeatureConfig domain team featureName payload = do
tid <- asString team
fn <- asString featureName
p <- make payload
req <- baseRequest domain Galley Unversioned $ joinHttpPath ["i", "teams", tid, "features", fn]
submit "PATCH" $ req & addJSON p

-- https://staging-nginz-https.zinfra.io/api-internal/swagger-ui/galley/#/galley/post_i_features_multi_teams_searchVisibilityInbound
getFeatureStatusMulti :: (HasCallStack, MakesValue domain, MakesValue featureName) => domain -> featureName -> [String] -> App Response
getFeatureStatusMulti domain featureName tids = do
Expand Down
45 changes: 29 additions & 16 deletions integration/test/Test/FeatureFlags.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ module Test.FeatureFlags where

import qualified API.Galley as Public
import qualified API.GalleyInternal as Internal
import Control.Concurrent (threadDelay)
import Control.Monad.Codensity (Codensity (runCodensity))
import Control.Monad.Reader
import qualified Data.Aeson as A
Expand Down Expand Up @@ -433,8 +432,9 @@ testAllFeatures = do
"appLock" .= defEnabledObj (object ["enforceAppLock" .= False, "inactivityTimeoutSecs" .= A.Number 60]),
"fileSharing" .= enabled,
"classifiedDomains" .= defEnabledObj (object ["domains" .= ["example.com"]]),
"conferenceCalling" .= defEnabledObj (object ["useSFTForOneToOneCalls" .= A.Bool False]),
"selfDeletingMessages" .= defEnabledObj (object ["enforcedTimeoutSeconds" .= A.Number 0]),
"conferenceCalling" .= confCalling def {lockStatus = Just "locked"},
"selfDeletingMessages"
.= defEnabledObj (object ["enforcedTimeoutSeconds" .= A.Number 0]),
"conversationGuestLinks" .= enabled,
"sndFactorPasswordChallenge" .= disabledLocked,
"mls"
Expand Down Expand Up @@ -791,34 +791,52 @@ testConferenceCalling = do
_testLockStatusWithConfig
"conferenceCalling"
Public.setTeamFeatureConfig
(confCalling def {lockStatus = Just "unlocked", ttl = Just (toJSON "unlimited")})
(confCalling def {lockStatus = Just "locked"})
(confCalling def {sft = toJSON True})
(confCalling def)
(confCalling def {sft = toJSON (0 :: Int)})

testConferenceCallingInternal :: (HasCallStack) => App ()
testConferenceCallingInternal = do
let defaultArgs = def {lockStatus = Just "unlocked", ttl = Just (toJSON "unlimited")}
let defaultArgs = def {lockStatus = Just "locked"}

(owner, tid, m : _) <- createTeam OwnDomain 2
nonTeamMember <- randomUser OwnDomain def
assertForbidden =<< Public.getTeamFeature nonTeamMember tid "conferenceCalling"
checkFeature "conferenceCalling" m tid (confCalling defaultArgs)

-- should receive an event
void $ withWebSocket m $ \ws -> do
-- unlock and enable
assertSuccess =<< Internal.patchTeamFeatureConfig owner tid "conferenceCalling" (object ["status" .= "enabled", "lockStatus" .= "unlocked"])
do
notif <- awaitMatch isFeatureConfigUpdateNotif ws
notif %. "payload.0.name" `shouldMatch` "conferenceCalling"
-- TODO: the patch event is currently wrong, and does not reflect the update
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs {status = "disabled", lockStatus = Just "locked"})
checkFeature "conferenceCalling" m tid (confCalling defaultArgs {status = "enabled", lockStatus = Just "unlocked"})

-- just disable
assertSuccess =<< Internal.setTeamFeatureConfig owner tid "conferenceCalling" (confCalling def {status = "disabled"})
do
notif <- awaitMatch isFeatureConfigUpdateNotif ws
notif %. "payload.0.name" `shouldMatch` "conferenceCalling"
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs {status = "disabled"})
checkFeature "conferenceCalling" m tid (confCalling defaultArgs {status = "disabled"})
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs {status = "disabled", lockStatus = Just "unlocked"})
checkFeature "conferenceCalling" m tid (confCalling defaultArgs {lockStatus = Just "unlocked"})

assertSuccess =<< Internal.setTeamFeatureConfig owner tid "conferenceCalling" (confCalling def)
-- re-enable
assertSuccess =<< Internal.setTeamFeatureConfig owner tid "conferenceCalling" (confCalling def {status = "enabled"})
do
notif <- awaitMatch isFeatureConfigUpdateNotif ws
notif %. "payload.0.name" `shouldMatch` "conferenceCalling"
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs)
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs {status = "enabled", lockStatus = Just "unlocked"})
checkFeature "conferenceCalling" m tid (confCalling defaultArgs {status = "enabled", lockStatus = Just "unlocked"})

-- restore initial state
assertSuccess =<< Internal.patchTeamFeatureConfig owner tid "conferenceCalling" (object ["status" .= "disabled", "lockStatus" .= "locked"])
do
notif <- awaitMatch isFeatureConfigUpdateNotif ws
notif %. "payload.0.name" `shouldMatch` "conferenceCalling"
notif %. "payload.0.data" `shouldMatch` (confCalling defaultArgs {lockStatus = Just "unlocked"})
checkFeature "conferenceCalling" m tid (confCalling defaultArgs)

_testLockStatusWithConfig ::
Expand Down Expand Up @@ -965,12 +983,7 @@ testPatchAppLock = do

testPatchConferenceCalling :: (HasCallStack) => App ()
testPatchConferenceCalling = do
let defCfg =
confCalling
def
{ lockStatus = Just "unlocked",
ttl = Just (toJSON "unlimited")
}
let defCfg = confCalling def {lockStatus = Just "locked"}
_testPatch "conferenceCalling" True defCfg (object ["lockStatus" .= "locked"])
_testPatch "conferenceCalling" True defCfg (object ["status" .= "disabled"])
_testPatch "conferenceCalling" True defCfg (object ["lockStatus" .= "locked", "status" .= "disabled"])
Expand Down
28 changes: 18 additions & 10 deletions integration/test/Test/FeatureFlags/User.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import qualified API.BrigInternal as I
import API.Galley
import qualified API.GalleyInternal as I
import SetupHelpers
import Test.FeatureFlags.Util
import Testlib.Prelude

testFeatureConferenceCallingForUser :: App ()
Expand All @@ -14,17 +13,26 @@ testFeatureConferenceCallingForUser = do
let featureName = "conferenceCalling"

-- set initial value at the team level
let initial =
confCalling
def
{ status = "enabled",
sft = toJSON True
}
assertSuccess =<< I.setTeamFeatureConfig OwnDomain tid featureName initial
let patch =
object
[ "lockStatus" .= "unlocked",
"status" .= "enabled",
"config" .= object ["useSFTForOneToOneCalls" .= True]
]

assertSuccess =<< I.patchTeamFeatureConfig OwnDomain tid featureName patch

-- set user value for both users
for_ [alice, bob] $ \u -> do
void $ I.putFeatureForUser u featureName (object ["status" .= "disabled"]) >>= getBody 200
void
$ I.putFeatureForUser
u
featureName
( object
[ "status" .= "disabled"
]
)
>>= getBody 200
config <- I.getFeatureForUser u featureName >>= getJSON 200
config %. "status" `shouldMatch` "disabled"

Expand Down Expand Up @@ -59,5 +67,5 @@ testFeatureConferenceCallingForUser = do
void $ I.deleteFeatureForUser bob featureName >>= getBody 200
features <- getFeaturesForUser bob >>= getJSON 200
config <- features %. featureName
config %. "status" `shouldMatch` "enabled"
config %. "status" `shouldMatch` "disabled"
config %. "config.useSFTForOneToOneCalls" `shouldMatch` False
6 changes: 2 additions & 4 deletions integration/test/Test/FeatureFlags/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ assertForbidden = assertLabel 403 "no-team-member"

data ConfCalling = ConfCalling
{ lockStatus :: Maybe String,
ttl :: Maybe Value,
status :: String,
sft :: Value
}
Expand All @@ -104,16 +103,15 @@ instance Default ConfCalling where
def =
ConfCalling
{ lockStatus = Nothing,
ttl = Nothing,
status = "enabled",
status = "disabled",
sft = toJSON False
}

confCalling :: ConfCalling -> Value
confCalling args =
object
$ ["lockStatus" .= s | s <- toList args.lockStatus]
<> ["ttl" .= s | s <- toList args.ttl]
<> ["ttl" .= "unlimited"]
<> [ "status" .= args.status,
"config"
.= object ["useSFTForOneToOneCalls" .= args.sft]
Expand Down
4 changes: 2 additions & 2 deletions libs/galley-types/src/Galley/Types/Teams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ data FeatureFlags = FeatureFlags
_flagAppLockDefaults :: !(Defaults (ImplicitLockStatus AppLockConfig)),
_flagClassifiedDomains :: !(ImplicitLockStatus ClassifiedDomainsConfig),
_flagFileSharing :: !(Defaults (WithStatus FileSharingConfig)),
_flagConferenceCalling :: !(Defaults (ImplicitLockStatus ConferenceCallingConfig)),
_flagConferenceCalling :: !(Defaults (WithStatus ConferenceCallingConfig)),
_flagSelfDeletingMessages :: !(Defaults (WithStatus SelfDeletingMessagesConfig)),
_flagConversationGuestLinks :: !(Defaults (WithStatus GuestLinksConfig)),
_flagsTeamFeatureValidateSAMLEmailsStatus :: !(Defaults (ImplicitLockStatus ValidateSAMLEmailsConfig)),
Expand Down Expand Up @@ -139,7 +139,7 @@ instance FromJSON FeatureFlags where
<*> withImplicitLockStatusOrDefault obj "appLock"
<*> (fromMaybe (ImplicitLockStatus (defFeatureStatus @ClassifiedDomainsConfig)) <$> (obj .:? "classifiedDomains"))
<*> (fromMaybe (Defaults (defFeatureStatus @FileSharingConfig)) <$> (obj .:? "fileSharing"))
<*> withImplicitLockStatusOrDefault obj "conferenceCalling"
<*> (fromMaybe (Defaults (defFeatureStatus @ConferenceCallingConfig)) <$> (obj .:? "conferenceCalling"))
<*> (fromMaybe (Defaults (defFeatureStatus @SelfDeletingMessagesConfig)) <$> (obj .:? "selfDeletingMessages"))
<*> (fromMaybe (Defaults (defFeatureStatus @GuestLinksConfig)) <$> (obj .:? "conversationGuestLinks"))
<*> withImplicitLockStatusOrDefault obj "validateSAMLEmails"
Expand Down
2 changes: 1 addition & 1 deletion libs/galley-types/test/unit/Test/Galley/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ instance Arbitrary FeatureFlags where
<*> fmap (fmap unlocked) arbitrary
<*> fmap unlocked arbitrary
<*> arbitrary
<*> fmap (fmap unlocked) arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> fmap (fmap unlocked) arbitrary
Expand Down
2 changes: 1 addition & 1 deletion libs/wire-api/src/Wire/API/Team/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ instance RenderableSymbol ConferenceCallingConfig where

instance IsFeatureConfig ConferenceCallingConfig where
type FeatureSymbol ConferenceCallingConfig = "conferenceCalling"
defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked def FeatureTTLUnlimited
defFeatureStatus = withStatus FeatureStatusEnabled LockStatusLocked def FeatureTTLUnlimited
featureSingleton = FeatureSingletonConferenceCallingConfig
objectSchema = fromMaybe def <$> optField "config" schema

Expand Down
5 changes: 5 additions & 0 deletions services/brig/brig.integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ optSettings:
# Remember to keep it the same in Galley.
setFederationDomain: example.com
setFeatureFlags: # see #RefConfigOptions in `/docs/reference`
conferenceCalling:
defaultForNew:
status: disabled
defaultForNull:
status: disabled
setFederationDomainConfigsUpdateFreq: 1
setFederationStrategy: allowAll
setFederationDomainConfigs:
Expand Down
3 changes: 2 additions & 1 deletion services/galley/galley.integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ settings:
lockStatus: unlocked
conferenceCalling:
defaults:
status: enabled
status: disabled
lockStatus: locked
outlookCalIntegration:
defaults:
status: disabled
Expand Down
2 changes: 1 addition & 1 deletion services/galley/src/Galley/API/Teams/Features/Get.hs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ instance GetFeatureConfig ConferenceCallingConfig where
)

getConfigForServer =
input <&> view (settings . featureFlags . flagConferenceCalling . unDefaults . unImplicitLockStatus)
input <&> view (settings . featureFlags . flagConferenceCalling . unDefaults)

getConfigForUser uid = do
wsnl <- getAccountConferenceCallingConfigClient uid
Expand Down

0 comments on commit 4af90ec

Please sign in to comment.