diff options
Diffstat (limited to 'transferengine-plugins/mastodontransferplugin')
7 files changed, 0 insertions, 724 deletions
diff --git a/transferengine-plugins/mastodontransferplugin/mastodonapi.cpp b/transferengine-plugins/mastodontransferplugin/mastodonapi.cpp deleted file mode 100644 index fa973d0..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodonapi.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "mastodonapi.h" -#include "mastodonauthutils.h" - -#include <QtCore/QFile> -#include <QtCore/QFileInfo> -#include <QtNetwork/QHttpMultiPart> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> -#include <QtCore/QUrl> -#include <QtCore/QUrlQuery> - -#include <QtNetwork/QNetworkRequest> - -#include <QtDebug> - -MastodonApi::MastodonApi(QNetworkAccessManager *qnam, QObject *parent) - : QObject(parent) - , m_cancelRequested(false) - , m_qnam(qnam) -{ -} - -MastodonApi::~MastodonApi() -{ -} - -bool MastodonApi::uploadImage(const QString &filePath, - const QString &statusText, - const QString &mimeType, - const QString &apiHost, - const QString &accessToken) -{ - QFile file(filePath); - if (filePath.isEmpty() || !file.open(QIODevice::ReadOnly)) { - qWarning() << Q_FUNC_INFO << "error opening file:" << filePath; - return false; - } - - m_cancelRequested = false; - m_apiHost = MastodonAuthUtils::normalizeApiHost(apiHost); - m_accessToken = accessToken; - m_statusText = statusText; - - if (m_accessToken.isEmpty()) { - qWarning() << Q_FUNC_INFO << "missing access token"; - return false; - } - - const QByteArray imageData = file.readAll(); - const QFileInfo fileInfo(filePath); - - QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); - - QHttpPart filePart; - filePart.setHeader(QNetworkRequest::ContentDispositionHeader, - QVariant(QStringLiteral("form-data; name=\"file\"; filename=\"%1\"") - .arg(fileInfo.fileName()))); - if (!mimeType.isEmpty()) { - filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(mimeType)); - } - filePart.setBody(imageData); - multiPart->append(filePart); - - QNetworkRequest request(QUrl(m_apiHost + QStringLiteral("/api/v1/media"))); - request.setRawHeader(QByteArrayLiteral("Authorization"), - QByteArrayLiteral("Bearer ") + m_accessToken.toUtf8()); - - QNetworkReply *reply = m_qnam->post(request, multiPart); - if (!reply) { - delete multiPart; - return false; - } - - multiPart->setParent(reply); - m_replies.insert(reply, UPLOAD_MEDIA); - - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(replyError(QNetworkReply::NetworkError))); - connect(reply, &QNetworkReply::uploadProgress, - this, &MastodonApi::uploadProgress); - connect(reply, &QNetworkReply::finished, - this, &MastodonApi::finished); - - return true; -} - -bool MastodonApi::postStatus(const QString &statusText, - const QString &apiHost, - const QString &accessToken) -{ - m_cancelRequested = false; - m_apiHost = MastodonAuthUtils::normalizeApiHost(apiHost); - m_accessToken = accessToken; - m_statusText = statusText; - - if (m_accessToken.isEmpty()) { - qWarning() << Q_FUNC_INFO << "missing access token"; - return false; - } - - return postStatusInternal(QString()); -} - -bool MastodonApi::postStatusInternal(const QString &mediaId) -{ - if (m_statusText.trimmed().isEmpty() && mediaId.isEmpty()) { - qWarning() << Q_FUNC_INFO << "status and media id are empty"; - return false; - } - - QUrlQuery query; - if (!m_statusText.isEmpty()) { - query.addQueryItem(QStringLiteral("status"), m_statusText); - } - if (!mediaId.isEmpty()) { - query.addQueryItem(QStringLiteral("media_ids[]"), mediaId); - } - - const QByteArray postData = query.query(QUrl::FullyEncoded).toUtf8(); - - QNetworkRequest request(QUrl(m_apiHost + QStringLiteral("/api/v1/statuses"))); - request.setRawHeader(QByteArrayLiteral("Authorization"), - QByteArrayLiteral("Bearer ") + m_accessToken.toUtf8()); - request.setHeader(QNetworkRequest::ContentTypeHeader, - QVariant(QStringLiteral("application/x-www-form-urlencoded"))); - - QNetworkReply *reply = m_qnam->post(request, postData); - if (!reply) { - return false; - } - - m_replies.insert(reply, POST_STATUS); - connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), - this, SLOT(replyError(QNetworkReply::NetworkError))); - connect(reply, &QNetworkReply::finished, - this, &MastodonApi::finished); - - return true; -} - -void MastodonApi::cancelUpload() -{ - if (m_replies.isEmpty()) { - qWarning() << Q_FUNC_INFO << "can't cancel upload"; - return; - } - - m_cancelRequested = true; - const QList<QNetworkReply*> replies = m_replies.keys(); - Q_FOREACH (QNetworkReply *reply, replies) { - reply->abort(); - } -} - -void MastodonApi::replyError(QNetworkReply::NetworkError error) -{ - Q_UNUSED(error) -} - -void MastodonApi::uploadProgress(qint64 sent, qint64 total) -{ - if (total > 0) { - emit transferProgressUpdated(sent / static_cast<qreal>(total)); - } -} - -void MastodonApi::finished() -{ - QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender()); - if (!reply || !m_replies.contains(reply)) { - return; - } - - const API_CALL apiCall = m_replies.take(reply); - const QByteArray data = reply->readAll(); - const int httpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); - const QNetworkReply::NetworkError error = reply->error(); - - reply->deleteLater(); - - if (m_cancelRequested && error == QNetworkReply::OperationCanceledError) { - if (m_replies.isEmpty()) { - m_cancelRequested = false; - emit transferCanceled(); - } - return; - } - - if (apiCall == UPLOAD_MEDIA) { - if (error != QNetworkReply::NoError || httpCode < 200 || httpCode >= 300) { - finishTransfer(error == QNetworkReply::NoError ? QNetworkReply::UnknownNetworkError : error, - httpCode, - data); - return; - } - - QString mediaId; - const QJsonDocument doc = QJsonDocument::fromJson(data); - if (doc.isObject()) { - const QJsonValue idValue = doc.object().value(QStringLiteral("id")); - if (idValue.isString()) { - mediaId = idValue.toString(); - } else if (idValue.isDouble()) { - mediaId = QString::number(static_cast<qint64>(idValue.toDouble())); - } - } - - if (!postStatusInternal(mediaId)) { - qWarning() << Q_FUNC_INFO << "unable to create mastodon status"; - emit transferError(); - } - return; - } - - if (apiCall == POST_STATUS) { - finishTransfer(error, httpCode, data); - return; - } - - emit transferError(); -} - -void MastodonApi::finishTransfer(QNetworkReply::NetworkError error, int httpCode, const QByteArray &data) -{ - m_cancelRequested = false; - - if (httpCode == 401) { - emit credentialsExpired(); - } - - if (error != QNetworkReply::NoError) { - if (error == QNetworkReply::OperationCanceledError) { - emit transferCanceled(); - return; - } - - qWarning() << Q_FUNC_INFO << "network error:" << error << "httpCode:" << httpCode << "data:" << data; - emit transferError(); - return; - } - - if (httpCode < 200 || httpCode >= 300) { - qWarning() << Q_FUNC_INFO << "http error:" << httpCode << "data:" << data; - emit transferError(); - return; - } - - emit transferFinished(); -} diff --git a/transferengine-plugins/mastodontransferplugin/mastodonapi.h b/transferengine-plugins/mastodontransferplugin/mastodonapi.h deleted file mode 100644 index df4c87a..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodonapi.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MASTODONAPI_H -#define MASTODONAPI_H - -#include <QtCore/QMap> -#include <QtCore/QObject> - -#include <QtNetwork/QNetworkAccessManager> -#include <QtNetwork/QNetworkReply> - -class MastodonApi : public QObject -{ - Q_OBJECT - -public: - enum API_CALL { - NONE, - UPLOAD_MEDIA, - POST_STATUS - }; - - explicit MastodonApi(QNetworkAccessManager *qnam, QObject *parent = 0); - ~MastodonApi(); - - bool uploadImage(const QString &filePath, - const QString &statusText, - const QString &mimeType, - const QString &apiHost, - const QString &accessToken); - bool postStatus(const QString &statusText, - const QString &apiHost, - const QString &accessToken); - - void cancelUpload(); - -Q_SIGNALS: - void transferProgressUpdated(qreal progress); - void transferFinished(); - void transferError(); - void transferCanceled(); - void credentialsExpired(); - -private Q_SLOTS: - void replyError(QNetworkReply::NetworkError error); - void finished(); - void uploadProgress(qint64 received, qint64 total); - -private: - bool postStatusInternal(const QString &mediaId); - void finishTransfer(QNetworkReply::NetworkError error, int httpCode, const QByteArray &data); - - QMap<QNetworkReply*, API_CALL> m_replies; - bool m_cancelRequested; - QNetworkAccessManager *m_qnam; - QString m_accessToken; - QString m_apiHost; - QString m_statusText; -}; - -#endif // MASTODONAPI_H diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp b/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp deleted file mode 100644 index a843df2..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "mastodontransferplugin.h" -#include "mastodonuploader.h" - -#include <QtPlugin> -#include <QNetworkAccessManager> - -MastodonTransferPlugin::MastodonTransferPlugin() - : QObject(), TransferPluginInterface() - , m_qnam(new QNetworkAccessManager(this)) -{ -} - -MastodonTransferPlugin::~MastodonTransferPlugin() -{ -} - -MediaTransferInterface *MastodonTransferPlugin::transferObject() -{ - return new MastodonUploader(m_qnam, this); -} - -QString MastodonTransferPlugin::pluginId() const -{ - return QLatin1String("Mastodon"); -} diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h b/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h deleted file mode 100644 index 4d3baaf..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MASTODONTRANSFERPLUGIN_H -#define MASTODONTRANSFERPLUGIN_H - -#include <QtCore/QObject> - -#include <transferplugininterface.h> - -class QNetworkAccessManager; - -class Q_DECL_EXPORT MastodonTransferPlugin : public QObject, public TransferPluginInterface -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID "org.sailfishos.transfer.plugin.mastodon") - Q_INTERFACES(TransferPluginInterface) - -public: - MastodonTransferPlugin(); - ~MastodonTransferPlugin(); - - MediaTransferInterface *transferObject(); - QString pluginId() const; - -private: - QNetworkAccessManager *m_qnam; -}; - -#endif // MASTODONTRANSFERPLUGIN_H diff --git a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro b/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro deleted file mode 100644 index 422a889..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodontransferplugin.pro +++ /dev/null @@ -1,29 +0,0 @@ -# SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. -# -# SPDX-License-Identifier: BSD-3-Clause - -TEMPLATE = lib -TARGET = $$qtLibraryTarget(mastodontransferplugin) -CONFIG += plugin -DEPENDPATH += . -INCLUDEPATH += .. -INCLUDEPATH += ../../common - -QT += network - -CONFIG += link_pkgconfig -PKGCONFIG += nemotransferengine-qt5 accounts-qt5 sailfishaccounts libsignon-qt5 - -HEADERS += mastodontransferplugin.h \ - mastodonuploader.h \ - ../mastodonshareservicestatus.h \ - mastodonapi.h - -SOURCES += mastodontransferplugin.cpp \ - mastodonuploader.cpp \ - ../mastodonshareservicestatus.cpp \ - mastodonapi.cpp - -target.path = $$[QT_INSTALL_LIBS]/nemo-transferengine/plugins/transfer - -INSTALLS += target diff --git a/transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp b/transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp deleted file mode 100644 index 7b87823..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodonuploader.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#include "mastodonuploader.h" -#include "mastodonapi.h" - -#include <imageoperation.h> -#include <mediaitem.h> - -#include <QtCore/QFile> -#include <QtCore/QMimeDatabase> -#include <QtCore/QMimeType> - -#include <QtDebug> - -MastodonUploader::MastodonUploader(QNetworkAccessManager *qnam, QObject *parent) - : MediaTransferInterface(parent) - , m_api(0) - , m_mastodonShareServiceStatus(0) - , m_qnam(qnam) - , m_useTmpFile(false) -{ -} - -MastodonUploader::~MastodonUploader() -{ -} - -QString MastodonUploader::displayName() const -{ - return tr("Mastodon"); -} - -QUrl MastodonUploader::serviceIcon() const -{ - return QUrl(QStringLiteral("image://theme/icon-l-mastodon")); -} - -bool MastodonUploader::cancelEnabled() const -{ - return true; -} - -bool MastodonUploader::restartEnabled() const -{ - return true; -} - -void MastodonUploader::start() -{ - if (!mediaItem()) { - qWarning() << Q_FUNC_INFO << "NULL MediaItem. Can't continue"; - setStatus(MediaTransferInterface::TransferInterrupted); - return; - } - - if (!m_mastodonShareServiceStatus) { - m_mastodonShareServiceStatus = new MastodonShareServiceStatus(this); - connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceReady, - this, &MastodonUploader::startUploading); - connect(m_mastodonShareServiceStatus, &MastodonShareServiceStatus::serviceError, - this, [this] (const QString &) { - transferError(); - }); - } - - m_mastodonShareServiceStatus->queryStatus(); -} - -void MastodonUploader::cancel() -{ - if (m_api) { - m_api->cancelUpload(); - } else { - qWarning() << Q_FUNC_INFO << "Can't cancel. NULL MastodonApi object!"; - } -} - -void MastodonUploader::startUploading() -{ - if (!m_mastodonShareServiceStatus) { - qWarning() << Q_FUNC_INFO << "NULL MastodonShareServiceStatus object!"; - return; - } - - const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt(); - m_accountDetails = m_mastodonShareServiceStatus->detailsByIdentifier(accountId); - if (m_accountDetails.accountId <= 0 || m_accountDetails.accessToken.isEmpty()) { - qWarning() << Q_FUNC_INFO << "Mastodon account details missing for id" << accountId; - transferError(); - return; - } - - const QString mimeType = mediaItem()->value(MediaItem::MimeType).toString(); - if (mimeType.startsWith(QLatin1String("image/")) - || mimeType.startsWith(QLatin1String("video/"))) { - postImage(); - } else if (mimeType.contains(QLatin1String("text/plain")) - || mimeType.contains(QLatin1String("text/x-url"))) { - postStatus(); - } else { - qWarning() << Q_FUNC_INFO << "Unsupported mime type:" << mimeType; - setStatus(MediaTransferInterface::TransferInterrupted); - } -} - -void MastodonUploader::transferFinished() -{ - setStatus(MediaTransferInterface::TransferFinished); -} - -void MastodonUploader::transferProgress(qreal progress) -{ - setProgress(progress); -} - -void MastodonUploader::transferError() -{ - setStatus(MediaTransferInterface::TransferInterrupted); - qWarning() << Q_FUNC_INFO << "Transfer interrupted"; -} - -void MastodonUploader::transferCanceled() -{ - setStatus(MediaTransferInterface::TransferCanceled); -} - -void MastodonUploader::credentialsExpired() -{ - const quint32 accountId = mediaItem()->value(MediaItem::AccountId).toInt(); - m_mastodonShareServiceStatus->setCredentialsNeedUpdate(accountId, QStringLiteral("mastodon-sharing")); -} - -void MastodonUploader::setStatus(MediaTransferInterface::TransferStatus status) -{ - const bool finished = (status == TransferCanceled - || status == TransferInterrupted - || status == TransferFinished); - if (m_useTmpFile && finished) { - QFile::remove(m_filePath); - m_useTmpFile = false; - m_filePath.clear(); - } - - MediaTransferInterface::setStatus(status); -} - -void MastodonUploader::postImage() -{ - m_useTmpFile = false; - m_filePath.clear(); - const QString sourceFile = mediaItem()->value(MediaItem::Url).toUrl().toLocalFile(); - if (sourceFile.isEmpty()) { - qWarning() << Q_FUNC_INFO << "Empty source file"; - setStatus(MediaTransferInterface::TransferInterrupted); - return; - } - - QMimeDatabase db; - const QMimeType mime = db.mimeTypeForFile(sourceFile); - const bool isImage = mediaItem()->value(MediaItem::MimeType).toString().startsWith(QLatin1String("image/")); - const bool isJpeg = isImage && mime.name() == QLatin1String("image/jpeg"); - - if (isJpeg && mediaItem()->value(MediaItem::MetadataStripped).toBool()) { - m_useTmpFile = true; - m_filePath = ImageOperation::removeImageMetadata(sourceFile); - if (m_filePath.isEmpty()) { - qWarning() << Q_FUNC_INFO << "Failed to remove metadata"; - MediaTransferInterface::setStatus(MediaTransferInterface::TransferInterrupted); - return; - } - } - - const qreal scale = mediaItem()->value(MediaItem::ScalePercent).toReal(); - if (isImage && 0 < scale && scale < 1) { - m_useTmpFile = true; - m_filePath = ImageOperation::scaleImage(sourceFile, scale, m_filePath); - if (m_filePath.isEmpty()) { - qWarning() << Q_FUNC_INFO << "Failed to scale image"; - MediaTransferInterface::setStatus(MediaTransferInterface::TransferInterrupted); - return; - } - } - - if (!m_useTmpFile) { - m_filePath = sourceFile; - } - - ensureApi(); - - const bool ok = m_api->uploadImage(m_filePath, - mediaItem()->value(MediaItem::Description).toString(), - mediaItem()->value(MediaItem::MimeType).toString(), - m_accountDetails.apiHost, - m_accountDetails.accessToken); - if (ok) { - setStatus(MediaTransferInterface::TransferStarted); - } else { - setStatus(MediaTransferInterface::TransferInterrupted); - qWarning() << Q_FUNC_INFO << "Failed to upload media"; - } -} - -void MastodonUploader::postStatus() -{ - ensureApi(); - - const QVariantMap userData = mediaItem()->value(MediaItem::UserData).toMap(); - QString statusText = userData.value(QStringLiteral("status")).toString().trimmed(); - if (statusText.isEmpty()) { - statusText = mediaItem()->value(MediaItem::Description).toString().trimmed(); - } - if (statusText.isEmpty()) { - statusText = mediaItem()->value(MediaItem::ContentData).toString().trimmed(); - } - - if (statusText.isEmpty()) { - qWarning() << Q_FUNC_INFO << "Failed to resolve status text"; - setStatus(MediaTransferInterface::TransferInterrupted); - return; - } - - const bool ok = m_api->postStatus(statusText, - m_accountDetails.apiHost, - m_accountDetails.accessToken); - if (ok) { - setStatus(MediaTransferInterface::TransferStarted); - } else { - setStatus(MediaTransferInterface::TransferInterrupted); - qWarning() << Q_FUNC_INFO << "Failed to post status"; - } -} - -void MastodonUploader::ensureApi() -{ - if (!m_api) { - m_api = new MastodonApi(m_qnam, this); - connect(m_api, &MastodonApi::transferProgressUpdated, - this, &MastodonUploader::transferProgress); - connect(m_api, &MastodonApi::transferFinished, - this, &MastodonUploader::transferFinished); - connect(m_api, &MastodonApi::transferError, - this, &MastodonUploader::transferError); - connect(m_api, &MastodonApi::transferCanceled, - this, &MastodonUploader::transferCanceled); - connect(m_api, &MastodonApi::credentialsExpired, - this, &MastodonUploader::credentialsExpired); - } -} diff --git a/transferengine-plugins/mastodontransferplugin/mastodonuploader.h b/transferengine-plugins/mastodontransferplugin/mastodonuploader.h deleted file mode 100644 index 72d9689..0000000 --- a/transferengine-plugins/mastodontransferplugin/mastodonuploader.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2013 - 2026 Jolla Ltd. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -#ifndef MASTODONUPLOADER_H -#define MASTODONUPLOADER_H - -#include <QtNetwork/QNetworkAccessManager> - -#include <mediatransferinterface.h> - -#include "mastodonshareservicestatus.h" - -class MastodonApi; - -class MastodonUploader : public MediaTransferInterface -{ - Q_OBJECT - -public: - MastodonUploader(QNetworkAccessManager *qnam, QObject *parent = 0); - ~MastodonUploader(); - - QString displayName() const; - QUrl serviceIcon() const; - bool cancelEnabled() const; - bool restartEnabled() const; - -public Q_SLOTS: - void start(); - void cancel(); - -private Q_SLOTS: - void startUploading(); - void transferFinished(); - void transferProgress(qreal progress); - void transferError(); - void transferCanceled(); - void credentialsExpired(); - -protected: - void setStatus(MediaTransferInterface::TransferStatus status); - -private: - void ensureApi(); - void postImage(); - void postStatus(); - - MastodonApi *m_api; - MastodonShareServiceStatus *m_mastodonShareServiceStatus; - QNetworkAccessManager *m_qnam; - MastodonShareServiceStatus::AccountDetails m_accountDetails; - bool m_useTmpFile; - QString m_filePath; -}; - -#endif // MASTODONUPLOADER_H |
