diff --git a/scripts/flatpak/chat.simplex.simplex.metainfo.xml b/scripts/flatpak/chat.simplex.simplex.metainfo.xml index e56ab82d2b..2ff17a6ddf 100644 --- a/scripts/flatpak/chat.simplex.simplex.metainfo.xml +++ b/scripts/flatpak/chat.simplex.simplex.metainfo.xml @@ -38,6 +38,34 @@ + + https://simplex.chat/blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.html + +

New in v6.3.1-6:

+
    +
  • forward compatibility with short link data.
  • +
  • fixes
  • +
  • fixes mentions with trailing punctuation (e.g., hello @name!).
  • +
  • recognizes domain names as links (e.g., simplex.chat).
  • +
  • forward compatibility with "knocking" (a feature for group admins to review and to chat with the new members prior to admitting them to groups, it will be released in 6.4)
  • +
  • support for connecting via short connection links.
  • +
  • fix related to backward/forward compatibility of the app in some rare cases.
  • +
  • scrolling/navigation improvements.
  • +
  • faster onboarding (conditions and operators are combined to one screen).
  • +
+

New in v6.3.0:

+
    +
  • Mention members and get notified when mentioned.
  • +
  • Send private reports to moderators.
  • +
  • Delete, block and change role for multiple members at once
  • +
  • Faster sending messages and faster deletion.
  • +
  • Organize chats into lists to keep track of what's important.
  • +
  • Jump to found and forwarded messages.
  • +
  • Private media file names.
  • +
  • Message expiration in chats.
  • +
