mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-08-06 23:39:54 +00:00
chat: APIConnectPlan accepts ConnectTarget; connectPlanName looks up by name
APIConnectPlan/Connect flip from Maybe AConnectionLink to Maybe ConnectTarget. connectPlan dispatches CTLink -> connectPlanLink (the prior body, renamed) and CTName -> connectPlanName (new) which looks the name up against contacts.simplex_name and groups.simplex_name via the new getContactBySimplexName / getGroupInfoBySimplexName store helpers. The hit path returns the contact's / group's stored conn link from preparedContact / preparedGroup; missing prepared state or unknown names return CEInvalidConnReq. RSLV on-chain resolution is out of scope for this branch -- known-name lookup is enough for conversation display, search, and external-link share. connLinkP_ parser is unchanged: APIConnect's preparedLink_ stays ACreatedConnLink-shaped, and the Connect / APIConnectPlan parsers already use inline strP for ConnectTarget without going through the helper. Directory.Service call sites updated to wrap their AConnectionLink in CTLink when invoking APIConnectPlan.
This commit is contained in:
@@ -65,7 +65,7 @@ import Simplex.Chat.Types
|
||||
import Simplex.Chat.Types.Preferences
|
||||
import Simplex.Chat.Types.Shared
|
||||
import Simplex.Chat.View (serializeChatError, serializeChatResponse, simplexChatContact, viewContactName, viewGroupName)
|
||||
import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ACreatedConnLink (..), AgentErrorType (..), ConnectionLink (..), CreatedConnLink (..), SConnectionMode (..), sameConnReqContact, sameShortLinkContact)
|
||||
import Simplex.Messaging.Agent.Protocol (AConnectionLink (..), ACreatedConnLink (..), AgentErrorType (..), ConnectTarget (..), ConnectionLink (..), CreatedConnLink (..), SConnectionMode (..), sameConnReqContact, sameShortLinkContact)
|
||||
import qualified Simplex.Messaging.Crypto.File as CF
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Protocol (ErrorType (..))
|
||||
@@ -552,7 +552,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
<> ".\nIt is hidden from the directory until approved."
|
||||
notifyAdminUsers $ "The " <> gt <> " " <> groupRef <> " is updated" <> byMember <> "."
|
||||
sendToApprove g' gr' n'
|
||||
sendChatCmd cc (APIConnectPlan userId (Just link) True Nothing) >>= \case
|
||||
sendChatCmd cc (APIConnectPlan userId (Just (CTLink link)) True Nothing) >>= \case
|
||||
Right (CRConnectionPlan _ _ (CPGroupLink (GLPKnown {groupInfo = g'}))) ->
|
||||
case dbOwnerMemberId gr of
|
||||
Just ownerGMId ->
|
||||
@@ -797,7 +797,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
forM_ pg_ $ \pg@PublicGroupProfile {groupLink} ->
|
||||
when (groupRegStatus == GRSActive || pendingApproval groupRegStatus) $ do
|
||||
let link = ACL SCMContact $ CLShort groupLink
|
||||
sendChatCmd cc (APIConnectPlan userId (Just link) True Nothing) >>= \case
|
||||
sendChatCmd cc (APIConnectPlan userId (Just (CTLink link)) True Nothing) >>= \case
|
||||
Right (CRConnectionPlan _ _ (CPGroupLink (GLPKnown {groupInfo = g', groupUpdated = BoolDef updated, linkOwners = ListDef owners}))) ->
|
||||
checkValidOwner dbOwnerMemberId owners $ do
|
||||
when updated $ reapprove pg gr groupRegStatus g'
|
||||
@@ -933,7 +933,7 @@ directoryServiceEvent st opts@DirectoryOpts {adminUsers, superUsers, serviceName
|
||||
let link = ACL SCMContact $ CLShort connLink
|
||||
mId = MemberId oIdBytes
|
||||
gt' = groupTypeStr gt
|
||||
sendChatCmd cc (APIConnectPlan userId (Just link) True (Just ownerSig)) >>= \case
|
||||
sendChatCmd cc (APIConnectPlan userId (Just (CTLink link)) True (Just ownerSig)) >>= \case
|
||||
Right (CRConnectionPlan _ (ACCL SCMContact ccLink) plan) ->
|
||||
handleGroupLinkPlan ct ccLink mId ownerSig gt' plan
|
||||
_ -> sendMessage cc ct "Error: could not connect. Please report it to directory admins."
|
||||
|
||||
@@ -477,7 +477,7 @@ data ChatCommand
|
||||
| AddContact IncognitoEnabled
|
||||
| APISetConnectionIncognito Int64 IncognitoEnabled
|
||||
| APIChangeConnectionUser Int64 UserId -- new user id to switch connection to
|
||||
| APIConnectPlan {userId :: UserId, connectionLink :: Maybe AConnectionLink, resolveKnown :: Bool, linkOwnerSig :: Maybe LinkOwnerSig} -- Maybe AConnectionLink is used to report link parsing failure as special error
|
||||
| APIConnectPlan {userId :: UserId, connectTarget :: Maybe ConnectTarget, resolveKnown :: Bool, linkOwnerSig :: Maybe LinkOwnerSig} -- Maybe ConnectTarget is used to report parsing failure as special error
|
||||
| APIPrepareContact UserId ACreatedConnLink ContactShortLinkData
|
||||
| APIPrepareGroup UserId CreatedLinkContact DirectLink GroupShortLinkData
|
||||
| APIChangePreparedContactUser ContactId UserId
|
||||
@@ -485,7 +485,7 @@ data ChatCommand
|
||||
| APIConnectPreparedContact {contactId :: ContactId, incognito :: IncognitoEnabled, msgContent_ :: Maybe MsgContent}
|
||||
| APIConnectPreparedGroup {groupId :: GroupId, incognito :: IncognitoEnabled, ownerContact :: Maybe GroupOwnerContact, msgContent_ :: Maybe MsgContent}
|
||||
| APIConnect {userId :: UserId, incognito :: IncognitoEnabled, preparedLink_ :: Maybe ACreatedConnLink} -- Maybe is used to report link parsing failure as special error
|
||||
| Connect {incognito :: IncognitoEnabled, connLink_ :: Maybe AConnectionLink}
|
||||
| Connect {incognito :: IncognitoEnabled, connTarget_ :: Maybe ConnectTarget}
|
||||
| APIConnectContactViaAddress UserId IncognitoEnabled ContactId
|
||||
| ConnectSimplex IncognitoEnabled -- UserId (not used in UI)
|
||||
| DeleteContact ContactName ChatDeleteMode
|
||||
|
||||
@@ -2007,8 +2007,8 @@ processChatCommand vr nm = \case
|
||||
createDirectConnection db newUser agConnId ccLink' Nothing ConnNew Nothing subMode initialChatVersion PQSupportOn
|
||||
deleteAgentConnectionAsync (aConnId' conn)
|
||||
pure conn'
|
||||
APIConnectPlan userId (Just cLink) resolveKnown linkOwnerSig_ -> withUserId userId $ \user ->
|
||||
uncurry (CRConnectionPlan user) <$> connectPlan user cLink resolveKnown linkOwnerSig_
|
||||
APIConnectPlan userId (Just ct) resolveKnown linkOwnerSig_ -> withUserId userId $ \user ->
|
||||
uncurry (CRConnectionPlan user) <$> connectPlan user ct resolveKnown linkOwnerSig_
|
||||
APIConnectPlan _ Nothing _ _ -> throwChatError CEInvalidConnReq
|
||||
APIPrepareContact userId accLink contactSLinkData -> withUserId userId $ \user -> do
|
||||
let ContactShortLinkData {profile, message, business} = contactSLinkData
|
||||
@@ -2235,10 +2235,13 @@ processChatCommand vr nm = \case
|
||||
CVRConnectedContact ct -> pure $ CRContactAlreadyExists user ct
|
||||
CVRSentInvitation conn incognitoProfile -> pure $ CRSentInvitation user (mkPendingContactConnection conn Nothing) incognitoProfile
|
||||
APIConnect _ _ Nothing -> throwChatError CEInvalidConnReq
|
||||
Connect incognito (Just cLink@(ACL m cLink')) -> withUser $ \user -> do
|
||||
Connect incognito (Just (CTLink cLink@(ACL m cLink'))) -> withUser $ \user -> do
|
||||
-- TODO [relays] member: /c api to support groups with relays
|
||||
-- TODO - possibly by going through APIPrepareGroup -> APIConnectPreparedGroup
|
||||
(ccLink, plan) <- connectPlan user cLink False Nothing `catchAllErrors` \e -> case cLink' of CLFull cReq -> pure (ACCL m (CCLink cReq Nothing), CPInvitationLink (ILPOk Nothing Nothing)); _ -> throwError e
|
||||
(ccLink, plan) <- connectPlanLink user cLink False Nothing `catchAllErrors` \e -> case cLink' of CLFull cReq -> pure (ACCL m (CCLink cReq Nothing), CPInvitationLink (ILPOk Nothing Nothing)); _ -> throwError e
|
||||
connectWithPlan user incognito ccLink plan
|
||||
Connect incognito (Just (CTName ni)) -> withUser $ \user -> do
|
||||
(ccLink, plan) <- connectPlanName user ni
|
||||
connectWithPlan user incognito ccLink plan
|
||||
Connect _ Nothing -> throwChatError CEInvalidConnReq
|
||||
APIConnectContactViaAddress userId incognito contactId -> withUserId userId $ \user -> do
|
||||
@@ -4068,8 +4071,12 @@ processChatCommand vr nm = \case
|
||||
pure (gId, chatSettings)
|
||||
_ -> throwCmdError "not supported"
|
||||
processChatCommand vr nm $ APISetChatSettings (ChatRef cType chatId Nothing) $ updateSettings chatSettings
|
||||
connectPlan :: User -> AConnectionLink -> Bool -> Maybe LinkOwnerSig -> CM (ACreatedConnLink, ConnectionPlan)
|
||||
connectPlan user (ACL SCMInvitation cLink) _ sig_ = case cLink of
|
||||
connectPlan :: User -> ConnectTarget -> Bool -> Maybe LinkOwnerSig -> CM (ACreatedConnLink, ConnectionPlan)
|
||||
connectPlan user ct resolveKnown sig_ = case ct of
|
||||
CTLink l -> connectPlanLink user l resolveKnown sig_
|
||||
CTName ni -> connectPlanName user ni
|
||||
connectPlanLink :: User -> AConnectionLink -> Bool -> Maybe LinkOwnerSig -> CM (ACreatedConnLink, ConnectionPlan)
|
||||
connectPlanLink user (ACL SCMInvitation cLink) _ sig_ = case cLink of
|
||||
CLFull cReq -> invitationReqAndPlan cReq Nothing Nothing Nothing
|
||||
CLShort l -> do
|
||||
let l' = serverShortLink l
|
||||
@@ -4090,7 +4097,7 @@ processChatCommand vr nm = \case
|
||||
invitationReqAndPlan cReq sLnk_ cld ov = do
|
||||
plan <- invitationRequestPlan user cReq cld ov `catchAllErrors` (pure . CPError)
|
||||
pure (ACCL SCMInvitation (CCLink cReq sLnk_), plan)
|
||||
connectPlan user (ACL SCMContact cLink) resolveKnown sig_ = case cLink of
|
||||
connectPlanLink user (ACL SCMContact cLink) resolveKnown sig_ = case cLink of
|
||||
CLFull cReq -> do
|
||||
plan <- contactOrGroupRequestPlan user cReq `catchAllErrors` (pure . CPError)
|
||||
pure (ACCL SCMContact $ CCLink cReq Nothing, plan)
|
||||
@@ -4164,6 +4171,23 @@ processChatCommand vr nm = \case
|
||||
Just sLinkData -> updateGroupFromLinkData user g sLinkData
|
||||
_ -> pure (g, False)
|
||||
pure (con (linkConnReq fd), CPGroupLink (GLPKnown g' (BoolDef updated) ov (ListDef glOwners)))
|
||||
connectPlanName :: User -> SimplexNameInfo -> CM (ACreatedConnLink, ConnectionPlan)
|
||||
connectPlanName user ni@SimplexNameInfo {nameType} = do
|
||||
ct_ <- withFastStore $ \db -> getContactBySimplexName db vr user ni
|
||||
case ct_ of
|
||||
Just ct -> case preparedContact ct of
|
||||
Just PreparedContact {connLinkToConnect} -> pure (connLinkToConnect, CPContactAddress (CAPKnown ct))
|
||||
Nothing -> throwChatError CEInvalidConnReq
|
||||
Nothing -> case nameType of
|
||||
NTContact -> throwChatError CEInvalidConnReq
|
||||
NTPublicGroup -> do
|
||||
g_ <- withFastStore $ \db -> getGroupInfoBySimplexName db vr user ni
|
||||
case g_ of
|
||||
Just g -> case preparedGroup g of
|
||||
Just PreparedGroup {connLinkToConnect = ccLink} ->
|
||||
pure (ACCL SCMContact ccLink, CPGroupLink (GLPKnown g (BoolDef False) Nothing (ListDef [])))
|
||||
Nothing -> throwChatError CEInvalidConnReq
|
||||
Nothing -> throwChatError CEInvalidConnReq
|
||||
connectWithPlan :: User -> IncognitoEnabled -> ACreatedConnLink -> ConnectionPlan -> CM ChatResponse
|
||||
connectWithPlan user@User {userId} incognito ccLink plan
|
||||
| connectionPlanProceed plan = do
|
||||
|
||||
@@ -46,9 +46,11 @@ module Simplex.Chat.Store.Direct
|
||||
deleteContactWithoutGroups,
|
||||
getDeletedContacts,
|
||||
getContactByName,
|
||||
getContactBySimplexName,
|
||||
getContact,
|
||||
getContactViaShortLinkToConnect,
|
||||
getContactIdByName,
|
||||
getContactIdBySimplexName,
|
||||
updateContactProfile,
|
||||
updateContactUserPreferences,
|
||||
updateContactAlias,
|
||||
@@ -763,6 +765,23 @@ getContactByName db vr user localDisplayName = do
|
||||
cId <- getContactIdByName db user localDisplayName
|
||||
getContact db vr user cId
|
||||
|
||||
getContactBySimplexName :: DB.Connection -> VersionRangeChat -> User -> SimplexNameInfo -> ExceptT StoreError IO (Maybe Contact)
|
||||
getContactBySimplexName db vr user ni =
|
||||
liftIO (getContactIdBySimplexName db user ni) >>= \case
|
||||
Nothing -> pure Nothing
|
||||
Just cId -> Just <$> getContact db vr user cId
|
||||
|
||||
getContactIdBySimplexName :: DB.Connection -> User -> SimplexNameInfo -> IO (Maybe Int64)
|
||||
getContactIdBySimplexName db User {userId} ni =
|
||||
maybeFirstRow fromOnly $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT contact_id FROM contacts
|
||||
WHERE user_id = ? AND simplex_name = ? AND deleted = 0
|
||||
|]
|
||||
(userId, ni)
|
||||
|
||||
getUserContacts :: DB.Connection -> VersionRangeChat -> User -> IO [Contact]
|
||||
getUserContacts db vr user@User {userId} = do
|
||||
contactIds <- map fromOnly <$> DB.query db "SELECT contact_id FROM contacts WHERE user_id = ? AND deleted = 0" (Only userId)
|
||||
|
||||
@@ -49,9 +49,11 @@ module Simplex.Chat.Store.Groups
|
||||
updateGroupPreferences,
|
||||
updateGroupProfileFromMember,
|
||||
getGroupIdByName,
|
||||
getGroupIdBySimplexName,
|
||||
getGroupMemberIdByName,
|
||||
getActiveMembersByName,
|
||||
getGroupInfoByName,
|
||||
getGroupInfoBySimplexName,
|
||||
getGroupMember,
|
||||
getHostMember,
|
||||
getMentionedGroupMember,
|
||||
@@ -1043,6 +1045,17 @@ getGroupInfoByName db vr user gName = do
|
||||
gId <- getGroupIdByName db user gName
|
||||
getGroupInfo db vr user gId
|
||||
|
||||
getGroupInfoBySimplexName :: DB.Connection -> VersionRangeChat -> User -> SimplexNameInfo -> ExceptT StoreError IO (Maybe GroupInfo)
|
||||
getGroupInfoBySimplexName db vr user ni =
|
||||
liftIO (getGroupIdBySimplexName db user ni) >>= \case
|
||||
Nothing -> pure Nothing
|
||||
Just gId -> Just <$> getGroupInfo db vr user gId
|
||||
|
||||
getGroupIdBySimplexName :: DB.Connection -> User -> SimplexNameInfo -> IO (Maybe GroupId)
|
||||
getGroupIdBySimplexName db User {userId} ni =
|
||||
maybeFirstRow fromOnly $
|
||||
DB.query db "SELECT group_id FROM groups WHERE user_id = ? AND simplex_name = ?" (userId, ni)
|
||||
|
||||
getGroupMember :: DB.Connection -> VersionRangeChat -> User -> GroupId -> GroupMemberId -> ExceptT StoreError IO GroupMember
|
||||
getGroupMember db vr user@User {userId} groupId groupMemberId =
|
||||
ExceptT . firstRow (toContactMember vr user) (SEGroupMemberNotFound groupMemberId) $
|
||||
|
||||
Reference in New Issue
Block a user