{-# OPTIONS -Wno-ambiguous-fields #-}
module Notifications where

import API.Gundeck
import Control.Error (lastMay)
import Control.Monad.Extra
import Control.Monad.Reader (asks)
import Testlib.Prelude
import UnliftIO (timeout)
import UnliftIO.Concurrent

-- | assert that no notifications with the predicate happen within the timeout
assertNoNotifications ::
  (HasCallStack, MakesValue user, MakesValue client) =>
  -- | the user
  user ->
  -- | the client of that user
  client ->
  -- | the last notif
  Maybe String ->
  -- | the predicate
  (Value -> App Bool) ->
  App ()
assertNoNotifications :: forall user client.
(HasCallStack, MakesValue user, MakesValue client) =>
user -> client -> Maybe String -> (Value -> App Bool) -> App ()
assertNoNotifications user
u client
uc Maybe String
since0 Value -> App Bool
p = do
  String
ucid <- client -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
objId client
uc
  let go :: Maybe String -> App Any
go Maybe String
since = do
        [Value]
notifs <-
          user -> GetNotifications -> App Response
forall user.
(HasCallStack, MakesValue user) =>
user -> GetNotifications -> App Response
getNotifications user
u GetNotifications
forall a. Default a => a
def {client = Just ucid, since = since}
            App Response -> (Response -> App [Value]) -> App [Value]
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
`bindResponse` App Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
              (App Value -> App [Value])
-> (Response -> App Value) -> Response -> App [Value]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications")
              (App Value -> App Value)
-> (Response -> App Value) -> Response -> App Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (.json)
        (Value -> App Bool) -> [Value] -> App ([Value], [Value])
forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> [a] -> m ([a], [a])
partitionM Value -> App Bool
p [Value]
notifs App ([Value], [Value])
-> (([Value], [Value]) -> App Any) -> App Any
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
          ([], [Value]
nonMatching) ->
            Int -> App ()
forall (m :: * -> *). MonadIO m => Int -> m ()
threadDelay Int
1_000 App () -> App Any -> App Any
forall a b. App a -> App b -> App b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> case [Value]
nonMatching of
              ([Value] -> Maybe Value
forall a. [a] -> Maybe a
lastMay -> Just Value
lst) -> Value -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
objId Value
lst App String -> (String -> App Any) -> App Any
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe String -> App Any
go (Maybe String -> App Any)
-> (String -> Maybe String) -> String -> App Any
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just
              [Value]
_ -> Maybe String -> App Any
go Maybe String
forall a. Maybe a
Nothing
          ([Value]
matching, [Value]
_) -> do
            String
pj <- [Value] -> App String
forall a. MakesValue a => a -> App String
prettyJSON [Value]
matching
            String -> App Any
forall a. HasCallStack => String -> App a
assertFailure
              (String -> App Any) -> String -> App Any
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
                [ String
"Expected no matching events  but got:",
                  String
pj
                ]
  Maybe Any
Nothing <- (Env -> Int) -> App Int
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks Env -> Int
timeOutSeconds App Int -> (Int -> App (Maybe Any)) -> App (Maybe Any)
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Int -> App Any -> App (Maybe Any))
-> App Any -> Int -> App (Maybe Any)
forall a b c. (a -> b -> c) -> b -> a -> c
flip Int -> App Any -> App (Maybe Any)
forall (m :: * -> *) a.
MonadUnliftIO m =>
Int -> m a -> m (Maybe a)
timeout (Maybe String -> App Any
go Maybe String
since0)
  () -> App ()
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

awaitNotifications ::
  (HasCallStack, MakesValue user, MakesValue client) =>
  user ->
  client ->
  Maybe String ->
  -- | Max no. of notifications
  Int ->
  -- | Selection function. Should not throw any exceptions
  (Value -> App Bool) ->
  App [Value]
