preliminary miniflux support
This commit is contained in:
parent
a902beaf80
commit
35e9f299a6
@ -26,7 +26,7 @@
|
||||
<url type="donation">https://github.com/sponsors/martinrotter</url>
|
||||
<content_rating type="oars-1.1" />
|
||||
<releases>
|
||||
<release version="4.2.3" date="2022-08-19"/>
|
||||
<release version="4.2.3" date="2022-08-22"/>
|
||||
</releases>
|
||||
<content_rating type="oars-1.0">
|
||||
<content_attribute id="violence-cartoon">none</content_attribute>
|
||||
|
BIN
resources/graphics/misc/miniflux.png
Executable file
BIN
resources/graphics/misc/miniflux.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 881 B |
@ -38,6 +38,7 @@
|
||||
<file>graphics/misc/image-placeholder.png</file>
|
||||
<file>graphics/misc/image-placeholder-error.png</file>
|
||||
<file>graphics/misc/inoreader.png</file>
|
||||
<file>graphics/misc/miniflux.png</file>
|
||||
<file>graphics/misc/newsblur.png</file>
|
||||
<file>graphics/misc/nextcloud.png</file>
|
||||
<file>graphics/misc/reddit.png</file>
|
||||
|
@ -26,11 +26,14 @@
|
||||
#include <QThread>
|
||||
#include <QUrl>
|
||||
|
||||
GmailNetworkFactory::GmailNetworkFactory(QObject* parent) : QObject(parent),
|
||||
m_service(nullptr), m_username(QString()), m_batchSize(GMAIL_DEFAULT_BATCH_SIZE),
|
||||
m_downloadOnlyUnreadMessages(false),
|
||||
m_oauth2(new OAuth2Service(QSL(GMAIL_OAUTH_AUTH_URL), QSL(GMAIL_OAUTH_TOKEN_URL),
|
||||
{}, {}, QSL(GMAIL_OAUTH_SCOPE), this)) {
|
||||
GmailNetworkFactory::GmailNetworkFactory(QObject* parent)
|
||||
: QObject(parent), m_service(nullptr), m_username(QString()), m_batchSize(GMAIL_DEFAULT_BATCH_SIZE),
|
||||
m_downloadOnlyUnreadMessages(false), m_oauth2(new OAuth2Service(QSL(GMAIL_OAUTH_AUTH_URL),
|
||||
QSL(GMAIL_OAUTH_TOKEN_URL),
|
||||
{},
|
||||
{},
|
||||
QSL(GMAIL_OAUTH_SCOPE),
|
||||
this)) {
|
||||
initializeOauth();
|
||||
}
|
||||
|
||||
@ -54,19 +57,19 @@ void GmailNetworkFactory::setBatchSize(int batch_size) {
|
||||
m_batchSize = batch_size;
|
||||
}
|
||||
|
||||
QString GmailNetworkFactory::sendEmail(Mimesis::Message msg, const QNetworkProxy& custom_proxy, Message* reply_to_message) {
|
||||
QString GmailNetworkFactory::sendEmail(Mimesis::Message msg,
|
||||
const QNetworkProxy& custom_proxy,
|
||||
Message* reply_to_message) {
|
||||
QString bearer = m_oauth2->bearer().toLocal8Bit();
|
||||
|
||||
if (bearer.isEmpty()) {
|
||||
//throw ApplicationException(tr("you aren't logged in"));
|
||||
// throw ApplicationException(tr("you aren't logged in"));
|
||||
}
|
||||
|
||||
if (reply_to_message != nullptr) {
|
||||
// We need to obtain some extra information.
|
||||
auto metadata = getMessageMetadata(reply_to_message->m_customId, {
|
||||
QSL("References"),
|
||||
QSL("Message-ID")
|
||||
}, custom_proxy);
|
||||
auto metadata =
|
||||
getMessageMetadata(reply_to_message->m_customId, {QSL("References"), QSL("Message-ID")}, custom_proxy);
|
||||
|
||||
if (metadata.contains(QSL("Message-ID"))) {
|
||||
msg["References"] = metadata.value(QSL("Message-ID")).toStdString();
|
||||
@ -120,14 +123,14 @@ void GmailNetworkFactory::initializeOauth() {
|
||||
m_oauth2->setClientSecretSecret(TextFactory::decrypt(QSL(GMAIL_CLIENT_SECRET), OAUTH_DECRYPTION_KEY));
|
||||
#endif
|
||||
|
||||
m_oauth2->setRedirectUrl(QSL(OAUTH_REDIRECT_URI) +
|
||||
QL1C(':') +
|
||||
QString::number(GMAIL_OAUTH_REDIRECT_URI_PORT),
|
||||
true);
|
||||
m_oauth2->setRedirectUrl(QSL(OAUTH_REDIRECT_URI) + QL1C(':') + QString::number(GMAIL_OAUTH_REDIRECT_URI_PORT), true);
|
||||
|
||||
connect(m_oauth2, &OAuth2Service::tokensRetrieveError, this, &GmailNetworkFactory::onTokensError);
|
||||
connect(m_oauth2, &OAuth2Service::authFailed, this, &GmailNetworkFactory::onAuthFailed);
|
||||
connect(m_oauth2, &OAuth2Service::tokensRetrieved, this, [this](QString access_token, QString refresh_token, int expires_in) {
|
||||
connect(m_oauth2,
|
||||
&OAuth2Service::tokensRetrieved,
|
||||
this,
|
||||
[this](QString access_token, QString refresh_token, int expires_in) {
|
||||
Q_UNUSED(expires_in)
|
||||
Q_UNUSED(access_token)
|
||||
|
||||
@ -197,8 +200,7 @@ QList<Message> GmailNetworkFactory::messages(const QString& stream_id,
|
||||
}
|
||||
}
|
||||
catch (const NetworkException& net_ex) {
|
||||
qCriticalNN << LOGSEC_GMAIL
|
||||
<< "Failed to get list of e-mail IDs:" << QUOTE_W_SPACE_DOT(net_ex.message());
|
||||
qCriticalNN << LOGSEC_GMAIL << "Failed to get list of e-mail IDs:" << QUOTE_W_SPACE_DOT(net_ex.message());
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -300,7 +302,8 @@ QNetworkReply::NetworkError GmailNetworkFactory::markMessagesRead(RootItem::Read
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
custom_proxy).m_networkError;
|
||||
custom_proxy)
|
||||
.m_networkError;
|
||||
|
||||
if (result != QNetworkReply::NetworkError::NoError) {
|
||||
return result;
|
||||
@ -359,7 +362,8 @@ QNetworkReply::NetworkError GmailNetworkFactory::markMessagesStarred(RootItem::I
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
custom_proxy).m_networkError;
|
||||
custom_proxy)
|
||||
.m_networkError;
|
||||
|
||||
if (result != QNetworkReply::NetworkError::NoError) {
|
||||
return result;
|
||||
@ -413,13 +417,13 @@ QStringList GmailNetworkFactory::list(const QString& stream_id,
|
||||
}
|
||||
|
||||
QByteArray messages_raw_data;
|
||||
auto netw = NetworkFactory::performNetworkOperation(target_url,
|
||||
auto netw =
|
||||
NetworkFactory::performNetworkOperation(target_url,
|
||||
timeout,
|
||||
{},
|
||||
messages_raw_data,
|
||||
QNetworkAccessManager::Operation::GetOperation,
|
||||
{ { QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
bearer.toLocal8Bit() } },
|
||||
{{QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit()}},
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
@ -430,12 +434,12 @@ QStringList GmailNetworkFactory::list(const QString& stream_id,
|
||||
QString messages_data = QString::fromUtf8(messages_raw_data);
|
||||
|
||||
message_ids << decodeLiteMessages(messages_data, next_page_token);
|
||||
|
||||
}
|
||||
else {
|
||||
throw NetworkException(netw.m_networkError, tr("failed to download IDs of e-mail messages"));
|
||||
}
|
||||
} while (!next_page_token.isEmpty() && (max_results <= 0 || message_ids.size() < max_results));
|
||||
}
|
||||
while (!next_page_token.isEmpty() && (max_results <= 0 || message_ids.size() < max_results));
|
||||
|
||||
return message_ids;
|
||||
}
|
||||
@ -463,7 +467,8 @@ QVariantHash GmailNetworkFactory::getProfile(const QNetworkProxy& custom_proxy)
|
||||
false,
|
||||
{},
|
||||
{},
|
||||
custom_proxy).m_networkError;
|
||||
custom_proxy)
|
||||
.m_networkError;
|
||||
|
||||
if (result != QNetworkReply::NetworkError::NoError) {
|
||||
throw NetworkException(result, output);
|
||||
@ -478,32 +483,30 @@ QVariantHash GmailNetworkFactory::getProfile(const QNetworkProxy& custom_proxy)
|
||||
void GmailNetworkFactory::onTokensError(const QString& error, const QString& error_description) {
|
||||
Q_UNUSED(error)
|
||||
|
||||
qApp->showGuiMessage(Notification::Event::LoginFailure, {
|
||||
tr("Gmail: authentication error"),
|
||||
qApp->showGuiMessage(Notification::Event::LoginFailure,
|
||||
{tr("Gmail: authentication error"),
|
||||
tr("Click this to login again. Error is: '%1'").arg(error_description),
|
||||
QSystemTrayIcon::MessageIcon::Critical },
|
||||
{}, {
|
||||
tr("Login"),
|
||||
[this]() {
|
||||
QSystemTrayIcon::MessageIcon::Critical},
|
||||
{},
|
||||
{tr("Login"), [this]() {
|
||||
m_oauth2->setAccessToken(QString());
|
||||
m_oauth2->setRefreshToken(QString());
|
||||
m_oauth2->login();
|
||||
} });
|
||||
}});
|
||||
}
|
||||
|
||||
void GmailNetworkFactory::onAuthFailed() {
|
||||
qApp->showGuiMessage(Notification::Event::LoginFailure, {
|
||||
tr("Gmail: authorization denied"),
|
||||
qApp->showGuiMessage(Notification::Event::LoginFailure,
|
||||
{tr("Gmail: authorization denied"),
|
||||
tr("Click this to login again."),
|
||||
QSystemTrayIcon::MessageIcon::Critical },
|
||||
{}, {
|
||||
tr("Login"),
|
||||
[this]() {
|
||||
QSystemTrayIcon::MessageIcon::Critical},
|
||||
{},
|
||||
{tr("Login"), [this]() {
|
||||
m_oauth2->login();
|
||||
} });
|
||||
}});
|
||||
}
|
||||
|
||||
bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id) {
|
||||
bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id) const {
|
||||
QHash<QString, QString> headers;
|
||||
auto json_headers = json[QSL("payload")].toObject()[QSL("headers")].toArray();
|
||||
|
||||
@ -543,7 +546,7 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
}
|
||||
}
|
||||
|
||||
msg.m_author = headers[QSL("From")];
|
||||
msg.m_author = sanitizeEmailAuthor(headers[QSL("From")]);
|
||||
msg.m_title = headers[QSL("Subject")];
|
||||
msg.m_createdFromFeed = true;
|
||||
msg.m_created = TextFactory::parseDateTime(headers[QSL("Date")]);
|
||||
@ -587,7 +590,8 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
// We check if it is HTML.
|
||||
if (msg.m_contents.isEmpty()) {
|
||||
if (mime.contains(QL1S("text/html"))) {
|
||||
msg.m_contents = QByteArray::fromBase64(body[QSL("data")].toString().toUtf8(), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
msg.m_contents =
|
||||
QByteArray::fromBase64(body[QSL("data")].toString().toUtf8(), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
|
||||
if (msg.m_contents.contains(QSL("<body>"))) {
|
||||
int strt = msg.m_contents.indexOf(QSL("<body>"));
|
||||
@ -599,10 +603,10 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
}
|
||||
}
|
||||
else if (backup_contents.isEmpty()) {
|
||||
backup_contents = QByteArray::fromBase64(body[QSL("data")].toString().toUtf8(), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
backup_contents =
|
||||
QByteArray::fromBase64(body[QSL("data")].toString().toUtf8(), QByteArray::Base64Option::Base64UrlEncoding);
|
||||
|
||||
backup_contents = backup_contents
|
||||
.replace(QSL("\r\n"), QSL("\n"))
|
||||
backup_contents = backup_contents.replace(QSL("\r\n"), QSL("\n"))
|
||||
.replace(QSL("\n"), QSL("\n"))
|
||||
.replace(QSL("\n"), QSL("<br/>"));
|
||||
}
|
||||
@ -610,9 +614,9 @@ bool GmailNetworkFactory::fillFullMessage(Message& msg, const QJsonObject& json,
|
||||
}
|
||||
else if (!filename.isEmpty()) {
|
||||
// We have attachment.
|
||||
msg.m_enclosures.append(Enclosure(filename +
|
||||
QSL(GMAIL_ATTACHMENT_SEP) + body[QSL("attachmentId")].toString(),
|
||||
filename + QSL(" (%1 KB)").arg(QString::number(body["size"].toInt() / 1000.0))));
|
||||
msg.m_enclosures.append(Enclosure(filename + QSL(GMAIL_ATTACHMENT_SEP) + body[QSL("attachmentId")].toString(),
|
||||
filename +
|
||||
QSL(" (%1 KB)").arg(QString::number(body["size"].toInt() / 1000.0))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,12 +640,10 @@ QMap<QString, QString> GmailNetworkFactory::getMessageMetadata(const QString& ms
|
||||
QByteArray output;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
bearer.toLocal8Bit()));
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit()));
|
||||
|
||||
QString query = QString("%1/%2?format=metadata&metadataHeaders=%3").arg(QSL(GMAIL_API_MSGS_LIST),
|
||||
msg_id,
|
||||
metadata.join(QSL("&metadataHeaders=")));
|
||||
QString query = QString("%1/%2?format=metadata&metadataHeaders=%3")
|
||||
.arg(QSL(GMAIL_API_MSGS_LIST), msg_id, metadata.join(QSL("&metadataHeaders=")));
|
||||
NetworkResult res = NetworkFactory::performNetworkOperation(query,
|
||||
timeout,
|
||||
QByteArray(),
|
||||
@ -673,7 +675,7 @@ QMap<QString, QString> GmailNetworkFactory::getMessageMetadata(const QString& ms
|
||||
|
||||
QList<Message> GmailNetworkFactory::obtainAndDecodeFullMessages(const QStringList& message_ids,
|
||||
const QString& feed_id,
|
||||
const QNetworkProxy& custom_proxy) {
|
||||
const QNetworkProxy& custom_proxy) const {
|
||||
QHash<QString, Message> msgs;
|
||||
int next_message = 0;
|
||||
QString bearer = m_oauth2->bearer();
|
||||
@ -687,7 +689,7 @@ QList<Message> GmailNetworkFactory::obtainAndDecodeFullMessages(const QStringLis
|
||||
|
||||
multi->setContentType(QHttpMultiPart::ContentType::MixedType);
|
||||
|
||||
for (int window = next_message + 100; next_message < window && next_message < message_ids.size(); next_message++ ) {
|
||||
for (int window = next_message + 100; next_message < window && next_message < message_ids.size(); next_message++) {
|
||||
QString msg_id = message_ids[next_message];
|
||||
Message msg;
|
||||
QHttpPart part;
|
||||
@ -706,8 +708,7 @@ QList<Message> GmailNetworkFactory::obtainAndDecodeFullMessages(const QStringLis
|
||||
QList<HttpResponse> output;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(),
|
||||
bearer.toLocal8Bit()));
|
||||
headers.append(QPair<QByteArray, QByteArray>(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit()));
|
||||
|
||||
NetworkResult res = NetworkFactory::performNetworkOperation(GMAIL_API_BATCH,
|
||||
timeout,
|
||||
@ -750,7 +751,7 @@ QList<Message> GmailNetworkFactory::obtainAndDecodeFullMessages(const QStringLis
|
||||
return msgs.values();
|
||||
}
|
||||
|
||||
QStringList GmailNetworkFactory::decodeLiteMessages(const QString& messages_json_data, QString& next_page_token) {
|
||||
QStringList GmailNetworkFactory::decodeLiteMessages(const QString& messages_json_data, QString& next_page_token) const {
|
||||
QList<QString> message_ids;
|
||||
QJsonObject top_object = QJsonDocument::fromJson(messages_json_data.toUtf8()).object();
|
||||
QJsonArray json_msgs = top_object[QSL("messages")].toArray();
|
||||
@ -766,3 +767,7 @@ QStringList GmailNetworkFactory::decodeLiteMessages(const QString& messages_json
|
||||
|
||||
return message_ids;
|
||||
}
|
||||
|
||||
QString GmailNetworkFactory::sanitizeEmailAuthor(const QString& author) const {
|
||||
return author.mid(0, author.indexOf(QL1S(" <"))).replace(QL1S("\""), QString());
|
||||
}
|
||||
|
@ -68,11 +68,12 @@ class GmailNetworkFactory : public QObject {
|
||||
void onAuthFailed();
|
||||
|
||||
private:
|
||||
bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id);
|
||||
bool fillFullMessage(Message& msg, const QJsonObject& json, const QString& feed_id) const;
|
||||
QList<Message> obtainAndDecodeFullMessages(const QStringList& message_ids,
|
||||
const QString& feed_id,
|
||||
const QNetworkProxy& custom_proxy);
|
||||
QStringList decodeLiteMessages(const QString& messages_json_data, QString& next_page_token);
|
||||
const QNetworkProxy& custom_proxy) const;
|
||||
QStringList decodeLiteMessages(const QString& messages_json_data, QString& next_page_token) const;
|
||||
QString sanitizeEmailAuthor(const QString& author) const;
|
||||
|
||||
void initializeOauth();
|
||||
|
||||
|
@ -41,7 +41,7 @@ FormAddEditEmail::FormAddEditEmail(GmailServiceRoot* root, QWidget* parent)
|
||||
m_possibleRecipients = DatabaseQueries::getAllGmailRecipients(db, m_root->accountId());
|
||||
auto ctrls = recipientControls();
|
||||
|
||||
for (auto* rec: qAsConst(ctrls)) {
|
||||
for (auto* rec : qAsConst(ctrls)) {
|
||||
rec->setPossibleRecipients(m_possibleRecipients);
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,10 @@ void FormAddEditEmail::execForReply(Message* original_message) {
|
||||
m_ui.m_txtSubject->setEnabled(false);
|
||||
m_ui.m_txtMessage->setFocus();
|
||||
|
||||
addRecipientRow(m_originalMessage->m_author);
|
||||
auto from_header =
|
||||
m_root->network()->getMessageMetadata(original_message->m_customId, {QSL("FROM")}, m_root->networkProxy());
|
||||
|
||||
addRecipientRow(from_header["From"]);
|
||||
exec();
|
||||
}
|
||||
|
||||
@ -70,15 +73,15 @@ void FormAddEditEmail::execForForward(Message* original_message) {
|
||||
m_ui.m_txtMessage->setFocus();
|
||||
|
||||
// TODO: Obtain "To" header from Gmail API and fill it in too.
|
||||
const QString forward_header = QSL("<pre>"
|
||||
const QString forward_header =
|
||||
QSL("<pre>"
|
||||
"---------- Forwarded message ---------<br/>"
|
||||
"From: %1<br/>"
|
||||
"Date: %2<br/>"
|
||||
"Subject: %3<br/>"
|
||||
"To: -"
|
||||
"</pre><br/>").arg(m_originalMessage->m_author,
|
||||
m_originalMessage->m_created.toString(),
|
||||
m_originalMessage->m_title);
|
||||
"</pre><br/>")
|
||||
.arg(m_originalMessage->m_author, m_originalMessage->m_created.toString(), m_originalMessage->m_title);
|
||||
|
||||
m_ui.m_txtMessage->setHtml(forward_header + m_originalMessage->m_contents);
|
||||
m_ui.m_txtMessage->moveCursor(QTextCursor::MoveOperation::Start);
|
||||
@ -145,7 +148,8 @@ void FormAddEditEmail::onOkClicked() {
|
||||
msg["Reply-To"] = rec_repl.join(',').toStdString();
|
||||
}
|
||||
|
||||
msg["Subject"] = QSL("=?utf-8?B?%1?=")
|
||||
msg["Subject"] =
|
||||
QSL("=?utf-8?B?%1?=")
|
||||
.arg(QString(m_ui.m_txtSubject->text().toUtf8().toBase64(QByteArray::Base64Option::Base64UrlEncoding)))
|
||||
.toStdString();
|
||||
|
||||
@ -161,8 +165,10 @@ void FormAddEditEmail::onOkClicked() {
|
||||
accept();
|
||||
}
|
||||
catch (const ApplicationException& ex) {
|
||||
MsgBox::show(this, QMessageBox::Icon::Critical,
|
||||
tr("E-mail NOT sent"), tr("Your e-mail message wasn't sent."),
|
||||
MsgBox::show(this,
|
||||
QMessageBox::Icon::Critical,
|
||||
tr("E-mail NOT sent"),
|
||||
tr("Your e-mail message wasn't sent."),
|
||||
QString(),
|
||||
ex.message());
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ QNetworkReply::NetworkError GreaderNetwork::editLabels(const QString& state,
|
||||
args += working_subset.join(QL1C('&'));
|
||||
|
||||
if (m_service == GreaderServiceRoot::Service::Reedah) {
|
||||
args += QSL("&T=%1").arg(m_authToken);
|
||||
args += QSL("&%1").arg(tokenParameter());
|
||||
}
|
||||
|
||||
// We send this batch.
|
||||
@ -493,7 +493,13 @@ QList<Message> GreaderNetwork::itemContents(ServiceRoot* root,
|
||||
: QUrl::toPercentEncoding(id));
|
||||
})
|
||||
.toStdList();
|
||||
QByteArray input = FROM_STD_LIST(QStringList, inp).join(QSL("&")).toUtf8();
|
||||
QStringList inp_s = FROM_STD_LIST(QStringList, inp);
|
||||
|
||||
if (m_service == GreaderServiceRoot::Service::Reedah || m_service == GreaderServiceRoot::Service::Miniflux) {
|
||||
inp_s.append(tokenParameter());
|
||||
}
|
||||
|
||||
QByteArray input = inp_s.join(QSL("&")).toUtf8();
|
||||
QByteArray output_stream;
|
||||
auto result_stream =
|
||||
NetworkFactory::performNetworkOperation(full_url,
|
||||
@ -861,7 +867,7 @@ QNetworkReply::NetworkError GreaderNetwork::clientLogin(const QNetworkProxy& pro
|
||||
return QNetworkReply::NetworkError::InternalServerError;
|
||||
}
|
||||
|
||||
if (m_service == GreaderServiceRoot::Service::Reedah) {
|
||||
if (m_service == GreaderServiceRoot::Service::Reedah || m_service == GreaderServiceRoot::Service::Miniflux) {
|
||||
// We need "T=" token for editing.
|
||||
full_url = generateFullUrl(Operations::Token);
|
||||
|
||||
@ -929,6 +935,10 @@ QPair<QByteArray, QByteArray> GreaderNetwork::authHeader() const {
|
||||
}
|
||||
}
|
||||
|
||||
QString GreaderNetwork::tokenParameter() const {
|
||||
return QSL("T=%1").arg(m_authToken);
|
||||
}
|
||||
|
||||
bool GreaderNetwork::ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output) {
|
||||
if (m_service == GreaderServiceRoot::Service::Inoreader) {
|
||||
return !m_oauth->bearer().isEmpty();
|
||||
|
@ -83,15 +83,24 @@ class GreaderNetwork : public QObject {
|
||||
void setOauth(OAuth2Service* oauth);
|
||||
|
||||
// API methods.
|
||||
QNetworkReply::NetworkError editLabels(const QString& state, bool assign,
|
||||
const QStringList& msg_custom_ids, const QNetworkProxy& proxy);
|
||||
QNetworkReply::NetworkError editLabels(const QString& state,
|
||||
bool assign,
|
||||
const QStringList& msg_custom_ids,
|
||||
const QNetworkProxy& proxy);
|
||||
QVariantHash userInfo(const QNetworkProxy& proxy);
|
||||
QStringList itemIds(const QString& stream_id, bool unread_only, const QNetworkProxy& proxy, int max_count = -1,
|
||||
QStringList itemIds(const QString& stream_id,
|
||||
bool unread_only,
|
||||
const QNetworkProxy& proxy,
|
||||
int max_count = -1,
|
||||
QDate newer_than = {});
|
||||
QList<Message> itemContents(ServiceRoot* root, const QList<QString>& stream_ids,
|
||||
Feed::Status& error, const QNetworkProxy& proxy);
|
||||
QList<Message> streamContents(ServiceRoot* root, const QString& stream_id,
|
||||
Feed::Status& error, const QNetworkProxy& proxy);
|
||||
QList<Message> itemContents(ServiceRoot* root,
|
||||
const QList<QString>& stream_ids,
|
||||
Feed::Status& error,
|
||||
const QNetworkProxy& proxy);
|
||||
QList<Message> streamContents(ServiceRoot* root,
|
||||
const QString& stream_id,
|
||||
Feed::Status& error,
|
||||
const QNetworkProxy& proxy);
|
||||
QNetworkReply::NetworkError clientLogin(const QNetworkProxy& proxy);
|
||||
|
||||
QDate newerThanFilter() const;
|
||||
@ -103,6 +112,7 @@ class GreaderNetwork : public QObject {
|
||||
|
||||
private:
|
||||
QPair<QByteArray, QByteArray> authHeader() const;
|
||||
QString tokenParameter() const;
|
||||
|
||||
// Make sure we are logged in and if we are not, return error.
|
||||
bool ensureLogin(const QNetworkProxy& proxy, QNetworkReply::NetworkError* output = nullptr);
|
||||
@ -112,8 +122,14 @@ class GreaderNetwork : public QObject {
|
||||
QString simplifyStreamId(const QString& stream_id) const;
|
||||
|
||||
QStringList decodeItemIds(const QString& stream_json_data, QString& continuation);
|
||||
QList<Message> decodeStreamContents(ServiceRoot* root, const QString& stream_json_data, const QString& stream_id, QString& continuation);
|
||||
RootItem* decodeTagsSubscriptions(const QString& categories, const QString& feeds, bool obtain_icons, const QNetworkProxy& proxy);
|
||||
QList<Message> decodeStreamContents(ServiceRoot* root,
|
||||
const QString& stream_json_data,
|
||||
const QString& stream_id,
|
||||
QString& continuation);
|
||||
RootItem* decodeTagsSubscriptions(const QString& categories,
|
||||
const QString& feeds,
|
||||
bool obtain_icons,
|
||||
const QNetworkProxy& proxy);
|
||||
|
||||
QString sanitizedBaseUrl() const;
|
||||
QString generateFullUrl(Operations operation) const;
|
||||
|
@ -17,8 +17,7 @@
|
||||
#include "services/greader/greadernetwork.h"
|
||||
#include "services/greader/gui/formeditgreaderaccount.h"
|
||||
|
||||
GreaderServiceRoot::GreaderServiceRoot(RootItem* parent)
|
||||
: ServiceRoot(parent), m_network(new GreaderNetwork(this)) {
|
||||
GreaderServiceRoot::GreaderServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new GreaderNetwork(this)) {
|
||||
setIcon(GreaderEntryPoint().icon());
|
||||
m_network->setRoot(this);
|
||||
}
|
||||
@ -91,7 +90,8 @@ void GreaderServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
|
||||
}
|
||||
|
||||
void GreaderServiceRoot::aboutToBeginFeedFetching(const QList<Feed*>& feeds,
|
||||
const QHash<QString, QHash<BagOfMessages, QStringList>>& stated_messages,
|
||||
const QHash<QString, QHash<BagOfMessages, QStringList>>&
|
||||
stated_messages,
|
||||
const QHash<QString, QStringList>& tagged_messages) {
|
||||
if (m_network->intelligentSynchronization()) {
|
||||
m_network->prepareFeedFetching(this, feeds, stated_messages, tagged_messages, networkProxy());
|
||||
@ -118,13 +118,17 @@ QString GreaderServiceRoot::serviceToString(Service service) {
|
||||
case Service::Inoreader:
|
||||
return QSL("Inoreader");
|
||||
|
||||
case Service::Miniflux:
|
||||
return QSL("Miniflux");
|
||||
|
||||
default:
|
||||
return tr("Other services");
|
||||
}
|
||||
}
|
||||
|
||||
QList<Message> GreaderServiceRoot::obtainNewMessages(Feed* feed,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>&
|
||||
stated_messages,
|
||||
const QHash<QString, QStringList>& tagged_messages) {
|
||||
Feed::Status error = Feed::Status::Normal;
|
||||
QList<Message> msgs;
|
||||
@ -207,7 +211,8 @@ void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||
QList<Message> messages = j.value();
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
QStringList custom_ids; custom_ids.reserve(messages.size());
|
||||
QStringList custom_ids;
|
||||
custom_ids.reserve(messages.size());
|
||||
|
||||
for (const Message& msg : messages) {
|
||||
custom_ids.append(msg.m_customId);
|
||||
@ -231,7 +236,8 @@ void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||
QStringList messages = k.value();
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
if (network()->editLabels(label_custom_id, true, messages, networkProxy()) != QNetworkReply::NetworkError::NoError &&
|
||||
if (network()->editLabels(label_custom_id, true, messages, networkProxy()) !=
|
||||
QNetworkReply::NetworkError::NoError &&
|
||||
!ignore_errors) {
|
||||
addLabelsAssignmentsToCache(messages, label_custom_id, true);
|
||||
}
|
||||
@ -247,7 +253,8 @@ void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||
QStringList messages = l.value();
|
||||
|
||||
if (!messages.isEmpty()) {
|
||||
if (network()->editLabels(label_custom_id, false, messages, networkProxy()) != QNetworkReply::NetworkError::NoError &&
|
||||
if (network()->editLabels(label_custom_id, false, messages, networkProxy()) !=
|
||||
QNetworkReply::NetworkError::NoError &&
|
||||
!ignore_errors) {
|
||||
addLabelsAssignmentsToCache(messages, label_custom_id, false);
|
||||
}
|
||||
@ -285,6 +292,10 @@ void GreaderServiceRoot::updateTitleIcon() {
|
||||
setIcon(qApp->icons()->miscIcon(QSL("inoreader")));
|
||||
break;
|
||||
|
||||
case Service::Miniflux:
|
||||
setIcon(qApp->icons()->miscIcon(QSL("miniflux")));
|
||||
break;
|
||||
|
||||
default:
|
||||
setIcon(GreaderEntryPoint().icon());
|
||||
break;
|
||||
|
@ -18,9 +18,12 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||
Bazqux = 4,
|
||||
Reedah = 8,
|
||||
Inoreader = 16,
|
||||
Miniflux = 32,
|
||||
Other = 1024
|
||||
};
|
||||
|
||||
Q_ENUM(Service)
|
||||
|
||||
explicit GreaderServiceRoot(RootItem* parent = nullptr);
|
||||
|
||||
virtual bool isSyncable() const;
|
||||
@ -33,7 +36,8 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
||||
virtual QVariantHash customDatabaseData() const;
|
||||
virtual void setCustomDatabaseData(const QVariantHash& data);
|
||||
virtual void aboutToBeginFeedFetching(const QList<Feed*>& feeds,
|
||||
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>& stated_messages,
|
||||
const QHash<QString, QHash<ServiceRoot::BagOfMessages, QStringList>>&
|
||||
stated_messages,
|
||||
const QHash<QString, QStringList>& tagged_messages);
|
||||
virtual QList<Message> obtainNewMessages(Feed* feed,
|
||||
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
|
||||
|
@ -12,18 +12,17 @@
|
||||
#include "services/greader/definitions.h"
|
||||
#include "services/greader/greadernetwork.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
#include <QVariantHash>
|
||||
|
||||
GreaderAccountDetails::GreaderAccountDetails(QWidget* parent) : QWidget(parent),
|
||||
m_oauth(nullptr), m_lastProxy({}) {
|
||||
GreaderAccountDetails::GreaderAccountDetails(QWidget* parent) : QWidget(parent), m_oauth(nullptr), m_lastProxy({}) {
|
||||
m_ui.setupUi(this);
|
||||
|
||||
for (auto serv : { GreaderServiceRoot::Service::Bazqux,
|
||||
GreaderServiceRoot::Service::FreshRss,
|
||||
GreaderServiceRoot::Service::Inoreader,
|
||||
GreaderServiceRoot::Service::Reedah,
|
||||
GreaderServiceRoot::Service::TheOldReader,
|
||||
GreaderServiceRoot::Service::Other }) {
|
||||
QMetaEnum me = QMetaEnum::fromType<GreaderServiceRoot::Service>();
|
||||
|
||||
for (int i = 0; i < me.keyCount(); i++) {
|
||||
GreaderServiceRoot::Service serv = static_cast<GreaderServiceRoot::Service>(me.value(i));
|
||||
|
||||
m_ui.m_cmbService->addItem(GreaderServiceRoot::serviceToString(serv), QVariant::fromValue(serv));
|
||||
}
|
||||
|
||||
@ -54,7 +53,8 @@ GreaderAccountDetails::GreaderAccountDetails(QWidget* parent) : QWidget(parent),
|
||||
false);
|
||||
|
||||
#if defined(INOREADER_OFFICIAL_SUPPORT)
|
||||
m_ui.m_lblInfo->setHelpText(tr("There are some preconfigured OAuth tokens so you do not have to fill in your "
|
||||
m_ui.m_lblInfo
|
||||
->setHelpText(tr("There are some preconfigured OAuth tokens so you do not have to fill in your "
|
||||
"client ID/secret, but it is strongly recommended to obtain your "
|
||||
"own as preconfigured tokens have limited global usage quota. If you wish "
|
||||
"to use preconfigured tokens, simply leave all above fields to their default values even "
|
||||
@ -68,7 +68,10 @@ GreaderAccountDetails::GreaderAccountDetails(QWidget* parent) : QWidget(parent),
|
||||
connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onPasswordChanged);
|
||||
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onUsernameChanged);
|
||||
connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::onUrlChanged);
|
||||
connect(m_ui.m_cmbService, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GreaderAccountDetails::fillPredefinedUrl);
|
||||
connect(m_ui.m_cmbService,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this,
|
||||
&GreaderAccountDetails::fillPredefinedUrl);
|
||||
connect(m_ui.m_cbNewAlgorithm, &QCheckBox::toggled, m_ui.m_spinLimitMessages, &MessageCountSpinBox::setDisabled);
|
||||
connect(m_ui.m_txtAppId->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::checkOAuthValue);
|
||||
connect(m_ui.m_txtAppKey->lineEdit(), &BaseLineEdit::textChanged, this, &GreaderAccountDetails::checkOAuthValue);
|
||||
@ -126,9 +129,7 @@ void GreaderAccountDetails::onAuthGranted() {
|
||||
m_ui.m_txtUsername->lineEdit()->setText(resp[QSL("userEmail")].toString());
|
||||
}
|
||||
catch (const ApplicationException& ex) {
|
||||
qCriticalNN << LOGSEC_GREADER
|
||||
<< "Failed to obtain profile with error:"
|
||||
<< QUOTE_W_SPACE_DOT(ex.message());
|
||||
qCriticalNN << LOGSEC_GREADER << "Failed to obtain profile with error:" << QUOTE_W_SPACE_DOT(ex.message());
|
||||
}
|
||||
}
|
||||
|
||||
@ -198,9 +199,7 @@ void GreaderAccountDetails::performTest(const QNetworkProxy& custom_proxy) {
|
||||
tr("Network error, have you entered correct Nextcloud endpoint and password?"));
|
||||
}
|
||||
else {
|
||||
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok,
|
||||
tr("You are good to go!"),
|
||||
tr("Yeah."));
|
||||
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok, tr("You are good to go!"), tr("Yeah."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user