Purpose

imgurplugin.cpp
1/*
2 SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "mpform.h"
8#include <KIO/StoredTransferJob>
9#include <KIO/TransferJob>
10#include <KJob>
11#include <KLocalizedString>
12#include <KNotification>
13#include <KPluginFactory>
14#include <QClipboard>
15#include <QDebug>
16#include <QGuiApplication>
17#include <QJsonArray>
18#include <QJsonDocument>
19#include <QJsonObject>
20#include <QStandardPaths>
21#include <purpose/pluginbase.h>
22
23Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, imageImgurUrl, (QLatin1String("https://api.imgur.com/3/image")))
24Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, albumImgurUrl, (QLatin1String("https://api.imgur.com/3/album")))
25
26// key associated with aleixpol@kde.org
27Q_GLOBAL_STATIC_WITH_ARGS(const QString, YOUR_CLIENT_ID, (QLatin1String("0bffa5b4ac8383c")))
28
29class ImgurShareJob : public Purpose::Job
30{
31 Q_OBJECT
32public:
33 explicit ImgurShareJob(QObject *parent)
34 : Purpose::Job(parent)
35 , m_pendingJobs(0)
36 {
37 }
38
39 void start() override
40 {
41 m_pendingJobs = 0;
42 const QJsonArray urls = data().value(QLatin1String("urls")).toArray();
43 if (urls.isEmpty()) {
44 qWarning() << "no urls to share" << urls << data();
45 emitResult();
46 return;
47 }
48
49 if (urls.count() > 1) {
51 tJob->setMetaData(QMap<QString, QString>{{QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: Client-ID ") + *YOUR_CLIENT_ID}});
52 connect(tJob, &KJob::result, this, &ImgurShareJob::albumCreated);
53 } else {
54 startUploading();
55 }
56 }
57
58 QJsonObject processResponse(KJob *job)
59 {
60 KIO::StoredTransferJob *sjob = qobject_cast<KIO::StoredTransferJob *>(job);
62 const QJsonObject resultMap = QJsonDocument::fromJson(sjob->data(), &error).object();
63 if (sjob->isErrorPage()) {
64 setError(3);
65 setErrorText(i18n("Error page returned"));
66 } else if (job->error()) {
67 setError(job->error());
68 setErrorText(job->errorText());
69 } else if (error.error) {
70 setError(1);
71 setErrorText(error.errorString());
72 } else if (!resultMap.value(QLatin1String("success")).toBool()) {
73 setError(2);
74 const QJsonObject dataMap = resultMap[QLatin1String("data")].toObject();
75 setErrorText(dataMap[QLatin1String("error")].toString());
76 } else {
77 return resultMap[QLatin1String("data")].toObject();
78 }
79 emitResult();
80 return {};
81 }
82
83 void albumCreated(KJob *job)
84 {
85 const QJsonObject dataMap = processResponse(job);
86 if (!dataMap.isEmpty()) {
87 m_albumId = dataMap[QLatin1String("id")].toString();
88 m_albumDeleteHash = dataMap[QLatin1String("deletehash")].toString();
89 startUploading();
90 }
91 }
92
93 void startUploading()
94 {
95 Q_EMIT infoMessage(this, i18n("Uploading files to imgur..."));
96 const QJsonArray urls = data().value(QLatin1String("urls")).toArray();
97 for (const QJsonValue &val : urls) {
98 QString u = val.toString();
100 connect(job, &KJob::finished, this, &ImgurShareJob::fileFetched);
101 m_pendingJobs++;
102 }
103 }
104
105 void fileFetched(KJob *j)
106 {
107 if (j->error()) {
108 setError(j->error());
109 setErrorText(j->errorText());
110 emitResult();
111
112 qDebug() << "error:" << j->errorText() << j->errorString();
113
114 return;
115 }
116
117 MPForm form;
118 KIO::StoredTransferJob *job = qobject_cast<KIO::StoredTransferJob *>(j);
119 form.addFile(QStringLiteral("image"), job->url(), job->data());
120 form.addPair(QStringLiteral("album"), m_albumDeleteHash, {});
121 form.finish();
122
123 KIO::StoredTransferJob *tJob = KIO::storedHttpPost(form.formData(), *imageImgurUrl, KIO::HideProgressInfo);
125 {QStringLiteral("content-type"), QString::fromLocal8Bit(form.contentType())},
126 {QStringLiteral("customHTTPHeader"), QStringLiteral("Authorization: Client-ID ") + *YOUR_CLIENT_ID},
127 });
128 connect(tJob, &KJob::result, this, &ImgurShareJob::imageUploaded);
129 }
130
131 void imageUploaded(KJob *job)
132 {
133 const QJsonObject dataMap = processResponse(job);
134 if (!dataMap.isEmpty()) {
135 const QString url = dataMap[QStringLiteral("link")].toString();
136 Q_EMIT infoMessage(this, url);
137 const QString deletehash = dataMap[QStringLiteral("deletehash")].toString();
138 Q_EMIT infoMessage(this, deletehash);
139 --m_pendingJobs;
140
141 if (m_pendingJobs == 0) {
142 const QString finalUrl = m_albumId.isEmpty() ? url : QStringLiteral("https://imgur.com/a/") + m_albumId;
143 const QString deleteUrl = QStringLiteral("https://imgur.com/delete/") + deletehash;
144
146 KNotification::event(KNotification::Notification,
147 i18n("Imgur Upload"),
148 i18n("The shared image link (<a href=\"%1\">%1</a>) has been copied to the clipboard.<br><br>If you would like to remove "
149 "the uploaded image, visit <a href=\"%2\">%2</a>",
150 finalUrl,
151 deleteUrl),
153
154 emitResult();
155 }
156 }
157 }
158
159private:
160 QString m_albumId;
161 QString m_albumDeleteHash;
162 int m_pendingJobs;
163};
164
165class ImgurPlugin : public Purpose::PluginBase
166{
168public:
169 using PluginBase::PluginBase;
170 Purpose::Job *createJob() const override
171 {
172 return new ImgurShareJob(nullptr);
173 }
174};
175
176K_PLUGIN_CLASS_WITH_JSON(ImgurPlugin, "imgurplugin.json")
177
178#include "imgurplugin.moc"
void setMetaData(const KIO::MetaData &metaData)
const QUrl & url() const
QByteArray data() const
bool isErrorPage() const
virtual QString errorString() const
int error() const
void result(KJob *job)
void finished(KJob *job)
QString errorText() const
static KNotification * event(const QString &eventId, const QString &text=QString(), const QPixmap &pixmap=QPixmap(), const NotificationFlags &flags=CloseOnTimeout, const QString &componentName=QString())
#define K_PLUGIN_CLASS_WITH_JSON(classname, jsonFile)
Job that will actually perform the sharing.
Definition job.h:34
Base class to implement by plugins.
Definition pluginbase.h:29
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
KIOCORE_EXPORT StoredTransferJob * storedHttpPost(const QByteArray &arr, const QUrl &url, JobFlags flags=DefaultFlags)
HideProgressInfo
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
void setText(const QString &text, Mode mode)
QClipboard * clipboard()
qsizetype count() const const
bool isEmpty() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QJsonObject object() const const
bool isEmpty() const const
QJsonValue value(QLatin1StringView key) const const
Q_OBJECTQ_OBJECT
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.