module Wire.InvitationStore.Cassandra
  ( interpretInvitationStoreToCassandra,
  )
where

import Cassandra
import Control.Monad.Trans.Maybe
import Data.Conduit (runConduit, (.|))
import Data.Conduit.List qualified as Conduit
import Data.Id
import Data.Json.Util (UTCTimeMillis, toUTCTimeMillis)
import Data.Range (Range, fromRange)
import Database.CQL.Protocol (Record (..), TupleType, asRecord)
import Imports
import Polysemy
import Polysemy.Embed
import UnliftIO.Async (pooledMapConcurrentlyN_)
import Util.Timeout
import Wire.API.Team.Role (Role)
import Wire.API.User
import Wire.InvitationStore

interpretInvitationStoreToCassandra :: (Member (Embed IO) r) => ClientState -> InterpreterFor InvitationStore r
interpretInvitationStoreToCassandra :: forall (r :: EffectRow).
Member (Embed IO) r =>
ClientState -> InterpreterFor InvitationStore r
interpretInvitationStoreToCassandra ClientState
casClient =
  (forall (rInitial :: EffectRow) x.
 InvitationStore (Sem rInitial) x -> Sem r x)
-> Sem (InvitationStore : r) a -> Sem r a
forall (e :: (* -> *) -> * -> *) (r :: EffectRow) a.
FirstOrder e "interpret" =>
(forall (rInitial :: EffectRow) x. e (Sem rInitial) x -> Sem r x)
-> Sem (e : r) a -> Sem r a
interpret ((forall (rInitial :: EffectRow) x.
  InvitationStore (Sem rInitial) x -> Sem r x)
 -> Sem (InvitationStore : r) a -> Sem r a)
-> (forall (rInitial :: EffectRow) x.
    InvitationStore (Sem rInitial) x -> Sem r x)
-> Sem (InvitationStore : r) a
-> Sem r a
forall a b. (a -> b) -> a -> b
$
    (forall x. Client x -> IO x) -> Sem (Embed Client : r) x -> Sem r x
forall (m1 :: * -> *) (m2 :: * -> *) (r :: EffectRow) a.
Member (Embed m2) r =>
(forall x. m1 x -> m2 x) -> Sem (Embed m1 : r) a -> Sem r a
runEmbedded (ClientState -> Client x -> IO x
forall (m :: * -> *) a. MonadIO m => ClientState -> Client a -> m a
runClient ClientState
casClient) (Sem (Embed Client : r) x -> Sem r x)
-> (InvitationStore (Sem rInitial) x -> Sem (Embed Client : r) x)
-> InvitationStore (Sem rInitial) x
-> Sem r x
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
      InsertInvitation InsertInvitation
newInv Timeout
timeout -> Client StoredInvitation -> Sem (Embed Client : r) StoredInvitation
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client StoredInvitation
 -> Sem (Embed Client : r) StoredInvitation)
-> Client StoredInvitation
-> Sem (Embed Client : r) StoredInvitation
forall a b. (a -> b) -> a -> b
$ InsertInvitation -> Timeout -> Client StoredInvitation
insertInvitationImpl InsertInvitation
newInv Timeout
timeout
      LookupInvitation TeamId
tid InvitationId
iid -> Client (Maybe StoredInvitation)
-> Sem (Embed Client : r) (Maybe StoredInvitation)
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client (Maybe StoredInvitation)
 -> Sem (Embed Client : r) (Maybe StoredInvitation))
-> Client (Maybe StoredInvitation)
-> Sem (Embed Client : r) (Maybe StoredInvitation)
forall a b. (a -> b) -> a -> b
$ TeamId -> InvitationId -> Client (Maybe StoredInvitation)
lookupInvitationImpl TeamId
tid InvitationId
iid
      LookupInvitationsByEmail EmailAddress
email -> Client [StoredInvitation]
-> Sem (Embed Client : r) [StoredInvitation]
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client [StoredInvitation]
 -> Sem (Embed Client : r) [StoredInvitation])
-> Client [StoredInvitation]
-> Sem (Embed Client : r) [StoredInvitation]
forall a b. (a -> b) -> a -> b
$ EmailAddress -> Client [StoredInvitation]
lookupInvitationsByEmailImpl EmailAddress
email
      LookupInvitationByCode InvitationCode
