guessing feed now exception based

This commit is contained in:
Martin Rotter 2021-03-14 19:53:51 +01:00 committed by Martin Rotter
parent 7446d7323b
commit 9f929fb787
4 changed files with 122 additions and 147 deletions

View File

@ -2,6 +2,9 @@
#include "services/standard/gui/standardfeeddetails.h"
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "exceptions/scriptexception.h"
#include "gui/guiutilities.h"
#include "miscellaneous/iconfactory.h"
#include "network-web/networkfactory.h"
@ -115,37 +118,36 @@ StandardFeedDetails::StandardFeedDetails(QWidget* parent) : QWidget(parent) {
void StandardFeedDetails::guessIconOnly(StandardFeed::SourceType source_type, const QString& source,
const QString& post_process_script, const QString& username,
const QString& password, const QNetworkProxy& custom_proxy) {
bool result;
StandardFeed* metadata = StandardFeed::guessFeed(source_type,
source,
post_process_script,
&result,
username,
password,
custom_proxy);
try {
StandardFeed* metadata = StandardFeed::guessFeed(source_type,
source,
post_process_script,
username,
password,
custom_proxy);
if (metadata != nullptr) {
// Icon or whole feed was guessed.
m_ui.m_btnIcon->setIcon(metadata->icon());
if (result) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Icon fetched successfully."),
tr("Icon metadata fetched."));
}
else {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Warning,
tr("Icon metadata not fetched."),
tr("Icon metadata not fetched."));
}
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Icon fetched successfully."),
tr("Icon metadata fetched."));
// Remove temporary feed object.
delete metadata;
metadata->deleteLater();
}
else {
// No feed guessed, even no icon available.
catch (const ScriptException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("No icon fetched."),
tr("Script failed: %1").arg(ex.message()),
tr("No icon fetched."));
}
catch (const NetworkException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: %1").arg(ex.message()),
tr("No icon fetched."));
}
catch (const ApplicationException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("Error: %1").arg(ex.message()),
tr("No icon fetched."));
}
}
@ -153,16 +155,14 @@ void StandardFeedDetails::guessIconOnly(StandardFeed::SourceType source_type, co
void StandardFeedDetails::guessFeed(StandardFeed::SourceType source_type, const QString& source,
const QString& post_process_script, const QString& username,
const QString& password, const QNetworkProxy& custom_proxy) {
bool result;
StandardFeed* metadata = StandardFeed::guessFeed(source_type,
source,
post_process_script,
&result,
username,
password,
custom_proxy);
try {
StandardFeed* metadata = StandardFeed::guessFeed(source_type,
source,
post_process_script,
username,
password,
custom_proxy);
if (metadata != nullptr) {
// Icon or whole feed was guessed.
m_ui.m_btnIcon->setIcon(metadata->icon());
m_ui.m_txtTitle->lineEdit()->setText(metadata->title());
@ -177,24 +177,26 @@ void StandardFeedDetails::guessFeed(StandardFeed::SourceType source_type, const
m_ui.m_cmbEncoding->setCurrentIndex(m_ui.m_cmbEncoding->findText(DEFAULT_FEED_ENCODING, Qt::MatchFixedString));
}
if (result) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Ok,
tr("All metadata fetched successfully."),
tr("Feed and icon metadata fetched."));
}
else {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Warning,
tr("Feed or icon metadata not fetched."),
tr("Feed or icon metadata not fetched."));
}
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Ok,
tr("All metadata fetched successfully."),
tr("Feed and icon metadata fetched."));
// Remove temporary feed object.
delete metadata;
metadata->deleteLater();
}
else {
// No feed guessed, even no icon available.
catch (const ScriptException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("No metadata fetched."),
tr("Script failed: %1").arg(ex.message()),
tr("No metadata fetched."));
}
catch (const NetworkException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: %1").arg(ex.message()),
tr("No metadata fetched."));
}
catch (const ApplicationException& ex) {
m_ui.m_lblFetchMetadata->setStatus(WidgetWithStatus::StatusType::Error,
tr("Error: %1").arg(ex.message()),
tr("No metadata fetched."));
}
}

View File

