File indexing completed on 2025-03-16 13:27:30
0001 /* 0002 SPDX-FileCopyrightText: 2021 David Faure <faure@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "localmessagelogger.h" 0008 0009 #include "localdatabaseutils.h" 0010 #include "messages/message.h" 0011 #include "ruqola_database_debug.h" 0012 #include "ruqolaglobalconfig.h" 0013 0014 #include <QDir> 0015 #include <QSqlDatabase> 0016 #include <QSqlError> 0017 #include <QSqlQuery> 0018 #include <QSqlRecord> 0019 #include <QSqlTableModel> 0020 #include <QStandardPaths> 0021 #include <QTextStream> 0022 0023 LocalMessageLogger::LocalMessageLogger() 0024 : LocalDatabaseBase(LocalDatabaseUtils::localMessageLoggerPath(), LocalDatabaseBase::DatabaseType::Logger) 0025 { 0026 } 0027 0028 static const char s_schema[] = "CREATE TABLE LOGS (messageId TEXT PRIMARY KEY NOT NULL, timestamp INTEGER, userName TEXT, text TEXT)"; 0029 enum class Fields { 0030 MessageId, 0031 TimeStamp, 0032 UserName, 0033 Text, 0034 }; // in the same order as the table 0035 0036 QString LocalMessageLogger::schemaDataBase() const 0037 { 0038 return QString::fromLatin1(s_schema); 0039 } 0040 0041 void LocalMessageLogger::addMessage(const QString &accountName, const QString &_roomName, const Message &m) 0042 { 0043 if (!RuqolaGlobalConfig::self()->enableLogging()) { 0044 return; 0045 } 0046 QSqlDatabase db; 0047 if (initializeDataBase(accountName, _roomName, db)) { 0048 QSqlQuery query(LocalDatabaseUtils::insertReplaceMessageFromLogs(), db); 0049 query.addBindValue(m.messageId()); 0050 query.addBindValue(m.timeStamp()); 0051 query.addBindValue(m.username()); 0052 query.addBindValue(m.text()); 0053 if (!query.exec()) { 0054 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't insert-or-replace in LOGS table" << db.databaseName() << query.lastError(); 0055 } 0056 } 0057 } 0058 0059 void LocalMessageLogger::deleteMessage(const QString &accountName, const QString &roomName, const QString &messageId) 0060 { 0061 if (!RuqolaGlobalConfig::self()->enableLogging()) { 0062 return; 0063 } 0064 QSqlDatabase db; 0065 if (!checkDataBase(accountName, roomName, db)) { 0066 return; 0067 } 0068 QSqlQuery query(LocalDatabaseUtils::deleteMessageFromLogs(), db); 0069 query.addBindValue(messageId); 0070 if (!query.exec()) { 0071 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't insert-or-replace in LOGS table" << db.databaseName() << query.lastError(); 0072 } 0073 } 0074 0075 std::unique_ptr<QSqlTableModel> LocalMessageLogger::createMessageModel(const QString &accountName, const QString &_roomName) const 0076 { 0077 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0078 const QString dbName = databaseName(accountName + QLatin1Char('-') + roomName); 0079 QSqlDatabase db = QSqlDatabase::database(dbName); 0080 if (!db.isValid()) { 0081 // Open the DB if it exists (don't create a new one) 0082 const QString fileName = dbFileName(accountName, roomName); 0083 if (!QFileInfo::exists(fileName)) { 0084 return {}; 0085 } 0086 db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), dbName); 0087 db.setDatabaseName(fileName); 0088 if (!db.open()) { 0089 qCWarning(RUQOLA_DATABASE_LOG) << "Couldn't open" << fileName; 0090 return {}; 0091 } 0092 } 0093 0094 Q_ASSERT(db.isValid()); 0095 Q_ASSERT(db.isOpen()); 0096 auto model = std::make_unique<QSqlTableModel>(nullptr, db); 0097 model->setTable(QStringLiteral("LOGS")); 0098 model->setSort(int(Fields::TimeStamp), Qt::AscendingOrder); 0099 model->select(); 0100 return model; 0101 } 0102 0103 bool LocalMessageLogger::saveToFile(QFile &file, const QString &accountName, const QString &_roomName) const 0104 { 0105 const QString roomName = LocalDatabaseUtils::fixRoomName(_roomName); 0106 auto model = createMessageModel(accountName, roomName); 0107 if (!model) { 0108 return false; 0109 } 0110 Q_ASSERT(file.isOpen()); 0111 QTextStream stream(&file); 0112 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0113 stream.setCodec("utf-8"); 0114 #endif 0115 0116 int rows = model->rowCount(); 0117 for (int row = 0; row < rows; ++row) { 0118 const QSqlRecord record = model->record(row); 0119 const QDateTime timeStamp = QDateTime::fromMSecsSinceEpoch(record.value(int(Fields::TimeStamp)).toULongLong()); 0120 const QString userName = record.value(int(Fields::UserName)).toString(); 0121 const QString text = record.value(int(Fields::Text)).toString(); 0122 stream << "[" << timeStamp.toString(Qt::ISODate) << "] <" << userName << "> " << text << '\n'; 0123 if (row == rows - 1 && model->canFetchMore()) { 0124 model->fetchMore(); 0125 rows = model->rowCount(); 0126 } 0127 } 0128 return true; 0129 }