diff options
| author | Andrew Branson <andrew.branson@jolla.com> | 2026-02-10 23:16:37 +0100 |
|---|---|---|
| committer | Andrew Branson <andrew.branson@jolla.com> | 2026-02-10 23:16:37 +0100 |
| commit | 69628390815254297bbd8c95436f6780fa846fae (patch) | |
| tree | df6114043e489bf5d767ac39f0d20636e12cf3a2 /buteo-plugins | |
| parent | ff1c2efe40bf53c146b4a2e3b5046ae8ecb32264 (diff) | |
Translations fixed and other stuff
Diffstat (limited to 'buteo-plugins')
6 files changed, 150 insertions, 327 deletions
diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp index f915507..295d7b9 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.cpp @@ -19,10 +19,10 @@ ****************************************************************************/ #include "mastodondatatypesyncadaptor.h" +#include "mastodonauthutils.h" #include "trace.h" #include <QtCore/QVariantMap> -#include <QtCore/QUrl> #include <QtNetwork/QNetworkRequest> // libaccounts-qt5 @@ -131,29 +131,6 @@ void MastodonNotificationsDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts account->syncAndBlock(); } -QString MastodonNotificationsDataTypeSyncAdaptor::normalizeApiHost(const QString &rawHost) -{ - QString host = rawHost.trimmed(); - if (host.isEmpty()) { - host = QStringLiteral("https://mastodon.social"); - } - if (!host.startsWith(QLatin1String("https://")) - && !host.startsWith(QLatin1String("http://"))) { - host.prepend(QStringLiteral("https://")); - } - - QUrl url(host); - if (!url.isValid() || url.host().isEmpty()) { - return QStringLiteral("https://mastodon.social"); - } - - QString normalized = QString::fromLatin1(url.toEncoded(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment)); - if (normalized.endsWith(QLatin1Char('/'))) { - normalized.chop(1); - } - return normalized; -} - void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account) { const int accountId = account->id(); @@ -185,59 +162,7 @@ void MastodonNotificationsDataTypeSyncAdaptor::signIn(Accounts::Account *account } QVariantMap signonSessionData = accSrv.authData().parameters(); - QString configuredHost = account->value(QStringLiteral("auth/oauth2/web_server/Host")).toString().trimmed(); - if (configuredHost.isEmpty()) { - configuredHost = normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()); - } - if (configuredHost.startsWith(QLatin1String("https://"))) { - configuredHost.remove(0, 8); - } else if (configuredHost.startsWith(QLatin1String("http://"))) { - configuredHost.remove(0, 7); - } - while (configuredHost.endsWith(QLatin1Char('/'))) { - configuredHost.chop(1); - } - if (configuredHost.isEmpty()) { - configuredHost = QStringLiteral("mastodon.social"); - } - signonSessionData.insert(QStringLiteral("Host"), configuredHost); - - const QString authPath = account->value(QStringLiteral("auth/oauth2/web_server/AuthPath")).toString().trimmed(); - if (!authPath.isEmpty()) { - signonSessionData.insert(QStringLiteral("AuthPath"), authPath); - } - - const QString tokenPath = account->value(QStringLiteral("auth/oauth2/web_server/TokenPath")).toString().trimmed(); - if (!tokenPath.isEmpty()) { - signonSessionData.insert(QStringLiteral("TokenPath"), tokenPath); - } - - const QString responseType = account->value(QStringLiteral("auth/oauth2/web_server/ResponseType")).toString().trimmed(); - if (!responseType.isEmpty()) { - signonSessionData.insert(QStringLiteral("ResponseType"), responseType); - } - - const QString redirectUri = account->value(QStringLiteral("auth/oauth2/web_server/RedirectUri")).toString().trimmed(); - if (!redirectUri.isEmpty()) { - signonSessionData.insert(QStringLiteral("RedirectUri"), redirectUri); - } - - const QVariant scopeValue = account->value(QStringLiteral("auth/oauth2/web_server/Scope")); - if (scopeValue.isValid()) { - signonSessionData.insert(QStringLiteral("Scope"), scopeValue); - } - - const QString clientId = account->value(QStringLiteral("auth/oauth2/web_server/ClientId")).toString().trimmed(); - if (!clientId.isEmpty()) { - signonSessionData.insert(QStringLiteral("ClientId"), clientId); - } - - const QString clientSecret = account->value(QStringLiteral("auth/oauth2/web_server/ClientSecret")).toString().trimmed(); - if (!clientSecret.isEmpty()) { - signonSessionData.insert(QStringLiteral("ClientSecret"), clientSecret); - } - - signonSessionData.insert(QStringLiteral("UiPolicy"), SignOn::NoUserInteractionPolicy); + MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData); connect(session, SIGNAL(response(SignOn::SessionData)), this, SLOT(signOnResponse(SignOn::SessionData)), @@ -276,10 +201,7 @@ void MastodonNotificationsDataTypeSyncAdaptor::signOnError(const SignOn::Error & void MastodonNotificationsDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData) { - QVariantMap data; - foreach (const QString &key, responseData.propertyNames()) { - data.insert(key, responseData.getProperty(key)); - } + const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData); QString accessToken; SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender()); @@ -287,16 +209,13 @@ void MastodonNotificationsDataTypeSyncAdaptor::signOnResponse(const SignOn::Sess SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>(); const int accountId = account->id(); - accessToken = data.value(QLatin1String("AccessToken")).toString().trimmed(); - if (accessToken.isEmpty()) { - accessToken = data.value(QLatin1String("access_token")).toString().trimmed(); - } + accessToken = MastodonAuthUtils::accessToken(data); if (accessToken.isEmpty()) { qCWarning(lcSocialPlugin) << "signon response for account with id" << accountId << "contained no access token; keys:" << data.keys(); } - m_apiHosts.insert(accountId, normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())); + m_apiHosts.insert(accountId, MastodonAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())); session->disconnect(this); identity->destroySession(session); diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h index 1c2d13f..3bb6e23 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodondatatypesyncadaptor.h @@ -59,7 +59,6 @@ private Q_SLOTS: void signOnResponse(const SignOn::SessionData &responseData); private: - static QString normalizeApiHost(const QString &rawHost); void setCredentialsNeedUpdate(Accounts::Account *account); void signIn(Accounts::Account *account); diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp index aa1089c..79b996c 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.cpp @@ -31,6 +31,8 @@ #include <notification.h> +#include <algorithm> + #define OPEN_BROWSER_ACTION(openUrlArgs) \ Notification::remoteAction( \ "default", \ @@ -45,8 +47,9 @@ namespace { const char *const NotificationCategory = "x-nemo.social.mastodon.notification"; const char *const LastReadIdProperty = "mastodonLastReadId"; + const char *const NotificationIdHint = "x-nemo.sociald.notification-id"; const int NotificationsPageLimit = 80; - const uint NotificationDismissedReason = 2; + const uint NotificationDismissedReason = 1; QString decodeHtmlEntities(QString text) { @@ -118,41 +121,12 @@ namespace { return QStringLiteral("sent you a notification"); } - QList<QPair<QString, SocialPostImage::ImageType> > parseMediaAttachments(const QJsonObject &statusObject) - { - QList<QPair<QString, SocialPostImage::ImageType> > imageList; - - const QJsonArray mediaAttachments = statusObject.value(QStringLiteral("media_attachments")).toArray(); - foreach (const QJsonValue &attachmentValue, mediaAttachments) { - const QJsonObject attachment = attachmentValue.toObject(); - const QString mediaType = attachment.value(QStringLiteral("type")).toString(); - - QString mediaUrl; - SocialPostImage::ImageType imageType = SocialPostImage::Invalid; - if (mediaType == QLatin1String("image")) { - mediaUrl = attachment.value(QStringLiteral("url")).toString(); - imageType = SocialPostImage::Photo; - } else if (mediaType == QLatin1String("video") || mediaType == QLatin1String("gifv")) { - mediaUrl = attachment.value(QStringLiteral("preview_url")).toString(); - if (mediaUrl.isEmpty()) { - mediaUrl = attachment.value(QStringLiteral("url")).toString(); - } - imageType = SocialPostImage::Video; - } - - if (!mediaUrl.isEmpty() && imageType != SocialPostImage::Invalid) { - imageList.append(qMakePair(mediaUrl, imageType)); - } - } - - return imageList; - } } MastodonNotificationsSyncAdaptor::MastodonNotificationsSyncAdaptor(QObject *parent) : MastodonNotificationsDataTypeSyncAdaptor(SocialNetworkSyncAdaptor::Notifications, parent) { - setInitialActive(m_db.isValid()); + setInitialActive(true); } MastodonNotificationsSyncAdaptor::~MastodonNotificationsSyncAdaptor() @@ -166,17 +140,7 @@ QString MastodonNotificationsSyncAdaptor::syncServiceName() const void MastodonNotificationsSyncAdaptor::purgeDataForOldAccount(int oldId, SocialNetworkSyncAdaptor::PurgeMode) { - Notification *notification = findNotification(oldId); - if (notification) { - notification->close(); - notification->deleteLater(); - } - - m_db.removePosts(oldId); - m_db.commit(); - m_db.wait(); - - purgeCachedImages(&m_imageCacheDb, oldId); + closeAccountNotifications(oldId); m_pendingSyncStates.remove(oldId); m_accessTokens.remove(oldId); @@ -193,12 +157,10 @@ void MastodonNotificationsSyncAdaptor::beginSync(int accountId, const QString &a void MastodonNotificationsSyncAdaptor::finalize(int accountId) { if (syncAborted()) { - qCInfo(lcSocialPlugin) << "sync aborted, won't commit database changes"; - } else { - m_db.commit(); - m_db.wait(); - purgeExpiredImages(&m_imageCacheDb, accountId); + qCInfo(lcSocialPlugin) << "sync aborted, won't update notifications"; } + + Q_UNUSED(accountId) } QString MastodonNotificationsSyncAdaptor::sanitizeContent(const QString &content) @@ -271,6 +233,11 @@ int MastodonNotificationsSyncAdaptor::compareNotificationIds(const QString &left return left < right ? -1 : 1; } +QString MastodonNotificationsSyncAdaptor::notificationObjectKey(int accountId, const QString ¬ificationId) +{ + return QString::number(accountId) + QLatin1Char(':') + notificationId; +} + void MastodonNotificationsSyncAdaptor::requestUnreadMarker(int accountId, const QString &accessToken) { QUrl url(apiHost(accountId) + QStringLiteral("/api/v1/markers")); @@ -369,7 +336,6 @@ void MastodonNotificationsSyncAdaptor::finishedUnreadMarkerHandler() PendingSyncState state; state.accessToken = accessToken; state.minReadId = minReadId; - state.maxNotificationId = minReadId; m_pendingSyncStates.insert(accountId, state); requestNotifications(accountId, accessToken, minReadId); @@ -397,33 +363,19 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() if (state.accessToken.isEmpty()) { state.accessToken = accessToken; state.minReadId = minId; - state.maxNotificationId = minId; } bool ok = false; const QJsonArray notifications = parseJsonArrayReplyData(replyData, &ok); if (!isError && ok) { if (!notifications.size()) { - if (!state.dbCleared) { - m_db.removePosts(accountId); - state.dbCleared = true; - } - Notification *notification = findNotification(accountId); - if (notification) { - notification->close(); - notification->deleteLater(); - } + closeAccountNotifications(accountId); qCDebug(lcSocialPlugin) << "no notifications received for account" << accountId; m_pendingSyncStates.remove(accountId); decrementSemaphore(accountId); return; } - if (!state.dbCleared) { - m_db.removePosts(accountId); - state.dbCleared = true; - } - QString pageMinNotificationId; foreach (const QJsonValue ¬ificationValue, notifications) { @@ -441,10 +393,6 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() || compareNotificationIds(notificationId, pageMinNotificationId) < 0) { pageMinNotificationId = notificationId; } - if (state.maxNotificationId.isEmpty() - || compareNotificationIds(notificationId, state.maxNotificationId) > 0) { - state.maxNotificationId = notificationId; - } const QString notificationType = notificationObject.value(QStringLiteral("type")).toString(); const QJsonObject actorObject = notificationObject.value(QStringLiteral("account")).toObject(); @@ -464,11 +412,6 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() const QString displayName = displayNameForAccount(actorObject); const QString accountName = actorObject.value(QStringLiteral("acct")).toString(); - QString icon = actorObject.value(QStringLiteral("avatar_static")).toString(); - if (icon.isEmpty()) { - icon = actorObject.value(QStringLiteral("avatar")).toString(); - } - const QString statusBody = sanitizeContent(statusObject.value(QStringLiteral("content")).toString()); const QString action = actionText(notificationType); QString body; @@ -495,33 +438,13 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() url = QStringLiteral("%1/@%2").arg(apiHost(accountId), accountName); } - QString boostedBy; - if (notificationType == QLatin1String("reblog") - || notificationType == QLatin1String("favourite")) { - boostedBy = displayName; - } - - const QList<QPair<QString, SocialPostImage::ImageType> > imageList = parseMediaAttachments(statusObject); - - m_db.addMastodonNotification(QStringLiteral("n:%1").arg(notificationId), - displayName, - accountName, - body, - eventTimestamp, - icon, - imageList, - url, - boostedBy, - apiHost(accountId), - accountId); - - ++state.newNotificationCount; - if (state.newNotificationCount == 1) { - state.singleSummary = displayName; - state.singleBody = body; - state.singleLink = url; - state.singleTimestamp = eventTimestamp; - } + PendingNotification pendingNotification; + pendingNotification.notificationId = notificationId; + pendingNotification.summary = displayName; + pendingNotification.body = body; + pendingNotification.link = url; + pendingNotification.timestamp = eventTimestamp; + state.pendingNotifications.insert(notificationId, pendingNotification); } if (notifications.size() >= NotificationsPageLimit @@ -533,8 +456,19 @@ void MastodonNotificationsSyncAdaptor::finishedNotificationsHandler() return; } - if (state.newNotificationCount > 0) { - publishSystemNotification(accountId, state); + if (state.pendingNotifications.size() > 0) { + QStringList notificationIds = state.pendingNotifications.keys(); + std::sort(notificationIds.begin(), notificationIds.end(), [](const QString &left, const QString &right) { + return compareNotificationIds(left, right) > 0; + }); + + QSet<QString> keepNotificationIds; + foreach (const QString ¬ificationId, notificationIds) { + const PendingNotification pendingNotification = state.pendingNotifications.value(notificationId); + publishSystemNotification(accountId, pendingNotification); + keepNotificationIds.insert(notificationId); + } + closeAccountNotifications(accountId, keepNotificationIds); } } else { qCWarning(lcSocialPlugin) << "unable to parse notifications data from request with account" << accountId @@ -601,30 +535,76 @@ void MastodonNotificationsSyncAdaptor::finishedMarkReadHandler() decrementSemaphore(accountId); } -void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId, const PendingSyncState &state) +void MastodonNotificationsSyncAdaptor::publishSystemNotification(int accountId, + const PendingNotification ¬ificationData) { - Notification *notification = createNotification(accountId); - notification->setItemCount(state.newNotificationCount); - - QStringList openUrlArgs; - if (notification->itemCount() == 1) { - notification->setTimestamp(state.singleTimestamp.isValid() ? state.singleTimestamp : QDateTime::currentDateTimeUtc()); - notification->setSummary(state.singleSummary.isEmpty() ? QStringLiteral("Mastodon") : state.singleSummary); - notification->setBody(state.singleBody.isEmpty() ? QStringLiteral("New notification") : state.singleBody); - openUrlArgs << (state.singleLink.isEmpty() ? apiHost(accountId) + QStringLiteral("/notifications") : state.singleLink); - } else { - notification->setTimestamp(QDateTime::currentDateTimeUtc()); - notification->setSummary(QStringLiteral("Mastodon")); - notification->setBody(QStringLiteral("You have %1 new notifications").arg(notification->itemCount())); - openUrlArgs << apiHost(accountId) + QStringLiteral("/notifications"); - } - - notification->setProperty(LastReadIdProperty, state.maxNotificationId); + Notification *notification = createNotification(accountId, notificationData.notificationId); + notification->setItemCount(1); + notification->setTimestamp(notificationData.timestamp.isValid() + ? notificationData.timestamp + : QDateTime::currentDateTimeUtc()); + notification->setSummary(notificationData.summary.isEmpty() + ? QStringLiteral("Mastodon") + : notificationData.summary); + notification->setBody(notificationData.body.isEmpty() + ? QStringLiteral("New notification") + : notificationData.body); + notification->setPreviewSummary(notificationData.summary); + notification->setPreviewBody(notificationData.body); + + const QString openUrl = notificationData.link.isEmpty() + ? apiHost(accountId) + QStringLiteral("/notifications") + : notificationData.link; + notification->setProperty(LastReadIdProperty, notificationData.notificationId); notification->setUrgency(Notification::Low); - notification->setRemoteAction(OPEN_BROWSER_ACTION(openUrlArgs)); + notification->setRemoteAction(OPEN_BROWSER_ACTION(QStringList() << openUrl)); notification->publish(); if (notification->replacesId() == 0) { - qCWarning(lcSocialPlugin) << "failed to publish Mastodon notification"; + qCWarning(lcSocialPlugin) << "failed to publish Mastodon notification" + << notificationData.notificationId; + } +} + +void MastodonNotificationsSyncAdaptor::closeAccountNotifications(int accountId, + const QSet<QString> &keepNotificationIds) +{ + QStringList cachedKeys = m_notificationObjects.keys(); + foreach (const QString &objectKey, cachedKeys) { + Notification *notification = m_notificationObjects.value(objectKey); + if (!notification + || notification->hintValue("x-nemo.sociald.account-id").toInt() != accountId) { + continue; + } + + const QString notificationId = notification->hintValue(NotificationIdHint).toString(); + if (!notificationId.isEmpty() && keepNotificationIds.contains(notificationId)) { + continue; + } + + notification->close(); + m_notificationObjects.remove(objectKey); + notification->deleteLater(); + } + + QList<QObject *> notifications = Notification::notifications(); + foreach (QObject *object, notifications) { + Notification *notification = qobject_cast<Notification *>(object); + if (!notification) { + delete object; + continue; + } + + if (notification->category() == QLatin1String(NotificationCategory) + && notification->hintValue("x-nemo.sociald.account-id").toInt() == accountId) { + const QString notificationId = notification->hintValue(NotificationIdHint).toString(); + if (notificationId.isEmpty() || !keepNotificationIds.contains(notificationId)) { + notification->close(); + } + } + + if (notification->parent() != this) { + delete notification; + } } } @@ -662,30 +642,42 @@ void MastodonNotificationsSyncAdaptor::markReadFromNotification(Notification *no requestMarkRead(accountId, accessToken, lastReadId); } -Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId) +Notification *MastodonNotificationsSyncAdaptor::createNotification(int accountId, const QString ¬ificationId) { - Notification *notification = findNotification(accountId); + const QString objectKey = notificationObjectKey(accountId, notificationId); + Notification *notification = m_notificationObjects.value(objectKey); + if (!notification) { + notification = findNotification(accountId, notificationId); + } if (!notification) { notification = new Notification(this); - notification->setAppName(QStringLiteral("Mastodon")); - notification->setAppIcon(QStringLiteral("icon-l-mastodon")); - notification->setHintValue("x-nemo.sociald.account-id", accountId); - notification->setHintValue("x-nemo-feedback", QStringLiteral("social")); - notification->setCategory(QLatin1String(NotificationCategory)); + } else if (notification->parent() != this) { + notification->setParent(this); } + + notification->setAppName(QStringLiteral("Mastodon")); + notification->setAppIcon(QStringLiteral("icon-l-mastodon")); + notification->setHintValue("x-nemo.sociald.account-id", accountId); + notification->setHintValue(NotificationIdHint, notificationId); + notification->setHintValue("x-nemo-feedback", QStringLiteral("social")); + notification->setCategory(QLatin1String(NotificationCategory)); + connect(notification, SIGNAL(closed(uint)), this, SLOT(notificationClosedWithReason(uint)), Qt::UniqueConnection); + m_notificationObjects.insert(objectKey, notification); return notification; } -Notification *MastodonNotificationsSyncAdaptor::findNotification(int accountId) +Notification *MastodonNotificationsSyncAdaptor::findNotification(int accountId, const QString ¬ificationId) { Notification *notification = 0; QList<QObject *> notifications = Notification::notifications(); foreach (QObject *object, notifications) { - Notification *castedNotification = static_cast<Notification *>(object); - if (castedNotification->category() == QLatin1String(NotificationCategory) - && castedNotification->hintValue("x-nemo.sociald.account-id").toInt() == accountId) { + Notification *castedNotification = qobject_cast<Notification *>(object); + if (castedNotification + && castedNotification->category() == QLatin1String(NotificationCategory) + && castedNotification->hintValue("x-nemo.sociald.account-id").toInt() == accountId + && castedNotification->hintValue(NotificationIdHint).toString() == notificationId) { notification = castedNotification; break; } diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h index 8c79d7d..0cd63a4 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h +++ b/buteo-plugins/buteo-sync-plugin-mastodon-notifications/mastodonnotificationssyncadaptor.h @@ -25,11 +25,9 @@ #include <QtCore/QDateTime> #include <QtCore/QHash> +#include <QtCore/QSet> #include <QtNetwork/QNetworkReply> -#include "mastodonnotificationsdatabase.h" -#include <socialcache/socialimagesdatabase.h> - class Notification; class MastodonNotificationsSyncAdaptor : public MastodonNotificationsDataTypeSyncAdaptor @@ -48,22 +46,18 @@ protected: void finalize(int accountId) override; private: + struct PendingNotification { + QString notificationId; + QString summary; + QString body; + QString link; + QDateTime timestamp; + }; + struct PendingSyncState { QString accessToken; QString minReadId; - QString maxNotificationId; - int newNotificationCount; - QString singleSummary; - QString singleBody; - QString singleLink; - QDateTime singleTimestamp; - bool dbCleared; - - PendingSyncState() - : newNotificationCount(0) - , dbCleared(false) - { - } + QHash<QString, PendingNotification> pendingNotifications; }; static QString sanitizeContent(const QString &content); @@ -76,9 +70,11 @@ private: const QString &minId, const QString &maxId = QString()); void requestMarkRead(int accountId, const QString &accessToken, const QString &lastReadId); - void publishSystemNotification(int accountId, const PendingSyncState &state); - Notification *createNotification(int accountId); - Notification *findNotification(int accountId); + void publishSystemNotification(int accountId, const PendingNotification ¬ificationData); + Notification *createNotification(int accountId, const QString ¬ificationId); + Notification *findNotification(int accountId, const QString ¬ificationId); + void closeAccountNotifications(int accountId, const QSet<QString> &keepNotificationIds = QSet<QString>()); + static QString notificationObjectKey(int accountId, const QString ¬ificationId); void markReadFromNotification(Notification *notification); private Q_SLOTS: @@ -88,11 +84,10 @@ private Q_SLOTS: void notificationClosedWithReason(uint reason); private: - MastodonNotificationsDatabase m_db; - SocialImagesDatabase m_imageCacheDb; QHash<int, PendingSyncState> m_pendingSyncStates; QHash<int, QString> m_accessTokens; QHash<int, QString> m_lastMarkedReadIds; + QHash<QString, Notification *> m_notificationObjects; }; #endif // MASTODONNOTIFICATIONSSYNCADAPTOR_H diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp index 83a5249..7b47fe8 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp +++ b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.cpp @@ -19,10 +19,10 @@ ****************************************************************************/ #include "mastodondatatypesyncadaptor.h" +#include "mastodonauthutils.h" #include "trace.h" #include <QtCore/QVariantMap> -#include <QtCore/QUrl> #include <QtNetwork/QNetworkRequest> // libaccounts-qt5 @@ -131,29 +131,6 @@ void MastodonDataTypeSyncAdaptor::setCredentialsNeedUpdate(Accounts::Account *ac account->syncAndBlock(); } -QString MastodonDataTypeSyncAdaptor::normalizeApiHost(const QString &rawHost) -{ - QString host = rawHost.trimmed(); - if (host.isEmpty()) { - host = QStringLiteral("https://mastodon.social"); - } - if (!host.startsWith(QLatin1String("https://")) - && !host.startsWith(QLatin1String("http://"))) { - host.prepend(QStringLiteral("https://")); - } - - QUrl url(host); - if (!url.isValid() || url.host().isEmpty()) { - return QStringLiteral("https://mastodon.social"); - } - - QString normalized = QString::fromLatin1(url.toEncoded(QUrl::RemovePath | QUrl::RemoveQuery | QUrl::RemoveFragment)); - if (normalized.endsWith(QLatin1Char('/'))) { - normalized.chop(1); - } - return normalized; -} - void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account) { const int accountId = account->id(); @@ -185,59 +162,7 @@ void MastodonDataTypeSyncAdaptor::signIn(Accounts::Account *account) } QVariantMap signonSessionData = accSrv.authData().parameters(); - QString configuredHost = account->value(QStringLiteral("auth/oauth2/web_server/Host")).toString().trimmed(); - if (configuredHost.isEmpty()) { - configuredHost = normalizeApiHost(account->value(QStringLiteral("api/Host")).toString()); - } - if (configuredHost.startsWith(QLatin1String("https://"))) { - configuredHost.remove(0, 8); - } else if (configuredHost.startsWith(QLatin1String("http://"))) { - configuredHost.remove(0, 7); - } - while (configuredHost.endsWith(QLatin1Char('/'))) { - configuredHost.chop(1); - } - if (configuredHost.isEmpty()) { - configuredHost = QStringLiteral("mastodon.social"); - } - signonSessionData.insert(QStringLiteral("Host"), configuredHost); - - const QString authPath = account->value(QStringLiteral("auth/oauth2/web_server/AuthPath")).toString().trimmed(); - if (!authPath.isEmpty()) { - signonSessionData.insert(QStringLiteral("AuthPath"), authPath); - } - - const QString tokenPath = account->value(QStringLiteral("auth/oauth2/web_server/TokenPath")).toString().trimmed(); - if (!tokenPath.isEmpty()) { - signonSessionData.insert(QStringLiteral("TokenPath"), tokenPath); - } - - const QString responseType = account->value(QStringLiteral("auth/oauth2/web_server/ResponseType")).toString().trimmed(); - if (!responseType.isEmpty()) { - signonSessionData.insert(QStringLiteral("ResponseType"), responseType); - } - - const QString redirectUri = account->value(QStringLiteral("auth/oauth2/web_server/RedirectUri")).toString().trimmed(); - if (!redirectUri.isEmpty()) { - signonSessionData.insert(QStringLiteral("RedirectUri"), redirectUri); - } - - const QVariant scopeValue = account->value(QStringLiteral("auth/oauth2/web_server/Scope")); - if (scopeValue.isValid()) { - signonSessionData.insert(QStringLiteral("Scope"), scopeValue); - } - - const QString clientId = account->value(QStringLiteral("auth/oauth2/web_server/ClientId")).toString().trimmed(); - if (!clientId.isEmpty()) { - signonSessionData.insert(QStringLiteral("ClientId"), clientId); - } - - const QString clientSecret = account->value(QStringLiteral("auth/oauth2/web_server/ClientSecret")).toString().trimmed(); - if (!clientSecret.isEmpty()) { - signonSessionData.insert(QStringLiteral("ClientSecret"), clientSecret); - } - - signonSessionData.insert(QStringLiteral("UiPolicy"), SignOn::NoUserInteractionPolicy); + MastodonAuthUtils::addSignOnSessionParameters(account, &signonSessionData); connect(session, SIGNAL(response(SignOn::SessionData)), this, SLOT(signOnResponse(SignOn::SessionData)), @@ -276,10 +201,7 @@ void MastodonDataTypeSyncAdaptor::signOnError(const SignOn::Error &error) void MastodonDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &responseData) { - QVariantMap data; - foreach (const QString &key, responseData.propertyNames()) { - data.insert(key, responseData.getProperty(key)); - } + const QVariantMap data = MastodonAuthUtils::responseDataToMap(responseData); QString accessToken; SignOn::AuthSession *session = qobject_cast<SignOn::AuthSession*>(sender()); @@ -287,16 +209,13 @@ void MastodonDataTypeSyncAdaptor::signOnResponse(const SignOn::SessionData &resp SignOn::Identity *identity = session->property("identity").value<SignOn::Identity*>(); const int accountId = account->id(); - accessToken = data.value(QLatin1String("AccessToken")).toString().trimmed(); - if (accessToken.isEmpty()) { - accessToken = data.value(QLatin1String("access_token")).toString().trimmed(); - } + accessToken = MastodonAuthUtils::accessToken(data); if (accessToken.isEmpty()) { qCWarning(lcSocialPlugin) << "signon response for account with id" << accountId << "contained no access token; keys:" << data.keys(); } - m_apiHosts.insert(accountId, normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())); + m_apiHosts.insert(accountId, MastodonAuthUtils::normalizeApiHost(account->value(QStringLiteral("api/Host")).toString())); session->disconnect(this); identity->destroySession(session); diff --git a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h index ad8321d..3ebbbf5 100644 --- a/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h +++ b/buteo-plugins/buteo-sync-plugin-mastodon-posts/mastodondatatypesyncadaptor.h @@ -59,7 +59,6 @@ private Q_SLOTS: void signOnResponse(const SignOn::SessionData &responseData); private: - static QString normalizeApiHost(const QString &rawHost); void setCredentialsNeedUpdate(Accounts::Account *account); void signIn(Accounts::Account *account); |
