Add S3 cloud storage support

This commit is contained in:
Yuriy Puchkov
2020-06-22 18:07:14 +03:00
parent 91ba28c3de
commit 54812db981
7 changed files with 464 additions and 1 deletions

View File

@@ -96,6 +96,7 @@ SOURCES += src/main.cpp \
src/tools/copy/copytool.cpp \
src/tools/exit/exittool.cpp \
src/tools/imgur/imguruploadertool.cpp \
src/tools/imgs3/imgs3uploadertool.cpp \
src/tools/line/linetool.cpp \
src/tools/marker/markertool.cpp \
src/tools/move/movetool.cpp \
@@ -113,6 +114,7 @@ SOURCES += src/main.cpp \
src/cli/commandargument.cpp \
src/utils/screenshotsaver.cpp \
src/tools/imgur/imguruploader.cpp \
src/tools/imgs3/imgs3uploader.cpp \
src/widgets/loadspinner.cpp \
src/widgets/imagelabel.cpp \
src/widgets/notificationwidget.cpp \
@@ -170,6 +172,7 @@ HEADERS += src/widgets/capture/buttonhandler.h \
src/tools/copy/copytool.h \
src/tools/exit/exittool.h \
src/tools/imgur/imguruploadertool.h \
src/tools/imgs3/imgs3uploadertool.h \
src/tools/line/linetool.h \
src/tools/marker/markertool.h \
src/tools/move/movetool.h \
@@ -186,6 +189,7 @@ HEADERS += src/widgets/capture/buttonhandler.h \
src/cli/commandargument.h \
src/utils/screenshotsaver.h \
src/tools/imgur/imguruploader.h \
src/tools/imgs3/imgs3uploader.h \
src/widgets/loadspinner.h \
src/widgets/imagelabel.h \
src/widgets/notificationwidget.h \
@@ -289,3 +293,5 @@ unix:!macx {
# Imgur API data
include(src/imgur.pri)
# ImgS3 API data
include(src/imgs3.pri)

7
src/imgs3.pri Normal file
View File

@@ -0,0 +1,7 @@
# Use default ImgS3 client_id if user did not pass
# this variable to qmake
isEmpty(IMG_S3_CLIENT_ID) {
IMG_S3_CLIENT_ID = "313baf0c7b4d3f0"
}
DEFINES += IMG_S3_CLIENT_ID=\\\"$${IMG_S3_CLIENT_ID}\\\"

View File

@@ -0,0 +1,274 @@
// Copyright(c) 2017-2019 Alejandro Sirgo Rica & Contributors
//
// This file is part of Flameshot.
//
// Flameshot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Flameshot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "imgs3uploader.h"
#include "src/utils/filenamehandler.h"
#include "src/utils/systemnotification.h"
#include "src/widgets/loadspinner.h"
#include "src/widgets/imagelabel.h"
#include "src/widgets/notificationwidget.h"
#include "src/utils/confighandler.h"
#include <QApplication>
#include <QClipboard>
#include <QDesktopServices>
#include <QShortcut>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QDrag>
#include <QMimeData>
#include <QBuffer>
#include <QUrlQuery>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QJsonDocument>
#include <QJsonObject>
#include <QHttpMultiPart>
ImgS3Uploader::ImgS3Uploader(const QPixmap &capture, QWidget *parent) :
QWidget(parent), m_pixmap(capture)
{
setWindowTitle(tr("Upload to ImgS3"));
setWindowIcon(QIcon(":img/app/flameshot.svg"));
m_spinner = new LoadSpinner(this);
m_spinner->setColor(ConfigHandler().uiMainColorValue());
m_spinner->start();
m_infoLabel = new QLabel(tr("Uploading Image"));
m_vLayout = new QVBoxLayout();
setLayout(m_vLayout);
m_vLayout->addWidget(m_spinner, 0, Qt::AlignHCenter);
m_vLayout->addWidget(m_infoLabel);
m_NetworkAM = new QNetworkAccessManager(this);
connect(m_NetworkAM, &QNetworkAccessManager::finished, this, &ImgS3Uploader::handleReply);
m_NetworkAMCreds = new QNetworkAccessManager(this);
connect(m_NetworkAMCreds, &QNetworkAccessManager::finished, this, &ImgS3Uploader::handleCredsReply);
setAttribute(Qt::WA_DeleteOnClose);
upload();
}
void ImgS3Uploader::handleReply(QNetworkReply *reply) {
m_spinner->deleteLater();
if (reply->error() == QNetworkReply::NoError) {
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) {
QApplication::clipboard()->setText(m_imageURL.toString());
SystemNotification().sendMessage(QObject::tr("URL copied to clipboard."));
close();
} else {
onUploadOk();
}
} else {
QString reason = reply->attribute( QNetworkRequest::HttpReasonPhraseAttribute ).toString();
qDebug() << reply->header(QNetworkRequest::ContentDispositionHeader);
qDebug() << reply->header(QNetworkRequest::ContentTypeHeader);
qDebug() << reply->readAll();
qDebug() << reason;
m_infoLabel->setText(reply->errorString());
}
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
}
void ImgS3Uploader::startDrag() {
QMimeData *mimeData = new QMimeData;
mimeData->setUrls(QList<QUrl> { m_imageURL });
mimeData->setImageData(m_pixmap);
QDrag *dragHandler = new QDrag(this);
dragHandler->setMimeData(mimeData);
dragHandler->setPixmap(m_pixmap.scaled(256, 256, Qt::KeepAspectRatioByExpanding,
Qt::SmoothTransformation));
dragHandler->exec();
}
void ImgS3Uploader::handleCredsReply(QNetworkReply *reply){
if (reply->error() == QNetworkReply::NoError) {
QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
uploadToS3(response);
} else {
m_infoLabel->setText(reply->errorString());
}
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
}
void ImgS3Uploader::uploadToS3(QJsonDocument &response) {
QJsonObject json = response.object();
QJsonObject formData = json["formData"].toObject();
QJsonObject fields = formData["fields"].toObject();
QString resultURL = json["resultURL"].toString();
QString url = formData["url"].toString();
QString acl = fields["acl"].toString();
QString contentType = fields["Content-Type"].toString();
QString key = fields["Key"].toString();
QString bucket = fields["bucket"].toString();
QString xAmzAlgorithm = fields["X-Amz-Algorithm"].toString();
QString xAmzCredential = fields["X-Amz-Credential"].toString();
QString xAmzDate = fields["X-Amz-Date"].toString();
QString xAmzSecurityToken = fields["X-Amz-Security-Token"].toString();
QString policy = fields["Policy"].toString();
QString xAmzSignature = fields["X-Amz-Signature"].toString();
//
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart aclPart;
aclPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"acl\""));
aclPart.setBody(acl.toLatin1());
multiPart->append(aclPart);
QHttpPart contentTypePart;
contentTypePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"Content-Type\""));
contentTypePart.setBody(contentType.toLatin1());
multiPart->append(contentTypePart);
QHttpPart keyPart;
keyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"Key\""));
keyPart.setBody(key.toLatin1());
multiPart->append(keyPart);
QHttpPart bucketPart;
bucketPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"bucket\""));
bucketPart.setBody(bucket.toLatin1());
multiPart->append(bucketPart);
QHttpPart xAmzAlgorithmPart;
xAmzAlgorithmPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"X-Amz-Algorithm\""));
xAmzAlgorithmPart.setBody(xAmzAlgorithm.toLatin1());
multiPart->append(xAmzAlgorithmPart);
QHttpPart xAmzCredentialPart;
xAmzCredentialPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"X-Amz-Credential\""));
xAmzCredentialPart.setBody(xAmzCredential.toLatin1());
multiPart->append(xAmzCredentialPart);
QHttpPart xAmzDatePart;
xAmzDatePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"X-Amz-Date\""));
xAmzDatePart.setBody(xAmzDate.toLatin1());
multiPart->append(xAmzDatePart);
QHttpPart xAmzSecurityTokenPart;
xAmzSecurityTokenPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"X-Amz-Security-Token\""));
xAmzSecurityTokenPart.setBody(xAmzSecurityToken.toLatin1());
multiPart->append(xAmzSecurityTokenPart);
QHttpPart policyPart;
policyPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"Policy\""));
policyPart.setBody(policy.toLatin1());
multiPart->append(policyPart);
QHttpPart xAmzSignaturePart;
xAmzSignaturePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"X-Amz-Signature\""));
xAmzSignaturePart.setBody(xAmzSignature.toLatin1());
multiPart->append(xAmzSignaturePart);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QVariant("form-data; name=\"file\""));
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
m_pixmap.save(&buffer, "PNG");
imagePart.setBody(byteArray);
multiPart->append(imagePart);
m_imageURL.setUrl(resultURL);
QUrl qUrl(url);
QNetworkRequest request(qUrl);
m_NetworkAM->post(request, multiPart);
}
void ImgS3Uploader::upload() {
// get creads
QUrl creds("https://api.img.rnd.namecheap.net/");
QNetworkRequest requestCreds(creds);
m_NetworkAMCreds->get(requestCreds);
}
void ImgS3Uploader::onUploadOk() {
m_infoLabel->deleteLater();
m_notification = new NotificationWidget();
m_vLayout->addWidget(m_notification);
ImageLabel *imageLabel = new ImageLabel();
imageLabel->setScreenshot(m_pixmap);
imageLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
connect(imageLabel, &ImageLabel::dragInitiated, this, &ImgS3Uploader::startDrag);
m_vLayout->addWidget(imageLabel);
m_hLayout = new QHBoxLayout();
m_vLayout->addLayout(m_hLayout);
m_copyUrlButton = new QPushButton(tr("Copy URL"));
m_openUrlButton = new QPushButton(tr("Open URL"));
m_openDeleteUrlButton = new QPushButton(tr("Delete image"));
m_toClipboardButton = new QPushButton(tr("Image to Clipboard."));
m_hLayout->addWidget(m_copyUrlButton);
m_hLayout->addWidget(m_openUrlButton);
m_hLayout->addWidget(m_openDeleteUrlButton);
m_hLayout->addWidget(m_toClipboardButton);
connect(m_copyUrlButton, &QPushButton::clicked,
this, &ImgS3Uploader::copyURL);
connect(m_openUrlButton, &QPushButton::clicked,
this, &ImgS3Uploader::openURL);
connect(m_openDeleteUrlButton, &QPushButton::clicked,
this, &ImgS3Uploader::openDeleteURL);
connect(m_toClipboardButton, &QPushButton::clicked,
this, &ImgS3Uploader::copyImage);
}
void ImgS3Uploader::openURL() {
bool successful = QDesktopServices::openUrl(m_imageURL);
if (!successful) {
m_notification->showMessage(tr("Unable to open the URL."));
}
}
void ImgS3Uploader::copyURL() {
QApplication::clipboard()->setText(m_imageURL.toString());
m_notification->showMessage(tr("URL copied to clipboard."));
}
void ImgS3Uploader::openDeleteURL()
{
bool successful = QDesktopServices::openUrl(m_deleteImageURL);
if (!successful) {
m_notification->showMessage(tr("Unable to open the URL."));
}
}
void ImgS3Uploader::copyImage() {
QApplication::clipboard()->setPixmap(m_pixmap);
m_notification->showMessage(tr("Screenshot copied to clipboard."));
}

View File

@@ -0,0 +1,73 @@
// Copyright(c) 2017-2019 Alejandro Sirgo Rica & Contributors
//
// This file is part of Flameshot.
//
// Flameshot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Flameshot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <QWidget>
#include <QUrl>
class QNetworkReply;
class QNetworkAccessManager;
class QHBoxLayout;
class QVBoxLayout;
class QLabel;
class LoadSpinner;
class QPushButton;
class QUrl;
class NotificationWidget;
class ImgS3Uploader : public QWidget {
Q_OBJECT
public:
explicit ImgS3Uploader(const QPixmap &capture, QWidget *parent = nullptr);
private slots:
void handleReply(QNetworkReply *reply);
void handleCredsReply(QNetworkReply *reply);
void startDrag();
void openURL();
void copyURL();
void openDeleteURL();
void copyImage();
private:
void uploadToS3(QJsonDocument &response);
private:
QString m_hostName;
QPixmap m_pixmap;
QNetworkAccessManager *m_NetworkAM;
QNetworkAccessManager *m_NetworkAMCreds;
QVBoxLayout *m_vLayout;
QHBoxLayout *m_hLayout;
// loading
QLabel *m_infoLabel;
LoadSpinner *m_spinner;
// uploaded
QPushButton *m_openUrlButton;
QPushButton *m_openDeleteUrlButton;
QPushButton *m_copyUrlButton;
QPushButton *m_toClipboardButton;
QUrl m_imageURL;
QUrl m_deleteImageURL;
NotificationWidget *m_notification;
void upload();
void onUploadOk();
};

