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
1 change: 1 addition & 0 deletions changelog.d/5-internal/sqservices-1169
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
New internal endpoint to configure the guest links team feature.
1 change: 1 addition & 0 deletions services/galley/galley.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ executable galley-schema
V54_TeamFeatureSelfDeletingMessages
V55_SelfDeletingMessagesLockStatus
V56_GuestLinksTeamFeatureStatus
V57_GuestLinksLockStatus
Paths_galley
hs-source-dirs:
schema/src
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 @@ -59,6 +59,7 @@ import qualified V53_AddRemoteConvStatus
import qualified V54_TeamFeatureSelfDeletingMessages
import qualified V55_SelfDeletingMessagesLockStatus
import qualified V56_GuestLinksTeamFeatureStatus
import qualified V57_GuestLinksLockStatus

main :: IO ()
main = do
Expand Down Expand Up @@ -103,7 +104,8 @@ main = do
V53_AddRemoteConvStatus.migration,
V54_TeamFeatureSelfDeletingMessages.migration,
V55_SelfDeletingMessagesLockStatus.migration,
V56_GuestLinksTeamFeatureStatus.migration
V56_GuestLinksTeamFeatureStatus.migration,
V57_GuestLinksLockStatus.migration
-- When adding migrations here, don't forget to update
-- 'schemaVersion' in Galley.Cassandra
-- (see also docs/developer/cassandra-interaction.md)
Expand Down
33 changes: 33 additions & 0 deletions services/galley/schema/src/V57_GuestLinksLockStatus.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2020 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 V57_GuestLinksLockStatus
( migration,
)
where

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

