From fec195fe7bebbd715834ac786c8dc4a13bbbdb69 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Thu, 6 Aug 2026 13:34:37 +0000 Subject: [PATCH] core: don't consume an active order for a user created without activating it createUserRecordAt gates the "UPDATE users SET active_user = 0" on the activeUser argument but called getNextActiveOrder unconditionally, so a profile created with keepActiveUser got active_order = max + 1 despite never having been active. Every picker sorts on that column descending, so the new profile sorted above the profile actually in use - in the Android user picker, which sorts the full list, literally above the active one. active_order means "last activated" and setActiveUser is otherwise its only writer, so a profile that was never activated now keeps 0 and sorts last until it is used. Also asserts in the test that the created user's own record is not active: /u only covers the currentUser TVar, and it is the user record that the clients branch on to detect a core that ignored the flag. Moves the second test to "user profiles", which is what it tests - it has nothing to do with short links. --- src/Simplex/Chat/Store/Profiles.hs | 5 ++++- tests/ChatTests/Profiles.hs | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Simplex/Chat/Store/Profiles.hs b/src/Simplex/Chat/Store/Profiles.hs index ce6a8c4c9f..67acc6ba75 100644 --- a/src/Simplex/Chat/Store/Profiles.hs +++ b/src/Simplex/Chat/Store/Profiles.hs @@ -140,7 +140,10 @@ createUserRecordAt db (AgentUserId auId) userChatRelay clientService Profile {di sendRcptsContacts = True sendRcptsSmallGroups = True autoAcceptMemberContacts = False - order <- getNextActiveOrder db + -- active_order means "last activated", and setActiveUser is otherwise its only + -- writer - so a user created without being activated must not consume an order, + -- or it would sort above the profile that is actually in use. + order <- if activeUser then getNextActiveOrder db else pure 0 DB.execute db "INSERT INTO users (agent_user_id, local_display_name, active_user, is_user_chat_relay, active_order, contact_id, show_ntfs, send_rcpts_contacts, send_rcpts_small_groups, auto_accept_member_contacts, client_service, created_at, updated_at) VALUES (?,?,?,?,?,0,?,?,?,?,?,?,?)" diff --git a/tests/ChatTests/Profiles.hs b/tests/ChatTests/Profiles.hs index 5810417389..fdcf1d4ee8 100644 --- a/tests/ChatTests/Profiles.hs +++ b/tests/ChatTests/Profiles.hs @@ -52,6 +52,7 @@ chatProfileTests = do it "reject profile image that is too large" testSetProfileImageTooLarge it "set profile image from file" testSetProfileImageFromFile it "use multiword profile names" testMultiWordProfileNames + it "create user without keepActiveUser activates it" testCreateUserWithoutKeepActiveUser it "present supporter badge to contacts" testUserBadgeBroadcast it "supporter badge sent to contact connecting after attach" testUserBadgeOnConnect it "supporter badge sent to member joining via group link" testUserBadgeGroupLink @@ -154,7 +155,6 @@ shortLinkTests = do it "change prepared contact user" testShortLinkChangePreparedContactUser it "change prepared contact user, new user has contact with the same name" testShortLinkChangePreparedContactUserDuplicate it "create user keeping active user, then change prepared contact user" testCreateUserKeepingActiveUser - it "create user without keepActiveUser activates it" testCreateUserWithoutKeepActiveUser it "connect to prepared group incognito" testShortLinkConnectPreparedGroupIncognito it "change prepared group user" testShortLinkChangePreparedGroupUser it "change prepared group user, new user has group with the same name" testShortLinkChangePreparedGroupUserDuplicate @@ -4005,6 +4005,11 @@ testCreateUserKeepingActiveUser = testChat2 aliceProfile bobProfile test -- ... and the active user is unchanged, with no switch back needed bob ##> "/u" showActiveUser bob "bob (Bob)" + -- the new user's own record is not active either - the clients branch on this + -- field of the created user, and it is listed last, having never been activated + bob ##> "/users" + bob <## "bob (Bob) (active)" + bob <## "robert" alice ##> "/_connect 1" (shortLink, fullLink) <- getInvitations alice