Added some base file sfor gmail plugin.
This commit is contained in:
parent
93f4dae658
commit
b72375e8e8
8 changed files with 939 additions and 2 deletions
10
rssguard.pro
10
rssguard.pro
|
@ -501,7 +501,10 @@ equals(USE_WEBENGINE, true) {
|
|||
src/network-web/oauth2service.h \
|
||||
src/gui/dialogs/oauthlogin.h \
|
||||
src/services/gmail/definitions.h \
|
||||
src/services/gmail/gmailentrypoint.h
|
||||
src/services/gmail/gmailentrypoint.h \
|
||||
src/services/gmail/gmailserviceroot.h \
|
||||
src/services/gmail/gmailfeed.h \
|
||||
src/services/gmail/network/gmailnetworkfactory.h
|
||||
|
||||
SOURCES += src/gui/locationlineedit.cpp \
|
||||
src/gui/webviewer.cpp \
|
||||
|
@ -517,7 +520,10 @@ equals(USE_WEBENGINE, true) {
|
|||
src/services/inoreader/inoreaderfeed.cpp \
|
||||
src/network-web/oauth2service.cpp \
|
||||
src/gui/dialogs/oauthlogin.cpp \
|
||||
src/services/gmail/gmailentrypoint.cpp
|
||||
src/services/gmail/gmailentrypoint.cpp \
|
||||
src/services/gmail/gmailserviceroot.cpp \
|
||||
src/services/gmail/gmailfeed.cpp \
|
||||
src/services/gmail/network/gmailnetworkfactory.cpp
|
||||
|
||||
# Add AdBlock sources.
|
||||
HEADERS += src/network-web/adblock/adblockaddsubscriptiondialog.h \
|
||||
|
|
|
@ -19,4 +19,9 @@
|
|||
#ifndef GMAIL_DEFINITIONS_H
|
||||
#define GMAIL_DEFINITIONS_H
|
||||
|
||||
#define GMAIL_OAUTH_AUTH_URL "https://accounts.google.com/o/oauth2/auth"
|
||||
#define GMAIL_OAUTH_TOKEN_URL "https://accounts.google.com/o/oauth2/token"
|
||||
#define GMAIL_OAUTH_SCOPE "https://mail.google.com/"
|
||||
#define GMAIL_DEFAULT_BATCH_SIZE 100
|
||||
|
||||
#endif // GMAIL_DEFINITIONS_H
|
||||
|
|
47
src/services/gmail/gmailfeed.cpp
Executable file
47
src/services/gmail/gmailfeed.cpp
Executable file
|
@ -0,0 +1,47 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "services/gmail/gmailfeed.h"
|
||||
|
||||
#include "miscellaneous/application.h"
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
#include "services/gmail/gmailserviceroot.h"
|
||||
#include "services/gmail/network/gmailnetworkfactory.h"
|
||||
|
||||
GmailFeed::GmailFeed(RootItem* parent) : Feed(parent) {}
|
||||
|
||||
GmailFeed::GmailFeed(const QSqlRecord& record) : Feed(record) {}
|
||||
|
||||
GmailServiceRoot* GmailFeed::serviceRoot() const {
|
||||
return qobject_cast<GmailServiceRoot*>(getParentServiceRoot());
|
||||
}
|
||||
|
||||
QList<Message> GmailFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||
Feed::Status error;
|
||||
|
||||
// TODO: dodělat
|
||||
QList<Message> messages;/* = serviceRoot()->network()->messages(customId(), error);
|
||||
|
||||
setStatus(error);
|
||||
|
||||
if (error == Feed::Status::NetworkError || error == Feed::Status::AuthError) {
|
||||
* error_during_obtaining = true;
|
||||
}*/
|
||||
|
||||
return messages;
|
||||
}
|
37
src/services/gmail/gmailfeed.h
Executable file
37
src/services/gmail/gmailfeed.h
Executable file
|
@ -0,0 +1,37 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef GMAILFEED_H
|
||||
#define GMAILFEED_H
|
||||
|
||||
#include "services/abstract/feed.h"
|
||||
|
||||
class GmailServiceRoot;
|
||||
|
||||
class GmailFeed : public Feed {
|
||||
public:
|
||||
explicit GmailFeed(RootItem* parent = nullptr);
|
||||
explicit GmailFeed(const QSqlRecord& record);
|
||||
|
||||
GmailServiceRoot* serviceRoot() const;
|
||||
|
||||
private:
|
||||
QList<Message> obtainNewMessages(bool* error_during_obtaining);
|
||||
};
|
||||
|
||||
#endif // GMAILFEED_H
|
224
src/services/gmail/gmailserviceroot.cpp
Executable file
224
src/services/gmail/gmailserviceroot.cpp
Executable file
|
@ -0,0 +1,224 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "services/gmail/gmailserviceroot.h"
|
||||
|
||||
#include "miscellaneous/application.h"
|
||||
#include "miscellaneous/databasequeries.h"
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
#include "network-web/oauth2service.h"
|
||||
#include "services/abstract/recyclebin.h"
|
||||
#include "services/gmail/gmailentrypoint.h"
|
||||
#include "services/gmail/network/gmailnetworkfactory.h"
|
||||
|
||||
GmailServiceRoot::GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent) : ServiceRoot(parent),
|
||||
CacheForServiceRoot(), m_serviceMenu(QList<QAction*>()), m_network(network) {
|
||||
if (network == nullptr) {
|
||||
m_network = new GmailNetworkFactory(this);
|
||||
}
|
||||
else {
|
||||
m_network->setParent(this);
|
||||
}
|
||||
|
||||
m_network->setService(this);
|
||||
setIcon(GmailEntryPoint().icon());
|
||||
}
|
||||
|
||||
GmailServiceRoot::~GmailServiceRoot() {}
|
||||
|
||||
void GmailServiceRoot::updateTitle() {
|
||||
setTitle(m_network->userName() + QSL(" (Gmail)"));
|
||||
}
|
||||
|
||||
void GmailServiceRoot::loadFromDatabase() {
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
Assignment categories = DatabaseQueries::getCategories(database, accountId());
|
||||
Assignment feeds = DatabaseQueries::getInoreaderFeeds(database, accountId());
|
||||
|
||||
// All data are now obtained, lets create the hierarchy.
|
||||
assembleCategories(categories);
|
||||
assembleFeeds(feeds);
|
||||
|
||||
// As the last item, add recycle bin, which is needed.
|
||||
appendChild(recycleBin());
|
||||
updateCounts(true);
|
||||
}
|
||||
|
||||
void GmailServiceRoot::saveAccountDataToDatabase() {
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
|
||||
if (accountId() != NO_PARENT_CATEGORY) {
|
||||
// TODO: dodělat
|
||||
|
||||
/*if (DatabaseQueries::overwriteInoreaderAccount(database, m_network->userName(),
|
||||
m_network->oauth()->clientId(),
|
||||
m_network->oauth()->clientSecret(),
|
||||
m_network->oauth()->redirectUrl(),
|
||||
m_network->oauth()->refreshToken(),
|
||||
m_network->batchSize(),
|
||||
accountId())) {
|
||||
updateTitle();
|
||||
itemChanged(QList<RootItem*>() << this);
|
||||
}*/
|
||||
}
|
||||
else {
|
||||
bool saved;
|
||||
int id_to_assign = DatabaseQueries::createAccount(database, code(), &saved);
|
||||
|
||||
if (saved) {
|
||||
// TODO: dodělat
|
||||
|
||||
/*if (DatabaseQueries::createInoreaderAccount(database, id_to_assign,
|
||||
m_network->userName(),
|
||||
m_network->oauth()->clientId(),
|
||||
m_network->oauth()->clientSecret(),
|
||||
m_network->oauth()->redirectUrl(),
|
||||
m_network->oauth()->refreshToken(),
|
||||
m_network->batchSize())) {
|
||||
setId(id_to_assign);
|
||||
setAccountId(id_to_assign);
|
||||
updateTitle();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::canBeEdited() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::editViaGui() {
|
||||
//FormEditInoreaderAccount form_pointer(qApp->mainFormWidget());
|
||||
// TODO: dodělat
|
||||
//form_pointer.execForEdit(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::supportsFeedAdding() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::supportsCategoryAdding() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void GmailServiceRoot::start(bool freshly_activated) {
|
||||
Q_UNUSED(freshly_activated)
|
||||
|
||||
loadFromDatabase();
|
||||
loadCacheFromFile(accountId());
|
||||
|
||||
m_network->oauth()->login();
|
||||
|
||||
if (childCount() <= 1) {
|
||||
syncIn();
|
||||
}
|
||||
}
|
||||
|
||||
void GmailServiceRoot::stop() {
|
||||
saveCacheToFile(accountId());
|
||||
}
|
||||
|
||||
QList<QAction*> GmailServiceRoot::serviceMenu() {
|
||||
if (m_serviceMenu.isEmpty()) {
|
||||
QAction* act_sync_in = new QAction(qApp->icons()->fromTheme(QSL("view-refresh")), tr("Sync in"), this);
|
||||
|
||||
connect(act_sync_in, &QAction::triggered, this, &GmailServiceRoot::syncIn);
|
||||
m_serviceMenu.append(act_sync_in);
|
||||
}
|
||||
|
||||
return m_serviceMenu;
|
||||
}
|
||||
|
||||
QString GmailServiceRoot::code() const {
|
||||
return GmailEntryPoint().code();
|
||||
}
|
||||
|
||||
QString GmailServiceRoot::additionalTooltip() const {
|
||||
return tr("Authentication status: %1\n"
|
||||
"Login tokens expiration: %2").arg(network()->oauth()->isFullyLoggedIn() ? tr("logged-in") : tr("NOT logged-in"),
|
||||
network()->oauth()->tokensExpireIn().isValid() ?
|
||||
network()->oauth()->tokensExpireIn().toString() : QSL("-"));
|
||||
}
|
||||
|
||||
RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const {
|
||||
// TODO: dodělat
|
||||
return nullptr;
|
||||
|
||||
//return m_network->feedsCategories(true);
|
||||
}
|
||||
|
||||
void GmailServiceRoot::addNewFeed(const QString& url) {
|
||||
Q_UNUSED(url)
|
||||
}
|
||||
|
||||
void GmailServiceRoot::addNewCategory() {}
|
||||
|
||||
void GmailServiceRoot::saveAllCachedData(bool async) {
|
||||
QPair<QMap<RootItem::ReadStatus, QStringList>, QMap<RootItem::Importance, QList<Message>>> msgCache = takeMessageCache();
|
||||
QMapIterator<RootItem::ReadStatus, QStringList> i(msgCache.first);
|
||||
|
||||
// Save the actual data read/unread.
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
auto key = i.key();
|
||||
QStringList ids = i.value();
|
||||
|
||||
if (!ids.isEmpty()) {
|
||||
// TODO: dodělat
|
||||
//network()->markMessagesRead(key, ids, async);
|
||||
}
|
||||
}
|
||||
|
||||
QMapIterator<RootItem::Importance, QList<Message>> j(msgCache.second);
|
||||
|
||||
// Save the actual data important/not important.
|
||||
while (j.hasNext()) {
|
||||
j.next();
|
||||
auto key = j.key();
|
||||
|
||||
QList<Message> messages = j.value();
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
QStringList custom_ids;
|
||||
|
||||
foreach (const Message& msg, messages) {
|
||||
custom_ids.append(msg.m_customId);
|
||||
}
|
||||
|
||||
// TODO: dodělat
|
||||
//network()->markMessagesStarred(key, custom_ids, async);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::canBeDeleted() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GmailServiceRoot::deleteViaGui() {
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
|
||||
if (DatabaseQueries::deleteInoreaderAccount(database, accountId())) {
|
||||
return ServiceRoot::deleteViaGui();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
78
src/services/gmail/gmailserviceroot.h
Executable file
78
src/services/gmail/gmailserviceroot.h
Executable file
|
@ -0,0 +1,78 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
// Copyright (C) 2010-2014 by David Rosca <nowrep@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef INOREADERSERVICEROOT_H
|
||||
#define INOREADERSERVICEROOT_H
|
||||
|
||||
#include "services/abstract/cacheforserviceroot.h"
|
||||
#include "services/abstract/serviceroot.h"
|
||||
|
||||
class GmailNetworkFactory;
|
||||
|
||||
class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GmailServiceRoot(GmailNetworkFactory* network, RootItem* parent = nullptr);
|
||||
virtual ~GmailServiceRoot();
|
||||
|
||||
void saveAccountDataToDatabase();
|
||||
|
||||
void setNetwork(GmailNetworkFactory* network);
|
||||
GmailNetworkFactory* network() const;
|
||||
|
||||
bool canBeEdited() const;
|
||||
bool editViaGui();
|
||||
bool canBeDeleted() const;
|
||||
bool deleteViaGui();
|
||||
bool supportsFeedAdding() const;
|
||||
bool supportsCategoryAdding() const;
|
||||
void start(bool freshly_activated);
|
||||
void stop();
|
||||
QString code() const;
|
||||
|
||||
QString additionalTooltip() const;
|
||||
|
||||
RootItem* obtainNewTreeForSyncIn() const;
|
||||
|
||||
void saveAllCachedData(bool async = true);
|
||||
|
||||
public slots:
|
||||
void addNewFeed(const QString& url);
|
||||
void addNewCategory();
|
||||
void updateTitle();
|
||||
|
||||
private:
|
||||
void loadFromDatabase();
|
||||
QList<QAction*> serviceMenu();
|
||||
|
||||
private:
|
||||
QList<QAction*> m_serviceMenu;
|
||||
GmailNetworkFactory* m_network;
|
||||
};
|
||||
|
||||
inline void GmailServiceRoot::setNetwork(GmailNetworkFactory* network) {
|
||||
m_network = network;
|
||||
}
|
||||
|
||||
inline GmailNetworkFactory* GmailServiceRoot::network() const {
|
||||
return m_network;
|
||||
}
|
||||
|
||||
#endif // INOREADERSERVICEROOT_H
|
462
src/services/gmail/network/gmailnetworkfactory.cpp
Executable file
462
src/services/gmail/network/gmailnetworkfactory.cpp
Executable file
|
@ -0,0 +1,462 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "services/gmail/network/gmailnetworkfactory.h"
|
||||
|
||||
#include "definitions/definitions.h"
|
||||
#include "gui/dialogs/formmain.h"
|
||||
#include "gui/tabwidget.h"
|
||||
#include "miscellaneous/application.h"
|
||||
#include "miscellaneous/databasequeries.h"
|
||||
#include "network-web/networkfactory.h"
|
||||
#include "network-web/oauth2service.h"
|
||||
#include "network-web/silentnetworkaccessmanager.h"
|
||||
#include "network-web/webfactory.h"
|
||||
#include "services/abstract/category.h"
|
||||
#include "services/gmail/definitions.h"
|
||||
#include "services/gmail/gmailfeed.h"
|
||||
#include "services/gmail/gmailserviceroot.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QUrl>
|
||||
|
||||
GmailNetworkFactory::GmailNetworkFactory(QObject* parent) : QObject(parent),
|
||||
m_service(nullptr), m_username(QString()), m_batchSize(GMAIL_DEFAULT_BATCH_SIZE),
|
||||
m_oauth2(new OAuth2Service(GMAIL_OAUTH_AUTH_URL, GMAIL_OAUTH_TOKEN_URL,
|
||||
QString(), QString(), GMAIL_OAUTH_SCOPE)) {
|
||||
initializeOauth();
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::setService(GmailServiceRoot* service) {
|
||||
m_service = service;
|
||||
}
|
||||
|
||||
OAuth2Service* GmailNetworkFactory::oauth() const {
|
||||
return m_oauth2;
|
||||
}
|
||||
|
||||
QString GmailNetworkFactory::userName() const {
|
||||
return m_username;
|
||||
}
|
||||
|
||||
int GmailNetworkFactory::batchSize() const {
|
||||
return m_batchSize;
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::setBatchSize(int batch_size) {
|
||||
m_batchSize = batch_size;
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::initializeOauth() {
|
||||
connect(m_oauth2, &OAuth2Service::tokensRetrieveError, this, &GmailNetworkFactory::onTokensError);
|
||||
connect(m_oauth2, &OAuth2Service::authFailed, this, &GmailNetworkFactory::onAuthFailed);
|
||||
connect(m_oauth2, &OAuth2Service::tokensReceived, [this](QString access_token, QString refresh_token, int expires_in) {
|
||||
Q_UNUSED(expires_in)
|
||||
|
||||
if (m_service != nullptr && !access_token.isEmpty() && !refresh_token.isEmpty()) {
|
||||
QSqlDatabase database = qApp->database()->connection(metaObject()->className(), DatabaseFactory::FromSettings);
|
||||
DatabaseQueries::storeNewInoreaderTokens(database, refresh_token, m_service->accountId());
|
||||
|
||||
qApp->showGuiMessage(tr("Logged in successfully"),
|
||||
tr("Your login to Inoreader was authorized."),
|
||||
QSystemTrayIcon::MessageIcon::Information);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::setUsername(const QString& username) {
|
||||
m_username = username;
|
||||
}
|
||||
|
||||
RootItem* GmailNetworkFactory::feedsCategories(bool obtain_icons) {
|
||||
Downloader downloader;
|
||||
QEventLoop loop;
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
downloader.appendRawHeader(QString("Authorization").toLocal8Bit(), bearer.toLocal8Bit());
|
||||
|
||||
// We need to quit event loop when the download finishes.
|
||||
connect(&downloader, &Downloader::completed, &loop, &QEventLoop::quit);
|
||||
|
||||
// TODO: dodělat
|
||||
//downloader.manipulateData(INOREADER_API_LIST_LABELS, QNetworkAccessManager::Operation::GetOperation);
|
||||
loop.exec();
|
||||
|
||||
if (downloader.lastOutputError() != QNetworkReply::NetworkError::NoError) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString category_data = downloader.lastOutputData();
|
||||
|
||||
// TODO: dodělat
|
||||
//downloader.manipulateData(INOREADER_API_LIST_FEEDS, QNetworkAccessManager::Operation::GetOperation);
|
||||
loop.exec();
|
||||
|
||||
if (downloader.lastOutputError() != QNetworkReply::NetworkError::NoError) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString feed_data = downloader.lastOutputData();
|
||||
|
||||
return decodeFeedCategoriesData(category_data, feed_data, obtain_icons);
|
||||
}
|
||||
|
||||
QList<Message> GmailNetworkFactory::messages(const QString& stream_id, Feed::Status& error) {
|
||||
Downloader downloader;
|
||||
QEventLoop loop;
|
||||
QString target_url;// TODO: dodělat
|
||||
// = INOREADER_API_FEED_CONTENTS;
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
error = Feed::Status::AuthError;
|
||||
return QList<Message>();
|
||||
}
|
||||
|
||||
target_url += QSL("/") + QUrl::toPercentEncoding(stream_id) + QString("?n=%1").arg(batchSize());
|
||||
downloader.appendRawHeader(QString("Authorization").toLocal8Bit(), bearer.toLocal8Bit());
|
||||
|
||||
// We need to quit event loop when the download finishes.
|
||||
connect(&downloader, &Downloader::completed, &loop, &QEventLoop::quit);
|
||||
downloader.manipulateData(target_url, QNetworkAccessManager::Operation::GetOperation);
|
||||
loop.exec();
|
||||
|
||||
if (downloader.lastOutputError() != QNetworkReply::NetworkError::NoError) {
|
||||
error = Feed::Status::NetworkError;
|
||||
return QList<Message>();
|
||||
}
|
||||
else {
|
||||
QString messages_data = downloader.lastOutputData();
|
||||
|
||||
error = Feed::Status::Normal;
|
||||
return decodeMessages(messages_data, stream_id);
|
||||
}
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids, bool async) {
|
||||
QString target_url;// TODO: dodělat
|
||||
// = INOREADER_API_EDIT_TAG;
|
||||
// TODO: dodělat
|
||||
//
|
||||
|
||||
/*
|
||||
if (status == RootItem::ReadStatus::Read) {
|
||||
target_url += QString("?a=user/-/") + INOREADER_STATE_READ + "&";
|
||||
}
|
||||
else {
|
||||
target_url += QString("?r=user/-/") + INOREADER_STATE_READ + "&";
|
||||
}*/
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QPair<QByteArray, QByteArray>> headers;
|
||||
headers.append(QPair<QByteArray, QByteArray>(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
m_oauth2->bearer().toLocal8Bit()));
|
||||
|
||||
QStringList trimmed_ids;
|
||||
QRegularExpression regex_short_id(QSL("[0-9a-zA-Z]+$"));
|
||||
|
||||
foreach (const QString& id, custom_ids) {
|
||||
QString simplified_id = regex_short_id.match(id).captured();
|
||||
|
||||
trimmed_ids.append(QString("i=") + simplified_id);
|
||||
}
|
||||
|
||||
QStringList working_subset;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
working_subset.reserve(trimmed_ids.size() > 200 ? 200 : trimmed_ids.size());
|
||||
|
||||
// Now, we perform messages update in batches (max 200 messages per batch).
|
||||
while (!trimmed_ids.isEmpty()) {
|
||||
// We take 200 IDs.
|
||||
for (int i = 0; i < 200 && !trimmed_ids.isEmpty(); i++) {
|
||||
working_subset.append(trimmed_ids.takeFirst());
|
||||
}
|
||||
|
||||
QString batch_final_url = target_url + working_subset.join(QL1C('&'));
|
||||
|
||||
// We send this batch.
|
||||
if (async) {
|
||||
|
||||
NetworkFactory::performAsyncNetworkOperation(batch_final_url,
|
||||
timeout,
|
||||
QByteArray(),
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
headers);
|
||||
}
|
||||
else {
|
||||
QByteArray output;
|
||||
|
||||
NetworkFactory::performNetworkOperation(batch_final_url,
|
||||
timeout,
|
||||
QByteArray(),
|
||||
output,
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
headers);
|
||||
}
|
||||
|
||||
// Cleanup for next batch.
|
||||
working_subset.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::markMessagesStarred(RootItem::Importance importance, const QStringList& custom_ids, bool async) {
|
||||
QString target_url; // TODO: dodělat
|
||||
//= INOREADER_API_EDIT_TAG;
|
||||
|
||||
/*
|
||||
if (importance == RootItem::Importance::Important) {
|
||||
target_url += QString("?a=user/-/") + INOREADER_STATE_IMPORTANT + "&";
|
||||
}
|
||||
else {
|
||||
target_url += QString("?r=user/-/") + INOREADER_STATE_IMPORTANT + "&";
|
||||
}*/
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QPair<QByteArray, QByteArray>> headers;
|
||||
headers.append(QPair<QByteArray, QByteArray>(QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
m_oauth2->bearer().toLocal8Bit()));
|
||||
|
||||
QStringList trimmed_ids;
|
||||
QRegularExpression regex_short_id(QSL("[0-9a-zA-Z]+$"));
|
||||
|
||||
foreach (const QString& id, custom_ids) {
|
||||
QString simplified_id = regex_short_id.match(id).captured();
|
||||
|
||||
trimmed_ids.append(QString("i=") + simplified_id);
|
||||
}
|
||||
|
||||
QStringList working_subset;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
working_subset.reserve(trimmed_ids.size() > 200 ? 200 : trimmed_ids.size());
|
||||
|
||||
// Now, we perform messages update in batches (max 200 messages per batch).
|
||||
while (!trimmed_ids.isEmpty()) {
|
||||
// We take 200 IDs.
|
||||
for (int i = 0; i < 200 && !trimmed_ids.isEmpty(); i++) {
|
||||
working_subset.append(trimmed_ids.takeFirst());
|
||||
}
|
||||
|
||||
QString batch_final_url = target_url + working_subset.join(QL1C('&'));
|
||||
|
||||
// We send this batch.
|
||||
if (async) {
|
||||
|
||||
NetworkFactory::performAsyncNetworkOperation(batch_final_url,
|
||||
timeout,
|
||||
QByteArray(),
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
headers);
|
||||
}
|
||||
else {
|
||||
QByteArray output;
|
||||
|
||||
NetworkFactory::performNetworkOperation(batch_final_url,
|
||||
timeout,
|
||||
QByteArray(),
|
||||
output,
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
headers);
|
||||
}
|
||||
|
||||
// Cleanup for next batch.
|
||||
working_subset.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::onTokensError(const QString& error, const QString& error_description) {
|
||||
Q_UNUSED(error)
|
||||
|
||||
qApp->showGuiMessage(tr("Inoreader: authentication error"),
|
||||
tr("Click this to login again. Error is: '%1'").arg(error_description),
|
||||
QSystemTrayIcon::Critical,
|
||||
nullptr, false,
|
||||
[this]() {
|
||||
m_oauth2->login();
|
||||
});
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::onAuthFailed() {
|
||||
qApp->showGuiMessage(tr("Inoreader: authorization denied"),
|
||||
tr("Click this to login again."),
|
||||
QSystemTrayIcon::Critical,
|
||||
nullptr, false,
|
||||
[this]() {
|
||||
m_oauth2->login();
|
||||
});
|
||||
}
|
||||
|
||||
QList<Message> GmailNetworkFactory::decodeMessages(const QString& messages_json_data, const QString& stream_id) {
|
||||
QList<Message> messages;
|
||||
QJsonArray json = QJsonDocument::fromJson(messages_json_data.toUtf8()).object()["items"].toArray();
|
||||
|
||||
messages.reserve(json.count());
|
||||
|
||||
foreach (const QJsonValue& obj, json) {
|
||||
auto message_obj = obj.toObject();
|
||||
Message message;
|
||||
|
||||
message.m_title = message_obj["title"].toString();
|
||||
message.m_author = message_obj["author"].toString();
|
||||
message.m_created = QDateTime::fromSecsSinceEpoch(message_obj["published"].toInt());
|
||||
message.m_createdFromFeed = true;
|
||||
message.m_customId = message_obj["id"].toString();
|
||||
|
||||
auto alternates = message_obj["alternate"].toArray();
|
||||
auto enclosures = message_obj["enclosure"].toArray();
|
||||
auto categories = message_obj["categories"].toArray();
|
||||
|
||||
foreach (const QJsonValue& alt, alternates) {
|
||||
auto alt_obj = alt.toObject();
|
||||
QString mime = alt_obj["type"].toString();
|
||||
QString href = alt_obj["href"].toString();
|
||||
|
||||
if (mime == QL1S("text/html")) {
|
||||
message.m_url = href;
|
||||
}
|
||||
else {
|
||||
message.m_enclosures.append(Enclosure(href, mime));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const QJsonValue& enc, enclosures) {
|
||||
auto enc_obj = enc.toObject();
|
||||
QString mime = enc_obj["type"].toString();
|
||||
QString href = enc_obj["href"].toString();
|
||||
|
||||
message.m_enclosures.append(Enclosure(href, mime));
|
||||
}
|
||||
|
||||
foreach (const QJsonValue& cat, categories) {
|
||||
QString category = cat.toString();
|
||||
|
||||
// TODO: dodělat
|
||||
//
|
||||
|
||||
/*
|
||||
if (category.contains(INOREADER_STATE_READ)) {
|
||||
message.m_isRead = !category.contains(INOREADER_STATE_READING_LIST);
|
||||
}
|
||||
else if (category.contains(INOREADER_STATE_IMPORTANT)) {
|
||||
message.m_isImportant = category.contains(INOREADER_STATE_IMPORTANT);
|
||||
}*/
|
||||
}
|
||||
|
||||
message.m_contents = message_obj["summary"].toObject()["content"].toString();
|
||||
message.m_feedId = stream_id;
|
||||
|
||||
messages.append(message);
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
RootItem* GmailNetworkFactory::decodeFeedCategoriesData(const QString& categories, const QString& feeds, bool obtain_icons) {
|
||||
RootItem* parent = new RootItem();
|
||||
QJsonArray json = QJsonDocument::fromJson(categories.toUtf8()).object()["tags"].toArray();
|
||||
|
||||
QMap<QString, RootItem*> cats;
|
||||
cats.insert(QString(), parent);
|
||||
|
||||
foreach (const QJsonValue& obj, json) {
|
||||
auto label = obj.toObject();
|
||||
QString label_id = label["id"].toString();
|
||||
|
||||
if (label_id.contains(QSL("/label/"))) {
|
||||
// We have label (not "state").
|
||||
Category* category = new Category();
|
||||
|
||||
category->setDescription(label["htmlUrl"].toString());
|
||||
category->setTitle(label_id.mid(label_id.lastIndexOf(QL1C('/')) + 1));
|
||||
category->setCustomId(label_id);
|
||||
|
||||
cats.insert(category->customId(), category);
|
||||
|
||||
// All categories in ownCloud are top-level.
|
||||
parent->appendChild(category);
|
||||
}
|
||||
}
|
||||
|
||||
json = QJsonDocument::fromJson(feeds.toUtf8()).object()["subscriptions"].toArray();
|
||||
|
||||
foreach (const QJsonValue& obj, json) {
|
||||
auto subscription = obj.toObject();
|
||||
QString id = subscription["id"].toString();
|
||||
QString title = subscription["title"].toString();
|
||||
QString url = subscription["htmlUrl"].toString();
|
||||
QString parent_label;
|
||||
QJsonArray categories = subscription["categories"].toArray();
|
||||
|
||||
foreach (const QJsonValue& cat, categories) {
|
||||
QString potential_id = cat.toObject()["id"].toString();
|
||||
|
||||
if (potential_id.contains(QSL("/label/"))) {
|
||||
parent_label = potential_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We have label (not "state").
|
||||
GmailFeed* feed = new GmailFeed();
|
||||
|
||||
feed->setDescription(url);
|
||||
feed->setUrl(url);
|
||||
feed->setTitle(title);
|
||||
feed->setCustomId(id);
|
||||
|
||||
if (obtain_icons) {
|
||||
QString icon_url = subscription["iconUrl"].toString();
|
||||
|
||||
if (!icon_url.isEmpty()) {
|
||||
QByteArray icon_data;
|
||||
|
||||
if (NetworkFactory::performNetworkOperation(icon_url, DOWNLOAD_TIMEOUT,
|
||||
QByteArray(), icon_data,
|
||||
QNetworkAccessManager::GetOperation).first == QNetworkReply::NoError) {
|
||||
// Icon downloaded, set it up.
|
||||
QPixmap icon_pixmap;
|
||||
|
||||
icon_pixmap.loadFromData(icon_data);
|
||||
feed->setIcon(QIcon(icon_pixmap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cats.contains(parent_label)) {
|
||||
cats[parent_label]->appendChild(feed);
|
||||
}
|
||||
}
|
||||
|
||||
return parent;
|
||||
}
|
78
src/services/gmail/network/gmailnetworkfactory.h
Executable file
78
src/services/gmail/network/gmailnetworkfactory.h
Executable file
|
@ -0,0 +1,78 @@
|
|||
// This file is part of RSS Guard.
|
||||
|
||||
//
|
||||
// Copyright (C) 2011-2017 by Martin Rotter <rotter.martinos@gmail.com>
|
||||
//
|
||||
// RSS Guard 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.
|
||||
//
|
||||
// RSS Guard 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 RSS Guard. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#ifndef INOREADERNETWORKFACTORY_H
|
||||
#define INOREADERNETWORKFACTORY_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "core/message.h"
|
||||
|
||||
#include "services/abstract/feed.h"
|
||||
#include "services/abstract/rootitem.h"
|
||||
|
||||
#include <QNetworkReply>
|
||||
|
||||
class RootItem;
|
||||
class GmailServiceRoot;
|
||||
class OAuth2Service;
|
||||
|
||||
class GmailNetworkFactory : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GmailNetworkFactory(QObject* parent = nullptr);
|
||||
|
||||
void setService(GmailServiceRoot* service);
|
||||
|
||||
OAuth2Service* oauth() const;
|
||||
|
||||
QString userName() const;
|
||||
void setUsername(const QString& username);
|
||||
|
||||
// Gets/sets the amount of messages to obtain during single feed update.
|
||||
int batchSize() const;
|
||||
void setBatchSize(int batch_size);
|
||||
|
||||
// Returns tree of feeds/categories.
|
||||
// Top-level root of the tree is not needed here.
|
||||
// Returned items do not have primary IDs assigned.
|
||||
RootItem* feedsCategories(bool obtain_icons);
|
||||
|
||||
QList<Message> messages(const QString& stream_id, Feed::Status& error);
|
||||
void markMessagesRead(RootItem::ReadStatus status, const QStringList& custom_ids, bool async = true);
|
||||
void markMessagesStarred(RootItem::Importance importance, const QStringList& custom_ids, bool async = true);
|
||||
|
||||
private slots:
|
||||
void onTokensError(const QString& error, const QString& error_description);
|
||||
void onAuthFailed();
|
||||
|
||||
private:
|
||||
QList<Message> decodeMessages(const QString& messages_json_data, const QString& stream_id);
|
||||
RootItem* decodeFeedCategoriesData(const QString& categories, const QString& feeds, bool obtain_icons);
|
||||
|
||||
void initializeOauth();
|
||||
|
||||
private:
|
||||
GmailServiceRoot* m_service;
|
||||
QString m_username;
|
||||
int m_batchSize;
|
||||
OAuth2Service* m_oauth2;
|
||||
};
|
||||
|
||||
#endif // INOREADERNETWORKFACTORY_H
|
Loading…
Add table
Reference in a new issue