awaitNotifications :: forall user client.
(HasCallStack, MakesValue user, MakesValue client) =>
user
-> client
-> Maybe String
-> Int
-> (Value -> App Bool)
-> App [Value]
awaitNotifications user
user client
client Maybe String
since0 Int
n Value -> App Bool
selector = do
  Int
tSecs <- (Env -> Int) -> App Int
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks ((Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1000) (Int -> Int) -> (Env -> Int) -> Env -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Env -> Int
timeOutSeconds)
  HasCallStack => AwaitResult -> App [Value]
AwaitResult -> App [Value]
assertAwaitResult (AwaitResult -> App [Value]) -> App AwaitResult -> App [Value]
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Int -> Maybe String -> AwaitResult -> App AwaitResult
go Int
tSecs Maybe String
since0 (Bool -> Int -> [Value] -> [Value] -> AwaitResult
AwaitResult Bool
False Int
n [] [])
  where
    go :: Int -> Maybe String -> AwaitResult -> App AwaitResult
go Int
timeRemaining Maybe String
since AwaitResult
res0
      | Int
timeRemaining Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = AwaitResult -> App AwaitResult
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AwaitResult
res0
      | Bool
otherwise =
          do
            String
c <- client -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make client
client App Value -> (App Value -> App String) -> App String
forall a b. a -> (a -> b) -> b
& App Value -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
asString
            [Value]
notifs <-
              user -> GetNotifications -> App Response
forall user.
(HasCallStack, MakesValue user) =>
user -> GetNotifications -> App Response
getNotifications
                user
user
                GetNotifications
