{-# LANGUAGE UndecidableSuperClasses #-}
{-# OPTIONS_GHC -Wno-ambiguous-fields #-}

-- 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 Galley.API.Teams.Features.Get
  ( getFeature,
    getFeatureInternal,
    getFeatureMulti,
    getAllTeamFeaturesForServer,
    getAllTeamFeaturesForTeam,
    getAllTeamFeaturesForUser,
    getSingleFeatureForUser,
    GetFeatureConfig (..),
    getFeatureForTeam,
    getFeatureForServer,
    guardSecondFactorDisabled,
    DoAuth (..),
    featureEnabledForTeam,
    toTeamStatus,
  )
where

import Control.Error (hush)
import Control.Lens
import Data.Default
import Data.Id
import Data.Kind
import Data.Qualified (Local, tUnqualified)
import Data.SOP
import Data.Tagged
import Galley.API.LegalHold.Team
import Galley.API.Util
import Galley.Effects
import Galley.Effects.BrigAccess (getAccountConferenceCallingConfigClient)
import Galley.Effects.ConversationStore as ConversationStore
import Galley.Effects.TeamFeatureStore
import Galley.Effects.TeamStore (getOneUserTeam, getTeamMember)
import Galley.Options
import Galley.Types.Teams
import Imports
import Polysemy
import Polysemy.Error
import Polysemy.Input
import Wire.API.Conversation (cnvmTeam)
import Wire.API.Error
import Wire.API.Error.Galley
import Wire.API.Routes.Internal.Galley.TeamFeatureNoConfigMulti qualified as Multi
import Wire.API.Team.Feature

data DoAuth = DoAuth UserId | DontDoAuth

type DefaultGetFeatureForUserConstraints cfg r =
  ( Member (Input Opts) r,
    Member TeamFeatureStore r,
    ComputeFeatureConstraints cfg r
  )

-- | Don't export methods of this typeclass
class
  ( IsFeatureConfig cfg,
    GetFeatureDefaults (FeatureDefaults cfg),
    NpProject cfg Features
  ) =>
  GetFeatureConfig cfg
  where
  type GetFeatureForUserConstraints cfg (r :: EffectRow) :: Constraint
  type
    GetFeatureForUserConstraints cfg (r :: EffectRow) =
      DefaultGetFeatureForUserConstraints cfg r

  type ComputeFeatureConstraints cfg (r :: EffectRow) :: Constraint
  type ComputeFeatureConstraints cfg r = ()

  getFeatureForUser ::
    (GetFeatureForUserConstraints cfg r) =>
    UserId ->
    Sem r (LockableFeature cfg)
  default getFeatureForUser ::
    (DefaultGetFeatureForUserConstraints cfg r) =>
    UserId ->
    Sem r (LockableFeature cfg)
  getFeatureForUser UserId
_ = Sem r (LockableFeature cfg)
forall cfg (r :: EffectRow).
(GetFeatureDefaults (FeatureDefaults cfg), NpProject cfg Features,
 Member (Input Opts) r) =>
Sem r (LockableFeature cfg)
getFeatureForServer

  computeFeature ::
    (ComputeFeatureConstraints cfg r) =>
    TeamId ->
    LockableFeature cfg ->
    DbFeature cfg ->
    Sem r (LockableFeature cfg)
  default computeFeature ::
    TeamId ->
    LockableFeature cfg ->
    DbFeature cfg ->
    Sem r (LockableFeature cfg)
  computeFeature TeamId
_tid LockableFeature cfg
defFeature DbFeature cfg
dbFeature =
    LockableFeature cfg -> Sem r (LockableFeature cfg)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LockableFeature cfg -> Sem r (LockableFeature cfg))
-> LockableFeature cfg -> Sem r (LockableFeature cfg)
forall a b. (a -> b) -> a -> b
$
      forall cfg.
LockableFeature cfg -> DbFeature cfg -> LockableFeature cfg
genericComputeFeature @cfg LockableFeature cfg
defFeature DbFeature cfg
dbFeature

getFeature ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    ComputeFeatureConstraints cfg r,
    Member (Input Opts) r,
    Member TeamFeatureStore r,
    Member (ErrorS 'NotATeamMember) r,
    Member TeamStore r
  ) =>
  UserId ->
  TeamId ->
  Sem r (LockableFeature cfg)
getFeature :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r,
 Member (ErrorS 'NotATeamMember) r, Member TeamStore r) =>
UserId -> TeamId -> Sem r (LockableFeature cfg)
getFeature UserId
uid TeamId
tid = do
  Sem r TeamMember -> Sem r ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Sem r TeamMember -> Sem r ()) -> Sem r TeamMember -> Sem r ()
forall a b. (a -> b) -> a -> b
$ TeamId -> UserId -> Sem r (Maybe TeamMember)
forall (r :: EffectRow).
Member TeamStore r =>
TeamId -> UserId -> Sem r (Maybe TeamMember)
getTeamMember TeamId
tid UserId
uid Sem r (Maybe TeamMember)
-> (Maybe TeamMember -> Sem r TeamMember) -> Sem r TeamMember
forall a b. Sem r a -> (a -> Sem r b) -> Sem r b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall {k} (e :: k) (r :: EffectRow) a.
Member (ErrorS e) r =>
Maybe a -> Sem r a
forall (e :: GalleyError) (r :: EffectRow) a.
Member (ErrorS e) r =>
Maybe a -> Sem r a
noteS @'NotATeamMember
  forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeam @cfg TeamId
tid

getFeatureInternal ::
  ( GetFeatureConfig cfg,
    ComputeFeatureConstraints cfg r,
    Member (Input Opts) r,
    Member (ErrorS 'TeamNotFound) r,
    Member TeamFeatureStore r,
    Member TeamStore r
  ) =>
  TeamId ->
  Sem r (LockableFeature cfg)
getFeatureInternal :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member (ErrorS 'TeamNotFound) r,
 Member TeamFeatureStore r, Member TeamStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureInternal TeamId
tid = do
  TeamId -> Sem r ()
forall (r :: EffectRow).
(Member (ErrorS 'TeamNotFound) r, Member TeamStore r) =>
TeamId -> Sem r ()
assertTeamExists TeamId
tid
  TeamId -> Sem r (LockableFeature cfg)
forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeam TeamId
tid

getFeatureMulti ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    ComputeFeatureConstraints cfg r,
    Member (Input Opts) r,
    Member TeamFeatureStore r
  ) =>
  Multi.TeamFeatureNoConfigMultiRequest ->
  Sem r (Multi.TeamFeatureNoConfigMultiResponse cfg)
getFeatureMulti :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r) =>
TeamFeatureNoConfigMultiRequest
-> Sem r (TeamFeatureNoConfigMultiResponse cfg)
getFeatureMulti (Multi.TeamFeatureNoConfigMultiRequest [TeamId]
tids) = do
  [(TeamId, LockableFeature cfg)]
cfgs <- forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member TeamFeatureStore r, Member (Input Opts) r) =>
[TeamId] -> Sem r [(TeamId, LockableFeature cfg)]
getFeatureForMultiTeam @cfg [TeamId]
tids
  let xs :: [TeamStatus cfg]
xs = (TeamId -> LockableFeature cfg -> TeamStatus cfg)
-> (TeamId, LockableFeature cfg) -> TeamStatus cfg
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry TeamId -> LockableFeature cfg -> TeamStatus cfg
forall cfg. TeamId -> LockableFeature cfg -> TeamStatus cfg
toTeamStatus ((TeamId, LockableFeature cfg) -> TeamStatus cfg)
-> [(TeamId, LockableFeature cfg)] -> [TeamStatus cfg]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(TeamId, LockableFeature cfg)]
cfgs
  TeamFeatureNoConfigMultiResponse cfg
-> Sem r (TeamFeatureNoConfigMultiResponse cfg)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TeamFeatureNoConfigMultiResponse cfg
 -> Sem r (TeamFeatureNoConfigMultiResponse cfg))