@ -6,6 +6,8 @@
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "exceptions/scriptexception.h"
#include "exceptions/scriptexception.h"
#include "gui/feedmessageviewer.h"
#include "gui/feedsview.h"
@ -184,46 +186,36 @@ QString StandardFeed::sourceTypeToString(StandardFeed::SourceType type) {
}
void StandardFeed::fetchMetadataForItself() {
bool result;
StandardFeed* metadata = guessFeed(sourceType(),
source(),
postProcessScript(),
&result,
username(),
password(),
getParentServiceRoot()->networkProxy());
try {
StandardFeed* metadata = guessFeed(sourceType(),
source(),
postProcessScript(),
username(),
password(),
getParentServiceRoot()->networkProxy());
if (metadata != nullptr && result) {
// Copy metadata to our object.
setTitle(metadata->title());
setDescription(metadata->description());
setType(metadata->type());
setEncoding(metadata->encoding());
setIcon(metadata->icon());
delete metadata;
metadata->deleteLater();
QSqlDatabase database = qApp->database()->driver()->connection(metaObject()->className());
try {
DatabaseQueries::createOverwriteFeed(database, this, getParentServiceRoot()->accountId(), parent()->id());
serviceRoot()->itemChanged({ this });
}
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_DB
<< "Cannot overwrite feed:"
<< QUOTE_W_SPACE_DOT(ex.message());
qApp->showGuiMessage(tr("Error"),
tr("Cannot save data for feed, detailed information was logged via debug log."),
QSystemTrayIcon::MessageIcon::Critical,
nullptr,
true);
}
DatabaseQueries::createOverwriteFeed(database, this, getParentServiceRoot()->accountId(), parent()->id());
serviceRoot()->itemChanged({ this });
}
else {
qApp->showGuiMessage(tr("Metadata not fetched"),
tr("Metadata was not fetched."),
QSystemTrayIcon::MessageIcon::Critical);
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_DB
<< "Cannot overwrite feed:"
<< QUOTE_W_SPACE_DOT(ex.message());
qApp->showGuiMessage(tr("Error"),
tr("Cannot save data for feed: %1").arg(ex.message()),
QSystemTrayIcon::MessageIcon::Critical,
nullptr,
true);
}
}
@ -246,7 +238,6 @@ void StandardFeed::setSourceType(SourceType source_type) {
StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
const QString& source,
const QString& post_process_script,
bool* result,
const QString& username,
const QString& password,
const QNetworkProxy& custom_proxy) {
@ -271,8 +262,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
content_type = network_result.second.toString();
if (network_result.first != QNetworkReply::NetworkError::NoError) {
*result = false;
return nullptr;
throw NetworkException(network_result.first);
}
}
else {
@ -282,37 +272,14 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
<< "to obtain feed data.";
// Use script to generate feed file.
try {
feed_contents = generateFeedFileWithScript(source, timeout).toUtf8();
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Custom script for generating feed file failed during guessing:"
<< QUOTE_W_SPACE_DOT(ex.message());
*result = false;
return nullptr;
}
feed_contents = generateFeedFileWithScript(source, timeout).toUtf8();
}
if (!post_process_script.simplified().isEmpty()) {
qDebugNN << LOGSEC_CORE
<< "Post-processing obtained feed data with custom script for guessing"
<< QUOTE_W_SPACE_DOT(post_process_script);
try {
feed_contents = postProcessFeedFileWithScript(post_process_script,
feed_contents,
timeout).toUtf8();
}
catch (const ScriptException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Post-processing script for feed file for guessing failed:"
<< QUOTE_W_SPACE_DOT(ex.message());
*result = false;
return nullptr;
}
feed_contents = postProcessFeedFileWithScript(post_process_script, feed_contents, timeout).toUtf8();
}
StandardFeed* feed = nullptr;
@ -326,8 +293,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
// only use its domain and download via DuckDuckGo.
QList<QPair<QString, bool>> icon_possible_locations;
if (content_type.contains(QSL("json"), Qt::CaseSensitivity::CaseInsensitive) ||
feed_contents.startsWith('{')) {
if (content_type.contains(QSL("json"), Qt::CaseSensitivity::CaseInsensitive) || feed_contents.startsWith('{')) {
feed = new StandardFeed();
// We have JSON feed.
@ -362,9 +328,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
QString xml_schema_encoding;
QString xml_contents_encoded;
QString enc = QRegularExpression(QSL("encoding=\"([A-Z0-9\\-]+)\""),
QRegularExpression::PatternOption::CaseInsensitiveOption)
.match(feed_contents)
.captured(1);
QRegularExpression::PatternOption::CaseInsensitiveOption).match(feed_contents).captured(1);
if (!enc.isEmpty()) {
// Some "encoding" attribute was found get the encoding
@ -396,13 +360,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
&error_msg,
&error_line,
&error_column)) {
qDebugNN << LOGSEC_CORE
<< "XML of feed" << QUOTE_W_SPACE(source) << "is not valid and cannot be loaded. "
<< "Error:" << QUOTE_W_SPACE(error_msg) << "(line " << error_line
<< ", column " << error_column << ").";
*result = false;
return nullptr;
throw ApplicationException(tr("XML is not well-formed, %1").arg(error_msg));
}
feed = new StandardFeed();
@ -479,9 +437,7 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
// File was downloaded and it really was XML file
// but feed format was NOT recognized.
feed->deleteLater();
*result = false;
return nullptr;
throw ApplicationException(tr("XML feed file format unrecognized"));
}
}
@ -501,7 +457,6 @@ StandardFeed* StandardFeed::guessFeed(StandardFeed::SourceType source_type,
feed->setIcon(icon_data);
}
*result = true;
return feed;
}

