Warning, file /network/ruqola/src/core/localdatabase/localmessagedatabase.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 SPDX-FileCopyrightText: 2023-2024 Laurent Montel <montel.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "localmessagedatabase.h" 0008 #include "localdatabaseutils.h" 0009 #include "messages/message.h" 0010 #include "rocketchataccount.h" 0011 #include "ruqola_database_debug.h" 0012 0013 #include <QDir> 0014 #include <QJsonDocument> 0015 #include <QSqlDatabase> 0016 #include <QSqlError> 0017 #include <QSqlQuery> 0018 #include <QSqlRecord> 0019 #include <QSqlTableModel> 0020 0021 static const char s_schemaMessageDataBase[] = "CREATE TABLE MESSAGES (messageId TEXT PRIMARY KEY NOT NULL, timestamp INTEGER, json TEXT)"; 0022 enum class MessagesFields { 0023 MessageId, 0024 TimeStamp, 0025 Json, 0026 }; // in the same order as the table 0027 0028 LocalMessageDatabase::LocalMessageDatabase() 0029 : LocalDatabaseBase(LocalDatabaseUtils::localMessagesDatabasePath(), LocalDatabaseBase::DatabaseType::Message) 0030 { 0031 } 0032 0033 LocalMessageDatabase::~LocalMessageDatabase() = default; 0034 0035 QString LocalMessageDatabase::schemaDataBase() const 0036 { 0037 return QString::fromLatin1(s_schemaMessageDataBase); 0038 } 0039 0040 void LocalMessageDatabase::addMessage(const QString &accountName, const QString &roomName, const Message &m) 0041 { 0042 QSqlDatabase db; 0043 if (initializeDataBase(accountName, roomName, db)) { 0044 QSqlQuery query(LocalDatabaseUtils::insertReplaceMessages(), db); 0045 query.addBindValue(m.messageId()); 0046 query.addBindValue(m.timeStamp()); 0047 // qDebug() << " m.timeStamp() " << m.timeStamp(); 0048 // FIXME look at why we can't save a binary ? 0049 query.addBindValue(Message::serialize(m, false)); // TODO binary or not ? 0050 if (!query.exec()) { 0051 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't insert-or-replace in MESSAGES table" << db.databaseName() << query.lastError(); 0052 } 0053 } 0054 } 0055 0056 void LocalMessageDatabase::deleteMessage(const QString &accountName, const QString &roomName, const QString &messageId) 0057 { 0058 QSqlDatabase db; 0059 if (!checkDataBase(accountName, roomName, db)) { 0060 return; 0061 } 0062 QSqlQuery query(LocalDatabaseUtils::deleteMessage(), db); 0063 query.addBindValue(messageId); 0064 if (!query.exec()) { 0065 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't insert-or-replace in MESSAGES table" << db.databaseName() << query.lastError(); 0066 } 0067 } 0068 0069 QString LocalMessageDatabase::generateQueryStr(qint64 startId, qint64 endId, qint64 numberElements) 0070 { 0071 QString query = QStringLiteral("SELECT * FROM MESSAGES"); 0072 if (startId != -1) { 0073 query += QStringLiteral(" WHERE timestamp >= :startId"); 0074 if (endId != -1) { 0075 query += QStringLiteral(" AND timestamp <= :endId"); 0076 } 0077 } else { 0078 if (endId != -1) { 0079 query += QStringLiteral(" WHERE timestamp <= :endId"); 0080 } 0081 } 0082 query += QStringLiteral(" ORDER BY timestamp DESC"); 0083 0084 if (numberElements != -1) { 0085 query += QStringLiteral(" LIMIT :limit"); 0086 } 0087 return query; 0088 } 0089 0090 QVector<Message> 0091 LocalMessageDatabase::loadMessages(RocketChatAccount *account, const QString &_roomName, qint64 startId, qint64 endId, qint64 numberElements) const 0092 { 0093 Q_ASSERT(account); 0094 return loadMessages(account->accountName(), _roomName, startId, endId, numberElements, account->emojiManager()); 0095 } 0096 0097 QVector<Message> LocalMessageDatabase::loadMessages(const QString &accountName, 0098 const QString &_roomName, 0099 qint64 startId, 0100 qint64 endId, 0101 qint64 numberElements, 0102 EmojiManager *emojiManager) const 0103 { 0104 #if 0 0105 SELECT id, nom, email 0106 FROM utilisateurs 0107 LIMIT 5 OFFSET 5; 0108 0109 // Use sorting ASC or DESC 0110 #endif 0111 0112 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0113 const QString dbName = databaseName(accountName + QLatin1Char('-') + roomName); 0114 QSqlDatabase db = QSqlDatabase::database(dbName); 0115 if (!db.isValid()) { 0116 // Open the DB if it exists (don't create a new one) 0117 const QString fileName = dbFileName(accountName, roomName); 0118 // qDebug() << " fileName " << fileName; 0119 if (!QFileInfo::exists(fileName)) { 0120 return {}; 0121 } 0122 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); 0123 db.setDatabaseName(fileName); 0124 if (!db.open()) { 0125 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't open" << fileName; 0126 return {}; 0127 } 0128 } 0129 0130 Q_ASSERT(db.isValid()); 0131 Q_ASSERT(db.isOpen()); 0132 const QString query = LocalMessageDatabase::generateQueryStr(startId, endId, numberElements); 0133 QSqlQuery resultQuery(db); 0134 resultQuery.prepare(query); 0135 if (startId != -1) { 0136 resultQuery.bindValue(QStringLiteral(":startId"), startId); 0137 if (endId != -1) { 0138 resultQuery.bindValue(QStringLiteral(":endId"), endId); 0139 } 0140 } else { 0141 if (endId != -1) { 0142 resultQuery.bindValue(QStringLiteral(":endId"), endId); 0143 } 0144 } 0145 if (numberElements != -1) { 0146 resultQuery.bindValue(QStringLiteral(":limit"), numberElements); 0147 } 0148 if (!resultQuery.exec()) { 0149 qCWarning(RUQOLA_DATABASE_LOG) << " Impossible to execute query: " << resultQuery.lastError() << " query: " << query; 0150 return {}; 0151 } 0152 0153 QVector<Message> listMessages; 0154 while (resultQuery.next()) { 0155 const QString json = resultQuery.value(QStringLiteral("json")).toString(); 0156 listMessages.append(convertJsonToMessage(json, emojiManager)); 0157 } 0158 return listMessages; 0159 } 0160 0161 Message LocalMessageDatabase::convertJsonToMessage(const QString &json, EmojiManager *emojiManager) 0162 { 0163 const QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); 0164 const Message msg = Message::deserialize(doc.object(), emojiManager); 0165 return msg; 0166 } 0167 0168 std::unique_ptr<QSqlTableModel> LocalMessageDatabase::createMessageModel(const QString &accountName, const QString &_roomName) const 0169 { 0170 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0171 const QString dbName = databaseName(accountName + QLatin1Char('-') + roomName); 0172 QSqlDatabase db = QSqlDatabase::database(dbName); 0173 if (!db.isValid()) { 0174 // Open the DB if it exists (don't create a new one) 0175 const QString fileName = dbFileName(accountName, roomName); 0176 // qDebug() << " fileName " << fileName; 0177 if (!QFileInfo::exists(fileName)) { 0178 return {}; 0179 } 0180 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); 0181 db.setDatabaseName(fileName); 0182 if (!db.open()) { 0183 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't open" << fileName; 0184 return {}; 0185 } 0186 } 0187 0188 Q_ASSERT(db.isValid()); 0189 Q_ASSERT(db.isOpen()); 0190 auto model = std::make_unique<QSqlTableModel>(nullptr, db); 0191 model->setTable(QStringLiteral("MESSAGES")); 0192 model->setSort(int(MessagesFields::TimeStamp), Qt::AscendingOrder); 0193 model->select(); 0194 return model; 0195 }