mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-09-17 03:45:01 +00:00
core: allow to delete contacts that are in groups; group contacts management rfc (#1229)
This commit is contained in:
+13
-16
@@ -486,20 +486,17 @@ processChatCommand = \case
|
||||
APIDeleteChat (ChatRef cType chatId) -> withUser $ \user@User {userId} -> case cType of
|
||||
CTDirect -> do
|
||||
ct@Contact {localDisplayName} <- withStore $ \db -> getContact db userId chatId
|
||||
withStore' (\db -> getContactGroupNames db userId ct) >>= \case
|
||||
[] -> do
|
||||
filesInfo <- withStore' $ \db -> getContactFileInfo db user ct
|
||||
conns <- withStore $ \db -> getContactConnections db userId ct
|
||||
withChatLock . procCmd $ do
|
||||
forM_ filesInfo $ \fileInfo -> deleteFile user fileInfo
|
||||
forM_ conns $ \conn -> deleteAgentConnectionAsync user conn `catchError` \_ -> pure ()
|
||||
-- functions below are called in separate transactions to prevent crashes on android
|
||||
-- (possibly, race condition on integrity check?)
|
||||
withStore' $ \db -> deleteContactConnectionsAndFiles db userId ct
|
||||
withStore' $ \db -> deleteContact db userId ct
|
||||
unsetActive $ ActiveC localDisplayName
|
||||
pure $ CRContactDeleted ct
|
||||
gs -> throwChatError $ CEContactGroups ct gs
|
||||
filesInfo <- withStore' $ \db -> getContactFileInfo db user ct
|
||||
conns <- withStore $ \db -> getContactConnections db userId ct
|
||||
withChatLock . procCmd $ do
|
||||
forM_ filesInfo $ \fileInfo -> deleteFile user fileInfo
|
||||
forM_ conns $ \conn -> deleteAgentConnectionAsync user conn `catchError` \_ -> pure ()
|
||||
-- functions below are called in separate transactions to prevent crashes on android
|
||||
-- (possibly, race condition on integrity check?)
|
||||
withStore' $ \db -> deleteContactConnectionsAndFiles db userId ct
|
||||
withStore' $ \db -> deleteContact db userId ct
|
||||
unsetActive $ ActiveC localDisplayName
|
||||
pure $ CRContactDeleted ct
|
||||
CTContactConnection -> withChatLock . procCmd $ do
|
||||
conn@PendingContactConnection {pccConnId, pccAgentConnId} <- withStore $ \db -> getPendingContactConnection db userId chatId
|
||||
deleteAgentConnectionAsync' user pccConnId pccAgentConnId
|
||||
@@ -518,7 +515,7 @@ processChatCommand = \case
|
||||
-- functions below are called in separate transactions to prevent crashes on android
|
||||
-- (possibly, race condition on integrity check?)
|
||||
withStore' $ \db -> deleteGroupConnectionsAndFiles db user gInfo members
|
||||
withStore' $ \db -> deleteGroupItemsAndMembers db user gInfo
|
||||
withStore' $ \db -> deleteGroupItemsAndMembers db user gInfo members
|
||||
withStore' $ \db -> deleteGroup db user gInfo
|
||||
pure $ CRGroupDeletedUser gInfo
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
@@ -1814,7 +1811,7 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM
|
||||
withStore' (\db -> getViaGroupContact db user m) >>= \case
|
||||
Nothing -> do
|
||||
notifyMemberConnected gInfo m
|
||||
messageError "implementation error: connected member does not have contact"
|
||||
messageWarning "connected member does not have contact"
|
||||
Just ct@Contact {activeConn = Connection {connStatus}} ->
|
||||
when (connStatus == ConnReady) $ do
|
||||
notifyMemberConnected gInfo m
|
||||
|
||||
@@ -464,7 +464,6 @@ data ChatErrorType
|
||||
| CEInvalidConnReq
|
||||
| CEInvalidChatMessage {message :: String}
|
||||
| CEContactNotReady {contact :: Contact}
|
||||
| CEContactGroups {contact :: Contact, groupNames :: [GroupName]}
|
||||
| CEGroupUserRole
|
||||
| CEContactIncognitoCantInvite
|
||||
| CEGroupIncognitoCantInvite
|
||||
|
||||
+23
-20
@@ -31,7 +31,6 @@ module Simplex.Chat.Store
|
||||
getProfileById,
|
||||
getConnReqContactXContactId,
|
||||
createDirectContact,
|
||||
getContactGroupNames,
|
||||
deleteContactConnectionsAndFiles,
|
||||
deleteContact,
|
||||
getContactByName,
|
||||
@@ -241,7 +240,7 @@ import Data.Functor (($>))
|
||||
import Data.Int (Int64)
|
||||
import Data.List (find, sortBy, sortOn)
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import Data.Maybe (fromMaybe, isJust, listToMaybe)
|
||||
import Data.Maybe (fromMaybe, isJust, isNothing, listToMaybe)
|
||||
import Data.Ord (Down (..))
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
@@ -534,19 +533,6 @@ createContact_ db userId connId Profile {displayName, fullName, image} localAlia
|
||||
DB.execute db "UPDATE connections SET contact_id = ?, updated_at = ? WHERE connection_id = ?" (contactId, currentTs, connId)
|
||||
pure . Right $ (ldn, contactId, profileId)
|
||||
|
||||
getContactGroupNames :: DB.Connection -> UserId -> Contact -> IO [GroupName]
|
||||
getContactGroupNames db userId Contact {contactId} =
|
||||
map fromOnly
|
||||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT DISTINCT g.local_display_name
|
||||
FROM groups g
|
||||
JOIN group_members m ON m.group_id = g.group_id
|
||||
WHERE g.user_id = ? AND m.contact_id = ?
|
||||
|]
|
||||
(userId, contactId)
|
||||
|
||||
deleteContactConnectionsAndFiles :: DB.Connection -> UserId -> Contact -> IO ()
|
||||
deleteContactConnectionsAndFiles db userId Contact {contactId} = do
|
||||
DB.execute
|
||||
@@ -565,9 +551,15 @@ deleteContactConnectionsAndFiles db userId Contact {contactId} = do
|
||||
deleteContact :: DB.Connection -> UserId -> Contact -> IO ()
|
||||
deleteContact db userId Contact {contactId, localDisplayName} = do
|
||||
DB.execute db "DELETE FROM chat_items WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
deleteContactProfile_ db userId contactId
|
||||
ctMember :: (Maybe ContactId) <- maybeFirstRow fromOnly $ DB.query db "SELECT contact_id FROM group_members WHERE user_id = ? AND contact_id = ? LIMIT 1" (userId, contactId)
|
||||
if isNothing ctMember
|
||||
then do
|
||||
deleteContactProfile_ db userId contactId
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
else do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute db "UPDATE group_members SET contact_id = NULL, updated_at = ? WHERE user_id = ? AND contact_id = ?" (currentTs, userId, contactId)
|
||||
DB.execute db "DELETE FROM contacts WHERE user_id = ? AND contact_id = ?" (userId, contactId)
|
||||
DB.execute db "DELETE FROM display_names WHERE user_id = ? AND local_display_name = ?" (userId, localDisplayName)
|
||||
|
||||
deleteContactProfile_ :: DB.Connection -> UserId -> ContactId -> IO ()
|
||||
deleteContactProfile_ db userId contactId =
|
||||
@@ -1641,10 +1633,13 @@ deleteGroupConnectionsAndFiles db User {userId} GroupInfo {groupId} members = do
|
||||
forM_ members $ \m -> DB.execute db "DELETE FROM connections WHERE user_id = ? AND group_member_id = ?" (userId, groupMemberId' m)
|
||||
DB.execute db "DELETE FROM files WHERE user_id = ? AND group_id = ?" (userId, groupId)
|
||||
|
||||
deleteGroupItemsAndMembers :: DB.Connection -> User -> GroupInfo -> IO ()
|
||||
deleteGroupItemsAndMembers db User {userId} GroupInfo {groupId} = do
|
||||
deleteGroupItemsAndMembers :: DB.Connection -> User -> GroupInfo -> [GroupMember] -> IO ()
|
||||
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
|
||||
|
||||
deleteGroup :: DB.Connection -> User -> GroupInfo -> IO ()
|
||||
deleteGroup db User {userId} GroupInfo {groupId, localDisplayName} = do
|
||||
@@ -1953,9 +1948,17 @@ createNewMember_
|
||||
pure GroupMember {groupMemberId, groupId, memberId, memberRole, memberCategory, memberStatus, invitedBy, localDisplayName, memberProfile = toLocalProfile memberContactProfileId memberProfile "", memberContactId, memberContactProfileId, activeConn}
|
||||
|
||||
deleteGroupMember :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteGroupMember db user@User {userId} m@GroupMember {groupMemberId} = do
|
||||
deleteGroupMember db user@User {userId} m@GroupMember {groupMemberId, memberContactId, memberContactProfileId} = do
|
||||
deleteGroupMemberConnection db user m
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
deleteGroupMemberConnection :: DB.Connection -> User -> GroupMember -> IO ()
|
||||
deleteGroupMemberConnection db User {userId} GroupMember {groupMemberId} =
|
||||
|
||||
@@ -955,7 +955,6 @@ viewChatError = \case
|
||||
CEInvalidConnReq -> viewInvalidConnReq
|
||||
CEInvalidChatMessage e -> ["chat message error: " <> sShow e]
|
||||
CEContactNotReady c -> [ttyContact' c <> ": not ready"]
|
||||
CEContactGroups c gNames -> [ttyContact' c <> ": contact cannot be deleted, it is a member of the group(s) " <> ttyGroups gNames]
|
||||
CEGroupDuplicateMember c -> ["contact " <> ttyContact c <> " is already in the group"]
|
||||
CEGroupDuplicateMemberId -> ["cannot add member - duplicate member ID"]
|
||||
CEGroupUserRole -> ["you have insufficient permissions for this group command"]
|
||||
|
||||
Reference in New Issue
Block a user