View File

@ -87,7 +87,6 @@ class StandardFeed : public Feed {
static StandardFeed* guessFeed(SourceType source_type,
const QString& url,
const QString& post_process_script,
bool* result,
const QString& username = QString(),
const QString& password = QString(),
const QNetworkProxy& custom_proxy = QNetworkProxy::ProxyType::DefaultProxy);

View File

@ -3,6 +3,7 @@
#include "services/standard/standardfeedsimportexportmodel.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/standard/definitions.h"
@ -193,23 +194,31 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m
// This is FEED.
// Add feed and end this iteration.
QString feed_url = child_element.attribute(QSL("xmlUrl"));
bool add_offline_anyway = true;
if (!feed_url.isEmpty()) {
StandardFeed* guessed = nullptr;
bool result = false;
try {
if (fetch_metadata_online) {
StandardFeed* guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url,
feed_url,
{}, {}, {},
custom_proxy);
if (fetch_metadata_online &&
(guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url,
feed_url,
{}, &result, {}, {},
custom_proxy)) != nullptr &&
result) {
// We should obtain fresh metadata from online feed source.
guessed->setSource(feed_url);
active_model_item->appendChild(guessed);
succeded++;
guessed->setSource(feed_url);
active_model_item->appendChild(guessed);
succeded++;
add_offline_anyway = false;
}
}
else {
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Cannot fetch medatada for feed:"
<< QUOTE_W_SPACE(feed_url)
<< "with error:"
<< QUOTE_W_SPACE_DOT(ex.message());
}
if (add_offline_anyway) {
QString feed_title = child_element.attribute(QSL("text"));
QString feed_encoding = child_element.attribute(QSL("encoding"), DEFAULT_FEED_ENCODING);
QString feed_type = child_element.attribute(QSL("version"), DEFAULT_FEED_TYPE).toUpper();
@ -246,7 +255,7 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m
active_model_item->appendChild(new_feed);
if (fetch_metadata_online && result) {
if (fetch_metadata_online) {
failed++;
}
else {
@ -330,19 +339,29 @@ void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data, bool
for (const QByteArray& url : urls) {
if (!url.isEmpty()) {
StandardFeed* guessed = nullptr;
bool result = false;
bool add_offline_anyway = true;
if (fetch_metadata_online &&
(guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url,
url, {}, &result, {}, {},
custom_proxy)) != nullptr &&
result) {
guessed->setSource(url);
root_item->appendChild(guessed);
succeded++;
try {
if (fetch_metadata_online) {
StandardFeed* guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url,
url, {}, {}, {},
custom_proxy);
guessed->setSource(url);
root_item->appendChild(guessed);
succeded++;
add_offline_anyway = false;
}
}
else {
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_CORE
<< "Cannot fetch medatada for feed:"
<< QUOTE_W_SPACE(url)
<< "with error:"
<< QUOTE_W_SPACE_DOT(ex.message());
}
if (add_offline_anyway) {
auto* feed = new StandardFeed();
feed->setSource(url);
@ -352,7 +371,7 @@ void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data, bool
feed->setEncoding(DEFAULT_FEED_ENCODING);
root_item->appendChild(feed);
if (fetch_metadata_online && result) {
if (fetch_metadata_online) {
failed++;
}
else {