mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2025-06-28 20:29:53 +00:00
core: multi forward api (#4704)
This commit is contained in:
parent
c485837910
commit
791489e943
21 changed files with 601 additions and 343 deletions
|
@ -1848,7 +1848,6 @@ public enum ChatErrorType: Decodable, Hashable {
|
||||||
case inlineFileProhibited(fileId: Int64)
|
case inlineFileProhibited(fileId: Int64)
|
||||||
case invalidQuote
|
case invalidQuote
|
||||||
case invalidForward
|
case invalidForward
|
||||||
case forwardNoFile
|
|
||||||
case invalidChatItemUpdate
|
case invalidChatItemUpdate
|
||||||
case invalidChatItemDelete
|
case invalidChatItemDelete
|
||||||
case hasCurrentCall
|
case hasCurrentCall
|
||||||
|
|
|
@ -46,7 +46,7 @@ mySquaringBot _user cc = do
|
||||||
CRContactConnected _ contact _ -> do
|
CRContactConnected _ contact _ -> do
|
||||||
contactConnected contact
|
contactConnected contact
|
||||||
sendMessage cc contact welcomeMessage
|
sendMessage cc contact welcomeMessage
|
||||||
CRNewChatItem _ (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) -> do
|
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) : _} -> do
|
||||||
let msg = T.unpack $ ciContentToText mc
|
let msg = T.unpack $ ciContentToText mc
|
||||||
number_ = readMaybe msg :: Maybe Integer
|
number_ = readMaybe msg :: Maybe Integer
|
||||||
sendMessage cc contact $ case number_ of
|
sendMessage cc contact $ case number_ of
|
||||||
|
|
|
@ -40,7 +40,7 @@ broadcastBot BroadcastBotOpts {publishers, welcomeMessage, prohibitedMessage} _u
|
||||||
CRContactConnected _ ct _ -> do
|
CRContactConnected _ ct _ -> do
|
||||||
contactConnected ct
|
contactConnected ct
|
||||||
sendMessage cc ct welcomeMessage
|
sendMessage cc ct welcomeMessage
|
||||||
CRNewChatItem _ (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc})
|
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc}) : _}
|
||||||
| publisher `elem` publishers ->
|
| publisher `elem` publishers ->
|
||||||
if allowContent mc
|
if allowContent mc
|
||||||
then do
|
then do
|
||||||
|
|
|
@ -73,7 +73,7 @@ crDirectoryEvent = \case
|
||||||
CRGroupDeleted {groupInfo} -> Just $ DEGroupDeleted groupInfo
|
CRGroupDeleted {groupInfo} -> Just $ DEGroupDeleted groupInfo
|
||||||
CRChatItemUpdated {chatItem = AChatItem _ SMDRcv (DirectChat ct) _} -> Just $ DEItemEditIgnored ct
|
CRChatItemUpdated {chatItem = AChatItem _ SMDRcv (DirectChat ct) _} -> Just $ DEItemEditIgnored ct
|
||||||
CRChatItemsDeleted {chatItemDeletions = ((ChatItemDeletion (AChatItem _ SMDRcv (DirectChat ct) _) _) : _), byUser = False} -> Just $ DEItemDeleteIgnored ct
|
CRChatItemsDeleted {chatItemDeletions = ((ChatItemDeletion (AChatItem _ SMDRcv (DirectChat ct) _) _) : _), byUser = False} -> Just $ DEItemDeleteIgnored ct
|
||||||
CRNewChatItem {chatItem = AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc, meta = CIMeta {itemLive}}} ->
|
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat ct) ci@ChatItem {content = CIRcvMsgContent mc, meta = CIMeta {itemLive}}) : _} ->
|
||||||
Just $ case (mc, itemLive) of
|
Just $ case (mc, itemLive) of
|
||||||
(MCText t, Nothing) -> DEContactCommand ct ciId $ fromRight err $ A.parseOnly (directoryCmdP <* A.endOfInput) $ T.dropWhileEnd isSpace t
|
(MCText t, Nothing) -> DEContactCommand ct ciId $ fromRight err $ A.parseOnly (directoryCmdP <* A.endOfInput) $ T.dropWhileEnd isSpace t
|
||||||
_ -> DEUnsupportedMessage ct ciId
|
_ -> DEUnsupportedMessage ct ciId
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@ import Control.Concurrent.Async
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
import qualified Data.ByteString.Char8 as B
|
import qualified Data.ByteString.Char8 as B
|
||||||
|
import Data.List.NonEmpty (NonEmpty (..))
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Simplex.Chat.Controller
|
import Simplex.Chat.Controller
|
||||||
import Simplex.Chat.Core
|
import Simplex.Chat.Core
|
||||||
|
@ -31,7 +32,7 @@ chatBotRepl welcome answer _user cc = do
|
||||||
CRContactConnected _ contact _ -> do
|
CRContactConnected _ contact _ -> do
|
||||||
contactConnected contact
|
contactConnected contact
|
||||||
void $ sendMessage cc contact welcome
|
void $ sendMessage cc contact welcome
|
||||||
CRNewChatItem _ (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) -> do
|
CRNewChatItems {chatItems = (AChatItem _ SMDRcv (DirectChat contact) ChatItem {content = mc@CIRcvMsgContent {}}) : _} -> do
|
||||||
let msg = T.unpack $ ciContentToText mc
|
let msg = T.unpack $ ciContentToText mc
|
||||||
void $ sendMessage cc contact =<< answer contact msg
|
void $ sendMessage cc contact =<< answer contact msg
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
|
@ -68,8 +69,8 @@ sendComposedMessage cc = sendComposedMessage' cc . contactId'
|
||||||
sendComposedMessage' :: ChatController -> ContactId -> Maybe ChatItemId -> MsgContent -> IO ()
|
sendComposedMessage' :: ChatController -> ContactId -> Maybe ChatItemId -> MsgContent -> IO ()
|
||||||
sendComposedMessage' cc ctId quotedItemId msgContent = do
|
sendComposedMessage' cc ctId quotedItemId msgContent = do
|
||||||
let cm = ComposedMessage {fileSource = Nothing, quotedItemId, msgContent}
|
let cm = ComposedMessage {fileSource = Nothing, quotedItemId, msgContent}
|
||||||
sendChatCmd cc (APISendMessage (ChatRef CTDirect ctId) False Nothing cm) >>= \case
|
sendChatCmd cc (APISendMessages (ChatRef CTDirect ctId) False Nothing (cm :| [])) >>= \case
|
||||||
CRNewChatItem {} -> printLog cc CLLInfo $ "sent message to contact ID " <> show ctId
|
CRNewChatItems {} -> printLog cc CLLInfo $ "sent message to contact ID " <> show ctId
|
||||||
r -> putStrLn $ "unexpected send message response: " <> show r
|
r -> putStrLn $ "unexpected send message response: " <> show r
|
||||||
|
|
||||||
deleteMessage :: ChatController -> Contact -> ChatItemId -> IO ()
|
deleteMessage :: ChatController -> Contact -> ChatItemId -> IO ()
|
||||||
|
|
|
@ -292,13 +292,13 @@ data ChatCommand
|
||||||
| APIGetChat ChatRef ChatPagination (Maybe String)
|
| APIGetChat ChatRef ChatPagination (Maybe String)
|
||||||
| APIGetChatItems ChatPagination (Maybe String)
|
| APIGetChatItems ChatPagination (Maybe String)
|
||||||
| APIGetChatItemInfo ChatRef ChatItemId
|
| APIGetChatItemInfo ChatRef ChatItemId
|
||||||
| APISendMessage {chatRef :: ChatRef, liveMessage :: Bool, ttl :: Maybe Int, composedMessage :: ComposedMessage}
|
| APISendMessages {chatRef :: ChatRef, liveMessage :: Bool, ttl :: Maybe Int, composedMessages :: NonEmpty ComposedMessage}
|
||||||
| APICreateChatItem {noteFolderId :: NoteFolderId, composedMessage :: ComposedMessage}
|
| APICreateChatItems {noteFolderId :: NoteFolderId, composedMessages :: NonEmpty ComposedMessage}
|
||||||
| APIUpdateChatItem {chatRef :: ChatRef, chatItemId :: ChatItemId, liveMessage :: Bool, msgContent :: MsgContent}
|
| APIUpdateChatItem {chatRef :: ChatRef, chatItemId :: ChatItemId, liveMessage :: Bool, msgContent :: MsgContent}
|
||||||
| APIDeleteChatItem ChatRef (NonEmpty ChatItemId) CIDeleteMode
|
| APIDeleteChatItem ChatRef (NonEmpty ChatItemId) CIDeleteMode
|
||||||
| APIDeleteMemberChatItem GroupId (NonEmpty ChatItemId)
|
| APIDeleteMemberChatItem GroupId (NonEmpty ChatItemId)
|
||||||
| APIChatItemReaction {chatRef :: ChatRef, chatItemId :: ChatItemId, add :: Bool, reaction :: MsgReaction}
|
| APIChatItemReaction {chatRef :: ChatRef, chatItemId :: ChatItemId, add :: Bool, reaction :: MsgReaction}
|
||||||
| APIForwardChatItem {toChatRef :: ChatRef, fromChatRef :: ChatRef, chatItemId :: ChatItemId, ttl :: Maybe Int}
|
| APIForwardChatItems {toChatRef :: ChatRef, fromChatRef :: ChatRef, chatItemIds :: NonEmpty ChatItemId, ttl :: Maybe Int}
|
||||||
| APIUserRead UserId
|
| APIUserRead UserId
|
||||||
| UserRead
|
| UserRead
|
||||||
| APIChatRead ChatRef (Maybe (ChatItemId, ChatItemId))
|
| APIChatRead ChatRef (Maybe (ChatItemId, ChatItemId))
|
||||||
|
@ -597,7 +597,7 @@ data ChatResponse
|
||||||
| CRContactCode {user :: User, contact :: Contact, connectionCode :: Text}
|
| CRContactCode {user :: User, contact :: Contact, connectionCode :: Text}
|
||||||
| CRGroupMemberCode {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionCode :: Text}
|
| CRGroupMemberCode {user :: User, groupInfo :: GroupInfo, member :: GroupMember, connectionCode :: Text}
|
||||||
| CRConnectionVerified {user :: User, verified :: Bool, expectedCode :: Text}
|
| CRConnectionVerified {user :: User, verified :: Bool, expectedCode :: Text}
|
||||||
| CRNewChatItem {user :: User, chatItem :: AChatItem}
|
| CRNewChatItems {user :: User, chatItems :: [AChatItem]}
|
||||||
| CRChatItemStatusUpdated {user :: User, chatItem :: AChatItem}
|
| CRChatItemStatusUpdated {user :: User, chatItem :: AChatItem}
|
||||||
| CRChatItemUpdated {user :: User, chatItem :: AChatItem}
|
| CRChatItemUpdated {user :: User, chatItem :: AChatItem}
|
||||||
| CRChatItemNotChanged {user :: User, chatItem :: AChatItem}
|
| CRChatItemNotChanged {user :: User, chatItem :: AChatItem}
|
||||||
|
@ -1178,7 +1178,6 @@ data ChatErrorType
|
||||||
| CEInlineFileProhibited {fileId :: FileTransferId}
|
| CEInlineFileProhibited {fileId :: FileTransferId}
|
||||||
| CEInvalidQuote
|
| CEInvalidQuote
|
||||||
| CEInvalidForward
|
| CEInvalidForward
|
||||||
| CEForwardNoFile
|
|
||||||
| CEInvalidChatItemUpdate
|
| CEInvalidChatItemUpdate
|
||||||
| CEInvalidChatItemDelete
|
| CEInvalidChatItemDelete
|
||||||
| CEHasCurrentCall
|
| CEHasCurrentCall
|
||||||
|
|
|
@ -17,16 +17,18 @@ import Simplex.Chat.Messages
|
||||||
|
|
||||||
data MsgBatch = MsgBatch ByteString [SndMessage]
|
data MsgBatch = MsgBatch ByteString [SndMessage]
|
||||||
|
|
||||||
-- | Batches [SndMessage] into batches of ByteStrings in form of JSON arrays.
|
-- | Batches SndMessages in [Either ChatError SndMessage] into batches of ByteStrings in form of JSON arrays.
|
||||||
|
-- Preserves original errors in the list.
|
||||||
-- Does not check if the resulting batch is a valid JSON.
|
-- Does not check if the resulting batch is a valid JSON.
|
||||||
-- If a single element is passed, it is returned as is (a JSON string).
|
-- If a single element is passed, it is returned as is (a JSON string).
|
||||||
-- If an element exceeds maxLen, it is returned as ChatError.
|
-- If an element exceeds maxLen, it is returned as ChatError.
|
||||||
batchMessages :: Int -> [SndMessage] -> [Either ChatError MsgBatch]
|
batchMessages :: Int -> [Either ChatError SndMessage] -> [Either ChatError MsgBatch]
|
||||||
batchMessages maxLen = addBatch . foldr addToBatch ([], [], 0, 0)
|
batchMessages maxLen = addBatch . foldr addToBatch ([], [], 0, 0)
|
||||||
where
|
where
|
||||||
msgBatch batch = Right (MsgBatch (encodeMessages batch) batch)
|
msgBatch batch = Right (MsgBatch (encodeMessages batch) batch)
|
||||||
addToBatch :: SndMessage -> ([Either ChatError MsgBatch], [SndMessage], Int, Int) -> ([Either ChatError MsgBatch], [SndMessage], Int, Int)
|
addToBatch :: Either ChatError SndMessage -> ([Either ChatError MsgBatch], [SndMessage], Int, Int) -> ([Either ChatError MsgBatch], [SndMessage], Int, Int)
|
||||||
addToBatch msg@SndMessage {msgBody} acc@(batches, batch, len, n)
|
addToBatch (Left err) acc = (Left err : addBatch acc, [], 0, 0) -- step over original error
|
||||||
|
addToBatch (Right msg@SndMessage {msgBody}) acc@(batches, batch, len, n)
|
||||||
| batchLen <= maxLen = (batches, msg : batch, len', n + 1)
|
| batchLen <= maxLen = (batches, msg : batch, len', n + 1)
|
||||||
| msgLen <= maxLen = (addBatch acc, [msg], msgLen, 1)
|
| msgLen <= maxLen = (addBatch acc, [msg], msgLen, 1)
|
||||||
| otherwise = (errLarge msg : addBatch acc, [], 0, 0)
|
| otherwise = (errLarge msg : addBatch acc, [], 0, 0)
|
||||||
|
|
|
@ -966,20 +966,20 @@ lookupFileTransferRedirectMeta db User {userId} fileId = do
|
||||||
redirects <- DB.query db "SELECT file_id FROM files WHERE user_id = ? AND redirect_file_id = ?" (userId, fileId)
|
redirects <- DB.query db "SELECT file_id FROM files WHERE user_id = ? AND redirect_file_id = ?" (userId, fileId)
|
||||||
rights <$> mapM (runExceptT . getFileTransferMeta_ db userId . fromOnly) redirects
|
rights <$> mapM (runExceptT . getFileTransferMeta_ db userId . fromOnly) redirects
|
||||||
|
|
||||||
createLocalFile :: ToField (CIFileStatus d) => CIFileStatus d -> DB.Connection -> User -> NoteFolder -> ChatItemId -> UTCTime -> CryptoFile -> Integer -> Integer -> IO Int64
|
createLocalFile :: ToField (CIFileStatus d) => CIFileStatus d -> DB.Connection -> User -> NoteFolder -> UTCTime -> CryptoFile -> Integer -> Integer -> IO Int64
|
||||||
createLocalFile fileStatus db User {userId} NoteFolder {noteFolderId} chatItemId itemTs CryptoFile {filePath, cryptoArgs} fileSize fileChunkSize = do
|
createLocalFile fileStatus db User {userId} NoteFolder {noteFolderId} itemTs CryptoFile {filePath, cryptoArgs} fileSize fileChunkSize = do
|
||||||
DB.execute
|
DB.execute
|
||||||
db
|
db
|
||||||
[sql|
|
[sql|
|
||||||
INSERT INTO files
|
INSERT INTO files
|
||||||
( user_id, note_folder_id, chat_item_id,
|
( user_id, note_folder_id,
|
||||||
file_name, file_path, file_size,
|
file_name, file_path, file_size,
|
||||||
file_crypto_key, file_crypto_nonce,
|
file_crypto_key, file_crypto_nonce,
|
||||||
chunk_size, file_inline, ci_file_status, protocol, created_at, updated_at
|
chunk_size, file_inline, ci_file_status, protocol, created_at, updated_at
|
||||||
)
|
)
|
||||||
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||||
|]
|
|]
|
||||||
( (userId, noteFolderId, chatItemId)
|
( (userId, noteFolderId)
|
||||||
:. (takeFileName filePath, filePath, fileSize)
|
:. (takeFileName filePath, filePath, fileSize)
|
||||||
:. maybe (Nothing, Nothing) (\(CFArgs key nonce) -> (Just key, Just nonce)) cryptoArgs
|
:. maybe (Nothing, Nothing) (\(CFArgs key nonce) -> (Just key, Just nonce)) cryptoArgs
|
||||||
:. (fileChunkSize, Nothing :: Maybe InlineFileMode, fileStatus, FPLocal, itemTs, itemTs)
|
:. (fileChunkSize, Nothing :: Maybe InlineFileMode, fileStatus, FPLocal, itemTs, itemTs)
|
||||||
|
|
|
@ -69,7 +69,7 @@ runInputLoop ct@ChatTerminal {termState, liveMessageState} cc = forever $ do
|
||||||
Nothing -> setActive ct ""
|
Nothing -> setActive ct ""
|
||||||
Just rhId -> updateRemoteUser ct u rhId
|
Just rhId -> updateRemoteUser ct u rhId
|
||||||
CRChatItems u chatName_ _ -> whenCurrUser cc u $ mapM_ (setActive ct . chatActiveTo) chatName_
|
CRChatItems u chatName_ _ -> whenCurrUser cc u $ mapM_ (setActive ct . chatActiveTo) chatName_
|
||||||
CRNewChatItem u (AChatItem _ SMDSnd cInfo _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
CRNewChatItems u ((AChatItem _ SMDSnd cInfo _) : _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||||
CRChatItemUpdated u (AChatItem _ SMDSnd cInfo _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
CRChatItemUpdated u (AChatItem _ SMDSnd cInfo _) -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||||
CRChatItemsDeleted u ((ChatItemDeletion (AChatItem _ _ cInfo _) _) : _) _ _ -> whenCurrUser cc u $ setActiveChat ct cInfo
|
CRChatItemsDeleted u ((ChatItemDeletion (AChatItem _ _ cInfo _) _) : _) _ _ -> whenCurrUser cc u $ setActiveChat ct cInfo
|
||||||
CRContactDeleted u c -> whenCurrUser cc u $ unsetActiveContact ct c
|
CRContactDeleted u c -> whenCurrUser cc u $ unsetActiveContact ct c
|
||||||
|
@ -93,7 +93,7 @@ runInputLoop ct@ChatTerminal {termState, liveMessageState} cc = forever $ do
|
||||||
Right SendMessageBroadcast {} -> True
|
Right SendMessageBroadcast {} -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
startLiveMessage :: Either a ChatCommand -> ChatResponse -> IO ()
|
startLiveMessage :: Either a ChatCommand -> ChatResponse -> IO ()
|
||||||
startLiveMessage (Right (SendLiveMessage chatName msg)) (CRNewChatItem _ (AChatItem cType SMDSnd _ ChatItem {meta = CIMeta {itemId}})) = do
|
startLiveMessage (Right (SendLiveMessage chatName msg)) (CRNewChatItems {chatItems = [AChatItem cType SMDSnd _ ChatItem {meta = CIMeta {itemId}}]}) = do
|
||||||
whenM (isNothing <$> readTVarIO liveMessageState) $ do
|
whenM (isNothing <$> readTVarIO liveMessageState) $ do
|
||||||
let s = T.unpack msg
|
let s = T.unpack msg
|
||||||
int = case cType of SCTGroup -> 5000000; _ -> 3000000 :: Int
|
int = case cType of SCTGroup -> 5000000; _ -> 3000000 :: Int
|
||||||
|
|
|
@ -44,7 +44,7 @@ simplexChatCLI' cfg opts@ChatOpts {chatCmd, chatCmdLog, chatCmdDelay, chatServer
|
||||||
when (chatCmdLog /= CCLNone) . void . forkIO . forever $ do
|
when (chatCmdLog /= CCLNone) . void . forkIO . forever $ do
|
||||||
(_, _, r') <- atomically . readTBQueue $ outputQ cc
|
(_, _, r') <- atomically . readTBQueue $ outputQ cc
|
||||||
case r' of
|
case r' of
|
||||||
CRNewChatItem {} -> printResponse r'
|
CRNewChatItems {} -> printResponse r'
|
||||||
_ -> when (chatCmdLog == CCLAll) $ printResponse r'
|
_ -> when (chatCmdLog == CCLAll) $ printResponse r'
|
||||||
sendChatCmdStr cc chatCmd >>= printResponse
|
sendChatCmdStr cc chatCmd >>= printResponse
|
||||||
threadDelay $ chatCmdDelay * 1000000
|
threadDelay $ chatCmdDelay * 1000000
|
||||||
|
|
|
@ -147,7 +147,7 @@ runTerminalOutput ct cc@ChatController {outputQ, showLiveItems, logFilePath} Cha
|
||||||
forever $ do
|
forever $ do
|
||||||
(_, outputRH, r) <- atomically $ readTBQueue outputQ
|
(_, outputRH, r) <- atomically $ readTBQueue outputQ
|
||||||
case r of
|
case r of
|
||||||
CRNewChatItem u ci -> when markRead $ markChatItemRead u ci
|
CRNewChatItems u (ci : _) -> when markRead $ markChatItemRead u ci -- At the moment of writing received items are created one at a time
|
||||||
CRChatItemUpdated u ci -> when markRead $ markChatItemRead u ci
|
CRChatItemUpdated u ci -> when markRead $ markChatItemRead u ci
|
||||||
CRRemoteHostConnected {remoteHost = RemoteHostInfo {remoteHostId}} -> getRemoteUser remoteHostId
|
CRRemoteHostConnected {remoteHost = RemoteHostInfo {remoteHostId}} -> getRemoteUser remoteHostId
|
||||||
CRRemoteHostStopped {remoteHostId_} -> mapM_ removeRemoteUser remoteHostId_
|
CRRemoteHostStopped {remoteHostId_} -> mapM_ removeRemoteUser remoteHostId_
|
||||||
|
@ -175,7 +175,8 @@ runTerminalOutput ct cc@ChatController {outputQ, showLiveItems, logFilePath} Cha
|
||||||
|
|
||||||
responseNotification :: ChatTerminal -> ChatController -> ChatResponse -> IO ()
|
responseNotification :: ChatTerminal -> ChatController -> ChatResponse -> IO ()
|
||||||
responseNotification t@ChatTerminal {sendNotification} cc = \case
|
responseNotification t@ChatTerminal {sendNotification} cc = \case
|
||||||
CRNewChatItem u (AChatItem _ SMDRcv cInfo ci@ChatItem {chatDir, content = CIRcvMsgContent mc, formattedText}) ->
|
-- At the moment of writing received items are created one at a time
|
||||||
|
CRNewChatItems u ((AChatItem _ SMDRcv cInfo ci@ChatItem {chatDir, content = CIRcvMsgContent mc, formattedText}) : _) ->
|
||||||
when (chatDirNtf u cInfo chatDir $ isMention ci) $ do
|
when (chatDirNtf u cInfo chatDir $ isMention ci) $ do
|
||||||
whenCurrUser cc u $ setActiveChat t cInfo
|
whenCurrUser cc u $ setActiveChat t cInfo
|
||||||
case (cInfo, chatDir) of
|
case (cInfo, chatDir) of
|
||||||
|
|
|
@ -120,7 +120,10 @@ responseToView hu@(currentRH, user_) ChatConfig {logLevel, showReactions, showRe
|
||||||
CRConnectionVerified u verified code -> ttyUser u [plain $ if verified then "connection verified" else "connection not verified, current code is " <> code]
|
CRConnectionVerified u verified code -> ttyUser u [plain $ if verified then "connection verified" else "connection not verified, current code is " <> code]
|
||||||
CRContactCode u ct code -> ttyUser u $ viewContactCode ct code testView
|
CRContactCode u ct code -> ttyUser u $ viewContactCode ct code testView
|
||||||
CRGroupMemberCode u g m code -> ttyUser u $ viewGroupMemberCode g m code testView
|
CRGroupMemberCode u g m code -> ttyUser u $ viewGroupMemberCode g m code testView
|
||||||
CRNewChatItem u (AChatItem _ _ chat item) -> ttyUser u $ unmuted u chat item $ viewChatItem chat item False ts tz <> viewItemReactions item
|
CRNewChatItems u chatItems ->
|
||||||
|
concatMap
|
||||||
|
(\(AChatItem _ _ chat item) -> ttyUser u $ unmuted u chat item $ viewChatItem chat item False ts tz <> viewItemReactions item)
|
||||||
|
chatItems
|
||||||
CRChatItems u _ chatItems -> ttyUser u $ concatMap (\(AChatItem _ _ chat item) -> viewChatItem chat item True ts tz <> viewItemReactions item) chatItems
|
CRChatItems u _ chatItems -> ttyUser u $ concatMap (\(AChatItem _ _ chat item) -> viewChatItem chat item True ts tz <> viewItemReactions item) chatItems
|
||||||
CRChatItemInfo u ci ciInfo -> ttyUser u $ viewChatItemInfo ci ciInfo tz
|
CRChatItemInfo u ci ciInfo -> ttyUser u $ viewChatItemInfo ci ciInfo tz
|
||||||
CRChatItemId u itemId -> ttyUser u [plain $ maybe "no item" show itemId]
|
CRChatItemId u itemId -> ttyUser u [plain $ maybe "no item" show itemId]
|
||||||
|
@ -2025,7 +2028,6 @@ viewChatError isCmd logLevel testView = \case
|
||||||
CEInlineFileProhibited _ -> ["A small file sent without acceptance - you can enable receiving such files with -f option."]
|
CEInlineFileProhibited _ -> ["A small file sent without acceptance - you can enable receiving such files with -f option."]
|
||||||
CEInvalidQuote -> ["cannot reply to this message"]
|
CEInvalidQuote -> ["cannot reply to this message"]
|
||||||
CEInvalidForward -> ["cannot forward this message"]
|
CEInvalidForward -> ["cannot forward this message"]
|
||||||
CEForwardNoFile -> ["cannot forward this message, file not found"]
|
|
||||||
CEInvalidChatItemUpdate -> ["cannot update this item"]
|
CEInvalidChatItemUpdate -> ["cannot update this item"]
|
||||||
CEInvalidChatItemDelete -> ["cannot delete this item"]
|
CEInvalidChatItemDelete -> ["cannot delete this item"]
|
||||||
CEHasCurrentCall -> ["call already in progress"]
|
CEHasCurrentCall -> ["call already in progress"]
|
||||||
|
|
|
@ -52,6 +52,7 @@ chatDirectTests = do
|
||||||
it "repeat AUTH errors disable contact" testRepeatAuthErrorsDisableContact
|
it "repeat AUTH errors disable contact" testRepeatAuthErrorsDisableContact
|
||||||
it "should send multiline message" testMultilineMessage
|
it "should send multiline message" testMultilineMessage
|
||||||
it "send large message" testLargeMessage
|
it "send large message" testLargeMessage
|
||||||
|
it "send multiple messages api" testSendMulti
|
||||||
describe "duplicate contacts" $ do
|
describe "duplicate contacts" $ do
|
||||||
it "duplicate contacts are separate (contacts don't merge)" testDuplicateContactsSeparate
|
it "duplicate contacts are separate (contacts don't merge)" testDuplicateContactsSeparate
|
||||||
it "new contact is separate with multiple duplicate contacts (contacts don't merge)" testDuplicateContactsMultipleSeparate
|
it "new contact is separate with multiple duplicate contacts (contacts don't merge)" testDuplicateContactsMultipleSeparate
|
||||||
|
@ -839,6 +840,18 @@ testLargeMessage =
|
||||||
bob <## "contact alice changed to alice2"
|
bob <## "contact alice changed to alice2"
|
||||||
bob <## "use @alice2 <message> to send messages"
|
bob <## "use @alice2 <message> to send messages"
|
||||||
|
|
||||||
|
testSendMulti :: HasCallStack => FilePath -> IO ()
|
||||||
|
testSendMulti =
|
||||||
|
testChat2 aliceProfile bobProfile $
|
||||||
|
\alice bob -> do
|
||||||
|
connectUsers alice bob
|
||||||
|
|
||||||
|
alice ##> "/_send @2 json [{\"msgContent\": {\"type\": \"text\", \"text\": \"test 1\"}}, {\"msgContent\": {\"type\": \"text\", \"text\": \"test 2\"}}]"
|
||||||
|
alice <# "@bob test 1"
|
||||||
|
alice <# "@bob test 2"
|
||||||
|
bob <# "alice> test 1"
|
||||||
|
bob <# "alice> test 2"
|
||||||
|
|
||||||
testGetSetSMPServers :: HasCallStack => FilePath -> IO ()
|
testGetSetSMPServers :: HasCallStack => FilePath -> IO ()
|
||||||
testGetSetSMPServers =
|
testGetSetSMPServers =
|
||||||
testChat2 aliceProfile bobProfile $
|
testChat2 aliceProfile bobProfile $
|
||||||
|
@ -2162,7 +2175,7 @@ testSetChatItemTTL =
|
||||||
-- chat item with file
|
-- chat item with file
|
||||||
alice #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
alice #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
||||||
copyFile "./tests/fixtures/test.jpg" "./tests/tmp/app_files/test.jpg"
|
copyFile "./tests/fixtures/test.jpg" "./tests/tmp/app_files/test.jpg"
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f @bob test.jpg"
|
alice <# "/f @bob test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||||
|
@ -2410,7 +2423,7 @@ setupDesynchronizedRatchet tmp alice = do
|
||||||
(bob </)
|
(bob </)
|
||||||
bob ##> "/tail @alice 1"
|
bob ##> "/tail @alice 1"
|
||||||
bob <# "alice> decryption error, possibly due to the device change (header, 3 messages)"
|
bob <# "alice> decryption error, possibly due to the device change (header, 3 messages)"
|
||||||
bob ##> "@alice 1"
|
bob `send` "@alice 1"
|
||||||
bob <## "error: command is prohibited, sendMessagesB: send prohibited"
|
bob <## "error: command is prohibited, sendMessagesB: send prohibited"
|
||||||
(alice </)
|
(alice </)
|
||||||
where
|
where
|
||||||
|
|
|
@ -64,7 +64,7 @@ runTestMessageWithFile :: HasCallStack => FilePath -> IO ()
|
||||||
runTestMessageWithFile = testChat2 aliceProfile bobProfile $ \alice bob -> withXFTPServer $ do
|
runTestMessageWithFile = testChat2 aliceProfile bobProfile $ \alice bob -> withXFTPServer $ do
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
|
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi, sending a file\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi, sending a file\"}}]"
|
||||||
alice <# "@bob hi, sending a file"
|
alice <# "@bob hi, sending a file"
|
||||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
@ -91,7 +91,7 @@ testSendImage =
|
||||||
testChat2 aliceProfile bobProfile $
|
testChat2 aliceProfile bobProfile $
|
||||||
\alice bob -> withXFTPServer $ do
|
\alice bob -> withXFTPServer $ do
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||||
|
@ -122,7 +122,7 @@ testSenderMarkItemDeleted =
|
||||||
testChat2 aliceProfile bobProfile $
|
testChat2 aliceProfile bobProfile $
|
||||||
\alice bob -> withXFTPServer $ do
|
\alice bob -> withXFTPServer $ do
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test_1MB.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi, sending a file\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"./tests/fixtures/test_1MB.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi, sending a file\"}}]"
|
||||||
alice <# "@bob hi, sending a file"
|
alice <# "@bob hi, sending a file"
|
||||||
alice <# "/f @bob ./tests/fixtures/test_1MB.pdf"
|
alice <# "/f @bob ./tests/fixtures/test_1MB.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
@ -147,7 +147,7 @@ testFilesFoldersSendImage =
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
||||||
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f @bob test.jpg"
|
alice <# "/f @bob test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||||
|
@ -180,7 +180,7 @@ testFilesFoldersImageSndDelete =
|
||||||
alice #$> ("/_files_folder ./tests/tmp/alice_app_files", id, "ok")
|
alice #$> ("/_files_folder ./tests/tmp/alice_app_files", id, "ok")
|
||||||
copyFile "./tests/fixtures/test_1MB.pdf" "./tests/tmp/alice_app_files/test_1MB.pdf"
|
copyFile "./tests/fixtures/test_1MB.pdf" "./tests/tmp/alice_app_files/test_1MB.pdf"
|
||||||
bob #$> ("/_files_folder ./tests/tmp/bob_app_files", id, "ok")
|
bob #$> ("/_files_folder ./tests/tmp/bob_app_files", id, "ok")
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"test_1MB.pdf\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"test_1MB.pdf\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f @bob test_1MB.pdf"
|
alice <# "/f @bob test_1MB.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
|
bob <# "alice> sends file test_1MB.pdf (1017.7 KiB / 1042157 bytes)"
|
||||||
|
@ -212,7 +212,7 @@ testFilesFoldersImageRcvDelete =
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
alice #$> ("/_files_folder ./tests/fixtures", id, "ok")
|
||||||
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
bob #$> ("/_files_folder ./tests/tmp/app_files", id, "ok")
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f @bob test.jpg"
|
alice <# "/f @bob test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
bob <# "alice> sends file test.jpg (136.5 KiB / 139737 bytes)"
|
||||||
|
@ -239,7 +239,7 @@ testSendImageWithTextAndQuote =
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
bob #> "@alice hi alice"
|
bob #> "@alice hi alice"
|
||||||
alice <# "bob> hi alice"
|
alice <# "bob> hi alice"
|
||||||
alice ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 1 <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
alice ##> ("/_send @2 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 1 <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]")
|
||||||
alice <# "@bob > hi alice"
|
alice <# "@bob > hi alice"
|
||||||
alice <## " hey bob"
|
alice <## " hey bob"
|
||||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||||
|
@ -265,7 +265,7 @@ testSendImageWithTextAndQuote =
|
||||||
bob @@@ [("@alice", "hey bob")]
|
bob @@@ [("@alice", "hey bob")]
|
||||||
|
|
||||||
-- quoting (file + text) with file uses quoted text
|
-- quoting (file + text) with file uses quoted text
|
||||||
bob ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.pdf\", \"quotedItemId\": " <> itemId 2 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"file\"}}")
|
bob ##> ("/_send @2 json [{\"filePath\": \"./tests/fixtures/test.pdf\", \"quotedItemId\": " <> itemId 2 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"file\"}}]")
|
||||||
bob <# "@alice > hey bob"
|
bob <# "@alice > hey bob"
|
||||||
bob <## " test.pdf"
|
bob <## " test.pdf"
|
||||||
bob <# "/f @alice ./tests/fixtures/test.pdf"
|
bob <# "/f @alice ./tests/fixtures/test.pdf"
|
||||||
|
@ -287,7 +287,7 @@ testSendImageWithTextAndQuote =
|
||||||
B.readFile "./tests/tmp/test.pdf" `shouldReturn` txtSrc
|
B.readFile "./tests/tmp/test.pdf" `shouldReturn` txtSrc
|
||||||
|
|
||||||
-- quoting (file without text) with file uses file name
|
-- quoting (file without text) with file uses file name
|
||||||
alice ##> ("/_send @2 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 3 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
alice ##> ("/_send @2 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> itemId 3 <> ", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]")
|
||||||
alice <# "@bob > test.pdf"
|
alice <# "@bob > test.pdf"
|
||||||
alice <## " test.jpg"
|
alice <## " test.jpg"
|
||||||
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
alice <# "/f @bob ./tests/fixtures/test.jpg"
|
||||||
|
@ -313,7 +313,7 @@ testGroupSendImage =
|
||||||
\alice bob cath -> withXFTPServer $ do
|
\alice bob cath -> withXFTPServer $ do
|
||||||
createGroup3 "team" alice bob cath
|
createGroup3 "team" alice bob cath
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
alice ##> "/_send #1 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_send #1 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "/f #team ./tests/fixtures/test.jpg"
|
alice <# "/f #team ./tests/fixtures/test.jpg"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
concurrentlyN_
|
concurrentlyN_
|
||||||
|
@ -361,7 +361,7 @@ testGroupSendImageWithTextAndQuote =
|
||||||
(cath <# "#team bob> hi team")
|
(cath <# "#team bob> hi team")
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
msgItemId <- lastItemId alice
|
msgItemId <- lastItemId alice
|
||||||
alice ##> ("/_send #1 json {\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> msgItemId <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}")
|
alice ##> ("/_send #1 json [{\"filePath\": \"./tests/fixtures/test.jpg\", \"quotedItemId\": " <> msgItemId <> ", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]")
|
||||||
alice <# "#team > bob hi team"
|
alice <# "#team > bob hi team"
|
||||||
alice <## " hey bob"
|
alice <## " hey bob"
|
||||||
alice <# "/f #team ./tests/fixtures/test.jpg"
|
alice <# "/f #team ./tests/fixtures/test.jpg"
|
||||||
|
@ -460,7 +460,7 @@ testXFTPFileTransferEncrypted =
|
||||||
let fileJSON = LB.unpack $ J.encode $ CryptoFile srcPath $ Just cfArgs
|
let fileJSON = LB.unpack $ J.encode $ CryptoFile srcPath $ Just cfArgs
|
||||||
withXFTPServer $ do
|
withXFTPServer $ do
|
||||||
connectUsers alice bob
|
connectUsers alice bob
|
||||||
alice ##> ("/_send @2 json {\"msgContent\":{\"type\":\"file\", \"text\":\"\"}, \"fileSource\": " <> fileJSON <> "}")
|
alice ##> ("/_send @2 json [{\"msgContent\":{\"type\":\"file\", \"text\":\"\"}, \"fileSource\": " <> fileJSON <> "}]")
|
||||||
alice <# "/f @bob ./tests/tmp/alice/test.pdf"
|
alice <# "/f @bob ./tests/tmp/alice/test.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
bob <# "alice> sends file test.pdf (266.0 KiB / 272376 bytes)"
|
bob <# "alice> sends file test.pdf (266.0 KiB / 272376 bytes)"
|
||||||
|
|
|
@ -33,6 +33,8 @@ chatForwardTests = do
|
||||||
it "with relative paths: from contact to contact" testForwardFileContactToContact
|
it "with relative paths: from contact to contact" testForwardFileContactToContact
|
||||||
it "with relative paths: from group to notes" testForwardFileGroupToNotes
|
it "with relative paths: from group to notes" testForwardFileGroupToNotes
|
||||||
it "with relative paths: from notes to group" testForwardFileNotesToGroup
|
it "with relative paths: from notes to group" testForwardFileNotesToGroup
|
||||||
|
describe "multi forward api" $ do
|
||||||
|
it "from contact to contact" testForwardContactToContactMulti
|
||||||
|
|
||||||
testForwardContactToContact :: HasCallStack => FilePath -> IO ()
|
testForwardContactToContact :: HasCallStack => FilePath -> IO ()
|
||||||
testForwardContactToContact =
|
testForwardContactToContact =
|
||||||
|
@ -384,7 +386,7 @@ testForwardFileNoFilesFolder =
|
||||||
connectUsers bob cath
|
connectUsers bob cath
|
||||||
|
|
||||||
-- send original file
|
-- send original file
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"./tests/fixtures/test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"./tests/fixtures/test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}]"
|
||||||
alice <# "@bob hi"
|
alice <# "@bob hi"
|
||||||
alice <# "/f @bob ./tests/fixtures/test.pdf"
|
alice <# "/f @bob ./tests/fixtures/test.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
@ -441,7 +443,7 @@ testForwardFileContactToContact =
|
||||||
connectUsers bob cath
|
connectUsers bob cath
|
||||||
|
|
||||||
-- send original file
|
-- send original file
|
||||||
alice ##> "/_send @2 json {\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}"
|
alice ##> "/_send @2 json [{\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}]"
|
||||||
alice <# "@bob hi"
|
alice <# "@bob hi"
|
||||||
alice <# "/f @bob test.pdf"
|
alice <# "/f @bob test.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
@ -506,7 +508,7 @@ testForwardFileGroupToNotes =
|
||||||
createCCNoteFolder cath
|
createCCNoteFolder cath
|
||||||
|
|
||||||
-- send original file
|
-- send original file
|
||||||
alice ##> "/_send #1 json {\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}"
|
alice ##> "/_send #1 json [{\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}]"
|
||||||
alice <# "#team hi"
|
alice <# "#team hi"
|
||||||
alice <# "/f #team test.pdf"
|
alice <# "/f #team test.pdf"
|
||||||
alice <## "use /fc 1 to cancel sending"
|
alice <## "use /fc 1 to cancel sending"
|
||||||
|
@ -555,7 +557,7 @@ testForwardFileNotesToGroup =
|
||||||
createGroup2 "team" alice cath
|
createGroup2 "team" alice cath
|
||||||
|
|
||||||
-- create original file
|
-- create original file
|
||||||
alice ##> "/_create *1 json {\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}"
|
alice ##> "/_create *1 json [{\"filePath\": \"test.pdf\", \"msgContent\": {\"type\": \"text\", \"text\": \"hi\"}}]"
|
||||||
alice <# "* hi"
|
alice <# "* hi"
|
||||||
alice <# "* file 1 (test.pdf)"
|
alice <# "* file 1 (test.pdf)"
|
||||||
|
|
||||||
|
@ -590,3 +592,31 @@ testForwardFileNotesToGroup =
|
||||||
alice <## "notes: all messages are removed"
|
alice <## "notes: all messages are removed"
|
||||||
fwdFileExists <- doesFileExist "./tests/tmp/alice_files/test_1.pdf"
|
fwdFileExists <- doesFileExist "./tests/tmp/alice_files/test_1.pdf"
|
||||||
fwdFileExists `shouldBe` True
|
fwdFileExists `shouldBe` True
|
||||||
|
|
||||||
|
testForwardContactToContactMulti :: HasCallStack => FilePath -> IO ()
|
||||||
|
testForwardContactToContactMulti =
|
||||||
|
testChat3 aliceProfile bobProfile cathProfile $
|
||||||
|
\alice bob cath -> do
|
||||||
|
connectUsers alice bob
|
||||||
|
connectUsers alice cath
|
||||||
|
connectUsers bob cath
|
||||||
|
|
||||||
|
alice #> "@bob hi"
|
||||||
|
bob <# "alice> hi"
|
||||||
|
msgId1 <- lastItemId alice
|
||||||
|
|
||||||
|
threadDelay 1000000
|
||||||
|
|
||||||
|
bob #> "@alice hey"
|
||||||
|
alice <# "bob> hey"
|
||||||
|
msgId2 <- lastItemId alice
|
||||||
|
|
||||||
|
alice ##> ("/_forward @3 @2 " <> msgId1 <> "," <> msgId2)
|
||||||
|
alice <# "@cath <- you @bob"
|
||||||
|
alice <## " hi"
|
||||||
|
alice <# "@cath <- @bob"
|
||||||
|
alice <## " hey"
|
||||||
|
cath <# "alice> -> forwarded"
|
||||||
|
cath <## " hi"
|
||||||
|
cath <# "alice> -> forwarded"
|
||||||
|
cath <## " hey"
|
||||||
|
|
|
@ -64,6 +64,7 @@ chatGroupTests = do
|
||||||
it "moderate message of another group member (full delete)" testGroupModerateFullDelete
|
it "moderate message of another group member (full delete)" testGroupModerateFullDelete
|
||||||
it "moderate message that arrives after the event of moderation" testGroupDelayedModeration
|
it "moderate message that arrives after the event of moderation" testGroupDelayedModeration
|
||||||
it "moderate message that arrives after the event of moderation (full delete)" testGroupDelayedModerationFullDelete
|
it "moderate message that arrives after the event of moderation (full delete)" testGroupDelayedModerationFullDelete
|
||||||
|
it "send multiple messages api" testSendMulti
|
||||||
describe "async group connections" $ do
|
describe "async group connections" $ do
|
||||||
xit "create and join group when clients go offline" testGroupAsync
|
xit "create and join group when clients go offline" testGroupAsync
|
||||||
describe "group links" $ do
|
describe "group links" $ do
|
||||||
|
@ -1818,6 +1819,18 @@ testGroupDelayedModerationFullDelete tmp = do
|
||||||
where
|
where
|
||||||
cfg = testCfgCreateGroupDirect
|
cfg = testCfgCreateGroupDirect
|
||||||
|
|
||||||
|
testSendMulti :: HasCallStack => FilePath -> IO ()
|
||||||
|
testSendMulti =
|
||||||
|
testChat2 aliceProfile bobProfile $
|
||||||
|
\alice bob -> do
|
||||||
|
createGroup2 "team" alice bob
|
||||||
|
|
||||||
|
alice ##> "/_send #1 json [{\"msgContent\": {\"type\": \"text\", \"text\": \"test 1\"}}, {\"msgContent\": {\"type\": \"text\", \"text\": \"test 2\"}}]"
|
||||||
|
alice <# "#team test 1"
|
||||||
|
alice <# "#team test 2"
|
||||||
|
bob <# "#team alice> test 1"
|
||||||
|
bob <# "#team alice> test 2"
|
||||||
|
|
||||||
testGroupAsync :: HasCallStack => FilePath -> IO ()
|
testGroupAsync :: HasCallStack => FilePath -> IO ()
|
||||||
testGroupAsync tmp = do
|
testGroupAsync tmp = do
|
||||||
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
|
@ -3468,7 +3481,8 @@ testGroupSyncRatchet tmp =
|
||||||
bob <## "1 contacts connected (use /cs for the list)"
|
bob <## "1 contacts connected (use /cs for the list)"
|
||||||
bob <## "#team: connected to server(s)"
|
bob <## "#team: connected to server(s)"
|
||||||
bob `send` "#team 1"
|
bob `send` "#team 1"
|
||||||
bob <## "error: command is prohibited, sendMessagesB: send prohibited" -- silence?
|
-- "send prohibited" error is not printed in group as SndMessage is created,
|
||||||
|
-- but it should be displayed in per member snd statuses
|
||||||
bob <# "#team 1"
|
bob <# "#team 1"
|
||||||
(alice </)
|
(alice </)
|
||||||
-- synchronize bob and alice
|
-- synchronize bob and alice
|
||||||
|
@ -4908,7 +4922,7 @@ testGroupHistoryLargeFile =
|
||||||
|
|
||||||
createGroup2 "team" alice bob
|
createGroup2 "team" alice bob
|
||||||
|
|
||||||
bob ##> "/_send #1 json {\"filePath\": \"./tests/tmp/testfile\", \"msgContent\": {\"text\":\"hello\",\"type\":\"file\"}}"
|
bob ##> "/_send #1 json [{\"filePath\": \"./tests/tmp/testfile\", \"msgContent\": {\"text\":\"hello\",\"type\":\"file\"}}]"
|
||||||
bob <# "#team hello"
|
bob <# "#team hello"
|
||||||
bob <# "/f #team ./tests/tmp/testfile"
|
bob <# "/f #team ./tests/tmp/testfile"
|
||||||
bob <## "use /fc 1 to cancel sending"
|
bob <## "use /fc 1 to cancel sending"
|
||||||
|
@ -4969,7 +4983,7 @@ testGroupHistoryMultipleFiles =
|
||||||
|
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
|
|
||||||
bob ##> "/_send #1 json {\"filePath\": \"./tests/tmp/testfile_bob\", \"msgContent\": {\"text\":\"hi alice\",\"type\":\"file\"}}"
|
bob ##> "/_send #1 json [{\"filePath\": \"./tests/tmp/testfile_bob\", \"msgContent\": {\"text\":\"hi alice\",\"type\":\"file\"}}]"
|
||||||
bob <# "#team hi alice"
|
bob <# "#team hi alice"
|
||||||
bob <# "/f #team ./tests/tmp/testfile_bob"
|
bob <# "/f #team ./tests/tmp/testfile_bob"
|
||||||
bob <## "use /fc 1 to cancel sending"
|
bob <## "use /fc 1 to cancel sending"
|
||||||
|
@ -4981,7 +4995,7 @@ testGroupHistoryMultipleFiles =
|
||||||
|
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
|
|
||||||
alice ##> "/_send #1 json {\"filePath\": \"./tests/tmp/testfile_alice\", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"file\"}}"
|
alice ##> "/_send #1 json [{\"filePath\": \"./tests/tmp/testfile_alice\", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"file\"}}]"
|
||||||
alice <# "#team hey bob"
|
alice <# "#team hey bob"
|
||||||
alice <# "/f #team ./tests/tmp/testfile_alice"
|
alice <# "/f #team ./tests/tmp/testfile_alice"
|
||||||
alice <## "use /fc 2 to cancel sending"
|
alice <## "use /fc 2 to cancel sending"
|
||||||
|
@ -5047,7 +5061,7 @@ testGroupHistoryFileCancel =
|
||||||
|
|
||||||
createGroup2 "team" alice bob
|
createGroup2 "team" alice bob
|
||||||
|
|
||||||
bob ##> "/_send #1 json {\"filePath\": \"./tests/tmp/testfile_bob\", \"msgContent\": {\"text\":\"hi alice\",\"type\":\"file\"}}"
|
bob ##> "/_send #1 json [{\"filePath\": \"./tests/tmp/testfile_bob\", \"msgContent\": {\"text\":\"hi alice\",\"type\":\"file\"}}]"
|
||||||
bob <# "#team hi alice"
|
bob <# "#team hi alice"
|
||||||
bob <# "/f #team ./tests/tmp/testfile_bob"
|
bob <# "/f #team ./tests/tmp/testfile_bob"
|
||||||
bob <## "use /fc 1 to cancel sending"
|
bob <## "use /fc 1 to cancel sending"
|
||||||
|
@ -5063,7 +5077,7 @@ testGroupHistoryFileCancel =
|
||||||
|
|
||||||
threadDelay 1000000
|
threadDelay 1000000
|
||||||
|
|
||||||
alice ##> "/_send #1 json {\"filePath\": \"./tests/tmp/testfile_alice\", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"file\"}}"
|
alice ##> "/_send #1 json [{\"filePath\": \"./tests/tmp/testfile_alice\", \"msgContent\": {\"text\":\"hey bob\",\"type\":\"file\"}}]"
|
||||||
alice <# "#team hey bob"
|
alice <# "#team hey bob"
|
||||||
alice <# "/f #team ./tests/tmp/testfile_alice"
|
alice <# "/f #team ./tests/tmp/testfile_alice"
|
||||||
alice <## "use /fc 2 to cancel sending"
|
alice <## "use /fc 2 to cancel sending"
|
||||||
|
|
|
@ -17,6 +17,7 @@ chatLocalChatsTests :: SpecWith FilePath
|
||||||
chatLocalChatsTests = do
|
chatLocalChatsTests = do
|
||||||
describe "note folders" $ do
|
describe "note folders" $ do
|
||||||
it "create folders, add notes, read, search" testNotes
|
it "create folders, add notes, read, search" testNotes
|
||||||
|
it "create multiple messages api" testCreateMulti
|
||||||
it "switch users" testUserNotes
|
it "switch users" testUserNotes
|
||||||
it "preview pagination for notes" testPreviewsPagination
|
it "preview pagination for notes" testPreviewsPagination
|
||||||
it "chat pagination" testChatPagination
|
it "chat pagination" testChatPagination
|
||||||
|
@ -52,6 +53,14 @@ testNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
alice ##> "/tail *"
|
alice ##> "/tail *"
|
||||||
alice <# "* Greetings."
|
alice <# "* Greetings."
|
||||||
|
|
||||||
|
testCreateMulti :: FilePath -> IO ()
|
||||||
|
testCreateMulti tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
|
createCCNoteFolder alice
|
||||||
|
|
||||||
|
alice ##> "/_create *1 json [{\"msgContent\": {\"type\": \"text\", \"text\": \"test 1\"}}, {\"msgContent\": {\"type\": \"text\", \"text\": \"test 2\"}}]"
|
||||||
|
alice <# "* test 1"
|
||||||
|
alice <# "* test 2"
|
||||||
|
|
||||||
testUserNotes :: FilePath -> IO ()
|
testUserNotes :: FilePath -> IO ()
|
||||||
testUserNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
testUserNotes tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
createCCNoteFolder alice
|
createCCNoteFolder alice
|
||||||
|
@ -120,7 +129,7 @@ testFiles tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
let source = "./tests/fixtures/test.jpg"
|
let source = "./tests/fixtures/test.jpg"
|
||||||
let stored = files </> "test.jpg"
|
let stored = files </> "test.jpg"
|
||||||
copyFile source stored
|
copyFile source stored
|
||||||
alice ##> "/_create *1 json {\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"hi myself\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_create *1 json [{\"filePath\": \"test.jpg\", \"msgContent\": {\"text\":\"hi myself\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "* hi myself"
|
alice <# "* hi myself"
|
||||||
alice <# "* file 1 (test.jpg)"
|
alice <# "* file 1 (test.jpg)"
|
||||||
|
|
||||||
|
@ -141,7 +150,7 @@ testFiles tmp = withNewTestChat tmp "alice" aliceProfile $ \alice -> do
|
||||||
-- one more file
|
-- one more file
|
||||||
let stored2 = files </> "another_test.jpg"
|
let stored2 = files </> "another_test.jpg"
|
||||||
copyFile source stored2
|
copyFile source stored2
|
||||||
alice ##> "/_create *1 json {\"filePath\": \"another_test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}"
|
alice ##> "/_create *1 json [{\"filePath\": \"another_test.jpg\", \"msgContent\": {\"text\":\"\",\"type\":\"image\",\"image\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII=\"}}]"
|
||||||
alice <# "* file 2 (another_test.jpg)"
|
alice <# "* file 2 (another_test.jpg)"
|
||||||
|
|
||||||
alice ##> "/_delete item *1 2 internal"
|
alice ##> "/_delete item *1 2 internal"
|
||||||
|
@ -173,8 +182,8 @@ testOtherFiles =
|
||||||
bob ##> "/fr 1"
|
bob ##> "/fr 1"
|
||||||
bob
|
bob
|
||||||
<### [ "saving file 1 from alice to test.jpg",
|
<### [ "saving file 1 from alice to test.jpg",
|
||||||
"started receiving file 1 (test.jpg) from alice"
|
"started receiving file 1 (test.jpg) from alice"
|
||||||
]
|
]
|
||||||
bob <## "completed receiving file 1 (test.jpg) from alice"
|
bob <## "completed receiving file 1 (test.jpg) from alice"
|
||||||
|
|
||||||
bob /* "test"
|
bob /* "test"
|
||||||
|
|
|
@ -1721,7 +1721,7 @@ testSetContactPrefs = testChat2 aliceProfile bobProfile $
|
||||||
let startFeatures = [(0, e2eeInfoPQStr), (0, "Disappearing messages: allowed"), (0, "Full deletion: off"), (0, "Message reactions: enabled"), (0, "Voice messages: off"), (0, "Audio/video calls: enabled")]
|
let startFeatures = [(0, e2eeInfoPQStr), (0, "Disappearing messages: allowed"), (0, "Full deletion: off"), (0, "Message reactions: enabled"), (0, "Voice messages: off"), (0, "Audio/video calls: enabled")]
|
||||||
alice #$> ("/_get chat @2 count=100", chat, startFeatures)
|
alice #$> ("/_get chat @2 count=100", chat, startFeatures)
|
||||||
bob #$> ("/_get chat @2 count=100", chat, startFeatures)
|
bob #$> ("/_get chat @2 count=100", chat, startFeatures)
|
||||||
let sendVoice = "/_send @2 json {\"filePath\": \"test.txt\", \"msgContent\": {\"type\": \"voice\", \"text\": \"\", \"duration\": 10}}"
|
let sendVoice = "/_send @2 json [{\"filePath\": \"test.txt\", \"msgContent\": {\"type\": \"voice\", \"text\": \"\", \"duration\": 10}}]"
|
||||||
voiceNotAllowed = "bad chat command: feature not allowed Voice messages"
|
voiceNotAllowed = "bad chat command: feature not allowed Voice messages"
|
||||||
alice ##> sendVoice
|
alice ##> sendVoice
|
||||||
alice <## voiceNotAllowed
|
alice <## voiceNotAllowed
|
||||||
|
@ -2227,7 +2227,7 @@ testGroupPrefsSimplexLinksForRole = testChat3 aliceProfile bobProfile cathProfil
|
||||||
inv <- getInvitation bob
|
inv <- getInvitation bob
|
||||||
bob ##> ("#team \"" <> inv <> "\\ntest\"")
|
bob ##> ("#team \"" <> inv <> "\\ntest\"")
|
||||||
bob <## "bad chat command: feature not allowed SimpleX links"
|
bob <## "bad chat command: feature not allowed SimpleX links"
|
||||||
bob ##> ("/_send #1 json {\"msgContent\": {\"type\": \"text\", \"text\": \"" <> inv <> "\\ntest\"}}")
|
bob ##> ("/_send #1 json [{\"msgContent\": {\"type\": \"text\", \"text\": \"" <> inv <> "\\ntest\"}}]")
|
||||||
bob <## "bad chat command: feature not allowed SimpleX links"
|
bob <## "bad chat command: feature not allowed SimpleX links"
|
||||||
(alice </)
|
(alice </)
|
||||||
(cath </)
|
(cath </)
|
||||||
|
|
|
@ -112,7 +112,7 @@ runBatcherTest maxLen msgs expectedErrors expectedBatches =
|
||||||
|
|
||||||
runBatcherTest' :: Int -> [SndMessage] -> [ChatError] -> [ByteString] -> IO ()
|
runBatcherTest' :: Int -> [SndMessage] -> [ChatError] -> [ByteString] -> IO ()
|
||||||
runBatcherTest' maxLen msgs expectedErrors expectedBatches = do
|
runBatcherTest' maxLen msgs expectedErrors expectedBatches = do
|
||||||
let (errors, batches) = partitionEithers $ batchMessages maxLen msgs
|
let (errors, batches) = partitionEithers $ batchMessages maxLen (map Right msgs)
|
||||||
batchedStrs = map (\(MsgBatch batchBody _) -> batchBody) batches
|
batchedStrs = map (\(MsgBatch batchBody _) -> batchBody) batches
|
||||||
testErrors errors `shouldBe` testErrors expectedErrors
|
testErrors errors `shouldBe` testErrors expectedErrors
|
||||||
batchedStrs `shouldBe` expectedBatches
|
batchedStrs `shouldBe` expectedBatches
|
||||||
|
|
|
@ -238,7 +238,7 @@ remoteStoreFileTest =
|
||||||
desktop ##> "/get remote file 1 {\"userId\": 1, \"fileId\": 1, \"sent\": true, \"fileSource\": {\"filePath\": \"test_1.pdf\"}}"
|
desktop ##> "/get remote file 1 {\"userId\": 1, \"fileId\": 1, \"sent\": true, \"fileSource\": {\"filePath\": \"test_1.pdf\"}}"
|
||||||
hostError desktop "SEFileNotFound"
|
hostError desktop "SEFileNotFound"
|
||||||
-- send file not encrypted locally on mobile host
|
-- send file not encrypted locally on mobile host
|
||||||
desktop ##> "/_send @2 json {\"filePath\": \"test_1.pdf\", \"msgContent\": {\"type\": \"file\", \"text\": \"sending a file\"}}"
|
desktop ##> "/_send @2 json [{\"filePath\": \"test_1.pdf\", \"msgContent\": {\"type\": \"file\", \"text\": \"sending a file\"}}]"
|
||||||
desktop <# "@bob sending a file"
|
desktop <# "@bob sending a file"
|
||||||
desktop <# "/f @bob test_1.pdf"
|
desktop <# "/f @bob test_1.pdf"
|
||||||
desktop <## "use /fc 1 to cancel sending"
|
desktop <## "use /fc 1 to cancel sending"
|
||||||
|
@ -268,7 +268,7 @@ remoteStoreFileTest =
|
||||||
B.readFile (desktopHostStore </> "test_1.pdf") `shouldReturn` src
|
B.readFile (desktopHostStore </> "test_1.pdf") `shouldReturn` src
|
||||||
|
|
||||||
-- send file encrypted locally on mobile host
|
-- send file encrypted locally on mobile host
|
||||||
desktop ##> ("/_send @2 json {\"fileSource\": {\"filePath\":\"test_2.pdf\", \"cryptoArgs\": " <> LB.unpack (J.encode cfArgs) <> "}, \"msgContent\": {\"type\": \"file\", \"text\": \"\"}}")
|
desktop ##> ("/_send @2 json [{\"fileSource\": {\"filePath\":\"test_2.pdf\", \"cryptoArgs\": " <> LB.unpack (J.encode cfArgs) <> "}, \"msgContent\": {\"type\": \"file\", \"text\": \"\"}}]")
|
||||||
desktop <# "/f @bob test_2.pdf"
|
desktop <# "/f @bob test_2.pdf"
|
||||||
desktop <## "use /fc 2 to cancel sending"
|
desktop <## "use /fc 2 to cancel sending"
|
||||||
bob <# "alice> sends file test_2.pdf (266.0 KiB / 272376 bytes)"
|
bob <# "alice> sends file test_2.pdf (266.0 KiB / 272376 bytes)"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue