diff --git a/changelog.d/2-features/WPB-25521-finish-collaborator-crud-api b/changelog.d/2-features/WPB-25521-finish-collaborator-crud-api new file mode 100644 index 00000000000..bdf44a1f679 --- /dev/null +++ b/changelog.d/2-features/WPB-25521-finish-collaborator-crud-api @@ -0,0 +1 @@ +Finish collaborator crud api. diff --git a/integration/test/API/Brig.hs b/integration/test/API/Brig.hs index 70e74fce45e..c3e0decf671 100644 --- a/integration/test/API/Brig.hs +++ b/integration/test/API/Brig.hs @@ -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], diff --git a/integration/test/API/Galley.hs b/integration/test/API/Galley.hs index 658b6275c59..480d6c79f6d 100644 --- a/integration/test/API/Galley.hs +++ b/integration/test/API/Galley.hs @@ -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 diff --git a/integration/test/Test/TeamCollaborators.hs b/integration/test/Test/TeamCollaborators.hs index 7286d1224c0..f0d568a57ee 100644 --- a/integration/test/Test/TeamCollaborators.hs +++ b/integration/test/Test/TeamCollaborators.hs @@ -17,7 +17,6 @@ module Test.TeamCollaborators where -import API.Brig import API.Galley import qualified API.GalleyInternal as Internal import Data.Tuple.Extra @@ -25,8 +24,8 @@ import Notifications (isConvLeaveNotif, isTeamCollaboratorAddedNotif, isTeamColl 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. @@ -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 diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs index 16b4bc0e09b..8fe7484156b 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Brig.hs @@ -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) @@ -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 diff --git a/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs index e28ac848bbc..33044bfcc0a 100644 --- a/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs +++ b/libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs @@ -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." diff --git a/services/brig/src/Brig/Team/API.hs b/services/brig/src/Brig/Team/API.hs index a612f9ec371..5eb72a4ae57 100644 --- a/services/brig/src/Brig/Team/API.hs +++ b/services/brig/src/Brig/Team/API.hs @@ -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, diff --git a/services/galley/src/Galley/API/Public/TeamMember.hs b/services/galley/src/Galley/API/Public/TeamMember.hs index d85d89f514e..5c56816012e 100644 --- a/services/galley/src/Galley/API/Public/TeamMember.hs +++ b/services/galley/src/Galley/API/Public/TeamMember.hs @@ -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 = @@ -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