View File

@@ -0,0 +1,58 @@
// Copyright(c) 2017-2019 Alejandro Sirgo Rica & Contributors
//
// This file is part of Flameshot.
//
// Flameshot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Flameshot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#include "imgs3uploadertool.h"
#include "imgs3uploader.h"
#include <QPainter>
ImgS3UploaderTool::ImgS3UploaderTool(QObject *parent) : AbstractActionTool(parent) {
}
bool ImgS3UploaderTool::closeOnButtonPressed() const {
return true;
}
QIcon ImgS3UploaderTool::icon(const QColor &background, bool inEditor) const {
Q_UNUSED(inEditor);
return QIcon(iconPath(background) + "cloud-upload.svg");
}
QString ImgS3UploaderTool::name() const {
return tr("Image Uploader");
}
QString ImgS3UploaderTool::nameID() {
return QLatin1String("");
}
QString ImgS3UploaderTool::description() const {
return tr("Upload the selection to ImgS3");
}
QWidget* ImgS3UploaderTool::widget() {
return new ImgS3Uploader(capture);
}
CaptureTool* ImgS3UploaderTool::copy(QObject *parent) {
return new ImgS3UploaderTool(parent);
}
void ImgS3UploaderTool::pressed(const CaptureContext &context) {
capture = context.selectedScreenshotArea();
emit requestAction(REQ_CAPTURE_DONE_OK);
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
}

