Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Finish collaborator crud api.
16 changes: 0 additions & 16 deletions integration/test/API/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1218,22 +1218,6 @@ removeUserFromGroup user gid uid = do
req <- baseRequest user Brig Versioned $ joinHttpPath ["user-groups", gid, "users", uid]
submit "DELETE" req

addTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> [String] -> App Response
addTeamCollaborator owner tid collaborator permissions = do
req <- baseRequest owner Brig Versioned $ joinHttpPath ["teams", tid, "collaborators"]
(_, collabId) <- objQid collaborator
submit "POST" $
req
& addJSONObject
[ "user" .= collabId,
"permissions" .= permissions
]

getAllTeamCollaborators :: (MakesValue owner) => owner -> String -> App Response
getAllTeamCollaborators owner tid = do
req <- baseRequest owner Brig Versioned $ joinHttpPath ["teams", tid, "collaborators"]
submit "GET" req

data NewApp = NewApp
{ name :: String,
assets :: Maybe [Value],
Expand Down
16 changes: 16 additions & 0 deletions integration/test/API/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,22 @@ resetConversation user groupId epoch = do
let payload = object ["group_id" .= groupId, "epoch" .= epoch]
submit "POST" $ req & addJSON payload

addTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> [String] -> App Response
addTeamCollaborator owner tid collaborator permissions = do
req <- baseRequest owner Galley Versioned $ joinHttpPath ["teams", tid, "collaborators"]
(_, collabId) <- objQid collaborator
submit "POST"
$ req
& addJSONObject
[ "user" .= collabId,
"permissions" .= permissions
]

getAllTeamCollaborators :: (MakesValue owner) => owner -> String -> App Response
getAllTeamCollaborators owner tid = do
req <- baseRequest owner Galley Versioned $ joinHttpPath ["teams", tid, "collaborators"]
submit "GET" req

updateTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> [String] -> App Response
updateTeamCollaborator owner tid collaborator permissions = do
(_, collabId) <- objQid collaborator
Expand Down
25 changes: 22 additions & 3 deletions integration/test/Test/TeamCollaborators.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@

module Test.TeamCollaborators where

import API.Brig
import API.Galley
import qualified API.GalleyInternal as Internal
import Data.Tuple.Extra
import Notifications (isConvLeaveNotif, isTeamCollaboratorAddedNotif, isTeamCollaboratorRemovedNotif, isTeamMemberLeaveNotif)
import SetupHelpers
import Testlib.Prelude

testCreateTeamCollaborator :: (HasCallStack) => App ()
testCreateTeamCollaborator = do
testCrudTeamCollaborator :: (HasCallStack) => App ()
testCrudTeamCollaborator = do
(owner, team, [alice]) <- createTeam OwnDomain 2

-- At the time of writing, it wasn't clear if this should be a bot instead.
Expand Down Expand Up @@ -59,6 +58,26 @@ testCreateTeamCollaborator = do
res %. "team" `shouldMatch` team
res %. "permissions" `shouldMatch` ["create_team_conversation", "implicit_connection"]

withWebSockets [owner, alice] $ \[wsOwner, wsAlice] -> do
removeTeamCollaborator
owner
team
user
>>= assertSuccess

let checkEvent :: (MakesValue a) => a -> App ()
checkEvent evt = do
evt %. "payload.0.data.user" `shouldMatch` userId
evt %. "payload.0.team" `shouldMatch` team
evt %. "transient" `shouldMatch` False

forM_ [wsOwner, wsAlice] $ \mem ->
awaitMatch isTeamMemberLeaveNotif mem >>= checkEvent

bindResponse (getAllTeamCollaborators owner team) $ \resp -> do
resp.status `shouldMatchInt` 200
asList resp.json `shouldMatch` ([] :: [()])

testTeamCollaboratorEndpointsForbiddenForOtherTeams :: (HasCallStack) => App ()
testTeamCollaboratorEndpointsForbiddenForOtherTeams = do
(owner, _team, _members) <- createTeam OwnDomain 2
Expand Down
22 changes: 0 additions & 22 deletions libs/wire-api/src/Wire/API/Routes/Public/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ import Wire.API.Routes.QualifiedCapture
import Wire.API.Routes.Version
import Wire.API.Routes.Versioned
import Wire.API.SystemSettings
import Wire.API.Team.Collaborator
import Wire.API.Team.Invitation
import Wire.API.Team.Size
import Wire.API.User hiding (NoIdentity)
Expand Down Expand Up @@ -2097,27 +2096,6 @@ type TeamsAPI =
:> ReqBody '[JSON] AcceptTeamInvitation
:> MultiVerb 'POST '[JSON] '[RespondEmpty 200 "Team invitation accepted."] ()
)
:<|> Named
"add-team-collaborator"
( Summary "Add a collaborator to the team."
:> From 'V10
:> ZLocalUser
:> "teams"
:> Capture "tid" TeamId
:> "collaborators"
:> ReqBody '[JSON] NewTeamCollaborator
:> MultiVerb1 'POST '[JSON] (RespondEmpty 200 "")
)
:<|> Named
"get-team-collaborators"
( Summary "Get all collaborators of the team."
:> From 'V10
:> ZLocalUser
:> "teams"
:> Capture "tid" TeamId
:> "collaborators"
:> MultiVerb1 'GET '[JSON] (Respond 200 "Return collaborators" [TeamCollaborator])
)

