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 | |
23 | Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, imageImgurUrl, (QLatin1String("https://api.imgur.com/3/image" ))) |
24 | Q_GLOBAL_STATIC_WITH_ARGS(const QUrl, albumImgurUrl, (QLatin1String("https://api.imgur.com/3/album" ))) |
25 | |
26 | // key associated with aleixpol@kde.org |
27 | Q_GLOBAL_STATIC_WITH_ARGS(const QString, YOUR_CLIENT_ID, (QLatin1String("0bffa5b4ac8383c" ))) |
28 | |
29 | class ImgurShareJob : public Purpose::Job |
30 | { |
31 | Q_OBJECT |
32 | public: |
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(key: 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) { |
50 | KIO::TransferJob *tJob = KIO::storedHttpPost(arr: "" , url: *albumImgurUrl, flags: KIO::HideProgressInfo); |
51 | tJob->setMetaData(QMap<QString, QString>{{QStringLiteral("customHTTPHeader" ), QStringLiteral("Authorization: Client-ID " ) + *YOUR_CLIENT_ID}}); |
52 | connect(sender: tJob, signal: &KJob::result, context: this, slot: &ImgurShareJob::albumCreated); |
53 | } else { |
54 | startUploading(); |
55 | } |
56 | } |
57 | |
58 | QJsonObject processResponse(KJob *job) |
59 | { |
60 | KIO::StoredTransferJob *sjob = qobject_cast<KIO::StoredTransferJob *>(object: job); |
61 | QJsonParseError error; |
62 | const QJsonObject resultMap = QJsonDocument::fromJson(json: sjob->data(), error: &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(key: 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(job: this, i18n("Uploading files to imgur..." )); |
96 | const QJsonArray urls = data().value(key: QLatin1String("urls" )).toArray(); |
97 | for (const QJsonValue &val : urls) { |
98 | QString u = val.toString(); |
99 | KIO::StoredTransferJob *job = KIO::storedGet(url: QUrl(u)); |
100 | connect(sender: job, signal: &KJob::finished, context: this, slot: &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 *>(object: j); |
119 | form.addFile(QStringLiteral("image" ), filePath: job->url(), fileData: job->data()); |
120 | form.addPair(QStringLiteral("album" ), value: m_albumDeleteHash, type: {}); |
121 | form.finish(); |
122 | |
123 | KIO::StoredTransferJob *tJob = KIO::storedHttpPost(arr: form.formData(), url: *imageImgurUrl, flags: KIO::HideProgressInfo); |
124 | tJob->setMetaData(QMap<QString, QString>{ |
125 | {QStringLiteral("content-type" ), QString::fromLocal8Bit(ba: form.contentType())}, |
126 | {QStringLiteral("customHTTPHeader" ), QStringLiteral("Authorization: Client-ID " ) + *YOUR_CLIENT_ID}, |
127 | }); |
128 | connect(sender: tJob, signal: &KJob::result, context: this, slot: &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(job: this, message: url); |
137 | const QString deletehash = dataMap[QStringLiteral("deletehash" )].toString(); |
138 | Q_EMIT infoMessage(job: this, message: 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 | |
145 | QGuiApplication::clipboard()->setText(url); |
146 | KNotification::event(eventId: 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), |
152 | flags: KNotification::Persistent); |
153 | |
154 | emitResult(); |
155 | } |
156 | } |
157 | } |
158 | |
159 | private: |
160 | QString m_albumId; |
161 | QString m_albumDeleteHash; |
162 | int m_pendingJobs; |
163 | }; |
164 | |
165 | class ImgurPlugin : public Purpose::PluginBase |
166 | { |
167 | Q_OBJECT |
168 | public: |
169 | using PluginBase::PluginBase; |
170 | Purpose::Job *createJob() const override |
171 | { |
172 | return new ImgurShareJob(nullptr); |
173 | } |
174 | }; |
175 | |
176 | K_PLUGIN_CLASS_WITH_JSON(ImgurPlugin, "imgurplugin.json" ) |
177 | |
178 | #include "imgurplugin.moc" |
179 | |