forall a. Default a => a
def {since = since, client = Just c}
                App Response -> (Response -> App [Value]) -> App [Value]
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
`bindResponse` \Response
resp -> App Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList (Response
resp.json App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications")
            Maybe String
lastNotifId <- case [Value]
notifs of
              [] -> Maybe String -> App (Maybe String)
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe String
since
              [Value]
_ -> String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> App String -> App (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Value -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
objId ([Value] -> Value
forall a. HasCallStack => [a] -> a
last [Value]
notifs)
            ([Value]
matching, [Value]
notMatching) <- (Value -> App Bool) -> [Value] -> App ([Value], [Value])
forall (m :: * -> *) a.
Monad m =>
(a -> m Bool) -> [a] -> m ([a], [a])
partitionM Value -> App Bool
selector [Value]
notifs
            let matchesSoFar :: [Value]
matchesSoFar = AwaitResult
res0.matches [Value] -> [Value] -> [Value]
forall a. Semigroup a => a -> a -> a
<> [Value]
matching
                res :: AwaitResult
res =
                  AwaitResult
res0
                    { matches = matchesSoFar,
                      nonMatches = res0.nonMatches <> notMatching,
                      success = length matchesSoFar >= res0.nMatchesExpected
                    }
            if AwaitResult
res.success
              then AwaitResult -> App AwaitResult
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure AwaitResult
res
              else do
                Int -> App ()
forall (m :: * -> *). MonadIO m => Int -> m ()
threadDelay Int
1_000
                Int -> Maybe String -> AwaitResult -> App AwaitResult
go (Int
timeRemaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) Maybe String
lastNotifId AwaitResult
res

awaitNotification ::
  (HasCallStack, MakesValue user, MakesValue client, MakesValue lastNotifId) =>
  user ->
  client ->
  Maybe lastNotifId ->
  (Value -> App Bool) ->
  App Value
awaitNotification :: forall user client lastNotifId.
(HasCallStack, MakesValue user, MakesValue client,
 MakesValue lastNotifId) =>
user
-> client -> Maybe lastNotifId -> (Value -> App Bool) -> App Value
awaitNotification user
user client
client Maybe lastNotifId
lastNotifId Value -> App Bool
selector = do
  Maybe String
since0 <- (lastNotifId -> App String)
-> Maybe lastNotifId -> App (Maybe String)
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> Maybe a -> m (Maybe b)
mapM lastNotifId -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
objId Maybe lastNotifId
lastNotifId
  [Value] -> Value
forall a. HasCallStack => [a] -> a
head ([Value] -> Value) -> App [Value] -> App Value
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> user
-> client
-> Maybe String
-> Int
-> (Value -> App Bool)
-> App [Value]
forall user client.
(HasCallStack, MakesValue user, MakesValue client) =>
user
-> client
-> Maybe String
-> Int
-> (Value -> App Bool)
-> App [Value]
awaitNotifications user
user client
client Maybe String
since0 Int
1 Value -> App Bool
selector

isDeleteUserNotif :: (MakesValue a) => a -> App Bool
isDeleteUserNotif :: forall a. MakesValue a => a -> App Bool
isDeleteUserNotif a
n =
  a -> App Value
forall a. MakesValue a => a -> App Value
nPayload a
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` String
"user.delete"

isFeatureConfigUpdateNotif :: (MakesValue a) => a -> App Bool
isFeatureConfigUpdateNotif :: forall a. MakesValue a => a -> App Bool
isFeatureConfigUpdateNotif a
n =
  a -> App Value
forall a. MakesValue a => a -> App Value
nPayload a
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` String
"feature-config.update"

isNewMessageNotif :: (MakesValue a) => a -> App Bool
isNewMessageNotif :: forall a. MakesValue a => a -> App Bool
isNewMessageNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.otr-message-add"

isNewMLSMessageNotif :: (MakesValue a) => a -> App Bool
isNewMLSMessageNotif :: forall a. MakesValue a => a -> App Bool
isNewMLSMessageNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.mls-message-add"

isWelcomeNotif :: (MakesValue a) => a -> App Bool
isWelcomeNotif :: forall a. MakesValue a => a -> App Bool
isWelcomeNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.mls-welcome"

isMemberJoinNotif :: (MakesValue a) => a -> App Bool
isMemberJoinNotif :: forall a. MakesValue a => a -> App Bool
isMemberJoinNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.member-join"

isConvLeaveNotif :: (MakesValue a) => a -> App Bool
isConvLeaveNotif :: forall a. MakesValue a => a -> App Bool
isConvLeaveNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.member-leave"

isConvLeaveNotifWithLeaver :: (MakesValue user, MakesValue a) => user -> a -> App Bool
isConvLeaveNotifWithLeaver :: forall user a.
(MakesValue user, MakesValue a) =>
user -> a -> App Bool
isConvLeaveNotifWithLeaver user
user a
n =
  a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.member-leave"
    App Bool -> App Bool -> App Bool
&&~ (a
n a -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"payload.0.data.user_ids.0") App Value -> App Value -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` (user
user user -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"id")

isNotifConv :: (MakesValue conv, MakesValue a, HasCallStack) => conv -> a -> App Bool
isNotifConv :: forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifConv conv
conv a
n = a -> String -> App Value -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.qualified_conversation" (conv -> App Value
forall a. (HasCallStack, MakesValue a) => a -> App Value
objQidObject conv
conv)

isNotifForUser :: (MakesValue user, MakesValue a, HasCallStack) => user -> a -> App Bool
isNotifForUser :: forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifForUser user
user a
n = a -> String -> App Value -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.data.qualified_user_ids.0" (user -> App Value
forall a. (HasCallStack, MakesValue a) => a -> App Value
objQidObject user
user)

isNotifFromUser :: (MakesValue user, MakesValue a, HasCallStack) => user -> a -> App Bool
isNotifFromUser :: forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifFromUser user
user a
n = a -> String -> App Value -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.qualified_from" (user -> App Value
forall a. (HasCallStack, MakesValue a) => a -> App Value
objQidObject user
user)

isConvNameChangeNotif :: (HasCallStack, MakesValue a) => a -> App Bool
isConvNameChangeNotif :: forall a. (HasCallStack, MakesValue a) => a -> App Bool
isConvNameChangeNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.rename"

isMemberUpdateNotif :: (HasCallStack, MakesValue n) => n -> App Bool
isMemberUpdateNotif :: forall a. (HasCallStack, MakesValue a) => a -> App Bool
isMemberUpdateNotif n
n = n -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals n
n String
"payload.0.type" String
"conversation.member-update"

isReceiptModeUpdateNotif :: (HasCallStack, MakesValue n) => n -> App Bool
isReceiptModeUpdateNotif :: forall a. (HasCallStack, MakesValue a) => a -> App Bool
isReceiptModeUpdateNotif n
n =
  n -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals n
n String
"payload.0.type" String
"conversation.receipt-mode-update"

isConvMsgTimerUpdateNotif :: (HasCallStack, MakesValue n) => n -> App Bool
isConvMsgTimerUpdateNotif :: forall a. (HasCallStack, MakesValue a) => a -> App Bool
isConvMsgTimerUpdateNotif n
n =
  n -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals n
n String
"payload.0.type" String
"conversation.message-timer-update"

isConvAccessUpdateNotif :: (HasCallStack, MakesValue n) => n -> App Bool
isConvAccessUpdateNotif :: forall a. (HasCallStack, MakesValue a) => a -> App Bool
isConvAccessUpdateNotif n
n =
  n -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals n
n String
"payload.0.type" String
"conversation.access-update"

isConvCreateNotif :: (MakesValue a) => a -> App Bool
isConvCreateNotif :: forall a. MakesValue a => a -> App Bool
isConvCreateNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.create"

-- | like 'isConvCreateNotif' but excludes self conversations
isConvCreateNotifNotSelf :: (MakesValue a) => a -> App Bool
isConvCreateNotifNotSelf :: forall a. MakesValue a => a -> App Bool
isConvCreateNotifNotSelf a
n =
  a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.create"
    App Bool -> App Bool -> App Bool
&&~ do Bool -> Bool
not (Bool -> Bool) -> App Bool -> App Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> String -> [String] -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.data.access" [String
"private"]

isConvDeleteNotif :: (MakesValue a) => a -> App Bool
isConvDeleteNotif :: forall a. MakesValue a => a -> App Bool
isConvDeleteNotif a
n = a -> String -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b) =>
a -> String -> b -> App Bool
fieldEquals a
n String
"payload.0.type" String
"conversation.delete"

notifTypeIsEqual :: (MakesValue a) => String -> a -> App Bool
notifTypeIsEqual :: forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
typ a
n = a -> App Value
forall a. MakesValue a => a -> App Value
nPayload a
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` String
typ

isTeamMemberLeaveNotif :: (MakesValue a) => a -> App Bool
isTeamMemberLeaveNotif :: forall a. MakesValue a => a -> App Bool
isTeamMemberLeaveNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"team.member-leave"

isUserActivateNotif :: (MakesValue a) => a -> App Bool
isUserActivateNotif :: forall a. MakesValue a => a -> App Bool
isUserActivateNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.activate"

isUserClientAddNotif :: (MakesValue a) => a -> App Bool
isUserClientAddNotif :: forall a. MakesValue a => a -> App Bool
isUserClientAddNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.client-add"

isUserUpdatedNotif :: (MakesValue a) => a -> App Bool
isUserUpdatedNotif :: forall a. MakesValue a => a -> App Bool
isUserUpdatedNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.update"

isUserClientRemoveNotif :: (MakesValue a) => a -> App Bool
isUserClientRemoveNotif :: forall a. MakesValue a => a -> App Bool
isUserClientRemoveNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.client-remove"

isUserLegalholdRequestNotif :: (MakesValue a) => a -> App Bool
isUserLegalholdRequestNotif :: forall a. MakesValue a => a -> App Bool
isUserLegalholdRequestNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.legalhold-request"

isUserLegalholdEnabledNotif :: (MakesValue a) => a -> App Bool
isUserLegalholdEnabledNotif :: forall a. MakesValue a => a -> App Bool
isUserLegalholdEnabledNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.legalhold-enable"

isUserLegalholdDisabledNotif :: (MakesValue a) => a -> App Bool
isUserLegalholdDisabledNotif :: forall a. MakesValue a => a -> App Bool
isUserLegalholdDisabledNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.legalhold-disable"

isUserConnectionNotif :: (MakesValue a) => a -> App Bool
isUserConnectionNotif :: forall a. MakesValue a => a -> App Bool
isUserConnectionNotif = String -> a -> App Bool
forall a. MakesValue a => String -> a -> App Bool
notifTypeIsEqual String
"user.connection"

isConnectionNotif :: (MakesValue a) => String -> a -> App Bool
isConnectionNotif :: forall a. MakesValue a => String -> a -> App Bool
isConnectionNotif String
status a
n =
  -- NB:
  -- (&&) <$> (print "hello" *> pure False) <*> fail "bla" === _|_
  -- runMaybeT $  (lift (print "hello") *> MaybeT (pure Nothing)) *> lift (fail "bla") === pure Nothing
  a -> App Value
forall a. MakesValue a => a -> App Value
nPayload a
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` String
"user.connection"
    App Bool -> App Bool -> App Bool
&&~ a -> App Value
forall a. MakesValue a => a -> App Value
nPayload a
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"connection.status" App Value -> String -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
`isEqual` String
status

assertLeaveNotification ::
  ( HasCallStack,
    MakesValue fromUser,
    MakesValue conv,
    MakesValue user,
    MakesValue kickedUser
  ) =>
  fromUser ->
  conv ->
  user ->
  String ->
  kickedUser ->
  App ()
assertLeaveNotification :: forall fromUser conv user kickedUser.
(HasCallStack, MakesValue fromUser, MakesValue conv,
 MakesValue user, MakesValue kickedUser) =>
fromUser -> conv -> user -> String -> kickedUser -> App ()
assertLeaveNotification fromUser
fromUser conv
conv user
user String
client kickedUser
leaver =
  App Value -> App ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void
    (App Value -> App ()) -> App Value -> App ()
forall a b. (a -> b) -> a -> b
$ user -> String -> Maybe Value -> (Value -> App Bool) -> App Value
forall user client lastNotifId.
(HasCallStack, MakesValue user, MakesValue client,
 MakesValue lastNotifId) =>
user
-> client -> Maybe lastNotifId -> (Value -> App Bool) -> App Value
awaitNotification
      user
user
      String
client
      Maybe Value
noValue
      ( [Value -> App Bool] -> Value -> App Bool
forall (f :: * -> *) a.
Applicative f =>
[a -> f Bool] -> a -> f Bool
allPreds
          [ Value -> App Bool
forall a. MakesValue a => a -> App Bool
isConvLeaveNotif,
            conv -> Value -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifConv conv
conv,
            kickedUser -> Value -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifForUser kickedUser
leaver,
            fromUser -> Value -> App Bool
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App Bool
isNotifFromUser fromUser
fromUser
          ]
      )

assertConvUserDeletedNotif :: (MakesValue leaverId) => WebSocket -> leaverId -> App ()
assertConvUserDeletedNotif :: forall leaverId.
MakesValue leaverId =>
WebSocket -> leaverId -> App ()
assertConvUserDeletedNotif WebSocket
ws leaverId
leaverId = do
  Value
n <- HasCallStack => (Value -> App Bool) -> WebSocket -> App Value
(Value -> App Bool) -> WebSocket -> App Value
awaitMatch Value -> App Bool
forall a. MakesValue a => a -> App Bool
isConvLeaveNotif WebSocket
ws
  Value -> App Value
forall a. MakesValue a => a -> App Value
nPayload Value
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"data.qualified_user_ids.0" App Value -> leaverId -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` leaverId
leaverId
  Value -> App Value
forall a. MakesValue a => a -> App Value
nPayload Value
n App Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"data.reason" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"user-deleted"