From f961bb5d814b090b5e44c899f6aed33fc07fe258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Mon, 28 May 2018 17:49:06 -0400 Subject: [PATCH] conversationmodel: load text messages from daemon Because the daemon can be launched without any client, we need to get messages when the daemon was up and the client down. This patch uses the new getLastMessages() function from daemon. Change-Id: I54d0202ee3b7ca6fbe5fa619e2d735315590adf6 Reviewed-by: Philippe Gorley <philippe.gorley@savoirfairelinux.com> --- src/authority/databasehelper.cpp | 9 +++++++- src/authority/databasehelper.h | 7 ++++++ src/conversationmodel.cpp | 25 +++++++++++++++++---- src/dbus/metatypes.h | 27 ++++++++++++++++++++++- src/qtwrapper/configurationmanager_wrap.h | 8 +++++++ src/typedefs.h | 8 +++++++ test/mocks/configurationmanager_mock.h | 7 ++++++ 7 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp index 7e89ee9d..0c89068e 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 fff6d728..31725a1f 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 db4e4b27..6c1ec612 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 97350683..41d176d2 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 0279ba6f..5962cb18 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 476ecfb3..116e5c8a 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 740469ec..1f0a1fd8 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; -- GitLab