Skip to content

Commit d19e72b

Browse files
committed
WPB-18191: Add route to collaborator permissions from team
1 parent e77e1f9 commit d19e72b

File tree

16 files changed

+168
-19
lines changed

16 files changed

+168
-19
lines changed

changelog.d/2-features/WPB-18191

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Allow member permissions to be updated in a team.

integration/test/API/Brig.hs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,9 +1206,3 @@ refreshAppCookie :: (MakesValue u) => u -> String -> String -> App Response
12061206
refreshAppCookie u tid appId = do
12071207
req <- baseRequest u Brig Versioned $ joinHttpPath ["teams", tid, "apps", appId, "cookies"]
12081208
submit "POST" req
1209-
1210-
removeTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> App Response
1211-
removeTeamCollaborator owner tid collaborator = do
1212-
(_, collabId) <- objQid collaborator
1213-
req <- baseRequest owner Galley Versioned $ joinHttpPath ["teams", tid, "collaborators", collabId]
1214-
submit "DELETE" req

integration/test/API/Galley.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,3 +867,17 @@ resetConversation user groupId epoch = do
867867
req <- baseRequest user Galley Versioned (joinHttpPath ["mls", "reset-conversation"])
868868
let payload = object ["group_id" .= groupId, "epoch" .= epoch]
869869
submit "POST" $ req & addJSON payload
870+
871+
updateTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> [String] -> App Response
872+
updateTeamCollaborator owner tid collaborator permissions = do
873+
(_, collabId) <- objQid collaborator
874+
req <- baseRequest owner Galley Versioned $ joinHttpPath ["teams", tid, "collaborators", collabId]
875+
submit "PUT"
876+
$ req
877+
& addJSON permissions
878+
879+
removeTeamCollaborator :: (MakesValue owner, MakesValue collaborator, HasCallStack) => owner -> String -> collaborator -> App Response
880+
removeTeamCollaborator owner tid collaborator = do
881+
(_, collabId) <- objQid collaborator
882+
req <- baseRequest owner Galley Versioned $ joinHttpPath ["teams", tid, "collaborators", collabId]
883+
submit "DELETE" req

integration/test/Test/TeamCollaborators.hs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,33 @@ testRemoveCollaboratorInTeamConversation = do
271271
resp.status `shouldMatchInt` 200
272272
otherMembers <- asList (resp.json %. "members.others")
273273
traverse (%. "qualified_id") otherMembers `shouldMatchSet` traverse (%. "qualified_id") [owner, alice]
274+
275+
testUpdateCollaborator :: (HasCallStack) => App ()
276+
testUpdateCollaborator = do
277+
(owner, team, [alice]) <- createTeam OwnDomain 2
278+
279+
-- At the time of writing, it wasn't clear if this should be a bot instead.
280+
bob <- randomUser OwnDomain def
281+
addTeamCollaborator
282+
owner
283+
team
284+
bob
285+
["implicit_connection"]
286+
>>= assertSuccess
287+
postOne2OneConversation bob alice team "chit-chat" >>= assertSuccess
288+
289+
updateTeamCollaborator
290+
owner
291+
team
292+
bob
293+
["create_team_conversation", "implicit_connection"]
294+
>>= assertSuccess
295+
postOne2OneConversation bob alice team "chit-chat" >>= assertSuccess
296+
297+
updateTeamCollaborator
298+
owner
299+
team
300+
bob
301+
[]
302+
>>= assertSuccess
303+
postOne2OneConversation bob alice team "chit-chat" >>= assertLabel 403 "operation-denied"

libs/wire-api/src/Wire/API/Event/Team.hs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ data EventType
125125
| ConvDelete
126126
| CollaboratorAdd
127127
| AppCreate
128+
| CollaboratorUpdate
128129
| CollaboratorRemove
129130
deriving stock (Eq, Show, Generic)
130131
deriving (Arbitrary) via (GenericUniform EventType)
@@ -144,6 +145,7 @@ instance ToSchema EventType where
144145
element "team.conversation-delete" ConvDelete,
145146
element "team.collaborator-add" CollaboratorAdd,
146147
element "team.app-create" AppCreate,
148+
element "team.collaborator-update" CollaboratorUpdate,
147149
element "team.collaborator-remove" CollaboratorRemove
148150
]
149151

@@ -161,6 +163,7 @@ data EventData
161163
| EdConvDelete ConvId
162164
| EdCollaboratorAdd UserId [CollaboratorPermission]
163165
| EdAppCreate UserId
166+
| EdCollaboratorUpdate UserId [CollaboratorPermission]
164167
| EdCollaboratorRemove UserId
165168
deriving stock (Eq, Show, Generic)
166169

