Verified Commit 72457cd5 authored by Linus Jahn's avatar Linus Jahn Committed by Linus Jahn

database: Add message types and mediaUrl; Clean up

This introduces different message types (text, image, video, audio, document,
file). They should be used to determine the correct message element in the UI.

Also, there is a new mediaUrl in the Messages table which will be used to
save the HTTP urls to download the media shares.

The database version is increased to 5.
parent 07b87757
......@@ -41,7 +41,7 @@
#include <QSqlQuery>
#include <QSqlRecord>
static const int DATABASE_LATEST_VERSION = 4;
static const int DATABASE_LATEST_VERSION = 5;
static const char *DATABASE_TABLE_INFO = "dbinfo";
static const char *DATABASE_TABLE_MESSAGES = "Messages";
static const char *DATABASE_TABLE_ROSTER = "Roster";
......@@ -124,21 +124,22 @@ bool Database::needToConvert()
void Database::convertDatabase()
{
qDebug() << "[Database] Converting database to latest version from verion" << version;
switch (version) {
case 0:
createNewDatabase();
break;
case 1:
convertDatabaseToV2(); version = 2;
case 2:
convertDatabaseToV3(); version = 3;
case 3:
convertDatabaseToV4(); version = 4;
// only break on last convertion step, to not enter default (!)
break;
default:
createNewDatabase();
qDebug() << "[database] Converting database to latest version from verion" << version;
while (version < DATABASE_LATEST_VERSION) {
switch (version) {
case 0:
createNewDatabase(); version = DATABASE_LATEST_VERSION; break;
case 1:
convertDatabaseToV2(); version = 2; break;
case 2:
convertDatabaseToV3(); version = 3; break;
case 3:
convertDatabaseToV4(); version = 4; break;
case 4:
convertDatabaseToV5(); version = 5; break;
default:
break;
}
}
QSqlQuery query(database);
......@@ -195,6 +196,8 @@ void Database::createNewDatabase()
"'id' TEXT NOT NULL,"
"'isSent' BOOL," // is sent to server
"'isDelivered' BOOL," // message has arrived at other client
"'type' INTEGER," // type of message (text/image/video/...)
"'mediaUrl' TEXT,"
"FOREIGN KEY('author') REFERENCES Roster ('jid'),"
"FOREIGN KEY('recipient') REFERENCES Roster ('jid')"
")"))
......@@ -207,16 +210,11 @@ void Database::createDbInfoTable()
{
QSqlQuery query(database);
query.prepare("CREATE TABLE IF NOT EXISTS 'dbinfo' (version INTEGER NOT NULL)");
if (!query.exec()) {
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare(QString("INSERT INTO 'dbinfo' (version) VALUES (%1)")
.arg(DATABASE_LATEST_VERSION));
if (!query.exec()) {
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
}
void Database::convertDatabaseToV2()
......@@ -229,8 +227,7 @@ void Database::convertDatabaseToV3()
{
QSqlQuery query(database);
query.prepare("ALTER TABLE Roster ADD avatarHash TEXT");
if (!query.exec())
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
execQuery(query);
}
void Database::convertDatabaseToV4()
......@@ -241,35 +238,43 @@ void Database::convertDatabaseToV4()
// and copy everything to the normal table again
query.prepare("CREATE TEMPORARY TABLE roster_backup(jid,name,lastExchanged,"
"unreadMessages,lastMessage,lastOnline,activity,status,mood);");
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare("INSERT INTO roster_backup SELECT jid,name,lastExchanged,unreadMessages,"
"lastMessage,lastOnline,activity,status,mood FROM Roster;");
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare("DROP TABLE Roster;");
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare("CREATE TABLE Roster('jid' TEXT NOT NULL,'name' TEXT NOT NULL,"
"'lastExchanged' TEXT NOT NULL,'unreadMessages' INTEGER,'lastMessage' TEXT,"
"'lastOnline' TEXT,'activity' TEXT,'status' TEXT,'mood' TEXT);");
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare("INSERT INTO Roster SELECT jid,name,lastExchanged,unreadMessages,"
"lastMessage,lastOnline,activity,status,mood FROM Roster_backup;");
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
}
execQuery(query);
query.prepare("DROP TABLE Roster_backup;");
execQuery(query);
}
void Database::convertDatabaseToV5()
{
QSqlQuery query(database);
query.prepare("ALTER TABLE 'Messages' ADD 'type' INTEGER");
execQuery(query);
query.prepare("UPDATE Messages SET type = 0 WHERE type IS NULL");
execQuery(query);
query.prepare("ALTER TABLE 'Messages' ADD 'mediaUrl' TEXT");
execQuery(query);
}
void Database::execQuery(QSqlQuery &query)
{
if (!query.exec()) {
qDebug() << query.executedQuery();
qFatal("Failed to query database: %s", qPrintable(query.lastError().text()));
......
......@@ -34,6 +34,8 @@
#include <QObject>
#include <QSqlDatabase>
class QSqlQuery;
class Database : public QObject
{
Q_OBJECT
......@@ -54,6 +56,8 @@ private:
void convertDatabaseToV2();
void convertDatabaseToV3();
void convertDatabaseToV4();
void convertDatabaseToV5();
void execQuery(QSqlQuery &query);
QSqlDatabase database;
int version;
......
/*
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2018 Kaidan developers and contributors (see the LICENSE
* file for a full list of copyright authors)
*
* Kaidan is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL project's
* "OpenSSL" library (or with modified versions of it that use the same
* license as the "OpenSSL" library), and distribute the linked
* executables. You must obey the GNU General Public License in all
* respects for all of the code used other than "OpenSSL". If you modify
* this file, you may extend this exception to your version of the file,
* but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this package. If not, see <http://www.gnu.org/licenses/>.
* Kaidan - A user-friendly XMPP client for every device!
*
* Copyright (C) 2018 Kaidan developers and contributors
* (see the LICENSE file for a full list of copyright authors)
*
* Kaidan is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, as a special exception, the author of Kaidan gives
* permission to link the code of its release with the OpenSSL
* project's "OpenSSL" library (or with modified versions of it that
* use the same license as the "OpenSSL" library), and distribute the
* linked executables. You must obey the GNU General Public License in
* all respects for all of the code used other than "OpenSSL". If you
* modify this file, you may extend this exception to your version of
* the file, but you are not obligated to do so. If you do not wish to
* do so, delete this exception statement from your version.
*
* Kaidan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Kaidan. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENUMS_H
......@@ -38,7 +39,7 @@ namespace Enums {
Q_NAMESPACE
/**
* Enumration of possible connection states.
* Enumeration of possible connection states.
*/
enum class ConnectionState : quint8 {
StateNone,
......@@ -50,7 +51,7 @@ namespace Enums {
Q_ENUM_NS(ConnectionState)
/**
* Enumration of possible disconnection reasons (compatible to gloox::
* Enumeration of possible disconnection reasons (compatible to gloox::
* ConnectionError)
*/
enum class DisconnectionReason : quint8 {
......@@ -79,6 +80,19 @@ namespace Enums {
// Alias, so that qDebug outputs the full name, but it can be
// abrieviated in the code
using DisconnReason = DisconnectionReason;
/**
* Enumeration of different media/message types
*/
enum class MessageType : quint8 {
MessageText,
MessageFile,
MessageImage,
MessageVideo,
MessageAudio,
MessageDocument
};
Q_ENUM_NS(MessageType)
}
// Needed workaround to trigger older CMake auto moc versions to generate moc
......
......@@ -44,6 +44,7 @@
// Kaidan
#include "MessageModel.h"
#include "Notifications.h"
#include "Enums.h"
QDateTime stringToQDateTime(std::string stamp)
{
......@@ -131,9 +132,10 @@ void MessageHandler::handleMessage(const gloox::Message &stanza, gloox::MessageS
.toString(Qt::ISODate);
// add the message to the database
emit messageModel->addMessageRequested(fromJid, toJid, timestamp,
body, msgId, isSentByMe,
fromJidResource, toJidResource);
emit messageModel->addMessageRequested(
fromJid, toJid, timestamp, body, msgId, isSentByMe,
MessageType::MessageText, fromJidResource, toJidResource
);
//
// Send a new notification | TODO: Resolve nickname from JID
......@@ -211,7 +213,9 @@ void MessageHandler::sendMessage(QString toJid, QString body)
const QString id = QString::fromStdString(message.id());
const QString fromJid = QString::fromStdString(client->jid().bare());
emit messageModel->addMessageRequested(fromJid, toJid, timestamp, body, id, true);
emit messageModel->addMessageRequested(
fromJid, toJid, timestamp, body, id, true, MessageType::MessageText
);
// XEP-0184: Message Delivery Receipts
// request a delivery receipt from the other client
......
......@@ -52,7 +52,7 @@ class MessageHandler : public QObject, public gloox::MessageHandler
public:
MessageHandler(gloox::Client *client, MessageModel *messageModel,
RosterModel *rosterModel, QObject *parent = nullptr);
RosterModel *rosterModel, QObject *parent = nullptr);
~MessageHandler();
virtual void handleMessage(const gloox::Message &message, gloox::MessageSession *session = 0);
......
......@@ -105,8 +105,9 @@ void MessageModel::setMessageAsDelivered(const QString msgId)
void MessageModel::addMessage(const QString author, const QString recipient,
const QString timestamp, const QString message,
const QString msgId, bool sentByMe,
const QString author_resource, const QString recipient_resource)
const QString msgId, bool sentByMe, MessageType type,
const QString mediaUrl, const QString author_resource,
const QString recipient_resource)
{
//
// add the new message
......@@ -122,6 +123,8 @@ void MessageModel::addMessage(const QString author, const QString recipient,
record.setValue("id", msgId);
record.setValue("isSent", !sentByMe);
record.setValue("isDelivered", !sentByMe);
record.setValue("type", (quint8) type);
record.setValue("mediaUrl", mediaUrl);
if (!insertRecord(rowCount(), record)) {
qWarning() << "Failed to add message to DB:" << lastError().text();
......
......@@ -32,6 +32,9 @@
#define MESSAGEMODEL_H
#include <QSqlTableModel>
#include "Enums.h"
using namespace Enums;
class MessageModel : public QSqlTableModel
{
......@@ -61,7 +64,8 @@ signals:
void addMessageRequested(const QString author, const QString recipient,
const QString timestamp, const QString message,
const QString msgId, bool sentByMe,
const QString msgId, bool sentByMe, MessageType type,
const QString mediaUrl = QString(),
const QString author_resource = QString(),
const QString recipient_resource = QString());
void setMessageAsSentRequested(const QString msgId);
......@@ -69,8 +73,10 @@ signals:
private slots:
void addMessage(const QString author, const QString recipient,
const QString timestamp, const QString message, const QString msgId,
bool sentByMe, const QString author_resource = QString(),
const QString timestamp, const QString message,
const QString msgId, bool sentByMe, MessageType type,
const QString mediaUrl = QString(),
const QString author_resource = QString(),
const QString recipient_resource = QString());
void setMessageAsSent(const QString msgId);
void setMessageAsDelivered(const QString msgId);
......
......@@ -137,6 +137,7 @@ int main(int argc, char *argv[])
qRegisterMetaType<EntityPresence*>("EntityPresence*");
qRegisterMetaType<Qt::ApplicationState>("Qt::ApplicationState");
qRegisterMetaType<gloox::Presence::PresenceType>("gloox::Presence::PresenceType");
qRegisterMetaType<MessageType>("MessageType");
qmlRegisterUncreatableMetaObject(Enums::staticMetaObject, APPLICATION_ID,
1, 0, "Kaidan", "Access to enums & flags only");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment