From d7f319aa9e68db4fc4784f8492dc4fc71c1c3b64 Mon Sep 17 00:00:00 2001 From: JRoberts <8711996+jr-simplex@users.noreply.github.com> Date: Tue, 25 Oct 2022 12:50:26 +0400 Subject: [PATCH] core: mark group contacts as used on send, receive, api (#1253) --- simplex-chat.cabal | 1 + src/Simplex/Chat.hs | 23 ++++--- .../Chat/Migrations/M20221024_contact_used.hs | 22 +++++++ src/Simplex/Chat/Migrations/chat_schema.sql | 1 + src/Simplex/Chat/Store.hs | 66 +++++++++++-------- src/Simplex/Chat/Types.hs | 1 + tests/ChatTests.hs | 9 +++ 7 files changed, 86 insertions(+), 37 deletions(-) create mode 100644 src/Simplex/Chat/Migrations/M20221024_contact_used.hs diff --git a/simplex-chat.cabal b/simplex-chat.cabal index a00b36afd6..3843517e20 100644 --- a/simplex-chat.cabal +++ b/simplex-chat.cabal @@ -58,6 +58,7 @@ library Simplex.Chat.Migrations.M20221012_inline_files Simplex.Chat.Migrations.M20221019_unread_chat Simplex.Chat.Migrations.M20221021_auto_accept__group_links + Simplex.Chat.Migrations.M20221024_contact_used Simplex.Chat.Mobile Simplex.Chat.Options Simplex.Chat.ProfileGenerator diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index bb8b70870e..6b8115d7ce 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -271,14 +271,18 @@ processChatCommand = \case APIGetChats withPCC -> CRApiChats <$> withUser' (\user -> withStore' $ \db -> getChatPreviews db user withPCC) APIGetChat (ChatRef cType cId) pagination search -> withUser $ \user -> case cType of -- TODO optimize queries calculating ChatStats, currently they're disabled - CTDirect -> CRApiChat . AChat SCTDirect <$> withStore (\db -> getDirectChat db user cId pagination search) + CTDirect -> do + directChat@Chat {chatInfo} <- withStore (\db -> getDirectChat db user cId pagination search) + case chatInfo of DirectChat ct@Contact {contactUsed} -> unless contactUsed $ withStore' $ \db -> updateContactUsed db user ct + pure . CRApiChat $ AChat SCTDirect directChat CTGroup -> CRApiChat . AChat SCTGroup <$> withStore (\db -> getGroupChat db user cId pagination search) CTContactRequest -> pure $ chatCmdError "not implemented" CTContactConnection -> pure $ chatCmdError "not supported" APIGetChatItems _pagination -> pure $ chatCmdError "not implemented" APISendMessage (ChatRef cType chatId) (ComposedMessage file_ quotedItemId_ mc) -> withUser $ \user@User {userId} -> withChatLock "sendMessage" $ case cType of CTDirect -> do - ct@Contact {localDisplayName = c} <- withStore $ \db -> getContact db userId chatId + ct@Contact {localDisplayName = c, contactUsed} <- withStore $ \db -> getContact db userId chatId + unless contactUsed $ withStore' $ \db -> updateContactUsed db user ct (fileInvitation_, ciFile_, ft_) <- unzipMaybe3 <$> setupSndFileTransfer ct (msgContainer, quotedItem_) <- prepareMsg fileInvitation_ (msg@SndMessage {sharedMsgId}, _) <- sendDirectContactMessage ct (XMsgNew msgContainer) @@ -468,14 +472,14 @@ processChatCommand = \case CTContactConnection -> pure $ chatCmdError "not supported" APIChatUnread (ChatRef cType chatId) unreadChat -> withUser $ \user@User {userId} -> case cType of CTDirect -> do - _ <- withStore $ \db -> do - Contact {contactId} <- getContact db userId chatId - liftIO $ updateContactUnreadChat db user contactId unreadChat + withStore $ \db -> do + ct <- getContact db userId chatId + liftIO $ updateContactUnreadChat db user ct unreadChat pure CRCmdOk CTGroup -> do - _ <- withStore $ \db -> do - Group GroupInfo {groupId} _ <- getGroup db user chatId - liftIO $ updateGroupUnreadChat db user groupId unreadChat + withStore $ \db -> do + Group {groupInfo} <- getGroup db user chatId + liftIO $ updateGroupUnreadChat db user groupInfo unreadChat pure CRCmdOk _ -> pure $ chatCmdError "not supported" APIDeleteChat (ChatRef cType chatId) -> withUser $ \user@User {userId} -> case cType of @@ -2116,7 +2120,8 @@ processAgentMessage (Just user@User {userId, profile}) corrId agentConnId agentM messageError = toView . CRMessageError "error" newContentMessage :: Contact -> MsgContainer -> RcvMessage -> MsgMeta -> m () - newContentMessage ct@Contact {localDisplayName = c, chatSettings} mc msg msgMeta = do + newContentMessage ct@Contact {localDisplayName = c, contactUsed, chatSettings} mc msg msgMeta = do + unless contactUsed $ withStore' $ \db -> updateContactUsed db user ct checkIntegrityCreateItem (CDDirectRcv ct) msgMeta let (ExtMsgContent content fileInvitation_) = mcExtMsgContent mc ciFile_ <- processFileInvitation fileInvitation_ $ \db -> createRcvFileTransfer db userId ct diff --git a/src/Simplex/Chat/Migrations/M20221024_contact_used.hs b/src/Simplex/Chat/Migrations/M20221024_contact_used.hs new file mode 100644 index 0000000000..6f677f1c77 --- /dev/null +++ b/src/Simplex/Chat/Migrations/M20221024_contact_used.hs @@ -0,0 +1,22 @@ +{-# LANGUAGE QuasiQuotes #-} + +module Simplex.Chat.Migrations.M20221024_contact_used where + +import Database.SQLite.Simple (Query) +import Database.SQLite.Simple.QQ (sql) + +m20221024_contact_used :: Query +m20221024_contact_used = + [sql| +PRAGMA ignore_check_constraints=ON; + +ALTER TABLE contacts ADD COLUMN contact_used INTEGER DEFAULT 0 CHECK (contact_used NOT NULL); + +UPDATE contacts SET contact_used = 0; + +UPDATE contacts SET contact_used = 1 WHERE contact_id IN ( + SELECT DISTINCT contact_id FROM chat_items WHERE contact_id IS NOT NULL +); + +PRAGMA ignore_check_constraints=OFF; +|] diff --git a/src/Simplex/Chat/Migrations/chat_schema.sql b/src/Simplex/Chat/Migrations/chat_schema.sql index 47065fba2e..40ea1741bd 100644 --- a/src/Simplex/Chat/Migrations/chat_schema.sql +++ b/src/Simplex/Chat/Migrations/chat_schema.sql @@ -57,6 +57,7 @@ is_user INTEGER NOT NULL DEFAULT 0, -- 1 if this contact is a user xcontact_id BLOB, enable_ntfs INTEGER, unread_chat INTEGER DEFAULT 0 CHECK(unread_chat NOT NULL), + contact_used INTEGER DEFAULT 0 CHECK(contact_used NOT NULL), FOREIGN KEY(user_id, local_display_name) REFERENCES display_names(user_id, local_display_name) ON DELETE CASCADE diff --git a/src/Simplex/Chat/Store.hs b/src/Simplex/Chat/Store.hs index 8d23dcffd4..a36c205430 100644 --- a/src/Simplex/Chat/Store.hs +++ b/src/Simplex/Chat/Store.hs @@ -42,6 +42,7 @@ module Simplex.Chat.Store updateContactProfile, updateContactAlias, updateContactConnectionAlias, + updateContactUsed, updateContactUnreadChat, updateGroupUnreadChat, getUserContacts, @@ -286,6 +287,7 @@ import Simplex.Chat.Migrations.M20221011_user_contact_links_group_id import Simplex.Chat.Migrations.M20221012_inline_files import Simplex.Chat.Migrations.M20221019_unread_chat import Simplex.Chat.Migrations.M20221021_auto_accept__group_links +import Simplex.Chat.Migrations.M20221024_contact_used import Simplex.Chat.Protocol import Simplex.Chat.Types import Simplex.Messaging.Agent.Protocol (ACorrId, AgentMsgId, ConnId, InvitationId, MsgMeta (..)) @@ -329,7 +331,8 @@ schemaMigrations = ("20221011_user_contact_links_group_id", m20221011_user_contact_links_group_id), ("20221012_inline_files", m20221012_inline_files), ("20221019_unread_chat", m20221019_unread_chat), - ("20221021_auto_accept__group_links", m20221021_auto_accept__group_links) + ("20221021_auto_accept__group_links", m20221021_auto_accept__group_links), + ("20221024_contact_used", m20221024_contact_used) ] -- | The list of migrations in ascending order by date @@ -437,7 +440,7 @@ getConnReqContactXContactId db userId cReqHash = do [sql| SELECT -- Contact - ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, -- Connection 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 @@ -522,7 +525,7 @@ createDirectContact :: DB.Connection -> UserId -> Connection -> Profile -> Excep createDirectContact db userId activeConn@Connection {connId, localAlias} profile = do createdAt <- liftIO getCurrentTime (localDisplayName, contactId, profileId) <- createContact_ db userId connId profile localAlias Nothing createdAt - pure $ Contact {contactId, localDisplayName, profile = toLocalProfile profileId profile localAlias, activeConn, viaGroup = Nothing, chatSettings = defaultChatSettings, createdAt, updatedAt = createdAt} + pure $ Contact {contactId, localDisplayName, profile = toLocalProfile profileId profile localAlias, activeConn, viaGroup = Nothing, contactUsed = False, chatSettings = defaultChatSettings, createdAt, updatedAt = createdAt} createContact_ :: DB.Connection -> UserId -> Int64 -> Profile -> LocalAlias -> Maybe Int64 -> UTCTime -> ExceptT StoreError IO (Text, ContactId, ProfileId) createContact_ db userId connId Profile {displayName, fullName, image} localAlias viaGroup currentTs = @@ -634,13 +637,20 @@ updateContactConnectionAlias db userId conn localAlias = do (localAlias, updatedAt, userId, pccConnId conn) pure (conn :: PendingContactConnection) {localAlias} -updateContactUnreadChat :: DB.Connection -> User -> Int64 -> Bool -> IO () -updateContactUnreadChat db User {userId} contactId unreadChat = - DB.execute db "UPDATE contacts SET unread_chat = ? WHERE user_id = ? AND contact_id = ?" (unreadChat, userId, contactId) +updateContactUsed :: DB.Connection -> User -> Contact -> IO () +updateContactUsed db User {userId} Contact {contactId} = do + updatedAt <- getCurrentTime + DB.execute db "UPDATE contacts SET contact_used = 1, updated_at = ? WHERE user_id = ? AND contact_id = ?" (updatedAt, userId, contactId) -updateGroupUnreadChat :: DB.Connection -> User -> Int64 -> Bool -> IO () -updateGroupUnreadChat db User {userId} groupId unreadChat = - DB.execute db "UPDATE groups SET unread_chat = ? WHERE user_id = ? AND group_id = ?" (unreadChat, userId, groupId) +updateContactUnreadChat :: DB.Connection -> User -> Contact -> Bool -> IO () +updateContactUnreadChat db User {userId} Contact {contactId} unreadChat = do + updatedAt <- getCurrentTime + DB.execute db "UPDATE contacts SET unread_chat = ?, updated_at = ? WHERE user_id = ? AND contact_id = ?" (unreadChat, updatedAt, userId, contactId) + +updateGroupUnreadChat :: DB.Connection -> User -> GroupInfo -> Bool -> IO () +updateGroupUnreadChat db User {userId} GroupInfo {groupId} unreadChat = do + updatedAt <- getCurrentTime + DB.execute db "UPDATE groups SET unread_chat = ?, updated_at = ? WHERE user_id = ? AND group_id = ?" (unreadChat, updatedAt, userId, groupId) updateContactProfile_ :: DB.Connection -> UserId -> ProfileId -> Profile -> IO () updateContactProfile_ db userId profileId profile = do @@ -670,22 +680,22 @@ updateContact_ db userId contactId displayName newName updatedAt = do (newName, updatedAt, userId, contactId) DB.execute db "DELETE FROM display_names WHERE local_display_name = ? AND user_id = ?" (displayName, userId) -type ContactRow = (ContactId, ProfileId, ContactName, Maybe Int64, ContactName, Text, Maybe ImageData, LocalAlias, Maybe Bool, UTCTime, UTCTime) +type ContactRow = (ContactId, ProfileId, ContactName, Maybe Int64, ContactName, Text, Maybe ImageData, LocalAlias, Bool, Maybe Bool, UTCTime, UTCTime) toContact :: ContactRow :. ConnectionRow -> Contact -toContact ((contactId, profileId, localDisplayName, viaGroup, displayName, fullName, image, localAlias, enableNtfs_, createdAt, updatedAt) :. connRow) = +toContact ((contactId, profileId, localDisplayName, viaGroup, displayName, fullName, image, localAlias, contactUsed, enableNtfs_, createdAt, updatedAt) :. connRow) = let profile = LocalProfile {profileId, displayName, fullName, image, localAlias} activeConn = toConnection connRow chatSettings = ChatSettings {enableNtfs = fromMaybe True enableNtfs_} - in Contact {contactId, localDisplayName, profile, activeConn, viaGroup, chatSettings, createdAt, updatedAt} + in Contact {contactId, localDisplayName, profile, activeConn, viaGroup, contactUsed, chatSettings, createdAt, updatedAt} toContactOrError :: ContactRow :. MaybeConnectionRow -> Either StoreError Contact -toContactOrError ((contactId, profileId, localDisplayName, viaGroup, displayName, fullName, image, localAlias, enableNtfs_, createdAt, updatedAt) :. connRow) = +toContactOrError ((contactId, profileId, localDisplayName, viaGroup, displayName, fullName, image, localAlias, contactUsed, enableNtfs_, createdAt, updatedAt) :. connRow) = let profile = LocalProfile {profileId, displayName, fullName, image, localAlias} chatSettings = ChatSettings {enableNtfs = fromMaybe True enableNtfs_} in case toMaybeConnection connRow of Just activeConn -> - Right Contact {contactId, localDisplayName, profile, activeConn, viaGroup, chatSettings, createdAt, updatedAt} + Right Contact {contactId, localDisplayName, profile, activeConn, viaGroup, contactUsed, chatSettings, createdAt, updatedAt} _ -> Left $ SEContactNotReady localDisplayName -- TODO return the last connection that is ready, not any last connection @@ -965,7 +975,7 @@ createOrUpdateContactRequest db userId userContactLinkId invId Profile {displayN [sql| SELECT -- Contact - ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, -- Connection 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 @@ -1090,7 +1100,7 @@ createAcceptedContact db userId agentConnId localDisplayName profileId profile u (userId, localDisplayName, profileId, True, createdAt, createdAt, xContactId) contactId <- insertedRowId db activeConn <- createConnection_ db userId ConnContact (Just contactId) agentConnId Nothing (Just userContactLinkId) customUserProfileId 0 createdAt - pure $ Contact {contactId, localDisplayName, profile = toLocalProfile profileId profile "", activeConn, viaGroup = Nothing, chatSettings = defaultChatSettings, createdAt = createdAt, updatedAt = createdAt} + pure $ Contact {contactId, localDisplayName, profile = toLocalProfile profileId profile "", activeConn, viaGroup = Nothing, contactUsed = False, chatSettings = defaultChatSettings, createdAt = createdAt, updatedAt = createdAt} getLiveSndFileTransfers :: DB.Connection -> User -> IO [SndFileTransfer] getLiveSndFileTransfers db User {userId} = do @@ -1368,17 +1378,17 @@ getConnectionEntity db user@User {userId, userContactId} agentConnId = do <$> DB.query db [sql| - SELECT c.contact_profile_id, c.local_display_name, p.display_name, p.full_name, p.image, p.local_alias, c.via_group, c.enable_ntfs, c.created_at, c.updated_at + SELECT c.contact_profile_id, c.local_display_name, p.display_name, p.full_name, p.image, p.local_alias, c.via_group, c.contact_used, c.enable_ntfs, c.created_at, c.updated_at FROM contacts c JOIN contact_profiles p ON c.contact_profile_id = p.contact_profile_id WHERE c.user_id = ? AND c.contact_id = ? |] (userId, contactId) - toContact' :: Int64 -> Connection -> [(ProfileId, ContactName, Text, Text, Maybe ImageData, LocalAlias, Maybe Int64, Maybe Bool, UTCTime, UTCTime)] -> Either StoreError Contact - toContact' contactId activeConn [(profileId, localDisplayName, displayName, fullName, image, localAlias, viaGroup, enableNtfs_, createdAt, updatedAt)] = + toContact' :: Int64 -> Connection -> [(ProfileId, ContactName, Text, Text, Maybe ImageData, LocalAlias, Maybe Int64, Bool, Maybe Bool, UTCTime, UTCTime)] -> Either StoreError Contact + toContact' contactId activeConn [(profileId, localDisplayName, displayName, fullName, image, localAlias, viaGroup, contactUsed, enableNtfs_, createdAt, updatedAt)] = let profile = LocalProfile {profileId, displayName, fullName, image, localAlias} chatSettings = ChatSettings {enableNtfs = fromMaybe True enableNtfs_} - in Right $ Contact {contactId, localDisplayName, profile, activeConn, viaGroup, chatSettings, createdAt, updatedAt} + in Right $ Contact {contactId, localDisplayName, profile, activeConn, viaGroup, contactUsed, chatSettings, createdAt, updatedAt} toContact' _ _ _ = Left $ SEInternalError "referenced contact not found" getGroupAndMember_ :: Int64 -> Connection -> ExceptT StoreError IO (GroupInfo, GroupMember) getGroupAndMember_ groupMemberId c = ExceptT $ do @@ -1879,7 +1889,7 @@ getContactViaMember db User {userId} GroupMember {groupMemberId} = [sql| SELECT -- Contact - ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, -- Connection 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 @@ -2203,7 +2213,7 @@ getViaGroupContact db User {userId} GroupMember {groupMemberId} = db [sql| SELECT - ct.contact_id, ct.contact_profile_id, ct.local_display_name, p.display_name, p.full_name, p.image, p.local_alias, ct.via_group, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, p.display_name, p.full_name, p.image, p.local_alias, ct.via_group, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, 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 contacts ct @@ -2219,12 +2229,12 @@ getViaGroupContact db User {userId} GroupMember {groupMemberId} = |] (userId, groupMemberId) where - toContact' :: (ContactId, ProfileId, ContactName, Text, Text, Maybe ImageData, LocalAlias, Maybe Int64, Maybe Bool, UTCTime, UTCTime) :. ConnectionRow -> Contact - toContact' ((contactId, profileId, localDisplayName, displayName, fullName, image, localAlias, viaGroup, enableNtfs_, createdAt, updatedAt) :. connRow) = + toContact' :: (ContactId, ProfileId, ContactName, Text, Text, Maybe ImageData, LocalAlias, Maybe Int64, Bool, Maybe Bool, UTCTime, UTCTime) :. ConnectionRow -> Contact + toContact' ((contactId, profileId, localDisplayName, displayName, fullName, image, localAlias, viaGroup, contactUsed, enableNtfs_, createdAt, updatedAt) :. connRow) = let profile = LocalProfile {profileId, displayName, fullName, image, localAlias} chatSettings = ChatSettings {enableNtfs = fromMaybe True enableNtfs_} activeConn = toConnection connRow - in Contact {contactId, localDisplayName, profile, activeConn, viaGroup, chatSettings, createdAt, updatedAt} + in Contact {contactId, localDisplayName, profile, activeConn, viaGroup, contactUsed, chatSettings, createdAt, updatedAt} createSndDirectFileTransfer :: DB.Connection -> UserId -> Contact -> FilePath -> FileInvitation -> Maybe ConnId -> Integer -> IO FileTransferMeta createSndDirectFileTransfer db userId Contact {contactId} filePath FileInvitation {fileName, fileSize, fileInline} acId_ chunkSize = do @@ -3080,7 +3090,7 @@ getDirectChatPreviews_ db User {userId} = do [sql| SELECT -- Contact - ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, -- Connection 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, @@ -3112,7 +3122,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) + 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.connection_id = ( SELECT cc_connection_id FROM ( SELECT @@ -3404,7 +3414,7 @@ getContact db userId contactId = [sql| SELECT -- Contact - ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.enable_ntfs, ct.created_at, ct.updated_at, + ct.contact_id, ct.contact_profile_id, ct.local_display_name, ct.via_group, cp.display_name, cp.full_name, cp.image, cp.local_alias, ct.contact_used, ct.enable_ntfs, ct.created_at, ct.updated_at, -- Connection 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 diff --git a/src/Simplex/Chat/Types.hs b/src/Simplex/Chat/Types.hs index e909be3669..02422af564 100644 --- a/src/Simplex/Chat/Types.hs +++ b/src/Simplex/Chat/Types.hs @@ -81,6 +81,7 @@ data Contact = Contact profile :: LocalProfile, activeConn :: Connection, viaGroup :: Maybe Int64, + contactUsed :: Bool, chatSettings :: ChatSettings, createdAt :: UTCTime, updatedAt :: UTCTime diff --git a/tests/ChatTests.hs b/tests/ChatTests.hs index c3208aaeec..410637b950 100644 --- a/tests/ChatTests.hs +++ b/tests/ChatTests.hs @@ -3323,6 +3323,9 @@ testGroupLink = ] alice #$> ("/_get chat #1 count=100", chat, [(0, "invited via your group link")]) alice @@@ [("#team", "invited via your group link")] -- contacts connected via group link are not in chat previews + -- calling /_get chat api marks it as used and adds it to chat previews + alice #$> ("/_get chat @2 count=100", chat, []) + alice @@@ [("@bob", ""), ("#team", "invited via your group link")] alice <##> bob alice @@@ [("@bob", "hey"), ("#team", "invited via your group link")] bob ##> "/j team" @@ -3355,6 +3358,12 @@ testGroupLink = cath <## "#team: alice_1 invites you to join the group as member" cath <## "use /j team to accept" ] + -- sending message to contact marks it as used + alice @@@ [("@cath", "hey"), ("@bob", "hey"), ("#team", "invited via your group link")] + alice #> "@cath_1 hello" + cath <# "alice_1> hello" + alice #$> ("/clear cath_1", id, "cath_1: all messages are removed locally ONLY") + alice @@@ [("@cath_1", ""), ("@cath", "hey"), ("@bob", "hey"), ("#team", "invited via your group link")] cath ##> "/j team" concurrentlyN_ [ alice <## "#team: cath_1 joined the group",