mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-28 09:59:44 +00:00
core: remove SimpleX Status preset contact (#7231)
* core: remove SimpleX Status preset contact Preset contact cards are only created at user record creation (createPresetContactCards), so this affects new profiles only; existing profiles keep their stored SimpleX Status contact. Removing the card shifts contact ids allocated after /create user down by one, hence the test id updates. * plans: justify SimpleX Status preset contact removal
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# Remove the SimpleX Status preset contact
|
||||
|
||||
Branch: `nd/remove-status-preset-contact` · PR #7231 (supersedes #7200)
|
||||
|
||||
## 1. Problem statement
|
||||
|
||||
Every new profile gets a "SimpleX Status" preset contact card. It is too confusing for non-technical users: it looks like a person or a chat, but it is an automated broadcast bot, and tapping it opens a connect dialog rather than content. On top of that, its stored contact link is the old `simplex:/contact/#/...` invitation address; the intended replacement is a channel, which a preset *contact* card cannot deliver (see §3).
|
||||
|
||||
## 2. Solution summary
|
||||
|
||||
Delete the preset entirely:
|
||||
|
||||
- `simplexStatusContactProfile` removed from `Library/Internal.hs` (14 lines incl. inline logo).
|
||||
- Its `createContact` call removed from `createPresetContactCards` in `Library/Commands.hs` (one line; the "Ask SimpleX Team" preset stays).
|
||||
- Test expectations updated mechanically (see §5).
|
||||
|
||||
No migration for existing profiles: preset cards are only ever created inside user record creation (`APICreateActiveUser` → `createPresetContactCards`), so existing profiles keep their stored card, matching how presets have always behaved. Users can still reach the bot via https://status.simplex.chat and the blog.
|
||||
|
||||
## 3. Why not fix the link instead (the #7200 dead end)
|
||||
|
||||
#7200 swapped the preset's link to a channel link (`https://smp5.simplex.im/c#...`). That cannot work: preset cards are contacts, and tapping one runs `APIConnectContactViaAddress` → `prepareContact`/`joinContact` — the direct-contact handshake. Channel short links (`/c#` decodes to `CCTChannel`) must be joined via `APIConnectPreparedGroup`; `APIConnect` explicitly rejects them ("channel links must be connected via APIConnectPreparedGroup"), but the contact-card path has no such guard and silently performs the wrong handshake. Making the status channel a preset would require a preset *prepared channel* — `APIPrepareGroup` needs a full connReq plus `GroupShortLinkData`, run after the user is active — a substantially larger change than wanted, for a card that confuses the users it is shown to.
|
||||
|
||||
## 4. Scope of effect
|
||||
|
||||
- **New profiles**: get only the "Ask SimpleX Team" card.
|
||||
- **Existing profiles**: unchanged; their stored SimpleX Status contact remains until the user deletes it.
|
||||
- **Discovery**: this removes the status bot's only in-app discovery path for new users — deliberate, since the card was doing more harm (confusion) than good (discovery).
|
||||
|
||||
## 5. Test impact
|
||||
|
||||
Removing the card shifts contact ids allocated after `/create user` down by one:
|
||||
|
||||
- 10 chat-list / `hasContactProfiles` expectations lose the status entry (`Direct.hs`, `Profiles.hs`).
|
||||
- 24 numeric contact refs shift: `@6`→`@5` in `Direct.hs`; `@5`→`@4` and `@6`→`@5` in `Profiles.hs`, plus the id-arithmetic comments.
|
||||
- `configureTimedMessages alice bob "6" "3"` → `"5"` — the contact id travels as a bare string argument, invisible to `@N`-pattern search; caught only by running the tests.
|
||||
|
||||
Verified unaffected: group ids (`#N`), pending-connection ids (`:N` — preset cards create no connection rows), user ids, unread/`/users` counts (cards create no chat items), `MobileTests`/`RemoteTests`/`Local.hs` (harness users bypass presets), display-name allocation (per-user).
|
||||
|
||||
## 6. Verification
|
||||
|
||||
All 8 non-timing-sensitive affected tests pass locally. The 3 TTL/timed-message tests (`testUsersDifferentCIExpirationTTL`, `testUsersRestartCIExpiration`, `testUsersTimedMessages`) fail identically on the base commit `6bb1da9e8` in the same environment — pre-existing cleanup-manager timing flakes (cf. `d7010d527`), not regressions. The packaged desktop build was verified to contain no "SimpleX Status" strings in `libsimplex.so` while retaining "Ask SimpleX Team".
|
||||
@@ -441,7 +441,6 @@ processChatCommand cxt nm = \case
|
||||
where
|
||||
createPresetContactCards :: DB.Connection -> User -> ExceptT StoreError IO ()
|
||||
createPresetContactCards db user = do
|
||||
createContact db cxt user simplexStatusContactProfile
|
||||
createContact db cxt user simplexTeamContactProfile
|
||||
chooseServers :: Maybe User -> CM ([UpdatedUserOperatorServers], (NonEmpty (ServerCfg 'PSMP), NonEmpty (ServerCfg 'PXFTP)))
|
||||
chooseServers user_ = do
|
||||
|
||||
File diff suppressed because one or more lines are too long
+24
-24
@@ -1920,14 +1920,14 @@ testMultipleUserAddresses =
|
||||
cLinkAlisa <- getContactLink alice True
|
||||
bob ##> ("/c " <> cLinkAlisa)
|
||||
alice <#? bob
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", "Audio/video calls: enabled"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", "Audio/video calls: enabled"), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
alice ##> "/ac bob"
|
||||
alice <## "bob (Bob): accepting contact request, you can send messages to contact"
|
||||
concurrently_
|
||||
(bob <## "alisa: contact is connected")
|
||||
(alice <## "bob (Bob): contact is connected")
|
||||
threadDelay 100000
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", lastChatFeature), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@bob", lastChatFeature), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
alice <##> bob
|
||||
|
||||
bob #> "@alice hey alice"
|
||||
@@ -1958,7 +1958,7 @@ testMultipleUserAddresses =
|
||||
(cath <## "alisa: contact is connected")
|
||||
(alice <## "cath (Catherine): contact is connected")
|
||||
threadDelay 100000
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@cath", lastChatFeature), ("@bob", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
alice #$> ("/_get chats 2 pcc=on", chats, [("@cath", lastChatFeature), ("@bob", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
alice <##> cath
|
||||
|
||||
-- first user doesn't have cath as contact
|
||||
@@ -2171,7 +2171,7 @@ testUsersDifferentCIExpirationTTL ps = do
|
||||
bob #> "@alisa alisa 4"
|
||||
alice <# "bob> alisa 4"
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 3000000
|
||||
|
||||
@@ -2184,11 +2184,11 @@ testUsersDifferentCIExpirationTTL ps = do
|
||||
-- second user messages
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 2100000
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
where
|
||||
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
|
||||
|
||||
@@ -2254,7 +2254,7 @@ testUsersRestartCIExpiration ps = do
|
||||
bob #> "@alisa alisa 4"
|
||||
alice <# "bob> alisa 4"
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 3000000
|
||||
|
||||
@@ -2267,11 +2267,11 @@ testUsersRestartCIExpiration ps = do
|
||||
-- second user messages
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 4000000
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
where
|
||||
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
|
||||
|
||||
@@ -2313,7 +2313,7 @@ testEnableCIExpirationOnlyForOneUser ps = do
|
||||
bob #> "@alisa alisa 4"
|
||||
alice <# "bob> alisa 4"
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 2000000
|
||||
|
||||
@@ -2325,14 +2325,14 @@ testEnableCIExpirationOnlyForOneUser ps = do
|
||||
-- messages are not deleted for second user
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
withTestChatCfg ps cfg "alice" $ \alice -> do
|
||||
alice <## "subscribed 1 connections on server localhost"
|
||||
alice <## "subscribed 1 connections on server localhost"
|
||||
|
||||
-- messages are not deleted for second user after restart
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
alice #> "@bob alisa 5"
|
||||
bob <# "alisa> alisa 5"
|
||||
@@ -2342,7 +2342,7 @@ testEnableCIExpirationOnlyForOneUser ps = do
|
||||
threadDelay 2000000
|
||||
|
||||
-- new messages are not deleted for second user
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4"), (1, "alisa 5"), (0, "alisa 6")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2"), (1, "alisa 3"), (0, "alisa 4"), (1, "alisa 5"), (0, "alisa 6")])
|
||||
where
|
||||
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
|
||||
|
||||
@@ -2376,12 +2376,12 @@ testDisableCIExpirationOnlyForOneUser ps = do
|
||||
bob #> "@alisa alisa 2"
|
||||
alice <# "bob> alisa 2"
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, chatFeatures <> [(1, "alisa 1"), (0, "alisa 2")])
|
||||
|
||||
threadDelay 2000000
|
||||
|
||||
-- second user messages are deleted
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
|
||||
withTestChatCfg ps cfg "alice" $ \alice -> do
|
||||
alice <## "subscribed 1 connections on server localhost"
|
||||
@@ -2395,12 +2395,12 @@ testDisableCIExpirationOnlyForOneUser ps = do
|
||||
bob #> "@alisa alisa 4"
|
||||
alice <# "bob> alisa 4"
|
||||
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 3000000
|
||||
|
||||
-- second user messages are deleted
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
where
|
||||
cfg = testCfg {initialCleanupManagerDelay = 0, cleanupManagerStepDelay = 0, ciExpirationInterval = 500000}
|
||||
|
||||
@@ -2415,7 +2415,7 @@ testUsersTimedMessages ps' = do
|
||||
alice ##> "/create user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
connectUsers alice bob
|
||||
configureTimedMessages alice bob "6" "3"
|
||||
configureTimedMessages alice bob "5" "3"
|
||||
|
||||
-- first user messages
|
||||
alice ##> "/user alice"
|
||||
@@ -2444,7 +2444,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
|
||||
|
||||
threadDelay 1000000
|
||||
|
||||
@@ -2457,7 +2457,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 1"), (0, "alisa 2")])
|
||||
|
||||
threadDelay 1000000
|
||||
|
||||
@@ -2466,7 +2466,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
|
||||
-- first user messages
|
||||
alice ##> "/user alice"
|
||||
@@ -2496,7 +2496,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
-- messages are deleted after restart
|
||||
threadDelay 1000000
|
||||
@@ -2510,7 +2510,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user alisa"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner"), (1, "alisa 3"), (0, "alisa 4")])
|
||||
|
||||
threadDelay 1000000
|
||||
|
||||
@@ -2519,7 +2519,7 @@ testUsersTimedMessages ps' = do
|
||||
|
||||
alice ##> "/user"
|
||||
showActiveUser alice "alisa"
|
||||
alice #$> ("/_get chat @6 count=100", chat, [(1,"chat banner")])
|
||||
alice #$> ("/_get chat @5 count=100", chat, [(1,"chat banner")])
|
||||
where
|
||||
ps = ps' {printOutput = True} :: TestParams
|
||||
configureTimedMessages :: HasCallStack => TestCC -> TestCC -> String -> String -> IO ()
|
||||
|
||||
+14
-14
@@ -3934,14 +3934,14 @@ testShortLinkChangePreparedContactUser = testChat2 aliceProfile bobProfile test
|
||||
bob ##> ("/_prepare contact 1 " <> fullLink <> " " <> shortLink <> " " <> contactSLinkData)
|
||||
bob <## "alice: contact is prepared"
|
||||
|
||||
-- 2 ids are for "user contacts", 2 ids are for second user contact cards, so alice is id 5
|
||||
bob ##> "/_set contact user @5 2"
|
||||
-- 2 ids are for "user contacts", 1 id is for second user contact card, so alice is id 4
|
||||
bob ##> "/_set contact user @4 2"
|
||||
bob <## "contact alice changed from user bob to user robert"
|
||||
|
||||
bob ##> "/user robert"
|
||||
showActiveUser bob "robert"
|
||||
|
||||
bob ##> "/_connect contact @5 text hello"
|
||||
bob ##> "/_connect contact @4 text hello"
|
||||
bob
|
||||
<### [ "alice: connection started",
|
||||
WithTime "@alice hello"
|
||||
@@ -3955,8 +3955,8 @@ testShortLinkChangePreparedContactUser = testChat2 aliceProfile bobProfile test
|
||||
|
||||
alice @@@ [("@robert", "hey")]
|
||||
alice `hasContactProfiles` ["alice", "robert"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "Ask SimpleX Team", "SimpleX Status"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "Ask SimpleX Team"]
|
||||
bob ##> "/user bob"
|
||||
showActiveUser bob "bob (Bob)"
|
||||
bob @@@ []
|
||||
@@ -3984,16 +3984,16 @@ testShortLinkChangePreparedContactUserDuplicate = testChat2 aliceProfile bobProf
|
||||
bob <## "alice: contact is prepared"
|
||||
|
||||
-- 2 ids are for "user contacts"
|
||||
-- 2 ids are for second user contact cards
|
||||
-- 1 id is for second user contact card
|
||||
-- 1 for second user's alice
|
||||
-- so this alice is id 6
|
||||
bob ##> "/_set contact user @6 2"
|
||||
-- so this alice is id 5
|
||||
bob ##> "/_set contact user @5 2"
|
||||
bob <## "contact alice changed from user bob to user robert, new local name: alice_1"
|
||||
|
||||
bob ##> "/user robert"
|
||||
showActiveUser bob "robert"
|
||||
|
||||
bob ##> "/_connect contact @6 text hello"
|
||||
bob ##> "/_connect contact @5 text hello"
|
||||
bob
|
||||
<### [ "alice_1: connection started",
|
||||
WithTime "@alice_1 hello"
|
||||
@@ -4012,8 +4012,8 @@ testShortLinkChangePreparedContactUserDuplicate = testChat2 aliceProfile bobProf
|
||||
|
||||
alice @@@ [("@robert", "hey"), ("@robert_1", "hey")]
|
||||
alice `hasContactProfiles` ["alice", "robert", "robert"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@alice_1", "hey"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "alice", "Ask SimpleX Team", "SimpleX Status"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("@alice", "hey"), ("@alice_1", "hey"), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "alice", "Ask SimpleX Team"]
|
||||
bob ##> "/user bob"
|
||||
showActiveUser bob "bob (Bob)"
|
||||
bob @@@ []
|
||||
@@ -4106,8 +4106,8 @@ testShortLinkChangePreparedGroupUser = testChat3 aliceProfile bobProfile cathPro
|
||||
|
||||
alice @@@ [("#team", "3"), ("@cath","sent invitation to join group team as admin")]
|
||||
alice `hasContactProfiles` ["alice", "cath", "robert"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("#team", "3"), ("@Ask SimpleX Team", ""), ("@SimpleX Status", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "cath", "Ask SimpleX Team", "SimpleX Status"]
|
||||
bob #$> ("/_get chats 2 pcc=on", chats, [("#team", "3"), ("@Ask SimpleX Team", ""), ("*", "")])
|
||||
bob `hasContactProfiles` ["robert", "alice", "cath", "Ask SimpleX Team"]
|
||||
cath @@@ [("#team", "3"), ("@alice","received invitation to join group team as admin")]
|
||||
cath `hasContactProfiles` ["cath", "alice", "robert"]
|
||||
bob ##> "/user bob"
|
||||
@@ -4220,7 +4220,7 @@ testShortLinkChangePreparedGroupUserDuplicate = testChat3 aliceProfile bobProfil
|
||||
|
||||
alice @@@ [("#team", "7"), ("@cath","sent invitation to join group team as admin")]
|
||||
alice `hasContactProfiles` ["alice", "cath", "robert", "robert"]
|
||||
bob `hasContactProfiles` ["robert", "robert", "robert", "alice", "alice", "cath", "cath", "Ask SimpleX Team", "SimpleX Status"]
|
||||
bob `hasContactProfiles` ["robert", "robert", "robert", "alice", "alice", "cath", "cath", "Ask SimpleX Team"]
|
||||
cath @@@ [("#team", "7"), ("@alice","received invitation to join group team as admin")]
|
||||
cath `hasContactProfiles` ["cath", "alice", "robert", "robert"]
|
||||
bob ##> "/user bob"
|
||||
|
||||
Reference in New Issue
Block a user