diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h index fb3bfe275aa853c2faea20a043b775353ec78b28..7a96dcf158217a2ffb3def02dfc932fcb5dc2977 100644 --- a/src/api/conversationmodel.h +++ b/src/api/conversationmodel.h @@ -160,7 +160,13 @@ public: /** * clear all history */ - void clearAllHistory(); + void clearAllHistory(); + /** + * Clear one interaction from the history + * @param convId + * @param interactionId + */ + void clearInteractionFromConversation(const std::string& convId, const uint64_t& interactionId); /** * delete obsolete history from the database * @param days, number of days from today. Below this date, interactions will be deleted @@ -191,12 +197,19 @@ Q_SIGNALS: /** * Emitted when an interaction got a new status * @param convUid conversation which owns the interaction - * @param msgId + * @param interactionId * @param msg */ void interactionStatusUpdated(const std::string& convUid, - uint64_t msgId, + uint64_t interactionId, const api::interaction::Info& msg) const; + /** + * Emitted when an interaction got removed from the conversation + * @param convUid conversation which owns the interaction + * @param interactionId + */ + void interactionRemoved(const std::string& convUid, + uint64_t interactionId) const; /** * Emitted when user clear the history of a conversation * @param uid diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp index 48f53a4739d1c3fd8ad1b3334eb03a9665228be8..7e89ee9d48f4bf93edf027c4dc32e366b01ff661 100644 --- a/src/authority/databasehelper.cpp +++ b/src/authority/databasehelper.cpp @@ -334,6 +334,14 @@ void clearHistory(Database& db, db.deleteFrom("interactions", "conversation_id=:id", {{":id", conversationId}}); } +void clearInteractionFromConversation(Database& db, + const std::string& conversationId, + const uint64_t& interactionId) +{ + db.deleteFrom("interactions", "conversation_id=:conv_id AND id=:int_id", + {{":conv_id", conversationId}, {":int_id", std::to_string(interactionId)}}); +} + void clearAllHistoryFor(Database& db, const std::string& accountUri) { auto accountId = db.select("id", "profiles","uri=:uri", {{":uri", accountUri}}).payloads; diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h index 744cb81ca2ac09844a59d46fafa32686fd67fdf2..fff6d72851d1c510bfef2ecc0c50c83d8b1b6084 100644 --- a/src/authority/databasehelper.h +++ b/src/authority/databasehelper.h @@ -200,6 +200,16 @@ void updateInteractionStatus(Database& db, unsigned int id, void clearHistory(Database& db, const std::string& conversationId); +/** + * Clear interaction from history + * @param db + * @param conversationId + * @param interactionId + */ +void clearInteractionFromConversation(Database& db, + const std::string& conversationId, + const uint64_t& interactionId); + /** * Clear all history stored in the database for the account uri * @param db diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index 06ade4e0292c7fec4f65e44c49e1c520e6514377..f0802aef3122bb2133a36294c733a43faec910b6 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -636,6 +636,7 @@ ConversationModel::sendMessage(const std::string& uid, const std::string& body) pimpl_->sortConversations(); // The order has changed, informs the client to redraw the list emit modelSorted(); + } void @@ -716,6 +717,30 @@ ConversationModel::clearHistory(const std::string& uid) emit conversationCleared(uid); } +void +ConversationModel::clearInteractionFromConversation(const std::string& convId, const uint64_t& interactionId) +{ + auto conversationIdx = pimpl_->indexOf(convId); + if (conversationIdx == -1) + return; + + auto erased_keys = 0; + { + std::lock_guard<std::mutex> lk(pimpl_->interactionsLocks[convId]); + try + { + auto& conversation = pimpl_->conversations.at(conversationIdx); + database::clearInteractionFromConversation(pimpl_->db, convId, interactionId); + + erased_keys = conversation.interactions.erase(interactionId); + } catch (const std::out_of_range& e) { + qDebug() << "can't clear interaction from conversation: " << e.what(); + } + } + if (erased_keys > 0) + emit interactionRemoved(convId, interactionId); +} + void ConversationModel::clearAllHistory() { diff --git a/test/conversationmodeltester.cpp b/test/conversationmodeltester.cpp index 10ca9051afcc3e981041e571cf89cbcf8fee8809..a66240ef09f401ac76311f7b681b1f03769af0e0 100644 --- a/test/conversationmodeltester.cpp +++ b/test/conversationmodeltester.cpp @@ -289,6 +289,59 @@ ConversationModelTester::testSendMessageAndClearHistory() CPPUNIT_ASSERT(conversationExists); } +void +ConversationModelTester::testSendMessagesAndClearInteraction() +{ + accInfo_.conversationModel->setFilter(""); + auto conversations = accInfo_.conversationModel->allFilteredConversations(); + CPPUNIT_ASSERT(conversations.size() != 0); + auto firstConversation = accInfo_.conversationModel->filteredConversation(0); + auto firstConversationUid = firstConversation.uid; + + // HACK reinit the conversation here (without these line, Hello World! will not be in interactions) + // FIXME + accInfo_.conversationModel->clearHistory(firstConversationUid); + firstConversation = accInfo_.conversationModel->filteredConversation(0); + + // Send 3 messages (will be added to conversation.interactions) + int baseInteractionsSize = firstConversation.interactions.size(); + accInfo_.conversationModel->sendMessage(firstConversationUid, "Hello World!"); + accInfo_.conversationModel->sendMessage(firstConversationUid, "It's been a long time"); + accInfo_.conversationModel->sendMessage(firstConversationUid, "How have you been?"); + + conversations = accInfo_.conversationModel->allFilteredConversations(); + auto conversationExists = false; + uint64_t secondInterId = {}; + for (const auto& conversation: conversations) { + if (conversation.uid == firstConversationUid) { + conversationExists = true; + CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), baseInteractionsSize + 3); + auto it = conversation.interactions.begin(); + it++; + secondInterId = it->first; + break; + } + } + CPPUNIT_ASSERT(conversationExists); + + accInfo_.conversationModel->clearInteractionFromConversation(firstConversationUid, secondInterId); + auto unreadMessage = WaitForSignalHelper(*accInfo_.conversationModel, + SIGNAL(interactionRemoved(const std::string& convUid, uint64_t interactionId))).wait(1000); + conversations = accInfo_.conversationModel->allFilteredConversations(); + conversationExists = false; + for (const auto& conversation: conversations) { + if (conversation.uid == firstConversationUid) { + conversationExists = true; + // Second interaction should be removed + CPPUNIT_ASSERT_EQUAL((int)conversation.interactions.size(), baseInteractionsSize + 2); + for (const auto& interaction: conversation.interactions) + CPPUNIT_ASSERT(interaction.first != secondInterId); + break; + } + } + CPPUNIT_ASSERT(conversationExists); +} + void ConversationModelTester::testReceiveMessageAndSetRead() { diff --git a/test/conversationmodeltester.h b/test/conversationmodeltester.h index b88dc6c004ffa0a24271747693f2d25424383a41..07ff662ea032babf673898e42a8c474d88157222 100644 --- a/test/conversationmodeltester.h +++ b/test/conversationmodeltester.h @@ -46,6 +46,7 @@ class ConversationModelTester : public CppUnit::TestFixture { CPPUNIT_TEST(testRmConversation); CPPUNIT_TEST(testFilterAndGetConversations); CPPUNIT_TEST(testSendMessageAndClearHistory); + CPPUNIT_TEST(testSendMessagesAndClearInteraction); CPPUNIT_TEST(testReceiveMessageAndSetRead); CPPUNIT_TEST(testPlaceCall); CPPUNIT_TEST(testCreateConference); @@ -94,6 +95,10 @@ public: * Make sure banned contacts only appear in perfect-match filter searches. */ void testFilterBannedContact(); + /** + * Send multiple messages to the first conversation and clear one interaction + */ + void testSendMessagesAndClearInteraction(); /** * Receives a message from a conversation and set this message READ */