display notifications when login failure etc.

This commit is contained in:
Martin Rotter 2021-08-13 11:11:57 +02:00
parent 0ff6e86c62
commit b1e45623c5
10 changed files with 128 additions and 103 deletions

View File

@ -10,7 +10,11 @@
NotificationsEditor::NotificationsEditor(QWidget* parent) : QScrollArea(parent), m_layout(new QVBoxLayout(this)) {
m_ui.setupUi(this);
setLayout(m_layout);
QWidget* wdg = new QWidget(this);
wdg->setLayout(m_layout);
setWidget(wdg);
}
void NotificationsEditor::loadNotifications(const QList<Notification>& notifications) {

View File

@ -13,6 +13,9 @@
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
</widget>
<resources/>
<connections/>

View File

@ -25,7 +25,7 @@ SingleNotificationEditor::SingleNotificationEditor(const Notification& notificat
connect(m_ui.m_txtSound, &QLineEdit::textChanged, this, &SingleNotificationEditor::notificationChanged);
connect(m_ui.m_cbBalloon, &QCheckBox::toggled, this, &SingleNotificationEditor::notificationChanged);
//setFixedHeight(sizeHint().height());
setFixedHeight(sizeHint().height());
}
Notification SingleNotificationEditor::notification() const {

View File

@ -95,13 +95,11 @@ Application::Application(const QString& id, int& argc, char** argv)
if (isFirstRun()) {
m_notifications->save({
Notification(Notification::Event::GeneralEvent,
true),
Notification(Notification::Event::NewUnreadArticlesFetched,
true,
Notification(Notification::Event::GeneralEvent, true),
Notification(Notification::Event::NewUnreadArticlesFetched, true,
QSL("%1/rooster.wav").arg(SOUNDS_BUILTIN_DIRECTORY)),
Notification(Notification::Event::NewAppVersionAvailable,
true)
Notification(Notification::Event::NewAppVersionAvailable, true),
Notification(Notification::Event::LoginFailure, true)
}, settings());
}
else {
@ -254,8 +252,7 @@ void Application::eliminateFirstRuns() {
settings()->setValue(GROUP(General), QString(General::FirstRun) + QL1C('_') + APP_VERSION, false);
}
NotificationFactory* Application::notifications() const
{
NotificationFactory* Application::notifications() const {
return m_notifications;
}

View File

@ -43,6 +43,7 @@ QList<Notification::Event> Notification::allEvents() {
Event::NewUnreadArticlesFetched,
Event::ArticlesFetchingStarted,
Event::LoginDataRefreshed,
Event::LoginFailure,
Event::NewAppVersionAvailable,
};
}
@ -58,6 +59,9 @@ QString Notification::nameForEvent(Notification::Event event) {
case Notification::Event::LoginDataRefreshed:
return QObject::tr("Login data refreshed");
case Notification::Event::LoginFailure:
return QObject::tr("Login failed");
case Notification::Event::NewAppVersionAvailable:
return QObject::tr("New %1 version is available").arg(APP_NAME);

View File

@ -28,7 +28,9 @@ class Notification {
// OAuth or similar mechanism.
LoginDataRefreshed = 4,
NewAppVersionAvailable = 5
NewAppVersionAvailable = 5,
LoginFailure = 6
};
explicit Notification(Event event = Event::NoEvent, bool balloon = {}, const QString& sound_path = {});

View File

@ -80,7 +80,7 @@ OAuth2Service::~OAuth2Service() {
QString OAuth2Service::bearer() {
if (!isFullyLoggedIn()) {
qApp->showGuiMessage(Notification::Event::GeneralEvent,
qApp->showGuiMessage(Notification::Event::LoginFailure,
tr("You have to login first"),
tr("Click here to login."),
QSystemTrayIcon::MessageIcon::Critical,

View File

@ -433,7 +433,7 @@ void GmailNetworkFactory::onTokensError(const QString& error, const QString& err
}
void GmailNetworkFactory::onAuthFailed() {
qApp->showGuiMessage(Notification::Event::GeneralEvent,
qApp->showGuiMessage(Notification::Event::LoginFailure,
tr("Gmail: authorization denied"),
tr("Click this to login again."),
QSystemTrayIcon::MessageIcon::Critical,

View File

@ -5,6 +5,7 @@
#include "3rd-party/boolinq/boolinq.h"
#include "database/databasequeries.h"
#include "exceptions/applicationexception.h"
#include "exceptions/feedfetchexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "network-web/networkfactory.h"
@ -22,10 +23,10 @@
GreaderNetwork::GreaderNetwork(QObject* parent)
: QObject(parent), m_root(nullptr), m_service(GreaderServiceRoot::Service::FreshRss), m_username(QString()),
m_password(QString()), m_baseUrl(QString()), m_batchSize(GREADER_DEFAULT_BATCH_SIZE), m_downloadOnlyUnreadMessages(false),
m_prefetchedMessages({}), m_performGlobalFetching(false), m_intelligentSynchronization(true),
m_newerThanFilter(QDate::currentDate().addYears(-1)),
m_oauth2(new OAuth2Service(INO_OAUTH_AUTH_URL, INO_OAUTH_TOKEN_URL,
{}, {}, INO_OAUTH_SCOPE, this)) {
m_prefetchedMessages({}), m_prefetchedStatus(Feed::Status::Normal), m_performGlobalFetching(false),
m_intelligentSynchronization(true), m_newerThanFilter(QDate::currentDate().addYears(-1)),
m_oauth(new OAuth2Service(INO_OAUTH_AUTH_URL, INO_OAUTH_TOKEN_URL,
{}, {}, INO_OAUTH_SCOPE, this)) {
initializeOauth();
clearCredentials();
}
@ -129,6 +130,7 @@ QVariantHash GreaderNetwork::userInfo(const QNetworkProxy& proxy) {
void GreaderNetwork::clearPrefetchedMessages() {
m_prefetchedMessages.clear();
m_prefetchedStatus = Feed::Status::Normal;
}
void GreaderNetwork::prepareFeedFetching(GreaderServiceRoot* root,
@ -139,96 +141,103 @@ void GreaderNetwork::prepareFeedFetching(GreaderServiceRoot* root,
Q_UNUSED(tagged_messages)
m_prefetchedMessages.clear();
m_prefetchedStatus = Feed::Status::Normal;
double perc_of_fetching = (feeds.size() * 1.0) / root->getSubTreeFeeds().size();
try {
m_performGlobalFetching = perc_of_fetching > GREADER_GLOBAL_UPDATE_THRES;
double perc_of_fetching = (feeds.size() * 1.0) / root->getSubTreeFeeds().size();
qDebugNN << LOGSEC_GREADER
<< "Percentage of feeds for fetching:"
<< QUOTE_W_SPACE_DOT(perc_of_fetching);
m_performGlobalFetching = perc_of_fetching > GREADER_GLOBAL_UPDATE_THRES;
auto remote_starred_ids_list = itemIds(GREADER_API_FULL_STATE_IMPORTANT, false, proxy, -1, m_newerThanFilter);
qDebugNN << LOGSEC_GREADER
<< "Percentage of feeds for fetching:"
<< QUOTE_W_SPACE_DOT(perc_of_fetching);
for (int i = 0; i < remote_starred_ids_list.size(); i++) {
remote_starred_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_starred_ids_list.at(i)));
}
auto remote_starred_ids_list = itemIds(GREADER_API_FULL_STATE_IMPORTANT, false, proxy, -1, m_newerThanFilter);
QSet<QString> remote_starred_ids = FROM_LIST_TO_SET(QSet<QString>, remote_starred_ids_list);
QSet<QString> local_starred_ids;
QList<QHash<ServiceRoot::BagOfMessages, QStringList>> all_states = stated_messages.values();
for (auto& lst : all_states) {
auto s = lst.value(ServiceRoot::BagOfMessages::Starred);
local_starred_ids.unite(FROM_LIST_TO_SET(QSet<QString>, s));
}
auto starred_to_download((remote_starred_ids - local_starred_ids).unite(local_starred_ids - remote_starred_ids));
auto to_download = starred_to_download;
if (m_performGlobalFetching) {
qWarningNN << LOGSEC_GREADER << "Performing global contents fetching.";
QStringList remote_all_ids_list = m_downloadOnlyUnreadMessages
? QStringList()
: itemIds(GREADER_API_FULL_STATE_READING_LIST, false, proxy, -1, m_newerThanFilter);
QStringList remote_unread_ids_list = itemIds(GREADER_API_FULL_STATE_READING_LIST, true, proxy, -1, m_newerThanFilter);
for (int i = 0; i < remote_all_ids_list.size(); i++) {
remote_all_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_all_ids_list.at(i)));
for (int i = 0; i < remote_starred_ids_list.size(); i++) {
remote_starred_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_starred_ids_list.at(i)));
}
for (int i = 0; i < remote_unread_ids_list.size(); i++) {
remote_unread_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_unread_ids_list.at(i)));
}
QSet<QString> remote_all_ids = FROM_LIST_TO_SET(QSet<QString>, remote_all_ids_list);
QSet<QString> remote_unread_ids = FROM_LIST_TO_SET(QSet<QString>, remote_unread_ids_list);
QSet<QString> remote_read_ids = remote_all_ids - remote_unread_ids;
QSet<QString> local_unread_ids;
QSet<QString> local_read_ids;
QSet<QString> remote_starred_ids = FROM_LIST_TO_SET(QSet<QString>, remote_starred_ids_list);
QSet<QString> local_starred_ids;
QList<QHash<ServiceRoot::BagOfMessages, QStringList>> all_states = stated_messages.values();
for (auto& lst : all_states) {
auto u = lst.value(ServiceRoot::BagOfMessages::Unread);
auto r = lst.value(ServiceRoot::BagOfMessages::Read);
auto s = lst.value(ServiceRoot::BagOfMessages::Starred);
local_unread_ids.unite(FROM_LIST_TO_SET(QSet<QString>, u));
local_read_ids.unite(FROM_LIST_TO_SET(QSet<QString>, r));
local_starred_ids.unite(FROM_LIST_TO_SET(QSet<QString>, s));
}
if (!m_downloadOnlyUnreadMessages) {
to_download += remote_all_ids - local_read_ids - local_unread_ids;
}
else {
to_download += remote_unread_ids - local_read_ids - local_unread_ids;
}
auto starred_to_download((remote_starred_ids - local_starred_ids).unite(local_starred_ids - remote_starred_ids));
auto to_download = starred_to_download;
auto moved_read = local_read_ids.intersect(remote_unread_ids);
if (m_performGlobalFetching) {
qWarningNN << LOGSEC_GREADER << "Performing global contents fetching.";
to_download += moved_read;
QStringList remote_all_ids_list = m_downloadOnlyUnreadMessages
? QStringList()
: itemIds(GREADER_API_FULL_STATE_READING_LIST, false, proxy, -1, m_newerThanFilter);
QStringList remote_unread_ids_list = itemIds(GREADER_API_FULL_STATE_READING_LIST, true, proxy, -1, m_newerThanFilter);
if (!m_downloadOnlyUnreadMessages) {
auto moved_unread = local_unread_ids.intersect(remote_read_ids);
for (int i = 0; i < remote_all_ids_list.size(); i++) {
remote_all_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_all_ids_list.at(i)));
}
to_download += moved_unread;
}
}
else {
qWarningNN << LOGSEC_GREADER << "Performing feed-based contents fetching.";
}
for (int i = 0; i < remote_unread_ids_list.size(); i++) {
remote_unread_ids_list.replace(i, convertShortStreamIdToLongStreamId(remote_unread_ids_list.at(i)));
}
Feed::Status error;
QList<QString> to_download_list(to_download.values());
QSet<QString> remote_all_ids = FROM_LIST_TO_SET(QSet<QString>, remote_all_ids_list);
QSet<QString> remote_unread_ids = FROM_LIST_TO_SET(QSet<QString>, remote_unread_ids_list);
QSet<QString> remote_read_ids = remote_all_ids - remote_unread_ids;
QSet<QString> local_unread_ids;
QSet<QString> local_read_ids;
if (!to_download_list.isEmpty()) {
if (m_service == GreaderServiceRoot::Service::Reedah) {
for (int i = 0; i < to_download_list.size(); i++) {
to_download_list.replace(i, convertLongStreamIdToShortStreamId(to_download_list.at(i)));
for (auto& lst : all_states) {
auto u = lst.value(ServiceRoot::BagOfMessages::Unread);
auto r = lst.value(ServiceRoot::BagOfMessages::Read);
local_unread_ids.unite(FROM_LIST_TO_SET(QSet<QString>, u));
local_read_ids.unite(FROM_LIST_TO_SET(QSet<QString>, r));
}
if (!m_downloadOnlyUnreadMessages) {
to_download += remote_all_ids - local_read_ids - local_unread_ids;
}
else {
to_download += remote_unread_ids - local_read_ids - local_unread_ids;
}
auto moved_read = local_read_ids.intersect(remote_unread_ids);
to_download += moved_read;
if (!m_downloadOnlyUnreadMessages) {
auto moved_unread = local_unread_ids.intersect(remote_read_ids);
to_download += moved_unread;
}
}
else {
qWarningNN << LOGSEC_GREADER << "Performing feed-based contents fetching.";
}
m_prefetchedMessages = itemContents(root, to_download_list, error, proxy);
Feed::Status error;
QList<QString> to_download_list(to_download.values());
if (!to_download_list.isEmpty()) {
if (m_service == GreaderServiceRoot::Service::Reedah) {
for (int i = 0; i < to_download_list.size(); i++) {
to_download_list.replace(i, convertLongStreamIdToShortStreamId(to_download_list.at(i)));
}
}
m_prefetchedMessages = itemContents(root, to_download_list, error, proxy);
}
}
catch (const FeedFetchException& fex) {
m_prefetchedStatus = fex.feedStatus();
}
}
@ -242,6 +251,11 @@ QList<Message> GreaderNetwork::getMessagesIntelligently(ServiceRoot* root,
QList<Message> msgs;
if (m_prefetchedStatus != Feed::Status::Normal) {
error = m_prefetchedStatus;
return msgs;
}
if (!m_performGlobalFetching) {
// 1. Get unread IDs for a feed.
// 2. Get read IDs for a feed.
@ -339,7 +353,7 @@ QStringList GreaderNetwork::itemIds(const QString& stream_id, bool unread_only,
QString continuation;
if (!ensureLogin(proxy)) {
throw ApplicationException(tr("login failed"));
throw FeedFetchException(Feed::Status::AuthError, tr("login failed"));
}
QStringList ids;
@ -839,7 +853,7 @@ void GreaderNetwork::setBaseUrl(const QString& base_url) {
QPair<QByteArray, QByteArray> GreaderNetwork::authHeader() const {
if (m_service == GreaderServiceRoot::Service::Inoreader) {
return { QString(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
m_oauth2->bearer().toLocal8Bit() };
m_oauth->bearer().toLocal8Bit() };
}
else {
return { QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
@ -849,7 +863,7 @@ QPair<QByteArray, QByteArray> GreaderNetwork::authHeader() const {
bool GreaderNetwork::ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output) {
if (m_service == GreaderServiceRoot::Service::Inoreader) {
return !m_oauth2->bearer().isEmpty();
return !m_oauth->bearer().isEmpty();
}
if (m_authSid.isEmpty() && m_authAuth.isEmpty()) {
@ -1073,20 +1087,20 @@ void GreaderNetwork::onTokensError(const QString& error, const QString& error_de
QSystemTrayIcon::MessageIcon::Critical,
{}, {},
[this]() {
m_oauth2->setAccessToken(QString());
m_oauth2->setRefreshToken(QString());
m_oauth2->login();
m_oauth->setAccessToken(QString());
m_oauth->setRefreshToken(QString());
m_oauth->login();
});
}
void GreaderNetwork::onAuthFailed() {
qApp->showGuiMessage(Notification::Event::GeneralEvent,
qApp->showGuiMessage(Notification::Event::LoginFailure,
tr("Inoreader: authorization denied"),
tr("Click this to login again."),
QSystemTrayIcon::MessageIcon::Critical,
{}, {},
[this]() {
m_oauth2->login();
m_oauth->login();
});
}
@ -1096,14 +1110,14 @@ void GreaderNetwork::initializeOauth() {
m_oauth2->setClientSecretSecret(TextFactory::decrypt(INOREADER_CLIENT_SECRET, OAUTH_DECRYPTION_KEY));
#endif
m_oauth2->setRedirectUrl(QString(OAUTH_REDIRECT_URI) +
QL1C(':') +
QString::number(INO_OAUTH_REDIRECT_URI_PORT),
false);
m_oauth->setRedirectUrl(QString(OAUTH_REDIRECT_URI) +
QL1C(':') +
QString::number(INO_OAUTH_REDIRECT_URI_PORT),
false);
connect(m_oauth2, &OAuth2Service::tokensRetrieveError, this, &GreaderNetwork::onTokensError);
connect(m_oauth2, &OAuth2Service::authFailed, this, &GreaderNetwork::onAuthFailed);
connect(m_oauth2, &OAuth2Service::tokensRetrieved, this, [this](QString access_token, QString refresh_token, int expires_in) {
connect(m_oauth, &OAuth2Service::tokensRetrieveError, this, &GreaderNetwork::onTokensError);
connect(m_oauth, &OAuth2Service::authFailed, this, &GreaderNetwork::onAuthFailed);
connect(m_oauth, &OAuth2Service::tokensRetrieved, this, [this](QString access_token, QString refresh_token, int expires_in) {
Q_UNUSED(expires_in)
Q_UNUSED(access_token)
@ -1124,11 +1138,11 @@ void GreaderNetwork::setNewerThanFilter(const QDate& newer_than) {
}
OAuth2Service* GreaderNetwork::oauth() const {
return m_oauth2;
return m_oauth;
}
void GreaderNetwork::setOauth(OAuth2Service* oauth) {
m_oauth2 = oauth;
m_oauth = oauth;
}
void GreaderNetwork::setRoot(GreaderServiceRoot* root) {

View File

@ -132,10 +132,11 @@ class GreaderNetwork : public QObject {
QString m_authAuth;
QString m_authToken;
QList<Message> m_prefetchedMessages;
Feed::Status m_prefetchedStatus;
bool m_performGlobalFetching;
bool m_intelligentSynchronization;
QDate m_newerThanFilter;
OAuth2Service* m_oauth2;
OAuth2Service* m_oauth;
};
#endif // GREADERNETWORK_H