File indexing completed on 2024-05-12 16:25:42

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 }