diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml index 539d28188..e535c0821 100644 --- a/resources/desktop/com.github.rssguard.appdata.xml +++ b/resources/desktop/com.github.rssguard.appdata.xml @@ -26,7 +26,7 @@ https://github.com/sponsors/martinrotter - + none diff --git a/resources/sql.qrc b/resources/sql.qrc index 7d8fa9596..632398b4d 100644 --- a/resources/sql.qrc +++ b/resources/sql.qrc @@ -1,7 +1,9 @@ - sql/db_init_mysql.sql + sql/db_init_mysql.sql + sql/db_update_mysql_1_2.sql sql/db_init_sqlite.sql + sql/db_update_sqlite_1_2.sql \ No newline at end of file diff --git a/resources/sql/db_init_sqlite.sql b/resources/sql/db_init_sqlite.sql index 6326f28b0..95d519354 100644 --- a/resources/sql/db_init_sqlite.sql +++ b/resources/sql/db_init_sqlite.sql @@ -3,7 +3,7 @@ CREATE TABLE Information ( inf_value TEXT ); -- ! -INSERT INTO Information VALUES ('schema_version', '1'); +INSERT INTO Information VALUES ('schema_version', '2'); -- ! CREATE TABLE Accounts ( id $$, @@ -40,11 +40,12 @@ CREATE TABLE Feeds ( source TEXT, update_type INTEGER NOT NULL CHECK (update_type >= 0), update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 1), + is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1), + open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1), account_id INTEGER NOT NULL, custom_id TEXT NOT NULL CHECK (custom_id != ''), /* Custom ID cannot be empty, it must contain either service-specific ID, or Feeds/id. */ /* Custom column for (serialized) custom account-specific data. */ custom_data TEXT, - display_url BOOLEAN NOT NULL DEFAULT FALSE, FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE ); diff --git a/resources/sql/db_update_mysql_1_2.sql b/resources/sql/db_update_mysql_1_2.sql new file mode 100755 index 000000000..1b825cb30 --- /dev/null +++ b/resources/sql/db_update_mysql_1_2.sql @@ -0,0 +1,3 @@ +USE ##; +-- ! +!! db_update_sqlite_1_2.sql \ No newline at end of file diff --git a/resources/sql/db_update_sqlite_1_2.sql b/resources/sql/db_update_sqlite_1_2.sql new file mode 100755 index 000000000..927e9081c --- /dev/null +++ b/resources/sql/db_update_sqlite_1_2.sql @@ -0,0 +1,31 @@ +CREATE TABLE backup_Feeds AS SELECT * FROM Feeds; +-- ! +DROP TABLE Feeds; +-- ! +CREATE TABLE Feeds ( + id $$, + title TEXT NOT NULL CHECK (title != ''), + description TEXT, + date_created BIGINT, + icon ^^, + category INTEGER NOT NULL CHECK (category >= -1), /* Physical category ID, also root feeds contain -1 here. */ + source TEXT, + update_type INTEGER NOT NULL CHECK (update_type >= 0), + update_interval INTEGER NOT NULL DEFAULT 15 CHECK (update_interval >= 1), + is_off INTEGER NOT NULL DEFAULT 0 CHECK (is_off >= 0 AND is_off <= 1), + open_articles INTEGER NOT NULL DEFAULT 0 CHECK (open_articles >= 0 AND open_articles <= 1), + account_id INTEGER NOT NULL, + custom_id TEXT NOT NULL CHECK (custom_id != ''), /* Custom ID cannot be empty, it must contain either service-specific ID, or Feeds/id. */ + /* Custom column for (serialized) custom account-specific data. */ + custom_data TEXT, + + FOREIGN KEY (account_id) REFERENCES Accounts (id) ON DELETE CASCADE +); +-- ! +INSERT INTO Feeds (id, title, description, date_created, icon, category, source, update_type, update_interval, account_id, custom_id, custom_data) +SELECT id, title, description, date_created, icon, category, source, update_type, update_interval, account_id, custom_id, custom_data +FROM backup_Feeds; +-- ! +DROP TABLE backup_Feeds; +-- ! +UPDATE Information SET inf_value = '2' WHERE inf_key = 'schema_version'; \ No newline at end of file diff --git a/src/librssguard/database/databasefactory.cpp b/src/librssguard/database/databasefactory.cpp index 6c1d5eb38..3f80a405c 100644 --- a/src/librssguard/database/databasefactory.cpp +++ b/src/librssguard/database/databasefactory.cpp @@ -48,16 +48,16 @@ void DatabaseFactory::determineDriver() { qFatal("DB driver for '%s' was not found.", qPrintable(db_driver)); } - if (m_dbDriver->driverType() != DatabaseDriver::DriverType::SQLite) { - // Try to setup connection and fallback to SQLite. - try { - m_dbDriver->connection(QSL("DatabaseFactory")); - } - catch (const ApplicationException& ex) { - qCriticalNN << LOGSEC_DB - << "Failed to reach connection to DB source, let's fallback to SQLite:" - << QUOTE_W_SPACE_DOT(ex.message()); + // Try to setup connection and fallback to SQLite. + try { + m_dbDriver->connection(QSL("DatabaseFactory")); + } + catch (const ApplicationException& ex) { + qCriticalNN << LOGSEC_DB + << "Failed to reach connection to DB source:" + << QUOTE_W_SPACE_DOT(ex.message()); + if (m_dbDriver->driverType() != DatabaseDriver::DriverType::SQLite) { MessageBox::show(nullptr, QMessageBox::Icon::Critical, tr("Cannot connect to database"), diff --git a/src/librssguard/database/databasequeries.cpp b/src/librssguard/database/databasequeries.cpp index f3d2c2db7..f9a9912c3 100644 --- a/src/librssguard/database/databasequeries.cpp +++ b/src/librssguard/database/databasequeries.cpp @@ -1989,8 +1989,8 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in q.prepare("UPDATE Feeds " "SET title = :title, description = :description, date_created = :date_created, " " icon = :icon, category = :category, source = :source, update_type = :update_type, " - " update_interval = :update_interval, account_id = :account_id, " - " custom_id = :custom_id, custom_data = :custom_data, display_url = :display_url " + " update_interval = :update_interval, is_off = :is_off, open_articles = :open_articles, " + " account_id = :account_id, custom_id = :custom_id, custom_data = :custom_data " "WHERE id = :id;"); q.bindValue(QSL(":title"), feed->title()); q.bindValue(QSL(":description"), feed->description()); @@ -2003,7 +2003,8 @@ void DatabaseQueries::createOverwriteFeed(const QSqlDatabase& db, Feed* feed, in q.bindValue(QSL(":account_id"), account_id); q.bindValue(QSL(":custom_id"), feed->customId()); q.bindValue(QSL(":id"), feed->id()); - q.bindValue(QSL(":display_url"), feed->displayUrl()); + q.bindValue(QSL(":is_off"), feed->isSwitchedOff()); + q.bindValue(QSL(":open_articles"), feed->openArticlesDirectly()); auto custom_data = feed->customDatabaseData(); QString serialized_custom_data = serializeCustomData(custom_data); diff --git a/src/librssguard/database/databasequeries.h b/src/librssguard/database/databasequeries.h index 4f34e6bba..375d95c83 100644 --- a/src/librssguard/database/databasequeries.h +++ b/src/librssguard/database/databasequeries.h @@ -299,14 +299,15 @@ Assignment DatabaseQueries::getFeeds(const QSqlDatabase& db, feed->setIcon(qApp->icons()->fromByteArray(query.value(FDS_DB_ICON_INDEX).toByteArray())); feed->setAutoUpdateType(static_cast(query.value(FDS_DB_UPDATE_TYPE_INDEX).toInt())); feed->setAutoUpdateInitialInterval(query.value(FDS_DB_UPDATE_INTERVAL_INDEX).toInt()); - feed->setDisplayUrl(query.value(FDS_DB_DISPLAY_URL_INDEX).toBool()); + feed->setIsSwitchedOff(query.value(FDS_DB_IS_OFF_INDEX).toBool()); + feed->setOpenArticlesDirectly(query.value(FDS_DB_OPEN_ARTICLES_INDEX).toBool()); qDebugNN << LOGSEC_CORE << "Custom ID of feed when loading from DB is" << QUOTE_W_SPACE_DOT(feed->customId()); // Load custom data. - feed->setCustomDatabaseData(deserializeCustomData(query.value(QSL("custom_data")).toString())); + feed->setCustomDatabaseData(deserializeCustomData(query.value(FDS_DB_CUSTOM_DATA_INDEX).toString())); if (filters_in_feeds.contains(feed->customId())) { auto all_filters_for_this_feed = filters_in_feeds.values(feed->customId()); diff --git a/src/librssguard/database/mariadbdriver.cpp b/src/librssguard/database/mariadbdriver.cpp index 0a3852c87..77ee7fae1 100644 --- a/src/librssguard/database/mariadbdriver.cpp +++ b/src/librssguard/database/mariadbdriver.cpp @@ -191,7 +191,7 @@ QSqlDatabase MariaDbDriver::initializeDatabase(const QString& connection_name) { const QString installed_db_schema = query_db.value(0).toString(); if (installed_db_schema.toInt() < QSL(APP_DB_SCHEMA_VERSION).toInt()) { - if (updateDatabaseSchema(database, installed_db_schema, database_name)) { + if (updateDatabaseSchema(query_db, installed_db_schema, database_name)) { qDebugNN << LOGSEC_DB << "Database schema was updated from" << QUOTE_W_SPACE(installed_db_schema) @@ -214,7 +214,7 @@ QSqlDatabase MariaDbDriver::initializeDatabase(const QString& connection_name) { return database; } -bool MariaDbDriver::updateDatabaseSchema(const QSqlDatabase& database, +bool MariaDbDriver::updateDatabaseSchema(QSqlQuery& query, const QString& source_db_schema_version, const QString& database_name) { int working_version = QString(source_db_schema_version).remove('.').toInt(); @@ -229,8 +229,6 @@ bool MariaDbDriver::updateDatabaseSchema(const QSqlDatabase& database, database_name); for (const QString& statement : statements) { - QSqlQuery query = database.exec(statement); - if (!query.exec(statement) && query.lastError().isValid()) { throw ApplicationException(query.lastError().text()); } @@ -246,6 +244,7 @@ bool MariaDbDriver::updateDatabaseSchema(const QSqlDatabase& database, << QUOTE_W_SPACE(working_version) << "->" << QUOTE_W_SPACE_DOT(working_version + 1); + working_version++; } diff --git a/src/librssguard/database/mariadbdriver.h b/src/librssguard/database/mariadbdriver.h index 294d8255a..86d55a057 100644 --- a/src/librssguard/database/mariadbdriver.h +++ b/src/librssguard/database/mariadbdriver.h @@ -42,7 +42,7 @@ class MariaDbDriver : public DatabaseDriver { QString interpretErrorCode(MariaDbError error_code) const; private: - bool updateDatabaseSchema(const QSqlDatabase& database, + bool updateDatabaseSchema(QSqlQuery &query, const QString& source_db_schema_version, const QString& database_name); QSqlDatabase initializeDatabase(const QString& connection_name); diff --git a/src/librssguard/database/sqlitedriver.cpp b/src/librssguard/database/sqlitedriver.cpp index ea226f982..c1e38236d 100644 --- a/src/librssguard/database/sqlitedriver.cpp +++ b/src/librssguard/database/sqlitedriver.cpp @@ -262,7 +262,7 @@ QSqlDatabase SqliteDriver::initializeDatabase(const QString& connection_name, bo const QString installed_db_schema = query_db.value(0).toString(); if (installed_db_schema.toInt() < QSL(APP_DB_SCHEMA_VERSION).toInt()) { - if (updateDatabaseSchema(database, installed_db_schema)) { + if (updateDatabaseSchema(query_db, installed_db_schema)) { qDebugNN << LOGSEC_DB << "Database schema was updated from '" << installed_db_schema @@ -342,7 +342,7 @@ QString SqliteDriver::databaseFilePath() const { return m_databaseFilePath + QDir::separator() + APP_DB_SQLITE_FILE; } -bool SqliteDriver::updateDatabaseSchema(const QSqlDatabase& database, const QString& source_db_schema_version) { +bool SqliteDriver::updateDatabaseSchema(QSqlQuery& query, const QString& source_db_schema_version) { int working_version = QString(source_db_schema_version).remove('.').toInt(); const int current_version = QSL(APP_DB_SCHEMA_VERSION).remove('.').toInt(); @@ -362,8 +362,6 @@ bool SqliteDriver::updateDatabaseSchema(const QSqlDatabase& database, const QStr QString::number(working_version + 1))); for (const QString& statement : statements) { - QSqlQuery query = database.exec(statement); - if (!query.exec(statement) && query.lastError().isValid()) { throw ApplicationException(query.lastError().text()); } diff --git a/src/librssguard/database/sqlitedriver.h b/src/librssguard/database/sqlitedriver.h index 2b581383c..e046312c0 100644 --- a/src/librssguard/database/sqlitedriver.h +++ b/src/librssguard/database/sqlitedriver.h @@ -28,7 +28,7 @@ class SqliteDriver : public DatabaseDriver { private: QSqlDatabase initializeDatabase(const QString& connection_name, bool in_memory); - bool updateDatabaseSchema(const QSqlDatabase& database, const QString& source_db_schema_version); + bool updateDatabaseSchema(QSqlQuery &query, const QString& source_db_schema_version); void setPragmas(QSqlQuery& query); QString databaseFilePath() const; diff --git a/src/librssguard/definitions/definitions.h b/src/librssguard/definitions/definitions.h index 541558361..d0bbc9612 100644 --- a/src/librssguard/definitions/definitions.h +++ b/src/librssguard/definitions/definitions.h @@ -181,7 +181,7 @@ #define APP_DB_SQLITE_FILE "database.db" // Keep this in sync with schema versions declared in SQL initialization code. -#define APP_DB_SCHEMA_VERSION "1" +#define APP_DB_SCHEMA_VERSION "2" #define APP_DB_UPDATE_FILE_PATTERN "db_update_%1_%2_%3.sql" #define APP_DB_COMMENT_SPLIT "-- !\n" #define APP_DB_INCLUDE_PLACEHOLDER "!!" @@ -246,10 +246,11 @@ #define FDS_DB_SOURCE_INDEX 6 #define FDS_DB_UPDATE_TYPE_INDEX 7 #define FDS_DB_UPDATE_INTERVAL_INDEX 8 -#define FDS_DB_ACCOUNT_ID_INDEX 9 -#define FDS_DB_CUSTOM_ID_INDEX 10 -#define FDS_DB_CUSTOM_DATA_INDEX 11 -#define FDS_DB_DISPLAY_URL_INDEX 12 +#define FDS_DB_IS_OFF_INDEX 9 +#define FDS_DB_OPEN_ARTICLES_INDEX 10 +#define FDS_DB_ACCOUNT_ID_INDEX 11 +#define FDS_DB_CUSTOM_ID_INDEX 12 +#define FDS_DB_CUSTOM_DATA_INDEX 13 // Indexes of columns for feed models. #define FDS_MODEL_TITLE_INDEX 0 diff --git a/src/librssguard/gui/messagepreviewer.cpp b/src/librssguard/gui/messagepreviewer.cpp index 56fe05383..5ed95217c 100644 --- a/src/librssguard/gui/messagepreviewer.cpp +++ b/src/librssguard/gui/messagepreviewer.cpp @@ -121,15 +121,23 @@ void MessagePreviewer::loadMessage(const Message& message, RootItem* root) { if (!same_message) { m_txtMessage->setVerticalScrollBarPosition(0.0); - const auto * feed = root->getParentServiceRoot()->getItemFromSubTree( - [feedId = message.m_feedId](const RootItem * it) { - return it->kind() == RootItem::Kind::Feed && it->customId() == feedId; - })->toFeed(); - if (feed && feed->displayUrl()) { + +#if defined(USE_WEBENGINE) + const auto msg_feed_id = message.m_feedId; + const auto* feed = root->getParentServiceRoot()->getItemFromSubTree( + [msg_feed_id](const RootItem* it) { + return it->kind() == RootItem::Kind::Feed && it->customId() == msg_feed_id; + })->toFeed(); + + if (feed != nullptr && feed->openArticlesDirectly()) { m_txtMessage->loadUrl(m_message.m_url); - } else { + } + else { m_txtMessage->loadMessage(message, m_root); } +#else + m_txtMessage->loadMessage(message, m_root); +#endif } } } diff --git a/src/librssguard/services/abstract/feed.cpp b/src/librssguard/services/abstract/feed.cpp index 0be63ed0d..a10464931 100644 --- a/src/librssguard/services/abstract/feed.cpp +++ b/src/librssguard/services/abstract/feed.cpp @@ -22,7 +22,7 @@ Feed::Feed(RootItem* parent) : RootItem(parent), m_source(QString()), m_status(Status::Normal), m_statusString(QString()), m_autoUpdateType(AutoUpdateType::DefaultAutoUpdate), m_autoUpdateInitialInterval(DEFAULT_AUTO_UPDATE_INTERVAL), m_autoUpdateRemainingInterval(DEFAULT_AUTO_UPDATE_INTERVAL), - m_messageFilters(QList>()) { + m_isSwitchedOff(false), m_openArticlesDirectly(false), m_messageFilters(QList>()) { setKind(RootItem::Kind::Feed); } @@ -43,7 +43,8 @@ Feed::Feed(const Feed& other) : RootItem(other) { setAutoUpdateInitialInterval(other.autoUpdateInitialInterval()); setAutoUpdateRemainingInterval(other.autoUpdateRemainingInterval()); setMessageFilters(other.messageFilters()); - setDisplayUrl(other.displayUrl()); + setOpenArticlesDirectly(other.openArticlesDirectly()); + setIsSwitchedOff(other.isSwitchedOff()); } QList Feed::undeletedMessages() const { @@ -172,12 +173,12 @@ void Feed::setSource(const QString& source) { m_source = source; } -bool Feed::displayUrl() const { - return m_displayUrl; +bool Feed::openArticlesDirectly() const { + return m_openArticlesDirectly; } -void Feed::setDisplayUrl(bool flag) { - m_displayUrl = flag; +void Feed::setOpenArticlesDirectly(bool opn) { + m_openArticlesDirectly = opn; } void Feed::appendMessageFilter(MessageFilter* filter) { @@ -266,6 +267,14 @@ QString Feed::getStatusDescription() const { } } +bool Feed::isSwitchedOff() const { + return m_isSwitchedOff; +} + +void Feed::setIsSwitchedOff(bool switched_off) { + m_isSwitchedOff = switched_off; +} + QString Feed::statusString() const { return m_statusString; } diff --git a/src/librssguard/services/abstract/feed.h b/src/librssguard/services/abstract/feed.h index 7e2c8d8a7..2330d0557 100644 --- a/src/librssguard/services/abstract/feed.h +++ b/src/librssguard/services/abstract/feed.h @@ -73,8 +73,11 @@ class Feed : public RootItem { QString source() const; void setSource(const QString& source); - bool displayUrl() const; - void setDisplayUrl(bool flag); + bool openArticlesDirectly() const; + void setOpenArticlesDirectly(bool opn); + + bool isSwitchedOff() const; + void setIsSwitchedOff(bool switched_off); void appendMessageFilter(MessageFilter* filter); QList> messageFilters() const; @@ -95,7 +98,8 @@ class Feed : public RootItem { AutoUpdateType m_autoUpdateType; int m_autoUpdateInitialInterval{}; int m_autoUpdateRemainingInterval{}; - bool m_displayUrl{false}; + bool m_isSwitchedOff; + bool m_openArticlesDirectly; int m_totalCount{}; int m_unreadCount{}; QList> m_messageFilters; diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.cpp b/src/librssguard/services/abstract/gui/formfeeddetails.cpp index 64bdbcaad..56399403c 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.cpp +++ b/src/librssguard/services/abstract/gui/formfeeddetails.cpp @@ -47,8 +47,7 @@ void FormFeedDetails::apply() { m_feed->setAutoUpdateType(static_cast(m_ui->m_cmbAutoUpdateType->itemData( m_ui->m_cmbAutoUpdateType->currentIndex()).toInt())); m_feed->setAutoUpdateInitialInterval(int(m_ui->m_spinAutoUpdateInterval->value())); - m_feed->setDisplayUrl(m_ui->m_cbLoadUrl->checkState() == Qt::CheckState::Checked); - + m_feed->setOpenArticlesDirectly(m_ui->m_cbOpenArticlesAutomatically->isChecked()); if (!m_creatingNew) { // We need to make sure that common data are saved. @@ -92,7 +91,7 @@ void FormFeedDetails::loadFeedData() { m_ui->m_cmbAutoUpdateType->setCurrentIndex(m_ui->m_cmbAutoUpdateType->findData(QVariant::fromValue(int(m_feed->autoUpdateType())))); m_ui->m_spinAutoUpdateInterval->setValue(m_feed->autoUpdateInitialInterval()); - m_ui->m_cbLoadUrl->setCheckState(m_feed->displayUrl() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + m_ui->m_cbOpenArticlesAutomatically->setChecked(m_feed->openArticlesDirectly()); } void FormFeedDetails::acceptIfPossible() { diff --git a/src/librssguard/services/abstract/gui/formfeeddetails.ui b/src/librssguard/services/abstract/gui/formfeeddetails.ui index f6674748f..ca15a8a30 100644 --- a/src/librssguard/services/abstract/gui/formfeeddetails.ui +++ b/src/librssguard/services/abstract/gui/formfeeddetails.ui @@ -52,20 +52,10 @@ - - + + - Display URL in preview - - - m_cmbAutoUpdateType - - - - - - - + Open articles via their URL automatically diff --git a/src/librssguard/services/abstract/serviceroot.cpp b/src/librssguard/services/abstract/serviceroot.cpp index c8db8c124..dc6b4b3e2 100644 --- a/src/librssguard/services/abstract/serviceroot.cpp +++ b/src/librssguard/services/abstract/serviceroot.cpp @@ -373,6 +373,9 @@ QMap ServiceRoot::storeCustomFeedsData() { feed_custom_data.insert(QSL("auto_update_interval"), feed->autoUpdateInitialInterval()); feed_custom_data.insert(QSL("auto_update_type"), int(feed->autoUpdateType())); feed_custom_data.insert(QSL("msg_filters"), QVariant::fromValue(feed->messageFilters())); + feed_custom_data.insert(QSL("is_off"), feed->isSwitchedOff()); + feed_custom_data.insert(QSL("open_articles_directly"), feed->openArticlesDirectly()); + custom_data.insert(feed->customId(), feed_custom_data); } @@ -393,6 +396,9 @@ void ServiceRoot::restoreCustomFeedsData(const QMap& data, feed->setAutoUpdateInitialInterval(feed_custom_data.value(QSL("auto_update_interval")).toInt()); feed->setAutoUpdateType(static_cast(feed_custom_data.value(QSL("auto_update_type")).toInt())); feed->setMessageFilters(feed_custom_data.value(QSL("msg_filters")).value>>()); + + feed->setIsSwitchedOff(feed_custom_data.value(QSL("is_off")).toBool()); + feed->setOpenArticlesDirectly(feed_custom_data.value(QSL("open_articles_directly")).toBool()); } } }