mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-31 03:16:05 +00:00
core: update deleteGroupMember logic and its usages (no items & expiration) (#1258)
This commit is contained in:
@@ -537,6 +537,8 @@ processChatCommand = \case
|
||||
maxItemTs_ <- withStore' $ \db -> getGroupMaxItemTs db user gInfo
|
||||
forM_ filesInfo $ \fileInfo -> deleteFile user fileInfo
|
||||
withStore' $ \db -> deleteGroupCIs db user gInfo
|
||||
membersToDelete <- withStore' $ \db -> getGroupMembersForExpiration db user gInfo
|
||||
forM_ membersToDelete $ \m -> withStore' $ \db -> deleteGroupMember db user m
|
||||
gInfo' <- case maxItemTs_ of
|
||||
Just ts -> do
|
||||
withStore' $ \db -> updateGroupTs db user gInfo ts
|
||||
@@ -905,7 +907,10 @@ processChatCommand = \case
|
||||
ci <- saveSndChatItem user (CDGroupSnd gInfo) msg (CISndGroupEvent $ SGEMemberDeleted memberId (fromLocalProfile memberProfile)) Nothing Nothing
|
||||
toView . CRNewChatItem $ AChatItem SCTGroup SMDSnd (GroupChat gInfo) ci
|
||||
deleteMemberConnection user m
|
||||
withStore' $ \db -> updateGroupMemberStatus db userId m GSMemRemoved
|
||||
withStore' $ \db ->
|
||||
checkGroupMemberHasItems db user m >>= \case
|
||||
Just _ -> updateGroupMemberStatus db userId m GSMemRemoved
|
||||
Nothing -> deleteGroupMember db user m
|
||||
pure $ CRUserDeletedMember gInfo m {memberStatus = GSMemRemoved}
|
||||
APILeaveGroup groupId -> withUser $ \user@User {userId} -> do
|
||||
Group gInfo@GroupInfo {membership} members <- withStore $ \db -> getGroup db user groupId
|
||||
@@ -1536,6 +1541,8 @@ expireChatItems user ttl sync = do
|
||||
maxItemTs_ <- withStore' $ \db -> getGroupMaxItemTs db user gInfo
|
||||
forM_ filesInfo $ \fileInfo -> deleteFile user fileInfo
|
||||
withStore' $ \db -> deleteGroupExpiredCIs db user gInfo expirationDate createdAtCutoff
|
||||
membersToDelete <- withStore' $ \db -> getGroupMembersForExpiration db user gInfo
|
||||
forM_ membersToDelete $ \m -> withStore' $ \db -> deleteGroupMember db user m
|
||||
withStore' $ \db -> do
|
||||
ciCount_ <- getGroupCICount db user gInfo
|
||||
case (maxItemTs_, ciCount_) of
|
||||
|
||||
@@ -83,6 +83,7 @@ module Simplex.Chat.Store
|
||||
getGroupInfoByName,
|
||||
getGroupMember,
|
||||
getGroupMembers,
|
||||
getGroupMembersForExpiration,
|
||||
deleteGroupConnectionsAndFiles,
|
||||
deleteGroupItemsAndMembers,
|
||||
deleteGroup,
|
||||
@@ -98,6 +99,7 @@ module Simplex.Chat.Store
|
||||
updateGroupMemberStatus,
|
||||
updateGroupMemberStatusById,
|
||||
createNewGroupMember,
|
||||
checkGroupMemberHasItems,
|
||||
deleteGroupMember,
|
||||
deleteGroupMemberConnection,
|
||||
updateGroupMemberRole,
|
||||
@@ -1676,9 +1678,7 @@ deleteGroupItemsAndMembers :: DB.Connection -> User -> GroupInfo -> [GroupMember
|
||||
deleteGroupItemsAndMembers db user@User {userId} GroupInfo {groupId} members = do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
||||
DB.execute db "DELETE FROM group_members WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
||||
forM_ members $ \m@GroupMember {groupMemberId, memberContactId, memberContactProfileId} -> unless (isJust memberContactId) $ do
|
||||
sameProfileMember :: (Maybe GroupMemberId) <- maybeFirstRow fromOnly $ DB.query db "SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1" (userId, memberContactProfileId, groupMemberId)
|
||||
unless (isJust sameProfileMember) $ deleteMemberProfileAndName_ db user m
|
||||
forM_ members $ \m -> cleanupMemberContactAndProfile_ db user m
|
||||
|
||||
deleteGroup :: DB.Connection -> User -> GroupInfo -> IO ()
|
||||
deleteGroup db User {userId} GroupInfo {groupId, localDisplayName} = do
|
||||
@@ -1779,6 +1779,32 @@ getGroupMembers db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
|]
|
||||
(groupId, userId, userContactId)
|
||||
|
||||
getGroupMembersForExpiration :: DB.Connection -> User -> GroupInfo -> IO [GroupMember]
|
||||
getGroupMembersForExpiration db user@User {userId, userContactId} GroupInfo {groupId} = do
|
||||
map (toContactMember user)
|
||||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT
|
||||
m.group_member_id, m.group_id, m.member_id, m.member_role, m.member_category, m.member_status,
|
||||
m.invited_by, m.local_display_name, m.contact_id, m.contact_profile_id, p.contact_profile_id, p.display_name, p.full_name, p.image, p.local_alias,
|
||||
c.connection_id, c.agent_conn_id, c.conn_level, c.via_contact, c.via_user_contact_link, c.via_group_link, c.custom_user_profile_id,
|
||||
c.conn_status, c.conn_type, c.local_alias, c.contact_id, c.group_member_id, c.snd_file_id, c.rcv_file_id, c.user_contact_link_id, c.created_at
|
||||
FROM group_members m
|
||||
JOIN contact_profiles p ON p.contact_profile_id = COALESCE(m.member_profile_id, m.contact_profile_id)
|
||||
LEFT JOIN connections c ON c.connection_id = (
|
||||
SELECT max(cc.connection_id)
|
||||
FROM connections cc
|
||||
where cc.group_member_id = m.group_member_id
|
||||
)
|
||||
WHERE m.group_id = ? AND m.user_id = ? AND (m.contact_id IS NULL OR m.contact_id != ?)
|
||||
AND m.member_status IN (?, ?, ?)
|
||||
AND m.group_member_id NOT IN (
|
||||
SELECT DISTINCT group_member_id FROM chat_items
|
||||
)
|
||||
|]
|
||||
(groupId, userId, userContactId, GSMemRemoved, GSMemLeft, GSMemGroupDeleted)
|
||||
|
||||
toContactMember :: User -> (GroupMemberRow :. MaybeConnectionRow) -> GroupMember
|
||||
toContactMember User {userContactId} (memberRow :. connRow) =
|
||||
(toGroupMember userContactId memberRow) {activeConn = toMaybeConnection connRow}
|
||||
@@ -1986,19 +2012,30 @@ createNewMember_
|
||||
groupMemberId <- insertedRowId db
|
||||
pure GroupMember {groupMemberId, groupId, memberId, memberRole, memberCategory, memberStatus, invitedBy, localDisplayName, memberProfile = toLocalProfile memberContactProfileId memberProfile "", memberContactId, memberContactProfileId, activeConn}
|
||||
|
||||
checkGroupMemberHasItems :: DB.Connection -> User -> GroupMember -> IO (Maybe ChatItemId)
|
||||
checkGroupMemberHasItems db User {userId} GroupMember {groupMemberId, groupId} =
|
||||
maybeFirstRow fromOnly $ DB.query db "SELECT chat_item_id FROM chat_items WHERE user_id = ? AND group_id = ? AND group_member_id = ? LIMIT 1" (userId, groupId, groupMemberId)
|
||||
|
||||
deleteGroupMember :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteGroupMember db user@User {userId} m@GroupMember {groupMemberId, groupId, memberContactId, memberContactProfileId} = do
|
||||
deleteGroupMember db user@User {userId} m@GroupMember {groupMemberId, groupId} = do
|
||||
deleteGroupMemberConnection db user m
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND group_id = ? AND group_member_id = ?" (userId, groupId, groupMemberId)
|
||||
DB.execute db "DELETE FROM group_members WHERE user_id = ? AND group_member_id = ?" (userId, groupMemberId)
|
||||
unless (isJust memberContactId) $ do
|
||||
sameProfileMember :: (Maybe GroupMemberId) <- maybeFirstRow fromOnly $ DB.query db "SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1" (userId, memberContactProfileId, groupMemberId)
|
||||
unless (isJust sameProfileMember) $ deleteMemberProfileAndName_ db user m
|
||||
cleanupMemberContactAndProfile_ db user m
|
||||
|
||||
deleteMemberProfileAndName_ :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteMemberProfileAndName_ db User {userId} GroupMember {memberContactProfileId, localDisplayName} = do
|
||||
DB.execute db "DELETE FROM contact_profiles WHERE user_id = ? AND contact_profile_id = ?" (userId, memberContactProfileId)
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
cleanupMemberContactAndProfile_ :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
cleanupMemberContactAndProfile_ db User {userId} GroupMember {groupMemberId, localDisplayName, memberContactId, memberContactProfileId} =
|
||||
case memberContactId of
|
||||
Just contactId ->
|
||||
runExceptT (getContact db userId contactId) >>= \case
|
||||
Right ct@Contact {activeConn = Connection {connLevel, viaGroupLink}, contactUsed} ->
|
||||
unless ((connLevel == 0 && not viaGroupLink) || contactUsed) $ deleteContact db userId ct
|
||||
_ -> pure ()
|
||||
Nothing -> do
|
||||
sameProfileMember :: (Maybe GroupMemberId) <- maybeFirstRow fromOnly $ DB.query db "SELECT group_member_id FROM group_members WHERE user_id = ? AND contact_profile_id = ? AND group_member_id != ? LIMIT 1" (userId, memberContactProfileId, groupMemberId)
|
||||
unless (isJust sameProfileMember) $ do
|
||||
DB.execute db "DELETE FROM contact_profiles WHERE user_id = ? AND contact_profile_id = ?" (userId, memberContactProfileId)
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
|
||||
deleteGroupMemberConnection :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteGroupMemberConnection db User {userId} GroupMember {groupMemberId} =
|
||||
@@ -3122,7 +3159,7 @@ getDirectChatPreviews_ db User {userId} = do
|
||||
) ChatStats ON ChatStats.contact_id = ct.contact_id
|
||||
LEFT JOIN chat_items ri ON i.quoted_shared_msg_id = ri.shared_msg_id
|
||||
WHERE ct.user_id = ?
|
||||
AND ((c.conn_level = 0 AND c.via_group_link = 0) OR i.chat_item_id IS NOT NULL OR ct.contact_used = 1)
|
||||
AND ((c.conn_level = 0 AND c.via_group_link = 0) OR ct.contact_used = 1)
|
||||
AND c.connection_id = (
|
||||
SELECT cc_connection_id FROM (
|
||||
SELECT
|
||||
|
||||
@@ -768,7 +768,13 @@ testGroupDelete =
|
||||
cath <## "#team: you deleted the group"
|
||||
alice <##> bob
|
||||
alice <##> cath
|
||||
bob <##> cath
|
||||
-- unused group contacts are deleted
|
||||
bob ##> "@cath hi"
|
||||
bob <## "no contact cath"
|
||||
(cath </)
|
||||
cath ##> "@bob hi"
|
||||
cath <## "no contact bob"
|
||||
(bob </)
|
||||
|
||||
testGroupSameName :: IO ()
|
||||
testGroupSameName =
|
||||
@@ -3557,8 +3563,10 @@ testGroupLinkDeleteInvitedMemberNoBrokenItem =
|
||||
alice <## "#team: you removed bob from the group"
|
||||
alice #$> ("/_get chat #1 count=100", chat, [])
|
||||
alice @@@ [("#team", "")]
|
||||
alice <##> bob
|
||||
alice @@@ [("@bob", "hey"), ("#team", "")]
|
||||
-- removing member deletes unused group contact
|
||||
alice ##> "@bob hi"
|
||||
alice <## "no contact bob"
|
||||
(bob </)
|
||||
bob ##> "/j team"
|
||||
bob <## "error: connection authorization failed - this could happen if connection was deleted, secured with different credentials, or due to a bug - please re-create the connection"
|
||||
-- repeat request is prohibited because of the re-used XContactId, until contact is deleted
|
||||
@@ -3568,11 +3576,11 @@ testGroupLinkDeleteInvitedMemberNoBrokenItem =
|
||||
bob <## "alice: contact is deleted"
|
||||
bob ##> ("/c " <> gLink)
|
||||
bob <## "connection request sent!"
|
||||
alice <## "bob_1 (Bob): accepting request to join group #team..."
|
||||
alice <## "bob (Bob): accepting request to join group #team..."
|
||||
concurrentlyN_
|
||||
[ do
|
||||
alice <## "bob_1 (Bob): contact is connected"
|
||||
alice <## "bob_1 invited to group #team via your group link",
|
||||
alice <## "bob (Bob): contact is connected"
|
||||
alice <## "bob invited to group #team via your group link",
|
||||
do
|
||||
bob <## "alice_1 (Alice): contact is connected"
|
||||
bob <## "#team_1 (team): alice_1 invites you to join the group as member"
|
||||
@@ -3580,12 +3588,12 @@ testGroupLinkDeleteInvitedMemberNoBrokenItem =
|
||||
]
|
||||
bob ##> "/j team_1"
|
||||
concurrently_
|
||||
(alice <## "#team: bob_1 joined the group")
|
||||
(alice <## "#team: bob joined the group")
|
||||
(bob <## "#team_1: you joined the group")
|
||||
alice #> "#team hello"
|
||||
bob <# "#team_1 alice_1> hello"
|
||||
bob #> "#team_1 hi there"
|
||||
alice <# "#team bob_1> hi there"
|
||||
alice <# "#team bob> hi there"
|
||||
|
||||
withTestChatContactConnected :: String -> (TestCC -> IO a) -> IO a
|
||||
withTestChatContactConnected dbPrefix action =
|
||||
|
||||
Reference in New Issue
Block a user