type SystemSettingsAPI =
Named
Expand Down
21 changes: 21 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,27 @@ type TeamMemberAPI =
"CSV of team members"
CSV
)
:<|> Named
"add-team-collaborator"
( Summary "Add a collaborator to the team."
:> From 'V10
:> ZLocalUser
:> "teams"
:> Capture "tid" TeamId
:> "collaborators"
:> ReqBody '[JSON] NewTeamCollaborator
:> MultiVerb1 'POST '[JSON] (RespondEmpty 200 "")
)
:<|> Named
"get-team-collaborators"
( Summary "Get all collaborators of the team."
:> From 'V10
:> ZLocalUser
:> "teams"
:> Capture "tid" TeamId
:> "collaborators"
:> MultiVerb1 'GET '[JSON] (Respond 200 "Return collaborators" [TeamCollaborator])
)
:<|> Named
"update-team-collaborator"
( Summary "Update a collaborator permissions from the team."
Expand Down
2 changes: 0 additions & 2 deletions services/brig/src/Brig/Team/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,6 @@ servantAPI =
:<|> Named @"head-team-invitations" (lift . liftSem . headInvitationByEmail)
:<|> Named @"get-team-size" (\uid tid -> lift . liftSem $ teamSizePublic uid tid)
:<|> Named @"accept-team-invitation" (\luid req -> lift $ liftSem $ acceptTeamInvitation luid req.password req.code)
:<|> Named @"add-team-collaborator" (\zuid tid (NewTeamCollaborator uid perms) -> lift . liftSem $ createTeamCollaborator zuid uid tid perms)
:<|> Named @"get-team-collaborators" (\zuid tid -> lift . liftSem $ getAllTeamCollaborators zuid tid)

teamSizePublic ::
( Member (Error UserSubsystemError) r,
Expand Down
5 changes: 5 additions & 0 deletions services/galley/src/Galley/API/Public/TeamMember.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import Galley.API.Teams.Export qualified as Export
import Galley.App
import Wire.API.Routes.API
import Wire.API.Routes.Public.Galley.TeamMember
import Wire.API.Team.Collaborator
import Wire.TeamCollaboratorsSubsystem

teamMemberAPI :: API TeamMemberAPI GalleyEffects
teamMemberAPI =
Expand All @@ -33,5 +35,8 @@ teamMemberAPI =
<@> mkNamedAPI @"delete-non-binding-team-member" deleteNonBindingTeamMember
<@> mkNamedAPI @"update-team-member" updateTeamMember
<@> mkNamedAPI @"get-team-members-csv" Export.getTeamMembersCSV
<@> mkNamedAPI @"add-team-collaborator"
(\zuid tid (NewTeamCollaborator uid perms) -> createTeamCollaborator zuid uid tid perms)
<@> mkNamedAPI @"get-team-collaborators" getAllTeamCollaborators
<@> mkNamedAPI @"update-team-collaborator" updateTeamCollaborator
<@> mkNamedAPI @"remove-team-collaborator" removeTeamCollaborator