View File

@@ -0,0 +1,43 @@
// Copyright(c) 2017-2019 Alejandro Sirgo Rica & Contributors
//
// This file is part of Flameshot.
//
// Flameshot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Flameshot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Flameshot. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include "src/tools/abstractactiontool.h"
class ImgS3UploaderTool : public AbstractActionTool {
Q_OBJECT
public:
explicit ImgS3UploaderTool(QObject *parent = nullptr);
bool closeOnButtonPressed() const;
QIcon icon(const QColor &background, bool inEditor) const override;
QString name() const override;
static QString nameID();
QString description() const override;
QWidget* widget() override;
CaptureTool* copy(QObject *parent = nullptr) override;
public slots:
void pressed(const CaptureContext &context) override;
private:
QPixmap capture;
};

View File

@@ -21,6 +21,7 @@
#include "copy/copytool.h"
#include "exit/exittool.h"
#include "imgur/imguruploadertool.h"
#include "imgs3/imgs3uploadertool.h"
#include "line/linetool.h"
#include "marker/markertool.h"
#include "move/movetool.h"
@@ -59,7 +60,8 @@ CaptureTool* ToolFactory::CreateTool(
tool = new ExitTool(parent);
break;
case CaptureButton::TYPE_IMAGEUPLOADER:
tool = new ImgurUploaderTool(parent);
// tool = new ImgurUploaderTool(parent);
tool = new ImgS3UploaderTool(parent);
break;
case CaptureButton::TYPE_DRAWER:
tool = new LineTool(parent);