code -> Client (Maybe StoredInvitation)
-> Sem (Embed Client : r) (Maybe StoredInvitation)
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client (Maybe StoredInvitation)
 -> Sem (Embed Client : r) (Maybe StoredInvitation))
-> Client (Maybe StoredInvitation)
-> Sem (Embed Client : r) (Maybe StoredInvitation)
forall a b. (a -> b) -> a -> b
$ InvitationCode -> Client (Maybe StoredInvitation)
lookupInvitationByCodeImpl InvitationCode
code
      LookupInvitationsPaginated Maybe (Range 1 500 Int32)
mSize TeamId
tid Maybe InvitationId
miid -> Client (PaginatedResult [StoredInvitation])
-> Sem (Embed Client : r) (PaginatedResult [StoredInvitation])
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client (PaginatedResult [StoredInvitation])
 -> Sem (Embed Client : r) (PaginatedResult [StoredInvitation]))
-> Client (PaginatedResult [StoredInvitation])
-> Sem (Embed Client : r) (PaginatedResult [StoredInvitation])
forall a b. (a -> b) -> a -> b
$ Maybe (Range 1 500 Int32)
-> TeamId
-> Maybe InvitationId
-> Client (PaginatedResult [StoredInvitation])
lookupInvitationsPaginatedImpl Maybe (Range 1 500 Int32)
mSize TeamId
tid Maybe InvitationId
miid
      CountInvitations TeamId
tid -> Client Int64 -> Sem (Embed Client : r) Int64
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client Int64 -> Sem (Embed Client : r) Int64)
-> Client Int64 -> Sem (Embed Client : r) Int64
forall a b. (a -> b) -> a -> b
$ TeamId -> Client Int64
countInvitationsImpl TeamId
tid
      DeleteInvitation TeamId
tid InvitationId
invId -> Client () -> Sem (Embed Client : r) ()
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client () -> Sem (Embed Client : r) ())
-> Client () -> Sem (Embed Client : r) ()
forall a b. (a -> b) -> a -> b
$ TeamId -> InvitationId -> Client ()
deleteInvitationImpl TeamId
tid InvitationId
invId
      DeleteAllTeamInvitations TeamId
tid -> Client () -> Sem (Embed Client : r) ()
forall (m :: * -> *) (r :: EffectRow) a.
Member (Embed m) r =>
m a -> Sem r a
embed (Client () -> Sem (Embed Client : r) ())
-> Client () -> Sem (Embed Client : r) ()
forall a b. (a -> b) -> a -> b
$ TeamId -> Client ()
deleteInvitationsImpl TeamId
tid

insertInvitationImpl ::
  InsertInvitation ->
  -- | The timeout for the invitation code.
  Timeout ->
  Client StoredInvitation
insertInvitationImpl :: InsertInvitation -> Timeout -> Client StoredInvitation
insertInvitationImpl (MkInsertInvitation InvitationId
invId TeamId
teamId Role
role (UTCTime -> UTCTimeMillis
toUTCTimeMillis -> UTCTimeMillis
now) Maybe UserId
uid EmailAddress
email Maybe Name
name InvitationCode
code) Timeout
timeout = do
  let inv :: StoredInvitation
inv =
        MkStoredInvitation
          { $sel:teamId:MkStoredInvitation :: TeamId
teamId = TeamId
teamId,
            $sel:role:MkStoredInvitation :: Maybe Role
role = Role -> Maybe Role
forall a. a -> Maybe a
Just Role
role,
            $sel:invitationId:MkStoredInvitation :: InvitationId
invitationId = InvitationId
invId,
            $sel:createdAt:MkStoredInvitation :: UTCTimeMillis
createdAt = UTCTimeMillis
now,
            $sel:createdBy:MkStoredInvitation :: Maybe UserId
createdBy = Maybe UserId
uid,
            $sel:email:MkStoredInvitation :: EmailAddress
email = EmailAddress
email,
            $sel:name:MkStoredInvitation :: Maybe Name
name = Maybe Name
name,
            $sel:code:MkStoredInvitation :: InvitationCode
code = InvitationCode
code
          }
  RetrySettings -> Client () -> Client ()
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x5 (Client () -> Client ())
-> (BatchM () -> Client ()) -> BatchM () -> Client ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BatchM () -> Client ()
forall (m :: * -> *). MonadClient m => BatchM () -> m ()
batch (BatchM () -> Client ()) -> BatchM () -> Client ()
forall a b. (a -> b) -> a -> b
$ do
    BatchType -> BatchM ()