migration :: Migration
migration = Migration 57 "Add lock status for guest links team feature" $ do
schema'
[r| ALTER TABLE team_features ADD (
guest_links_lock_status int
Copy link
Contributor

Choose a reason for hiding this comment

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

should this be consistent with the symbol?

type KnownTeamFeatureNameSymbol 'TeamFeatureGuestLinks = "conversationGuestLinks"

)
|]
12 changes: 12 additions & 0 deletions services/galley/src/Galley/API/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,15 @@ data InternalApi routes = InternalApi
iTeamFeatureLockStatusSelfDeletingMessagesPut ::
routes
:- IFeatureStatusLockStatusPut 'Public.TeamFeatureSelfDeletingMessages,
iTeamFeatureStatusGuestLinksGet ::
routes
:- IFeatureStatusGet 'Public.WithLockStatus 'Public.TeamFeatureGuestLinks,
iTeamFeatureStatusGuestLinksPut ::
routes
:- IFeatureStatusPut 'Public.TeamFeatureGuestLinks,
iTeamFeatureLockStatusGuestLinksPut ::
routes
:- IFeatureStatusLockStatusPut 'Public.TeamFeatureGuestLinks,
-- This endpoint can lead to the following events being sent:
-- - MemberLeave event to members for all conversations the user was in
iDeleteUser ::
Expand Down Expand Up @@ -318,6 +327,9 @@ servantSitemap =
iTeamFeatureStatusSelfDeletingMessagesPut = iPutTeamFeature @'Public.TeamFeatureSelfDeletingMessages Features.setSelfDeletingMessagesInternal,
iTeamFeatureStatusSelfDeletingMessagesGet = iGetTeamFeature @'Public.WithLockStatus @'Public.TeamFeatureSelfDeletingMessages Features.getSelfDeletingMessagesInternal,
iTeamFeatureLockStatusSelfDeletingMessagesPut = Features.setLockStatus @'Public.TeamFeatureSelfDeletingMessages,
iTeamFeatureStatusGuestLinksGet = iGetTeamFeature @'Public.WithLockStatus @'Public.TeamFeatureGuestLinks Features.getGuestLinkInternal,
iTeamFeatureStatusGuestLinksPut = iPutTeamFeature @'Public.TeamFeatureGuestLinks Features.setGuestLinkInternal,
iTeamFeatureLockStatusGuestLinksPut = Features.setLockStatus @'Public.TeamFeatureGuestLinks,
iDeleteUser = rmUser,
iConnect = Create.createConnectConversation,
iUpsertOne2OneConversation = One2One.iUpsertOne2OneConversation
Expand Down
29 changes: 13 additions & 16 deletions services/galley/src/Galley/API/Teams/Features.hs
Original file line number Diff line number Diff line change
Expand Up @@ -590,8 +590,8 @@ getSelfDeletingMessagesInternal = \case
Right tid -> do
cfgDefault <- getCfgDefault
let defLockStatus = Public.tfwcapsLockStatus cfgDefault
(maybeFeatureStatus, fromMaybe defLockStatus -> lockStatus) <- TeamFeatures.getSelfDeletingMessagesStatus tid
pure $ case (lockStatus, maybeFeatureStatus) of
(mbFeatureStatus, fromMaybe defLockStatus -> lockStatus) <- TeamFeatures.getSelfDeletingMessagesStatus tid
pure $ case (lockStatus, mbFeatureStatus) of
(Public.Unlocked, Just featureStatus) ->
Public.TeamFeatureStatusWithConfigAndLockStatus
(Public.tfwcStatus featureStatus)
Expand All @@ -616,15 +616,14 @@ setSelfDeletingMessagesInternal ::
Public.TeamFeatureStatus 'Public.WithoutLockStatus 'Public.TeamFeatureSelfDeletingMessages ->
Sem r (Public.TeamFeatureStatus 'Public.WithoutLockStatus 'Public.TeamFeatureSelfDeletingMessages)
setSelfDeletingMessagesInternal tid st = do
dftLockStatus <- Public.tfwcapsLockStatus <$> getCfgDefault
guardLockStatus @'Public.TeamFeatureSelfDeletingMessages tid dftLockStatus
getDftLockStatus >>= guardLockStatus @'Public.TeamFeatureSelfDeletingMessages tid
let pushEvent =
pushFeatureConfigEvent tid $
Event.Event Event.Update Public.TeamFeatureSelfDeletingMessages (EdFeatureSelfDeletingMessagesChanged st)
TeamFeatures.setSelfDeletingMessagesStatus tid st <* pushEvent
where
getCfgDefault :: Sem r (Public.TeamFeatureStatusWithConfigAndLockStatus Public.TeamFeatureSelfDeletingMessagesConfig)
getCfgDefault = input <&> view (optSettings . setFeatureFlags . flagSelfDeletingMessages . unDefaults)
getDftLockStatus :: Sem r Public.LockStatusValue
getDftLockStatus = input <&> view (optSettings . setFeatureFlags . flagSelfDeletingMessages . unDefaults . to Public.tfwcapsLockStatus)

