Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ CREATE TABLE galley_test.team_features (
mls_default_protocol int,
mls_protocol_toggle_users set<uuid>,
mls_status int,
outlook_cal_integration_lock_status int,
outlook_cal_integration_status int,
search_visibility_inbound_status int,
search_visibility_status int,
self_deleting_messages_lock_status int,
Expand Down
1 change: 1 addition & 0 deletions changelog.d/2-features/pr-3025
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature flag for Outlook calendar integration
4 changes: 4 additions & 0 deletions charts/galley/templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,9 @@ data:
mls:
{{- toYaml .settings.featureFlags.mls | nindent 10 }}
{{- end }}
{{- if .settings.featureFlags.outlookCalIntegration }}
outlookCalIntegration:
{{- toYaml .settings.featureFlags.outlookCalIntegration | nindent 10 }}
{{- end }}
{{- end }}
{{- end }}
4 changes: 4 additions & 0 deletions charts/galley/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ config:
validateSAMLemails:
defaults:
status: enabled
outlookCalIntegration:
defaults:
status: disabled
lockStatus: locked

aws:
region: "eu-west-1"
Expand Down
14 changes: 14 additions & 0 deletions docs/src/developer/reference/config-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,20 @@ federator:
clientPrivateKey: client-key.pem
```

## Outlook calalendar integration

This feature setting only applies to the Outlook Calendar extension for Wire. As it is an external service, it should only be configured through this feature flag and otherwise ignored by the backend.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/As it is an external service, it should only be configured through this feature flag and otherwise ignored by the backend./This does not change the behavior of the backend, but it will be consulted by the [calendar integration service](TODO: which repo? ask dejan?), which will adopt its behavior accordingly./


Example default configuration:

```yaml
# galley.yaml
outlookCalIntegration:
defaults:
status: disabled
lockStatus: locked
```

## Settings in brig

Some features (as of the time of writing this: only
Expand Down
9 changes: 7 additions & 2 deletions libs/galley-types/src/Galley/Types/Teams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module Galley.Types.Teams
flagsTeamFeatureValidateSAMLEmailsStatus,
flagTeamFeatureSndFactorPasswordChallengeStatus,
flagTeamFeatureSearchVisibilityInbound,
flagOutlookCalIntegration,
flagMLS,
Defaults (..),
ImplicitLockStatus (..),
Expand Down Expand Up @@ -150,7 +151,8 @@ data FeatureFlags = FeatureFlags
_flagsTeamFeatureValidateSAMLEmailsStatus :: !(Defaults (ImplicitLockStatus ValidateSAMLEmailsConfig)),
_flagTeamFeatureSndFactorPasswordChallengeStatus :: !(Defaults (WithStatus SndFactorPasswordChallengeConfig)),
_flagTeamFeatureSearchVisibilityInbound :: !(Defaults (ImplicitLockStatus SearchVisibilityInboundConfig)),
_flagMLS :: !(Defaults (ImplicitLockStatus MLSConfig))
_flagMLS :: !(Defaults (ImplicitLockStatus MLSConfig)),
_flagOutlookCalIntegration :: !(Defaults (WithStatus OutlookCalIntegrationConfig))
}
deriving (Eq, Show, Generic)

Expand Down Expand Up @@ -200,6 +202,7 @@ instance FromJSON FeatureFlags where
<*> (fromMaybe (Defaults (defFeatureStatus @SndFactorPasswordChallengeConfig)) <$> (obj .:? "sndFactorPasswordChallenge"))
<*> withImplicitLockStatusOrDefault obj "searchVisibilityInbound"
<*> withImplicitLockStatusOrDefault obj "mls"
<*> (fromMaybe (Defaults (defFeatureStatus @OutlookCalIntegrationConfig)) <$> (obj .:? "outlookCalIntegration"))
where
withImplicitLockStatusOrDefault :: forall cfg. (IsFeatureConfig cfg, Schema.ToSchema cfg) => Object -> Key -> A.Parser (Defaults (ImplicitLockStatus cfg))
withImplicitLockStatusOrDefault obj fieldName = fromMaybe (Defaults (ImplicitLockStatus (defFeatureStatus @cfg))) <$> obj .:? fieldName
Expand All @@ -220,6 +223,7 @@ instance ToJSON FeatureFlags where
sndFactorPasswordChallenge
searchVisibilityInbound
mls
outlookCalIntegration
) =
object
[ "sso" .= sso,
Expand All @@ -234,7 +238,8 @@ instance ToJSON FeatureFlags where
"validateSAMLEmails" .= validateSAMLEmails,
"sndFactorPasswordChallenge" .= sndFactorPasswordChallenge,
"searchVisibilityInbound" .= searchVisibilityInbound,
"mls" .= mls
"mls" .= mls,
"outlookCalIntegration" .= outlookCalIntegration
]

instance FromJSON FeatureSSO where
Expand Down
1 change: 1 addition & 0 deletions libs/galley-types/test/unit/Test/Galley/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ instance Arbitrary FeatureFlags where
<*> arbitrary
<*> fmap (fmap unlocked) arbitrary
<*> fmap (fmap unlocked) arbitrary
<*> arbitrary
where
unlocked :: ImplicitLockStatus a -> ImplicitLockStatus a
unlocked = ImplicitLockStatus . Public.setLockStatus Public.LockStatusUnlocked . _unImplicitLockStatus
2 changes: 2 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Public/Galley/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ type FeatureAPI =
:<|> FeatureStatusPut '[] '() ExposeInvitationURLsToTeamAdminConfig
:<|> FeatureStatusGet SearchVisibilityInboundConfig
:<|> FeatureStatusPut '[] '() SearchVisibilityInboundConfig
:<|> FeatureStatusGet OutlookCalIntegrationConfig
:<|> FeatureStatusPut '[] '() OutlookCalIntegrationConfig
:<|> AllFeatureConfigsUserGet
:<|> AllFeatureConfigsTeamGet
:<|> FeatureConfigDeprecatedGet "The usage of this endpoint was removed in iOS in version 3.101. It is not used by team management, or webapp, and is potentially used by the old Android client as of June 2022" LegalholdConfig
Expand Down
44 changes: 38 additions & 6 deletions libs/wire-api/src/Wire/API/Team/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ module Wire.API.Team.Feature
AppLockConfig (..),
FileSharingConfig (..),
MLSConfig (..),
OutlookCalIntegrationConfig (..),
AllFeatureConfigs (..),
typeFeatureTTL,
unImplicitLockStatus,
Expand Down Expand Up @@ -120,11 +121,11 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- 1. Add a data type for your feature's "config" part, naming convention:
-- **<NameOfFeature>Config**. If your feature doesn't have a config besides
-- being enabled/disabled, locked/unlocked, then the config should be a unit
-- type, e.g. **data MyFeatureConfig = MyFeatureConfig**. Implement type clases
-- type, e.g. **data MyFeatureConfig = MyFeatureConfig**. Implement type classes
-- 'ToSchema', 'IsFeatureConfig' and 'Arbitrary'. If your feature doesn't have a
-- config implement 'FeatureTrivialConfig'.
--
-- 2. Add the config to to 'AllFeatureConfigs'. Add your feature to 'allFeatureModels'.
-- 2. Add the config to to 'AllFeatureConfigs'.
--
-- 3. If your feature is configurable on a per-team basis, add a schema
-- migration in galley and add 'FeatureStatusCassandra' instance in
Expand All @@ -137,21 +138,29 @@ import Wire.Arbitrary (Arbitrary, GenericUniform (..))
-- Galley.API.Teams.Features which defines the main business logic for getting
-- and setting (with side-effects).
--
-- 6. Add public routes to Routes.Public.Galley: 'FeatureStatusGet',
-- 6. Add public routes to Wire.API.Routes.Public.Galley.Feature: 'FeatureStatusGet',
-- 'FeatureStatusPut' (optional) and by by user: 'FeatureConfigGet'. Then
-- implement them in Galley.API.Public.
-- implement them in Galley.API.Public.Feature.
--
-- 7. Add internal routes in Galley.API.Internal
--
-- 8. If the feature should be configurable via Stern add routes to Stern.API.
-- Manually check that the swagger looks okay.
-- Manually check that the swagger looks okay and works.
--
-- 9. If the feature is configured on a per-user level, see the
-- 'ConferenceCallingConfig' as an example.
-- (https://github.com/wireapp/wire-server/pull/1811,
-- https://github.com/wireapp/wire-server/pull/1818)
--
-- 10. Extend the integration tests with cases
--
-- 11. Edit/update the configurations:
-- - optionally add the config for local integration tests to 'galley.integration.yaml'
-- - add a config mapping to 'charts/galley/templates/configmap.yaml'
-- - add the defaults to 'charts/galley/values.yaml'
-- - optionally add config for CI to 'hack/helm_vars/wire-server/values.yaml'
--
-- 12. Add a section to the documentation at an appropriate place (e.g. 'docs/src/developer/reference/config-options.md' or 'docs/src/understand/team-feature-settings.md')
class IsFeatureConfig cfg where
type FeatureSymbol cfg :: Symbol
defFeatureStatus :: WithStatus cfg
Expand Down Expand Up @@ -852,6 +861,26 @@ instance ToSchema ExposeInvitationURLsToTeamAdminConfig where
instance FeatureTrivialConfig ExposeInvitationURLsToTeamAdminConfig where
trivialConfig = ExposeInvitationURLsToTeamAdminConfig

----------------------------------------------------------------------
-- OutlookCalIntegrationConfig

-- | This feature setting only applies to the Outlook Calendar extension for Wire.
-- As it is an external service, it should only be configured through this feature flag and otherwise ignored by the backend.
data OutlookCalIntegrationConfig = OutlookCalIntegrationConfig
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform OutlookCalIntegrationConfig)

instance IsFeatureConfig OutlookCalIntegrationConfig where
type FeatureSymbol OutlookCalIntegrationConfig = "outlookCalIntegration"
defFeatureStatus = withStatus FeatureStatusDisabled LockStatusLocked OutlookCalIntegrationConfig FeatureTTLUnlimited
objectSchema = pure OutlookCalIntegrationConfig

instance ToSchema OutlookCalIntegrationConfig where
schema = object "OutlookCalIntegrationConfig" objectSchema

instance FeatureTrivialConfig OutlookCalIntegrationConfig where
trivialConfig = OutlookCalIntegrationConfig

----------------------------------------------------------------------
-- FeatureStatus

Expand Down Expand Up @@ -926,7 +955,8 @@ data AllFeatureConfigs = AllFeatureConfigs
afcGuestLink :: WithStatus GuestLinksConfig,
afcSndFactorPasswordChallenge :: WithStatus SndFactorPasswordChallengeConfig,
afcMLS :: WithStatus MLSConfig,
afcExposeInvitationURLsToTeamAdmin :: WithStatus ExposeInvitationURLsToTeamAdminConfig
afcExposeInvitationURLsToTeamAdmin :: WithStatus ExposeInvitationURLsToTeamAdminConfig,
afcOutlookCalIntegration :: WithStatus OutlookCalIntegrationConfig
}
deriving stock (Eq, Show)
deriving (FromJSON, ToJSON, S.ToSchema) via (Schema AllFeatureConfigs)
Expand All @@ -950,6 +980,7 @@ instance ToSchema AllFeatureConfigs where
<*> afcSndFactorPasswordChallenge .= featureField
<*> afcMLS .= featureField
<*> afcExposeInvitationURLsToTeamAdmin .= featureField
<*> afcOutlookCalIntegration .= featureField
where
featureField ::
forall cfg.
Expand All @@ -975,5 +1006,6 @@ instance Arbitrary AllFeatureConfigs where
<*> arbitrary
<*> arbitrary
<*> arbitrary
<*> arbitrary

makeLenses ''ImplicitLockStatus
1 change: 1 addition & 0 deletions services/galley/galley.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,7 @@ executable galley-schema
V75_MLSGroupInfo
V76_ProposalOrigin
V77_MLSGroupMemberClient
V78_TeamFeatureOutlookCalIntegration

hs-source-dirs: schema/src
default-extensions:
Expand Down
4 changes: 4 additions & 0 deletions services/galley/galley.integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ settings:
conferenceCalling:
defaults:
status: enabled
outlookCalIntegration:
defaults:
status: disabled
lockStatus: locked

logLevel: Info
logNetStrings: false
Expand Down
4 changes: 3 additions & 1 deletion services/galley/schema/src/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ import qualified V74_ExposeInvitationsToTeamAdmin
import qualified V75_MLSGroupInfo
import qualified V76_ProposalOrigin
import qualified V77_MLSGroupMemberClient
import qualified V78_TeamFeatureOutlookCalIntegration

main :: IO ()
main = do
Expand Down Expand Up @@ -145,7 +146,8 @@ main = do
V74_ExposeInvitationsToTeamAdmin.migration,
V75_MLSGroupInfo.migration,
V76_ProposalOrigin.migration,
V77_MLSGroupMemberClient.migration
V77_MLSGroupMemberClient.migration,
V78_TeamFeatureOutlookCalIntegration.migration
-- When adding migrations here, don't forget to update
-- 'schemaVersion' in Galley.Cassandra
-- (see also docs/developer/cassandra-interaction.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <opensource@wire.com>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module V78_TeamFeatureOutlookCalIntegration
( migration,
)
where

import Cassandra.Schema
import Imports
import Text.RawString.QQ

migration :: Migration
migration = Migration 78 "Add feature config for team feature outlook calendar integration" $ do
schema'
[r| ALTER TABLE team_features ADD (
outlook_cal_integration_status int,
outlook_cal_integration_lock_status int
)
|]
9 changes: 9 additions & 0 deletions services/galley/src/Galley/API/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ type IFeatureAPI =
:<|> IFeatureStatusGet SearchVisibilityInboundConfig
:<|> IFeatureStatusPut '[] '() SearchVisibilityInboundConfig
:<|> IFeatureStatusPatch '[] '() SearchVisibilityInboundConfig
-- OutlookCalIntegrationConfig
:<|> IFeatureStatusGet OutlookCalIntegrationConfig
:<|> IFeatureStatusPut '[] '() OutlookCalIntegrationConfig
:<|> IFeatureStatusPatch '[] '() OutlookCalIntegrationConfig
:<|> IFeatureStatusLockStatusPut OutlookCalIntegrationConfig
-- all feature configs
:<|> Named
"feature-configs-internal"
Expand Down Expand Up @@ -571,6 +576,10 @@ featureAPI =
<@> mkNamedAPI @'("iget", SearchVisibilityInboundConfig) (getFeatureStatus @Cassandra DontDoAuth)
<@> mkNamedAPI @'("iput", SearchVisibilityInboundConfig) (setFeatureStatusInternal @Cassandra)
<@> mkNamedAPI @'("ipatch", SearchVisibilityInboundConfig) (patchFeatureStatusInternal @Cassandra)
<@> mkNamedAPI @'("iget", OutlookCalIntegrationConfig) (getFeatureStatus @Cassandra DontDoAuth)
<@> mkNamedAPI @'("iput", OutlookCalIntegrationConfig) (setFeatureStatusInternal @Cassandra)
<@> mkNamedAPI @'("ipatch", OutlookCalIntegrationConfig) (patchFeatureStatusInternal @Cassandra)
<@> mkNamedAPI @'("ilock", OutlookCalIntegrationConfig) (updateLockStatus @Cassandra @OutlookCalIntegrationConfig)
<@> mkNamedAPI @"feature-configs-internal" (maybe (getAllFeatureConfigsForServer @Cassandra) (getAllFeatureConfigsForUser @Cassandra))

internalSitemap :: Routes a (Sem GalleyEffects) ()
Expand Down
2 changes: 2 additions & 0 deletions services/galley/src/Galley/API/Public/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ featureAPI =
<@> mkNamedAPI @'("put", ExposeInvitationURLsToTeamAdminConfig) (setFeatureStatus @Cassandra . DoAuth)
<@> mkNamedAPI @'("get", SearchVisibilityInboundConfig) (getFeatureStatus @Cassandra . DoAuth)
<@> mkNamedAPI @'("put", SearchVisibilityInboundConfig) (setFeatureStatus @Cassandra . DoAuth)
<@> mkNamedAPI @'("get", OutlookCalIntegrationConfig) (getFeatureStatus @Cassandra . DoAuth)
<@> mkNamedAPI @'("put", OutlookCalIntegrationConfig) (setFeatureStatus @Cassandra . DoAuth)
<@> mkNamedAPI @"get-all-feature-configs-for-user" (getAllFeatureConfigsForUser @Cassandra)
<@> mkNamedAPI @"get-all-feature-configs-for-team" (getAllFeatureConfigsForTeam @Cassandra)
<@> mkNamedAPI @'("get-config", LegalholdConfig) (getFeatureStatusForUser @Cassandra)
Expand Down
13 changes: 12 additions & 1 deletion services/galley/src/Galley/API/Teams/Features.hs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@ type FeaturePersistentAllFeatures db =
FeaturePersistentConstraint db SndFactorPasswordChallengeConfig,
FeaturePersistentConstraint db MLSConfig,
FeaturePersistentConstraint db SearchVisibilityInboundConfig,
FeaturePersistentConstraint db ExposeInvitationURLsToTeamAdminConfig
FeaturePersistentConstraint db ExposeInvitationURLsToTeamAdminConfig,
FeaturePersistentConstraint db OutlookCalIntegrationConfig
)

getFeatureStatus ::
Expand Down Expand Up @@ -443,6 +444,7 @@ getAllFeatureConfigsForServer =
<*> getConfigForServer @db @SndFactorPasswordChallengeConfig
<*> getConfigForServer @db @MLSConfig
<*> getConfigForServer @db @ExposeInvitationURLsToTeamAdminConfig
<*> getConfigForServer @db @OutlookCalIntegrationConfig

getAllFeatureConfigsUser ::
forall db r.
Expand Down Expand Up @@ -477,6 +479,7 @@ getAllFeatureConfigsUser uid =
<*> getConfigForUser @db @SndFactorPasswordChallengeConfig uid
<*> getConfigForUser @db @MLSConfig uid
<*> getConfigForUser @db @ExposeInvitationURLsToTeamAdminConfig uid
<*> getConfigForUser @db @OutlookCalIntegrationConfig uid

getAllFeatureConfigsTeam ::
forall db r.
Expand Down Expand Up @@ -510,6 +513,7 @@ getAllFeatureConfigsTeam tid =
<*> getConfigForTeam @db @SndFactorPasswordChallengeConfig tid
<*> getConfigForTeam @db @MLSConfig tid
<*> getConfigForTeam @db @ExposeInvitationURLsToTeamAdminConfig tid
<*> getConfigForTeam @db @OutlookCalIntegrationConfig tid

-- | Note: this is an internal function which doesn't cover all features, e.g. LegalholdConfig
genericGetConfigForTeam ::
Expand Down Expand Up @@ -899,6 +903,13 @@ instance SetFeatureConfig db ExposeInvitationURLsToTeamAdminConfig where
LockStatusLocked -> throwS @OperationDenied
LockStatusUnlocked -> persistAndPushEvent @db tid wsnl

instance SetFeatureConfig db OutlookCalIntegrationConfig where
setConfigForTeam tid wsnl = persistAndPushEvent @db tid wsnl
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check lock status like in ExposeInvitationURLsToTeamAdminConfig above?

Copy link
Contributor Author

@battermann battermann Jan 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, we don't want to check if the feature is locked here. This is an internal function and the necessary checks should already been made before this is called. And specifically for PATCH we want to allow overriding the team feature status even if locked because this is used by IBIS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then why does the instance above do it? and why would ibis be allowed to break locks? ah, i see. it's locked for team admins, but ibis still needs to touch it.

oh dear what a mess.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why the function above does the check, either. I am currently trying to clarify this. Maybe it is a mistake.

It used to be much messier, believe me :)


instance GetFeatureConfig db OutlookCalIntegrationConfig where
getConfigForServer =
input <&> view (optSettings . setFeatureFlags . flagOutlookCalIntegration . unDefaults)

-- -- | If second factor auth is enabled, make sure that end-points that don't support it, but should, are blocked completely. (This is a workaround until we have 2FA for those end-points as well.)
-- --
-- This function exists to resolve a cyclic dependency.
Expand Down
2 changes: 1 addition & 1 deletion services/galley/src/Galley/Cassandra.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ module Galley.Cassandra (schemaVersion) where
import Imports

schemaVersion :: Int32
schemaVersion = 77
schemaVersion = 78
7 changes: 7 additions & 0 deletions services/galley/src/Galley/Cassandra/TeamFeatures.hs
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,10 @@ instance FeatureStatusCassandra MLSConfig where
instance FeatureStatusCassandra ExposeInvitationURLsToTeamAdminConfig where
getFeatureConfig _ = getTrivialConfigC "expose_invitation_urls_to_team_admin"
setFeatureConfig _ tid statusNoLock = setFeatureStatusC "expose_invitation_urls_to_team_admin" tid (wssStatus statusNoLock)

instance FeatureStatusCassandra OutlookCalIntegrationConfig where
getFeatureConfig _ = getTrivialConfigC "outlook_cal_integration_status"
setFeatureConfig _ tid statusNoLock = setFeatureStatusC "outlook_cal_integration_status" tid (wssStatus statusNoLock)

getFeatureLockStatus _ = getLockStatusC "outlook_cal_integration_lock_status"
setFeatureLockStatus _ = setLockStatusC "outlook_cal_integration_lock_status"
Loading