From 6ab5452fb6aaf446e47be4518bab8dd8ff3c293d Mon Sep 17 00:00:00 2001 From: ArsenArsen Date: Fri, 30 Jun 2017 15:05:37 +0200 Subject: [PATCH] Add imgur auth. upload and uploader settings --- KShare.pro | 9 +- recording/recordingformats.cpp | 4 +- settingsdialog.cpp | 31 +++-- settingsdialog.hpp | 6 +- uploaders/default/imgursettingsdialog.cpp | 73 +++++++++++ uploaders/default/imgursettingsdialog.hpp | 26 ++++ uploaders/default/imgursettingsdialog.ui | 150 ++++++++++++++++++++++ uploaders/default/imguruploader.cpp | 66 +++++++++- uploaders/default/imguruploader.hpp | 12 +- uploaders/uploader.hpp | 5 + uploaders/uploadersingleton.cpp | 21 ++- uploaders/uploadersingleton.hpp | 3 + 12 files changed, 376 insertions(+), 30 deletions(-) create mode 100644 uploaders/default/imgursettingsdialog.cpp create mode 100644 uploaders/default/imgursettingsdialog.hpp create mode 100644 uploaders/default/imgursettingsdialog.ui diff --git a/KShare.pro b/KShare.pro index 11295da..fbfb2c6 100644 --- a/KShare.pro +++ b/KShare.pro @@ -63,7 +63,8 @@ SOURCES += main.cpp\ cropeditor/drawing/rectitem.cpp \ cropeditor/drawing/ellipseitem.cpp \ hotkeyinputdialog.cpp \ - cropeditor/drawing/arrowitem.cpp + cropeditor/drawing/arrowitem.cpp \ + uploaders/default/imgursettingsdialog.cpp HEADERS += mainwindow.hpp \ cropeditor/cropeditor.hpp \ @@ -105,7 +106,8 @@ HEADERS += mainwindow.hpp \ cropeditor/drawing/rectitem.hpp \ cropeditor/drawing/ellipseitem.hpp \ hotkeyinputdialog.hpp \ - cropeditor/drawing/arrowitem.hpp + cropeditor/drawing/arrowitem.hpp \ + uploaders/default/imgursettingsdialog.hpp LIBS += -lavcodec -lavformat -lavutil -lswscale -lavutil @@ -133,7 +135,8 @@ FORMS += mainwindow.ui \ recording/encoders/encodersettingsdialog.ui \ settingsdialog.ui \ aboutbox.ui \ - hotkeyinputdialog.ui + hotkeyinputdialog.ui \ + uploaders/default/imgursettingsdialog.ui DISTFILES += \ README.md \ diff --git a/recording/recordingformats.cpp b/recording/recordingformats.cpp index b1e24c3..20f333d 100644 --- a/recording/recordingformats.cpp +++ b/recording/recordingformats.cpp @@ -53,7 +53,7 @@ RecordingFormats::RecordingFormats(formats::Recording f) { delete enc; return false; } - } catch (std::runtime_error e) { + } catch (std::runtime_error &e) { // notifications::notify("KShare Video Encoder Error", e.what(), // QSystemTrayIcon::Critical); qCritical() << "Encoder error: " << e.what(); @@ -68,7 +68,7 @@ RecordingFormats::RecordingFormats(formats::Recording f) { if (!interrupt) try { frameAdded = true; enc->addFrame(img); - } catch (std::runtime_error e) { + } catch (std::runtime_error &e) { // notifications::notify("KShare Video Encoder Error", e.what(), // QSystemTrayIcon::Critical); qCritical() << "Encoder error: " << e.what(); diff --git a/settingsdialog.cpp b/settingsdialog.cpp index a00ec11..617f286 100644 --- a/settingsdialog.cpp +++ b/settingsdialog.cpp @@ -35,12 +35,13 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se ui->uploaderList->setSelectionMode(QAbstractItemView::SingleSelection); // Add items to uploader selection + connect(&UploaderSingleton::inst(), &UploaderSingleton::newUploader, this, &SettingsDialog::newUploader); + connect(&UploaderSingleton::inst(), &UploaderSingleton::uploaderChanged, this, &SettingsDialog::uploaderChanged); for (Uploader *u : UploaderSingleton::inst().uploaderList()) newUploader(u); // Set filename scheme setScheme(settings::settings().value("fileFormat", "Screenshot %(yyyy-MM-dd HH:mm:ss)date.ext").toString()); - // Set delay if ((settings::settings().contains("delay"))) ui->delay->setValue(settings::settings().value("delay").toDouble()); @@ -93,11 +94,17 @@ void SettingsDialog::newUploader(Uploader *u) { if (UploaderSingleton::inst().currentUploader() == u->name()) ui->uploaderList->setCurrentItem(uploader); } +void SettingsDialog::uploaderChanged(QString newName) { + for (auto item : ui->uploaderList->findItems(newName, Qt::MatchCaseSensitive)) + ui->uploaderList->setCurrentItem(item); +} + void SettingsDialog::on_uploaderList_clicked(const QModelIndex &) { - QList index = ui->uploaderList->selectedItems(); - if (index.size() == 1) { - UploaderSingleton::inst().set(index.at(0)->text()); - } + UploaderSingleton::inst().set(ui->uploaderList->currentItem()->text()); +} + +void SettingsDialog::on_uploaderList_doubleClicked(const QModelIndex &) { + UploaderSingleton::inst().showSettings(); } void SettingsDialog::on_nameScheme_textChanged(const QString &arg1) { @@ -109,14 +116,12 @@ void SettingsDialog::on_delay_valueChanged(double arg1) { } void SettingsDialog::on_hotkeys_doubleClicked(const QModelIndex &) { - if (ui->hotkeys->selectedItems().length() == 1) { - QListWidgetItem *i = ui->hotkeys->selectedItems().at(0); - QString str = i->data(Qt::UserRole + 1).toString(); - HotkeyInputDialog *hotkey = new HotkeyInputDialog(str, hotkeying::sequence(str), this); - connect(hotkey, &HotkeyInputDialog::sequenceSelected, - [&](QKeySequence seq, QString name) { hotkeying::hotkey(name, seq, fncs.value(name)); }); - hotkey->show(); - } + QListWidgetItem *i = ui->hotkeys->currentItem(); + QString str = i->data(Qt::UserRole + 1).toString(); + HotkeyInputDialog *hotkey = new HotkeyInputDialog(str, hotkeying::sequence(str), this); + connect(hotkey, &HotkeyInputDialog::sequenceSelected, + [&](QKeySequence seq, QString name) { hotkeying::hotkey(name, seq, fncs.value(name)); }); + hotkey->show(); } void SettingsDialog::on_settingsButton_clicked() { diff --git a/settingsdialog.hpp b/settingsdialog.hpp index 3916b68..38ecbfe 100644 --- a/settingsdialog.hpp +++ b/settingsdialog.hpp @@ -16,12 +16,12 @@ public: explicit SettingsDialog(QWidget *parent = 0); ~SettingsDialog(); void setScheme(QString scheme); - void newUploader(Uploader *u); public slots: void on_uploaderList_clicked(const QModelIndex &); + void on_uploaderList_doubleClicked(const QModelIndex &); void on_delay_valueChanged(double arg1); - void on_hotkeys_doubleClicked(const QModelIndex &index); + void on_hotkeys_doubleClicked(const QModelIndex &i); void on_settingsButton_clicked(); void on_quickMode_clicked(bool checked); void on_hideToTray_clicked(bool checked); @@ -30,6 +30,8 @@ public slots: void on_imageFormatBox_currentIndexChanged(int index); void on_pushButton_clicked(); void on_nameScheme_textChanged(const QString &arg1); + void newUploader(Uploader *u); + void uploaderChanged(QString newName); private: Ui::SettingsDialog *ui; diff --git a/uploaders/default/imgursettingsdialog.cpp b/uploaders/default/imgursettingsdialog.cpp new file mode 100644 index 0000000..f69aba6 --- /dev/null +++ b/uploaders/default/imgursettingsdialog.cpp @@ -0,0 +1,73 @@ +#include "imgursettingsdialog.hpp" +#include "ui_imgursettingsdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ImgurSettingsDialog::ImgurSettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ImgurSettingsDialog) { + ui->setupUi(this); + connect(this, &ImgurSettingsDialog::accepted, this, &ImgurSettingsDialog::deleteLater); + ui->clientId->setText(settings::settings().value("imgur/cid").toString()); + ui->clientSecret->setText(settings::settings().value("imgur/csecret").toString()); +} + +ImgurSettingsDialog::~ImgurSettingsDialog() { + delete ui; +} + +void ImgurSettingsDialog::on_addApp_clicked() { + QDesktopServices::openUrl(QUrl("https://api.imgur.com/oauth2/addclient")); +} + +void ImgurSettingsDialog::on_getPin_clicked() { + QDesktopServices::openUrl( + QUrl(QString("https://api.imgur.com/oauth2/authorize?client_id=%1&response_type=pin").arg(ui->clientId->text()))); +} + +void ImgurSettingsDialog::on_authorize_clicked() { + if (ui->pin->text().isEmpty() || ui->clientId->text().isEmpty() || ui->clientSecret->text().isEmpty()) return; + ui->buttonBox->setEnabled(false); + QJsonObject object; + object.insert("client_id", ui->clientId->text()); + object.insert("client_secret", ui->clientSecret->text()); + object.insert("grant_type", "pin"); + object.insert("pin", ui->pin->text()); + settings::settings().setValue("imgur/cid", ui->clientId->text()); + settings::settings().setValue("imgur/csecret", ui->clientSecret->text()); + + ioutils::postJson(QUrl("https://api.imgur.com/oauth2/token"), + QList>({ QPair("Content-Type", "applicaton/json") }), + QJsonDocument::fromVariant(object.toVariantMap()).toJson(), + [&](QJsonDocument response, QByteArray, QNetworkReply *r) { + if (r->error() != QNetworkReply::NoError || !response.isObject()) { + ui->buttonBox->setEnabled(true); + return; + } + QJsonObject res = response.object(); + if (res.value("success").toBool()) { + ui->buttonBox->setEnabled(true); + return; + } + + settings::settings().setValue("imgur/expire", + QDateTime::currentDateTimeUtc().addSecs(res["expires_in"].toInt())); + settings::settings().setValue("imgur/refresh", res["refresh_token"].toString()); + settings::settings().setValue("imgur/access", res["refresh_token"].toString()); + ui->status->setText("It works!"); + ui->status->setStyleSheet("* { color: green; }"); + + ui->authorize->setEnabled(false); + ui->addApp->setEnabled(false); + ui->clientSecret->setEnabled(false); + ui->clientId->setEnabled(false); + + ui->buttonBox->setEnabled(true); + }); +} diff --git a/uploaders/default/imgursettingsdialog.hpp b/uploaders/default/imgursettingsdialog.hpp new file mode 100644 index 0000000..2d47c1b --- /dev/null +++ b/uploaders/default/imgursettingsdialog.hpp @@ -0,0 +1,26 @@ +#ifndef IMGURSETTINGSDIALOG_HPP +#define IMGURSETTINGSDIALOG_HPP + +#include + +namespace Ui { +class ImgurSettingsDialog; +} + +class ImgurSettingsDialog : public QDialog { + Q_OBJECT + +public: + explicit ImgurSettingsDialog(QWidget *parent = 0); + ~ImgurSettingsDialog(); + +private slots: + void on_addApp_clicked(); + void on_getPin_clicked(); + void on_authorize_clicked(); + +private: + Ui::ImgurSettingsDialog *ui; +}; + +#endif // IMGURSETTINGSDIALOG_HPP diff --git a/uploaders/default/imgursettingsdialog.ui b/uploaders/default/imgursettingsdialog.ui new file mode 100644 index 0000000..7b7dc54 --- /dev/null +++ b/uploaders/default/imgursettingsdialog.ui @@ -0,0 +1,150 @@ + + + ImgurSettingsDialog + + + + 0 + 0 + 287 + 367 + + + + Imgur auth + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + OAuth2 + + + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Create a new application:</p></body></html> + + + + + + + Open imgur + + + + + + + Insert Client ID and secret: + + + + + + + Client ID + + + + + + + Client Secret + + + + + + + Get the pin + + + + + + + Insert the pin below: + + + + + + + PIN + + + + + + + Authorize + + + + + + + * { color: red; } + + + Not working + + + + + + + + + + + + buttonBox + accepted() + ImgurSettingsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ImgurSettingsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/uploaders/default/imguruploader.cpp b/uploaders/default/imguruploader.cpp index c2bbe04..dc86fdb 100644 --- a/uploaders/default/imguruploader.cpp +++ b/uploaders/default/imguruploader.cpp @@ -1,12 +1,56 @@ #include "imguruploader.hpp" +#include "imgursettingsdialog.hpp" #include #include #include +#include #include #include #include +#include #include +#include + +struct SegfaultWorkaround { + SegfaultWorkaround(QByteArray a, ImgurUploader *u, QString m) : byteArray(), dis(u), mime(m) { + a.swap(byteArray); + QJsonObject object; + object.insert("client_id", settings::settings().value("imgur/cid").toString()); + object.insert("client_secret", settings::settings().value("imgur/csecret").toString()); + object.insert("grant_type", "refresh_token"); + object.insert("refresh_token", settings::settings().value("imgur/refresh").toString()); + + ioutils::postJson( + QUrl("https://api.imgur.com/oauth2/token"), + QList>({ QPair("Content-Type", "applicaton/json") }), + QJsonDocument::fromVariant(object.toVariantMap()).toJson(), [&](QJsonDocument response, QByteArray, QNetworkReply *r) { + qDebug() << response; + if (r->error() != QNetworkReply::NoError || !response.isObject()) { + dis->handleSend(QStringLiteral("Client-ID 8a98f183fc895da"), mime, byteArray); + return; + } + QJsonObject res = response.object(); + if (res.value("success").toBool()) { + dis->handleSend(QStringLiteral("Client-ID 8a98f183fc895da"), mime, byteArray); + return; + } + + QString token = res["access_token"].toString(); + settings::settings().setValue("imgur/expire", QDateTime::currentDateTimeUtc().addSecs(res["expires_in"].toInt())); + settings::settings().setValue("imgur/refresh", res["refresh_token"].toString()); + settings::settings().setValue("imgur/access", token); + + dis->handleSend(token.prepend("Bearer "), mime, byteArray); + QScopedPointer(this); + }); + } + +private: + QByteArray byteArray; + ImgurUploader *dis; + QString mime; +}; void ImgurUploader::doUpload(QByteArray byteArray, QString format) { if (byteArray.size() > 1e+7) { @@ -18,10 +62,26 @@ void ImgurUploader::doUpload(QByteArray byteArray, QString format) { mime = formats::normalFormatMIME(formats::normalFormatFromName(format)); else mime = formats::recordingFormatMIME(formats::recordingFormatFromName(format)); + if (settings::settings().contains("imgur/expire") // + && settings::settings().contains("imgur/refresh") // + && settings::settings().contains("imgur/access")) { + QDateTime loltheseguysIminacallwithareretarded = settings::settings().value("imgur/expire").toDateTime(); + if (loltheseguysIminacallwithareretarded.msecsTo(QDateTime::currentDateTimeUtc()) < 0) { + new SegfaultWorkaround(byteArray, this, mime); + } else + handleSend("Bearer " + settings::settings().value("imgur/access").toString(), mime, byteArray); + } else + handleSend(QStringLiteral("Client-ID 8a98f183fc895da"), mime, byteArray); +} + +void ImgurUploader::showSettings() { + (new ImgurSettingsDialog())->show(); +} + +void ImgurUploader::handleSend(QString auth, QString mime, QByteArray byteArray) { ioutils::postJson(QUrl("https://api.imgur.com/3/image"), - QList>() - << QPair("Content-Type", mime.toLatin1()) - << QPair("Authorization", "Client-ID 8a98f183fc895da"), + QList>() << QPair("Content-Type", mime.toUtf8()) + << QPair("Authorization", auth), byteArray, [](QJsonDocument res, QByteArray, QNetworkReply *) { QString result = res.object()["data"].toObject()["link"].toString(); if (!result.isEmpty()) { diff --git a/uploaders/default/imguruploader.hpp b/uploaders/default/imguruploader.hpp index 9ce9e99..5419f31 100644 --- a/uploaders/default/imguruploader.hpp +++ b/uploaders/default/imguruploader.hpp @@ -4,14 +4,20 @@ #include "../uploader.hpp" class ImgurUploader : public Uploader { + friend struct SegfaultWorkaround; + public: - QString name() { + QString name() override { return "imgur"; } - QString description() { + QString description() override { return "imgur.com uploader"; } - void doUpload(QByteArray byteArray, QString); + void doUpload(QByteArray byteArray, QString) override; + void showSettings() override; + +private: + void handleSend(QString auth, QString mime, QByteArray byteArray); }; #endif // IMGURUPLOADER_HPP diff --git a/uploaders/uploader.hpp b/uploaders/uploader.hpp index 5bfaca3..357c852 100644 --- a/uploaders/uploader.hpp +++ b/uploaders/uploader.hpp @@ -9,6 +9,11 @@ public: virtual void doUpload(QByteArray imgData, QString format) = 0; virtual QString name() = 0; virtual QString description() = 0; + virtual void showSettings() { + } + virtual bool validate() { + return true; + } }; #endif // UPLOADER_HPP diff --git a/uploaders/uploadersingleton.cpp b/uploaders/uploadersingleton.cpp index dcc13e6..614ae2e 100644 --- a/uploaders/uploadersingleton.cpp +++ b/uploaders/uploadersingleton.cpp @@ -29,7 +29,7 @@ UploaderSingleton::UploaderSingleton() for (QString file : configDir.entryList()) { try { registerUploader(new CustomUploader(configDir.absoluteFilePath(file))); - } catch (std::runtime_error e) { + } catch (std::runtime_error &e) { qWarning() << e.what(); errs << e; } @@ -45,21 +45,25 @@ UploaderSingleton::UploaderSingleton() else settings::settings().setValue("uploader", uploader); if (!uploaders.contains(uploader)) { - settings::settings().setValue("uploader", uploader); uploader = "imgur"; + settings::settings().setValue("uploader", uploader); } } void UploaderSingleton::registerUploader(Uploader *uploader) { - if (uploaders.contains(uploader->name())) { + if (uploaders.contains(uploader->name())) throw std::runtime_error(("Ambigious uploader " + uploader->name()).toStdString()); - } uploaders.insert(uploader->name(), uploader); emit newUploader(uploader); } void UploaderSingleton::upload(QPixmap *pixmap) { auto u = uploaders.value(uploader); + if (!u->validate()) { + u = uploaders.value("imgur"); + set("imgur"); + qWarning() << "Currently selected uploader is not set up properly! Falling back to imgur"; + } QString format = settings::settings().value("captureformat", "PNG").toString(); QFile file(saveDir.absoluteFilePath( formatter::format(settings::settings().value("fileFormat", "Screenshot %(yyyy-MM-dd HH:mm:ss)date.%ext").toString(), @@ -91,6 +95,14 @@ void UploaderSingleton::upload(QFile img, QString format) { } } +void UploaderSingleton::showSettings() { + uploaders.value(uploader)->showSettings(); +} + +bool UploaderSingleton::validate() { + return uploaders.value(uploader)->validate(); +} + QList UploaderSingleton::uploaderList() { return uploaders.values(); } @@ -99,6 +111,7 @@ void UploaderSingleton::set(QString uploader) { if (uploaders.contains(uploader)) { this->uploader = uploader; settings::settings().setValue("uploader", uploader); + emit uploaderChanged(uploader); } } diff --git a/uploaders/uploadersingleton.hpp b/uploaders/uploadersingleton.hpp index 6f3efe5..73a4d76 100644 --- a/uploaders/uploadersingleton.hpp +++ b/uploaders/uploadersingleton.hpp @@ -16,14 +16,17 @@ public: void upload(QPixmap *pixmap); void upload(QByteArray img, QString format); void upload(QFile img, QString format); + void showSettings(); QList uploaderList(); void set(QString uploader); QString selectedUploader(); QList errors(); QString currentUploader(); + bool validate(); signals: void newUploader(Uploader *u); + void uploaderChanged(QString newName); private: QDir saveDir;