File indexing completed on 2024-05-19 04:03:03

0001 /*
0002     SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "mpform.h"
0008 #include <KIO/StoredTransferJob>
0009 #include <KIO/TransferJob>
0010 #include <KJob>
0011 #include <KLocalizedString>
0012 #include <KNotification>
0013 #include <KPluginFactory>
0014 #include <QClipboard>
0015 #include <QDebug>
0016 #include <QGuiApplication>
0017 #include <QJsonArray>
0018 #include <QJsonDocument>
0019 #include <QJsonObject>
0020 #include <QStandardPaths>
0021 #include <purpose/pluginbase.h>
0022 
0023 Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, imageImgurUrl, (QLatin1String("https://api.imgur.com/3/image")))
0024 Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, albumImgurUrl, (QLatin1String("https://api.imgur.com/3/album")))
0025 
0026 // key associated with aleixpol@kde.org
0027 Q_GLOBAL_STATIC_WITH_ARGS(const QString, YOUR_CLIENT_ID, (QLatin1String("0bffa5b4ac8383c")))
0028 
0029 class ImgurShareJob : public Purpose::Job
0030 {
0031     Q_OBJECT
0032 public:
0033     explicit ImgurShareJob(QObject *parent)
0034         : Purpose::Job(parent)
0035         , m_pendingJobs(0)
0036     {
0037     }
0038 
0039     void start() override
0040     {
0041         m_pendingJobs = 0;
0042         const QJsonArray urls = data().value(QLatin1String("urls")).toArray();
0043         if (urls.isEmpty()) {
0044             qWarning() << "no urls to share" << urls << data();
0045             emitResult();
0046             return;
0047         }
0048 
0049         if (urls.count() > 1) {
0050             KIO::TransferJob *tJob = KIO::storedHttpPost("", *albumImgurUrl, KIO::HideProgressInfo);
0051             tJob->setMetaData(QMap<QString, QString>{{QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: Client-ID ") + *YOUR_CLIENT_ID}});
0052             connect(tJob, &KJob::result, this, &ImgurShareJob::albumCreated);
0053         } else {
0054             startUploading();
0055         }
0056     }
0057 
0058     QJsonObject processResponse(KJob *job)
0059     {
0060         KIO::StoredTransferJob *sjob = qobject_cast<KIO::StoredTransferJob *>(job);
0061         QJsonParseError error;
0062         const QJsonObject resultMap = QJsonDocument::fromJson(sjob->data(), &error).object();
0063         if (sjob->isErrorPage()) {
0064             setError(3);
0065             setErrorText(i18n("Error page returned"));
0066         } else if (job->error()) {
0067             setError(job->error());
0068             setErrorText(job->errorText());
0069         } else if (error.error) {
0070             setError(1);
0071             setErrorText(error.errorString());
0072         } else if (!resultMap.value(QLatin1String("success")).toBool()) {
0073             setError(2);
0074             const QJsonObject dataMap = resultMap[QLatin1String("data")].toObject();
0075             setErrorText(dataMap[QLatin1String("error")].toString());
0076         } else {
0077             return resultMap[QLatin1String("data")].toObject();
0078         }
0079         emitResult();
0080         return {};
0081     }
0082 
0083     void albumCreated(KJob *job)
0084     {
0085         const QJsonObject dataMap = processResponse(job);
0086         if (!dataMap.isEmpty()) {
0087             m_albumId = dataMap[QLatin1String("id")].toString();
0088             m_albumDeleteHash = dataMap[QLatin1String("deletehash")].toString();
0089             startUploading();
0090         }
0091     }
0092 
0093     void startUploading()
0094     {
0095         Q_EMIT infoMessage(this, i18n("Uploading files to imgur..."));
0096         const QJsonArray urls = data().value(QLatin1String("urls")).toArray();
0097         for (const QJsonValue &val : urls) {
0098             QString u = val.toString();
0099             KIO::StoredTransferJob *job = KIO::storedGet(QUrl(u));
0100             connect(job, &KJob::finished, this, &ImgurShareJob::fileFetched);
0101             m_pendingJobs++;
0102         }
0103     }
0104 
0105     void fileFetched(KJob *j)
0106     {
0107         if (j->error()) {
0108             setError(j->error());
0109             setErrorText(j->errorText());
0110             emitResult();
0111 
0112             qDebug() << "error:" << j->errorText() << j->errorString();
0113 
0114             return;
0115         }
0116 
0117         MPForm form;
0118         KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob *>(j);
0119         form.addFile(QStringLiteral("image"), job->url(), job->data());
0120         form.addPair(QStringLiteral("album"), m_albumDeleteHash, {});
0121         form.finish();
0122 
0123         KIO::StoredTransferJob *tJob = KIO::storedHttpPost(form.formData(), *imageImgurUrl, KIO::HideProgressInfo);
0124         tJob->setMetaData(QMap<QString, QString>{
0125             {QStringLiteral("content-type"), QString::fromLocal8Bit(form.contentType())},
0126             {QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: Client-ID ") + *YOUR_CLIENT_ID},
0127         });
0128         connect(tJob, &KJob::result, this, &ImgurShareJob::imageUploaded);
0129     }
0130 
0131     void imageUploaded(KJob *job)
0132     {
0133         const QJsonObject dataMap = processResponse(job);
0134         if (!dataMap.isEmpty()) {
0135             const QString url = dataMap[QStringLiteral("link")].toString();
0136             Q_EMIT infoMessage(this, url);
0137             const QString deletehash = dataMap[QStringLiteral("deletehash")].toString();
0138             Q_EMIT infoMessage(this, deletehash);
0139             --m_pendingJobs;
0140 
0141             if (m_pendingJobs == 0) {
0142                 const QString finalUrl = m_albumId.isEmpty() ? url : QStringLiteral("https://imgur.com/a/") + m_albumId;
0143                 const QString deleteUrl = QStringLiteral("https://imgur.com/delete/") + deletehash;
0144 
0145                 QGuiApplication::clipboard()->setText(url);
0146                 KNotification::event(KNotification::Notification,
0147                                      i18n("Imgur Upload"),
0148                                      i18n("The shared image link (<a href=\"%1\">%1</a>) has been copied to the clipboard.<br><br>If you would like to remove "
0149                                           "the uploaded image, visit <a href=\"%2\">%2</a>",
0150                                           finalUrl,
0151                                           deleteUrl),
0152                                      KNotification::Persistent);
0153 
0154                 emitResult();
0155             }
0156         }
0157     }
0158 
0159 private:
0160     QString m_albumId;
0161     QString m_albumDeleteHash;
0162     int m_pendingJobs;
0163 };
0164 
0165 class ImgurPlugin : public Purpose::PluginBase
0166 {
0167     Q_OBJECT
0168 public:
0169     using PluginBase::PluginBase;
0170     Purpose::Job *createJob() const override
0171     {
0172         return new ImgurShareJob(nullptr);
0173     }
0174 };
0175 
0176 K_PLUGIN_CLASS_WITH_JSON(ImgurPlugin, "imgurplugin.json")
0177 
0178 #include "imgurplugin.moc"