setType BatchType
BatchLogged
    Consistency -> BatchM ()
setConsistency Consistency
LocalQuorum
    PrepQuery
  W
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode, Int32)
  ()
-> (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
    EmailAddress, Maybe Name, InvitationCode, Int32)
-> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery
  W
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode, Int32)
  ()
cqlInsert (TeamId
teamId, Role -> Maybe Role
forall a. a -> Maybe a
Just Role
role, InvitationId
invId, UTCTimeMillis
now, Maybe UserId
uid, EmailAddress
email, Maybe Name
name, InvitationCode
code, Timeout -> Int32
forall b. Integral b => Timeout -> b
forall a b. (RealFrac a, Integral b) => a -> b
round Timeout
timeout)
    PrepQuery W (InvitationCode, TeamId, InvitationId, Int32) ()
-> (InvitationCode, TeamId, InvitationId, Int32) -> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery W (InvitationCode, TeamId, InvitationId, Int32) ()
cqlInsertInfo (InvitationCode
code, TeamId
teamId, InvitationId
invId, Timeout -> Int32
forall b. Integral b => Timeout -> b
forall a b. (RealFrac a, Integral b) => a -> b
round Timeout
timeout)
    PrepQuery
  W (EmailAddress, TeamId, InvitationId, InvitationCode, Int32) ()
-> (EmailAddress, TeamId, InvitationId, InvitationCode, Int32)
-> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery
  W (EmailAddress, TeamId, InvitationId, InvitationCode, Int32) ()
cqlInsertByEmail (EmailAddress
email, TeamId
teamId, InvitationId
invId, InvitationCode
code, Timeout -> Int32
forall b. Integral b => Timeout -> b
forall a b. (RealFrac a, Integral b) => a -> b
round Timeout
timeout)
  StoredInvitation -> Client StoredInvitation
forall a. a -> Client a
forall (f :: * -> *) a. Applicative f => a -> f a
pure StoredInvitation
inv
  where
    cqlInsert :: PrepQuery W (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId, EmailAddress, Maybe Name, InvitationCode, Int32) ()
    cqlInsert :: PrepQuery
  W
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode, Int32)
  ()
cqlInsert =
      [sql|
        INSERT INTO team_invitation (team, role, id, created_at, created_by, email, name, code) VALUES (?, ?, ?, ?, ?, ?, ?, ?) USING TTL ?
      |]
    cqlInsertInfo :: PrepQuery W (InvitationCode, TeamId, InvitationId, Int32) ()
    cqlInsertInfo :: PrepQuery W (InvitationCode, TeamId, InvitationId, Int32) ()
cqlInsertInfo =
      [sql|
            INSERT INTO team_invitation_info (code, team, id) VALUES (?, ?, ?) USING TTL ?
          |]
    -- Note: the edge case of multiple invites to the same team by different admins from the
    -- same team results in last-invite-wins in the team_invitation_email table.
    cqlInsertByEmail :: PrepQuery W (EmailAddress, TeamId, InvitationId, InvitationCode, Int32) ()
    cqlInsertByEmail :: PrepQuery
  W (EmailAddress, TeamId, InvitationId, InvitationCode, Int32) ()
cqlInsertByEmail =
      [sql|
            INSERT INTO team_invitation_email (email, team, invitation, code) VALUES (?, ?, ?, ?) USING TTL ?
          |]

