From 18109b2f7fa795c0d310e7e4ab053250d1a45540 Mon Sep 17 00:00:00 2001 From: Mick Sayson Date: Sun, 28 Feb 2021 11:19:24 -0800 Subject: [PATCH] feat(history): Save/load system messages to history --- src/model/chathistory.cpp | 10 ++++- src/model/sessionchatlog.h | 1 + src/persistence/history.cpp | 61 ++++++++++++++++++++++++++++-- src/persistence/history.h | 32 +++++++++++++++- test/persistence/dbschema_test.cpp | 2 + 5 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/model/chathistory.cpp b/src/model/chathistory.cpp index c0494fdf1..994448266 100644 --- a/src/model/chathistory.cpp +++ b/src/model/chathistory.cpp @@ -214,7 +214,10 @@ std::vector ChatHistory::getDateIdxs(const QDate& void ChatHistory::addSystemMessage(const SystemMessage& message) { - // FIXME: #6221 Insert into history + if (canUseHistory()) { + history->addNewSystemMessage(f.getPublicKey(), message); + } + sessionChatLog.addSystemMessage(message); } @@ -410,6 +413,11 @@ void ChatHistory::loadHistoryIntoSessionChatLog(ChatLogIdx start) const } break; } + case HistMessageContentType::system: { + const auto& systemMessage = message.content.asSystemMessage(); + sessionChatLog.insertSystemMessageAtIdx(currentIdx, systemMessage); + break; + } } } diff --git a/src/model/sessionchatlog.h b/src/model/sessionchatlog.h index bb34219dd..a85fadfb9 100644 --- a/src/model/sessionchatlog.h +++ b/src/model/sessionchatlog.h @@ -65,6 +65,7 @@ public slots: void onFileTransferRemotePausedUnpaused(const ToxPk& sender, const ToxFile& file, bool paused); void onFileTransferBrokenUnbroken(const ToxPk& sender, const ToxFile& file, bool broken); + private: QString resolveSenderNameFromSender(const ToxPk &sender); diff --git a/src/persistence/history.cpp b/src/persistence/history.cpp index 6e4aeb2a1..fd2643259 100644 --- a/src/persistence/history.cpp +++ b/src/persistence/history.cpp @@ -27,7 +27,7 @@ #include "src/core/toxpk.h" namespace { -static constexpr int SCHEMA_VERSION = 7; +static constexpr int SCHEMA_VERSION = 8; bool createCurrentSchema(RawDatabase& db) { @@ -395,6 +395,19 @@ bool dbSchema6to7(RawDatabase& db) return db.execNow(upgradeQueries); } +bool dbSchema7to8(RawDatabase& db) +{ + // Dummy upgrade. This upgrade does not change the schema, however on + // version 7 if qtox saw a system message it would assert and crash. This + // upgrade ensures that old versions of qtox do not try to load the new + // database + + QVector upgradeQueries; + upgradeQueries += RawDatabase::Query(QStringLiteral("PRAGMA user_version = 8;")); + + return db.execNow(upgradeQueries); +} + /** * @brief Upgrade the db schema * @note On future alterations of the database all you have to do is bump the SCHEMA_VERSION @@ -444,7 +457,7 @@ bool dbSchemaUpgrade(std::shared_ptr& db) using DbSchemaUpgradeFn = bool (*)(RawDatabase&); std::vector upgradeFns = {dbSchema0to1, dbSchema1to2, dbSchema2to3, dbSchema3to4, dbSchema4to5, dbSchema5to6, - dbSchema6to7}; + dbSchema6to7, dbSchema7to8}; assert(databaseSchemaVersion < static_cast(upgradeFns.size())); assert(upgradeFns.size() == SCHEMA_VERSION); @@ -550,7 +563,26 @@ generateNewTextMessageQueries(const ToxPk& friendPk, const QString& message, con return queries; } +QVector generateNewSystemMessageQueries(const ToxPk& friendPk, + const SystemMessage& systemMessage) +{ + QVector queries; + queries += generateEnsurePkInPeers(friendPk); + queries += generateHistoryTableInsertion('S', systemMessage.timestamp, friendPk); + + QVector blobs; + std::transform(systemMessage.args.begin(), systemMessage.args.end(), std::back_inserter(blobs), + [](const QString& s) { return s.toUtf8(); }); + + queries += RawDatabase::Query(QString("INSERT INTO system_messages (id, message_type, " + "system_message_type, arg1, arg2, arg3, arg4)" + "VALUES (last_insert_rowid(), 'S', %1, ?, ?, ?, ?)") + .arg(static_cast(systemMessage.messageType)), + blobs); + + return queries; +} } // namespace /** @@ -756,6 +788,7 @@ History::generateNewFileTransferQueries(const ToxPk& friendPk, const ToxPk& send return queries; } + RawDatabase::Query History::generateFileFinished(RowId id, bool success, const QString& filePath, const QByteArray& fileHash) { @@ -818,6 +851,16 @@ void History::addNewFileMessage(const ToxPk& friendPk, const QString& fileId, db->execLater(queries); } +void History::addNewSystemMessage(const ToxPk& friendPk, const SystemMessage& systemMessage) +{ + if (historyAccessBlocked()) + return; + + const auto queries = generateNewSystemMessageQueries(friendPk, systemMessage); + + db->execLater(queries); +} + /** * @brief Saves a chat message in the database. * @param friendPk Friend publick key to save. @@ -983,8 +1026,18 @@ QList History::getMessagesForFriend(const ToxPk& friendPk, } default: case 'S': - // System messages not yet supported - assert(false); + it = std::next(row.begin(), systemOffset); + assert(!it->isNull()); + SystemMessage systemMessage; + systemMessage.messageType = static_cast((*it++).toLongLong()); + + auto argEnd = std::next(it, systemMessage.args.size()); + std::transform(it, argEnd, systemMessage.args.begin(), [](const QVariant& arg) { + return QString::fromUtf8(arg.toByteArray().replace('\0', "")); + }); + it = argEnd; + + messages += HistMessage(id, timestamp, friendPk.toString(), systemMessage); break; } }; diff --git a/src/persistence/history.h b/src/persistence/history.h index 0bd9be432..52679b3f6 100644 --- a/src/persistence/history.h +++ b/src/persistence/history.h @@ -28,10 +28,11 @@ #include #include +#include "src/core/extension.h" #include "src/core/toxfile.h" #include "src/core/toxpk.h" -#include "src/core/extension.h" #include "src/model/brokenmessagereason.h" +#include "src/model/systemmessage.h" #include "src/persistence/db/rawdatabase.h" #include "src/widget/searchtypes.h" @@ -41,7 +42,8 @@ class HistoryKeeper; enum class HistMessageContentType { message, - file + file, + system, }; class HistMessageContent @@ -57,6 +59,11 @@ public: , type(HistMessageContentType::file) {} + HistMessageContent(SystemMessage systemMessage) + : data(std::make_shared(std::move(systemMessage))) + , type(HistMessageContentType::system) + {} + HistMessageContentType getType() const { return type; @@ -74,6 +81,12 @@ public: return *static_cast(data.get()); } + SystemMessage& asSystemMessage() + { + assert(type == HistMessageContentType::system); + return *static_cast(data.get()); + } + const QString& asMessage() const { assert(type == HistMessageContentType::message); @@ -86,6 +99,12 @@ public: return *static_cast(data.get()); } + const SystemMessage& asSystemMessage() const + { + assert(type == HistMessageContentType::system); + return *static_cast(data.get()); + } + private: // Not really shared but shared_ptr has support for shared_ptr std::shared_ptr data; @@ -142,6 +161,13 @@ public: , content(std::move(file)) {} + HistMessage(RowId id, QDateTime timestamp, QString chat, SystemMessage systemMessage) + : chat{chat} + , timestamp{timestamp} + , id{id} + , state(MessageState::complete) + , content(std::move(systemMessage)) + {} QString chat; QString sender; @@ -177,6 +203,8 @@ public: const QString& fileName, const QString& filePath, int64_t size, const ToxPk& sender, const QDateTime& time, QString const& dispName); + void addNewSystemMessage(const ToxPk& friendPk, const SystemMessage& systemMessage); + void setFileFinished(const QString& fileId, bool success, const QString& filePath, const QByteArray& fileHash); size_t getNumMessagesForFriend(const ToxPk& friendPk); size_t getNumMessagesForFriendBeforeDate(const ToxPk& friendPk, const QDateTime& date); diff --git a/test/persistence/dbschema_test.cpp b/test/persistence/dbschema_test.cpp index 1fe1d8dd1..10a41fc90 100644 --- a/test/persistence/dbschema_test.cpp +++ b/test/persistence/dbschema_test.cpp @@ -53,6 +53,8 @@ private slots: void test4to5(); void test5to6(); void test6to7(); + // test7to8 omitted, version only upgrade, versions are not verified in this + // test suite void cleanupTestCase() const; private: