@@ -138,7 +138,6 @@ import Wire.API.Team.Conversation
138
138
import qualified Wire.API.Team.Conversation as Public
139
139
import Wire.API.Team.Export (TeamExportUser (.. ))
140
140
import Wire.API.Team.Member
141
- import qualified Wire.API.Team.Member as M
142
141
import qualified Wire.API.Team.Member as Public
143
142
import Wire.API.Team.Permission (Perm (.. ), Permissions (.. ), SPerm (.. ), copy , fullPermissions , self )
144
143
import Wire.API.Team.Role
@@ -329,13 +328,17 @@ updateTeamH ::
329
328
Sem r ()
330
329
updateTeamH zusr zcon tid updateData = do
331
330
zusrMembership <- E. getTeamMember tid zusr
331
+ -- let zothers = map (view userId) membs
332
+ -- Log.debug $
333
+ -- Log.field "targets" (toByteString . show $ toByteString <$> zothers)
334
+ -- . Log.field "action" (Log.val "Teams.updateTeam")
332
335
void $ permissionCheckS SSetTeamData zusrMembership
333
336
E. setTeamData tid updateData
334
337
now <- input
335
- admins <- E. getTeamAdmins tid
338
+ memList <- getTeamMembersForFanout tid
336
339
let e = newEvent tid now (EdTeamUpdate updateData)
337
- let r = list1 (userRecipient zusr) (map userRecipient ( filter ( /= zusr) admins ))
338
- E. push1 $ newPushLocal1 ListComplete zusr (TeamEvent e) r & pushConn ?~ zcon & pushTransient .~ True
340
+ let r = list1 (userRecipient zusr) (membersToRecipients ( Just zusr) (memList ^. teamMembers ))
341
+ E. push1 $ newPushLocal1 (memList ^. teamMemberListType) zusr (TeamEvent e) r & pushConn ?~ zcon
339
342
340
343
deleteTeam ::
341
344
forall r .
@@ -704,7 +707,6 @@ addTeamMember ::
704
707
Member (ErrorS OperationDenied ) r ,
705
708
Member (ErrorS 'TeamNotFound) r ,
706
709
Member (ErrorS 'TooManyTeamMembers) r ,
707
- Member (ErrorS 'TooManyTeamAdmins) r ,
708
710
Member (ErrorS 'UserBindingExists) r ,
709
711
Member (ErrorS 'TooManyTeamMembersOnTeamWithLegalhold) r ,
710
712
Member (Input Opts ) r ,
@@ -737,15 +739,15 @@ addTeamMember lzusr zcon tid nmem = do
737
739
ensureConnectedToLocals zusr [uid]
738
740
(TeamSize sizeBeforeJoin) <- E. getSize tid
739
741
ensureNotTooLargeForLegalHold tid (fromIntegral sizeBeforeJoin + 1 )
740
- void $ addTeamMemberInternal tid (Just zusr) (Just zcon) nmem
742
+ memList <- getTeamMembersForFanout tid
743
+ void $ addTeamMemberInternal tid (Just zusr) (Just zcon) nmem memList
741
744
742
745
-- This function is "unchecked" because there is no need to check for user binding (invite only).
743
746
uncheckedAddTeamMember ::
744
747
forall r .
745
748
( Member BrigAccess r ,
746
749
Member GundeckAccess r ,
747
750
Member (ErrorS 'TooManyTeamMembers) r ,
748
- Member (ErrorS 'TooManyTeamAdmins) r ,
749
751
Member (ErrorS 'TooManyTeamMembersOnTeamWithLegalhold) r ,
750
752
Member (Input Opts ) r ,
751
753
Member (Input UTCTime ) r ,
@@ -759,18 +761,18 @@ uncheckedAddTeamMember ::
759
761
NewTeamMember ->
760
762
Sem r ()
761
763
uncheckedAddTeamMember tid nmem = do
764
+ mems <- getTeamMembersForFanout tid
762
765
(TeamSize sizeBeforeJoin) <- E. getSize tid
763
766
ensureNotTooLargeForLegalHold tid (fromIntegral sizeBeforeJoin + 1 )
764
- (TeamSize sizeBeforeAdd) <- addTeamMemberInternal tid Nothing Nothing nmem
765
- owners <- E. getBillingTeamMembers tid
766
- Journal. teamUpdate tid (sizeBeforeAdd + 1 ) owners
767
+ (TeamSize sizeBeforeAdd) <- addTeamMemberInternal tid Nothing Nothing nmem mems
768
+ billingUserIds <- E. getBillingTeamMembers tid
769
+ Journal. teamUpdate tid (sizeBeforeAdd + 1 ) billingUserIds
767
770
768
771
uncheckedUpdateTeamMember ::
769
772
forall r .
770
773
( Member BrigAccess r ,
771
774
Member (ErrorS 'TeamNotFound) r ,
772
775
Member (ErrorS 'TeamMemberNotFound) r ,
773
- Member (ErrorS 'TooManyTeamAdmins) r ,
774
776
Member GundeckAccess r ,
775
777
Member (Input UTCTime ) r ,
776
778
Member P. TinyLog r ,
@@ -795,22 +797,33 @@ uncheckedUpdateTeamMember mlzusr mZcon tid newMember = do
795
797
previousMember <-
796
798
E. getTeamMember tid targetId >>= noteS @ 'TeamMemberNotFound
797
799
798
- admins <- E. getTeamAdmins tid
799
- let admins' = [targetId | isAdminOrOwner targetPermissions] <> filter (/= targetId) admins
800
- checkAdminLimit (length admins')
801
-
802
800
-- update target in Cassandra
803
801
E. setTeamMemberPermissions (previousMember ^. permissions) tid targetId targetPermissions
804
802
805
- when (team ^. teamBinding == Binding ) $ do
806
- (TeamSize size) <- E. getSize tid
807
- owners <- E. getBillingTeamMembers tid
808
- Journal. teamUpdate tid size owners
809
-
810
- now <- input
811
- let event = newEvent tid now (EdMemberUpdate targetId (Just targetPermissions))
812
- let pushPriv = newPush ListComplete mZusr (TeamEvent event) (map userRecipient admins')
813
- for_ pushPriv (\ p -> E. push1 (p & pushConn .~ mZcon & pushTransient .~ True ))
803
+ updatedMembers <- getTeamMembersForFanout tid
804
+ updateJournal team
805
+ updatePeers mZusr targetId targetMember targetPermissions updatedMembers
806
+ where
807
+ updateJournal :: Team -> Sem r ()
808
+ updateJournal team = do
809
+ when (team ^. teamBinding == Binding ) $ do
810
+ (TeamSize size) <- E. getSize tid
811
+ owners <- E. getBillingTeamMembers tid
812
+ Journal. teamUpdate tid size owners
813
+
814
+ updatePeers :: Maybe UserId -> UserId -> TeamMember -> Permissions -> TeamMemberList -> Sem r ()
815
+ updatePeers zusr targetId targetMember targetPermissions updatedMembers = do
816
+ -- inform members of the team about the change
817
+ -- some (privileged) users will be informed about which change was applied
818
+ let privileged = filter (`canSeePermsOf` targetMember) (updatedMembers ^. teamMembers)
819
+ mkUpdate = EdMemberUpdate targetId
820
+ privilegedUpdate = mkUpdate $ Just targetPermissions
821
+ privilegedRecipients = membersToRecipients Nothing privileged
822
+ now <- input
823
+ let ePriv = newEvent tid now privilegedUpdate
824
+ -- push to all members (user is privileged)
825
+ let pushPriv = newPush (updatedMembers ^. teamMemberListType) zusr (TeamEvent ePriv) $ privilegedRecipients
826
+ for_ pushPriv (\ p -> E. push1 (p & pushConn .~ mZcon))
814
827
815
828
updateTeamMember ::
816
829
forall r .
@@ -819,7 +832,6 @@ updateTeamMember ::
819
832
Member (ErrorS 'InvalidPermissions) r ,
820
833
Member (ErrorS 'TeamNotFound) r ,
821
834
Member (ErrorS 'TeamMemberNotFound) r ,
822
- Member (ErrorS 'TooManyTeamAdmins) r ,
823
835
Member (ErrorS 'NotATeamMember) r ,
824
836
Member (ErrorS OperationDenied ) r ,
825
837
Member GundeckAccess r ,
@@ -950,6 +962,7 @@ deleteTeamMember' lusr zcon tid remove mBody = do
950
962
tm <- noteS @ 'TeamMemberNotFound targetMember
951
963
unless (canDeleteMember dm tm) $ throwS @ 'AccessDenied
952
964
team <- fmap tdTeam $ E. getTeam tid >>= noteS @ 'TeamNotFound
965
+ mems <- getTeamMembersForFanout tid
953
966
if team ^. teamBinding == Binding && isJust targetMember
954
967
then do
955
968
body <- mBody & note (InvalidPayload " missing request body" )
@@ -967,8 +980,7 @@ deleteTeamMember' lusr zcon tid remove mBody = do
967
980
Journal. teamUpdate tid sizeAfterDelete $ filter (/= remove) owners
968
981
pure TeamMemberDeleteAccepted
969
982
else do
970
- admins <- E. getTeamAdmins tid
971
- uncheckedDeleteTeamMember lusr (Just zcon) tid remove admins
983
+ uncheckedDeleteTeamMember lusr (Just zcon) tid remove mems
972
984
pure TeamMemberDeleteCompleted
973
985
974
986
-- This function is "unchecked" because it does not validate that the user has the `RemoveTeamMember` permission.
@@ -985,43 +997,47 @@ uncheckedDeleteTeamMember ::
985
997
Maybe ConnId ->
986
998
TeamId ->
987
999
UserId ->
988
- [ UserId ] ->
1000
+ TeamMemberList ->
989
1001
Sem r ()
990
- uncheckedDeleteTeamMember lusr zcon tid remove admins = do
1002
+ uncheckedDeleteTeamMember lusr zcon tid remove mems = do
991
1003
now <- input
992
1004
pushMemberLeaveEvent now
993
1005
E. deleteTeamMember tid remove
994
1006
removeFromConvsAndPushConvLeaveEvent now
995
1007
where
996
- -- notify team admins
1008
+ -- notify all team members.
997
1009
pushMemberLeaveEvent :: UTCTime -> Sem r ()
998
1010
pushMemberLeaveEvent now = do
999
1011
let e = newEvent tid now (EdMemberLeave remove)
1000
1012
let r =
1001
- userRecipient
1002
- <$> list1
1003
- (tUnqualified lusr)
1004
- (filter (/= (tUnqualified lusr)) admins)
1013
+ list1
1014
+ (userRecipient (tUnqualified lusr))
1015
+ (membersToRecipients (Just (tUnqualified lusr)) (mems ^. teamMembers))
1005
1016
E. push1 $
1006
- newPushLocal1 ListComplete (tUnqualified lusr) (TeamEvent e) r & pushConn .~ zcon & pushTransient .~ True
1017
+ newPushLocal1 (mems ^. teamMemberListType) (tUnqualified lusr) (TeamEvent e) r & pushConn .~ zcon
1007
1018
-- notify all conversation members not in this team.
1008
1019
removeFromConvsAndPushConvLeaveEvent :: UTCTime -> Sem r ()
1009
1020
removeFromConvsAndPushConvLeaveEvent now = do
1010
- let tmids = Set. fromList admins
1021
+ -- This may not make sense if that list has been truncated. In such cases, we still want to
1022
+ -- remove the user from conversations but never send out any events. We assume that clients
1023
+ -- handle nicely these missing events, regardless of whether they are in the same team or not
1024
+ let tmids = Set. fromList $ map (view userId) (mems ^. teamMembers)
1011
1025
let edata = Conv. EdMembersLeave (Conv. QualifiedUserIdList [tUntagged (qualifyAs lusr remove)])
1012
1026
cc <- E. getTeamConversations tid
1013
1027
for_ cc $ \ c ->
1014
1028
E. getConversation (c ^. conversationId) >>= \ conv ->
1015
1029
for_ conv $ \ dc -> when (remove `isMember` Data. convLocalMembers dc) $ do
1016
1030
E. deleteMembers (c ^. conversationId) (UserList [remove] [] )
1017
- pushEvent tmids edata now dc
1031
+ -- If the list was truncated, then the tmids list is incomplete so we simply drop these events
1032
+ unless (mems ^. teamMemberListType == ListTruncated ) $
1033
+ pushEvent tmids edata now dc
1018
1034
pushEvent :: Set UserId -> Conv. EventData -> UTCTime -> Data. Conversation -> Sem r ()
1019
1035
pushEvent exceptTo edata now dc = do
1020
1036
let qconvId = tUntagged $ qualifyAs lusr (Data. convId dc)
1021
1037
let (bots, users) = localBotsAndUsers (Data. convLocalMembers dc)
1022
1038
let x = filter (\ m -> not (Conv. lmId m `Set.member` exceptTo)) users
1023
1039
let y = Conv. Event qconvId Nothing (tUntagged lusr) now edata
1024
- for_ (newPushLocal ListComplete (tUnqualified lusr) (ConvEvent y) (recipient <$> x)) $ \ p ->
1040
+ for_ (newPushLocal (mems ^. teamMemberListType) (tUnqualified lusr) (ConvEvent y) (recipient <$> x)) $ \ p ->
1025
1041
E. push1 $ p & pushConn .~ zcon
1026
1042
E. deliverAsync (bots `zip` repeat y)
1027
1043
@@ -1226,7 +1242,6 @@ ensureNotTooLargeForLegalHold tid teamSize =
1226
1242
addTeamMemberInternal ::
1227
1243
( Member BrigAccess r ,
1228
1244
Member (ErrorS 'TooManyTeamMembers) r ,
1229
- Member (ErrorS 'TooManyTeamAdmins) r ,
1230
1245
Member GundeckAccess r ,
1231
1246
Member (Input Opts ) r ,
1232
1247
Member (Input UTCTime ) r ,
@@ -1238,29 +1253,29 @@ addTeamMemberInternal ::
1238
1253
Maybe UserId ->
1239
1254
Maybe ConnId ->
1240
1255
NewTeamMember ->
1256
+ TeamMemberList ->
1241
1257
Sem r TeamSize
1242
- addTeamMemberInternal tid origin originConn (ntmNewTeamMember -> new) = do
1258
+ addTeamMemberInternal tid origin originConn (ntmNewTeamMember -> new) memList = do
1243
1259
P. debug $
1244
1260
Log. field " targets" (toByteString (new ^. userId))
1245
1261
. Log. field " action" (Log. val " Teams.addTeamMemberInternal" )
1246
1262
sizeBeforeAdd <- ensureNotTooLarge tid
1247
-
1248
- admins <- E. getTeamAdmins tid
1249
- let admins' = [new ^. userId | isAdminOrOwner (new ^. M. permissions)] <> admins
1250
- checkAdminLimit (length admins')
1251
-
1252
1263
E. createTeamMember tid new
1253
-
1254
1264
now <- input
1255
1265
let e = newEvent tid now (EdMemberJoin (new ^. userId))
1256
- let rs = case origin of
1257
- Just o -> userRecipient <$> list1 o (filter (/= o) ((new ^. userId) : admins'))
1258
- Nothing -> userRecipient <$> list1 (new ^. userId) (admins')
1259
1266
E. push1 $
1260
- newPushLocal1 ListComplete (new ^. userId) (TeamEvent e) rs & pushConn .~ originConn & pushTransient .~ True
1261
-
1267
+ newPushLocal1 (memList ^. teamMemberListType) (new ^. userId) (TeamEvent e) (recipients origin new) & pushConn .~ originConn
1262
1268
APITeamQueue. pushTeamEvent tid e
1263
1269
pure sizeBeforeAdd
1270
+ where
1271
+ recipients (Just o) n =
1272
+ list1
1273
+ (userRecipient o)
1274
+ (membersToRecipients (Just o) (n : memList ^. teamMembers))
1275
+ recipients Nothing n =
1276
+ list1
1277
+ (userRecipient (n ^. userId))
1278
+ (membersToRecipients Nothing (memList ^. teamMembers))
1264
1279
1265
1280
finishCreateTeam ::
1266
1281
( Member GundeckAccess r ,
@@ -1389,8 +1404,3 @@ queueTeamDeletion ::
1389
1404
queueTeamDeletion tid zusr zcon = do
1390
1405
ok <- E. tryPush (TeamItem tid zusr zcon)
1391
1406
unless ok $ throwS @ 'DeleteQueueFull
1392
-
1393
- checkAdminLimit :: Member (ErrorS 'TooManyTeamAdmins) r => Int -> Sem r ()
1394
- checkAdminLimit adminCount =
1395
- when (adminCount > 2000 ) $
1396
- throwS @ 'TooManyTeamAdmins
0 commit comments