getGuestLinkInternal ::
forall r.
Expand All @@ -635,15 +634,14 @@ getGuestLinkInternal = \case
Left _ -> getCfgDefault
Right tid -> do
cfgDefault <- getCfgDefault
let defLockStatus = Public.tfwoapsLockStatus cfgDefault
maybeFeatureStatus <- TeamFeatures.getFeatureStatusNoConfig @'Public.TeamFeatureGuestLinks tid
pure $ case (defLockStatus, maybeFeatureStatus) of
(mbFeatureStatus, fromMaybe (Public.tfwoapsLockStatus cfgDefault) -> lockStatus) <- TeamFeatures.getFeatureStatusNoConfigAndLockStatus @'Public.TeamFeatureGuestLinks tid
pure $ case (lockStatus, mbFeatureStatus) of
(Public.Unlocked, Just featureStatus) ->
Public.TeamFeatureStatusNoConfigAndLockStatus
(Public.tfwoStatus featureStatus)
Public.Unlocked
(Public.Unlocked, Nothing) -> cfgDefault {Public.tfwoapsLockStatus = Public.Unlocked}
(Public.Locked, _) -> cfgDefault {Public.tfwoapsLockStatus = Public.Locked}
lockStatus
(Public.Unlocked, Nothing) -> cfgDefault {Public.tfwoapsLockStatus = lockStatus}
(Public.Locked, _) -> cfgDefault {Public.tfwoapsLockStatus = lockStatus}
where
getCfgDefault :: Sem r (Public.TeamFeatureStatus 'Public.WithLockStatus 'Public.TeamFeatureGuestLinks)
getCfgDefault = input <&> view (optSettings . setFeatureFlags . flagConversationGuestLinks . unDefaults)
Expand All @@ -661,8 +659,7 @@ setGuestLinkInternal ::
Public.TeamFeatureStatus 'Public.WithoutLockStatus 'Public.TeamFeatureGuestLinks ->
Sem r (Public.TeamFeatureStatus 'Public.WithoutLockStatus 'Public.TeamFeatureGuestLinks)
setGuestLinkInternal tid status = do
cfgDefault <- Public.tfwoapsLockStatus <$> getCfgDefault
guardLockStatus @'Public.TeamFeatureGuestLinks tid cfgDefault
getDftLockStatus >>= guardLockStatus @'Public.TeamFeatureGuestLinks tid
let pushEvent =
pushFeatureConfigEvent tid $
Event.Event
Expand All @@ -673,8 +670,8 @@ setGuestLinkInternal tid status = do
)
TeamFeatures.setFeatureStatusNoConfig @'Public.TeamFeatureGuestLinks tid status <* pushEvent
where
getCfgDefault :: Sem r (Public.TeamFeatureStatus 'Public.WithLockStatus 'Public.TeamFeatureGuestLinks)
getCfgDefault = input <&> view (optSettings . setFeatureFlags . flagConversationGuestLinks . unDefaults)
getDftLockStatus :: Sem r Public.LockStatusValue
getDftLockStatus = input <&> view (optSettings . setFeatureFlags . flagConversationGuestLinks . unDefaults . to Public.tfwoapsLockStatus)

-- TODO(fisx): move this function to a more suitable place / module.
guardLockStatus ::
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 = 56
schemaVersion = 57
3 changes: 0 additions & 3 deletions services/galley/src/Galley/Cassandra/TeamFeatures.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ import Polysemy
import Polysemy.Input
import Wire.API.Team.Feature

