greader supports feed deleting

This commit is contained in:
Martin Rotter 2023-11-13 12:10:58 +01:00
parent 80392d4c05
commit caecf5355a
9 changed files with 115 additions and 12 deletions

View File

@ -30,7 +30,7 @@ else {
$is_qt_6 = $qt_version.StartsWith("6") $is_qt_6 = $qt_version.StartsWith("6")
$maria_version = "11.1.2" $maria_version = "11.1.2"
$maria_link = "https://archive.mariadb.org/mariadb-$maria_version/winx64-packages/mariadb-$maria_version-winx64.zip" $maria_link = "https://mirror.netcologne.de/mariadb/mariadb-$maria_version/winx64-packages/mariadb-$maria_version-winx64.zip"
$maria_output = "maria.zip" $maria_output = "maria.zip"
$cmake_version = "3.27.7" $cmake_version = "3.27.7"

View File

@ -352,10 +352,16 @@ set(SOURCES
services/greader/greadernetwork.h services/greader/greadernetwork.h
services/greader/greaderserviceroot.cpp services/greader/greaderserviceroot.cpp
services/greader/greaderserviceroot.h services/greader/greaderserviceroot.h
services/greader/greaderfeed.cpp
services/greader/greaderfeed.h
services/greader/gui/formeditgreaderaccount.cpp services/greader/gui/formeditgreaderaccount.cpp
services/greader/gui/formeditgreaderaccount.h services/greader/gui/formeditgreaderaccount.h
services/greader/gui/greaderaccountdetails.cpp services/greader/gui/greaderaccountdetails.cpp
services/greader/gui/greaderaccountdetails.h services/greader/gui/greaderaccountdetails.h
services/greader/gui/formgreaderfeeddetails.cpp
services/greader/gui/formgreaderfeeddetails.h
services/greader/gui/greaderfeeddetails.cpp
services/greader/gui/greaderfeeddetails.h
services/owncloud/definitions.h services/owncloud/definitions.h
services/owncloud/gui/formeditowncloudaccount.cpp services/owncloud/gui/formeditowncloudaccount.cpp
services/owncloud/gui/formeditowncloudaccount.h services/owncloud/gui/formeditowncloudaccount.h
@ -487,6 +493,7 @@ set(UI_FILES
services/gmail/gui/formaddeditemail.ui services/gmail/gui/formaddeditemail.ui
services/gmail/gui/gmailaccountdetails.ui services/gmail/gui/gmailaccountdetails.ui
services/greader/gui/greaderaccountdetails.ui services/greader/gui/greaderaccountdetails.ui
services/greader/gui/greaderfeeddetails.ui
services/owncloud/gui/owncloudaccountdetails.ui services/owncloud/gui/owncloudaccountdetails.ui
services/reddit/gui/redditaccountdetails.ui services/reddit/gui/redditaccountdetails.ui
services/standard/gui/formdiscoverfeeds.ui services/standard/gui/formdiscoverfeeds.ui

View File

@ -29,11 +29,17 @@
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag" #define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
#define GREADER_API_SUBSCRIPTION_EXPORT "reader/api/0/subscription/export" #define GREADER_API_SUBSCRIPTION_EXPORT "reader/api/0/subscription/export"
#define GREADER_API_SUBSCRIPTION_IMPORT "reader/api/0/subscription/import" #define GREADER_API_SUBSCRIPTION_IMPORT "reader/api/0/subscription/import"
#define GREADER_API_SUBSCRIPTION_EDIT "reader/api/0/subscription/edit?ac=%1&s=%2"
#define GREADER_API_ITEM_IDS "reader/api/0/stream/items/ids?output=json&n=%2&s=%1" #define GREADER_API_ITEM_IDS "reader/api/0/stream/items/ids?output=json&n=%2&s=%1"
#define GREADER_API_ITEM_CONTENTS "reader/api/0/stream/items/contents?output=json&n=200000" #define GREADER_API_ITEM_CONTENTS "reader/api/0/stream/items/contents?output=json&n=200000"
#define GREADER_API_TOKEN "reader/api/0/token" #define GREADER_API_TOKEN "reader/api/0/token"
#define GREADER_API_USER_INFO "reader/api/0/user-info?output=json" #define GREADER_API_USER_INFO "reader/api/0/user-info?output=json"
// Edit subscription ops.
#define GREADER_API_EDIT_SUBSCRIPTION_ADD "subscribe"
#define GREADER_API_EDIT_SUBSCRIPTION_MODIFY "edit"
#define GREADER_API_EDIT_SUBSCRIPTION_DELETE "unsubscribe"
// Misc. // Misc.
#define GREADER_API_ITEM_IDS_MAX 200000 #define GREADER_API_ITEM_IDS_MAX 200000
#define GREADER_API_EDIT_TAG_BATCH 200 #define GREADER_API_EDIT_TAG_BATCH 200

View File

@ -16,6 +16,7 @@
#include "services/abstract/label.h" #include "services/abstract/label.h"
#include "services/abstract/labelsnode.h" #include "services/abstract/labelsnode.h"
#include "services/greader/definitions.h" #include "services/greader/definitions.h"
#include "services/greader/greaderfeed.h"
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
@ -341,6 +342,57 @@ QNetworkReply::NetworkError GreaderNetwork::markMessagesStarred(RootItem::Import
proxy); proxy);
} }
void GreaderNetwork::subscriptionEdit(const QString& op,
const QString& stream_id,
const QString& new_title,
const QString& set_label,
const QString& unset_label,
const QNetworkProxy& proxy) {
if (!ensureLogin(proxy)) {
throw ApplicationException(tr("login failed"));
}
QString full_url = generateFullUrl(Operations::SubscriptionEdit).arg(op, stream_id);
if (op == QSL(GREADER_API_EDIT_SUBSCRIPTION_ADD)) {
full_url += QSL("&t=%1").arg(new_title);
if (!set_label.isEmpty()) {
full_url += QSL("&a=%1").arg(set_label);
}
}
if (op == QSL(GREADER_API_EDIT_SUBSCRIPTION_MODIFY)) {
full_url += QSL("&t=%1").arg(new_title);
if (!set_label.isEmpty()) {
full_url += QSL("&a=%1").arg(set_label);
}
else if (!unset_label.isEmpty()) {
full_url += QSL("&r=%1").arg(unset_label);
}
}
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
QByteArray output;
auto result = NetworkFactory::performNetworkOperation(full_url,
timeout,
{},
output,
QNetworkAccessManager::Operation::PostOperation,
{authHeader()},
false,
{},
{},
proxy);
if (result.m_networkError != QNetworkReply::NetworkError::NoError) {
qCriticalNN << LOGSEC_GREADER << "Cannot edit subscription:" << QUOTE_W_SPACE_DOT(result.m_networkError);
throw NetworkException(result.m_networkError, output);
}
}
void GreaderNetwork::subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy) { void GreaderNetwork::subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy) {
if (!ensureLogin(proxy)) { if (!ensureLogin(proxy)) {
throw ApplicationException(tr("login failed")); throw ApplicationException(tr("login failed"));
@ -749,7 +801,7 @@ RootItem* GreaderNetwork::decodeTagsSubscriptions(const QString& categories,
} }
// We have label (not "state"). // We have label (not "state").
auto* feed = new Feed(); auto* feed = new GreaderFeed();
feed->setDescription(url); feed->setDescription(url);
feed->setSource(url); feed->setSource(url);
@ -1127,6 +1179,9 @@ QString GreaderNetwork::generateFullUrl(GreaderNetwork::Operations operation) co
case Operations::SubscriptionImport: case Operations::SubscriptionImport:
return sanitizedBaseUrl() + QSL(GREADER_API_SUBSCRIPTION_IMPORT); return sanitizedBaseUrl() + QSL(GREADER_API_SUBSCRIPTION_IMPORT);
case Operations::SubscriptionEdit:
return sanitizedBaseUrl() + QSL(GREADER_API_SUBSCRIPTION_EDIT);
case Operations::Token: case Operations::Token:
return sanitizedBaseUrl() + QSL(GREADER_API_TOKEN); return sanitizedBaseUrl() + QSL(GREADER_API_TOKEN);

View File

@ -26,7 +26,8 @@ class GreaderNetwork : public QObject {
ItemIds, ItemIds,
ItemContents, ItemContents,
SubscriptionExport, SubscriptionExport,
SubscriptionImport SubscriptionImport,
SubscriptionEdit
}; };
explicit GreaderNetwork(QObject* parent = nullptr); explicit GreaderNetwork(QObject* parent = nullptr);
@ -84,6 +85,12 @@ class GreaderNetwork : public QObject {
void setOauth(OAuth2Service* oauth); void setOauth(OAuth2Service* oauth);
// API methods. // API methods.
void subscriptionEdit(const QString& op,
const QString& stream_id,
const QString& new_title,
const QString& set_label,
const QString& unset_label,
const QNetworkProxy& proxy);
void subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy); void subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy);
QByteArray subscriptionExport(const QNetworkProxy& proxy); QByteArray subscriptionExport(const QNetworkProxy& proxy);
QNetworkReply::NetworkError editLabels(const QString& state, QNetworkReply::NetworkError editLabels(const QString& state,

View File

@ -7,12 +7,15 @@
#include "gui/messagebox.h" #include "gui/messagebox.h"
#include "miscellaneous/application.h" #include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h" #include "miscellaneous/iconfactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/textfactory.h" #include "miscellaneous/textfactory.h"
#include "network-web/oauth2service.h" #include "network-web/oauth2service.h"
#include "services/greader/definitions.h" #include "services/greader/definitions.h"
#include "services/greader/greaderentrypoint.h" #include "services/greader/greaderentrypoint.h"
#include "services/greader/greaderfeed.h"
#include "services/greader/greadernetwork.h" #include "services/greader/greadernetwork.h"
#include "services/greader/gui/formeditgreaderaccount.h" #include "services/greader/gui/formeditgreaderaccount.h"
#include "services/greader/gui/formgreaderfeeddetails.h"
#include <QFileDialog> #include <QFileDialog>
@ -211,7 +214,7 @@ bool GreaderServiceRoot::wantsBaggedIdsOfExistingMessages() const {
void GreaderServiceRoot::start(bool freshly_activated) { void GreaderServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) { if (!freshly_activated) {
DatabaseQueries::loadRootFromDatabase<Category, Feed>(this); DatabaseQueries::loadRootFromDatabase<Category, GreaderFeed>(this);
loadCacheFromFile(); loadCacheFromFile();
} }
@ -331,6 +334,32 @@ ServiceRoot::LabelOperation GreaderServiceRoot::supportedLabelOperations() const
return ServiceRoot::LabelOperation::Synchronised; return ServiceRoot::LabelOperation::Synchronised;
} }
bool GreaderServiceRoot::supportsFeedAdding() const {
return true;
}
void GreaderServiceRoot::addNewFeed(RootItem* selected_item, const QString& url) {
if (!qApp->feedUpdateLock()->tryLock()) {
// Lock was not obtained because
// it is used probably by feed updater or application
// is quitting.
qApp->showGuiMessage(Notification::Event::GeneralEvent,
{tr("Cannot add item"),
tr("Cannot add feed because another critical operation is ongoing."),
QSystemTrayIcon::MessageIcon::Warning});
return;
}
QScopedPointer<FormGreaderFeedDetails> form_pointer(new FormGreaderFeedDetails(this,
selected_item,
url,
qApp->mainFormWidget()));
form_pointer->addEditFeed<GreaderFeed>();
qApp->feedUpdateLock()->unlock();
}
void GreaderServiceRoot::updateTitleIcon() { void GreaderServiceRoot::updateTitleIcon() {
setTitle(QSL("%1 (%2)").arg(TextFactory::extractUsernameFromEmail(m_network->username()), setTitle(QSL("%1 (%2)").arg(TextFactory::extractUsernameFromEmail(m_network->username()),
GreaderServiceRoot::serviceToString(m_network->service()))); GreaderServiceRoot::serviceToString(m_network->service())));

View File

@ -35,6 +35,8 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
virtual QList<QAction*> serviceMenu(); virtual QList<QAction*> serviceMenu();
virtual void saveAllCachedData(bool ignore_errors); virtual void saveAllCachedData(bool ignore_errors);
virtual LabelOperation supportedLabelOperations() const; virtual LabelOperation supportedLabelOperations() const;
virtual bool supportsFeedAdding() const;
virtual void addNewFeed(RootItem* selected_item, const QString& url = QString());
virtual QVariantHash customDatabaseData() const; virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data); virtual void setCustomDatabaseData(const QVariantHash& data);
virtual void aboutToBeginFeedFetching(const QList<Feed*>& feeds, virtual void aboutToBeginFeedFetching(const QList<Feed*>& feeds,

View File

@ -29,7 +29,7 @@ void FormTtRssFeedDetails::apply() {
else { else {
RootItem* parent = m_feedDetails->ui.m_cmbParentCategory->currentData().value<RootItem*>(); RootItem* parent = m_feedDetails->ui.m_cmbParentCategory->currentData().value<RootItem*>();
auto* root = qobject_cast<TtRssServiceRoot*>(parent->getParentServiceRoot()); auto* root = qobject_cast<TtRssServiceRoot*>(parent->getParentServiceRoot());
const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customId().toInt(); const int category_id = parent->kind() == RootItem::Kind::ServiceRoot ? 0 : parent->customNumericId();
const TtRssSubscribeToFeedResponse response = const TtRssSubscribeToFeedResponse response =
root->network()->subscribeToFeed(m_feedDetails->ui.m_txtUrl->lineEdit()->text(), root->network()->subscribeToFeed(m_feedDetails->ui.m_txtUrl->lineEdit()->text(),
category_id, category_id,
@ -66,11 +66,6 @@ void FormTtRssFeedDetails::loadFeedData() {
if (!m_urlToProcess.isEmpty()) { if (!m_urlToProcess.isEmpty()) {
m_feedDetails->ui.m_txtUrl->lineEdit()->setText(m_urlToProcess); m_feedDetails->ui.m_txtUrl->lineEdit()->setText(m_urlToProcess);
} }
/*
else if (Application::clipboard()->mimeData()->hasText()) {
m_feedDetails->ui.m_txtUrl->lineEdit()->setText(Application::clipboard()->text());
}
*/
m_feedDetails->ui.m_txtUrl->lineEdit()->selectAll(); m_feedDetails->ui.m_txtUrl->lineEdit()->selectAll();
m_feedDetails->ui.m_txtUrl->setFocus(); m_feedDetails->ui.m_txtUrl->setFocus();

View File

@ -11,8 +11,10 @@ class AuthenticationDetails;
class FormTtRssFeedDetails : public FormFeedDetails { class FormTtRssFeedDetails : public FormFeedDetails {
public: public:
explicit FormTtRssFeedDetails(ServiceRoot* service_root, RootItem* parent_to_select = nullptr, explicit FormTtRssFeedDetails(ServiceRoot* service_root,
const QString& url = QString(), QWidget* parent = nullptr); RootItem* parent_to_select = nullptr,
const QString& url = QString(),
QWidget* parent = nullptr);
protected slots: protected slots:
virtual void apply(); virtual void apply();