lookupInvitationsPaginatedImpl :: Maybe (Range 1 500 Int32) -> TeamId -> Maybe InvitationId -> Client (PaginatedResult [StoredInvitation])
lookupInvitationsPaginatedImpl :: Maybe (Range 1 500 Int32)
-> TeamId
-> Maybe InvitationId
-> Client (PaginatedResult [StoredInvitation])
lookupInvitationsPaginatedImpl Maybe (Range 1 500 Int32)
mSize TeamId
tid Maybe InvitationId
miid = do
  Page
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
page <- RetrySettings
-> Client
     (Page
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client
     (Page
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 case Maybe InvitationId
miid of
    Just InvitationId
ref -> PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> QueryParams (TeamId, InvitationId)
-> Client
     (Page
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Page b)
paginate PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
cqlSelectFrom (Consistency
-> (TeamId, InvitationId)
-> Int32
-> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> Int32 -> QueryParams a
paramsP Consistency
LocalQuorum (TeamId
tid, InvitationId
ref) (Int32
pageSize Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
1))
    Maybe InvitationId
Nothing -> PrepQuery
  R
  (Identity TeamId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> QueryParams (Identity TeamId)
-> Client
     (Page
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Page b)
paginate PrepQuery
  R
  (Identity TeamId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
cqlSelect (Consistency
-> Identity TeamId -> Int32 -> QueryParams (Identity TeamId)
forall a. Consistency -> a -> Int32 -> QueryParams a
paramsP Consistency
LocalQuorum (TeamId -> Identity TeamId
forall a. a -> Identity a
Identity TeamId
tid) (Int32
pageSize Int32 -> Int32 -> Int32
forall a. Num a => a -> a -> a
+ Int32
1))
  PaginatedResult [StoredInvitation]
-> Client (PaginatedResult [StoredInvitation])
forall a. a -> Client a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (PaginatedResult [StoredInvitation]
 -> Client (PaginatedResult [StoredInvitation]))
-> PaginatedResult [StoredInvitation]
-> Client (PaginatedResult [StoredInvitation])
forall a b. (a -> b) -> a -> b
$ Bool -> [StoredInvitation] -> PaginatedResult [StoredInvitation]
forall {a}. Bool -> a -> PaginatedResult a
mkPage (Page
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> Bool
forall a. Page a -> Bool
hasMore Page
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
page) ([StoredInvitation] -> PaginatedResult [StoredInvitation])
-> [StoredInvitation] -> PaginatedResult [StoredInvitation]
forall a b. (a -> b) -> a -> b
$ ((TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
  EmailAddress, Maybe Name, InvitationCode)
 -> StoredInvitation)
-> [(TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
     EmailAddress, Maybe Name, InvitationCode)]
-> [StoredInvitation]
forall a b. (a -> b) -> [a] -> [b]
map (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
 EmailAddress, Maybe Name, InvitationCode)
-> StoredInvitation
TupleType StoredInvitation -> StoredInvitation
forall a. Record a => TupleType a -> a
asRecord ([(TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)]
 -> [StoredInvitation])
-> [(TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
     EmailAddress, Maybe Name, InvitationCode)]
-> [StoredInvitation]
forall a b. (a -> b) -> a -> b
$ Page
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> [(TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
     EmailAddress, Maybe Name, InvitationCode)]
forall a. Page a -> [a]
trim Page
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
page
  where
    pageSize :: Int32
    pageSize :: Int32
pageSize = Int32
-> (Range 1 500 Int32 -> Int32)
-> Maybe (Range 1 500 Int32)
-> Int32
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int32
100 Range 1 500 Int32 -> Int32
forall (n :: Nat) (m :: Nat) a. Range n m a -> a
fromRange Maybe (Range 1 500 Int32)
mSize

    trim :: Page a -> [a]
    trim :: forall a. Page a -> [a]
trim Page a
p = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take (Int32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int32
pageSize) (Page a -> [a]
forall a. Page a -> [a]
result Page a
p)

    mkPage :: Bool -> a -> PaginatedResult a
mkPage Bool
more a
invs = if Bool
more then a -> PaginatedResult a
forall a. a -> PaginatedResult a
PaginatedResultHasMore a
invs else a -> PaginatedResult a
forall a. a -> PaginatedResult a
PaginatedResult a
invs

    cqlSelect :: PrepQuery R (Identity TeamId) (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId, EmailAddress, Maybe Name, InvitationCode)
    cqlSelect :: PrepQuery
  R
  (Identity TeamId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
cqlSelect =
      [sql|
      SELECT team, role, id, created_at, created_by, email, name, code FROM team_invitation WHERE team = ? ORDER BY id ASC
      |]
    cqlSelectFrom :: PrepQuery R (TeamId, InvitationId) (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId, EmailAddress, Maybe Name, InvitationCode)
    cqlSelectFrom :: PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
cqlSelectFrom =
      [sql|
      SELECT team, role, id, created_at, created_by, email, name, code FROM team_invitation WHERE team = ? AND id > ? ORDER BY id ASC
      |]

countInvitationsImpl :: TeamId -> Client (Int64)
countInvitationsImpl :: TeamId -> Client Int64
countInvitationsImpl TeamId
t =
  Int64
-> (Identity Int64 -> Int64) -> Maybe (Identity Int64) -> Int64
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int64
0 Identity Int64 -> Int64
forall a. Identity a -> a
runIdentity
    (Maybe (Identity Int64) -> Int64)
-> Client (Maybe (Identity Int64)) -> Client Int64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RetrySettings
-> Client (Maybe (Identity Int64))
-> Client (Maybe (Identity Int64))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery R (Identity TeamId) (Identity Int64)
-> QueryParams (Identity TeamId) -> Client (Maybe (Identity Int64))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery R (Identity TeamId) (Identity Int64)
cql (Consistency -> Identity TeamId -> QueryParams (Identity TeamId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId -> Identity TeamId
forall a. a -> Identity a
Identity TeamId
t)))
  where
    cql :: PrepQuery R (Identity TeamId) (Identity Int64)
    cql :: PrepQuery R (Identity TeamId) (Identity Int64)
cql = [sql| SELECT count(*) FROM team_invitation WHERE team = ?|]

lookupInvitationByCodeImpl :: InvitationCode -> Client (Maybe StoredInvitation)
lookupInvitationByCodeImpl :: InvitationCode -> Client (Maybe StoredInvitation)
lookupInvitationByCodeImpl InvitationCode
code = MaybeT Client StoredInvitation -> Client (Maybe StoredInvitation)
forall (m :: * -> *) a. MaybeT m a -> m (Maybe a)
runMaybeT do
  (TeamId
teamId, InvitationId
invId, InvitationCode
_) <-
    Client (Maybe (TeamId, InvitationId, InvitationCode))
-> MaybeT Client (TeamId, InvitationId, InvitationCode)
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (Client (Maybe (TeamId, InvitationId, InvitationCode))
 -> MaybeT Client (TeamId, InvitationId, InvitationCode))
-> Client (Maybe (TeamId, InvitationId, InvitationCode))
-> MaybeT Client (TeamId, InvitationId, InvitationCode)
forall a b. (a -> b) -> a -> b
$
      RetrySettings
-> Client (Maybe (TeamId, InvitationId, InvitationCode))
-> Client (Maybe (TeamId, InvitationId, InvitationCode))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery
  R (Identity InvitationCode) (TeamId, InvitationId, InvitationCode)
-> QueryParams (Identity InvitationCode)
-> Client (Maybe (TeamId, InvitationId, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery
  R (Identity InvitationCode) (TeamId, InvitationId, InvitationCode)
cqlInfo (Consistency
-> Identity InvitationCode -> QueryParams (Identity InvitationCode)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (InvitationCode -> Identity InvitationCode
forall a. a -> Identity a
Identity InvitationCode
code)))
  Client (Maybe StoredInvitation) -> MaybeT Client StoredInvitation
forall (m :: * -> *) a. m (Maybe a) -> MaybeT m a
MaybeT (Client (Maybe StoredInvitation) -> MaybeT Client StoredInvitation)
-> Client (Maybe StoredInvitation)
-> MaybeT Client StoredInvitation
forall a b. (a -> b) -> a -> b
$ ((TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
  EmailAddress, Maybe Name, InvitationCode)
 -> StoredInvitation)
-> Maybe
     (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
      EmailAddress, Maybe Name, InvitationCode)
-> Maybe StoredInvitation
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
 EmailAddress, Maybe Name, InvitationCode)
-> StoredInvitation
TupleType StoredInvitation -> StoredInvitation
forall a. Record a => TupleType a -> a
asRecord (Maybe
   (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
    EmailAddress, Maybe Name, InvitationCode)
 -> Maybe StoredInvitation)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client (Maybe StoredInvitation)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RetrySettings
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> QueryParams (TeamId, InvitationId)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cqlMain (Consistency
-> (TeamId, InvitationId) -> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId
teamId, InvitationId
invId)))
  where
    cqlInfo :: PrepQuery R (Identity InvitationCode) (TeamId, InvitationId, InvitationCode)
    cqlInfo :: PrepQuery
  R (Identity InvitationCode) (TeamId, InvitationId, InvitationCode)
cqlInfo =
      [sql|
      SELECT team, id, code FROM team_invitation_info WHERE code = ?
      |]
    cqlMain :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
    cqlMain :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cqlMain =
      PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
[sql|
      SELECT team, role, id, created_at, created_by, email, name, code FROM team_invitation WHERE team = ? AND id = ?
      |]

lookupInvitationsByEmailImpl :: EmailAddress -> Client [StoredInvitation]
lookupInvitationsByEmailImpl :: EmailAddress -> Client [StoredInvitation]
lookupInvitationsByEmailImpl EmailAddress
email = do
  [(TeamId, InvitationId, InvitationCode)]
infoList <-
    RetrySettings
-> Client [(TeamId, InvitationId, InvitationCode)]
-> Client [(TeamId, InvitationId, InvitationCode)]
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery
  R (Identity EmailAddress) (TeamId, InvitationId, InvitationCode)
-> QueryParams (Identity EmailAddress)
-> Client [(TeamId, InvitationId, InvitationCode)]
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m [b]
query PrepQuery
  R (Identity EmailAddress) (TeamId, InvitationId, InvitationCode)
cqlInfo (Consistency
-> Identity EmailAddress -> QueryParams (Identity EmailAddress)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (EmailAddress -> Identity EmailAddress
forall a. a -> Identity a
Identity EmailAddress
email)))
  ([Maybe StoredInvitation] -> [StoredInvitation])
-> Client [Maybe StoredInvitation] -> Client [StoredInvitation]
forall a b. (a -> b) -> Client a -> Client b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Maybe StoredInvitation] -> [StoredInvitation]
forall a. [Maybe a] -> [a]
catMaybes (Client [Maybe StoredInvitation] -> Client [StoredInvitation])
-> Client [Maybe StoredInvitation] -> Client [StoredInvitation]
forall a b. (a -> b) -> a -> b
$ [(TeamId, InvitationId, InvitationCode)]
-> ((TeamId, InvitationId, InvitationCode)
    -> Client (Maybe StoredInvitation))
-> Client [Maybe StoredInvitation]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM [(TeamId, InvitationId, InvitationCode)]
infoList (((TeamId, InvitationId, InvitationCode)
  -> Client (Maybe StoredInvitation))
 -> Client [Maybe StoredInvitation])
-> ((TeamId, InvitationId, InvitationCode)
    -> Client (Maybe StoredInvitation))
-> Client [Maybe StoredInvitation]
forall a b. (a -> b) -> a -> b
$ \(TeamId
tid, InvitationId
invId, InvitationCode
_invCode) ->
    ((TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
  EmailAddress, Maybe Name, InvitationCode)
 -> StoredInvitation)
-> Maybe
     (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
      EmailAddress, Maybe Name, InvitationCode)
-> Maybe StoredInvitation
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
 EmailAddress, Maybe Name, InvitationCode)
-> StoredInvitation
TupleType StoredInvitation -> StoredInvitation
forall a. Record a => TupleType a -> a
asRecord (Maybe
   (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
    EmailAddress, Maybe Name, InvitationCode)
 -> Maybe StoredInvitation)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client (Maybe StoredInvitation)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RetrySettings
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> QueryParams (TeamId, InvitationId)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cqlMain (Consistency
-> (TeamId, InvitationId) -> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId
tid, InvitationId
invId)))
  where
    cqlInfo :: PrepQuery R (Identity EmailAddress) (TeamId, InvitationId, InvitationCode)
    cqlInfo :: PrepQuery
  R (Identity EmailAddress) (TeamId, InvitationId, InvitationCode)
