kasts/src/database.cpp

202 lines
7.0 KiB
C++
Raw Normal View History

2020-03-16 22:37:04 +01:00
/**
2020-08-14 20:56:04 +02:00
* SPDX-FileCopyrightText: 2020 Tobias Fella <fella@posteo.de>
2020-03-16 22:37:04 +01:00
*
2020-08-14 20:56:04 +02:00
* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
2020-03-16 22:37:04 +01:00
*/
2020-04-22 02:17:57 +02:00
#include <QDateTime>
2020-03-16 22:37:04 +01:00
#include <QDir>
#include <QSqlDatabase>
2020-04-22 02:17:57 +02:00
#include <QSqlError>
#include <QStandardPaths>
2020-09-03 00:09:59 +02:00
#include <QUrl>
#include <QXmlStreamReader>
2020-09-04 16:52:32 +02:00
#include <QXmlStreamWriter>
2020-03-16 22:37:04 +01:00
#include "alligatorsettings.h"
2020-04-22 02:17:57 +02:00
#include "database.h"
2020-05-11 21:13:27 +02:00
#include "fetcher.h"
2020-03-16 22:37:04 +01:00
2020-04-22 02:17:57 +02:00
#define TRUE_OR_RETURN(x) \
if (!x) \
return false;
2020-03-16 22:37:04 +01:00
Database::Database()
{
QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"));
QString databasePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
QDir(databasePath).mkpath(databasePath);
db.setDatabaseName(databasePath + QStringLiteral("/database.db3"));
db.open();
2020-04-22 02:17:57 +02:00
if (!migrate()) {
2020-04-10 17:28:26 +02:00
qCritical() << "Failed to migrate the database";
2020-03-16 22:37:04 +01:00
}
cleanup();
2020-03-16 22:37:04 +01:00
}
2020-04-22 02:17:57 +02:00
bool Database::migrate()
{
if (version() < 1)
TRUE_OR_RETURN(migrateTo1());
2020-03-16 22:37:04 +01:00
return true;
}
2020-04-22 02:17:57 +02:00
bool Database::migrateTo1()
{
2020-04-18 21:07:49 +02:00
qDebug() << "Migrating database to version 1";
2020-07-06 18:14:43 +02:00
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Feeds (name TEXT, url TEXT, image TEXT, link TEXT, description TEXT, deleteAfterCount INTEGER, deleteAfterType INTEGER, subscribed INTEGER, lastUpdated INTEGER, notify BOOL);")));
2020-06-06 00:05:32 +02:00
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Entries (feed TEXT, id TEXT UNIQUE, title TEXT, content TEXT, created INTEGER, updated INTEGER, link TEXT, read bool);")));
2020-04-20 02:06:21 +02:00
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Authors (feed TEXT, id TEXT, name TEXT, uri TEXT, email TEXT);")));
2020-05-18 17:02:46 +02:00
TRUE_OR_RETURN(execute(QStringLiteral("CREATE TABLE IF NOT EXISTS Enclosures (feed TEXT, id TEXT, duration INTEGER, size INTEGER, title TEXT, type STRING, url STRING);")));
2020-03-16 22:37:04 +01:00
TRUE_OR_RETURN(execute(QStringLiteral("PRAGMA user_version = 1;")));
return true;
}
2020-04-22 02:17:57 +02:00
bool Database::execute(QString query)
{
2020-03-16 22:37:04 +01:00
QSqlQuery q;
q.prepare(query);
return execute(q);
}
2020-04-22 02:17:57 +02:00
bool Database::execute(QSqlQuery &query)
{
if (!query.exec()) {
2020-04-10 17:28:26 +02:00
qWarning() << "Failed to execute SQL Query";
qWarning() << query.lastQuery();
qWarning() << query.lastError();
2020-03-16 22:37:04 +01:00
return false;
}
return true;
}
2020-04-22 02:17:57 +02:00
int Database::version()
{
2020-03-16 22:37:04 +01:00
QSqlQuery query;
query.prepare(QStringLiteral("PRAGMA user_version;"));
execute(query);
2020-04-22 02:17:57 +02:00
if (query.next()) {
2020-03-16 22:37:04 +01:00
bool ok;
int value = query.value(0).toInt(&ok);
2020-04-10 17:28:26 +02:00
qDebug() << "Database version " << value;
2020-04-22 02:17:57 +02:00
if (ok)
return value;
2020-03-16 22:37:04 +01:00
} else {
2020-04-10 17:28:26 +02:00
qCritical() << "Failed to check database version";
2020-03-16 22:37:04 +01:00
}
return -1;
}
2020-04-22 02:17:57 +02:00
void Database::cleanup()
{
AlligatorSettings settings;
int count = settings.deleteAfterCount();
int type = settings.deleteAfterType();
2020-06-06 00:05:32 +02:00
if (type == 0) { // Never delete Entries
2020-06-03 00:20:29 +02:00
return;
}
if (type == 1) { // Delete after <count> posts per feed
2020-04-22 02:17:57 +02:00
// TODO
} else {
QDateTime dateTime = QDateTime::currentDateTime();
2020-06-03 00:20:29 +02:00
if (type == 2)
2020-04-22 02:17:57 +02:00
dateTime = dateTime.addDays(-count);
else if (type == 3)
2020-06-03 00:20:29 +02:00
dateTime = dateTime.addDays(-7 * count);
else if (type == 4)
2020-04-22 02:17:57 +02:00
dateTime = dateTime.addMonths(-count);
qint64 sinceEpoch = dateTime.toSecsSinceEpoch();
QSqlQuery query;
2020-04-21 23:27:15 +02:00
query.prepare(QStringLiteral("DELETE FROM Entries WHERE updated < :sinceEpoch;"));
query.bindValue(QStringLiteral(":sinceEpoch"), sinceEpoch);
execute(query);
}
}
2020-05-11 21:13:27 +02:00
bool Database::feedExists(QString url)
{
QSqlQuery query;
query.prepare(QStringLiteral("SELECT COUNT (url) FROM Feeds WHERE url=:url;"));
query.bindValue(QStringLiteral(":url"), url);
Database::instance().execute(query);
query.next();
return query.value(0).toInt() != 0;
}
void Database::addFeed(QString url)
{
qDebug() << "Adding feed";
if (feedExists(url)) {
qDebug() << "Feed already exists";
return;
}
qDebug() << "Feed does not yet exist";
QUrl urlFromInput = QUrl::fromUserInput(url);
2020-05-11 21:13:27 +02:00
QSqlQuery query;
2020-07-06 18:14:43 +02:00
query.prepare(QStringLiteral("INSERT INTO Feeds VALUES (:name, :url, :image, :link, :description, :deleteAfterCount, :deleteAfterType, :subscribed, :lastUpdated, :notify);"));
query.bindValue(QStringLiteral(":name"), urlFromInput.toString());
query.bindValue(QStringLiteral(":url"), urlFromInput.toString());
2020-05-11 21:13:27 +02:00
query.bindValue(QStringLiteral(":image"), QLatin1String(""));
query.bindValue(QStringLiteral(":link"), QLatin1String(""));
query.bindValue(QStringLiteral(":description"), QLatin1String(""));
2020-06-06 00:05:32 +02:00
query.bindValue(QStringLiteral(":deleteAfterCount"), 0);
query.bindValue(QStringLiteral(":deleteAfterType"), 0);
query.bindValue(QStringLiteral(":subscribed"), QDateTime::currentDateTime().toSecsSinceEpoch());
query.bindValue(QStringLiteral(":lastUpdated"), 0);
query.bindValue(QStringLiteral(":notify"), false);
2020-05-11 21:13:27 +02:00
execute(query);
Q_EMIT feedAdded(urlFromInput.toString());
2020-05-26 16:32:07 +02:00
Fetcher::instance().fetch(urlFromInput.toString());
2020-05-11 21:13:27 +02:00
}
2020-09-03 00:09:59 +02:00
2020-09-04 16:52:32 +02:00
void Database::importFeeds(QString path)
2020-09-03 00:09:59 +02:00
{
QUrl url(path);
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
2020-09-04 16:52:32 +02:00
file.open(QIODevice::ReadOnly);
2020-09-03 00:09:59 +02:00
2020-09-04 16:52:32 +02:00
QXmlStreamReader xmlReader(&file);
2020-09-03 00:09:59 +02:00
while(!xmlReader.atEnd()) {
xmlReader.readNext();
if(xmlReader.tokenType() == 4 && xmlReader.attributes().hasAttribute(QStringLiteral("xmlUrl"))) {
addFeed(xmlReader.attributes().value(QStringLiteral("xmlUrl")).toString());
}
}
Fetcher::instance().fetchAll();
}
2020-09-04 16:52:32 +02:00
void Database::exportFeeds(QString path)
{
QUrl url(path);
QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString());
2020-09-04 16:52:32 +02:00
file.open(QIODevice::WriteOnly);
2020-09-04 16:52:32 +02:00
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument(QStringLiteral("1.0"));
xmlWriter.writeStartElement(QStringLiteral("opml"));
xmlWriter.writeEmptyElement(QStringLiteral("head"));
xmlWriter.writeStartElement(QStringLiteral("body"));
xmlWriter.writeAttribute(QStringLiteral("version"), QStringLiteral("1.0"));
QSqlQuery query;
query.prepare(QStringLiteral("SELECT url, name FROM Feeds;"));
execute(query);
while(query.next()) {
xmlWriter.writeEmptyElement(QStringLiteral("outline"));
xmlWriter.writeAttribute(QStringLiteral("xmlUrl"), query.value(0).toString());
xmlWriter.writeAttribute(QStringLiteral("title"), query.value(1).toString());
}
xmlWriter.writeEndElement();
xmlWriter.writeEndElement();
xmlWriter.writeEndDocument();
}