@@ -192,6 +195,11 @@ instance ToJSON EventData where
192195
"permissions" A..= perms
193196
]
194197
toJSON (EdAppCreate usr) = A.object ["user" A..= usr]
198+
toJSON (EdCollaboratorUpdate usr perms) =
199+
A.object
200+
[ "user" A..= usr,
201+
"permissions" A..= perms
202+
]
195203
toJSON (EdCollaboratorRemove usr) = A.object ["user" A..= usr]
196204

197205
eventDataType :: EventData -> EventType
@@ -205,6 +213,7 @@ eventDataType (EdConvCreate _) = ConvCreate
205213
eventDataType (EdConvDelete _) = ConvDelete
206214
eventDataType (EdCollaboratorAdd _ _) = CollaboratorAdd
207215
eventDataType (EdAppCreate _) = AppCreate
216+
eventDataType (EdCollaboratorUpdate _ _) = CollaboratorUpdate
208217
eventDataType (EdCollaboratorRemove _) = CollaboratorRemove
209218

210219
parseEventData :: EventType -> Maybe Value -> Parser EventData
@@ -232,15 +241,19 @@ parseEventData TeamCreate Nothing = fail "missing event data for type 'team.crea
232241
parseEventData TeamCreate (Just j) = EdTeamCreate <$> parseJSON j
233242
parseEventData TeamUpdate Nothing = fail "missing event data for type 'team.update'"
234243
parseEventData TeamUpdate (Just j) = EdTeamUpdate <$> parseJSON j
235-
parseEventData CollaboratorAdd Nothing = fail "missing event data for type 'team.collaborator-add"
244+
parseEventData CollaboratorAdd Nothing = fail "missing event data for type 'team.collaborator-add'"
236245
parseEventData CollaboratorAdd (Just j) = do
237246
let f o = EdCollaboratorAdd <$> o .: "user" <*> o .: "permissions"
238247
withObject "collaborator add data" f j
239248
parseEventData AppCreate Nothing = fail "missing event data for type 'team.app-create'"
240249
parseEventData AppCreate (Just j) = do
241250
let f o = EdAppCreate <$> o .: "user"
242251
withObject "app create data" f j
243-
parseEventData CollaboratorRemove Nothing = fail "missing event data for type 'team.collaborator-remove"
252+
parseEventData CollaboratorUpdate Nothing = fail "missing event data for type 'team.collaborator-update'"
253+
parseEventData CollaboratorUpdate (Just j) = do
254+
let f o = EdCollaboratorUpdate <$> o .: "user" <*> o .: "permissions"
255+
withObject "collaborator update data" f j
256+
parseEventData CollaboratorRemove Nothing = fail "missing event data for type 'team.collaborator-remove'"
244257
parseEventData CollaboratorRemove (Just j) = do
245258
let f o = EdCollaboratorRemove <$> o .: "user"
246259
withObject "collaborator remove data" f j
@@ -259,6 +272,7 @@ genEventData = \case
259272
ConvDelete -> EdConvDelete <$> arbitrary
260273
CollaboratorAdd -> EdCollaboratorAdd <$> arbitrary <*> arbitrary
261274
AppCreate -> EdAppCreate <$> arbitrary
275+
CollaboratorUpdate -> EdCollaboratorUpdate <$> arbitrary <*> arbitrary
262276
CollaboratorRemove -> EdCollaboratorRemove <$> arbitrary
263277

264278
makeLenses ''Event

libs/wire-api/src/Wire/API/Routes/Public/Galley/TeamMember.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ module Wire.API.Routes.Public.Galley.TeamMember where
2020
import Data.Id
2121
import Data.Int
2222
import Data.Range
23+
import Data.Set (Set)
2324
import GHC.Generics
2425
import Generics.SOP qualified as GSOP
2526
import Servant
@@ -32,6 +33,7 @@ import Wire.API.Routes.MultiVerb
3233
import Wire.API.Routes.Named
3334
import Wire.API.Routes.Public
3435
import Wire.API.Routes.Version
36+
import Wire.API.Team.Collaborator
3537
import Wire.API.Team.Member
3638
import Wire.API.User qualified as User
3739

@@ -207,6 +209,18 @@ type TeamMemberAPI =
207209
"CSV of team members"
208210
CSV
209211
)
212+
:<|> Named
213+
"update-team-collaborator"
214+
( Summary "Update a collaborator permissions from the team."
215+
:> From 'V11
216+
:> ZLocalUser
217+
:> "teams"
218+
:> Capture "tid" TeamId
219+
:> "collaborators"
220+
:> Capture "uid" UserId
221+
:> ReqBody '[JSON] (Set CollaboratorPermission)
222+
:> MultiVerb1 'PUT '[JSON] (RespondEmpty 200 "")
223+
)
210224
:<|> Named
211225
"remove-team-collaborator"
212226
( Summary "Remove a collaborator from the team."

libs/wire-api/src/Wire/API/Team/Member.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,7 @@ data HiddenPerm
482482
| JoinRegularConversations
483483
| CreateApp
484484
| ManageApps
485+
| UpdateTeamCollaborator
485486
| RemoveTeamCollaborator
486487
deriving (Eq, Ord, Show)
487488

@@ -570,6 +571,7 @@ roleHiddenPermissions role = HiddenPermissions p p
570571
NewTeamCollaborator,
571572
CreateApp,
572573
ManageApps,
574+
UpdateTeamCollaborator,
573575
RemoveTeamCollaborator
574576
]
575577
roleHiddenPerms RoleMember =

libs/wire-subsystems/src/Wire/AppSubsystem/Interpreter.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ createAppImpl lusr tid new = do
9393
Store.createUser u Nothing
9494

9595
-- generate a team event
96-
generateTeamEvent creator.id tid (EdAppCreate u.id)
96+
generateTeamEvents creator.id tid [EdAppCreate u.id]
9797

9898
c :: Cookie (Token U) <- newCookie u.id Nothing PersistentCookie (Just "app")
9999
pure

libs/wire-subsystems/src/Wire/TeamCollaboratorsStore.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ data TeamCollaboratorsStore m a where
1313
GetTeamCollaborator :: TeamId -> UserId -> TeamCollaboratorsStore m (Maybe TeamCollaborator)
1414
GetTeamCollaborations :: UserId -> TeamCollaboratorsStore m ([TeamCollaborator])
1515
GetTeamCollaboratorsWithIds :: Set TeamId -> Set UserId -> TeamCollaboratorsStore m [TeamCollaborator]
16+
UpdateTeamCollaborator :: UserId -> TeamId -> Set CollaboratorPermission -> TeamCollaboratorsStore m ()
1617
RemoveTeamCollaborator :: UserId -> TeamId -> TeamCollaboratorsStore m ()
1718

1819
makeSem ''TeamCollaboratorsStore

libs/wire-subsystems/src/Wire/TeamCollaboratorsStore/Postgres.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interpretTeamCollaboratorsStoreToPostgres =
3838
GetTeamCollaborator teamId userId -> getTeamCollaboratorImpl teamId userId
3939
GetTeamCollaborations userId -> getTeamCollaborationsImpl userId
4040
GetTeamCollaboratorsWithIds teamIds userIds -> getTeamCollaboratorsWithIdsImpl teamIds userIds
41+
UpdateTeamCollaborator userId teamId permissions -> updateTeamCollaboratorImpl userId teamId permissions
4142
RemoveTeamCollaborator userId teamId -> removeTeamCollaboratorImpl userId teamId
4243

4344
getTeamCollaboratorImpl ::
@@ -125,6 +126,33 @@ getAllTeamCollaboratorsImpl teamId = do
125126
select user_id :: uuid, team_id :: uuid, permissions :: int2[] from collaborators where team_id = ($1 :: uuid)
126127
|]
127128

129+
updateTeamCollaboratorImpl ::
130+
( Member (Input Pool) r,
131+
Member (Embed IO) r,
132+
Member (Error UsageError) r
133+
) =>
134+
UserId ->
135+
TeamId ->
136+
Set CollaboratorPermission ->
137+
Sem r ()
138+
updateTeamCollaboratorImpl userId teamId permissions = do
139+
pool <- input
140+
eitherErrorOrUnit <- liftIO $ use pool session
141+
either throw pure eitherErrorOrUnit
142+
where
143+
session :: Session ()
144+
session = statement (userId, teamId, permissions) updateStatement
145+
146+
updateStatement :: Statement (UserId, TeamId, Set CollaboratorPermission) ()
147+
updateStatement =
148+
lmap
149+
( \(uid, tid, pms) ->
150+
(toUUID uid, toUUID tid, collaboratorPermissionToPostgreslRep <$> (Data.Vector.fromList . toAscList) pms)
151+
)
152+
$ [resultlessStatement|
153+
update collaborators set permissions = ($3 :: smallint[]) where user_id = ($1 :: uuid) and team_id = ($2 :: uuid)
154+
|]
155+
128156
removeTeamCollaboratorImpl ::
129157
( Member (Input Pool) r,
130158
Member (Embed IO) r,

0 commit comments

Comments
 (0)