79
79
import qualified Cassandra.CQL as Cass
80
80
import Control.Lens (makeLenses , (?~) )
81
81
import qualified Data.Aeson as A
82
+ import qualified Data.Aeson.Types as A
82
83
import qualified Data.Attoparsec.ByteString as Parser
83
84
import Data.ByteString.Conversion
84
85
import qualified Data.ByteString.UTF8 as UTF8
@@ -87,6 +88,7 @@ import Data.Either.Extra (maybeToEither)
87
88
import Data.Id
88
89
import Data.Proxy
89
90
import Data.Schema
91
+ import Data.Scientific (toBoundedInteger )
90
92
import Data.String.Conversions (cs )
91
93
import qualified Data.Swagger as S
92
94
import qualified Data.Swagger.Build.Api as Doc
@@ -174,7 +176,8 @@ featureNameBS = UTF8.fromString $ symbolVal (Proxy @(FeatureSymbol cfg))
174
176
data WithStatusBase (m :: * -> * ) (cfg :: * ) = WithStatusBase
175
177
{ wsbStatus :: m FeatureStatus ,
176
178
wsbLockStatus :: m LockStatus ,
177
- wsbConfig :: m cfg
179
+ wsbConfig :: m cfg ,
180
+ wsbTTL :: m FeatureTTL
178
181
}
179
182
deriving stock (Generic , Typeable , Functor )
180
183
@@ -191,17 +194,20 @@ wsLockStatus = runIdentity . wsbLockStatus
191
194
wsConfig :: WithStatus cfg -> cfg
192
195
wsConfig = runIdentity . wsbConfig
193
196
194
- withStatus :: FeatureStatus -> LockStatus -> cfg -> WithStatus cfg
195
- withStatus s ls c = WithStatusBase (Identity s) (Identity ls) (Identity c)
197
+ wsTTL :: WithStatus cfg -> FeatureTTL
198
+ wsTTL = runIdentity . wsbTTL
199
+
200
+ withStatus :: FeatureStatus -> LockStatus -> cfg -> FeatureTTL -> WithStatus cfg
201
+ withStatus s ls c ttl = WithStatusBase (Identity s) (Identity ls) (Identity c) (Identity ttl)
196
202
197
203
setStatus :: FeatureStatus -> WithStatus cfg -> WithStatus cfg
198
- setStatus s (WithStatusBase _ ls c) = WithStatusBase (Identity s) ls c
204
+ setStatus s (WithStatusBase _ ls c ttl ) = WithStatusBase (Identity s) ls c ttl
199
205
200
206
setLockStatus :: LockStatus -> WithStatus cfg -> WithStatus cfg
201
- setLockStatus ls (WithStatusBase s _ c) = WithStatusBase s (Identity ls) c
207
+ setLockStatus ls (WithStatusBase s _ c ttl ) = WithStatusBase s (Identity ls) c ttl
202
208
203
209
setConfig :: cfg -> WithStatus cfg -> WithStatus cfg
204
- setConfig c (WithStatusBase s ls _) = WithStatusBase s ls (Identity c)
210
+ setConfig c (WithStatusBase s ls _ ttl ) = WithStatusBase s ls (Identity c) ttl
205
211
206
212
type WithStatus (cfg :: * ) = WithStatusBase Identity cfg
207
213
@@ -222,12 +228,13 @@ instance (ToSchema cfg, IsFeatureConfig cfg) => ToSchema (WithStatus cfg) where
222
228
<$> (runIdentity . wsbStatus) .= (Identity <$> field " status" schema)
223
229
<*> (runIdentity . wsbLockStatus) .= (Identity <$> field " lockStatus" schema)
224
230
<*> (runIdentity . wsbConfig) .= (Identity <$> objectSchema @ cfg )
231
+ <*> (runIdentity . wsbTTL) .= (Identity <$> field " ttl" schema)
225
232
where
226
233
inner = schema @ cfg
227
234
name = fromMaybe " " (getName (schemaDoc inner)) <> " .WithStatus"
228
235
229
236
instance (Arbitrary cfg , IsFeatureConfig cfg ) => Arbitrary (WithStatus cfg ) where
230
- arbitrary = WithStatusBase <$> arbitrary <*> arbitrary <*> arbitrary
237
+ arbitrary = WithStatusBase <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
231
238
232
239
withStatusModel :: forall cfg . (IsFeatureConfig cfg , KnownSymbol (FeatureSymbol cfg )) => Doc. Model
233
240
withStatusModel =
@@ -267,7 +274,7 @@ wspLockStatus = wsbLockStatus
267
274
wspConfig :: WithStatusPatch cfg -> Maybe cfg
268
275
wspConfig = wsbConfig
269
276
270
- withStatus' :: Maybe FeatureStatus -> Maybe LockStatus -> Maybe cfg -> WithStatusPatch cfg
277
+ withStatus' :: Maybe FeatureStatus -> Maybe LockStatus -> Maybe cfg -> Maybe FeatureTTL -> WithStatusPatch cfg
271
278
withStatus' = WithStatusBase
272
279
273
280
-- | The ToJSON implementation of `WithStatusPatch` will encode the trivial config as `"config": {}`
@@ -279,31 +286,33 @@ instance (ToSchema cfg, IsFeatureConfig cfg) => ToSchema (WithStatusPatch cfg) w
279
286
<$> wsbStatus .= maybe_ (optField " status" schema)
280
287
<*> wsbLockStatus .= maybe_ (optField " lockStatus" schema)
281
288
<*> wsbConfig .= maybe_ (optField " config" schema)
289
+ <*> wsbTTL .= maybe_ (optField " ttl" schema)
282
290
where
283
291
inner = schema @ cfg
284
292
name = fromMaybe " " (getName (schemaDoc inner)) <> " .WithStatusPatch"
285
293
286
294
instance (Arbitrary cfg , IsFeatureConfig cfg ) => Arbitrary (WithStatusPatch cfg ) where
287
- arbitrary = WithStatusBase <$> arbitrary <*> arbitrary <*> arbitrary
295
+ arbitrary = WithStatusBase <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
288
296
289
297
----------------------------------------------------------------------
290
298
-- WithStatusNoLock
291
299
292
300
data WithStatusNoLock (cfg :: * ) = WithStatusNoLock
293
301
{ wssStatus :: FeatureStatus ,
294
- wssConfig :: cfg
302
+ wssConfig :: cfg ,
303
+ wssTTL :: FeatureTTL
295
304
}
296
305
deriving stock (Eq , Show , Generic , Typeable , Functor )
297
306
deriving (ToJSON , FromJSON , S.ToSchema ) via (Schema (WithStatusNoLock cfg ))
298
307
299
308
instance Arbitrary cfg => Arbitrary (WithStatusNoLock cfg ) where
300
- arbitrary = WithStatusNoLock <$> arbitrary <*> arbitrary
309
+ arbitrary = WithStatusNoLock <$> arbitrary <*> arbitrary <*> arbitrary
301
310
302
311
forgetLock :: WithStatus a -> WithStatusNoLock a
303
- forgetLock ws = WithStatusNoLock (wsStatus ws) (wsConfig ws)
312
+ forgetLock ws = WithStatusNoLock (wsStatus ws) (wsConfig ws) (wsTTL ws)
304
313
305
314
withLockStatus :: LockStatus -> WithStatusNoLock a -> WithStatus a
306
- withLockStatus ls (WithStatusNoLock s c) = withStatus s ls c
315
+ withLockStatus ls (WithStatusNoLock s c ttl ) = withStatus s ls c ttl
307
316
308
317
withUnlocked :: WithStatusNoLock a -> WithStatus a
309
318
withUnlocked = withLockStatus LockStatusUnlocked
@@ -317,6 +326,7 @@ instance (ToSchema cfg, IsFeatureConfig cfg) => ToSchema (WithStatusNoLock cfg)
317
326
WithStatusNoLock
318
327
<$> wssStatus .= field " status" schema
319
328
<*> wssConfig .= objectSchema @ cfg
329
+ <*> wssTTL .= field " ttl" schema
320
330
where
321
331
inner = schema @ cfg
322
332
name = fromMaybe " " (getName (schemaDoc inner)) <> " .WithStatusNoLock"
@@ -346,6 +356,35 @@ data FeatureTTL
346
356
deriving stock (Eq , Show , Generic )
347
357
deriving (Arbitrary ) via (GenericUniform FeatureTTL )
348
358
359
+ instance ToSchema FeatureTTL where
360
+ schema = mkSchema ttlDoc toTTL fromTTL
361
+ where
362
+ ttlDoc :: NamedSwaggerDoc
363
+ ttlDoc = swaggerDoc @ Word & S. schema . S. example ?~ " unlimited"
364
+
365
+ toTTL :: A. Value -> A. Parser FeatureTTL
366
+ toTTL v = parseUnlimited v <|> parseSeconds v
367
+
368
+ parseUnlimited :: A. Value -> A. Parser FeatureTTL
369
+ parseUnlimited =
370
+ A. withText " FeatureTTL" $
371
+ \ t ->
372
+ if t == " unlimited" || t == " 0"
373
+ then pure FeatureTTLUnlimited
374
+ else A. parseFail " Expected ''unlimited' or '0'."
375
+
376
+ parseSeconds :: A. Value -> A. Parser FeatureTTL
377
+ parseSeconds = A. withScientific " FeatureTTL" $
378
+ \ s -> case toBoundedInteger s of
379
+ Just 0 -> pure FeatureTTLUnlimited
380
+ Just i -> pure . FeatureTTLSeconds $ i
381
+ Nothing -> A. parseFail " Expected an integer."
382
+
383
+ fromTTL :: FeatureTTL -> Maybe A. Value
384
+ fromTTL FeatureTTLUnlimited = Just " unlimited"
385
+ fromTTL (FeatureTTLSeconds 0 ) = Just " unlimited"
386
+ fromTTL (FeatureTTLSeconds s) = A. decode . toByteString $ s
387
+
349
388
instance ToHttpApiData FeatureTTL where
350
389
toQueryParam = T. decodeUtf8 . toByteString'
351
390
@@ -532,7 +571,7 @@ instance ToSchema GuestLinksConfig where
532
571
533
572
instance IsFeatureConfig GuestLinksConfig where
534
573
type FeatureSymbol GuestLinksConfig = " conversationGuestLinks"
535
- defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked GuestLinksConfig
574
+ defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked GuestLinksConfig FeatureTTLUnlimited
536
575
537
576
objectSchema = pure GuestLinksConfig
538
577
@@ -548,8 +587,7 @@ data LegalholdConfig = LegalholdConfig
548
587
549
588
instance IsFeatureConfig LegalholdConfig where
550
589
type FeatureSymbol LegalholdConfig = " legalhold"
551
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked LegalholdConfig
552
-
590
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked LegalholdConfig FeatureTTLUnlimited
553
591
objectSchema = pure LegalholdConfig
554
592
555
593
instance ToSchema LegalholdConfig where
@@ -567,8 +605,7 @@ data SSOConfig = SSOConfig
567
605
568
606
instance IsFeatureConfig SSOConfig where
569
607
type FeatureSymbol SSOConfig = " sso"
570
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SSOConfig
571
-
608
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SSOConfig FeatureTTLUnlimited
572
609
objectSchema = pure SSOConfig
573
610
574
611
instance ToSchema SSOConfig where
@@ -588,8 +625,7 @@ data SearchVisibilityAvailableConfig = SearchVisibilityAvailableConfig
588
625
589
626
instance IsFeatureConfig SearchVisibilityAvailableConfig where
590
627
type FeatureSymbol SearchVisibilityAvailableConfig = " searchVisibility"
591
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SearchVisibilityAvailableConfig
592
-
628
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SearchVisibilityAvailableConfig FeatureTTLUnlimited
593
629
objectSchema = pure SearchVisibilityAvailableConfig
594
630
595
631
instance ToSchema SearchVisibilityAvailableConfig where
@@ -613,8 +649,7 @@ instance ToSchema ValidateSAMLEmailsConfig where
613
649
614
650
instance IsFeatureConfig ValidateSAMLEmailsConfig where
615
651
type FeatureSymbol ValidateSAMLEmailsConfig = " validateSAMLemails"
616
- defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked ValidateSAMLEmailsConfig
617
-
652
+ defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked ValidateSAMLEmailsConfig FeatureTTLUnlimited
618
653
objectSchema = pure ValidateSAMLEmailsConfig
619
654
620
655
instance HasDeprecatedFeatureName ValidateSAMLEmailsConfig where
@@ -632,8 +667,7 @@ data DigitalSignaturesConfig = DigitalSignaturesConfig
632
667
633
668
instance IsFeatureConfig DigitalSignaturesConfig where
634
669
type FeatureSymbol DigitalSignaturesConfig = " digitalSignatures"
635
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked DigitalSignaturesConfig
636
-
670
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked DigitalSignaturesConfig FeatureTTLUnlimited
637
671
objectSchema = pure DigitalSignaturesConfig
638
672
639
673
instance HasDeprecatedFeatureName DigitalSignaturesConfig where
@@ -654,8 +688,7 @@ data ConferenceCallingConfig = ConferenceCallingConfig
654
688
655
689
instance IsFeatureConfig ConferenceCallingConfig where
656
690
type FeatureSymbol ConferenceCallingConfig = " conferenceCalling"
657
- defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked ConferenceCallingConfig
658
-
691
+ defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked ConferenceCallingConfig FeatureTTLUnlimited
659
692
objectSchema = pure ConferenceCallingConfig
660
693
661
694
instance ToSchema ConferenceCallingConfig where
@@ -676,8 +709,7 @@ instance ToSchema SndFactorPasswordChallengeConfig where
676
709
677
710
instance IsFeatureConfig SndFactorPasswordChallengeConfig where
678
711
type FeatureSymbol SndFactorPasswordChallengeConfig = " sndFactorPasswordChallenge"
679
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusLocked SndFactorPasswordChallengeConfig
680
-
712
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusLocked SndFactorPasswordChallengeConfig FeatureTTLUnlimited
681
713
objectSchema = pure SndFactorPasswordChallengeConfig
682
714
683
715
instance FeatureTrivialConfig SndFactorPasswordChallengeConfig where
@@ -692,8 +724,7 @@ data SearchVisibilityInboundConfig = SearchVisibilityInboundConfig
692
724
693
725
instance IsFeatureConfig SearchVisibilityInboundConfig where
694
726
type FeatureSymbol SearchVisibilityInboundConfig = " searchVisibilityInbound"
695
- defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SearchVisibilityInboundConfig
696
-
727
+ defFeatureStatus = withStatus FeatureStatusDisabled LockStatusUnlocked SearchVisibilityInboundConfig FeatureTTLUnlimited
697
728
objectSchema = pure SearchVisibilityInboundConfig
698
729
699
730
instance ToSchema SearchVisibilityInboundConfig where
@@ -727,6 +758,7 @@ instance IsFeatureConfig ClassifiedDomainsConfig where
727
758
FeatureStatusDisabled
728
759
LockStatusUnlocked
729
760
(ClassifiedDomainsConfig [] )
761
+ FeatureTTLUnlimited
730
762
configModel = Just $
731
763
Doc. defineModel " ClassifiedDomainsConfig" $ do
732
764
Doc. property " domains" (Doc. array Doc. string') $ Doc. description " domains"
@@ -758,6 +790,7 @@ instance IsFeatureConfig AppLockConfig where
758
790
FeatureStatusEnabled
759
791
LockStatusUnlocked
760
792
(AppLockConfig (EnforceAppLock False ) 60 )
793
+ FeatureTTLUnlimited
761
794
configModel = Just $
762
795
Doc. defineModel " AppLockConfig" $ do
763
796
Doc. property " enforceAppLock" Doc. bool' $ Doc. description " enforceAppLock"
@@ -781,8 +814,7 @@ data FileSharingConfig = FileSharingConfig
781
814
782
815
instance IsFeatureConfig FileSharingConfig where
783
816
type FeatureSymbol FileSharingConfig = " fileSharing"
784
- defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked FileSharingConfig
785
-
817
+ defFeatureStatus = withStatus FeatureStatusEnabled LockStatusUnlocked FileSharingConfig FeatureTTLUnlimited
786
818
objectSchema = pure FileSharingConfig
787
819
788
820
instance ToSchema FileSharingConfig where
@@ -814,7 +846,7 @@ instance IsFeatureConfig SelfDeletingMessagesConfig where
814
846
FeatureStatusEnabled
815
847
LockStatusUnlocked
816
848
(SelfDeletingMessagesConfig 0 )
817
-
849
+ FeatureTTLUnlimited
818
850
configModel = Just $
819
851
Doc. defineModel " SelfDeletingMessagesConfig" $ do
820
852
Doc. property " enforcedTimeoutSeconds" Doc. int32' $ Doc. description " optional; default: `0` (no enforcement)"
@@ -845,7 +877,7 @@ instance IsFeatureConfig MLSConfig where
845
877
type FeatureSymbol MLSConfig = " mls"
846
878
defFeatureStatus =
847
879
let config = MLSConfig [] ProtocolProteusTag [MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ] MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
848
- in withStatus FeatureStatusDisabled LockStatusUnlocked config
880
+ in withStatus FeatureStatusDisabled LockStatusUnlocked config FeatureTTLUnlimited
849
881
objectSchema = field " config" schema
850
882
851
883
configModel = Just $
0 commit comments