mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-03-14 09:45:42 +00:00
core: include pending group link connections into chat previews on joining side (#1291)
This commit is contained in:
parent
5243613045
commit
d432dfba21
8 changed files with 33 additions and 26 deletions
|
@ -199,7 +199,7 @@ Currently members can have one of three roles - `owner`, `admin` and `member`. T
|
|||
|
||||
### Messages to manage groups and add members
|
||||
|
||||
`x.grp.inv` message is sent to invite contact to the group via contact's direct connection and includes group member connection address. This message MUST only be sent by members with `admin` or `owner` role.
|
||||
`x.grp.inv` message is sent to invite contact to the group via contact's direct connection and includes group member connection address. This message MUST only be sent by members with `admin` or `owner` role. Optional `groupLinkId` is included when this message is sent to contacts connected via the user's group link. This identifier is a random byte sequence, with no global or even local uniqueness - it is only used for the user's invitations to a given group to provide confirmation to the contact that the group invitation is for the same group the contact was connecting to via the group link, so that the invitation can be automatically accepted by the contact - the contact compares it with the group link id contained in the group link uri's data field.
|
||||
|
||||
`x.grp.acpt` message is sent as part of group member connection handshake, only to the inviting user.
|
||||
|
||||
|
|
|
@ -108,6 +108,12 @@
|
|||
"invitedMember": {"ref": "memberIdRole"},
|
||||
"connRequest": {"ref": "connReqUri"},
|
||||
"groupProfile": {"ref": "profile"}
|
||||
},
|
||||
"optionalProperties": {
|
||||
"groupLinkId": {"ref": "base64url"},
|
||||
"metadata": {
|
||||
"comment": "used to identify invitation via group link"
|
||||
}
|
||||
}
|
||||
},
|
||||
"memberIdRole": {
|
||||
|
|
|
@ -987,7 +987,7 @@ processChatCommand = \case
|
|||
when (memberStatus membership == GSMemInvited) $ throwChatError (CEGroupNotJoined gInfo)
|
||||
unless (memberActive membership) $ throwChatError CEGroupMemberNotActive
|
||||
groupLinkId <- GroupLinkId <$> (asks idsDrg >>= liftIO . (`randomBytes` 16))
|
||||
let crClientData = encodeJson $ CRGroupData groupLinkId
|
||||
let crClientData = encodeJSON $ CRGroupData groupLinkId
|
||||
(connId, cReq) <- withAgent $ \a -> createConnection a True SCMContact $ Just crClientData
|
||||
withStore $ \db -> createGroupLink db user gInfo connId cReq groupLinkId
|
||||
pure $ CRGroupLinkCreated gInfo cReq
|
||||
|
@ -1125,7 +1125,7 @@ processChatCommand = \case
|
|||
incognitoProfile <- if incognito then Just <$> liftIO generateRandomProfile else pure Nothing
|
||||
let profileToSend = fromMaybe profile incognitoProfile
|
||||
connId <- withAgent $ \a -> joinConnection a True cReq $ directMessage (XContact profileToSend $ Just xContactId)
|
||||
let groupLinkId = crClientData >>= decodeJson >>= \(CRGroupData gli) -> Just gli
|
||||
let groupLinkId = crClientData >>= decodeJSON >>= \(CRGroupData gli) -> Just gli
|
||||
conn <- withStore' $ \db -> createConnReqConnection db userId connId cReqHash xContactId incognitoProfile groupLinkId
|
||||
toView $ CRNewContactConnection conn
|
||||
pure $ CRSentInvitation incognitoProfile
|
||||
|
|
|
@ -21,7 +21,7 @@ import Data.Time.Clock (UTCTime)
|
|||
import Database.SQLite.Simple.FromField (FromField (..))
|
||||
import Database.SQLite.Simple.ToField (ToField (..))
|
||||
import GHC.Generics (Generic)
|
||||
import Simplex.Chat.Types (Contact, ContactId, decodeJson, encodeJson)
|
||||
import Simplex.Chat.Types (Contact, ContactId, decodeJSON, encodeJSON)
|
||||
import qualified Simplex.Messaging.Crypto as C
|
||||
import Simplex.Messaging.Encoding.String
|
||||
import Simplex.Messaging.Parsers (dropPrefix, enumJSON, fromTextField_, fstToLower, singleFieldJSON)
|
||||
|
@ -100,10 +100,10 @@ instance ToJSON CallState where
|
|||
toEncoding = J.genericToEncoding $ singleFieldJSON fstToLower
|
||||
|
||||
instance ToField CallState where
|
||||
toField = toField . encodeJson
|
||||
toField = toField . encodeJSON
|
||||
|
||||
instance FromField CallState where
|
||||
fromField = fromTextField_ decodeJson
|
||||
fromField = fromTextField_ decodeJSON
|
||||
|
||||
newtype CallId = CallId ByteString
|
||||
deriving (Eq, Show)
|
||||
|
|
|
@ -726,7 +726,7 @@ msgDirToDeletedContent_ msgDir mode = case msgDir of
|
|||
|
||||
-- platform independent
|
||||
instance ToField (CIContent d) where
|
||||
toField = toField . encodeJson . dbJsonCIContent
|
||||
toField = toField . encodeJSON . dbJsonCIContent
|
||||
|
||||
-- platform specific
|
||||
instance ToJSON (CIContent d) where
|
||||
|
@ -742,7 +742,7 @@ instance FromJSON ACIContent where
|
|||
parseJSON = fmap aciContentJSON . J.parseJSON
|
||||
|
||||
-- platform independent
|
||||
instance FromField ACIContent where fromField = fromTextField_ $ fmap aciContentDBJSON . decodeJson
|
||||
instance FromField ACIContent where fromField = fromTextField_ $ fmap aciContentDBJSON . decodeJSON
|
||||
|
||||
-- platform specific
|
||||
data JSONCIContent
|
||||
|
|
|
@ -391,10 +391,10 @@ instance ToJSON MsgContent where
|
|||
MCFile t -> J.pairs $ "type" .= MCFile_ <> "text" .= t
|
||||
|
||||
instance ToField MsgContent where
|
||||
toField = toField . encodeJson
|
||||
toField = toField . encodeJSON
|
||||
|
||||
instance FromField MsgContent where
|
||||
fromField = fromTextField_ decodeJson
|
||||
fromField = fromTextField_ decodeJSON
|
||||
|
||||
data CMEventTag (e :: MsgEncoding) where
|
||||
XMsgNew_ :: CMEventTag 'Json
|
||||
|
|
|
@ -434,7 +434,7 @@ createConnReqConnection db userId acId cReqHash xContactId incognitoProfile grou
|
|||
|]
|
||||
((userId, acId, pccConnStatus, ConnContact, cReqHash, xContactId) :. (customUserProfileId, isJust groupLinkId, groupLinkId, createdAt, createdAt))
|
||||
pccConnId <- insertedRowId db
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = True, viaUserContactLink = Nothing, customUserProfileId, connReqInv = Nothing, localAlias = "", createdAt, updatedAt = createdAt}
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = True, viaUserContactLink = Nothing, groupLinkId, customUserProfileId, connReqInv = Nothing, localAlias = "", createdAt, updatedAt = createdAt}
|
||||
|
||||
getConnReqContactXContactId :: DB.Connection -> UserId -> ConnReqUriHash -> IO (Maybe Contact, Maybe XContactId)
|
||||
getConnReqContactXContactId db userId cReqHash = do
|
||||
|
@ -482,7 +482,7 @@ createDirectConnection db userId acId cReq pccConnStatus incognitoProfile = do
|
|||
|]
|
||||
(userId, acId, cReq, pccConnStatus, ConnContact, customUserProfileId, createdAt, createdAt)
|
||||
pccConnId <- insertedRowId db
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = False, viaUserContactLink = Nothing, customUserProfileId, connReqInv = Just cReq, localAlias = "", createdAt, updatedAt = createdAt}
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = False, viaUserContactLink = Nothing, groupLinkId = Nothing, customUserProfileId, connReqInv = Just cReq, localAlias = "", createdAt, updatedAt = createdAt}
|
||||
|
||||
createIncognitoProfile_ :: DB.Connection -> UserId -> UTCTime -> Profile -> IO Int64
|
||||
createIncognitoProfile_ db userId createdAt Profile {displayName, fullName, image} = do
|
||||
|
@ -1203,7 +1203,7 @@ getPendingContactConnections db User {userId} = do
|
|||
<$> DB.queryNamed
|
||||
db
|
||||
[sql|
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, group_link_id, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
FROM connections
|
||||
WHERE user_id = :user_id
|
||||
AND conn_type = :conn_type
|
||||
|
@ -3342,13 +3342,13 @@ getContactConnectionChatPreviews_ db User {userId} _ =
|
|||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, group_link_id, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
FROM connections
|
||||
WHERE user_id = ? AND conn_type = ? AND contact_id IS NULL AND conn_level = 0 AND via_group_link = 0 AND via_contact IS NULL
|
||||
WHERE user_id = ? AND conn_type = ? AND contact_id IS NULL AND conn_level = 0 AND via_contact IS NULL AND (via_group_link = 0 || (via_group_link = 1 AND group_link_id IS NOT NULL))
|
||||
|]
|
||||
(userId, ConnContact)
|
||||
where
|
||||
toContactConnectionChatPreview :: (Int64, ConnId, ConnStatus, Maybe ByteString, Maybe Int64, Maybe Int64, Maybe ConnReqInvitation, LocalAlias, UTCTime, UTCTime) -> AChat
|
||||
toContactConnectionChatPreview :: (Int64, ConnId, ConnStatus, Maybe ByteString, Maybe Int64, Maybe GroupLinkId, Maybe Int64, Maybe ConnReqInvitation, LocalAlias, UTCTime, UTCTime) -> AChat
|
||||
toContactConnectionChatPreview connRow =
|
||||
let conn = toPendingContactConnection connRow
|
||||
stats = ChatStats {unreadCount = 0, minUnreadItemId = 0, unreadChat = False}
|
||||
|
@ -3360,7 +3360,7 @@ getPendingContactConnection db userId connId = do
|
|||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, via_user_contact_link, group_link_id, custom_user_profile_id, conn_req_inv, local_alias, created_at, updated_at
|
||||
FROM connections
|
||||
WHERE user_id = ?
|
||||
AND connection_id = ?
|
||||
|
@ -3394,9 +3394,9 @@ updateGroupSettings :: DB.Connection -> User -> Int64 -> ChatSettings -> IO ()
|
|||
updateGroupSettings db User {userId} groupId ChatSettings {enableNtfs} =
|
||||
DB.execute db "UPDATE groups SET enable_ntfs = ? WHERE user_id = ? AND group_id = ?" (enableNtfs, userId, groupId)
|
||||
|
||||
toPendingContactConnection :: (Int64, ConnId, ConnStatus, Maybe ByteString, Maybe Int64, Maybe Int64, Maybe ConnReqInvitation, LocalAlias, UTCTime, UTCTime) -> PendingContactConnection
|
||||
toPendingContactConnection (pccConnId, acId, pccConnStatus, connReqHash, viaUserContactLink, customUserProfileId, connReqInv, localAlias, createdAt, updatedAt) =
|
||||
PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = isJust connReqHash, viaUserContactLink, customUserProfileId, connReqInv, localAlias, createdAt, updatedAt}
|
||||
toPendingContactConnection :: (Int64, ConnId, ConnStatus, Maybe ByteString, Maybe Int64, Maybe GroupLinkId, Maybe Int64, Maybe ConnReqInvitation, LocalAlias, UTCTime, UTCTime) -> PendingContactConnection
|
||||
toPendingContactConnection (pccConnId, acId, pccConnStatus, connReqHash, viaUserContactLink, groupLinkId, customUserProfileId, connReqInv, localAlias, createdAt, updatedAt) =
|
||||
PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = isJust connReqHash, viaUserContactLink, groupLinkId, customUserProfileId, connReqInv, localAlias, createdAt, updatedAt}
|
||||
|
||||
getDirectChat :: DB.Connection -> User -> Int64 -> ChatPagination -> Maybe String -> ExceptT StoreError IO (Chat 'CTDirect)
|
||||
getDirectChat db user contactId pagination search_ = do
|
||||
|
|
|
@ -252,10 +252,10 @@ instance ToJSON ChatPreferences where
|
|||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
instance ToField ChatPreferences where
|
||||
toField = toField . encodeJson
|
||||
toField = toField . encodeJSON
|
||||
|
||||
instance FromField ChatPreferences where
|
||||
fromField = fromTextField_ decodeJson
|
||||
fromField = fromTextField_ decodeJSON
|
||||
|
||||
data Preference = Preference
|
||||
{enable :: PrefSwitch}
|
||||
|
@ -935,6 +935,7 @@ data PendingContactConnection = PendingContactConnection
|
|||
pccConnStatus :: ConnStatus,
|
||||
viaContactUri :: Bool,
|
||||
viaUserContactLink :: Maybe Int64,
|
||||
groupLinkId :: Maybe GroupLinkId,
|
||||
customUserProfileId :: Maybe Int64,
|
||||
connReqInv :: Maybe ConnReqInvitation,
|
||||
localAlias :: Text,
|
||||
|
@ -1164,8 +1165,8 @@ data XGrpMemIntroCont = XGrpMemIntroCont
|
|||
}
|
||||
deriving (Show)
|
||||
|
||||
encodeJson :: ToJSON a => a -> Text
|
||||
encodeJson = safeDecodeUtf8 . LB.toStrict . J.encode
|
||||
encodeJSON :: ToJSON a => a -> Text
|
||||
encodeJSON = safeDecodeUtf8 . LB.toStrict . J.encode
|
||||
|
||||
decodeJson :: FromJSON a => Text -> Maybe a
|
||||
decodeJson = J.decode . LB.fromStrict . encodeUtf8
|
||||
decodeJSON :: FromJSON a => Text -> Maybe a
|
||||
decodeJSON = J.decode . LB.fromStrict . encodeUtf8
|
||||
|
|
Loading…
Add table
Reference in a new issue