-- TODO(leif): according to the specs it should only be supported to read the lock status via the api
-- changes can only be made in the server configuration file
-- we can probably remove the lock status from the db?
getFeatureStatusNoConfigAndLockStatus ::
forall (a :: TeamFeatureName) m.
(MonadClient m, FeatureHasNoConfig 'WithoutLockStatus a, HasStatusCol a, HasLockStatusCol a) =>
Expand Down
3 changes: 2 additions & 1 deletion services/galley/src/Galley/Data/TeamFeatures.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ instance {-# OVERLAPPABLE #-} HasLockStatusCol a => MaybeHasLockStatusCol a wher
instance HasLockStatusCol 'TeamFeatureSelfDeletingMessages where
lockStatusCol = "self_deleting_messages_lock_status"

instance MaybeHasLockStatusCol 'TeamFeatureGuestLinks where maybeLockStatusCol = Nothing
instance HasLockStatusCol 'TeamFeatureGuestLinks where
lockStatusCol = "guest_links_lock_status"

instance MaybeHasLockStatusCol 'TeamFeatureLegalHold where maybeLockStatusCol = Nothing

Expand Down
59 changes: 46 additions & 13 deletions services/galley/test/integration/API/Teams/Feature.hs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ tests s =
test s "Feature Configs / Team Features Consistency" testFeatureConfigConsistency,
test s "ConferenceCalling" $ testSimpleFlag @'Public.TeamFeatureConferenceCalling Public.TeamFeatureEnabled,
test s "SelfDeletingMessages" testSelfDeletingMessages,
test s "ConversationGuestLinks" testGuestLinks
test s "ConversationGuestLinks - public API" testGuestLinksPublic,
test s "ConversationGuestLinks - internal API" testGuestLinksInternal
]

testSSO :: TestM ()
Expand Down Expand Up @@ -474,26 +475,58 @@ testSelfDeletingMessages = do
checkSetLockStatus Public.Unlocked
checkGet TeamFeatureDisabled 30 Public.Unlocked

testGuestLinks :: TestM ()
testGuestLinks = do
testGuestLinksInternal :: TestM ()
testGuestLinksInternal = do
galley <- view tsGalley
testGuestLinks
(const $ Util.getTeamFeatureFlagInternal Public.TeamFeatureGuestLinks)
(const $ Util.putTeamFeatureFlagInternal @'Public.TeamFeatureGuestLinks galley)
(Util.setLockStatusInternal @'Public.TeamFeatureGuestLinks galley)

testGuestLinksPublic :: TestM ()
testGuestLinksPublic = do
galley <- view tsGalley
testGuestLinks
(Util.getTeamFeatureFlagWithGalley Public.TeamFeatureGuestLinks galley)
(Util.putTeamFeatureFlagWithGalley @'Public.TeamFeatureGuestLinks galley)
(Util.setLockStatusInternal @'Public.TeamFeatureGuestLinks galley)

testGuestLinks ::
(UserId -> TeamId -> TestM ResponseLBS) ->
(UserId -> TeamId -> Public.TeamFeatureStatusNoConfig -> TestM ResponseLBS) ->
(TeamId -> Public.LockStatusValue -> TestM ResponseLBS) ->
TestM ()
testGuestLinks getStatus putStatus setLockStatusInternal = do
(owner, tid, []) <- Util.createBindingTeamWithNMembers 0
let checkGet :: HasCallStack => Public.TeamFeatureStatusValue -> Public.LockStatusValue -> TestM ()
checkGet status lock =
do
Util.getTeamFeatureFlagWithGalley Public.TeamFeatureGuestLinks galley owner tid
!!! responseJsonEither === const (Right (Public.TeamFeatureStatusNoConfigAndLockStatus status lock))
checkSet :: HasCallStack => Public.TeamFeatureStatusValue -> TestM ()
checkSet status =
do
Util.putTeamFeatureFlagWithGalley @'Public.TeamFeatureGuestLinks galley owner tid (Public.TeamFeatureStatusNoConfig status)
!!! statusCode === const 200
getStatus owner tid !!! do
statusCode === const 200
responseJsonEither === const (Right (Public.TeamFeatureStatusNoConfigAndLockStatus status lock))

checkSet :: HasCallStack => Public.TeamFeatureStatusValue -> Int -> TestM ()
checkSet status expectedStatusCode =
putStatus owner tid (Public.TeamFeatureStatusNoConfig status) !!! statusCode === const expectedStatusCode

checkSetLockStatusInternal :: HasCallStack => Public.LockStatusValue -> TestM ()
checkSetLockStatusInternal lockStatus =
setLockStatusInternal tid lockStatus !!! statusCode === const 200

checkGet Public.TeamFeatureEnabled Public.Unlocked
checkSet Public.TeamFeatureDisabled
checkSet Public.TeamFeatureDisabled 200
checkGet Public.TeamFeatureDisabled Public.Unlocked
checkSet Public.TeamFeatureEnabled
checkSet Public.TeamFeatureEnabled 200
checkGet Public.TeamFeatureEnabled Public.Unlocked
checkSet Public.TeamFeatureDisabled 200
checkGet Public.TeamFeatureDisabled Public.Unlocked
-- when locks status is locked the team default feature status should be returned
-- and the team feature status can not be changed
checkSetLockStatusInternal Public.Locked
checkGet Public.TeamFeatureEnabled Public.Locked
checkSet Public.TeamFeatureDisabled 409
-- when lock status is unlocked again the previously set feature status is restored
checkSetLockStatusInternal Public.Unlocked
checkGet Public.TeamFeatureDisabled Public.Unlocked

-- | Call 'GET /teams/:tid/features' and 'GET /feature-configs', and check if all
-- features are there.
Expand Down