diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp index 7e89ee9d48f4bf93edf027c4dc32e366b01ff661..0c89068ea1b7c6df0a17e787d3b30909014d8276 100644 --- a/src/authority/databasehelper.cpp +++ b/src/authority/databasehelper.cpp @@ -1,5 +1,5 @@ /**************************************************************************** - * Copyright (C) 2017-2018 Savoir-faire Linux * + * Copyright (C) 2017-2018 Savoir-faire Linux * * Author: Nicolas Jäger <nicolas.jager@savoirfairelinux.com> * * Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com> * * * @@ -426,6 +426,13 @@ deleteObsoleteHistory(Database& db, long int date) db.deleteFrom("interactions", "timestamp<=:date", {{":date", std::to_string(date)}}); } +uint64_t +getLastTimestamp(Database& db) +{ + auto timestamps = db.select("MAX(timestamp)", "interactions", "1=1", {}).payloads; + return timestamps.empty() ? std::time(nullptr) : std::stoull(timestamps[0]); +} + } // namespace database } // namespace authority diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h index fff6d72851d1c510bfef2ecc0c50c83d8b1b6084..31725a1f7508ceca50236f84809df75436910f81 100644 --- a/src/authority/databasehelper.h +++ b/src/authority/databasehelper.h @@ -259,6 +259,13 @@ int addDataTransferToConversation(Database& db, std::string conversationIdFromInteractionId(Database& db, unsigned int interactionId); +/** + * Retrieve the last timestamp from the interactions table + * is used for ConfigurationManager::getLastMessages + * @param db + */ +uint64_t getLastTimestamp(Database& db); + } // namespace database } // namespace authority diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index db4e4b27d2d2b73aade9c15f86e7c67010cbe716..6c1ec6120f30be396db97e3163a36d1110da4256 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -113,10 +113,13 @@ public: * Add a new message from a peer in the database * @param from the peer uri * @param body the content of the message - * @param authorProfileId override the author of the message (if empty it's from)*/ + * @param authorProfileId override the author of the message (if empty it's from) + * @param timestamp the timestamp of the message + */ void addIncomingMessage(const std::string& from, const std::string& body, - const std::string& authorProfileId=""); + const std::string& authorProfileId="", + const uint64_t& timestamp = 0); /** * Change the status of an interaction. Listen from callbacksHandler * @param accountId, account linked @@ -1146,6 +1149,18 @@ ConversationModelPimpl::initConversations() sortConversations(); filteredConversations = conversations; dirtyConversations.first = false; + + // Load all non treated messages for this account + QVector<Message> messages = ConfigurationManager::instance().getLastMessages( + linked.owner.id.c_str(), + database::getLastTimestamp(db)); + for (const auto& message : messages) { + uint64_t timestamp = 0; + try { + timestamp = static_cast<uint64_t>(message.received); + } catch (...) {} + addIncomingMessage(message.from.toStdString(), message.payloads["text/plain"].toStdString(), "", timestamp); + } } void @@ -1564,7 +1579,8 @@ ConversationModelPimpl::slotIncomingCallMessage(const std::string& callId, const void ConversationModelPimpl::addIncomingMessage(const std::string& from, const std::string& body, - const std::string& authorProfileId) + const std::string& authorProfileId, + const uint64_t& timestamp) { auto contactProfileId = database::getOrInsertProfile(db, from); auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri); @@ -1576,7 +1592,8 @@ ConversationModelPimpl::addIncomingMessage(const std::string& from, )); } auto authorId = authorProfileId.empty()? contactProfileId: authorProfileId; - auto msg = interaction::Info {authorId, body, std::time(nullptr), + auto msg = interaction::Info {authorId, body, + timestamp == 0 ? std::time(nullptr) : static_cast<time_t>(timestamp), interaction::Type::TEXT, interaction::Status::UNREAD}; int msgId = database::addMessageToConversation(db, accountProfileId, conv[0], msg); auto conversationIdx = indexOf(conv[0]); diff --git a/src/dbus/metatypes.h b/src/dbus/metatypes.h index 9735068340ee80f8ec28846312763eed775267a7..41d176d25a2766ccc828a1d025472c6511d3a966 100644 --- a/src/dbus/metatypes.h +++ b/src/dbus/metatypes.h @@ -42,6 +42,8 @@ Q_DECLARE_METATYPE(VectorString) Q_DECLARE_METATYPE(MapStringVectorString) Q_DECLARE_METATYPE(VectorVectorByte) Q_DECLARE_METATYPE(DataTransferInfo) +Q_DECLARE_METATYPE(uint64_t) +Q_DECLARE_METATYPE(Message) #ifndef ENABLE_LIBWRAP static inline QDBusArgument &operator<<(QDBusArgument& argument, const DataTransferInfo& info) @@ -77,6 +79,28 @@ static inline const QDBusArgument &operator>>(const QDBusArgument& argument, Dat return argument; } + +static inline QDBusArgument &operator<<(QDBusArgument& argument, const Message& m) +{ + argument.beginStructure(); + argument << m.from; + argument << m.payloads; + argument << m.received; + argument.endStructure(); + + return argument; +} + +static inline const QDBusArgument &operator>>(const QDBusArgument& argument, Message& m) +{ + argument.beginStructure(); + argument >> m.from; + argument >> m.payloads; + argument >> m.received; + argument.endStructure(); + + return argument; +} #endif #ifndef ENABLE_LIBWRAP @@ -95,9 +119,10 @@ inline void registerCommTypes() { qDBusRegisterMetaType<MapStringVectorString> (); qDBusRegisterMetaType<VectorVectorByte> (); qDBusRegisterMetaType<DataTransferInfo> (); + qDBusRegisterMetaType<Message> (); + qDBusRegisterMetaType<QVector<Message>> (); dbus_metaTypeInit = true; #endif } #pragma GCC diagnostic pop - diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h index 0279ba6fcaa2939c8cd7fd135b41819354cc0042..5962cb18cbd5536db65d49db3b192acc7e48e234 100644 --- a/src/qtwrapper/configurationmanager_wrap.h +++ b/src/qtwrapper/configurationmanager_wrap.h @@ -584,6 +584,14 @@ public Q_SLOTS: // METHODS return DRing::sendAccountTextMessage(accountId.toStdString(), to.toStdString(), convertMap(payloads)); } + QVector<Message> getLastMessages(const QString& accountID, const uint64_t& base_timestamp) { + QVector<Message> result; + for (auto& message : DRing::getLastMessages(accountID.toStdString(), base_timestamp)) { + result.append({message.from.c_str(), convertMap(message.payloads), message.received}); + } + return result; + } + bool setCodecDetails(const QString& accountId, unsigned int codecId, const MapStringString& details) { return DRing::setCodecDetails(accountId.toStdString(), codecId, convertMap(details)); } diff --git a/src/typedefs.h b/src/typedefs.h index 476ecfb3aaf003162d344ac6d2ea606910639f45..116e5c8a3f18226155b7795df2ffd7cec52cd772 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -53,6 +53,14 @@ struct DataTransferInfo QString mimetype; }; +struct Message { + QString from; + MapStringString payloads; + quint64 received; +}; + +typedef QVector<Message> messages; + /** * This function add a safe way to get an enum class size * @note it cannot be "const" due to some compiler issues diff --git a/test/mocks/configurationmanager_mock.h b/test/mocks/configurationmanager_mock.h index 740469ec98c5cd05adefa8eb03a5740d1e0f638e..1f0a1fd85580973bc31665f4532db585b156d51a 100644 --- a/test/mocks/configurationmanager_mock.h +++ b/test/mocks/configurationmanager_mock.h @@ -641,6 +641,13 @@ public Q_SLOTS: // METHODS Q_UNUSED(payload) } + QVector<Message> getLastMessages(const std::string& accountID, const uint64_t& base_timestamp) + { + Q_UNUSED(accountID) + Q_UNUSED(base_timestamp) + return {}; + } + void removeContact(const QString &accountId, const QString &uri, bool ban) { if (getAccountList().indexOf(accountId) == -1) return;