+
+
https://simplex.chat/blog/20250308-simplex-chat-v6-3-new-user-experience-safety-in-public-groups.html diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index 0e1a26987d..91e36375ab 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1708,33 +1708,17 @@ processChatCommand' vr = \case conn <- withFastStore $ \db -> getPendingContactConnection db userId connId let PendingContactConnection {pccConnStatus, connLinkInv} = conn case (pccConnStatus, connLinkInv) of - (ConnNew, Just (CCLink cReqInv _)) -> do + (ConnNew, Just _ссLink) -> do newUser <- privateGetUser newUserId - conn' <- ifM (canKeepLink cReqInv newUser) (updateConn user conn newUser) (recreateConn user conn newUser) + conn' <- recreateConn user conn newUser pure $ CRConnectionUserChanged user conn conn' newUser _ -> throwChatError CEConnectionUserChangeProhibited where - canKeepLink :: ConnReqInvitation -> User -> CM Bool - canKeepLink (CRInvitationUri crData _) newUser = do - let ConnReqUriData {crSmpQueues = q :| _} = crData - SMPQueueUri {queueAddress = SMPQueueAddress {smpServer}} = q - newUserServers <- - map protoServer' . L.filter (\ServerCfg {enabled} -> enabled) - <$> getKnownAgentServers SPSMP newUser - pure $ smpServer `elem` newUserServers - updateConn user@User {userId} conn@PendingContactConnection {customUserProfileId} newUser = do - withAgent $ \a -> changeConnectionUser a (aUserId user) (aConnId' conn) (aUserId newUser) - sLnk <- updatePCCShortLinkData conn $ userProfileToSend newUser Nothing Nothing False - withFastStore' $ \db -> do - conn' <- updatePCCUser db userId conn newUserId sLnk - forM_ customUserProfileId $ \profileId -> - deletePCCIncognitoProfile db user profileId - pure conn' recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do subMode <- chatReadVar subscriptionMode let short = isJust $ connShortLink =<< connLinkInv userData - | short = Just $ shortLinkUserData $ userProfileToSend user Nothing Nothing False + | short = Just $ shortLinkUserData $ userProfileToSend newUser Nothing Nothing False | otherwise = Nothing -- TODO [certs rcv] (agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData Nothing IKPQOn subMode diff --git a/src/Simplex/Chat/Store/Direct.hs b/src/Simplex/Chat/Store/Direct.hs index da83c89a0f..12940cf79b 100644 --- a/src/Simplex/Chat/Store/Direct.hs +++ b/src/Simplex/Chat/Store/Direct.hs @@ -71,7 +71,6 @@ module Simplex.Chat.Store.Direct updateContactAccepted, getUserByContactRequestId, getPendingContactConnections, - updatePCCUser, getContactConnections, getConnectionById, getConnectionsContacts, @@ -519,23 +518,6 @@ updatePCCIncognito db User {userId} conn@PendingContactConnection {connLinkInv} Just (CCLink cReq _) -> Just (CCLink cReq sLnk) Nothing -> Nothing -updatePCCUser :: DB.Connection -> UserId -> PendingContactConnection -> UserId -> Maybe ShortLinkInvitation -> IO PendingContactConnection -updatePCCUser db userId conn@PendingContactConnection {connLinkInv} newUserId sLnk = do - updatedAt <- getCurrentTime - DB.execute - db - [sql| - UPDATE connections - SET user_id = ?, short_link_inv = ?, custom_user_profile_id = NULL, updated_at = ? - WHERE user_id = ? AND connection_id = ? - |] - (newUserId, sLnk, updatedAt, userId, pccConnId conn) - pure (conn :: PendingContactConnection) {customUserProfileId = Nothing, connLinkInv = connLinkInv', updatedAt} - where - connLinkInv' = case connLinkInv of - Just (CCLink cReq _) -> Just (CCLink cReq sLnk) - Nothing -> Nothing - deletePCCIncognitoProfile :: DB.Connection -> User -> ProfileId -> IO () deletePCCIncognitoProfile db User {userId} profileId = DB.execute diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt index 13215dcb75..a85ba4a4cb 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/agent_query_plans.txt @@ -1071,10 +1071,6 @@ Query: UPDATE connections SET smp_agent_version = ? WHERE conn_id = ? Plan: SEARCH connections USING PRIMARY KEY (conn_id=?) -Query: UPDATE connections SET user_id = ? WHERE conn_id = ? and user_id = ? -Plan: -SEARCH connections USING PRIMARY KEY (conn_id=?) - Query: UPDATE messages SET msg_body = x'' WHERE conn_id = ? AND internal_id = ? Plan: SEARCH messages USING PRIMARY KEY (conn_id=? AND internal_id=?) diff --git a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt index 1dd18970cd..54f73be851 100644 --- a/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt +++ b/src/Simplex/Chat/Store/SQLite/Migrations/chat_query_plans.txt @@ -4400,14 +4400,6 @@ Query: Plan: SEARCH connections USING INTEGER PRIMARY KEY (rowid=?) -Query: - UPDATE connections - SET user_id = ?, short_link_inv = ?, custom_user_profile_id = NULL, updated_at = ? - WHERE user_id = ? AND connection_id = ? - -Plan: -SEARCH connections USING INTEGER PRIMARY KEY (rowid=?) - Query: UPDATE contact_profiles SET contact_link = ?, updated_at = ? diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 4d5e22e427..c1009c97d0 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -1817,10 +1817,9 @@ viewConnectionIncognitoUpdated PendingContactConnection {pccConnId, customUserPr | otherwise = ["connection " <> sShow pccConnId <> " changed to non incognito"] viewConnectionUserChanged :: User -> PendingContactConnection -> User -> PendingContactConnection -> [StyledString] -viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection {pccConnId, connLinkInv} User {localDisplayName = n'} PendingContactConnection {connLinkInv = connLinkInv'} = - case (connLinkInv, connLinkInv') of - (Just ccLink, Just ccLink') - | ccLink /= ccLink' -> [userChangedStr <> ", new link:"] <> newLink ccLink' +viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection {pccConnId} User {localDisplayName = n'} PendingContactConnection {connLinkInv = connLinkInv'} = + case connLinkInv' of + Just ccLink' -> [userChangedStr <> ", new link:"] <> newLink ccLink' _ -> [userChangedStr] where userChangedStr = "connection " <> sShow pccConnId <> " changed from user " <> plain n <> " to user " <> plain n' @@ -1829,7 +1828,13 @@ viewConnectionUserChanged User {localDisplayName = n} PendingContactConnection { plain $ maybe cReqStr strEncode shortLink, "" ] - <> ["The invitation link for old clients: " <> plain cReqStr | isJust shortLink] + <> + if isJust shortLink + then + [ "The invitation link for old clients:", + plain cReqStr + ] + else [] where cReqStr = strEncode $ simplexChatInvitation cReq diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index b427980d46..8a6f91204e 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -1855,7 +1855,7 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice -- Create new user and go back to original user alice ##> "/create user alisa" showActiveUser alice "alisa" @@ -1865,12 +1865,18 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + _ <- getTermLine alice + alice <## "" alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection back to other user alice ##> "/_set conn user :1 3" - alice <## "connection 1 changed from user alisa to user alisa2" + alice <## "connection 1 changed from user alisa to user alisa2, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alisa2" showActiveUser alice "alisa2" -- Connect @@ -1879,13 +1885,14 @@ testChangePCCUser = testChat2 aliceProfile bobProfile $ concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alisa2: contact is connected") + alice <##> bob testChangePCCUserFromIncognito :: HasCallStack => TestParams -> IO () testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite and set as incognito alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice alice ##> "/_set incognito :1 on" _ <- getTermLine alice alice <## "connection 1 changed to incognito" @@ -1896,13 +1903,19 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + _ <- getTermLine alice + alice <## "" alice `hasContactProfiles` ["alice"] alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection back to initial user alice ##> "/_set conn user :1 1" - alice <## "connection 1 changed from user alisa to user alice" + alice <## "connection 1 changed from user alisa to user alice, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alice" showActiveUser alice "alice (Alice)" -- Connect @@ -1911,13 +1924,14 @@ testChangePCCUserFromIncognito = testChat2 aliceProfile bobProfile $ concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alice (Alice): contact is connected") + alice <##> bob testChangePCCUserAndThenIncognito :: HasCallStack => TestParams -> IO () testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ \alice bob -> do -- Create a new invite and set as incognito alice ##> "/connect" - inv <- getInvitation alice + _ <- getInvitation alice -- Create new user and go back to original user alice ##> "/create user alisa" showActiveUser alice "alisa" @@ -1925,7 +1939,10 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ showActiveUser alice "alice (Alice)" -- Change connection to newly created user alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + inv <- getTermLine alice + alice <## "" alice ##> "/user alisa" showActiveUser alice "alisa" -- Change connection to incognito and make sure it's attached to the newly created user profile @@ -1941,6 +1958,10 @@ testChangePCCUserAndThenIncognito = testChat2 aliceProfile bobProfile $ alice <## ("bob (Bob): contact is connected, your incognito profile for this contact is " <> alisaIncognito) alice <## ("use /i bob to print out this incognito profile again") ] + alice ?#> "@bob hi" + bob <# (alisaIncognito <> "> hi") + bob #> ("@" <> alisaIncognito <> " hey") + alice ?<# "bob> hey" testChangePCCUserDiffSrv :: HasCallStack => TestParams -> IO () testChangePCCUserDiffSrv ps = do @@ -1982,6 +2003,7 @@ testChangePCCUserDiffSrv ps = do concurrently_ (alice <## "bob (Bob): contact is connected") (bob <## "alisa: contact is connected") + alice <##> bob where serverCfg' = smpServerCfg @@ -3235,10 +3257,15 @@ testShortLinkInvitationChangeUser = showActiveUser alice "alice (Alice)" alice ##> "/_connect 1 short=on" - (shortLink, fullLink) <- getShortInvitation alice + _ <- getShortInvitation alice alice ##> "/_set conn user :1 2" - alice <## "connection 1 changed from user alice to user alisa" + alice <## "connection 1 changed from user alice to user alisa, new link:" + alice <## "" + shortLink <- getTermLine alice + alice <## "" + alice <## "The invitation link for old clients:" + fullLink <- getTermLine alice alice ##> "/user alisa" showActiveUser alice "alisa" @@ -3252,12 +3279,11 @@ testShortLinkInvitationChangeUser = <### [ "alisa: connection started", WithTime "@alisa hello" ] - -- TODO [short links] - -- alice <# "bob> hello" + alice <# "bob> hello" concurrently_ (bob <## "alisa: contact is connected") (alice <## "bob (Bob): contact is connected") - -- alice <##> bob + alice <##> bob testShortLinkAddressChangeProfile :: HasCallStack => TestParams -> IO () testShortLinkAddressChangeProfile =