cqlInfo =
      [sql|
      SELECT team, invitation, code FROM team_invitation_email WHERE email = ?
      |]
    cqlMain :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
    cqlMain :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cqlMain =
      PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
[sql|
      SELECT team, role, id, created_at, created_by, email, name, code FROM team_invitation WHERE team = ? AND id = ?
      |]

lookupInvitationImpl :: TeamId -> InvitationId -> Client (Maybe StoredInvitation)
lookupInvitationImpl :: TeamId -> InvitationId -> Client (Maybe StoredInvitation)
lookupInvitationImpl TeamId
tid InvitationId
iid =
  ((TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
  EmailAddress, Maybe Name, InvitationCode)
 -> StoredInvitation)
-> Maybe
     (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
      EmailAddress, Maybe Name, InvitationCode)
-> Maybe StoredInvitation
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
 EmailAddress, Maybe Name, InvitationCode)
-> StoredInvitation
TupleType StoredInvitation -> StoredInvitation
forall a. Record a => TupleType a -> a
asRecord
    (Maybe
   (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
    EmailAddress, Maybe Name, InvitationCode)
 -> Maybe StoredInvitation)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client (Maybe StoredInvitation)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> RetrySettings
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
-> QueryParams (TeamId, InvitationId)
-> Client
     (Maybe
        (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
         EmailAddress, Maybe Name, InvitationCode))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery
  R
  (TeamId, InvitationId)
  (TeamId, Maybe Role, InvitationId, UTCTimeMillis, Maybe UserId,
   EmailAddress, Maybe Name, InvitationCode)
PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cql (Consistency
-> (TeamId, InvitationId) -> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId
tid, InvitationId
iid)))
  where
    cql :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
    cql :: PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
cql =
      PrepQuery R (TeamId, InvitationId) (TupleType StoredInvitation)
[sql|
      SELECT team, role, id, created_at, created_by, email, name, code FROM team_invitation WHERE team = ? AND id = ?
      |]

deleteInvitationImpl :: TeamId -> InvitationId -> Client ()
deleteInvitationImpl :: TeamId -> InvitationId -> Client ()
deleteInvitationImpl TeamId
teamId InvitationId
invId = do
  Maybe (InvitationCode, EmailAddress)
codeEmail <- Client (Maybe (InvitationCode, EmailAddress))
lookupInvitationCodeEmail
  case Maybe (InvitationCode, EmailAddress)
codeEmail of
    Just (InvitationCode
invCode, EmailAddress
invEmail) -> RetrySettings -> Client () -> Client ()
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x5 (Client () -> Client ())
-> (BatchM () -> Client ()) -> BatchM () -> Client ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BatchM () -> Client ()
forall (m :: * -> *). MonadClient m => BatchM () -> m ()
batch (BatchM () -> Client ()) -> BatchM () -> Client ()
forall a b. (a -> b) -> a -> b
$ do
      BatchType -> BatchM ()
setType BatchType
BatchLogged
      Consistency -> BatchM ()
setConsistency Consistency
LocalQuorum
      PrepQuery W (TeamId, InvitationId) ()
-> (TeamId, InvitationId) -> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery W (TeamId, InvitationId) ()
cqlInvitation (TeamId
teamId, InvitationId
invId)
      PrepQuery W (Identity InvitationCode) ()
-> Identity InvitationCode -> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery W (Identity InvitationCode) ()
cqlInvitationInfo (InvitationCode -> Identity InvitationCode
forall a. a -> Identity a
Identity InvitationCode
invCode)
      PrepQuery W (EmailAddress, TeamId) ()
-> (EmailAddress, TeamId) -> BatchM ()
forall a b.
(Show a, Tuple a, Tuple b) =>
PrepQuery W a b -> a -> BatchM ()
addPrepQuery PrepQuery W (EmailAddress, TeamId) ()
cqlInvitationEmail (EmailAddress
invEmail, TeamId
teamId)
    Maybe (InvitationCode, EmailAddress)
Nothing ->
      RetrySettings -> Client () -> Client ()
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x5 (Client () -> Client ()) -> Client () -> Client ()
forall a b. (a -> b) -> a -> b
$ PrepQuery W (TeamId, InvitationId) ()
-> QueryParams (TeamId, InvitationId) -> Client ()
forall (m :: * -> *) a (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, RunQ q) =>
q W a () -> QueryParams a -> m ()
write PrepQuery W (TeamId, InvitationId) ()
cqlInvitation (Consistency
-> (TeamId, InvitationId) -> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId
teamId, InvitationId
invId))
  where
    lookupInvitationCodeEmail :: Client (Maybe (InvitationCode, EmailAddress))
    lookupInvitationCodeEmail :: Client (Maybe (InvitationCode, EmailAddress))
lookupInvitationCodeEmail = RetrySettings
-> Client (Maybe (InvitationCode, EmailAddress))
-> Client (Maybe (InvitationCode, EmailAddress))
forall (m :: * -> *) a.
MonadClient m =>
RetrySettings -> m a -> m a
retry RetrySettings
x1 (PrepQuery R (TeamId, InvitationId) (InvitationCode, EmailAddress)
-> QueryParams (TeamId, InvitationId)
-> Client (Maybe (InvitationCode, EmailAddress))
forall (m :: * -> *) a b (q :: * -> * -> * -> *).
(MonadClient m, Tuple a, Tuple b, RunQ q) =>
q R a b -> QueryParams a -> m (Maybe b)
query1 PrepQuery R (TeamId, InvitationId) (InvitationCode, EmailAddress)
cqlInvitationCodeEmail (Consistency
-> (TeamId, InvitationId) -> QueryParams (TeamId, InvitationId)
forall a. Consistency -> a -> QueryParams a
params Consistency
LocalQuorum (TeamId
teamId, InvitationId
invId)))

    cqlInvitation :: PrepQuery W (TeamId, InvitationId) ()
    cqlInvitation :: PrepQuery W (TeamId, InvitationId) ()
