{-# OPTIONS -Wno-incomplete-patterns -Wno-ambiguous-fields #-}
module Test.Apps where
import API.Brig
import qualified API.BrigInternal as BrigI
import API.Common
import API.Galley
import Control.Lens hiding ((.=))
import Data.Aeson.QQ.Simple
import MLS.Util
import Notifications
import SetupHelpers
import Testlib.Prelude
testCreateGetApp :: (HasCallStack) => Domain -> App ()
testCreateGetApp :: HasCallStack => Domain -> App ()
testCreateGetApp Domain
sameOrOtherDomain = do
domainA <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
domainB <- make sameOrOtherDomain
(owner, tid, [regularMember]) <- createTeam domainA 2
let new :: NewApp =
def
{ name = "chappie",
description = "some description of this app",
category = "ai"
}
bindResponse (createApp regularMember tid new) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
403
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"app-no-permission"
lastTeamNotif <- bindResponse (getTeamNotifications regularMember Nothing) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications.-1.id" 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
(appId, cookie) <- withWebSockets [owner, regularMember] \[WebSocket
wsOwner, WebSocket
wsRegularMember] -> do
App Response
-> (Response -> App (String, String)) -> App (String, String)
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (Value -> String -> NewApp -> App Response
forall creator.
MakesValue creator =>
creator -> String -> NewApp -> App Response
createApp Value
owner String
tid NewApp
new) ((Response -> App (String, String)) -> App (String, String))
-> (Response -> App (String, String)) -> App (String, String)
forall a b. (a -> b) -> a -> b
$ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
appId <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user.id" 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
cookie <- resp.json %. "cookie" & asString
_ <- do
let predicate a
payload = do
typ <- a
payload a -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"payload.0.type" 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
pure $ typ == "team.member-join"
void $ awaitMatch predicate wsOwner
void $ assertNoEvent 5 wsRegularMember
pure (appId, cookie)
bindResponse (getTeamNotifications regularMember (Just lastTeamNotif)) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications.1.payload.0.type" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"team.member-join"
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications.1.payload.0.team" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
tid
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"notifications.1.payload.0.data.user" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
appId
let appIdObject = [Pair] -> Value
object [String
"domain" String -> Value -> Pair
forall a. ToJSON a => String -> a -> Pair
.= Value
domainA, String
"id" String -> String -> Pair
forall a. ToJSON a => String -> a -> Pair
.= String
appId]
bindResponse (getUser owner appIdObject) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"app"
bindResponse (getApp owner tid appId) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
bindResponse (getApps owner tid) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
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
$ Response
resp.json Maybe Value -> (Maybe Value -> App [Value]) -> App [Value]
forall a b. a -> (a -> b) -> b
& Maybe Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList App [Value] -> ([Value] -> App Value) -> App Value
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= [Value] -> App Value
forall (t :: * -> *) a. (HasCallStack, Foldable t) => t a -> App a
assertOne
bindResponse (createApp owner tid (new {name = "fmappie"})) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
bindResponse (getApps owner tid) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
apps <- Response
resp.json Maybe Value -> (Maybe Value -> App [Value]) -> App [Value]
forall a b. a -> (a -> b) -> b
& Maybe Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
name1 <- apps %. "0.name"
name2 <- apps %. "1.name"
[name1, name2] `shouldMatchSet` ["chappie", "fmappie"]
bindResponse (getUser owner owner) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"type" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"regular"
void $ bindResponse (renewToken domainA cookie) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
appId
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"token_type" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"Bearer"
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"access_token" 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
void $ getApp regularMember tid appId `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
(Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"name") App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"chappie"
(Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"app.description") App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"some description of this app"
(Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"app.category") App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"ai"
outsideUser <- randomUser domainB (def {BrigI.team = False})
bindResponse (getApp outsideUser tid appId) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
(owner2, tid2, [regularMember2]) <- createTeam domainB 2
bindResponse (getApp owner2 tid appId) $ \Response
resp -> Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
bindResponse (getApp owner2 tid2 appId) $ \Response
resp -> Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
bindResponse (getApp regularMember2 tid appId) $ \Response
resp -> Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
void $ getApp owner2 tid appId `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"not-found"
void $ bindResponse (createApp owner tid new {category = "notinenum"}) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
String -> Value -> App Value -> App Response
forall owner member.
(HasCallStack, MakesValue owner, MakesValue member) =>
String -> owner -> member -> App Response
deleteTeamMember String
tid Value
owner (Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user") App Response -> (Response -> App ()) -> App ()
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HasCallStack => Response -> App ()
Response -> App ()
assertSuccess
testRefreshAppCookie :: (HasCallStack) => App ()
testRefreshAppCookie :: HasCallStack => App ()
testRefreshAppCookie = do
(alice, tid, [bob]) <- Domain -> Int -> App (Value, String, [Value])
forall domain.
(HasCallStack, MakesValue domain) =>
domain -> Int -> App (Value, String, [Value])
createTeam Domain
OwnDomain Int
2
charlie <- randomUser OwnDomain def
let new = NewApp
forall a. Default a => a
def {name = "flexo"} :: NewApp
goodPassword = Value -> Maybe Value
forall a. a -> Maybe a
Just ([Pair] -> Value
object [String
"password" String -> String -> Pair
forall a. ToJSON a => String -> a -> Pair
.= String
defPassword])
(appId, cookie) <- bindResponse (createApp alice tid new) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
appId <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user.id" 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
cookie <- resp.json %. "cookie" & asString
pure (appId, cookie)
bindResponse (refreshAppCookie bob tid appId goodPassword) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
403
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"app-no-permission"
bindResponse (refreshAppCookie charlie tid appId goodPassword) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
403
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"app-no-permission"
forM_
[ (Nothing, 415),
(Just Null, 400),
(Just (object []), 403),
(Just (object ["password" .= "this is not a good password"]), 403)
]
$ \(Maybe Value
badPassword, Int
stat) -> do
Value -> String -> String -> Maybe Value -> App Response
forall u.
MakesValue u =>
u -> String -> String -> Maybe Value -> App Response
refreshAppCookie Value
alice String
tid String
appId Maybe Value
badPassword App Response -> (Response -> App ()) -> App ()
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= HasCallStack => Int -> Response -> App ()
Int -> Response -> App ()
assertStatus Int
stat
cookie' <- bindResponse (refreshAppCookie alice tid appId goodPassword) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"cookie" 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
renewToken OwnDomain cookie `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
403
renewToken OwnDomain cookie' `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
appId
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"token_type" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"Bearer"
App String -> App ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (App String -> App ()) -> App String -> App ()
forall a b. (a -> b) -> a -> b
$ Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"access_token" 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
testDeleteAppFromTeam :: (HasCallStack) => App ()
testDeleteAppFromTeam :: HasCallStack => App ()
testDeleteAppFromTeam = do
domain <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
(owner, tid, [regularMember]) <- createTeam domain 2
let new = NewApp
forall a. Default a => a
def {name = "chappie"} :: NewApp
appId <- bindResponse (createApp owner tid new) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user.id" 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
let appIdObject = [Pair] -> Value
object [String
"domain" String -> Value -> Pair
forall a. ToJSON a => String -> a -> Pair
.= Value
domain, String
"id" String -> String -> Pair
forall a. ToJSON a => String -> a -> Pair
.= String
appId]
withWebSockets [owner, regularMember] \[WebSocket
wsOwner, WebSocket
wsRegularMember] -> do
App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (String -> Value -> Value -> App Response
forall owner member.
(HasCallStack, MakesValue owner, MakesValue member) =>
String -> owner -> member -> App Response
deleteTeamMember String
tid Value
owner Value
appIdObject) ((Response -> App ()) -> App ()) -> (Response -> App ()) -> App ()
forall a b. (a -> b) -> a -> b
$ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
202
let predicate :: a -> App Bool
predicate a
payload = do
typ <- a
payload a -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"payload.0.type" 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
pure $ typ == "team.member-leave"
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
$ HasCallStack => (Value -> App Bool) -> WebSocket -> App Value
(Value -> App Bool) -> WebSocket -> App Value
awaitMatch Value -> App Bool
forall {a}. MakesValue a => a -> App Bool
predicate WebSocket
wsOwner
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
$ HasCallStack => (Value -> App Bool) -> WebSocket -> App Value
(Value -> App Bool) -> WebSocket -> App Value
awaitMatch Value -> App Bool
forall {a}. MakesValue a => a -> App Bool
predicate WebSocket
wsRegularMember
eventually $ do
bindResponse (getApp owner tid appId) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
bindResponse (getUser owner appIdObject) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"deleted" App Value -> Bool -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` Bool
True
bindResponse (BrigI.getUsersId domain [appId]) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> [Value] -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` ([] :: [Value])
testPutApp :: (HasCallStack) => App ()
testPutApp :: HasCallStack => App ()
testPutApp = do
domain <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
(owner, tid, [regularMember]) <- createTeam domain 2
let new = NewApp
forall a. Default a => a
def {name = "choppie"} :: NewApp
appId <- bindResponse (createApp owner tid new) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user.id" 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
let Object appMetadata =
[aesonQQ|
{
"accent_id": 2147483647,
"assets": [
{
"key": "3-1-47de4580-ae51-4650-acbb-d10c028cb0ac",
"size": "preview",
"type": "image"
}
],
"name": "Appy McApp",
"category": "security",
"description": "This is the best app ever."
}|]
withWebSockets [owner, regularMember] \[WebSocket
wsOwner, WebSocket
wsRegularMember] -> do
App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
bindResponse (String -> Value -> String -> Value -> App Response
forall user.
(HasCallStack, MakesValue user) =>
String -> user -> String -> Value -> App Response
putAppMetadata String
tid Value
owner String
appId (Object -> Value
Object Object
appMetadata)) ((Response -> App ()) -> App ()) -> (Response -> App ()) -> App ()
forall a b. (a -> b) -> a -> b
$ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
App () -> App ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (App () -> App ()) -> App () -> App ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => Int -> WebSocket -> App ()
Int -> WebSocket -> App ()
assertNoEvent Int
5 WebSocket
wsOwner
App () -> App ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (App () -> App ()) -> App () -> App ()
forall a b. (a -> b) -> a -> b
$ HasCallStack => Int -> WebSocket -> App ()
Int -> WebSocket -> App ()
assertNoEvent Int
5 WebSocket
wsRegularMember
bindResponse (getApp owner tid appId) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json
Maybe Value -> Shape -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Shape -> App ()
`shouldMatchShapeLenient` [(String, Shape)] -> Shape
SObject
[ (String
"accent_id", Shape
SNumber),
(String
"assets", Shape -> Shape
SArray ([(String, Shape)] -> Shape
SObject [(String
"key", Shape
SString), (String
"size", Shape
SString), (String
"type", Shape
SString)])),
(String
"name", Shape
SString),
(String
"app", [(String, Shape)] -> Shape
SObject [(String
"category", Shape
SString), (String
"description", Shape
SString)])
]
let badAppId = String
"5e002eca-114f-11f1-b5a3-7306b8837f91"
bindResponse (putAppMetadata tid owner badAppId (Object appMetadata)) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
404
testRetrieveUsersIncludingApps :: (HasCallStack) => App ()
testRetrieveUsersIncludingApps :: HasCallStack => App ()
testRetrieveUsersIncludingApps = do
let userShape :: Shape
userShape =
[(String, Shape)] -> Shape
SObject
[ (String
"accent_id", Shape
SNumber),
(String
"assets", Shape -> Shape
SArray Shape
SAny),
(String
"id", Shape
SString),
(String
"name", Shape
SString),
(String
"qualified_id", [(String, Shape)] -> Shape
SObject [(String
"domain", Shape
SString), (String
"id", Shape
SString)]),
(String
"searchable", Shape
SBool),
(String
"supported_protocols", Shape -> Shape
SArray Shape
SString),
(String
"team", Shape
SString),
(String
"type", Shape
SString)
]
memberShape :: Shape
memberShape =
[(String, Shape)] -> Shape
SObject
[ (String
"created_at", Shape
SString),
(String
"created_by", Shape
SString),
(String
"legalhold_status", Shape
SString),
(String
"permissions", [(String, Shape)] -> Shape
SObject [(String
"copy", Shape
SNumber), (String
"self", Shape
SNumber)]),
(String
"user", Shape
SString)
]
appShape :: Shape
appShape =
[(String, Shape)] -> Shape
SObject
[ (String
"category", Shape
SString),
(String
"description", Shape
SString)
]
appWithIdShape :: Shape
appWithIdShape =
[(String, Shape)] -> Shape
SObject
[ (String
"id", Shape
SString),
(String
"app", Shape
appShape)
]
searchResultShape :: Shape
searchResultShape =
[(String, Shape)] -> Shape
SObject
[ (String
"accent_id", Shape
SNumber),
(String
"handle", Shape
SAny),
(String
"id", Shape
SString),
(String
"name", Shape
SString),
(String
"qualified_id", [(String, Shape)] -> Shape
SObject [(String
"domain", Shape
SString), (String
"id", Shape
SString)]),
(String
"team", Shape
SString),
(String
"type", Shape
SString)
]
listResultShape :: Shape
listResultShape =
[(String, Shape)] -> Shape
SObject
[ (String
"accent_id", Shape
SNumber),
(String
"assets", Shape -> Shape
SArray Shape
SAny),
(String
"app", Shape
SAny),
(String
"id", Shape
SString),
(String
"legalhold_status", Shape
SString),
(String
"name", Shape
SString),
(String
"picture", Shape -> Shape
SArray Shape
SAny),
(String
"qualified_id", [(String, Shape)] -> Shape
SObject [(String
"domain", Shape
SString), (String
"id", Shape
SString)]),
(String
"searchable", Shape
SBool),
(String
"supported_protocols", Shape -> Shape
SArray Shape
SString),
(String
"team", Shape
SString),
(String
"type", Shape
SString)
]
domain <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
(owner, tid, [regular]) <- createTeam domain 2
let new = NewApp
forall a. Default a => a
def {name = "chippie"} :: NewApp
appCreated <- bindResponse (createApp owner tid new) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Maybe Value -> App (Maybe Value)
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Response
resp.json
appCreated
`shouldMatchShapeLenient` SObject
[ ("cookie", SString),
("user", userShape)
]
appId <- appCreated %. "user.id" & asString
getTeamMembers owner tid `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"hasMore" App Value -> Bool -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` Bool
False
mems <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"members" App Value -> (Value -> App [Value]) -> App [Value]
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
memIds <- (asString . (%. "user")) `mapM` mems
memIds
`shouldMatchSet` sequence
[ pure appId,
asString $ regular %. "qualified_id.id",
asString $ owner %. "qualified_id.id"
]
getTeamMember owner tid appId `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
appId
Response
resp.json Maybe Value -> Shape -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Shape -> App ()
`shouldMatchShapeLenient` Shape
memberShape
getApps owner tid `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
apps <- Response
resp.json Maybe Value -> (Maybe Value -> App Value) -> App Value
forall a b. a -> (a -> b) -> b
& App Value -> (Value -> App Value) -> Maybe Value -> App Value
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> App Value
forall a. HasCallStack => String -> a
error String
"this shouldn't happen") Value -> App Value
forall a. a -> App a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
apps `shouldMatchShapeLenient` SArray appWithIdShape
getApp owner tid appId `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> Shape -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Shape -> App ()
`shouldMatchShapeLenient` Shape
userShape
listUsers owner [appCreated %. "user"] `bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"found.0" App Value -> Shape -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Shape -> App ()
`shouldMatchShapeLenient` Shape
listResultShape
putSelf owner (def {name = Just "name-A1"}) >>= assertSuccess
putSelf regular (def {name = Just "name-A2"}) >>= assertSuccess
putSelf (appCreated %. "user") (def {name = Just "name-A3"}) >>= assertSuccess
eventually
$ searchContacts owner "name" domain
`bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
hits :: [Value] <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"documents" App Value -> (App Value -> App [Value]) -> App [Value]
forall a b. a -> (a -> b) -> b
& App Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
length hits `shouldMatchInt` 2
(`shouldMatchShapeLenient` searchResultShape) `mapM_` hits
testCrossTeamAppConversation :: (HasCallStack) => Domain -> App ()
testCrossTeamAppConversation :: HasCallStack => Domain -> App ()
testCrossTeamAppConversation Domain
sameOrOtherDomain = do
domainA <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
domainB <- make sameOrOtherDomain
(ownerA, tidA, [m1]) <- createTeam domainA 2
(ownerB, tidB, [m2]) <- createTeam domainB 2
let newAppA1 = NewApp
forall a. Default a => a
def {name = "app-a1"} :: NewApp
appA1 <- bindResponse (createApp ownerA tidA newAppA1) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user"
let newAppA2 = NewApp
forall a. Default a => a
def {name = "app-a2"} :: NewApp
appA2 <- bindResponse (createApp ownerB tidB newAppA2) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user"
[m1c, appA1c] <- traverse (createMLSClient def) [m1, appA1]
traverse_ (uploadNewKeyPackage def) [m1c, appA1c]
bindResponse (postConnection m1 appA2) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
400
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"label" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"invalid-user"
convId <- createNewGroupWith def m1c defMLS {team = Just tidA}
void $ createAddCommit m1c convId [appA1] >>= sendAndConsumeCommitBundle
postConnection m1 m2 >>= assertSuccess
putConnection m2 m1 "accepted" >>= assertSuccess
m2c <- createMLSClient def m2
void $ uploadNewKeyPackage def m2c
void $ createAddCommit m1c convId [m2] >>= sendAndConsumeCommitBundle
let newAppA3 = NewApp
forall a. Default a => a
def {name = "app-a3"} :: NewApp
appA3 <- bindResponse (createApp ownerA tidA newAppA3) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user"
appA3c <- createMLSClient def appA3
void $ uploadNewKeyPackage def appA3c
void $ createAddCommit m1c convId [appA3] >>= sendAndConsumeCommitBundle
void $ createApplicationMessage convId m1c "hello from M1" >>= sendAndConsumeMessage
void $ createApplicationMessage convId appA1c "hello from A1" >>= sendAndConsumeMessage
void $ createApplicationMessage convId appA3c "hello from A3" >>= sendAndConsumeMessage
void $ createApplicationMessage convId m2c "hello from M2" >>= sendAndConsumeMessage
testFindApp :: (HasCallStack) => Domain -> App ()
testFindApp :: HasCallStack => Domain -> App ()
testFindApp Domain
sameOrOtherDomain = do
domainA <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
domainB <- make sameOrOtherDomain
(ownerA1, tidA1, [regularMemberA1]) <- createTeam domainA 2
let newAppA1 :: NewApp = def {name = "app A1", description = ""}
(appA1Id) <- bindResponse (createApp ownerA1 tidA1 newAppA1) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user.id" 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
BrigI.refreshIndex domainA
(ownerA2, _, [regularMemberA2]) <- createTeam domainA 2
(ownerB1, _, [regularMemberB1]) <- createTeam domainB 2
let foundUserType :: (HasCallStack) => SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg
cfg [String]
uids =
SearchContactsCfg -> App Response
searchContactsWith SearchContactsCfg
cfg App Response -> (Response -> App ()) -> App ()
forall a.
HasCallStack =>
App Response -> (Response -> App a) -> App a
`bindResponse` \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
foundDocs :: [Value] <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"documents" App Value -> (Value -> App [Value]) -> App [Value]
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
((%. "id") `mapM` foundDocs) `shouldMatch` uids
searchTerm <- asString newAppA1.name
domain <- asString domainA
forM_ [ownerA1, regularMemberA1]
$ \Value
user -> do
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = Maybe [String]
forall a. Maybe a
Nothing, String
Value
searchTerm :: String
domain :: String
user :: Value
domain :: String
searchTerm :: String
user :: Value
..} [String
appA1Id]
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [], String
Value
searchTerm :: String
domain :: String
user :: Value
domain :: String
searchTerm :: String
user :: Value
..} [String
appA1Id]
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"app"], String
Value
searchTerm :: String
domain :: String
user :: Value
domain :: String
searchTerm :: String
user :: Value
..} [String
appA1Id]
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"app", String
"regular"], String
Value
searchTerm :: String
domain :: String
user :: Value
domain :: String
searchTerm :: String
user :: Value
..} [String
appA1Id]
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"regular"], String
Value
searchTerm :: String
domain :: String
user :: Value
domain :: String
searchTerm :: String
user :: Value
..} []
forM_ [ownerA2, regularMemberA2, ownerB1, regularMemberB1]
$ \Value
user -> do
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = Maybe [String]
forall a. Maybe a
Nothing, String
Value
searchTerm :: String
domain :: String
domain :: String
searchTerm :: String
user :: Value
user :: Value
..} []
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [], String
Value
searchTerm :: String
domain :: String
domain :: String
searchTerm :: String
user :: Value
user :: Value
..} []
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"app"], String
Value
searchTerm :: String
domain :: String
domain :: String
searchTerm :: String
user :: Value
user :: Value
..} []
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"app", String
"regular"], String
Value
searchTerm :: String
domain :: String
domain :: String
searchTerm :: String
user :: Value
user :: Value
..} []
HasCallStack => SearchContactsCfg -> [String] -> App ()
SearchContactsCfg -> [String] -> App ()
foundUserType SearchContactsCfg {types :: Maybe [String]
types = [String] -> Maybe [String]
forall a. a -> Maybe a
Just [String
"regular"], String
Value
searchTerm :: String
domain :: String
domain :: String
searchTerm :: String
user :: Value
user :: Value
..} []
testRemoveServicesAccessRole :: (HasCallStack) => App ()
testRemoveServicesAccessRole :: HasCallStack => App ()
testRemoveServicesAccessRole = do
domain <- Domain -> App Value
forall a. (MakesValue a, HasCallStack) => a -> App Value
make Domain
OwnDomain
(ownerA, tidA, [memberA]) <- createTeam domain 2
let newApp = NewApp
forall a. Default a => a
def {name = "test-app"} :: NewApp
app <- bindResponse (createApp ownerA tidA newApp) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user"
[memberAClient, appClient] <- traverse (createMLSClient def) [memberA, app]
traverse_ (uploadNewKeyPackage def) [memberAClient, appClient]
conv <- postConversation memberA defMLS {team = Just tidA, protocol = "mls"} >>= getJSON 201
convId <- objConvId conv
createGroup def memberAClient convId
void $ createAddCommit memberAClient convId [app] >>= sendAndConsumeCommitBundle
bindResponse (getConversation memberA conv) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
members <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"members.others" App Value -> (Value -> App [Value]) -> App [Value]
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
memberIds <- mapM (\Value
m -> Value
m Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"qualified_id.id" App Value -> (Value -> App String) -> App String
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
asString) members
appId <- app %. "qualified_id.id" & asString
memberIds `shouldContain` [appId]
bindResponse (getConversation memberA conv) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"protocol" App Value -> String -> App ()
forall a b.
(MakesValue a, MakesValue b, HasCallStack) =>
a -> b -> App ()
`shouldMatch` String
"mls"
let noServices =
[ String
"access" String -> [String] -> Pair
forall a. ToJSON a => String -> a -> Pair
.= [String
"invite", String
"link"],
String
"access_role" String -> [String] -> Pair
forall a. ToJSON a => String -> a -> Pair
.= ([String
"team_member", String
"non_team_member"] :: [String])
]
bindResponse (updateAccess memberA conv noServices) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
eventually $ do
bindResponse (getConversation memberA conv) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
members <- Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"members.others" App Value -> (Value -> App [Value]) -> App [Value]
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App [Value]
forall a. (HasCallStack, MakesValue a) => a -> App [Value]
asList
memberIds <- mapM (\Value
m -> Value
m Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"qualified_id.id" App Value -> (Value -> App String) -> App String
forall a b. App a -> (a -> App b) -> App b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> App String
forall a. (HasCallStack, MakesValue a) => a -> App String
asString) members
appId <- app %. "qualified_id.id" & asString
memberIds `shouldNotContain` [appId]
testAppReceivesMemberJoinNotification :: (HasCallStack) => App ()
testAppReceivesMemberJoinNotification :: HasCallStack => App ()
testAppReceivesMemberJoinNotification = do
(owner, tid, []) <- Domain -> Int -> App (Value, String, [Value])
forall domain.
(HasCallStack, MakesValue domain) =>
domain -> Int -> App (Value, String, [Value])
createTeam Domain
OwnDomain Int
1
app <- bindResponse (createApp owner tid def) $ \Response
resp -> do
Response
resp.status Int -> Int -> App ()
forall a. (MakesValue a, HasCallStack) => a -> Int -> App ()
`shouldMatchInt` Int
200
Response
resp.json Maybe Value -> String -> App Value
forall a. (HasCallStack, MakesValue a) => a -> String -> App Value
%. String
"user"
withWebSockets [owner, app] $ \[WebSocket
wsOwner, WebSocket
wsApp] -> do
newMember <- Value -> App Value
forall u. (HasCallStack, MakesValue u) => u -> App Value
addUserToTeam Value
owner
memberJoinOwner <- awaitMatch isTeamMemberJoinNotif wsOwner
memberJoinOwner %. "payload.0.team" `shouldMatch` tid
memberJoinOwner %. "payload.0.data.user" `shouldMatch` objId newMember
memberJoinApp <- awaitMatch isTeamMemberJoinNotif wsApp
memberJoinApp %. "payload.0.team" `shouldMatch` tid
memberJoinApp %. "payload.0.data.user" `shouldMatch` objId newMember