diff --git a/src/api/contactmodel.h b/src/api/contactmodel.h index 92b2bc2dfc10f277cb3a8f0973c91e9b5fd10b24..b0abbc32edc667706f5a8f1407e3d990c6b7e528 100644 --- a/src/api/contactmodel.h +++ b/src/api/contactmodel.h @@ -78,6 +78,11 @@ public: * @throws out_of_range exception if can't find the contact */ const contact::Info getContact(const std::string& contactUri) const; + /** + * get list of banned contacts. + * @return list of banned contacts uris as string + */ + const std::list<std::string>& getBannedContacts() const; /** * @param contactUri * @return empty string if no contact, else the uri in db diff --git a/src/bannedcontactmodel.cpp b/src/bannedcontactmodel.cpp index e4b7e88118788045d1a5aab672d7ec45c129f42e..e3683593b5328fb2c0e520a093817b8e5e97f7e9 100644 --- a/src/bannedcontactmodel.cpp +++ b/src/bannedcontactmodel.cpp @@ -150,7 +150,7 @@ BannedContactModel::add(ContactMethod* cm) * @param cm, the ContactMethod to remove from the list. */ void -BannedContactModel::remove(ContactMethod* cm) +BannedContactModel::remove(ContactMethod* cm, bool updatedaemon) { // Do not remove contact if contact isn't banned auto rowIndex = d_ptr->m_lBanned.indexOf(cm); @@ -166,7 +166,10 @@ BannedContactModel::remove(ContactMethod* cm) return; } - ConfigurationManager::instance().addContact(cm->account()->id(), cm->uri()); + if (updatedaemon) { + qWarning() << "deprecated method: updating daemon using BannedContactModel::remove is deprecated, please use ContactModel::addContact"; + ConfigurationManager::instance().addContact(cm->account()->id(), cm->uri()); + } } /** diff --git a/src/bannedcontactmodel.h b/src/bannedcontactmodel.h index 98143df097835d89df8fd08a246b0f4972e44429..9a5ca1b5981fec94b9ca3110cbaa3cdc244f7aab 100644 --- a/src/bannedcontactmodel.h +++ b/src/bannedcontactmodel.h @@ -44,7 +44,7 @@ public: // Helper void add(ContactMethod* cm); - void remove(ContactMethod* cm); + void remove(ContactMethod* cm, bool updatedaemon = true); bool isBanned(ContactMethod* cm); private: diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index 51e1fc0f8da5bab52bc5086a7784112a46b3c4ed..150f4cba3c013bb9fc49d4911a5e55e27501099d 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -76,8 +76,9 @@ public: * @note: the cm must corresponds to a profile in the database. * @param cm ContactMethod. * @param type + * @param banned whether contact is banned or not */ - void addToContacts(ContactMethod* cm, const profile::Type& type); + void addToContacts(ContactMethod* cm, const profile::Type& type, bool banned = false); // Helpers const ContactModel& linked; @@ -86,7 +87,9 @@ public: // Containers ContactModel::ContactInfoMap contacts; + std::list<std::string> bannedContacts; std::mutex contactsMtx_; + std::mutex bannedContactsMtx_; public Q_SLOTS: /** @@ -192,6 +195,15 @@ ContactModel::addContact(contact::Info contactInfo) { auto& profile = contactInfo.profileInfo; + // If passed contact is a banned contact, call the daemon to unban it + auto it = std::find(pimpl_->bannedContacts.begin(), pimpl_->bannedContacts.end(), profile.uri); + if (it != pimpl_->bannedContacts.end()) { + qDebug("Unban-ing contact %s", profile.uri.c_str()); + ConfigurationManager::instance().addContact(owner.id.c_str(), profile.uri.c_str()); + // bannedContacts will be updated in slotContactAdded + return; + } + if ((owner.profileInfo.type != profile.type) and (profile.type == profile::Type::RING or profile.type == profile::Type::SIP)) { qDebug() << "ContactModel::addContact, types invalids."; @@ -291,6 +303,12 @@ ContactModel::getContact(const std::string& contactUri) const return pimpl_->contacts.at(contactUri); } +const std::list<std::string>& +ContactModel::getBannedContacts() const +{ + return pimpl_->bannedContacts; +} + const std::string ContactModel::getContactProfileId(const std::string& contactUri) const { @@ -450,7 +468,7 @@ ContactModelPimpl::fillsWithRINGContacts() { for (auto contact_info : contacts_vector) { auto cm = PhoneDirectoryModel::instance().getNumber(contact_info["id"], account); std::lock_guard<std::mutex> lk(contactsMtx_); - addToContacts(cm, linked.owner.profileInfo.type); + addToContacts(cm, linked.owner.profileInfo.type, contact_info["banned"] == "true"); } // Add pending contacts @@ -515,11 +533,41 @@ ContactModelPimpl::slotContactAdded(const std::string& accountId, const std::str return; } auto* cm = PhoneDirectoryModel::instance().getNumber(QString(contactUri.c_str()), account); + auto contact = contacts.find(contactUri); + + bool isBanned = false; + { + // Always get contactsMtx_ lock before bannedContactsMtx_. std::lock_guard<std::mutex> lk(contactsMtx_); - addToContacts(cm, linked.owner.profileInfo.type); + + { + // Check whether contact is banned or not + std::lock_guard<std::mutex> lk(bannedContactsMtx_); + auto it = std::find(bannedContacts.begin(), bannedContacts.end(), contact->second.profileInfo.uri); + + isBanned = (it != bannedContacts.end()); + + // If contact is banned, do not re-add it, simply update its flag and the banned contacts list + if (isBanned) { + bannedContacts.erase(it); + + /* Update old LRC. + This method should NOT make any function call that requires the contactsMtx_ lock + otherwise we will get into a deadlock. This is only here for old-lrc transition. */ + account->bannedContactModel()->remove(cm, false); + } + + addToContacts(cm, linked.owner.profileInfo.type, false); + } + } + + if (isBanned) { + // Update the smartlist + linked.owner.conversationModel->refreshFilter(); + } else { + emit linked.contactAdded(contactUri); } - emit linked.contactAdded(contactUri); } void @@ -529,6 +577,7 @@ ContactModelPimpl::slotContactRemoved(const std::string& accountId, const std::s return; { + // Always get contactsMtx_ lock before bannedContactsMtx_. std::lock_guard<std::mutex> lk(contactsMtx_); auto contact = contacts.find(contactUri); @@ -539,12 +588,28 @@ ContactModelPimpl::slotContactRemoved(const std::string& accountId, const std::s auto* account = AccountModel::instance().getById(linked.owner.id.c_str()); if (not account) { - qDebug() << "ContactModel::slotContactsAdded(), nullptr"; + qDebug() << "ContactModel::slotContactsRemoved(), nullptr"; return; } auto* cm = PhoneDirectoryModel::instance().getNumber(QString(contactUri.c_str()), account); + + // Update bannedContactModel from old LRC account->bannedContactModel()->add(cm); + + // Update bannedContacts index + bannedContacts.emplace_back(contact->second.profileInfo.uri); } else { + if (contact->second.isBanned) { + // Contact was banned, update bannedContacts + std::lock_guard<std::mutex> lk(bannedContactsMtx_); + auto it = std::find(bannedContacts.begin(), bannedContacts.end(), contact->second.profileInfo.uri); + if (it == bannedContacts.end()) { + // should not happen + qDebug("ContactModel::slotContactsRemoved(): Contact is banned but not present in bannedContacts. This is most likely the result of an earlier bug."); + } else { + bannedContacts.erase(it); + } + } database::removeContact(db, linked.owner.profileInfo.uri, contactUri); contacts.erase(contactUri); } @@ -559,25 +624,22 @@ ContactModelPimpl::slotContactRemoved(const std::string& accountId, const std::s } void -ContactModelPimpl::addToContacts(ContactMethod* cm, const profile::Type& type) +ContactModelPimpl::addToContacts(ContactMethod* cm, const profile::Type& type, bool banned) { - if (!cm) return; + if (!cm) { + qDebug() << "addToContacts: Called with NULL contact method."; + } + auto contactUri = cm->uri().toStdString(); auto contactId = database::getProfileId(db, contactUri); if (contactId.empty()) { contactId = database::getOrInsertProfile(db, contactUri, "", "", to_string(linked.owner.profileInfo.type)); } + auto contactInfo = database::buildContactFromProfileId(db, contactId); contactInfo.registeredName = cm->registeredName().toStdString(); - - auto* account = AccountModel::instance().getById(linked.owner.id.c_str()); - if (not account) { - qDebug() << "ContactModel::addToContacts(), nullptr"; - return; - } - - contactInfo.isBanned = account->bannedContactModel()->isBanned(cm); + contactInfo.isBanned = banned; contactInfo.isPresent = cm->isPresent(); contactInfo.profileInfo.type = type; // Because PENDING should not be stored in the database auto iter = contacts.find(contactInfo.profileInfo.uri); @@ -585,6 +647,10 @@ ContactModelPimpl::addToContacts(ContactMethod* cm, const profile::Type& type) iter->second = contactInfo; else contacts.emplace_hint(iter, contactInfo.profileInfo.uri, contactInfo); + + if (banned) { + bannedContacts.emplace_back(contactUri); + } } void @@ -668,7 +734,7 @@ ContactModelPimpl::slotIncomingCall(const std::string& fromId, const std::string // The conversation model will create an entry and link the incomingCall. auto* cm = PhoneDirectoryModel::instance().getNumber(QString(fromId.c_str()), account); auto type = (linked.owner.profileInfo.type == profile::Type::RING) ? profile::Type::PENDING : profile::Type::SIP; - addToContacts(cm, type); + addToContacts(cm, type, false); emitContactAdded = true; } } @@ -698,7 +764,7 @@ ContactModelPimpl::slotNewAccountMessage(std::string& accountId, // Contact not found, load profile from database. // The conversation model will create an entry and link the incomingCall. auto* cm = PhoneDirectoryModel::instance().getNumber(QString(from.c_str()), account); - addToContacts(cm, profile::Type::PENDING); + addToContacts(cm, profile::Type::PENDING, false); } } emit linked.newAccountMessage(accountId, from, payloads); @@ -710,7 +776,7 @@ ContactModelPimpl::slotNewAccountTransfer(long long dringId, datatransfer::Info if (info.accountId != linked.owner.id) return; auto* account = AccountModel::instance().getById(linked.owner.id.c_str()); if (not account) { - qDebug() << "ContactModel::slotNewAccountMessage(), nullptr"; + qDebug() << "ContactModel::slotNewAccountTransfer(), nullptr"; return; } @@ -720,7 +786,7 @@ ContactModelPimpl::slotNewAccountTransfer(long long dringId, datatransfer::Info // Contact not found, load profile from database. // The conversation model will create an entry and link the incomingCall. auto* cm = PhoneDirectoryModel::instance().getNumber(QString(info.peerUri.c_str()), account); - addToContacts(cm, profile::Type::PENDING); + addToContacts(cm, profile::Type::PENDING, false); } } emit linked.newAccountTransfer(dringId, info); diff --git a/test/contactmodeltester.cpp b/test/contactmodeltester.cpp index 83193187d9578f97490c59cc644342b733944ea9..958fc56284833f74c63010479cdfaab067b58f2b 100644 --- a/test/contactmodeltester.cpp +++ b/test/contactmodeltester.cpp @@ -48,7 +48,54 @@ ContactModelTester::ContactModelTester() void ContactModelTester::setUp() { +} + +void +ContactModelTester::testBanUnbanContact() +{ + // "bigbadjohn" should not be in "ring1" contacts. + CPPUNIT_ASSERT_THROW(accInfo_.contactModel->getContact("bigbadjohn"), std::out_of_range); + + // Search and add the temporaryContact + accInfo_.contactModel->searchContact("bigbadjohn"); + WaitForSignalHelper(*accInfo_.contactModel, + SIGNAL(modelUpdated())).wait(1000); + auto temporaryContact = accInfo_.contactModel->getContact(""); + std::string uri = std::string("bigbadjohn"); + CPPUNIT_ASSERT_EQUAL(temporaryContact.profileInfo.uri, uri); + + accInfo_.contactModel->addContact(temporaryContact); + auto contactAdded = WaitForSignalHelper(*accInfo_.contactModel, + SIGNAL(contactAdded(const std::string& contactUri))).wait(1000); + CPPUNIT_ASSERT(contactAdded); + + // Ban contact + accInfo_.contactModel->removeContact(uri, true); + auto contactBanned = WaitForSignalHelper(ConfigurationManager::instance(), + SIGNAL(lrc::api::ConversationModel::filterChanged())).wait(1000); + CPPUNIT_ASSERT_EQUAL(contactBanned, true); + + auto contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, true); + + // Re-ban contact, make sure it isn't a problem + accInfo_.contactModel->removeContact(uri, true); + contactBanned = WaitForSignalHelper(ConfigurationManager::instance(), + SIGNAL(lrc::api::ConversationModel::filterChanged())).wait(1000); + CPPUNIT_ASSERT_EQUAL(contactBanned, true); + + contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, true); + + // Unban contact, make sure it worked + contactInfo = accInfo_.contactModel->getContact(uri); + accInfo_.contactModel->addContact(contactInfo); + bool contactUnbanned = WaitForSignalHelper(ConfigurationManager::instance(), + SIGNAL(lrc::api::ConversationModel::filterChanged())).wait(1000); + CPPUNIT_ASSERT_EQUAL(contactUnbanned, true); + contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, false); } void diff --git a/test/contactmodeltester.h b/test/contactmodeltester.h index 4ea98736db8bc107d020cd4da449f8368207202c..f4d6c1debb6acb944f6e5b298f4c2b169bc38763 100644 --- a/test/contactmodeltester.h +++ b/test/contactmodeltester.h @@ -52,6 +52,7 @@ class ContactModelTester : public CppUnit::TestFixture { CPPUNIT_TEST(testRmSIPContact); CPPUNIT_TEST(testRmTemporaryContact); CPPUNIT_TEST(testCountPendingRequests); + CPPUNIT_TEST(testBanUnbanContact); CPPUNIT_TEST_SUITE_END(); public: @@ -116,6 +117,10 @@ public: * Count contact requests when banned contacts exists */ void testCountPendingRequestsWithBlockedContact(); + /** + * Try to ban and unban contacts + */ + void testBanUnbanContact(); /** * Method automatically called after each test by CppUnit */ diff --git a/test/conversationmodeltester.cpp b/test/conversationmodeltester.cpp index a66240ef09f401ac76311f7b681b1f03769af0e0..336b8fccf882194dcc33f8aa954f917bc9582826 100644 --- a/test/conversationmodeltester.cpp +++ b/test/conversationmodeltester.cpp @@ -70,35 +70,55 @@ ConversationModelTester::testAddValidConversation() void ConversationModelTester::testPlaceCallWithBannedContact() { - // bannedContact should not be in contacts + // badguy0 should not be in contacts CPPUNIT_ASSERT(!isAContact("badguy0")); + // so, add him to contacts auto uri = addToContacts("badguy0"); - - // badguy0 should now be in contacts CPPUNIT_ASSERT(isAContact("badguy0")); - // Ban badguy0 + // and ban him banContact(uri); auto contactInfo = accInfo_.contactModel->getContact(uri); CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, true); - // So, now that badguy0 is banned, calling him should be forbidden + // find conversation auto conversations = accInfo_.conversationModel->allFilteredConversations(); - bool conversationExists = false; - for (const auto& conversation: conversations) { - if (std::find(conversation.participants.begin(), conversation.participants.end(), contactInfo.profileInfo.uri) != conversation.participants.end()) { - conversationExists = true; - // Try to call banned contact - auto baseInteractionsSize = conversation.interactions.size(); - accInfo_.conversationModel->placeCall(conversation.uid); - // Make sure call didn't succeed - CPPUNIT_ASSERT_EQUAL((int)baseInteractionsSize, (int)conversation.interactions.size()); - break; - } - } + auto conversation = std::find_if(conversations.begin(), conversations.end(), + [&contactInfo](const lrc::api::conversation::Info& conversation) { + return std::find(conversation.participants.begin(), + conversation.participants.end(), + contactInfo.profileInfo.uri) != conversation.participants.end(); + }); - CPPUNIT_ASSERT(conversationExists); + CPPUNIT_ASSERT(conversation != conversations.end()); + + // now that badguy0 is banned, calling him should be forbidden + auto baseInteractionsSize = conversation->interactions.size(); + accInfo_.conversationModel->placeCall(conversation->uid); + + // make sure call didn't succeed + CPPUNIT_ASSERT(conversation->callId.empty()); + + // unban badguy0 + unbanContact(uri); + contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, false); + + // call again, should succeed + accInfo_.conversationModel->placeCall(conversation->uid); + + // make sure call succeeded + conversations = accInfo_.conversationModel->allFilteredConversations(); + conversation = std::find_if(conversations.begin(), conversations.end(), + [&contactInfo](const lrc::api::conversation::Info& conversation) { + return std::find(conversation.participants.begin(), + conversation.participants.end(), + contactInfo.profileInfo.uri) != conversation.participants.end(); + }); + + CPPUNIT_ASSERT(conversation != conversations.end()); + CPPUNIT_ASSERT(!conversation->callId.empty()); } void @@ -109,14 +129,14 @@ ConversationModelTester::testFilterBannedContact() CPPUNIT_ASSERT(!isAContact("bannedContacte")); CPPUNIT_ASSERT(!isAContact("bannedContac")); - auto newContactUri = addToContacts("bannedContact"); + auto uri = addToContacts("bannedContact"); // bannedContact now should be in contacts CPPUNIT_ASSERT(isAContact("bannedContact")); - // Ban bannedContact - banContact(newContactUri); - auto contactInfo = accInfo_.contactModel->getContact(newContactUri); + // ban bannedContact + banContact(uri); + auto contactInfo = accInfo_.contactModel->getContact(uri); CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, true); // Make sure bannedContact doesn't appear is non-perfect-match filter searches @@ -142,12 +162,39 @@ ConversationModelTester::testFilterBannedContact() CPPUNIT_ASSERT_EQUAL(1, (int)accInfo_.conversationModel->allFilteredConversations().size()); isTemporary = accInfo_.conversationModel->filteredConversation(0).participants.front() == ""; CPPUNIT_ASSERT(!isTemporary); + + // Unban bannedContact + unbanContact(uri); + contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, false); + + // Make sure bannedContact appears is non-perfect-match filter searches + // We expect 2 (temporary item + bannedContact) + accInfo_.conversationModel->setFilter("bannedContac"); + WaitForSignalHelper(*accInfo_.contactModel, + SIGNAL(modelUpdated())).wait(1000); + CPPUNIT_ASSERT_EQUAL(2, (int)accInfo_.conversationModel->allFilteredConversations().size()); + + // Here we expect 1 (temporary item) + accInfo_.conversationModel->setFilter("bannedContacte"); + WaitForSignalHelper(*accInfo_.contactModel, + SIGNAL(modelUpdated())).wait(1000); + CPPUNIT_ASSERT_EQUAL(1, (int)accInfo_.conversationModel->allFilteredConversations().size()); + + // Make sure bannedContact appears in perfect-match filter searches + // We expect 1 (bannedContact) + accInfo_.conversationModel->setFilter("bannedContact"); + WaitForSignalHelper(*accInfo_.contactModel, + SIGNAL(modelUpdated())).wait(1000); + CPPUNIT_ASSERT_EQUAL(1, (int)accInfo_.conversationModel->allFilteredConversations().size()); + isTemporary = accInfo_.conversationModel->filteredConversation(0).participants.front() == ""; + CPPUNIT_ASSERT(!isTemporary); } void ConversationModelTester::testSendMessageToBannedContact() { - // bannedContact should not be in contacts + // badguy1 should not be in contacts CPPUNIT_ASSERT(!isAContact("badguy1")); auto uri = addToContacts("badguy1"); @@ -162,20 +209,41 @@ ConversationModelTester::testSendMessageToBannedContact() // So, now that badguy is banned, sending a message should be forbidden auto conversations = accInfo_.conversationModel->allFilteredConversations(); - bool conversationExists = false; - for (const auto& conversation: conversations) { - if (std::find(conversation.participants.begin(), conversation.participants.end(), contactInfo.profileInfo.uri) != conversation.participants.end()) { - conversationExists = true; - // Try to send message to banned contact - auto baseInteractionsSize = conversation.interactions.size(); - accInfo_.conversationModel->sendMessage(conversation.uid, "Hello banned !"); - // Make sure message didn't arrive (but contact added is already here) - CPPUNIT_ASSERT_EQUAL((int)baseInteractionsSize, (int)conversation.interactions.size()); - break; - } - } + auto conversation = std::find_if(conversations.begin(), conversations.end(), + [&contactInfo](const lrc::api::conversation::Info& conversation) { + return std::find(conversation.participants.begin(), + conversation.participants.end(), + contactInfo.profileInfo.uri) != conversation.participants.end(); + }); - CPPUNIT_ASSERT(conversationExists); + CPPUNIT_ASSERT(conversation != conversations.end()); + + // Try to send message to banned contact + auto baseInteractionsSize = conversation->interactions.size(); + accInfo_.conversationModel->sendMessage(conversation->uid, "Hello banned !"); + // Make sure message didn't arrive (but contact added is already here) + CPPUNIT_ASSERT_EQUAL((int)baseInteractionsSize, (int)conversation->interactions.size()); + + // Unban badguy1 + unbanContact(uri); + contactInfo = accInfo_.contactModel->getContact(uri); + CPPUNIT_ASSERT_EQUAL(contactInfo.isBanned, false); + + // Now send message again, should succeed + accInfo_.conversationModel->sendMessage(conversation->uid, "Hello unbanned !"); + + // Make sure message arrived + conversations = accInfo_.conversationModel->allFilteredConversations(); + conversation = std::find_if(conversations.begin(), conversations.end(), + [&contactInfo](const lrc::api::conversation::Info& conversation) { + return std::find(conversation.participants.begin(), + conversation.participants.end(), + contactInfo.profileInfo.uri) != conversation.participants.end(); + }); + + CPPUNIT_ASSERT(conversation != conversations.end()); + + CPPUNIT_ASSERT_EQUAL((int)baseInteractionsSize + 1, (int)conversation->interactions.size()); } void @@ -375,11 +443,16 @@ ConversationModelTester::testReceiveMessageAndSetRead() void ConversationModelTester::testPlaceCall() { + // Get first conversation and make sure it is empty auto conversations = accInfo_.conversationModel->allFilteredConversations(); CPPUNIT_ASSERT(conversations.size() != 0); auto firstConversation = accInfo_.conversationModel->filteredConversation(0); CPPUNIT_ASSERT(firstConversation.callId.empty()); + + // Place a call accInfo_.conversationModel->placeCall(firstConversation.uid); + + // Get first conversation again and make sure it isn't empty anymore (call suceeded) conversations = accInfo_.conversationModel->allFilteredConversations(); CPPUNIT_ASSERT(conversations.size() != 0); auto newConv = accInfo_.conversationModel->filteredConversation(0); @@ -487,7 +560,7 @@ ConversationModelTester::tearDown() } bool -ConversationModelTester::hasConversationWithContact(std::string uri) +ConversationModelTester::hasConversationWithContact(const std::string& uri) { auto conversations = accInfo_.conversationModel->allFilteredConversations(); auto i = std::find_if(conversations.begin(), conversations.end(), @@ -500,7 +573,7 @@ ConversationModelTester::hasConversationWithContact(std::string uri) } void -ConversationModelTester::banContact(std::string uri) +ConversationModelTester::banContact(const std::string& uri) { accInfo_.contactModel->removeContact(uri, true); auto contactBanned = WaitForSignalHelper(ConfigurationManager::instance(), @@ -508,14 +581,24 @@ ConversationModelTester::banContact(std::string uri) CPPUNIT_ASSERT_EQUAL(contactBanned, true); } +void +ConversationModelTester::unbanContact(const std::string& uri) +{ + auto contactInfo = accInfo_.contactModel->getContact(uri); + accInfo_.contactModel->addContact(contactInfo); + auto contactUnbanned = WaitForSignalHelper(ConfigurationManager::instance(), + SIGNAL(lrc::api::ConversationModel::filterChanged())).wait(2000); + CPPUNIT_ASSERT_EQUAL(contactUnbanned, true); +} + bool -ConversationModelTester::isAContact(std::string uri) +ConversationModelTester::isAContact(const std::string& uri) { return !accInfo_.contactModel->getContactProfileId(uri).empty(); } std::string -ConversationModelTester::addToContacts(std::string username) +ConversationModelTester::addToContacts(const std::string& username) { // Search contact accInfo_.conversationModel->setFilter(username); diff --git a/test/conversationmodeltester.h b/test/conversationmodeltester.h index 07ff662ea032babf673898e42a8c474d88157222..2aac71ff3957e7abbcea432e4876f5717b686569 100644 --- a/test/conversationmodeltester.h +++ b/test/conversationmodeltester.h @@ -137,19 +137,23 @@ protected: /** * Ban contact with passed uri */ - void banContact(std::string uri); + void banContact(const std::string& uri); + /** + * Unban contact with passed uri + */ + void unbanContact(const std::string& uri); /** * Return whether passed uri already maps to a contact or not */ - bool isAContact(std::string uri); + bool isAContact(const std::string& uri); /** * Add passed usename to contacts and return its uri */ - std::string addToContacts(std::string username); + std::string addToContacts(const std::string& username); /** * Return whether a converation with passed contact uri exists or not */ - bool hasConversationWithContact(std::string uri); + bool hasConversationWithContact(const std::string& uri); }; } // namespace test diff --git a/test/mocks/configurationmanager_mock.h b/test/mocks/configurationmanager_mock.h index ea3eee0d3339f1f8eef4ab5d324a00a1234f37c8..f23d418b5a8b9fc5d924fb3e40a940fd464e2aea 100644 --- a/test/mocks/configurationmanager_mock.h +++ b/test/mocks/configurationmanager_mock.h @@ -52,6 +52,7 @@ class ConfigurationManagerInterface: public QObject private: QMap<QString, VectorMapStringString> accountToContactsMap; QStringList availableContacts_; + std::mutex contactsMtx_; public: @@ -623,30 +624,58 @@ public Q_SLOTS: // METHODS { if (getAccountList().indexOf(accountId) == -1) return; auto contacts = accountToContactsMap[accountId]; - for (auto c = 0 ; c < contacts.size() ; ++c) { - if (contacts.at(c)["id"] == uri) { - if (ban) { - contacts[c].insert("removed", "true"); - contacts[c].insert("banned", "true"); - } else { - contacts.remove(c); - } - emit contactRemoved(accountId, uri, ban); + + { + std::lock_guard<std::mutex> lk(contactsMtx_); + auto i = std::find_if( + contacts.begin(), contacts.end(), + [&uri](auto contact) { + return contact["id"] == uri; + }); + + if (i == contacts.end()) { return; } + + if (ban) { + i->insert("removed", "true"); + i->insert("banned", "true"); + } else { + contacts.erase(i); + } } + + emit contactRemoved(accountId, uri, ban); } void addContact(const QString &accountId, const QString &uri) { if (getAccountList().indexOf(accountId) == -1) return; - auto contact = QMap<QString, QString>(); - contact.insert("id", uri); - contact.insert("added", "true"); - contact.insert("removed", "false"); - contact.insert("confirmed", "true"); - contact.insert("banned", "false"); - accountToContactsMap[accountId].push_back(contact); + auto& cm = accountToContactsMap[accountId]; + + { + std::lock_guard<std::mutex> lk(contactsMtx_); + auto i = std::find_if( + cm.begin(), cm.end(), + [&uri](auto contact) { + return contact["id"] == uri; + }); + + if (i != cm.end()) { + // Contact is already there, erase it before adding it back. + // This is important to reset the banned/removed flags. + cm.erase(i); + } + + auto contact = QMap<QString, QString>(); + contact.insert("id", uri); + contact.insert("added", "true"); + contact.insert("removed", "false"); + contact.insert("confirmed", "true"); + contact.insert("banned", "false"); + cm.push_back(contact); + } + emit contactAdded(accountId, uri, true); }