mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-26 10:58:02 +00:00
core, ui: create all links with short links, config parameter to use large link data, use short link as address in user profile (#5991)
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
This commit is contained in:
@@ -55,14 +55,15 @@ initializeBotAddress' logAddress cc = do
|
||||
Left (ChatErrorStore SEUserContactLinkNotFound) -> do
|
||||
when logAddress $ putStrLn "No bot address, creating..."
|
||||
-- TODO [short links] create short link by default
|
||||
sendChatCmd cc (CreateMyAddress False) >>= \case
|
||||
sendChatCmd cc CreateMyAddress >>= \case
|
||||
Right (CRUserContactLinkCreated _ ccLink) -> showBotAddress ccLink
|
||||
_ -> putStrLn "can't create bot address" >> exitFailure
|
||||
_ -> putStrLn "unexpected response" >> exitFailure
|
||||
where
|
||||
showBotAddress (CCLink uri shortUri) = do
|
||||
when logAddress $ putStrLn $ "Bot's contact address is: " <> B.unpack (maybe (strEncode uri) strEncode shortUri)
|
||||
when (isJust shortUri) $ putStrLn $ "Full contact address for old clients: " <> B.unpack (strEncode uri)
|
||||
when logAddress $ do
|
||||
putStrLn $ "Bot's contact address is: " <> B.unpack (maybe (strEncode uri) strEncode shortUri)
|
||||
when (isJust shortUri) $ putStrLn $ "Full contact address for old clients: " <> B.unpack (strEncode uri)
|
||||
void $ sendChatCmd cc $ AddressAutoAccept $ Just AutoAccept {businessAddress = False, acceptIncognito = False, autoReply = Nothing}
|
||||
|
||||
sendMessage :: ChatController -> Contact -> Text -> IO ()
|
||||
|
||||
@@ -249,7 +249,8 @@ data ChatController = ChatController
|
||||
tempDirectory :: TVar (Maybe FilePath),
|
||||
assetsDirectory :: TVar (Maybe FilePath),
|
||||
logFilePath :: Maybe FilePath,
|
||||
contactMergeEnabled :: TVar Bool
|
||||
contactMergeEnabled :: TVar Bool,
|
||||
useLargeLinkData :: TVar Bool
|
||||
}
|
||||
|
||||
data HelpSection = HSMain | HSFiles | HSGroups | HSContacts | HSMyAddress | HSIncognito | HSMarkdown | HSMessages | HSRemote | HSSettings | HSDatabase
|
||||
@@ -276,7 +277,7 @@ data ChatCommand
|
||||
| UnmuteUser
|
||||
| APIDeleteUser UserId Bool (Maybe UserPwd)
|
||||
| DeleteUser UserName Bool (Maybe UserPwd)
|
||||
| StartChat {mainApp :: Bool, enableSndFiles :: Bool} -- enableSndFiles has no effect when mainApp is True
|
||||
| StartChat {mainApp :: Bool, enableSndFiles :: Bool, largeLinkData :: Bool} -- enableSndFiles has no effect when mainApp is True
|
||||
| CheckChatRunning
|
||||
| APIStopChat
|
||||
| APIActivateChat {restoreChat :: Bool}
|
||||
@@ -369,7 +370,7 @@ data ChatCommand
|
||||
-- | APIDeleteGroupConversations GroupId (NonEmpty GroupConversationId)
|
||||
-- | APIArchiveGroupConversations GroupId (NonEmpty GroupConversationId)
|
||||
| APIUpdateGroupProfile GroupId GroupProfile
|
||||
| APICreateGroupLink GroupId GroupMemberRole CreateShortLink
|
||||
| APICreateGroupLink GroupId GroupMemberRole
|
||||
| APIGroupLinkMemberRole GroupId GroupMemberRole
|
||||
| APIDeleteGroupLink GroupId
|
||||
| APIGetGroupLink GroupId
|
||||
@@ -443,8 +444,8 @@ data ChatCommand
|
||||
| EnableGroupMember GroupName ContactName
|
||||
| ChatHelp HelpSection
|
||||
| Welcome
|
||||
| APIAddContact UserId CreateShortLink IncognitoEnabled
|
||||
| AddContact CreateShortLink IncognitoEnabled
|
||||
| APIAddContact UserId IncognitoEnabled
|
||||
| AddContact IncognitoEnabled
|
||||
| APISetConnectionIncognito Int64 IncognitoEnabled
|
||||
| APIChangeConnectionUser Int64 UserId -- new user id to switch connection to
|
||||
| APIConnectPlan UserId AConnectionLink
|
||||
@@ -462,8 +463,8 @@ data ChatCommand
|
||||
| ClearContact ContactName
|
||||
| APIListContacts UserId
|
||||
| ListContacts
|
||||
| APICreateMyAddress UserId CreateShortLink
|
||||
| CreateMyAddress CreateShortLink
|
||||
| APICreateMyAddress UserId
|
||||
| CreateMyAddress
|
||||
| APIDeleteMyAddress UserId
|
||||
| DeleteMyAddress
|
||||
| APIShowMyAddress UserId
|
||||
@@ -507,7 +508,7 @@ data ChatCommand
|
||||
| ShowGroupProfile GroupName
|
||||
| UpdateGroupDescription GroupName (Maybe Text)
|
||||
| ShowGroupDescription GroupName
|
||||
| CreateGroupLink GroupName GroupMemberRole CreateShortLink
|
||||
| CreateGroupLink GroupName GroupMemberRole
|
||||
| GroupLinkMemberRole GroupName GroupMemberRole
|
||||
| DeleteGroupLink GroupName
|
||||
| ShowGroupLink GroupName
|
||||
|
||||
@@ -413,7 +413,8 @@ processChatCommand' vr = \case
|
||||
checkDeleteChatUser user'
|
||||
withChatLock "deleteUser" . procCmd $ deleteChatUser user' delSMPQueues
|
||||
DeleteUser uName delSMPQueues viewPwd_ -> withUserName uName $ \userId -> APIDeleteUser userId delSMPQueues viewPwd_
|
||||
StartChat {mainApp, enableSndFiles} -> withUser' $ \_ ->
|
||||
StartChat {mainApp, enableSndFiles, largeLinkData} -> withUser' $ \_ -> do
|
||||
chatWriteVar useLargeLinkData largeLinkData
|
||||
asks agentAsync >>= readTVarIO >>= \case
|
||||
Just _ -> pure CRChatRunning
|
||||
_ -> checkStoreNotChanged . lift $ startChatController mainApp enableSndFiles $> CRChatStarted
|
||||
@@ -1671,21 +1672,19 @@ processChatCommand' vr = \case
|
||||
EnableGroupMember gName mName -> withMemberName gName mName $ \gId mId -> APIEnableGroupMember gId mId
|
||||
ChatHelp section -> pure $ CRChatHelp section
|
||||
Welcome -> withUser $ pure . CRWelcome
|
||||
APIAddContact userId short incognito -> withUserId userId $ \user -> procCmd $ do
|
||||
APIAddContact userId incognito -> withUserId userId $ \user -> procCmd $ do
|
||||
-- [incognito] generate profile for connection
|
||||
incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let userData
|
||||
| short = Just $ shortLinkUserData $ userProfileToSend user incognitoProfile Nothing False
|
||||
| otherwise = Nothing
|
||||
userData <- contactShortLinkData (userProfileToSend user incognitoProfile Nothing False) Nothing
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation userData Nothing IKPQOn subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMInvitation (Just userData) Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
-- TODO PQ pass minVersion from the current range
|
||||
conn <- withFastStore' $ \db -> createDirectConnection db user connId ccLink' Nothing ConnNew incognitoProfile subMode initialChatVersion PQSupportOn
|
||||
pure $ CRInvitation user ccLink' conn
|
||||
AddContact short incognito -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APIAddContact userId short incognito
|
||||
AddContact incognito -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APIAddContact userId incognito
|
||||
APISetConnectionIncognito connId incognito -> withUser $ \user@User {userId} -> do
|
||||
conn <- withFastStore $ \db -> getPendingContactConnection db userId connId
|
||||
let PendingContactConnection {pccConnStatus, customUserProfileId} = conn
|
||||
@@ -1717,11 +1716,12 @@ processChatCommand' vr = \case
|
||||
recreateConn user conn@PendingContactConnection {customUserProfileId, connLinkInv} newUser = do
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let short = isJust $ connShortLink =<< connLinkInv
|
||||
userData
|
||||
| short = Just $ shortLinkUserData $ userProfileToSend newUser Nothing Nothing False
|
||||
| otherwise = Nothing
|
||||
userData_ <-
|
||||
if short
|
||||
then Just <$> contactShortLinkData (userProfileToSend newUser Nothing Nothing False) Nothing
|
||||
else pure Nothing
|
||||
-- TODO [certs rcv]
|
||||
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData Nothing IKPQOn subMode
|
||||
(agConnId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId newUser) True SCMInvitation userData_ Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
conn' <- withFastStore' $ \db -> do
|
||||
deleteConnectionRecord db user connId
|
||||
@@ -1824,18 +1824,16 @@ processChatCommand' vr = \case
|
||||
CRContactsList user <$> withFastStore' (\db -> getUserContacts db vr user)
|
||||
ListContacts -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APIListContacts userId
|
||||
APICreateMyAddress userId short -> withUserId userId $ \user -> procCmd $ do
|
||||
APICreateMyAddress userId -> withUserId userId $ \user -> procCmd $ do
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let userData
|
||||
| short = Just $ shortLinkUserData $ userProfileToSend user Nothing Nothing False
|
||||
| otherwise = Nothing
|
||||
userData <- contactShortLinkData (userProfileToSend user Nothing Nothing False) Nothing
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData Nothing IKPQOn subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact (Just userData) Nothing IKPQOn subMode
|
||||
ccLink' <- shortenCreatedLink ccLink
|
||||
withFastStore $ \db -> createUserContactLink db user connId ccLink' short subMode
|
||||
withFastStore $ \db -> createUserContactLink db user connId ccLink' subMode
|
||||
pure $ CRUserContactLinkCreated user ccLink'
|
||||
CreateMyAddress short -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APICreateMyAddress userId short
|
||||
CreateMyAddress -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APICreateMyAddress userId
|
||||
APIDeleteMyAddress userId -> withUserId userId $ \user@User {profile = p} -> do
|
||||
conn <- withFastStore $ \db -> getUserAddressConnection db vr user
|
||||
withChatLock "deleteMyAddress" $ do
|
||||
@@ -1860,9 +1858,9 @@ processChatCommand' vr = \case
|
||||
let p' = (fromLocalProfile p :: Profile) {contactLink = Nothing}
|
||||
updateProfile_ user p' True $ withFastStore' $ \db -> setUserProfileContactLink db user Nothing
|
||||
APISetProfileAddress userId True -> withUserId userId $ \user@User {profile = p} -> do
|
||||
ucl@UserContactLink {connLinkContact = CCLink cReq _} <- withFastStore (`getUserAddress` user)
|
||||
ucl <- withFastStore (`getUserAddress` user)
|
||||
-- TODO [short links] replace with short links
|
||||
let p' = (fromLocalProfile p :: Profile) {contactLink = Just $ CLFull cReq}
|
||||
let p' = (fromLocalProfile p :: Profile) {contactLink = Just $ profileContactLink ucl}
|
||||
updateProfile_ user p' True $ withFastStore' $ \db -> setUserProfileContactLink db user $ Just ucl
|
||||
SetProfileAddress onOff -> withUser $ \User {userId} ->
|
||||
processChatCommand $ APISetProfileAddress userId onOff
|
||||
@@ -2435,20 +2433,18 @@ processChatCommand' vr = \case
|
||||
updateGroupProfileByName gName $ \p -> p {description}
|
||||
ShowGroupDescription gName -> withUser $ \user ->
|
||||
CRGroupDescription user <$> withFastStore (\db -> getGroupInfoByName db vr user gName)
|
||||
APICreateGroupLink groupId mRole short -> withUser $ \user -> withGroupLock "createGroupLink" groupId $ do
|
||||
APICreateGroupLink groupId mRole -> withUser $ \user -> withGroupLock "createGroupLink" groupId $ do
|
||||
gInfo@GroupInfo {groupProfile} <- withFastStore $ \db -> getGroupInfo db vr user groupId
|
||||
assertUserGroupRole gInfo GRAdmin
|
||||
when (mRole > GRMember) $ throwChatError $ CEGroupMemberInitialRole gInfo mRole
|
||||
groupLinkId <- GroupLinkId <$> drgRandomBytes 16
|
||||
subMode <- chatReadVar subscriptionMode
|
||||
let userData
|
||||
| short = Just $ UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile
|
||||
| otherwise = Nothing
|
||||
crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
userData <- groupShortLinkData groupProfile
|
||||
let crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
-- TODO [certs rcv]
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact userData (Just crClientData) IKPQOff subMode
|
||||
(connId, (ccLink, _serviceId)) <- withAgent $ \a -> createConnection a (aUserId user) True SCMContact (Just userData) (Just crClientData) IKPQOff subMode
|
||||
ccLink' <- createdGroupLink <$> shortenCreatedLink ccLink
|
||||
gLink <- withFastStore $ \db -> createGroupLink db user gInfo connId ccLink' groupLinkId mRole short subMode
|
||||
gLink <- withFastStore $ \db -> createGroupLink db user gInfo connId ccLink' groupLinkId mRole subMode
|
||||
pure $ CRGroupLinkCreated user gInfo gLink
|
||||
APIGroupLinkMemberRole groupId mRole' -> withUser $ \user -> withGroupLock "groupLinkMemberRole" groupId $ do
|
||||
gInfo <- withFastStore $ \db -> getGroupInfo db vr user groupId
|
||||
@@ -2507,9 +2503,9 @@ processChatCommand' vr = \case
|
||||
toView $ CEvtNewChatItems user [AChatItem SCTDirect SMDSnd (DirectChat ct') ci]
|
||||
pure $ CRNewMemberContactSentInv user ct' g m
|
||||
_ -> throwChatError CEGroupMemberNotActive
|
||||
CreateGroupLink gName mRole short -> withUser $ \user -> do
|
||||
CreateGroupLink gName mRole -> withUser $ \user -> do
|
||||
groupId <- withFastStore $ \db -> getGroupIdByName db user gName
|
||||
processChatCommand $ APICreateGroupLink groupId mRole short
|
||||
processChatCommand $ APICreateGroupLink groupId mRole
|
||||
GroupLinkMemberRole gName mRole -> withUser $ \user -> do
|
||||
groupId <- withFastStore $ \db -> getGroupIdByName db user gName
|
||||
processChatCommand $ APIGroupLinkMemberRole groupId mRole
|
||||
@@ -3030,7 +3026,7 @@ processChatCommand' vr = \case
|
||||
conn <- withFastStore $ \db -> getUserAddressConnection db vr user
|
||||
let shortLinkProfile = userProfileToSend user Nothing Nothing False
|
||||
shortLinkMsg = autoAccept >>= autoReply >>= (Just . msgContentText)
|
||||
userData = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData shortLinkProfile shortLinkMsg
|
||||
userData <- contactShortLinkData shortLinkProfile shortLinkMsg
|
||||
sLnk <- shortenShortLink' =<< withAgent (\a -> setConnShortLink a (aConnId conn) SCMContact userData Nothing)
|
||||
withFastStore' $ \db -> setUserContactLinkShortLink db userContactLinkId sLnk
|
||||
let autoAccept' = autoAccept >>= \aa -> Just aa {acceptIncognito = False}
|
||||
@@ -3089,8 +3085,8 @@ processChatCommand' vr = \case
|
||||
setGroupLinkData :: User -> GroupInfo -> GroupLink -> CM ChatResponse
|
||||
setGroupLinkData user gInfo@GroupInfo {groupProfile} gLink@GroupLink {groupLinkId} = do
|
||||
conn <- withFastStore $ \db -> getGroupLinkConnection db vr user gInfo
|
||||
let userData = UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData groupProfile
|
||||
crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
userData <- groupShortLinkData groupProfile
|
||||
let crClientData = encodeJSON $ CRDataGroup groupLinkId
|
||||
sLnk <- shortenShortLink' . toShortGroupLink =<< withAgent (\a -> setConnShortLink a (aConnId conn) SCMContact userData (Just crClientData))
|
||||
gLink' <- withFastStore' $ \db -> setGroupLinkShortLink db gLink sLnk
|
||||
pure $ CRGroupLink user gInfo gLink'
|
||||
@@ -3316,9 +3312,13 @@ processChatCommand' vr = \case
|
||||
Just UserContactLink {connLinkContact = CCLink cReq _} -> pure (ACCL SCMContact $ CCLink cReq (Just l'), CPContactAddress CAPOwnLink)
|
||||
Nothing -> do
|
||||
(cReq, cData) <- getShortLinkConnReq user l'
|
||||
let contactSLinkData_ = J.decodeStrict $ linkUserData' cData
|
||||
plan <- contactRequestPlan user cReq contactSLinkData_
|
||||
pure (ACCL SCMContact $ CCLink cReq (Just l'), plan)
|
||||
let cl = ACCL SCMContact $ CCLink cReq (Just l')
|
||||
withFastStore' (\db -> getContactWithoutConnViaShortAddress db vr user l') >>= \case
|
||||
Just ct -> pure (cl, CPContactAddress (CAPContactViaAddress ct))
|
||||
Nothing -> do
|
||||
let contactSLinkData_ = J.decodeStrict $ linkUserData' cData
|
||||
plan <- contactRequestPlan user cReq contactSLinkData_
|
||||
pure (cl, plan)
|
||||
CCTGroup ->
|
||||
withFastStore' (\db -> getGroupInfoViaUserShortLink db vr user l') >>= \case
|
||||
Just (cReq, g) -> pure (ACCL SCMContact $ CCLink cReq (Just l'), CPGroupLink (GLPOwnLink g))
|
||||
@@ -3434,12 +3434,26 @@ processChatCommand' vr = \case
|
||||
CSLInvitation _ srv lnkId linkKey -> CSLInvitation SLSServer srv lnkId linkKey
|
||||
CSLContact _ ct srv linkKey -> CSLContact SLSServer ct srv linkKey
|
||||
restoreShortLink' l = (`restoreShortLink` l) <$> asks (shortLinkPresetServers . config)
|
||||
shortLinkUserData :: Profile -> UserLinkData
|
||||
shortLinkUserData profile = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData profile Nothing
|
||||
contactShortLinkData :: Profile -> Maybe Text -> CM UserLinkData
|
||||
contactShortLinkData p msg = do
|
||||
largeLinkData <- chatReadVar useLargeLinkData
|
||||
let contactData
|
||||
| largeLinkData = ContactShortLinkData p msg
|
||||
| otherwise = ContactShortLinkData p {fullName = "", image = Nothing, contactLink = Nothing} Nothing
|
||||
-- TODO [short links] compress
|
||||
pure $ UserLinkData $ LB.toStrict $ J.encode contactData
|
||||
groupShortLinkData :: GroupProfile -> CM UserLinkData
|
||||
groupShortLinkData gp = do
|
||||
largeLinkData <- chatReadVar useLargeLinkData
|
||||
let gp'
|
||||
| largeLinkData = gp
|
||||
| otherwise = gp {fullName = "", description = Nothing, image = Nothing, memberAdmission = Nothing}
|
||||
-- TODO [short links] compress
|
||||
pure $ UserLinkData $ LB.toStrict $ J.encode $ GroupShortLinkData gp'
|
||||
updatePCCShortLinkData :: PendingContactConnection -> Profile -> CM (Maybe ShortLinkInvitation)
|
||||
updatePCCShortLinkData conn@PendingContactConnection {connLinkInv} profile =
|
||||
forM (connShortLink =<< connLinkInv) $ \_ -> do
|
||||
let userData = UserLinkData $ LB.toStrict $ J.encode $ ContactShortLinkData profile Nothing
|
||||
userData <- contactShortLinkData profile Nothing
|
||||
shortenShortLink' =<< withAgent (\a -> setConnShortLink a (aConnId' conn) SCMInvitation userData Nothing)
|
||||
shortenShortLink' :: ConnShortLink m -> CM (ConnShortLink m)
|
||||
shortenShortLink' l = (`shortenShortLink` l) <$> asks (shortLinkPresetServers . config)
|
||||
@@ -4180,8 +4194,9 @@ chatCommandP =
|
||||
"/_start " *> do
|
||||
mainApp <- "main=" *> onOffP
|
||||
enableSndFiles <- " snd_files=" *> onOffP <|> pure mainApp
|
||||
pure StartChat {mainApp, enableSndFiles},
|
||||
"/_start" $> StartChat True True,
|
||||
largeLinkData <- " large_link_data=" *> onOffP <|> pure False
|
||||
pure StartChat {mainApp, enableSndFiles, largeLinkData},
|
||||
"/_start" $> StartChat {mainApp = True, enableSndFiles = True, largeLinkData = False},
|
||||
"/_check running" $> CheckChatRunning,
|
||||
"/_stop" $> APIStopChat,
|
||||
"/_app activate restore=" *> (APIActivateChat <$> onOffP),
|
||||
@@ -4388,12 +4403,12 @@ chatCommandP =
|
||||
"/set welcome " *> char_ '#' *> (UpdateGroupDescription <$> displayNameP <* A.space <*> (Just <$> msgTextP)),
|
||||
"/delete welcome " *> char_ '#' *> (UpdateGroupDescription <$> displayNameP <*> pure Nothing),
|
||||
"/show welcome " *> char_ '#' *> (ShowGroupDescription <$> displayNameP),
|
||||
"/_create link #" *> (APICreateGroupLink <$> A.decimal <*> (memberRole <|> pure GRMember) <*> shortOnOffP),
|
||||
"/_create link #" *> (APICreateGroupLink <$> A.decimal <*> (memberRole <|> pure GRMember)),
|
||||
"/_set link role #" *> (APIGroupLinkMemberRole <$> A.decimal <*> memberRole),
|
||||
"/_delete link #" *> (APIDeleteGroupLink <$> A.decimal),
|
||||
"/_get link #" *> (APIGetGroupLink <$> A.decimal),
|
||||
"/_short link #" *> (APIAddGroupShortLink <$> A.decimal),
|
||||
"/create link #" *> (CreateGroupLink <$> displayNameP <*> (memberRole <|> pure GRMember) <*> shortP),
|
||||
"/create link #" *> (CreateGroupLink <$> displayNameP <*> (memberRole <|> pure GRMember)),
|
||||
"/set link role #" *> (GroupLinkMemberRole <$> displayNameP <*> memberRole),
|
||||
"/delete link #" *> (DeleteGroupLink <$> displayNameP),
|
||||
"/show link #" *> (ShowGroupLink <$> displayNameP),
|
||||
@@ -4410,11 +4425,11 @@ chatCommandP =
|
||||
"/_set group user #" *> (APIChangePreparedGroupUser <$> A.decimal <* A.space <*> A.decimal),
|
||||
"/_connect contact @" *> (APIConnectPreparedContact <$> A.decimal <*> incognitoOnOffP <*> optional (A.space *> msgContentP)),
|
||||
"/_connect group #" *> (APIConnectPreparedGroup <$> A.decimal <*> incognitoOnOffP),
|
||||
"/_connect " *> (APIAddContact <$> A.decimal <*> shortOnOffP <*> incognitoOnOffP),
|
||||
"/_connect " *> (APIAddContact <$> A.decimal <*> incognitoOnOffP),
|
||||
"/_connect " *> (APIConnect <$> A.decimal <*> incognitoOnOffP <* A.space <*> connLinkP_ <*> optional (A.space *> msgContentP)),
|
||||
"/_set incognito :" *> (APISetConnectionIncognito <$> A.decimal <* A.space <*> onOffP),
|
||||
"/_set conn user :" *> (APIChangeConnectionUser <$> A.decimal <* A.space <*> A.decimal),
|
||||
("/connect" <|> "/c") *> (AddContact <$> shortP <*> incognitoP),
|
||||
("/connect" <|> "/c") *> (AddContact <$> incognitoP),
|
||||
("/connect" <|> "/c") *> (Connect <$> incognitoP <* A.space <*> ((Just <$> strP) <|> A.takeTill isSpace $> Nothing)),
|
||||
ForwardMessage <$> chatNameP <* " <- @" <*> displayNameP <* A.space <*> msgTextP,
|
||||
ForwardGroupMessage <$> chatNameP <* " <- #" <*> displayNameP <* A.space <* A.char '@' <*> (Just <$> displayNameP) <* A.space <*> msgTextP,
|
||||
@@ -4448,8 +4463,8 @@ chatCommandP =
|
||||
("/fstatus " <|> "/fs ") *> (FileStatus <$> A.decimal),
|
||||
"/_connect contact " *> (APIConnectContactViaAddress <$> A.decimal <*> incognitoOnOffP <* A.space <*> A.decimal),
|
||||
"/simplex" *> (ConnectSimplex <$> incognitoP),
|
||||
"/_address " *> (APICreateMyAddress <$> A.decimal <*> shortOnOffP),
|
||||
("/address" <|> "/ad") *> (CreateMyAddress <$> shortP),
|
||||
"/_address " *> (APICreateMyAddress <$> A.decimal),
|
||||
("/address" <|> "/ad") $> CreateMyAddress,
|
||||
"/_delete_address " *> (APIDeleteMyAddress <$> A.decimal),
|
||||
("/delete_address" <|> "/da") $> DeleteMyAddress,
|
||||
"/_show_address " *> (APIShowMyAddress <$> A.decimal),
|
||||
@@ -4527,9 +4542,7 @@ chatCommandP =
|
||||
pure $ ACCL m (CCLink cReq sLink_)
|
||||
connLinkP_ =
|
||||
((Just <$> connLinkP) <|> A.takeTill (== ' ') $> Nothing)
|
||||
shortP = (A.space *> ("short" <|> "s")) $> True <|> pure False
|
||||
incognitoP = (A.space *> ("incognito" <|> "i")) $> True <|> pure False
|
||||
shortOnOffP = (A.space *> "short=" *> onOffP) <|> pure False
|
||||
incognitoOnOffP = (A.space *> "incognito=" *> onOffP) <|> pure False
|
||||
imagePrefix = (<>) <$> "data:" <*> ("image/png;base64," <|> "image/jpg;base64,")
|
||||
imageP = safeDecodeUtf8 <$> ((<>) <$> imagePrefix <*> (B64.encode <$> base64P))
|
||||
|
||||
@@ -200,14 +200,14 @@ toMaybeGroupMember userContactId ((Just groupMemberId, Just groupId, Just member
|
||||
Just $ toGroupMember userContactId ((groupMemberId, groupId, memberId, minVer, maxVer, memberRole, memberCategory, memberStatus, showMessages, memberBlocked) :. (invitedById, invitedByGroupMemberId, localDisplayName, memberContactId, memberContactProfileId, profileId, displayName, fullName, image, contactLink, localAlias, contactPreferences) :. (createdAt, updatedAt) :. (supportChatTs, supportChatUnread, supportChatUnanswered, supportChatMentions, supportChatLastMsgFromMemberTs))
|
||||
toMaybeGroupMember _ _ = Nothing
|
||||
|
||||
createGroupLink :: DB.Connection -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> Bool -> SubscriptionMode -> ExceptT StoreError IO GroupLink
|
||||
createGroupLink db user@User {userId} groupInfo@GroupInfo {groupId, localDisplayName} agentConnId (CCLink cReq shortLink) groupLinkId memberRole shortLinkDataSet subMode = do
|
||||
createGroupLink :: DB.Connection -> User -> GroupInfo -> ConnId -> CreatedLinkContact -> GroupLinkId -> GroupMemberRole -> SubscriptionMode -> ExceptT StoreError IO GroupLink
|
||||
createGroupLink db user@User {userId} groupInfo@GroupInfo {groupId, localDisplayName} agentConnId (CCLink cReq shortLink) groupLinkId memberRole subMode = do
|
||||
checkConstraint (SEDuplicateGroupLink groupInfo) . liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO user_contact_links (user_id, group_id, group_link_id, local_display_name, conn_req_contact, short_link_contact, short_link_data_set, group_link_member_role, auto_accept, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
|
||||
((userId, groupId, groupLinkId, "group_link_" <> localDisplayName, cReq, shortLink, BI shortLinkDataSet) :. (memberRole, BI True, currentTs, currentTs))
|
||||
((userId, groupId, groupLinkId, "group_link_" <> localDisplayName, cReq, shortLink, BI (isJust shortLink)) :. (memberRole, BI True, currentTs, currentTs))
|
||||
userContactLinkId <- insertedRowId db
|
||||
void $ createConnection_ db userId ConnUserContact (Just userContactLinkId) agentConnId ConnNew initialChatVersion chatInitialVRange Nothing Nothing Nothing 0 currentTs subMode PQSupportOff
|
||||
getGroupLink db user groupInfo
|
||||
@@ -2032,7 +2032,7 @@ getGroupInfoViaUserShortLink db vr user@User {userId} shortLink = fmap eitherToM
|
||||
(cReq, groupId) <- ExceptT getConnReqGroup
|
||||
(cReq,) <$> getGroupInfo db vr user groupId
|
||||
where
|
||||
getConnReqGroup =
|
||||
getConnReqGroup =
|
||||
firstRow' toConnReqGroupId (SEInternalError "group link not found") $
|
||||
DB.query
|
||||
db
|
||||
|
||||
@@ -53,6 +53,7 @@ module Simplex.Chat.Store.Profiles
|
||||
getUserContactLinkViaShortLink,
|
||||
setUserContactLinkShortLink,
|
||||
getContactWithoutConnViaAddress,
|
||||
getContactWithoutConnViaShortAddress,
|
||||
updateUserAddressAutoAccept,
|
||||
getProtocolServers,
|
||||
insertProtocolServer,
|
||||
@@ -75,6 +76,7 @@ module Simplex.Chat.Store.Profiles
|
||||
updateCommandStatus,
|
||||
getCommandDataByCorrId,
|
||||
setUserUIThemes,
|
||||
profileContactLink,
|
||||
)
|
||||
where
|
||||
|
||||
@@ -86,7 +88,7 @@ import Data.Functor (($>))
|
||||
import Data.Int (Int64)
|
||||
import Data.List.NonEmpty (NonEmpty)
|
||||
import qualified Data.List.NonEmpty as L
|
||||
import Data.Maybe (catMaybes, fromMaybe)
|
||||
import Data.Maybe (catMaybes, fromMaybe, isJust)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import Data.Text.Encoding (decodeLatin1, encodeUtf8)
|
||||
@@ -332,11 +334,7 @@ setUserProfileContactLink db user@User {userId, profile = p@LocalProfile {profil
|
||||
(contactLink, ts, userId, profileId)
|
||||
pure (user :: User) {profile = p {contactLink}}
|
||||
where
|
||||
-- TODO [short links] this should be replaced with short links once they are supported by all clients.
|
||||
-- Or, maybe, we want to allow both, when both are optional.
|
||||
contactLink = case ucl_ of
|
||||
Just UserContactLink {connLinkContact = CCLink cReq _} -> Just $ CLFull cReq
|
||||
_ -> Nothing
|
||||
contactLink = profileContactLink <$> ucl_
|
||||
|
||||
-- only used in tests
|
||||
getUserContactProfiles :: DB.Connection -> User -> IO [Profile]
|
||||
@@ -354,14 +352,14 @@ getUserContactProfiles db User {userId} =
|
||||
toContactProfile :: (ContactName, Text, Maybe ImageData, Maybe ConnLinkContact, Maybe Preferences) -> Profile
|
||||
toContactProfile (displayName, fullName, image, contactLink, preferences) = Profile {displayName, fullName, image, contactLink, preferences}
|
||||
|
||||
createUserContactLink :: DB.Connection -> User -> ConnId -> CreatedLinkContact -> Bool -> SubscriptionMode -> ExceptT StoreError IO ()
|
||||
createUserContactLink db User {userId} agentConnId (CCLink cReq shortLink) shortLinkDataSet subMode =
|
||||
createUserContactLink :: DB.Connection -> User -> ConnId -> CreatedLinkContact -> SubscriptionMode -> ExceptT StoreError IO ()
|
||||
createUserContactLink db User {userId} agentConnId (CCLink cReq shortLink) subMode =
|
||||
checkConstraint SEDuplicateContactLink . liftIO $ do
|
||||
currentTs <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
"INSERT INTO user_contact_links (user_id, conn_req_contact, short_link_contact, short_link_data_set, created_at, updated_at) VALUES (?,?,?,?,?,?)"
|
||||
(userId, cReq, shortLink, BI shortLinkDataSet, currentTs, currentTs)
|
||||
(userId, cReq, shortLink, BI (isJust shortLink), currentTs, currentTs)
|
||||
userContactLinkId <- insertedRowId db
|
||||
void $ createConnection_ db userId ConnUserContact (Just userContactLinkId) agentConnId ConnNew initialChatVersion chatInitialVRange Nothing Nothing Nothing 0 currentTs subMode CR.PQSupportOff
|
||||
|
||||
@@ -457,6 +455,9 @@ data UserContactLink = UserContactLink
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
profileContactLink :: UserContactLink -> ConnLinkContact
|
||||
profileContactLink UserContactLink {connLinkContact = CCLink cReq sLink} = maybe (CLFull cReq) CLShort sLink
|
||||
|
||||
data GroupLinkInfo = GroupLinkInfo
|
||||
{ groupId :: GroupId,
|
||||
memberRole :: GroupMemberRole
|
||||
@@ -559,6 +560,22 @@ getContactWithoutConnViaAddress db vr user@User {userId} (cReqSchema1, cReqSchem
|
||||
(userId, cReqSchema1, cReqSchema2)
|
||||
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) ctId_
|
||||
|
||||
getContactWithoutConnViaShortAddress :: DB.Connection -> VersionRangeChat -> User -> ShortLinkContact -> IO (Maybe Contact)
|
||||
getContactWithoutConnViaShortAddress db vr user@User {userId} shortLink = do
|
||||
ctId_ <-
|
||||
maybeFirstRow fromOnly $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT ct.contact_id
|
||||
FROM contacts ct
|
||||
JOIN contact_profiles cp ON cp.contact_profile_id = ct.contact_profile_id
|
||||
LEFT JOIN connections c ON c.contact_id = ct.contact_id
|
||||
WHERE cp.user_id = ? AND cp.contact_link = ? AND c.connection_id IS NULL
|
||||
|]
|
||||
(userId, shortLink)
|
||||
maybe (pure Nothing) (fmap eitherToMaybe . runExceptT . getContact db vr user) ctId_
|
||||
|
||||
updateUserAddressAutoAccept :: DB.Connection -> Int64 -> Maybe AutoAccept -> IO ()
|
||||
updateUserAddressAutoAccept db userContactLinkId autoAccept =
|
||||
DB.execute
|
||||
|
||||
@@ -1178,6 +1178,18 @@ Plan:
|
||||
SEARCH g USING INTEGER PRIMARY KEY (rowid=?)
|
||||
SEARCH m USING INDEX sqlite_autoindex_group_members_1 (group_id=?)
|
||||
|
||||
Query:
|
||||
SELECT ct.contact_id
|
||||
FROM contacts ct
|
||||
JOIN contact_profiles cp ON cp.contact_profile_id = ct.contact_profile_id
|
||||
LEFT JOIN connections c ON c.contact_id = ct.contact_id
|
||||
WHERE cp.user_id = ? AND cp.contact_link = ? AND c.connection_id IS NULL
|
||||
|
||||
Plan:
|
||||
SEARCH cp USING COVERING INDEX idx_contact_profiles_contact_link (user_id=? AND contact_link=?)
|
||||
SEARCH ct USING COVERING INDEX idx_contacts_contact_profile_id (contact_profile_id=?)
|
||||
SEARCH c USING COVERING INDEX idx_connections_contact_id (contact_id=?) LEFT-JOIN
|
||||
|
||||
Query:
|
||||
SELECT ct.contact_id
|
||||
FROM contacts ct
|
||||
|
||||
@@ -222,8 +222,6 @@ contactConnId c = aConnId <$> contactConn c
|
||||
|
||||
type IncognitoEnabled = Bool
|
||||
|
||||
type CreateShortLink = Bool
|
||||
|
||||
contactConnIncognito :: Contact -> IncognitoEnabled
|
||||
contactConnIncognito = maybe False connIncognito . contactConn
|
||||
|
||||
|
||||
Reference in New Issue
Block a user