-> TeamFeatureNoConfigMultiResponse cfg
-> Sem r (TeamFeatureNoConfigMultiResponse cfg)
forall a b. (a -> b) -> a -> b
$ [TeamStatus cfg] -> TeamFeatureNoConfigMultiResponse cfg
forall {k} (cfg :: k).
[TeamStatus cfg] -> TeamFeatureNoConfigMultiResponse cfg
Multi.TeamFeatureNoConfigMultiResponse [TeamStatus cfg]
xs

toTeamStatus :: TeamId -> LockableFeature cfg -> Multi.TeamStatus cfg
toTeamStatus :: forall cfg. TeamId -> LockableFeature cfg -> TeamStatus cfg
toTeamStatus TeamId
tid LockableFeature cfg
feat = TeamId -> FeatureStatus -> TeamStatus cfg
forall {k} (cfg :: k). TeamId -> FeatureStatus -> TeamStatus cfg
Multi.TeamStatus TeamId
tid LockableFeature cfg
feat.status

getTeamAndCheckMembership ::
  ( Member TeamStore r,
    Member (ErrorS 'NotATeamMember) r,
    Member (ErrorS 'TeamNotFound) r
  ) =>
  UserId ->
  Sem r (Maybe TeamId)
getTeamAndCheckMembership :: forall (r :: EffectRow).
(Member TeamStore r, Member (ErrorS 'NotATeamMember) r,
 Member (ErrorS 'TeamNotFound) r) =>
UserId -> Sem r (Maybe TeamId)
getTeamAndCheckMembership UserId
uid = do
  Maybe TeamId
mTid <- UserId -> Sem r (Maybe TeamId)
forall (r :: EffectRow).
Member TeamStore r =>
UserId -> Sem r (Maybe TeamId)
getOneUserTeam UserId
uid
  Maybe TeamId -> (TeamId -> Sem r ()) -> Sem r ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ Maybe TeamId
mTid ((TeamId -> Sem r ()) -> Sem r ())
-> (TeamId -> Sem r ()) -> Sem r ()
forall a b. (a -> b) -> a -> b
$ \TeamId
tid -> do
    Maybe TeamMember
zusrMembership <- TeamId -> UserId -> Sem r (Maybe TeamMember)
forall (r :: EffectRow).
Member TeamStore r =>
TeamId -> UserId -> Sem r (Maybe TeamMember)
getTeamMember TeamId
tid UserId
uid
    Sem r TeamMember -> Sem r ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Sem r TeamMember -> Sem r ()) -> Sem r TeamMember -> Sem r ()
forall a b. (a -> b) -> a -> b
$ Sem r TeamMember
-> (TeamMember -> Sem r TeamMember)
-> Maybe TeamMember
-> Sem r TeamMember
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (forall {k} (e :: k) (r :: EffectRow) a.
Member (ErrorS e) r =>
Sem r a
forall (e :: GalleyError) (r :: EffectRow) a.
Member (ErrorS e) r =>
Sem r a
throwS @'NotATeamMember) TeamMember -> Sem r TeamMember
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe TeamMember
zusrMembership
    TeamId -> Sem r ()
forall (r :: EffectRow).
(Member (ErrorS 'TeamNotFound) r, Member TeamStore r) =>
TeamId -> Sem r ()
assertTeamExists TeamId
tid
  Maybe TeamId -> Sem r (Maybe TeamId)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe TeamId
mTid

getAllTeamFeaturesForTeam ::
  forall r.
  ( Member (Input Opts) r,
    Member (ErrorS 'NotATeamMember) r,
    Member LegalHoldStore r,
    Member TeamFeatureStore r,
    Member TeamStore r
  ) =>
  Local UserId ->
  TeamId ->
  Sem r AllTeamFeatures
getAllTeamFeaturesForTeam :: forall (r :: EffectRow).
(Member (Input Opts) r, Member (ErrorS 'NotATeamMember) r,
 Member LegalHoldStore r, Member TeamFeatureStore r,
 Member TeamStore r) =>
Local UserId -> TeamId -> Sem r AllTeamFeatures
getAllTeamFeaturesForTeam Local UserId
luid TeamId
tid = do
  Sem r TeamMember -> Sem r ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Sem r TeamMember -> Sem r ()) -> Sem r TeamMember -> Sem r ()
forall a b. (a -> b) -> a -> b
$ TeamId -> UserId -> Sem r (Maybe TeamMember)
forall (r :: EffectRow).
Member TeamStore r =>
TeamId -> UserId -> Sem r (Maybe TeamMember)
getTeamMember TeamId
tid (Local UserId -> UserId
forall (t :: QTag) a. QualifiedWithTag t a -> a
tUnqualified Local UserId
luid) Sem r (Maybe TeamMember)
-> (Maybe TeamMember -> Sem r TeamMember) -> Sem r TeamMember
forall a b. Sem r a -> (a -> Sem r b) -> Sem r b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall {k} (e :: k) (r :: EffectRow) a.
Member (ErrorS e) r =>
Maybe a -> Sem r a
forall (e :: GalleyError) (r :: EffectRow) a.
Member (ErrorS e) r =>
Maybe a -> Sem r a
noteS @'NotATeamMember
  TeamId -> Sem r AllTeamFeatures
forall (r :: EffectRow).
(Member (Input Opts) r, Member LegalHoldStore r,
 Member TeamFeatureStore r, Member TeamStore r) =>
TeamId -> Sem r AllTeamFeatures
getAllTeamFeatures TeamId
tid

class
  (GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) =>
  GetAllFeaturesForServerConstraints r cfg

instance
  (GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) =>
  GetAllFeaturesForServerConstraints r cfg

getAllTeamFeaturesForServer ::
  forall r.
  (Member (Input Opts) r) =>
  Sem r AllTeamFeatures
getAllTeamFeaturesForServer :: forall (r :: EffectRow).
Member (Input Opts) r =>
Sem r AllTeamFeatures
getAllTeamFeaturesForServer =
  NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall (xs :: [*]) (f :: * -> *) (g :: * -> *).
(SListIN NP xs, Applicative f) =>
NP (f :.: g) xs -> f (NP g xs)
forall k l (h :: (k -> *) -> l -> *) (xs :: l) (f :: * -> *)
       (g :: k -> *).
(HSequence h, SListIN h xs, Applicative f) =>
h (f :.: g) xs -> f (h g xs)
hsequence' (NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures)
-> NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall a b. (a -> b) -> a -> b
$
    Proxy GetFeatureConfig
-> (forall {a}.
    GetFeatureConfig a =>
    (:.:) (Sem r) LockableFeature a)
-> NP (Sem r :.: LockableFeature) Features
forall k l (h :: (k -> *) -> l -> *) (c :: k -> Constraint)
       (xs :: l) (proxy :: (k -> Constraint) -> *) (f :: k -> *).
(HPure h, AllN h c xs) =>
proxy c -> (forall (a :: k). c a => f a) -> h f xs
forall (c :: * -> Constraint) (xs :: [*])
       (proxy :: (* -> Constraint) -> *) (f :: * -> *).
AllN NP c xs =>
proxy c -> (forall a. c a => f a) -> NP f xs
hcpure (forall {k} (t :: k). Proxy t
forall (t :: * -> Constraint). Proxy t
Proxy @GetFeatureConfig) ((forall {a}.
  GetFeatureConfig a =>
  (:.:) (Sem r) LockableFeature a)
 -> NP (Sem r :.: LockableFeature) Features)
-> (forall {a}.
    GetFeatureConfig a =>
    (:.:) (Sem r) LockableFeature a)
-> NP (Sem r :.: LockableFeature) Features
forall a b. (a -> b) -> a -> b
$
      Sem r (LockableFeature a) -> (:.:) (Sem r) LockableFeature a
forall l k (f :: l -> *) (g :: k -> l) (p :: k).
f (g p) -> (:.:) f g p
Comp Sem r (LockableFeature a)
forall cfg (r :: EffectRow).
(GetFeatureDefaults (FeatureDefaults cfg), NpProject cfg Features,
 Member (Input Opts) r) =>
Sem r (LockableFeature cfg)
getFeatureForServer

getAllTeamFeatures ::
  forall r.
  ( Member (Input Opts) r,
    Member LegalHoldStore r,
    Member TeamFeatureStore r,
    Member TeamStore r
  ) =>
  TeamId ->
  Sem r AllTeamFeatures
getAllTeamFeatures :: forall (r :: EffectRow).
(Member (Input Opts) r, Member LegalHoldStore r,
 Member TeamFeatureStore r, Member TeamStore r) =>
TeamId -> Sem r AllTeamFeatures
getAllTeamFeatures TeamId
tid = do
  AllFeatures DbFeature
features <- TeamId -> Sem r (AllFeatures DbFeature)
forall (r :: EffectRow).
Member TeamFeatureStore r =>
TeamId -> Sem r (AllFeatures DbFeature)
getAllDbFeatures TeamId
tid
  AllTeamFeatures
defFeatures <- Sem r AllTeamFeatures
forall (r :: EffectRow).
Member (Input Opts) r =>
Sem r AllTeamFeatures
getAllTeamFeaturesForServer
  NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall (xs :: [*]) (f :: * -> *) (g :: * -> *).
(SListIN NP xs, Applicative f) =>
NP (f :.: g) xs -> f (NP g xs)
forall k l (h :: (k -> *) -> l -> *) (xs :: l) (f :: * -> *)
       (g :: k -> *).
(HSequence h, SListIN h xs, Applicative f) =>
h (f :.: g) xs -> f (h g xs)
hsequence' (NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures)
-> NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall a b. (a -> b) -> a -> b
$ Proxy (GetAllFeaturesForServerConstraints r)
-> (forall a.
    GetAllFeaturesForServerConstraints r a =>
    LockableFeature a
    -> DbFeature a -> (:.:) (Sem r) LockableFeature a)
-> Prod NP LockableFeature Features
-> AllFeatures DbFeature
-> NP (Sem r :.: LockableFeature) Features
forall {k} {l} (h :: (k -> *) -> l -> *) (c :: k -> Constraint)
       (xs :: l) (proxy :: (k -> Constraint) -> *) (f :: k -> *)
       (f' :: k -> *) (f'' :: k -> *).
(AllN (Prod h) c xs, HAp h, HAp (Prod h)) =>
proxy c
-> (forall (a :: k). c a => f a -> f' a -> f'' a)
-> Prod h f xs
-> h f' xs
-> h f'' xs
hcliftA2 (forall {k} (t :: k). Proxy t
forall (t :: * -> Constraint). Proxy t
Proxy @(GetAllFeaturesForServerConstraints r)) LockableFeature a -> DbFeature a -> (:.:) (Sem r) LockableFeature a
forall a.
GetAllFeaturesForServerConstraints r a =>
LockableFeature a -> DbFeature a -> (:.:) (Sem r) LockableFeature a
forall p.
(ComputeFeatureConstraints p r, GetFeatureConfig p) =>
LockableFeature p -> DbFeature p -> (:.:) (Sem r) LockableFeature p
compute Prod NP LockableFeature Features
AllTeamFeatures
defFeatures AllFeatures DbFeature
features
  where
    compute ::
      (ComputeFeatureConstraints p r, GetFeatureConfig p) =>
      LockableFeature p ->
      DbFeature p ->
      (Sem r :.: LockableFeature) p
    compute :: forall p.
(ComputeFeatureConstraints p r, GetFeatureConfig p) =>
LockableFeature p -> DbFeature p -> (:.:) (Sem r) LockableFeature p
compute LockableFeature p
defFeature DbFeature p
feat = Sem r (LockableFeature p) -> (:.:) (Sem r) LockableFeature p
forall l k (f :: l -> *) (g :: k -> l) (p :: k).
f (g p) -> (:.:) f g p
Comp (Sem r (LockableFeature p) -> (:.:) (Sem r) LockableFeature p)
-> Sem r (LockableFeature p) -> (:.:) (Sem r) LockableFeature p
forall a b. (a -> b) -> a -> b
$ TeamId
-> LockableFeature p -> DbFeature p -> Sem r (LockableFeature p)
forall (r :: EffectRow).
ComputeFeatureConstraints p r =>
TeamId
-> LockableFeature p -> DbFeature p -> Sem r (LockableFeature p)
forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) =>
TeamId
-> LockableFeature cfg
-> DbFeature cfg
-> Sem r (LockableFeature cfg)
computeFeature TeamId
tid LockableFeature p
defFeature DbFeature p
feat

class (GetFeatureForUserConstraints cfg r, GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) => GetAllTeamFeaturesForUserConstraints r cfg

instance (GetFeatureForUserConstraints cfg r, GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) => GetAllTeamFeaturesForUserConstraints r cfg

getAllTeamFeaturesForUser ::
  forall r.
  ( Member BrigAccess r,
    Member (ErrorS 'NotATeamMember) r,
    Member (ErrorS 'TeamNotFound) r,
    Member (ErrorS OperationDenied) r,
    Member (Input Opts) r,
    Member LegalHoldStore r,
    Member TeamFeatureStore r,
    Member TeamStore r
  ) =>
  UserId ->
  Sem r AllTeamFeatures
getAllTeamFeaturesForUser :: forall (r :: EffectRow).
(Member BrigAccess r, Member (ErrorS 'NotATeamMember) r,
 Member (ErrorS 'TeamNotFound) r, Member (ErrorS OperationDenied) r,
 Member (Input Opts) r, Member LegalHoldStore r,
 Member TeamFeatureStore r, Member TeamStore r) =>
UserId -> Sem r AllTeamFeatures
getAllTeamFeaturesForUser UserId
uid = do
  Maybe TeamId
mTid <- UserId -> Sem r (Maybe TeamId)
forall (r :: EffectRow).
(Member TeamStore r, Member (ErrorS 'NotATeamMember) r,
 Member (ErrorS 'TeamNotFound) r) =>
UserId -> Sem r (Maybe TeamId)
getTeamAndCheckMembership UserId
uid
  NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall (xs :: [*]) (f :: * -> *) (g :: * -> *).
(SListIN NP xs, Applicative f) =>
NP (f :.: g) xs -> f (NP g xs)
forall k l (h :: (k -> *) -> l -> *) (xs :: l) (f :: * -> *)
       (g :: k -> *).
(HSequence h, SListIN h xs, Applicative f) =>
h (f :.: g) xs -> f (h g xs)
hsequence' (NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures)
-> NP (Sem r :.: LockableFeature) Features -> Sem r AllTeamFeatures
forall a b. (a -> b) -> a -> b
$ Proxy (GetAllTeamFeaturesForUserConstraints r)
-> (forall {a}.
    GetAllTeamFeaturesForUserConstraints r a =>
    (:.:) (Sem r) LockableFeature a)
-> NP (Sem r :.: LockableFeature) Features
forall k l (h :: (k -> *) -> l -> *) (c :: k -> Constraint)
       (xs :: l) (proxy :: (k -> Constraint) -> *) (f :: k -> *).
(HPure h, AllN h c xs) =>
proxy c -> (forall (a :: k). c a => f a) -> h f xs
forall (c :: * -> Constraint) (xs :: [*])
       (proxy :: (* -> Constraint) -> *) (f :: * -> *).
AllN NP c xs =>
proxy c -> (forall a. c a => f a) -> NP f xs
hcpure (forall {k} (t :: k). Proxy t
forall (t :: * -> Constraint). Proxy t
Proxy @(GetAllTeamFeaturesForUserConstraints r)) ((forall {a}.
  GetAllTeamFeaturesForUserConstraints r a =>
  (:.:) (Sem r) LockableFeature a)
 -> NP (Sem r :.: LockableFeature) Features)
-> (forall {a}.
    GetAllTeamFeaturesForUserConstraints r a =>
    (:.:) (Sem r) LockableFeature a)
-> NP (Sem r :.: LockableFeature) Features
forall a b. (a -> b) -> a -> b
$ Sem r (LockableFeature a) -> (:.:) (Sem r) LockableFeature a
forall l k (f :: l -> *) (g :: k -> l) (p :: k).
f (g p) -> (:.:) f g p
Comp (Sem r (LockableFeature a) -> (:.:) (Sem r) LockableFeature a)
-> Sem r (LockableFeature a) -> (:.:) (Sem r) LockableFeature a
forall a b. (a -> b) -> a -> b
$ UserId -> Maybe TeamId -> Sem r (LockableFeature a)
forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, GetFeatureForUserConstraints cfg r,
 ComputeFeatureConstraints cfg r, Member (Input Opts) r,
 Member TeamFeatureStore r) =>
UserId -> Maybe TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeamUser UserId
uid Maybe TeamId
mTid

getSingleFeatureForUser ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    Member (Input Opts) r,
    Member (ErrorS 'NotATeamMember) r,
    Member (ErrorS 'TeamNotFound) r,
    Member TeamStore r,
    Member TeamFeatureStore r,
    GetFeatureForUserConstraints cfg r,
    ComputeFeatureConstraints cfg r
  ) =>
  UserId ->
  Sem r (LockableFeature cfg)
getSingleFeatureForUser :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, Member (Input Opts) r,
 Member (ErrorS 'NotATeamMember) r, Member (ErrorS 'TeamNotFound) r,
 Member TeamStore r, Member TeamFeatureStore r,
 GetFeatureForUserConstraints cfg r,
 ComputeFeatureConstraints cfg r) =>
UserId -> Sem r (LockableFeature cfg)
getSingleFeatureForUser UserId
uid = do
  Maybe TeamId
mTid <- UserId -> Sem r (Maybe TeamId)
forall (r :: EffectRow).
(Member TeamStore r, Member (ErrorS 'NotATeamMember) r,
 Member (ErrorS 'TeamNotFound) r) =>
UserId -> Sem r (Maybe TeamId)
getTeamAndCheckMembership UserId
uid
  forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, GetFeatureForUserConstraints cfg r,
 ComputeFeatureConstraints cfg r, Member (Input Opts) r,
 Member TeamFeatureStore r) =>
UserId -> Maybe TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeamUser @cfg UserId
uid Maybe TeamId
mTid

getFeatureForTeam ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    ComputeFeatureConstraints cfg r,
    Member (Input Opts) r,
    Member TeamFeatureStore r
  ) =>
  TeamId ->
  Sem r (LockableFeature cfg)
getFeatureForTeam :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeam TeamId
tid = do
  DbFeature cfg
dbFeature <- TeamId -> Sem r (DbFeature cfg)
forall (r :: EffectRow) cfg.
(Member TeamFeatureStore r, IsFeatureConfig cfg) =>
TeamId -> Sem r (DbFeature cfg)
getDbFeature TeamId
tid
  LockableFeature cfg
defFeature <- Sem r (LockableFeature cfg)
forall cfg (r :: EffectRow).
(GetFeatureDefaults (FeatureDefaults cfg), NpProject cfg Features,
 Member (Input Opts) r) =>
Sem r (LockableFeature cfg)
getFeatureForServer
  forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) =>
TeamId
-> LockableFeature cfg
-> DbFeature cfg
-> Sem r (LockableFeature cfg)
computeFeature @cfg
    TeamId
tid
    LockableFeature cfg
defFeature
    DbFeature cfg
dbFeature

getFeatureForMultiTeam ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    ComputeFeatureConstraints cfg r,
    Member TeamFeatureStore r,
    Member (Input Opts) r
  ) =>
  [TeamId] ->
  Sem r [(TeamId, LockableFeature cfg)]
getFeatureForMultiTeam :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member TeamFeatureStore r, Member (Input Opts) r) =>
[TeamId] -> Sem r [(TeamId, LockableFeature cfg)]
getFeatureForMultiTeam [TeamId]
tids = do
  LockableFeature cfg
defFeature <- Sem r (LockableFeature cfg)
forall cfg (r :: EffectRow).
(GetFeatureDefaults (FeatureDefaults cfg), NpProject cfg Features,
 Member (Input Opts) r) =>
Sem r (LockableFeature cfg)
getFeatureForServer
  [(TeamId, DbFeature cfg)]
features <- [TeamId] -> Sem r [(TeamId, DbFeature cfg)]
forall (r :: EffectRow) cfg.
(Member TeamFeatureStore r, IsFeatureConfig cfg) =>
[TeamId] -> Sem r [(TeamId, DbFeature cfg)]
getDbFeatureMulti [TeamId]
tids
  [(TeamId, DbFeature cfg)]
-> ((TeamId, DbFeature cfg) -> Sem r (TeamId, LockableFeature cfg))
-> Sem r [(TeamId, LockableFeature cfg)]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [(TeamId, DbFeature cfg)]
features (((TeamId, DbFeature cfg) -> Sem r (TeamId, LockableFeature cfg))
 -> Sem r [(TeamId, LockableFeature cfg)])
-> ((TeamId, DbFeature cfg) -> Sem r (TeamId, LockableFeature cfg))
-> Sem r [(TeamId, LockableFeature cfg)]
forall a b. (a -> b) -> a -> b
$ \(TeamId
tid, DbFeature cfg
dbFeature) -> do
    LockableFeature cfg
feat <- forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r) =>
TeamId
-> LockableFeature cfg
-> DbFeature cfg
-> Sem r (LockableFeature cfg)
computeFeature @cfg TeamId
tid LockableFeature cfg
defFeature DbFeature cfg
dbFeature
    (TeamId, LockableFeature cfg)
-> Sem r (TeamId, LockableFeature cfg)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (TeamId
tid, LockableFeature cfg
feat)

getFeatureForTeamUser ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    GetFeatureForUserConstraints cfg r,
    ComputeFeatureConstraints cfg r,
    Member (Input Opts) r,
    Member TeamFeatureStore r
  ) =>
  UserId ->
  Maybe TeamId ->
  Sem r (LockableFeature cfg)
getFeatureForTeamUser :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, GetFeatureForUserConstraints cfg r,
 ComputeFeatureConstraints cfg r, Member (Input Opts) r,
 Member TeamFeatureStore r) =>
UserId -> Maybe TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeamUser UserId
uid Maybe TeamId
Nothing = UserId -> Sem r (LockableFeature cfg)
forall (r :: EffectRow).
GetFeatureForUserConstraints cfg r =>
UserId -> Sem r (LockableFeature cfg)
forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, GetFeatureForUserConstraints cfg r) =>
UserId -> Sem r (LockableFeature cfg)
getFeatureForUser UserId
uid
getFeatureForTeamUser UserId
_ (Just TeamId
tid) = forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member TeamFeatureStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeam @cfg TeamId
tid

getFeatureForServer ::
  forall cfg r.
  ( GetFeatureDefaults (FeatureDefaults cfg),
    NpProject cfg Features,
    Member (Input Opts) r
  ) =>
  Sem r (LockableFeature cfg)
getFeatureForServer :: forall cfg (r :: EffectRow).
(GetFeatureDefaults (FeatureDefaults cfg), NpProject cfg Features,
 Member (Input Opts) r) =>
Sem r (LockableFeature cfg)
getFeatureForServer = (Opts -> LockableFeature cfg) -> Sem r (LockableFeature cfg)
forall i j (r :: EffectRow).
Member (Input i) r =>
(i -> j) -> Sem r j
inputs ((Opts -> LockableFeature cfg) -> Sem r (LockableFeature cfg))
-> (Opts -> LockableFeature cfg) -> Sem r (LockableFeature cfg)
forall a b. (a -> b) -> a -> b
$ Getting (LockableFeature cfg) Opts (LockableFeature cfg)
-> Opts -> LockableFeature cfg
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((Settings -> Const (LockableFeature cfg) Settings)
-> Opts -> Const (LockableFeature cfg) Opts
Lens' Opts Settings
settings ((Settings -> Const (LockableFeature cfg) Settings)
 -> Opts -> Const (LockableFeature cfg) Opts)
-> ((LockableFeature cfg
     -> Const (LockableFeature cfg) (LockableFeature cfg))
    -> Settings -> Const (LockableFeature cfg) Settings)
-> Getting (LockableFeature cfg) Opts (LockableFeature cfg)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FeatureFlags -> Const (LockableFeature cfg) FeatureFlags)
-> Settings -> Const (LockableFeature cfg) Settings
Lens' Settings FeatureFlags
featureFlags ((FeatureFlags -> Const (LockableFeature cfg) FeatureFlags)
 -> Settings -> Const (LockableFeature cfg) Settings)
-> ((LockableFeature cfg
     -> Const (LockableFeature cfg) (LockableFeature cfg))
    -> FeatureFlags -> Const (LockableFeature cfg) FeatureFlags)
-> (LockableFeature cfg
    -> Const (LockableFeature cfg) (LockableFeature cfg))
-> Settings
-> Const (LockableFeature cfg) Settings
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FeatureFlags -> LockableFeature cfg)
-> (LockableFeature cfg
    -> Const (LockableFeature cfg) (LockableFeature cfg))
-> FeatureFlags
-> Const (LockableFeature cfg) FeatureFlags
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to (forall cfg.
(GetFeatureDefaults (FeatureDefaults cfg),
 NpProject cfg Features) =>
FeatureFlags -> LockableFeature cfg
featureDefaults @cfg))

-------------------------------------------------------------------------------
-- GetFeatureConfig instances

instance GetFeatureConfig SSOConfig

instance GetFeatureConfig SearchVisibilityAvailableConfig

instance GetFeatureConfig ValidateSAMLEmailsConfig

instance GetFeatureConfig DigitalSignaturesConfig

instance GetFeatureConfig LegalholdConfig where
  type
    GetFeatureForUserConstraints LegalholdConfig (r :: EffectRow) =
      ( Member (Input Opts) r,
        Member TeamFeatureStore r,
        Member LegalHoldStore r,
        Member TeamStore r,
        Member (ErrorS OperationDenied) r,
        Member (ErrorS 'NotATeamMember) r,
        Member (ErrorS 'TeamNotFound) r
      )
  type
    ComputeFeatureConstraints LegalholdConfig r =
      (Member TeamStore r, Member LegalHoldStore r)

  computeFeature :: forall (r :: EffectRow).
ComputeFeatureConstraints LegalholdConfig r =>
TeamId
-> LockableFeature LegalholdConfig
-> DbFeature LegalholdConfig
-> Sem r (LockableFeature LegalholdConfig)
computeFeature TeamId
tid LockableFeature LegalholdConfig
defFeature DbFeature LegalholdConfig
dbFeature = do
    FeatureStatus
status <- TeamId -> DbFeature LegalholdConfig -> Sem r FeatureStatus
forall (r :: EffectRow).
(Member TeamStore r, Member LegalHoldStore r) =>
TeamId -> DbFeature LegalholdConfig -> Sem r FeatureStatus
computeLegalHoldFeatureStatus TeamId
tid DbFeature LegalholdConfig
dbFeature
    LockableFeature LegalholdConfig
-> Sem r (LockableFeature LegalholdConfig)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LockableFeature LegalholdConfig
 -> Sem r (LockableFeature LegalholdConfig))
-> LockableFeature LegalholdConfig
-> Sem r (LockableFeature LegalholdConfig)
forall a b. (a -> b) -> a -> b
$ LockableFeature LegalholdConfig
defFeature {status = status}

instance GetFeatureConfig FileSharingConfig

instance GetFeatureConfig AppLockConfig

instance GetFeatureConfig ClassifiedDomainsConfig

-- | Conference calling gets enabled automatically once unlocked. To achieve
-- that, the default feature status in the unlocked case is forced to be
-- "enabled" before the database data is applied.
--
-- Previously, we were assuming that this feature would be left as "unlocked",
-- and the clients were simply setting the status field. Now, the pre-existing
-- status field is reinterpreted as the lock status, which means that the
-- status will be NULL in many cases. The defaulting logic in 'computeFeature'
-- here makes sure that the status is aligned with the lock status in those
-- situations.
instance GetFeatureConfig ConferenceCallingConfig where
  type
    GetFeatureForUserConstraints ConferenceCallingConfig r =
      ( Member (Input Opts) r,
        Member (ErrorS OperationDenied) r,
        Member (ErrorS 'NotATeamMember) r,
        Member (ErrorS 'TeamNotFound) r,
        Member TeamStore r,
        Member TeamFeatureStore r,
        Member BrigAccess r
      )

  getFeatureForUser :: forall (r :: EffectRow).
GetFeatureForUserConstraints ConferenceCallingConfig r =>
UserId -> Sem r (LockableFeature ConferenceCallingConfig)
getFeatureForUser UserId
uid = do
    Feature ConferenceCallingConfig
feat <- UserId -> Sem r (Feature ConferenceCallingConfig)
forall (r :: EffectRow).
Member BrigAccess r =>
UserId -> Sem r (Feature ConferenceCallingConfig)
getAccountConferenceCallingConfigClient UserId
uid
    LockableFeature ConferenceCallingConfig
-> Sem r (LockableFeature ConferenceCallingConfig)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LockableFeature ConferenceCallingConfig
 -> Sem r (LockableFeature ConferenceCallingConfig))
-> LockableFeature ConferenceCallingConfig
-> Sem r (LockableFeature ConferenceCallingConfig)
forall a b. (a -> b) -> a -> b
$ LockStatus
-> Feature ConferenceCallingConfig
-> LockableFeature ConferenceCallingConfig
forall a. LockStatus -> Feature a -> LockableFeature a
withLockStatus (forall a. Default a => a
def @(LockableFeature ConferenceCallingConfig)).lockStatus Feature ConferenceCallingConfig
feat

  computeFeature :: forall (r :: EffectRow).
ComputeFeatureConstraints ConferenceCallingConfig r =>
TeamId
-> LockableFeature ConferenceCallingConfig
-> DbFeature ConferenceCallingConfig
-> Sem r (LockableFeature ConferenceCallingConfig)
computeFeature TeamId
_tid LockableFeature ConferenceCallingConfig
defFeature DbFeature ConferenceCallingConfig
dbFeature =
    LockableFeature ConferenceCallingConfig
-> Sem r (LockableFeature ConferenceCallingConfig)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LockableFeature ConferenceCallingConfig
 -> Sem r (LockableFeature ConferenceCallingConfig))
-> LockableFeature ConferenceCallingConfig
-> Sem r (LockableFeature ConferenceCallingConfig)
forall a b. (a -> b) -> a -> b
$
      let feat :: LockableFeature ConferenceCallingConfig
feat = DbFeature ConferenceCallingConfig
-> LockableFeature ConferenceCallingConfig
-> LockableFeature ConferenceCallingConfig
forall cfg.
DbFeature cfg -> LockableFeature cfg -> LockableFeature cfg
applyDbFeature DbFeature ConferenceCallingConfig
dbFeature LockableFeature ConferenceCallingConfig
defFeature {status = FeatureStatusEnabled}
       in case LockableFeature ConferenceCallingConfig
feat.lockStatus of
            LockStatus
LockStatusLocked -> LockableFeature ConferenceCallingConfig
defFeature {lockStatus = LockStatusLocked}
            LockStatus
LockStatusUnlocked -> LockableFeature ConferenceCallingConfig
feat

instance GetFeatureConfig SelfDeletingMessagesConfig

instance GetFeatureConfig GuestLinksConfig

instance GetFeatureConfig SndFactorPasswordChallengeConfig

instance GetFeatureConfig SearchVisibilityInboundConfig

instance GetFeatureConfig MLSConfig

instance GetFeatureConfig ExposeInvitationURLsToTeamAdminConfig where
  type
    ComputeFeatureConstraints ExposeInvitationURLsToTeamAdminConfig r =
      (Member (Input Opts) r)

  -- the lock status of this feature is calculated from the allow list, not the database
  computeFeature :: forall (r :: EffectRow).
ComputeFeatureConstraints
  ExposeInvitationURLsToTeamAdminConfig r =>
TeamId
-> LockableFeature ExposeInvitationURLsToTeamAdminConfig
-> DbFeature ExposeInvitationURLsToTeamAdminConfig
-> Sem r (LockableFeature ExposeInvitationURLsToTeamAdminConfig)
computeFeature TeamId
tid LockableFeature ExposeInvitationURLsToTeamAdminConfig
defFeature DbFeature ExposeInvitationURLsToTeamAdminConfig
dbFeature = do
    [TeamId]
allowList <- Sem r Opts
forall i (r :: EffectRow). Member (Input i) r => Sem r i
input Sem r Opts -> (Opts -> [TeamId]) -> Sem r [TeamId]
forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> Getting [TeamId] Opts [TeamId] -> Opts -> [TeamId]
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view ((Settings -> Const [TeamId] Settings)
-> Opts -> Const [TeamId] Opts
Lens' Opts Settings
settings ((Settings -> Const [TeamId] Settings)
 -> Opts -> Const [TeamId] Opts)
-> (([TeamId] -> Const [TeamId] [TeamId])
    -> Settings -> Const [TeamId] Settings)
-> Getting [TeamId] Opts [TeamId]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe [TeamId] -> Const [TeamId] (Maybe [TeamId]))
-> Settings -> Const [TeamId] Settings
Lens' Settings (Maybe [TeamId])
exposeInvitationURLsTeamAllowlist ((Maybe [TeamId] -> Const [TeamId] (Maybe [TeamId]))
 -> Settings -> Const [TeamId] Settings)
-> (([TeamId] -> Const [TeamId] [TeamId])
    -> Maybe [TeamId] -> Const [TeamId] (Maybe [TeamId]))
-> ([TeamId] -> Const [TeamId] [TeamId])
-> Settings
-> Const [TeamId] Settings
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe [TeamId] -> [TeamId])
-> ([TeamId] -> Const [TeamId] [TeamId])
-> Maybe [TeamId]
-> Const [TeamId] (Maybe [TeamId])
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to ([TeamId] -> Maybe [TeamId] -> [TeamId]
forall a. a -> Maybe a -> a
fromMaybe []))
    let teamAllowed :: Bool
teamAllowed = TeamId
tid TeamId -> [TeamId] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [TeamId]
allowList
        lockStatus :: LockStatus
lockStatus = if Bool
teamAllowed then LockStatus
LockStatusUnlocked else LockStatus
LockStatusLocked
    LockableFeature ExposeInvitationURLsToTeamAdminConfig
-> Sem r (LockableFeature ExposeInvitationURLsToTeamAdminConfig)
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (LockableFeature ExposeInvitationURLsToTeamAdminConfig
 -> Sem r (LockableFeature ExposeInvitationURLsToTeamAdminConfig))
-> LockableFeature ExposeInvitationURLsToTeamAdminConfig
-> Sem r (LockableFeature ExposeInvitationURLsToTeamAdminConfig)
forall a b. (a -> b) -> a -> b
$ LockableFeature ExposeInvitationURLsToTeamAdminConfig
-> DbFeature ExposeInvitationURLsToTeamAdminConfig
-> LockableFeature ExposeInvitationURLsToTeamAdminConfig
forall cfg.
LockableFeature cfg -> DbFeature cfg -> LockableFeature cfg
genericComputeFeature LockableFeature ExposeInvitationURLsToTeamAdminConfig
defFeature (LockStatus -> DbFeature ExposeInvitationURLsToTeamAdminConfig
forall cfg. LockStatus -> DbFeature cfg
dbFeatureLockStatus LockStatus
lockStatus DbFeature ExposeInvitationURLsToTeamAdminConfig
-> DbFeature ExposeInvitationURLsToTeamAdminConfig
-> DbFeature ExposeInvitationURLsToTeamAdminConfig
forall a. Semigroup a => a -> a -> a
<> DbFeature ExposeInvitationURLsToTeamAdminConfig
dbFeature)

instance GetFeatureConfig OutlookCalIntegrationConfig

instance GetFeatureConfig MlsE2EIdConfig

instance GetFeatureConfig MlsMigrationConfig

instance GetFeatureConfig EnforceFileDownloadLocationConfig

instance GetFeatureConfig LimitedEventFanoutConfig

-- | 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.
guardSecondFactorDisabled ::
  forall r.
  ( Member TeamFeatureStore r,
    Member (Input Opts) r,
    Member (ErrorS 'AccessDenied) r,
    Member TeamStore r,
    Member ConversationStore r
  ) =>
  UserId ->
  ConvId ->
  Sem r ()
guardSecondFactorDisabled :: forall (r :: EffectRow).
(Member TeamFeatureStore r, Member (Input Opts) r,
 Member (ErrorS 'AccessDenied) r, Member TeamStore r,
 Member ConversationStore r) =>
UserId -> ConvId -> Sem r ()
guardSecondFactorDisabled UserId
uid ConvId
cid = do
  Maybe TeamId
mTid <- (Either () TeamId -> Maybe TeamId)
-> Sem r (Either () TeamId) -> Sem r (Maybe TeamId)
forall a b. (a -> b) -> Sem r a -> Sem r b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Either () TeamId -> Maybe TeamId
forall a b. Either a b -> Maybe b
hush (Sem r (Either () TeamId) -> Sem r (Maybe TeamId))
-> (Sem (Error () : r) TeamId -> Sem r (Either () TeamId))
-> Sem (Error () : r) TeamId
-> Sem r (Maybe TeamId)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e (r :: EffectRow) a.
Sem (Error e : r) a -> Sem r (Either e a)
runError @() (Sem (Error () : r) TeamId -> Sem r (Maybe TeamId))
-> Sem (Error () : r) TeamId -> Sem r (Maybe TeamId)
forall a b. (a -> b) -> a -> b
$ do
    ConversationMetadata
convData <- ConvId -> Sem (Error () : r) (Maybe ConversationMetadata)
forall (r :: EffectRow).
Member ConversationStore r =>
ConvId -> Sem r (Maybe ConversationMetadata)
ConversationStore.getConversationMetadata ConvId
cid Sem (Error () : r) (Maybe ConversationMetadata)
-> (Maybe ConversationMetadata
    -> Sem (Error () : r) ConversationMetadata)
-> Sem (Error () : r) ConversationMetadata
forall a b.
Sem (Error () : r) a
-> (a -> Sem (Error () : r) b) -> Sem (Error () : r) b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ()
-> Maybe ConversationMetadata
-> Sem (Error () : r) ConversationMetadata
forall e (r :: EffectRow) a.
Member (Error e) r =>
e -> Maybe a -> Sem r a
note ()
    TeamId
tid <- () -> Maybe TeamId -> Sem (Error () : r) TeamId
forall e (r :: EffectRow) a.
Member (Error e) r =>
e -> Maybe a -> Sem r a
note () ConversationMetadata
convData.cnvmTeam
    (Tagged 'TeamNotFound () -> ())
-> Sem (ErrorS 'TeamNotFound : Error () : r) ()
-> Sem (Error () : r) ()
forall e1 e2 (r :: EffectRow) a.
Member (Error e2) r =>
(e1 -> e2) -> Sem (Error e1 : r) a -> Sem r a
mapError (forall {k} (s :: k) b. Tagged s b -> b
forall (s :: GalleyError) b. Tagged s b -> b
unTagged @'TeamNotFound @()) (Sem (ErrorS 'TeamNotFound : Error () : r) ()
 -> Sem (Error () : r) ())
-> Sem (ErrorS 'TeamNotFound : Error () : r) ()
-> Sem (Error () : r) ()
forall a b. (a -> b) -> a -> b
$ TeamId -> Sem (ErrorS 'TeamNotFound : Error () : r) ()
forall (r :: EffectRow).
(Member (ErrorS 'TeamNotFound) r, Member TeamStore r) =>
TeamId -> Sem r ()
assertTeamExists TeamId
tid
    TeamId -> Sem (Error () : r) TeamId
forall a. a -> Sem (Error () : r) a
forall (f :: * -> *) a. Applicative f => a -> f a
pure TeamId
tid

  LockableFeature SndFactorPasswordChallengeConfig
tf <- forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, GetFeatureForUserConstraints cfg r,
 ComputeFeatureConstraints cfg r, Member (Input Opts) r,
 Member TeamFeatureStore r) =>
UserId -> Maybe TeamId -> Sem r (LockableFeature cfg)
getFeatureForTeamUser @SndFactorPasswordChallengeConfig UserId
uid Maybe TeamId
mTid
  case LockableFeature SndFactorPasswordChallengeConfig
tf.status of
    FeatureStatus
FeatureStatusDisabled -> () -> Sem r ()
forall a. a -> Sem r a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
    FeatureStatus
FeatureStatusEnabled -> forall {k} (e :: k) (r :: EffectRow) a.
Member (ErrorS e) r =>
Sem r a
forall (e :: GalleyError) (r :: EffectRow) a.
Member (ErrorS e) r =>
Sem r a
throwS @'AccessDenied

featureEnabledForTeam ::
  forall cfg r.
  ( GetFeatureConfig cfg,
    Member (Input Opts) r,
    Member (ErrorS 'TeamNotFound) r,
    Member TeamStore r,
    Member TeamFeatureStore r,
    ComputeFeatureConstraints cfg r
  ) =>
  TeamId ->
  Sem r Bool
featureEnabledForTeam :: forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, Member (Input Opts) r,
 Member (ErrorS 'TeamNotFound) r, Member TeamStore r,
 Member TeamFeatureStore r, ComputeFeatureConstraints cfg r) =>
TeamId -> Sem r Bool
featureEnabledForTeam TeamId
tid =
  FeatureStatus -> FeatureStatus -> Bool
forall a. Eq a => a -> a -> Bool
(==) FeatureStatus
FeatureStatusEnabled
    (FeatureStatus -> Bool)
-> (LockableFeature cfg -> FeatureStatus)
-> LockableFeature cfg
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (.status)
    (LockableFeature cfg -> Bool)
-> Sem r (LockableFeature cfg) -> Sem r Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall cfg (r :: EffectRow).
(GetFeatureConfig cfg, ComputeFeatureConstraints cfg r,
 Member (Input Opts) r, Member (ErrorS 'TeamNotFound) r,
 Member TeamFeatureStore r, Member TeamStore r) =>
TeamId -> Sem r (LockableFeature cfg)
getFeatureInternal @cfg TeamId
tid