mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-03-30 20:45:49 +00:00
core: api for pending contact connections (#553)
* core: api for pending contact connections * core: pending contact connection events / api
This commit is contained in:
committed by
GitHub
parent
a525f24969
commit
14514050ae
@@ -183,11 +183,12 @@ processChatCommand = \case
|
||||
ff <- asks filesFolder
|
||||
atomically . writeTVar ff $ Just filesFolder'
|
||||
pure CRCmdOk
|
||||
APIGetChats -> CRApiChats <$> withUser (\user -> withStore (`getChatPreviews` user))
|
||||
APIGetChats withPCC -> CRApiChats <$> withUser (\user -> withStore $ \st -> getChatPreviews st user withPCC)
|
||||
APIGetChat cType cId pagination -> withUser $ \user -> case cType of
|
||||
CTDirect -> CRApiChat . AChat SCTDirect <$> withStore (\st -> getDirectChat st user cId pagination)
|
||||
CTGroup -> CRApiChat . AChat SCTGroup <$> withStore (\st -> getGroupChat st user cId pagination)
|
||||
CTContactRequest -> pure $ chatCmdError "not implemented"
|
||||
CTContactConnection -> pure $ chatCmdError "not supported"
|
||||
APIGetChatItems _pagination -> pure $ chatCmdError "not implemented"
|
||||
APISendMessage cType chatId file_ quotedItemId_ mc -> withUser $ \user@User {userId} -> withChatLock $ case cType of
|
||||
CTDirect -> do
|
||||
@@ -263,6 +264,7 @@ processChatCommand = \case
|
||||
quoteData (CIRcvMsgContent qmc) (CIGroupRcv m) _ = pure (qmc, CIQGroupRcv $ Just m, False, m)
|
||||
quoteData _ _ _ = throwChatError CEInvalidQuote
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
CTContactConnection -> pure $ chatCmdError "not supported"
|
||||
where
|
||||
quoteContent qmc = \case
|
||||
MCText _ -> qmc
|
||||
@@ -300,6 +302,7 @@ processChatCommand = \case
|
||||
_ -> throwChatError CEInvalidChatItemUpdate
|
||||
CChatItem SMDRcv _ -> throwChatError CEInvalidChatItemUpdate
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
CTContactConnection -> pure $ chatCmdError "not supported"
|
||||
APIDeleteChatItem cType chatId itemId mode -> withUser $ \user@User {userId} -> withChatLock $ case cType of
|
||||
CTDirect -> do
|
||||
(ct@Contact {localDisplayName = c}, CChatItem msgDir deletedItem@ChatItem {meta = CIMeta {itemSharedMsgId}, file}) <- withStore $ \st -> (,) <$> getContact st userId chatId <*> getDirectChatItem st userId chatId itemId
|
||||
@@ -332,6 +335,7 @@ processChatCommand = \case
|
||||
pure $ CRChatItemDeleted (AChatItem SCTGroup msgDir (GroupChat gInfo) deletedItem) toCi
|
||||
(CIDMBroadcast, _, _) -> throwChatError CEInvalidChatItemDelete
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
CTContactConnection -> pure $ chatCmdError "not supported"
|
||||
where
|
||||
deleteFile :: MsgDirectionI d => UserId -> Maybe (CIFile d) -> m ()
|
||||
deleteFile userId file =
|
||||
@@ -343,6 +347,7 @@ processChatCommand = \case
|
||||
CTDirect -> withStore (\st -> updateDirectChatItemsRead st chatId fromToIds) $> CRCmdOk
|
||||
CTGroup -> withStore (\st -> updateGroupChatItemsRead st chatId fromToIds) $> CRCmdOk
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
CTContactConnection -> pure $ chatCmdError "not supported"
|
||||
APIDeleteChat cType chatId -> withUser $ \User {userId} -> case cType of
|
||||
CTDirect -> do
|
||||
ct@Contact {localDisplayName} <- withStore $ \st -> getContact st userId chatId
|
||||
@@ -360,6 +365,8 @@ processChatCommand = \case
|
||||
unsetActive $ ActiveC localDisplayName
|
||||
pure $ CRContactDeleted ct
|
||||
gs -> throwChatError $ CEContactGroups ct gs
|
||||
CTContactConnection ->
|
||||
CRContactConnectionDeleted <$> withStore (\st -> deletePendingContactConnection st userId chatId)
|
||||
CTGroup -> pure $ chatCmdError "not implemented"
|
||||
CTContactRequest -> pure $ chatCmdError "not supported"
|
||||
APIAcceptContact connReqId -> withUser $ \user@User {userId} -> withChatLock $ do
|
||||
@@ -387,11 +394,13 @@ processChatCommand = \case
|
||||
Welcome -> withUser $ pure . CRWelcome
|
||||
AddContact -> withUser $ \User {userId} -> withChatLock . procCmd $ do
|
||||
(connId, cReq) <- withAgent (`createConnection` SCMInvitation)
|
||||
withStore $ \st -> createDirectConnection st userId connId
|
||||
conn <- withStore $ \st -> createDirectConnection st userId connId ConnNew
|
||||
toView $ CRNewContactConnection conn
|
||||
pure $ CRInvitation cReq
|
||||
Connect (Just (ACR SCMInvitation cReq)) -> withUser $ \User {userId, profile} -> withChatLock . procCmd $ do
|
||||
connId <- withAgent $ \a -> joinConnection a cReq . directMessage $ XInfo profile
|
||||
withStore $ \st -> createDirectConnection st userId connId
|
||||
conn <- withStore $ \st -> createDirectConnection st userId connId ConnJoined
|
||||
toView $ CRNewContactConnection conn
|
||||
pure CRSentConfirmation
|
||||
Connect (Just (ACR SCMContact cReq)) -> withUser $ \User {userId, profile} ->
|
||||
connectViaContact userId cReq profile
|
||||
@@ -647,7 +656,8 @@ processChatCommand = \case
|
||||
let randomXContactId = XContactId <$> (asks idsDrg >>= liftIO . (`randomBytes` 16))
|
||||
xContactId <- maybe randomXContactId pure xContactId_
|
||||
connId <- withAgent $ \a -> joinConnection a cReq $ directMessage (XContact profile $ Just xContactId)
|
||||
withStore $ \st -> createConnReqConnection st userId connId cReqHash xContactId
|
||||
conn <- withStore $ \st -> createConnReqConnection st userId connId cReqHash xContactId
|
||||
toView $ CRNewContactConnection conn
|
||||
pure CRSentInvitation
|
||||
contactMember :: Contact -> [GroupMember] -> Maybe GroupMember
|
||||
contactMember Contact {contactId} =
|
||||
@@ -1889,7 +1899,7 @@ chatCommandP =
|
||||
<|> ("/user" <|> "/u") $> ShowActiveUser
|
||||
<|> "/_start" $> StartChat
|
||||
<|> "/_files_folder " *> (SetFilesFolder <$> filePath)
|
||||
<|> "/_get chats" $> APIGetChats
|
||||
<|> "/_get chats" *> (APIGetChats <$> (" connections" $> True <|> pure False))
|
||||
<|> "/_get chat " *> (APIGetChat <$> chatTypeP <*> A.decimal <* A.space <*> chatPaginationP)
|
||||
<|> "/_get items count=" *> (APIGetChatItems <$> A.decimal)
|
||||
<|> "/_send " *> (APISendMessage <$> chatTypeP <*> A.decimal <*> optional filePathTagged <*> optional quotedItemIdTagged <* A.space <*> msgContentP)
|
||||
@@ -1962,7 +1972,7 @@ chatCommandP =
|
||||
where
|
||||
imagePrefix = (<>) <$> "data:" <*> ("image/png;base64," <|> "image/jpg;base64,")
|
||||
imageP = safeDecodeUtf8 <$> ((<>) <$> imagePrefix <*> (B64.encode <$> base64P))
|
||||
chatTypeP = A.char '@' $> CTDirect <|> A.char '#' $> CTGroup
|
||||
chatTypeP = A.char '@' $> CTDirect <|> A.char '#' $> CTGroup <|> A.char ':' $> CTContactConnection
|
||||
chatPaginationP =
|
||||
(CPLast <$ "count=" <*> A.decimal)
|
||||
<|> (CPAfter <$ "after=" <*> A.decimal <* A.space <* "count=" <*> A.decimal)
|
||||
|
||||
@@ -96,7 +96,7 @@ data ChatCommand
|
||||
| CreateActiveUser Profile
|
||||
| StartChat
|
||||
| SetFilesFolder FilePath
|
||||
| APIGetChats
|
||||
| APIGetChats {pendingConnections :: Bool}
|
||||
| APIGetChat ChatType Int64 ChatPagination
|
||||
| APIGetChatItems Int
|
||||
| APISendMessage ChatType Int64 (Maybe FilePath) (Maybe ChatItemId) MsgContent
|
||||
@@ -246,6 +246,8 @@ data ChatResponse
|
||||
| CRUserContactLinkSubscribed
|
||||
| CRUserContactLinkSubError {chatError :: ChatError}
|
||||
| CRNtfTokenStatus {status :: NtfTknStatus}
|
||||
| CRNewContactConnection {connection :: PendingContactConnection}
|
||||
| CRContactConnectionDeleted {connection :: PendingContactConnection}
|
||||
| CRMessageError {severity :: Text, errorMessage :: Text}
|
||||
| CRChatCmdError {chatError :: ChatError}
|
||||
| CRChatError {chatError :: ChatError}
|
||||
|
||||
@@ -38,7 +38,7 @@ import Simplex.Messaging.Parsers (dropPrefix, enumJSON, fromTextField_, singleFi
|
||||
import Simplex.Messaging.Protocol (MsgBody)
|
||||
import Simplex.Messaging.Util ((<$?>))
|
||||
|
||||
data ChatType = CTDirect | CTGroup | CTContactRequest
|
||||
data ChatType = CTDirect | CTGroup | CTContactRequest | CTContactConnection
|
||||
deriving (Show, Generic)
|
||||
|
||||
instance ToJSON ChatType where
|
||||
@@ -49,6 +49,7 @@ data ChatInfo (c :: ChatType) where
|
||||
DirectChat :: Contact -> ChatInfo 'CTDirect
|
||||
GroupChat :: GroupInfo -> ChatInfo 'CTGroup
|
||||
ContactRequest :: UserContactRequest -> ChatInfo 'CTContactRequest
|
||||
ContactConnection :: PendingContactConnection -> ChatInfo 'CTContactConnection
|
||||
|
||||
deriving instance Show (ChatInfo c)
|
||||
|
||||
@@ -56,6 +57,7 @@ data JSONChatInfo
|
||||
= JCInfoDirect {contact :: Contact}
|
||||
| JCInfoGroup {groupInfo :: GroupInfo}
|
||||
| JCInfoContactRequest {contactRequest :: UserContactRequest}
|
||||
| JCInfoContactConnection {contactConnection :: PendingContactConnection}
|
||||
deriving (Generic)
|
||||
|
||||
instance ToJSON JSONChatInfo where
|
||||
@@ -71,6 +73,7 @@ jsonChatInfo = \case
|
||||
DirectChat c -> JCInfoDirect c
|
||||
GroupChat g -> JCInfoGroup g
|
||||
ContactRequest g -> JCInfoContactRequest g
|
||||
ContactConnection c -> JCInfoContactConnection c
|
||||
|
||||
data ChatItem (c :: ChatType) (d :: MsgDirection) = ChatItem
|
||||
{ chatDir :: CIDirection c d,
|
||||
@@ -519,12 +522,15 @@ data SChatType (c :: ChatType) where
|
||||
SCTDirect :: SChatType 'CTDirect
|
||||
SCTGroup :: SChatType 'CTGroup
|
||||
SCTContactRequest :: SChatType 'CTContactRequest
|
||||
SCTContactConnection :: SChatType 'CTContactConnection
|
||||
|
||||
deriving instance Show (SChatType c)
|
||||
|
||||
instance TestEquality SChatType where
|
||||
testEquality SCTDirect SCTDirect = Just Refl
|
||||
testEquality SCTGroup SCTGroup = Just Refl
|
||||
testEquality SCTContactRequest SCTContactRequest = Just Refl
|
||||
testEquality SCTContactConnection SCTContactConnection = Just Refl
|
||||
testEquality _ _ = Nothing
|
||||
|
||||
class ChatTypeI (c :: ChatType) where
|
||||
|
||||
@@ -151,6 +151,7 @@ module Simplex.Chat.Store
|
||||
updateGroupChatItemsRead,
|
||||
getSMPServers,
|
||||
overwriteSMPServers,
|
||||
deletePendingContactConnection,
|
||||
)
|
||||
where
|
||||
|
||||
@@ -171,7 +172,7 @@ import Data.Function (on)
|
||||
import Data.Functor (($>))
|
||||
import Data.Int (Int64)
|
||||
import Data.List (find, sortBy, sortOn)
|
||||
import Data.Maybe (fromMaybe, listToMaybe)
|
||||
import Data.Maybe (fromMaybe, isJust, listToMaybe)
|
||||
import Data.Ord (Down (..))
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
@@ -296,10 +297,11 @@ setActiveUser st userId = do
|
||||
DB.execute_ db "UPDATE users SET active_user = 0"
|
||||
DB.execute db "UPDATE users SET active_user = 1 WHERE user_id = ?" (Only userId)
|
||||
|
||||
createConnReqConnection :: MonadUnliftIO m => SQLiteStore -> UserId -> ConnId -> ConnReqUriHash -> XContactId -> m ()
|
||||
createConnReqConnection :: MonadUnliftIO m => SQLiteStore -> UserId -> ConnId -> ConnReqUriHash -> XContactId -> m PendingContactConnection
|
||||
createConnReqConnection st userId acId cReqHash xContactId = do
|
||||
liftIO . withTransaction st $ \db -> do
|
||||
currentTs <- getCurrentTime
|
||||
createdAt <- getCurrentTime
|
||||
let pccConnStatus = ConnJoined
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
@@ -308,7 +310,9 @@ createConnReqConnection st userId acId cReqHash xContactId = do
|
||||
created_at, updated_at, via_contact_uri_hash, xcontact_id
|
||||
) VALUES (?,?,?,?,?,?,?,?)
|
||||
|]
|
||||
(userId, acId, ConnNew, ConnContact, currentTs, currentTs, cReqHash, xContactId)
|
||||
(userId, acId, pccConnStatus, ConnContact, createdAt, createdAt, cReqHash, xContactId)
|
||||
pccConnId <- insertedRowId db
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = True, createdAt}
|
||||
|
||||
getConnReqContactXContactId :: MonadUnliftIO m => SQLiteStore -> UserId -> ConnReqUriHash -> m (Maybe Contact, Maybe XContactId)
|
||||
getConnReqContactXContactId st userId cReqHash = do
|
||||
@@ -345,11 +349,19 @@ getConnReqContactXContactId st userId cReqHash = do
|
||||
"SELECT xcontact_id FROM connections WHERE user_id = ? AND via_contact_uri_hash = ? LIMIT 1"
|
||||
(userId, cReqHash)
|
||||
|
||||
createDirectConnection :: MonadUnliftIO m => SQLiteStore -> UserId -> ConnId -> m ()
|
||||
createDirectConnection st userId agentConnId =
|
||||
createDirectConnection :: MonadUnliftIO m => SQLiteStore -> UserId -> ConnId -> ConnStatus -> m PendingContactConnection
|
||||
createDirectConnection st userId acId pccConnStatus =
|
||||
liftIO . withTransaction st $ \db -> do
|
||||
currentTs <- getCurrentTime
|
||||
void $ createContactConnection_ db userId agentConnId Nothing 0 currentTs
|
||||
createdAt <- getCurrentTime
|
||||
DB.execute
|
||||
db
|
||||
[sql|
|
||||
INSERT INTO connections
|
||||
(user_id, agent_conn_id, conn_status, conn_type, created_at, updated_at) VALUES (?,?,?,?,?,?)
|
||||
|]
|
||||
(userId, acId, pccConnStatus, ConnContact, createdAt, createdAt)
|
||||
pccConnId <- insertedRowId db
|
||||
pure PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, createdAt, viaContactUri = False}
|
||||
|
||||
createContactConnection_ :: DB.Connection -> UserId -> ConnId -> Maybe Int64 -> Int -> UTCTime -> IO Connection
|
||||
createContactConnection_ db userId = createConnection_ db userId ConnContact Nothing
|
||||
@@ -2500,13 +2512,14 @@ getChatItemQuote_ db User {userId, userContactId} chatDirection QuotedMsg {msgRe
|
||||
ciQuoteGroup [] = ciQuote Nothing $ CIQGroupRcv Nothing
|
||||
ciQuoteGroup ((Only itemId :. memberRow) : _) = ciQuote itemId . CIQGroupRcv . Just $ toGroupMember userContactId memberRow
|
||||
|
||||
getChatPreviews :: MonadUnliftIO m => SQLiteStore -> User -> m [AChat]
|
||||
getChatPreviews st user =
|
||||
getChatPreviews :: MonadUnliftIO m => SQLiteStore -> User -> Bool -> m [AChat]
|
||||
getChatPreviews st user withPCC =
|
||||
liftIO . withTransaction st $ \db -> do
|
||||
directChats <- getDirectChatPreviews_ db user
|
||||
groupChats <- getGroupChatPreviews_ db user
|
||||
cReqChats <- getContactRequestChatPreviews_ db user
|
||||
pure $ sortOn (Down . ts) (directChats <> groupChats <> cReqChats)
|
||||
connChats <- getContactConnectionChatPreviews_ db user withPCC
|
||||
pure $ sortOn (Down . ts) (directChats <> groupChats <> cReqChats <> connChats)
|
||||
where
|
||||
ts :: AChat -> UTCTime
|
||||
ts (AChat _ Chat {chatItems = ci : _}) = chatItemTs ci
|
||||
@@ -2514,6 +2527,7 @@ getChatPreviews st user =
|
||||
DirectChat Contact {createdAt} -> createdAt
|
||||
GroupChat GroupInfo {createdAt} -> createdAt
|
||||
ContactRequest UserContactRequest {createdAt} -> createdAt
|
||||
ContactConnection PendingContactConnection {createdAt} -> createdAt
|
||||
|
||||
chatItemTs :: CChatItem d -> UTCTime
|
||||
chatItemTs (CChatItem _ ChatItem {meta = CIMeta {itemTs}}) = itemTs
|
||||
@@ -2671,6 +2685,45 @@ getContactRequestChatPreviews_ db User {userId} =
|
||||
stats = ChatStats {unreadCount = 0, minUnreadItemId = 0}
|
||||
in AChat SCTContactRequest $ Chat (ContactRequest cReq) [] stats
|
||||
|
||||
getContactConnectionChatPreviews_ :: DB.Connection -> User -> Bool -> IO [AChat]
|
||||
getContactConnectionChatPreviews_ _ _ False = pure []
|
||||
getContactConnectionChatPreviews_ db User {userId} _ =
|
||||
map toContactConnectionChatPreview
|
||||
<$> DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, created_at
|
||||
FROM connections
|
||||
WHERE user_id = ? AND conn_type = ? AND contact_id IS NULL AND conn_level = 0 AND via_contact IS NULL
|
||||
|]
|
||||
(userId, ConnContact)
|
||||
where
|
||||
toContactConnectionChatPreview :: (Int64, ConnId, ConnStatus, Maybe ByteString, UTCTime) -> AChat
|
||||
toContactConnectionChatPreview connRow =
|
||||
let conn = toPendingContactConnection connRow
|
||||
stats = ChatStats {unreadCount = 0, minUnreadItemId = 0}
|
||||
in AChat SCTContactConnection $ Chat (ContactConnection conn) [] stats
|
||||
|
||||
deletePendingContactConnection :: StoreMonad m => SQLiteStore -> UserId -> Int64 -> m PendingContactConnection
|
||||
deletePendingContactConnection st userId connId =
|
||||
liftIOEither . withTransaction st $ \db -> runExceptT $ do
|
||||
conn <-
|
||||
ExceptT . firstRow toPendingContactConnection (SEPendingConnectionNotFound connId) $
|
||||
DB.query
|
||||
db
|
||||
[sql|
|
||||
SELECT connection_id, agent_conn_id, conn_status, via_contact_uri_hash, created_at
|
||||
FROM connections
|
||||
WHERE user_id = ? AND conn_type = ? AND contact_id IS NULL AND conn_level = 0 AND via_contact IS NULL
|
||||
|]
|
||||
(userId, ConnContact)
|
||||
liftIO $ DB.execute db "DELETE FROM connections WHERE connection_id = ?" (Only connId)
|
||||
pure conn
|
||||
|
||||
toPendingContactConnection :: (Int64, ConnId, ConnStatus, Maybe ByteString, UTCTime) -> PendingContactConnection
|
||||
toPendingContactConnection (pccConnId, acId, pccConnStatus, connReqHash, createdAt) =
|
||||
PendingContactConnection {pccConnId, pccAgentConnId = AgentConnId acId, pccConnStatus, viaContactUri = isJust connReqHash, createdAt}
|
||||
|
||||
getDirectChat :: StoreMonad m => SQLiteStore -> User -> Int64 -> ChatPagination -> m (Chat 'CTDirect)
|
||||
getDirectChat st user contactId pagination =
|
||||
liftIOEither . withTransaction st $ \db -> runExceptT $ do
|
||||
@@ -3646,6 +3699,7 @@ data StoreError
|
||||
| SESharedMsgIdNotFoundByFileId {fileId :: FileTransferId}
|
||||
| SEFileIdNotFoundBySharedMsgId {sharedMsgId :: SharedMsgId}
|
||||
| SEConnectionNotFound {agentConnId :: AgentConnId}
|
||||
| SEPendingConnectionNotFound {connId :: Int64}
|
||||
| SEIntroNotFound
|
||||
| SEUniqueID
|
||||
| SEInternalError {message :: String}
|
||||
|
||||
@@ -72,7 +72,7 @@ data Contact = Contact
|
||||
viaGroup :: Maybe Int64,
|
||||
createdAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON Contact where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -101,7 +101,7 @@ data UserContactRequest = UserContactRequest
|
||||
createdAt :: UTCTime,
|
||||
xContactId :: Maybe XContactId
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON UserContactRequest where
|
||||
toEncoding = J.genericToEncoding J.defaultOptions
|
||||
@@ -160,7 +160,7 @@ data GroupInfo = GroupInfo
|
||||
membership :: GroupMember,
|
||||
createdAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON GroupInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -262,7 +262,7 @@ data GroupMember = GroupMember
|
||||
memberContactId :: Maybe Int64,
|
||||
activeConn :: Maybe Connection
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON GroupMember where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
@@ -306,9 +306,6 @@ instance ToJSON MemberId where
|
||||
data InvitedBy = IBContact {byContactId :: Int64} | IBUser | IBUnknown
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON InvitedBy where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "IB"
|
||||
|
||||
instance ToJSON InvitedBy where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "IB"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "IB"
|
||||
@@ -401,8 +398,6 @@ instance FromField GroupMemberCategory where fromField = fromTextField_ textDeco
|
||||
|
||||
instance ToField GroupMemberCategory where toField = toField . textEncode
|
||||
|
||||
instance FromJSON GroupMemberCategory where parseJSON = textParseJSON "GroupMemberCategory"
|
||||
|
||||
instance ToJSON GroupMemberCategory where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -440,8 +435,6 @@ instance FromField GroupMemberStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField GroupMemberStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON GroupMemberStatus where parseJSON = textParseJSON "GroupMemberStatus"
|
||||
|
||||
instance ToJSON GroupMemberStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -536,7 +529,7 @@ data RcvFileTransfer = RcvFileTransfer
|
||||
cancelled :: Bool,
|
||||
grpMemberId :: Maybe Int64
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON RcvFileTransfer where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -548,9 +541,6 @@ data RcvFileStatus
|
||||
| RFSCancelled RcvFileInfo
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance FromJSON RcvFileStatus where
|
||||
parseJSON = J.genericParseJSON . sumTypeJSON $ dropPrefix "RFS"
|
||||
|
||||
instance ToJSON RcvFileStatus where
|
||||
toJSON = J.genericToJSON . sumTypeJSON $ dropPrefix "RFS"
|
||||
toEncoding = J.genericToEncoding . sumTypeJSON $ dropPrefix "RFS"
|
||||
@@ -560,7 +550,7 @@ data RcvFileInfo = RcvFileInfo
|
||||
connId :: Int64,
|
||||
agentConnId :: AgentConnId
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON RcvFileInfo where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
@@ -572,9 +562,6 @@ instance StrEncoding AgentConnId where
|
||||
strDecode s = AgentConnId <$> strDecode s
|
||||
strP = AgentConnId <$> strP
|
||||
|
||||
instance FromJSON AgentConnId where
|
||||
parseJSON = strParseJSON "AgentConnId"
|
||||
|
||||
instance ToJSON AgentConnId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -591,9 +578,6 @@ instance StrEncoding AgentInvId where
|
||||
strDecode s = AgentInvId <$> strDecode s
|
||||
strP = AgentInvId <$> strP
|
||||
|
||||
instance FromJSON AgentInvId where
|
||||
parseJSON = strParseJSON "AgentInvId"
|
||||
|
||||
instance ToJSON AgentInvId where
|
||||
toJSON = strToJSON
|
||||
toEncoding = strToJEncoding
|
||||
@@ -636,8 +620,6 @@ instance FromField FileStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField FileStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON FileStatus where parseJSON = textParseJSON "FileStatus"
|
||||
|
||||
instance ToJSON FileStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -674,7 +656,7 @@ data Connection = Connection
|
||||
entityId :: Maybe Int64, -- contact, group member, file ID or user contact ID
|
||||
createdAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic, FromJSON)
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
aConnId :: Connection -> ConnId
|
||||
aConnId Connection {agentConnId = AgentConnId cId} = cId
|
||||
@@ -683,6 +665,17 @@ instance ToJSON Connection where
|
||||
toJSON = J.genericToJSON J.defaultOptions {J.omitNothingFields = True}
|
||||
toEncoding = J.genericToEncoding J.defaultOptions {J.omitNothingFields = True}
|
||||
|
||||
data PendingContactConnection = PendingContactConnection
|
||||
{ pccConnId :: Int64,
|
||||
pccAgentConnId :: AgentConnId,
|
||||
pccConnStatus :: ConnStatus,
|
||||
viaContactUri :: Bool,
|
||||
createdAt :: UTCTime
|
||||
}
|
||||
deriving (Eq, Show, Generic)
|
||||
|
||||
instance ToJSON PendingContactConnection where toEncoding = J.genericToEncoding J.defaultOptions
|
||||
|
||||
data ConnStatus
|
||||
= -- | connection is created by initiating party with agent NEW command (createConnection)
|
||||
ConnNew
|
||||
@@ -704,8 +697,6 @@ instance FromField ConnStatus where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField ConnStatus where toField = toField . textEncode
|
||||
|
||||
instance FromJSON ConnStatus where parseJSON = textParseJSON "ConnStatus"
|
||||
|
||||
instance ToJSON ConnStatus where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
@@ -736,8 +727,6 @@ instance FromField ConnType where fromField = fromTextField_ textDecode
|
||||
|
||||
instance ToField ConnType where toField = toField . textEncode
|
||||
|
||||
instance FromJSON ConnType where parseJSON = textParseJSON "ConnType"
|
||||
|
||||
instance ToJSON ConnType where
|
||||
toJSON = J.String . textEncode
|
||||
toEncoding = JE.text . textEncode
|
||||
|
||||
@@ -141,6 +141,8 @@ responseToView testView = \case
|
||||
["received file " <> sShow fileId <> " (" <> plain fileName <> ") error: " <> sShow e]
|
||||
CRUserContactLinkSubscribed -> ["Your address is active! To show: " <> highlight' "/sa"]
|
||||
CRUserContactLinkSubError e -> ["user address error: " <> sShow e, "to delete your address: " <> highlight' "/da"]
|
||||
CRNewContactConnection _ -> []
|
||||
CRContactConnectionDeleted _ -> []
|
||||
CRNtfTokenStatus status -> ["device token status: " <> plain (smpEncode status)]
|
||||
CRMessageError prefix err -> [plain prefix <> ": " <> plain err]
|
||||
CRChatError e -> viewChatError e
|
||||
@@ -152,6 +154,7 @@ responseToView testView = \case
|
||||
toChatView (AChat _ (Chat (DirectChat Contact {localDisplayName}) items _)) = ("@" <> localDisplayName, toCIPreview items)
|
||||
toChatView (AChat _ (Chat (GroupChat GroupInfo {localDisplayName}) items _)) = ("#" <> localDisplayName, toCIPreview items)
|
||||
toChatView (AChat _ (Chat (ContactRequest UserContactRequest {localDisplayName}) items _)) = ("<@" <> localDisplayName, toCIPreview items)
|
||||
toChatView (AChat _ (Chat (ContactConnection PendingContactConnection {pccConnId}) items _)) = (":" <> T.pack (show pccConnId), toCIPreview items)
|
||||
toCIPreview :: [CChatItem c] -> Text
|
||||
toCIPreview ((CChatItem _ ChatItem {meta}) : _) = itemText meta
|
||||
toCIPreview _ = ""
|
||||
|
||||
Reference in New Issue
Block a user