gmail fetch labels too + fix label not updating its article count
This commit is contained in:
parent
f1d98bbc89
commit
1b093aa0f0
@ -673,7 +673,7 @@ QMap<QString, ArticleCounts> DatabaseQueries::getMessageCountsForAllLabels(const
|
||||
q.setForwardOnly(true);
|
||||
|
||||
if (db.driverName() == QSL(APP_DB_MYSQL_DRIVER)) {
|
||||
q.prepare(QSL("SELECT l.custom_id, CONCAT('%.', l.id,'.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
q.prepare(QSL("SELECT l.custom_id, CONCAT('%.', l.custom_id,'.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
"INNER JOIN Messages m "
|
||||
" ON m.account_id = l.account_id AND m.labels LIKE pid "
|
||||
"WHERE "
|
||||
@ -683,7 +683,7 @@ QMap<QString, ArticleCounts> DatabaseQueries::getMessageCountsForAllLabels(const
|
||||
"GROUP BY pid;"));
|
||||
}
|
||||
else {
|
||||
q.prepare(QSL("SELECT l.custom_id, ('%.' || l.id || '.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
q.prepare(QSL("SELECT l.custom_id, ('%.' || l.custom_id || '.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
"INNER JOIN Messages m "
|
||||
" ON m.account_id = l.account_id AND m.labels LIKE pid "
|
||||
"WHERE "
|
||||
@ -738,7 +738,7 @@ QMap<QString, ArticleCounts> DatabaseQueries::getCountOfAssignedLabelsToMessages
|
||||
auto msgs = msgs_lst.join(QSL(" OR "));
|
||||
|
||||
if (db.driverName() == QSL(APP_DB_MYSQL_DRIVER)) {
|
||||
q.prepare(QSL("SELECT l.custom_id, CONCAT('%.', l.id,'.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
q.prepare(QSL("SELECT l.custom_id, CONCAT('%.', l.custom_id,'.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
"INNER JOIN Messages m "
|
||||
" ON m.account_id = l.account_id AND m.labels LIKE pid "
|
||||
"WHERE "
|
||||
@ -750,7 +750,7 @@ QMap<QString, ArticleCounts> DatabaseQueries::getCountOfAssignedLabelsToMessages
|
||||
.arg(msgs));
|
||||
}
|
||||
else {
|
||||
q.prepare(QSL("SELECT l.custom_id, ('%.' || l.id || '.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
q.prepare(QSL("SELECT l.custom_id, ('%.' || l.custom_id || '.%') pid, SUM(m.is_read), COUNT(*) FROM Labels l "
|
||||
"INNER JOIN Messages m "
|
||||
" ON m.account_id = l.account_id AND m.labels LIKE pid "
|
||||
"WHERE "
|
||||
|
@ -293,6 +293,7 @@ void Application::loadDynamicShortcuts() {
|
||||
}
|
||||
|
||||
void Application::showPolls() const {
|
||||
/*
|
||||
if (isFirstRunCurrentVersion()) {
|
||||
qApp->showGuiMessage(Notification::Event::GeneralEvent,
|
||||
{QSL("%1 survey").arg(QSL(APP_NAME)),
|
||||
@ -301,6 +302,7 @@ void Application::showPolls() const {
|
||||
{false, true, false});
|
||||
qApp->web()->openUrlInExternalBrowser(QSL("https://forms.gle/FdzrwFGozCGViK8QA"));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Application::offerChanges() const {
|
||||
|
@ -63,7 +63,7 @@ int LabelsNode::countOfAllMessages() const {
|
||||
void LabelsNode::updateCounts(bool including_total_count) {
|
||||
// TODO: This is still rather slow because this is automatically
|
||||
// called when message is marked (un)read or starred.
|
||||
// It would be enought if only labels which are assigned to article
|
||||
// It would be enough if only labels which are assigned to article
|
||||
// are recounted, not all.
|
||||
|
||||
QSqlDatabase database = qApp->database()->driver()->threadSafeConnection(metaObject()->className());
|
||||
|
@ -3,42 +3,39 @@
|
||||
#ifndef GMAIL_DEFINITIONS_H
|
||||
#define GMAIL_DEFINITIONS_H
|
||||
|
||||
#define GMAIL_OAUTH_REDIRECT_URI_PORT 14499
|
||||
#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_OAUTH_REDIRECT_URI_PORT 14499
|
||||
#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_REG_API_URL "https://console.developers.google.com/apis/credentials"
|
||||
#define GMAIL_REG_API_URL "https://console.developers.google.com/apis/credentials"
|
||||
|
||||
#define GMAIL_API_SEND_MESSAGE "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media"
|
||||
#define GMAIL_API_BATCH_UPD_LABELS "https://www.googleapis.com/gmail/v1/users/me/messages/batchModify"
|
||||
#define GMAIL_API_GET_PROFILE "https://gmail.googleapis.com/gmail/v1/users/me/profile"
|
||||
#define GMAIL_API_GET_ATTACHMENT "https://www.googleapis.com/gmail/v1/users/me/messages/%1/attachments/%2"
|
||||
#define GMAIL_API_LABELS_LIST "https://www.googleapis.com/gmail/v1/users/me/labels"
|
||||
#define GMAIL_API_MSGS_LIST "https://www.googleapis.com/gmail/v1/users/me/messages"
|
||||
#define GMAIL_API_BATCH "https://www.googleapis.com/batch/gmail/v1"
|
||||
#define GMAIL_API_SEND_MESSAGE "https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media"
|
||||
#define GMAIL_API_BATCH_UPD_LABELS "https://www.googleapis.com/gmail/v1/users/me/messages/batchModify"
|
||||
#define GMAIL_API_GET_PROFILE "https://gmail.googleapis.com/gmail/v1/users/me/profile"
|
||||
#define GMAIL_API_GET_ATTACHMENT "https://www.googleapis.com/gmail/v1/users/me/messages/%1/attachments/%2"
|
||||
#define GMAIL_API_LABELS_LIST "https://www.googleapis.com/gmail/v1/users/me/labels"
|
||||
#define GMAIL_API_MSGS_LIST "https://www.googleapis.com/gmail/v1/users/me/messages"
|
||||
#define GMAIL_API_BATCH "https://www.googleapis.com/batch/gmail/v1"
|
||||
|
||||
#define GMAIL_ATTACHMENT_SEP "####"
|
||||
#define GMAIL_ATTACHMENT_SEP "####"
|
||||
|
||||
#define GMAIL_DEFAULT_BATCH_SIZE 100
|
||||
#define GMAIL_MAX_BATCH_SIZE 999
|
||||
#define GMAIL_DEFAULT_BATCH_SIZE 100
|
||||
#define GMAIL_MAX_BATCH_SIZE 999
|
||||
|
||||
#define GMAIL_SYSTEM_LABEL_UNREAD "UNREAD"
|
||||
#define GMAIL_SYSTEM_LABEL_INBOX "INBOX"
|
||||
#define GMAIL_SYSTEM_LABEL_SENT "SENT"
|
||||
#define GMAIL_SYSTEM_LABEL_DRAFT "DRAFT"
|
||||
#define GMAIL_SYSTEM_LABEL_SPAM "SPAM"
|
||||
#define GMAIL_SYSTEM_LABEL_STARRED "STARRED"
|
||||
#define GMAIL_SYSTEM_LABEL_TRASH "TRASH"
|
||||
#define GMAIL_LABEL_TYPE_USER "user"
|
||||
|
||||
#define GMAIL_CONTENT_TYPE_HTTP "application/http"
|
||||
#define GMAIL_CONTENT_TYPE_JSON "application/json"
|
||||
#define GMAIL_SYSTEM_LABEL_UNREAD "UNREAD"
|
||||
#define GMAIL_SYSTEM_LABEL_INBOX "INBOX"
|
||||
#define GMAIL_SYSTEM_LABEL_SENT "SENT"
|
||||
#define GMAIL_SYSTEM_LABEL_DRAFT "DRAFT"
|
||||
#define GMAIL_SYSTEM_LABEL_SPAM "SPAM"
|
||||
#define GMAIL_SYSTEM_LABEL_STARRED "STARRED"
|
||||
#define GMAIL_SYSTEM_LABEL_TRASH "TRASH"
|
||||
|
||||
enum class RecipientType {
|
||||
To,
|
||||
Cc,
|
||||
Bcc,
|
||||
ReplyTo
|
||||
};
|
||||
#define GMAIL_CONTENT_TYPE_HTTP "application/http"
|
||||
#define GMAIL_CONTENT_TYPE_JSON "application/json"
|
||||
|
||||
enum class RecipientType { To, Cc, Bcc, ReplyTo };
|
||||
|
||||
#endif // GMAIL_DEFINITIONS_H
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "services/gmail/gmailnetworkfactory.h"
|
||||
|
||||
#include "3rd-party/boolinq/boolinq.h"
|
||||
#include "database/databasequeries.h"
|
||||
#include "definitions/definitions.h"
|
||||
#include "exceptions/applicationexception.h"
|
||||
@ -15,6 +16,7 @@
|
||||
#include "network-web/silentnetworkaccessmanager.h"
|
||||
#include "network-web/webfactory.h"
|
||||
#include "services/abstract/category.h"
|
||||
#include "services/abstract/labelsnode.h"
|
||||
#include "services/gmail/definitions.h"
|
||||
#include "services/gmail/gmailserviceroot.h"
|
||||
|
||||
@ -149,6 +151,59 @@ void GmailNetworkFactory::setDownloadOnlyUnreadMessages(bool download_only_unrea
|
||||
m_downloadOnlyUnreadMessages = download_only_unread_messages;
|
||||
}
|
||||
|
||||
QList<RootItem*> GmailNetworkFactory::labels(bool only_user_labels, const QNetworkProxy& custom_proxy) {
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
throw NetworkException(QNetworkReply::NetworkError::AuthenticationRequiredError);
|
||||
}
|
||||
|
||||
QList<RootItem*> lbls;
|
||||
QList<QPair<QByteArray, QByteArray>> headers;
|
||||
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
m_oauth2->bearer().toLocal8Bit()));
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_CONTENT_TYPE).toLocal8Bit(),
|
||||
QSL(GMAIL_CONTENT_TYPE_JSON).toLocal8Bit()));
|
||||
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
QByteArray output;
|
||||
NetworkResult result = NetworkFactory::performNetworkOperation(QSL(GMAIL_API_LABELS_LIST),
|
||||
timeout,
|
||||
{},
|
||||
output,
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
headers,
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
custom_proxy);
|
||||
|
||||
if (result.m_networkError != QNetworkReply::NetworkError::NoError) {
|
||||
throw NetworkException(result.m_networkError, tr("failed to download list of labels"));
|
||||
}
|
||||
|
||||
QJsonObject obj = QJsonDocument::fromJson(output).object();
|
||||
QJsonArray lbls_arr = obj[QSL("labels")].toArray();
|
||||
|
||||
for (const QJsonValue& lbl_val : lbls_arr) {
|
||||
QJsonObject lbl_obj = lbl_val.toObject();
|
||||
|
||||
if (only_user_labels && lbl_obj[QSL("type")].toString() != QSL(GMAIL_LABEL_TYPE_USER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Label* lbl =
|
||||
new Label(lbl_obj[QSL("name")].toString(), TextFactory::generateColorFromText(lbl_obj[QSL("name")].toString()));
|
||||
|
||||
lbl->setCustomId(lbl_obj[QSL("id")].toString());
|
||||
lbls.append(lbl);
|
||||
}
|
||||
|
||||
return lbls;
|
||||
}
|
||||
|
||||
QNetworkRequest GmailNetworkFactory::requestForAttachment(const QString& email_id, const QString& attachment_id) {
|
||||
QString target_url = QSL(GMAIL_API_GET_ATTACHMENT).arg(email_id, attachment_id);
|
||||
QNetworkRequest req(target_url);
|
||||
@ -182,7 +237,8 @@ QList<Message> GmailNetworkFactory::messages(const QString& stream_id,
|
||||
return {};
|
||||
}
|
||||
|
||||
const bool is_spam_feed = QString::compare(stream_id, QSL("SPAM"), Qt::CaseSensitivity::CaseInsensitive) == 0;
|
||||
const bool is_spam_feed =
|
||||
QString::compare(stream_id, QSL(GMAIL_SYSTEM_LABEL_SPAM), Qt::CaseSensitivity::CaseInsensitive) == 0;
|
||||
|
||||
// 1. Get unread IDs for a feed.
|
||||
// 2. Get read IDs for a feed.
|
||||
@ -344,7 +400,7 @@ QNetworkReply::NetworkError GmailNetworkFactory::markMessagesStarred(RootItem::I
|
||||
param_obj[QSL("addLabelIds")] = param_add;
|
||||
param_obj[QSL("removeLabelIds")] = param_remove;
|
||||
|
||||
// We need to operate withing allowed batches.
|
||||
// We need to operate within allowed batches.
|
||||
for (int i = 0; i < custom_ids.size(); i += GMAIL_MAX_BATCH_SIZE) {
|
||||
auto batch = custom_ids.mid(i, GMAIL_MAX_BATCH_SIZE);
|
||||
|
||||
@ -412,7 +468,7 @@ QStringList GmailNetworkFactory::list(const QString& stream_id,
|
||||
}
|
||||
|
||||
if (!next_page_token.isEmpty()) {
|
||||
target_url += QString("&pageToken=%1").arg(next_page_token);
|
||||
target_url += QSL("&pageToken=%1").arg(next_page_token);
|
||||
}
|
||||
|
||||
QByteArray messages_raw_data;
|
||||
@ -506,6 +562,23 @@ void GmailNetworkFactory::onAuthFailed() {
|
||||
}
|
||||
|
||||
bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id) const {
|
||||
// Assign correct main labels/states.
|
||||
auto labelids = json[QSL("labelIds")].toArray().toVariantList();
|
||||
|
||||
// Every message which is in INBOX, must be in INBOX, even if Gmail API returns more labels for the message.
|
||||
// I have to always decide which single label is most important one.
|
||||
if (labelids.contains(QSL(GMAIL_SYSTEM_LABEL_INBOX)) && feed_id != QSL(GMAIL_SYSTEM_LABEL_INBOX)) {
|
||||
// This message is in INBOX label too, but this updated feed is not INBOX,
|
||||
// we want to leave this message in INBOX and not duplicate it to other feed/label.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (labelids.contains(QSL(GMAIL_SYSTEM_LABEL_TRASH)) && feed_id != QSL(GMAIL_SYSTEM_LABEL_TRASH)) {
|
||||
// This message is in trash, but this updated feed is not recycle bin, we do not want
|
||||
// this message to appear anywhere.
|
||||
return false;
|
||||
}
|
||||
|
||||
QHash<QString, QString> headers;
|
||||
auto json_headers = json[QSL("payload")].toObject()[QSL("headers")].toArray();
|
||||
|
||||
@ -516,8 +589,8 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
msg.m_isRead = true;
|
||||
msg.m_rawContents = QJsonDocument(json).toJson(QJsonDocument::JsonFormat::Compact);
|
||||
|
||||
// Assign correct main labels/states.
|
||||
auto labelids = json[QSL("labelIds")].toArray().toVariantList();
|
||||
auto active_labels = m_service->labelsNode() != nullptr ? m_service->labelsNode()->labels() : QList<Label*>();
|
||||
auto active_labels_linq = boolinq::from(active_labels);
|
||||
|
||||
for (const QVariant& label : qAsConst(labelids)) {
|
||||
QString lbl = label.toString();
|
||||
@ -528,20 +601,14 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
else if (lbl == QSL(GMAIL_SYSTEM_LABEL_STARRED)) {
|
||||
msg.m_isImportant = true;
|
||||
}
|
||||
else {
|
||||
auto* active_lb = active_labels_linq.firstOrDefault([lbl](Label* lb) {
|
||||
return lb->customId() == lbl;
|
||||
});
|
||||
|
||||
// RSS Guard does not support multi-labeling of messages, thus each message can have MAX single label.
|
||||
// Every message which is in INBOX, must be in INBOX, even if Gmail API returns more labels for the message.
|
||||
// I have to always decide which single label is most important one.
|
||||
if (lbl == QSL(GMAIL_SYSTEM_LABEL_INBOX) && feed_id != QSL(GMAIL_SYSTEM_LABEL_INBOX)) {
|
||||
// This message is in INBOX label too, but this updated feed is not INBOX,
|
||||
// we want to leave this message in INBOX and not duplicate it to other feed/label.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lbl == QSL(GMAIL_SYSTEM_LABEL_TRASH) && feed_id != QSL(GMAIL_SYSTEM_LABEL_TRASH)) {
|
||||
// This message is in trash, but this updated feed is not recycle bin, we do not want
|
||||
// this message to appear anywhere.
|
||||
return false;
|
||||
if (active_lb != nullptr) {
|
||||
msg.m_assignedLabels.append(active_lb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -697,6 +764,7 @@ QList<Message> GmailNetworkFactory::obtainAndDecodeFullMessages(const QStringLis
|
||||
Message msg;
|
||||
QHttpPart part;
|
||||
|
||||
msg.m_feedId = feed_id;
|
||||
msg.m_customId = msg_id;
|
||||
|
||||
part.setRawHeader(HTTP_HEADERS_CONTENT_TYPE, GMAIL_CONTENT_TYPE_HTTP);
|
||||
|
@ -40,6 +40,7 @@ class GmailNetworkFactory : public QObject {
|
||||
void setDownloadOnlyUnreadMessages(bool download_only_unread_messages);
|
||||
|
||||
// API methods.
|
||||
QList<RootItem*> labels(bool only_user_labels, const QNetworkProxy& custom_proxy);
|
||||
QMap<QString, QString> getMessageMetadata(const QString& msg_id,
|
||||
const QStringList& metadata,
|
||||
const QNetworkProxy& custom_proxy);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
#include "network-web/oauth2service.h"
|
||||
#include "services/abstract/importantnode.h"
|
||||
#include "services/abstract/labelsnode.h"
|
||||
#include "services/abstract/recyclebin.h"
|
||||
#include "services/gmail/definitions.h"
|
||||
#include "services/gmail/gmailentrypoint.h"
|
||||
@ -59,6 +60,12 @@ RootItem* GmailServiceRoot::obtainNewTreeForSyncIn() const {
|
||||
qApp->icons()->fromTheme(QSL("mail-mark-junk")),
|
||||
root));
|
||||
|
||||
auto* lblroot = new LabelsNode(root);
|
||||
auto labels = m_network->labels(true, networkProxy());
|
||||
|
||||
lblroot->setChildItems(labels);
|
||||
root->appendChild(lblroot);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@ -94,7 +101,6 @@ QList<Message> GmailServiceRoot::obtainNewMessages(Feed* feed,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>&
|
||||
stated_messages,
|
||||
const QHash<QString, QStringList>& tagged_messages) {
|
||||
Q_UNUSED(stated_messages)
|
||||
Q_UNUSED(tagged_messages)
|
||||
|
||||
Feed::Status error = Feed::Status::Normal;
|
||||
@ -249,3 +255,7 @@ void GmailServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||
bool GmailServiceRoot::displaysEnclosures() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
ServiceRoot::LabelOperation GmailServiceRoot::supportedLabelOperations() const {
|
||||
return ServiceRoot::LabelOperation::Synchronised;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class GmailServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||
virtual QString additionalTooltip() const;
|
||||
virtual void saveAllCachedData(bool ignore_errors);
|
||||
virtual bool displaysEnclosures() const;
|
||||
virtual LabelOperation supportedLabelOperations() const;
|
||||
virtual QVariantHash customDatabaseData() const;
|
||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||
virtual QList<Message> obtainNewMessages(Feed* feed,
|
||||
|
Loading…
x
Reference in New Issue
Block a user