cqlInvitation =
      [sql|
        DELETE FROM team_invitation where team = ? AND id = ?
      |]

    cqlInvitationInfo :: PrepQuery W (Identity InvitationCode) ()
    cqlInvitationInfo :: PrepQuery W (Identity InvitationCode) ()
cqlInvitationInfo =
      [sql|
        DELETE FROM team_invitation_info WHERE code = ?
      |]

    cqlInvitationEmail :: PrepQuery W (EmailAddress, TeamId) ()
    cqlInvitationEmail :: PrepQuery W (EmailAddress, TeamId) ()
cqlInvitationEmail =
      [sql|
        DELETE FROM team_invitation_email WHERE email = ? AND team = ?
      |]

    cqlInvitationCodeEmail :: PrepQuery R (TeamId, InvitationId) (InvitationCode, EmailAddress)
    cqlInvitationCodeEmail :: PrepQuery R (TeamId, InvitationId) (InvitationCode, EmailAddress)
cqlInvitationCodeEmail =
      [sql|
        SELECT code, email FROM team_invitation WHERE team = ? AND id = ?
      |]

deleteInvitationsImpl :: TeamId -> Client ()
deleteInvitationsImpl :: TeamId -> Client ()
deleteInvitationsImpl TeamId
teamId =
  ConduitT () Void Client () -> Client ()
forall (m :: * -> *) r. Monad m => ConduitT () Void m r -> m r
runConduit (ConduitT () Void Client () -> Client ())
-> ConduitT () Void Client () -> Client ()
forall a b. (a -> b) -> a -> b
$
    PrepQuery R (Identity TeamId) (Identity InvitationId)
-> QueryParams (Identity TeamId)
-> RetrySettings
-> ConduitM () [Identity InvitationId] Client ()
forall a b (q :: * -> * -> * -> *) (m :: * -> *).
(Tuple a, Tuple b, RunQ q, MonadClient m) =>
q R a b -> QueryParams a -> RetrySettings -> ConduitM () [b] m ()
paginateC PrepQuery R (Identity TeamId) (Identity InvitationId)
cqlSelect (Consistency
-> Identity TeamId -> Int32 -> QueryParams (Identity TeamId)
forall a. Consistency -> a -> Int32 -> QueryParams a
paramsP Consistency
LocalQuorum (TeamId -> Identity TeamId
forall a. a -> Identity a
Identity TeamId
teamId) Int32
100) RetrySettings
x1
      ConduitM () [Identity InvitationId] Client ()
-> ConduitT [Identity InvitationId] Void Client ()
-> ConduitT () Void Client ()
forall (m :: * -> *) a b c r.
Monad m =>
ConduitT a b m () -> ConduitT b c m r -> ConduitT a c m r
.| ([Identity InvitationId] -> Client ())
-> ConduitT [Identity InvitationId] Void Client ()
forall (m :: * -> *) a o.
Monad m =>
(a -> m ()) -> ConduitT a o m ()
Conduit.mapM_ (Int
-> (Identity InvitationId -> Client ())
-> [Identity InvitationId]
-> Client ()
forall (m :: * -> *) (f :: * -> *) a b.
(MonadUnliftIO m, Foldable f) =>
Int -> (a -> m b) -> f a -> m ()
pooledMapConcurrentlyN_ Int
16 (TeamId -> InvitationId -> Client ()
deleteInvitationImpl TeamId
teamId (InvitationId -> Client ())
-> (Identity InvitationId -> InvitationId)
-> Identity InvitationId
-> Client ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Identity InvitationId -> InvitationId
forall a. Identity a -> a
runIdentity))
  where
    cqlSelect :: PrepQuery R (Identity TeamId) (Identity InvitationId)
    cqlSelect :: PrepQuery R (Identity TeamId) (Identity InvitationId)
cqlSelect = PrepQuery R (Identity TeamId) (Identity InvitationId)
"SELECT id FROM team_invitation WHERE team = ? ORDER BY id ASC"