core: fix unread support items left behind when pending member leaves group

xGrpLeave deletes the leaving member's support chat, and every chat item in
it, and then creates the "member left" item - but it passes the pre-leave
member value to mkGroupChatScope. A member pending approval or review still
reads as pending there, so the item is written back into the support scope
that was just deleted, and mkMemberSupportChatInfo and updateChatTsStats
recreate the support chat around it.

That item is unread and counts towards the profile unread total, as the
group query in getUsersInfo has no group scope filter. The member is now
GSMemLeft, so the UI filters them out of the member support chat list and
the item can never be opened: the count stays until the whole profile is
marked read.

Pass the member with the status it was just given, so the event is created
in the group scope, as it already is when a member is removed.
This commit is contained in:
Narasimha-sc committed 2026-08-29 18:12:13 +00:00
1 parent 498d7da837
commit 1782c3db7b
2 files changed
+37 -3

No files matched your search

+5 -3
View File
@@ -3680,11 +3680,13 @@ processAgentMessageConn cxt user@User {userId} corrId agentConnId agentMessage =
-- member record is not deleted to allow creation of "member left" chat item
gInfo' <- updateMemberRecordDeleted user gInfo m GSMemLeft
gInfo'' <- updatePublicGroupData user gInfo'
unless (muteEventInChannel gInfo'' m) $ do
(gInfo''', m', scopeInfo) <- mkGroupChatScope gInfo'' m
-- support chat was deleted with the member record above, so the item has to be created in the group scope
let mLeft = m {memberStatus = GSMemLeft, supportChat = Nothing}
unless (muteEventInChannel gInfo'' mLeft) $ do
(gInfo''', m', scopeInfo) <- mkGroupChatScope gInfo'' mLeft
(ci, cInfo) <- saveRcvChatItemNoParse user (CDGroupRcv gInfo''' scopeInfo m') msg brokerTs (CIRcvGroupEvent RGEMemberLeft)
groupMsgToView cInfo ci
toView $ CEvtLeftMember user gInfo''' m' {memberStatus = GSMemLeft} msgSigned
toView $ CEvtLeftMember user gInfo''' m' msgSigned
pure $ memberEventDeliveryScope m
xGrpDel :: GroupInfo -> GroupMember -> RcvMessage -> UTCTime -> CM ()
+32
View File
@@ -128,6 +128,7 @@ chatGroupTests = do
it "accept member - only moderators review" testGLinkReviewMember
it "accept member - host approval, then moderators review" testGLinkApproveThenReviewMember
it "delete pending approval member" testGLinkDeletePendingApprovalMember
it "pending approval member leaves the group" testGLinkPendingApprovalMemberLeaves
it "admin that joined via link introduces member for moderator review" testGLinkReviewIntroduce
describe "group link connection plan" $ do
it "ok to connect; known group" testPlanGroupLinkKnown
@@ -3621,6 +3622,37 @@ testGLinkDeletePendingApprovalMember =
where
cfg = testCfg {chatHooks = defaultChatHooks {acceptMember = Just (\_ _ _ -> pure $ Right (GAPendingApproval, GRObserver))}}
testGLinkPendingApprovalMemberLeaves :: HasCallStack => TestParams -> IO ()
testGLinkPendingApprovalMemberLeaves =
testChatCfg3 cfg aliceProfile bobProfile cathProfile $
\alice bob cath -> do
createGroup2 "team" alice bob
alice ##> "/create link #team"
gLink <- getGroupLink alice "team" GRMember True
cath ##> ("/c " <> gLink)
cath <## "connection request sent!"
alice <## "cath (Catherine): accepting request to join group #team..."
concurrentlyN_
[ alice <## "#team: cath connected and pending approval, use /_accept member #1 3 <role> to accept member",
do
cath <## "#team: joining the group..."
cath <## "#team: you joined the group, pending approval"
]
cath ##> "/leave #team"
concurrentlyN_
[ do
cath <## "#team: you left the group"
cath <## "use /d #team to delete the group",
alice <## "#team: cath left the group"
]
alice ##> "/member support chats #team"
alice <## "members require attention: 0"
where
cfg = testCfg {chatHooks = defaultChatHooks {acceptMember = Just (\_ _ _ -> pure $ Right (GAPendingApproval, GRObserver))}}
testGLinkReviewIntroduce :: HasCallStack => TestParams -> IO ()
testGLinkReviewIntroduce =
testChat5 aliceProfile bobProfile cathProfile danProfile eveProfile $