Preparing for upstream merge
This commit is contained in:
4
.github/workflows/build_cmake.yml
vendored
4
.github/workflows/build_cmake.yml
vendored
@@ -2,12 +2,12 @@ name: Building(CMake)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, master_nc_merge_upstream_test ]
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- 'LICENSE'
|
||||
pull_request:
|
||||
branches: [ master, master_nc_merge_upstream_test ]
|
||||
branches: [ master ]
|
||||
paths-ignore:
|
||||
- 'README.md'
|
||||
- 'LICENSE'
|
||||
|
||||
@@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.13)
|
||||
# This can be read from ${PROJECT_NAME} after project() is called
|
||||
project(
|
||||
flameshot
|
||||
VERSION 0.8.5.2
|
||||
VERSION 0.8.5
|
||||
LANGUAGES CXX)
|
||||
set(PROJECT_NAME_CAPITALIZED "Flameshot")
|
||||
|
||||
|
||||
30
README.md
30
README.md
@@ -278,36 +278,6 @@ some Linux distributions:
|
||||
|
||||
Alternatively, in case you don't want to have a systray, you can always call Flameshot from the terminal. See [Usage section](#usage).
|
||||
|
||||
### S3 bucket configuration
|
||||
|
||||
S3 bucket credentials are placed in the file `config.ini` and cannot be configured with UI.
|
||||
This file is not included into installation and should be placed into the installation directory manually.
|
||||
On `linux` systems it can be placed at `/etc/flameshot/config.ini`.
|
||||
|
||||
You can also add `proxy` server settings. If you don't need a proxy server just remove or comment lines with a proxy settings.
|
||||
|
||||
Configuration file example:
|
||||
```
|
||||
[General]
|
||||
HTTP_PROXY_HOST=10.0.0.1
|
||||
HTTP_PROXY_PORT=3128
|
||||
|
||||
; No authentification USER and PASSWORD should be empty
|
||||
HTTP_PROXY_USER=
|
||||
HTTP_PROXY_PASSWORD=
|
||||
|
||||
HTTP_PROXY_TYPE=0
|
||||
; Proxy Types (0 is default):
|
||||
; 0 Proxy is determined based on the application proxy set using setApplicationProxy()
|
||||
; 1 Socks5 proxying is used
|
||||
; 3 HTTP transparent proxying is used
|
||||
; 4 Proxying for HTTP requests only
|
||||
; 5 Proxying for FTP requests only
|
||||
|
||||
[S3]
|
||||
S3_CREDS_URL=https://api.img.example.com/
|
||||
S3_X_API_KEY=seckret_key
|
||||
```
|
||||
|
||||
## Compilation
|
||||
|
||||
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -39,8 +39,8 @@ artifacts:
|
||||
- path: build\artifact.zip
|
||||
name: archive
|
||||
|
||||
#deploy:
|
||||
#- provider: Webhook
|
||||
# url: https://app.signpath.io/API/v1/042f605f-b378-45d8-ad16-b7695b071036/Integrations/AppVeyor?ProjectSlug=flameshot&SigningPolicySlug=test-signing
|
||||
# authorization:
|
||||
# secure: G5nNnkfRSJ+EEx+7LlUSSoEyoL+pHYItvjrNxbWITE7RB+cm9qzuHRdwmrZdEDjdVCLZ2TkNawynMxYcGMZAQA==
|
||||
deploy:
|
||||
- provider: Webhook
|
||||
url: https://app.signpath.io/API/v1/042f605f-b378-45d8-ad16-b7695b071036/Integrations/AppVeyor?ProjectSlug=flameshot&SigningPolicySlug=test-signing
|
||||
authorization:
|
||||
secure: G5nNnkfRSJ+EEx+7LlUSSoEyoL+pHYItvjrNxbWITE7RB+cm9qzuHRdwmrZdEDjdVCLZ2TkNawynMxYcGMZAQA==
|
||||
|
||||
@@ -12,5 +12,4 @@ target_sources(
|
||||
visualseditor.cpp
|
||||
shortcutswidget.cpp
|
||||
setshortcutwidget.cpp
|
||||
uploadstorageconfig.cpp
|
||||
)
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "src/config/geneneralconf.h"
|
||||
#include "src/config/shortcutswidget.h"
|
||||
#include "src/config/strftimechooserwidget.h"
|
||||
#include "src/config/uploadstorageconfig.h"
|
||||
#include "src/config/visualseditor.h"
|
||||
#include "src/utils/colorutils.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
@@ -77,12 +76,6 @@ ConfigWindow::ConfigWindow(QWidget* parent)
|
||||
m_shortcuts = new ShortcutsWidget();
|
||||
addTab(m_shortcuts, QIcon(modifier + "shortcut.svg"), tr("Shortcuts"));
|
||||
|
||||
// upload storage configuration
|
||||
m_uploadStorageConfig = new UploadStorageConfig();
|
||||
addTab(m_uploadStorageConfig,
|
||||
QIcon(modifier + "cloud-upload.svg"),
|
||||
tr("Storage"));
|
||||
|
||||
// connect update sigslots
|
||||
connect(this,
|
||||
&ConfigWindow::updateChildren,
|
||||
|
||||
@@ -24,7 +24,6 @@ class ShortcutsWidget;
|
||||
class GeneneralConf;
|
||||
class QFileSystemWatcher;
|
||||
class VisualsEditor;
|
||||
class UploadStorageConfig;
|
||||
|
||||
class ConfigWindow : public QTabWidget
|
||||
{
|
||||
@@ -42,7 +41,6 @@ private:
|
||||
FileNameEditor* m_filenameEditor;
|
||||
ShortcutsWidget* m_shortcuts;
|
||||
GeneneralConf* m_generalConfig;
|
||||
UploadStorageConfig* m_uploadStorageConfig;
|
||||
VisualsEditor* m_visuals;
|
||||
QFileSystemWatcher* m_configWatcher;
|
||||
};
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
// Copyright(c) 2020 Yurii Puchkov at Namecheap & 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 "uploadstorageconfig.h"
|
||||
#include "src/tools/storage/imgstorages.h"
|
||||
#include "src/tools/storage/storagemanager.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QGroupBox>
|
||||
#include <QRadioButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
UploadStorageConfig::UploadStorageConfig(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
m_layout = new QVBoxLayout(this);
|
||||
m_layout->setAlignment(Qt::AlignTop);
|
||||
|
||||
QGroupBox* groupBox = new QGroupBox(tr("Upload storage"));
|
||||
|
||||
// TODO - remove dependency injection (s3 & imgur)
|
||||
// imgur
|
||||
QRadioButton* storageImgUr = new QRadioButton(tr("Imgur storage"));
|
||||
connect(storageImgUr, &QCheckBox::clicked, [](bool checked) {
|
||||
ConfigHandler().setUploadStorage(SCREENSHOT_STORAGE_TYPE_IMGUR);
|
||||
});
|
||||
|
||||
// s3
|
||||
QRadioButton* storageImgS3 = new QRadioButton(
|
||||
tr("S3 storage (require config.ini file with s3 credentials)"));
|
||||
connect(storageImgS3, &QCheckBox::clicked, [](bool checked) {
|
||||
ConfigHandler().setUploadStorage(SCREENSHOT_STORAGE_TYPE_S3);
|
||||
});
|
||||
|
||||
StorageManager storageManager;
|
||||
if (storageManager.storageLocked()) {
|
||||
ConfigHandler().setUploadStorage(storageManager.storageDefault());
|
||||
storageImgUr->setDisabled(true);
|
||||
storageImgS3->setDisabled(true);
|
||||
}
|
||||
|
||||
// set current storage radiobutton active
|
||||
if (ConfigHandler().uploadStorage() == SCREENSHOT_STORAGE_TYPE_IMGUR) {
|
||||
storageImgUr->setChecked(true);
|
||||
|
||||
} else {
|
||||
storageImgS3->setChecked(true);
|
||||
}
|
||||
|
||||
// draw configuration options for uploadStorage
|
||||
QVBoxLayout* vbox = new QVBoxLayout;
|
||||
vbox->addWidget(storageImgUr);
|
||||
vbox->addWidget(storageImgS3);
|
||||
vbox->addStretch(1);
|
||||
groupBox->setLayout(vbox);
|
||||
m_layout->addWidget(groupBox);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright(c) 2020 Yurii Puchkov at Namecheap & 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/>.
|
||||
|
||||
#ifndef FLAMESHOT_UPLOADSTORAGECONFIG_H
|
||||
#define FLAMESHOT_UPLOADSTORAGECONFIG_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
|
||||
class QVBoxLayout;
|
||||
|
||||
class UploadStorageConfig : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit UploadStorageConfig(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
QVBoxLayout* m_layout;
|
||||
};
|
||||
|
||||
#endif // FLAMESHOT_UPLOADSTORAGECONFIG_H
|
||||
@@ -6,22 +6,10 @@ target_sources(flameshot PRIVATE copy/copytool.h copy/copytool.cpp)
|
||||
target_sources(flameshot PRIVATE exit/exittool.h exit/exittool.cpp)
|
||||
target_sources(
|
||||
flameshot
|
||||
PRIVATE storage/storagemanager.h
|
||||
storage/storagemanager.cpp
|
||||
storage/imguploader.h
|
||||
storage/imguploadertool.h
|
||||
storage/imguploader.cpp
|
||||
storage/imguploadertool.cpp
|
||||
storage/imgur/imguruploader.h
|
||||
storage/imgur/imguruploadertool.h
|
||||
storage/imgur/imguruploader.cpp
|
||||
storage/imgur/imguruploadertool.cpp
|
||||
storage/s3/imgs3settings.h
|
||||
storage/s3/imgs3settings.cpp
|
||||
storage/s3/imgs3uploader.h
|
||||
storage/s3/imgs3uploadertool.h
|
||||
storage/s3/imgs3uploader.cpp
|
||||
storage/s3/imgs3uploadertool.cpp
|
||||
PRIVATE imgur/imguruploader.h
|
||||
imgur/imguruploadertool.h
|
||||
imgur/imguruploader.cpp
|
||||
imgur/imguruploadertool.cpp
|
||||
)
|
||||
target_sources(
|
||||
flameshot
|
||||
|
||||
213
src/tools/imgur/imguruploader.cpp
Normal file
213
src/tools/imgur/imguruploader.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// 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 "imguruploader.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "src/utils/filenamehandler.h"
|
||||
#include "src/utils/systemnotification.h"
|
||||
#include "src/widgets/imagelabel.h"
|
||||
#include "src/widgets/loadspinner.h"
|
||||
#include "src/widgets/notificationwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QClipboard>
|
||||
#include <QCursor>
|
||||
#include <QDesktopServices>
|
||||
#include <QDrag>
|
||||
#include <QGuiApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QMimeData>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPushButton>
|
||||
#include <QRect>
|
||||
#include <QScreen>
|
||||
#include <QShortcut>
|
||||
#include <QTimer>
|
||||
#include <QUrlQuery>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ImgurUploader::ImgurUploader(const QPixmap& capture, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_pixmap(capture)
|
||||
{
|
||||
setWindowTitle(tr("Upload to Imgur"));
|
||||
setWindowIcon(QIcon(":img/app/flameshot.svg"));
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
QRect position = frameGeometry();
|
||||
QScreen* screen = QGuiApplication::screenAt(QCursor::pos());
|
||||
position.moveCenter(screen->availableGeometry().center());
|
||||
move(position.topLeft());
|
||||
#endif
|
||||
|
||||
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,
|
||||
&ImgurUploader::handleReply);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
upload();
|
||||
// QTimer::singleShot(2000, this, &ImgurUploader::onUploadOk); // testing
|
||||
}
|
||||
|
||||
void ImgurUploader::handleReply(QNetworkReply* reply)
|
||||
{
|
||||
m_spinner->deleteLater();
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject json = response.object();
|
||||
QJsonObject data = json[QStringLiteral("data")].toObject();
|
||||
m_imageURL.setUrl(data[QStringLiteral("link")].toString());
|
||||
m_deleteImageURL.setUrl(
|
||||
QStringLiteral("https://imgur.com/delete/%1")
|
||||
.arg(data[QStringLiteral("deletehash")].toString()));
|
||||
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) {
|
||||
QApplication::clipboard()->setText(m_imageURL.toString());
|
||||
SystemNotification().sendMessage(
|
||||
QObject::tr("URL copied to clipboard."));
|
||||
close();
|
||||
} else {
|
||||
onUploadOk();
|
||||
}
|
||||
} else {
|
||||
m_infoLabel->setText(reply->errorString());
|
||||
}
|
||||
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
|
||||
}
|
||||
|
||||
void ImgurUploader::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 ImgurUploader::upload()
|
||||
{
|
||||
QByteArray byteArray;
|
||||
QBuffer buffer(&byteArray);
|
||||
m_pixmap.save(&buffer, "PNG");
|
||||
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem(QStringLiteral("title"),
|
||||
QStringLiteral("flameshot_screenshot"));
|
||||
QString description = FileNameHandler().parsedPattern();
|
||||
urlQuery.addQueryItem(QStringLiteral("description"), description);
|
||||
|
||||
QUrl url(QStringLiteral("https://api.imgur.com/3/image"));
|
||||
url.setQuery(urlQuery);
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/application/x-www-form-urlencoded");
|
||||
request.setRawHeader(
|
||||
"Authorization",
|
||||
QStringLiteral("Client-ID %1").arg(IMGUR_CLIENT_ID).toUtf8());
|
||||
|
||||
m_NetworkAM->post(request, byteArray);
|
||||
}
|
||||
|
||||
void ImgurUploader::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, &ImgurUploader::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, &ImgurUploader::copyURL);
|
||||
connect(
|
||||
m_openUrlButton, &QPushButton::clicked, this, &ImgurUploader::openURL);
|
||||
connect(m_openDeleteUrlButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&ImgurUploader::openDeleteURL);
|
||||
connect(m_toClipboardButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&ImgurUploader::copyImage);
|
||||
}
|
||||
|
||||
void ImgurUploader::openURL()
|
||||
{
|
||||
bool successful = QDesktopServices::openUrl(m_imageURL);
|
||||
if (!successful) {
|
||||
m_notification->showMessage(tr("Unable to open the URL."));
|
||||
}
|
||||
}
|
||||
|
||||
void ImgurUploader::copyURL()
|
||||
{
|
||||
QApplication::clipboard()->setText(m_imageURL.toString());
|
||||
m_notification->showMessage(tr("URL copied to clipboard."));
|
||||
}
|
||||
|
||||
void ImgurUploader::openDeleteURL()
|
||||
{
|
||||
bool successful = QDesktopServices::openUrl(m_deleteImageURL);
|
||||
if (!successful) {
|
||||
m_notification->showMessage(tr("Unable to open the URL."));
|
||||
}
|
||||
}
|
||||
|
||||
void ImgurUploader::copyImage()
|
||||
{
|
||||
QApplication::clipboard()->setPixmap(m_pixmap);
|
||||
m_notification->showMessage(tr("Screenshot copied to clipboard."));
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../imguploader.h"
|
||||
#include <QUrl>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -31,21 +30,39 @@ class QPushButton;
|
||||
class QUrl;
|
||||
class NotificationWidget;
|
||||
|
||||
class ImgurUploader : public ImgUploader
|
||||
class ImgurUploader : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImgurUploader(const QPixmap& capture, QWidget* parent = nullptr);
|
||||
void upload();
|
||||
|
||||
private slots:
|
||||
void handleReply(QNetworkReply* reply);
|
||||
void startDrag();
|
||||
|
||||
protected slots:
|
||||
void deleteImageOnStorage();
|
||||
void openURL();
|
||||
void copyURL();
|
||||
void openDeleteURL();
|
||||
void copyImage();
|
||||
|
||||
// class members
|
||||
private:
|
||||
QPixmap m_pixmap;
|
||||
QNetworkAccessManager* m_NetworkAM;
|
||||
|
||||
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();
|
||||
};
|
||||
@@ -20,14 +20,29 @@
|
||||
#include <QPainter>
|
||||
|
||||
ImgurUploaderTool::ImgurUploaderTool(QObject* parent)
|
||||
: ImgUploaderTool(parent)
|
||||
: AbstractActionTool(parent)
|
||||
{}
|
||||
|
||||
bool ImgurUploaderTool::closeOnButtonPressed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QIcon ImgurUploaderTool::icon(const QColor& background, bool inEditor) const
|
||||
{
|
||||
Q_UNUSED(inEditor);
|
||||
return QIcon(iconPath(background) + "cloud-upload.svg");
|
||||
}
|
||||
QString ImgurUploaderTool::name() const
|
||||
{
|
||||
return tr("Image Uploader");
|
||||
}
|
||||
|
||||
ToolType ImgurUploaderTool::nameID() const
|
||||
{
|
||||
return ToolType::IMGUR;
|
||||
}
|
||||
|
||||
QString ImgurUploaderTool::description() const
|
||||
{
|
||||
return tr("Upload the selection to Imgur");
|
||||
@@ -35,12 +50,17 @@ QString ImgurUploaderTool::description() const
|
||||
|
||||
QWidget* ImgurUploaderTool::widget()
|
||||
{
|
||||
ImgurUploader* p = new ImgurUploader(capture());
|
||||
p->upload();
|
||||
return p;
|
||||
return new ImgurUploader(capture);
|
||||
}
|
||||
|
||||
CaptureTool* ImgurUploaderTool::copy(QObject* parent)
|
||||
{
|
||||
return new ImgurUploaderTool(parent);
|
||||
}
|
||||
|
||||
void ImgurUploaderTool::pressed(const CaptureContext& context)
|
||||
{
|
||||
capture = context.selectedScreenshotArea();
|
||||
emit requestAction(REQ_CAPTURE_DONE_OK);
|
||||
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
|
||||
}
|
||||
@@ -17,18 +17,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "src/tools/storage/imguploadertool.h"
|
||||
#include "src/tools/abstractactiontool.h"
|
||||
|
||||
class ImgurUploaderTool : public ImgUploaderTool
|
||||
class ImgurUploaderTool : public AbstractActionTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImgurUploaderTool(QObject* parent = nullptr);
|
||||
|
||||
bool closeOnButtonPressed() const;
|
||||
|
||||
QIcon icon(const QColor& background, bool inEditor) const override;
|
||||
QString name() const override;
|
||||
QString description() const override;
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
CaptureTool* copy(QObject* parent = nullptr) override;
|
||||
|
||||
protected:
|
||||
ToolType nameID() const override;
|
||||
|
||||
public slots:
|
||||
void pressed(const CaptureContext& context) override;
|
||||
|
||||
private:
|
||||
QPixmap capture;
|
||||
};
|
||||
@@ -85,9 +85,8 @@ void PixelateTool::process(QPainter& painter,
|
||||
scene.render(&painter, selection, QRectF());
|
||||
blur->setBlurRadius(12);
|
||||
// multiple repeat for make blur effect stronger
|
||||
for (int cnt = 100; cnt > 0; cnt--) {
|
||||
scene.render(&painter, selection, QRectF());
|
||||
}
|
||||
scene.render(&painter, selection, QRectF());
|
||||
|
||||
} else {
|
||||
int width = selection.width() * (0.5 / qMax(1, m_thickness));
|
||||
int height = selection.height() * (0.5 / qMax(1, m_thickness));
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef IMGSTORAGES_H
|
||||
#define IMGSTORAGES_H
|
||||
|
||||
#define SCREENSHOT_STORAGE_TYPE_S3 "s3"
|
||||
#define SCREENSHOT_STORAGE_TYPE_IMGUR "imgur"
|
||||
|
||||
#endif // IMGSTORAGES_H
|
||||
@@ -1,207 +0,0 @@
|
||||
// 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 "imguploader.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "src/widgets/imagelabel.h"
|
||||
#include "src/widgets/loadspinner.h"
|
||||
#include "src/widgets/notificationwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QCursor>
|
||||
#include <QDesktopServices>
|
||||
#include <QDrag>
|
||||
#include <QGuiApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QMimeData>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QPushButton>
|
||||
#include <QRect>
|
||||
#include <QScreen>
|
||||
#include <QShortcut>
|
||||
#include <QTimer>
|
||||
#include <QUrlQuery>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ImgUploader::ImgUploader(const QPixmap& capture, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_pixmap(capture)
|
||||
{
|
||||
init(tr("Upload image to S3"), tr("Uploading Image"));
|
||||
}
|
||||
|
||||
ImgUploader::ImgUploader(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
init(tr("Upload image"), tr("Uploading Image"));
|
||||
}
|
||||
|
||||
void ImgUploader::init(const QString& title, const QString& label)
|
||||
{
|
||||
m_imageLabel = nullptr;
|
||||
m_spinner = nullptr;
|
||||
|
||||
resultStatus = false;
|
||||
setWindowTitle(title);
|
||||
setWindowIcon(QIcon(":img/app/flameshot.svg"));
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
QRect position = frameGeometry();
|
||||
QScreen* screen = QGuiApplication::screenAt(QCursor::pos());
|
||||
position.moveCenter(screen->availableGeometry().center());
|
||||
move(position.topLeft());
|
||||
#endif
|
||||
|
||||
m_spinner = new LoadSpinner(this);
|
||||
m_spinner->setColor(ConfigHandler().uiMainColorValue());
|
||||
m_spinner->start();
|
||||
|
||||
m_infoLabel = new QLabel(label);
|
||||
m_infoLabel->setAlignment(Qt::AlignCenter);
|
||||
|
||||
m_vLayout = new QVBoxLayout();
|
||||
setLayout(m_vLayout);
|
||||
m_vLayout->addWidget(m_spinner, 0, Qt::AlignHCenter);
|
||||
m_vLayout->addWidget(m_infoLabel);
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
}
|
||||
|
||||
void ImgUploader::openURL()
|
||||
{
|
||||
bool successful = QDesktopServices::openUrl(imageUrl());
|
||||
if (!successful) {
|
||||
m_notification->showMessage(tr("Unable to open the URL."));
|
||||
}
|
||||
}
|
||||
|
||||
void ImgUploader::copyURL()
|
||||
{
|
||||
QApplication::clipboard()->setText(imageUrl().toString());
|
||||
m_notification->showMessage(tr("URL copied to clipboard."));
|
||||
}
|
||||
|
||||
void ImgUploader::copyImage()
|
||||
{
|
||||
QApplication::clipboard()->setPixmap(m_pixmap);
|
||||
m_notification->showMessage(tr("Screenshot copied to clipboard."));
|
||||
}
|
||||
|
||||
void ImgUploader::deleteImageOnStorage()
|
||||
{
|
||||
if (nullptr != m_imageLabel) {
|
||||
m_imageLabel->hide();
|
||||
}
|
||||
m_spinner->show();
|
||||
setInfoLabelText(tr("Deleting image..."));
|
||||
deleteResource(m_storageImageName, m_deleteToken);
|
||||
}
|
||||
|
||||
void ImgUploader::startDrag()
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData;
|
||||
mimeData->setUrls(QList<QUrl>{ 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 ImgUploader::hideSpinner()
|
||||
{
|
||||
if (nullptr != m_spinner) {
|
||||
m_spinner->hide();
|
||||
}
|
||||
if (nullptr != m_imageLabel) {
|
||||
m_imageLabel->hide();
|
||||
}
|
||||
}
|
||||
|
||||
void ImgUploader::setInfoLabelText(const QString& infoText)
|
||||
{
|
||||
m_infoLabel->setText(infoText);
|
||||
m_infoLabel->show();
|
||||
}
|
||||
|
||||
const QPixmap& ImgUploader::pixmap()
|
||||
{
|
||||
return m_pixmap;
|
||||
}
|
||||
|
||||
void ImgUploader::onUploadOk()
|
||||
{
|
||||
hideSpinner();
|
||||
|
||||
m_notification = new NotificationWidget();
|
||||
m_vLayout->addWidget(m_notification);
|
||||
|
||||
if (nullptr == m_imageLabel) {
|
||||
m_imageLabel = new ImageLabel();
|
||||
m_imageLabel->setScreenshot(pixmap());
|
||||
m_imageLabel->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
connect(m_imageLabel,
|
||||
&ImageLabel::dragInitiated,
|
||||
this,
|
||||
&ImgUploader::startDrag);
|
||||
m_vLayout->addWidget(m_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_deleteImageOnStorage = 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_deleteImageOnStorage);
|
||||
m_hLayout->addWidget(m_toClipboardButton);
|
||||
|
||||
connect(
|
||||
m_copyUrlButton, &QPushButton::clicked, this, &ImgUploader::copyURL);
|
||||
connect(
|
||||
m_openUrlButton, &QPushButton::clicked, this, &ImgUploader::openURL);
|
||||
connect(m_deleteImageOnStorage,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&ImgUploader::deleteImageOnStorage);
|
||||
connect(m_toClipboardButton,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&ImgUploader::copyImage);
|
||||
}
|
||||
|
||||
void ImgUploader::setImageUrl(const QUrl& imageURL)
|
||||
{
|
||||
m_imageURL = imageURL;
|
||||
}
|
||||
const QUrl& ImgUploader::imageUrl()
|
||||
{
|
||||
return m_imageURL;
|
||||
}
|
||||
|
||||
void ImgUploader::showNotificationMessage(const QString& notificationMessage)
|
||||
{
|
||||
m_notification->showMessage(notificationMessage);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
// 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 "imgstorages.h"
|
||||
#include "s3/imgs3settings.h"
|
||||
#include <QUrl>
|
||||
#include <QWidget>
|
||||
|
||||
class QNetworkReply;
|
||||
class QNetworkProxy;
|
||||
class QNetworkAccessManager;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class QLabel;
|
||||
class LoadSpinner;
|
||||
class QPushButton;
|
||||
class QUrl;
|
||||
class NotificationWidget;
|
||||
class ImageLabel;
|
||||
|
||||
class ImgUploader : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImgUploader(const QPixmap& capture, QWidget* parent = nullptr);
|
||||
explicit ImgUploader(QWidget* parent = nullptr);
|
||||
|
||||
virtual void upload(){};
|
||||
virtual void deleteResource(const QString&, const QString&){};
|
||||
|
||||
protected:
|
||||
const QPixmap& pixmap();
|
||||
void setImageUrl(const QUrl&);
|
||||
const QUrl& imageUrl();
|
||||
void onUploadOk();
|
||||
void hideSpinner();
|
||||
void setInfoLabelText(const QString&);
|
||||
void showNotificationMessage(const QString&);
|
||||
|
||||
public slots:
|
||||
virtual void openURL();
|
||||
virtual void copyURL();
|
||||
virtual void copyImage();
|
||||
virtual void deleteImageOnStorage();
|
||||
virtual void startDrag();
|
||||
|
||||
private:
|
||||
void init(const QString& title, const QString& label);
|
||||
|
||||
// class members
|
||||
private:
|
||||
QPixmap m_pixmap;
|
||||
|
||||
QUrl m_imageURL;
|
||||
ImageLabel* m_imageLabel;
|
||||
|
||||
NotificationWidget* m_notification;
|
||||
|
||||
QVBoxLayout* m_vLayout;
|
||||
QHBoxLayout* m_hLayout;
|
||||
// loading
|
||||
LoadSpinner* m_spinner;
|
||||
QLabel* m_infoLabel;
|
||||
// uploaded
|
||||
QPushButton* m_openUrlButton;
|
||||
QPushButton* m_copyUrlButton;
|
||||
QPushButton* m_toClipboardButton;
|
||||
QPushButton* m_deleteImageOnStorage;
|
||||
|
||||
protected:
|
||||
// bool m_success;
|
||||
|
||||
// Temporary variables
|
||||
QString m_deleteToken;
|
||||
QString m_storageImageName;
|
||||
|
||||
public:
|
||||
bool resultStatus;
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
#include "imguploadertool.h"
|
||||
|
||||
ImgUploaderTool::ImgUploaderTool(QObject* parent)
|
||||
: AbstractActionTool(parent)
|
||||
{}
|
||||
|
||||
void ImgUploaderTool::setCapture(const QPixmap& pixmap)
|
||||
{
|
||||
m_capture = pixmap;
|
||||
}
|
||||
|
||||
void ImgUploaderTool::pressed(const CaptureContext& context)
|
||||
{
|
||||
m_capture = context.selectedScreenshotArea();
|
||||
emit requestAction(REQ_CAPTURE_DONE_OK);
|
||||
emit requestAction(REQ_ADD_EXTERNAL_WIDGETS);
|
||||
}
|
||||
|
||||
QString ImgUploaderTool::name() const
|
||||
{
|
||||
return tr("Image uploader tool");
|
||||
}
|
||||
|
||||
const QPixmap& ImgUploaderTool::capture()
|
||||
{
|
||||
return m_capture;
|
||||
}
|
||||
|
||||
QIcon ImgUploaderTool::icon(const QColor& background, bool inEditor) const
|
||||
{
|
||||
Q_UNUSED(inEditor);
|
||||
return QIcon(iconPath(background) + "cloud-upload.svg");
|
||||
}
|
||||
|
||||
bool ImgUploaderTool::closeOnButtonPressed() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ToolType ImgUploaderTool::nameID() const
|
||||
{
|
||||
return ToolType::UPLOAD;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef IMGUPLOADERTOOL_H
|
||||
#define IMGUPLOADERTOOL_H
|
||||
|
||||
#include "src/tools/abstractactiontool.h"
|
||||
|
||||
class ImgUploaderTool : public AbstractActionTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImgUploaderTool(QObject* parent = nullptr);
|
||||
|
||||
bool closeOnButtonPressed() const;
|
||||
|
||||
QString name() const override;
|
||||
QIcon icon(const QColor& background, bool inEditor) const override;
|
||||
|
||||
void setCapture(const QPixmap& pixmap);
|
||||
const QPixmap& capture();
|
||||
|
||||
public slots:
|
||||
void pressed(const CaptureContext& context) override;
|
||||
|
||||
protected:
|
||||
ToolType nameID() const override;
|
||||
|
||||
private:
|
||||
QPixmap m_capture;
|
||||
};
|
||||
|
||||
#endif // IMGUPLOADERTOOL_H
|
||||
@@ -1,126 +0,0 @@
|
||||
// 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 "imguruploader.h"
|
||||
#include "src/core/controller.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "src/utils/filenamehandler.h"
|
||||
#include "src/utils/history.h"
|
||||
#include "src/utils/systemnotification.h"
|
||||
#include "src/widgets/imagelabel.h"
|
||||
#include "src/widgets/loadspinner.h"
|
||||
#include "src/widgets/notificationwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QClipboard>
|
||||
#include <QDesktopServices>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QMimeData>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QShortcut>
|
||||
#include <QUrlQuery>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ImgurUploader::ImgurUploader(const QPixmap& capture, QWidget* parent)
|
||||
: ImgUploader(capture, parent)
|
||||
{
|
||||
setWindowTitle(tr("Upload to Imgur"));
|
||||
|
||||
m_NetworkAM = new QNetworkAccessManager(this);
|
||||
connect(m_NetworkAM,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&ImgurUploader::handleReply);
|
||||
}
|
||||
|
||||
void ImgurUploader::handleReply(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
|
||||
QJsonObject json = response.object();
|
||||
QJsonObject data = json[QStringLiteral("data")].toObject();
|
||||
setImageUrl(data[QStringLiteral("link")].toString());
|
||||
m_deleteToken = data[QStringLiteral("deletehash")].toString();
|
||||
|
||||
m_deleteImageURL.setUrl(
|
||||
QStringLiteral("https://imgur.com/delete/%1").arg(m_deleteToken));
|
||||
|
||||
// save history
|
||||
QString imageName = imageUrl().toString();
|
||||
int lastSlash = imageName.lastIndexOf("/");
|
||||
if (lastSlash >= 0) {
|
||||
imageName = imageName.mid(lastSlash + 1);
|
||||
}
|
||||
m_storageImageName = imageName;
|
||||
|
||||
// save image to history
|
||||
History history;
|
||||
imageName = history.packFileName(
|
||||
SCREENSHOT_STORAGE_TYPE_IMGUR, m_deleteToken, imageName);
|
||||
history.save(pixmap(), imageName);
|
||||
resultStatus = true;
|
||||
|
||||
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) {
|
||||
QApplication::clipboard()->setText(imageUrl().toString());
|
||||
SystemNotification().sendMessage(
|
||||
QObject::tr("URL copied to clipboard."));
|
||||
Controller::getInstance()->updateRecentScreenshots();
|
||||
close();
|
||||
} else {
|
||||
onUploadOk();
|
||||
}
|
||||
} else {
|
||||
setInfoLabelText(reply->errorString());
|
||||
}
|
||||
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
|
||||
}
|
||||
|
||||
void ImgurUploader::upload()
|
||||
{
|
||||
QByteArray byteArray;
|
||||
QBuffer buffer(&byteArray);
|
||||
pixmap().save(&buffer, "PNG");
|
||||
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem(QStringLiteral("title"),
|
||||
QStringLiteral("flameshot_screenshot"));
|
||||
QString description = FileNameHandler().parsedPattern();
|
||||
urlQuery.addQueryItem(QStringLiteral("description"), description);
|
||||
|
||||
QUrl url(QStringLiteral("https://api.imgur.com/3/image"));
|
||||
url.setQuery(urlQuery);
|
||||
QNetworkRequest request(url);
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/application/x-www-form-urlencoded");
|
||||
request.setRawHeader(
|
||||
"Authorization",
|
||||
QStringLiteral("Client-ID %1").arg(IMGUR_CLIENT_ID).toUtf8());
|
||||
|
||||
m_NetworkAM->post(request, byteArray);
|
||||
}
|
||||
|
||||
void ImgurUploader::deleteImageOnStorage()
|
||||
{
|
||||
bool successful = QDesktopServices::openUrl(m_deleteImageURL);
|
||||
if (!successful) {
|
||||
showNotificationMessage(tr("Unable to open the URL."));
|
||||
}
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
# Flameshot Amazon S3 Storage
|
||||
|
||||
Flameshot S3 storage is using presigned multipart upload, the idea is explained here:
|
||||
|
||||
* [Upload files to AWS S3 using pre-signed POST data and a Lambda function](Upload files to AWS S3 using pre-signed POST data and a Lambda function)
|
||||
* [Uploading Objects to S3 Using One-Time Presigned URLs](https://medium.com/@laardee/uploading-objects-to-s3-using-one-time-presigned-urls-4374943f0801)
|
||||
|
||||
Supported operations:
|
||||
- upload
|
||||
- delete
|
||||
|
||||
## Upload
|
||||
|
||||
### Step 1 - get one-time presigned url
|
||||
|
||||
C++ example:
|
||||
```c++
|
||||
QUrl creds(m_s3Settings.credsUrl());
|
||||
QNetworkRequest requestCreds(creds);
|
||||
if (m_s3Settings.xApiKey().length() > 0) {
|
||||
requestCreds.setRawHeader(
|
||||
QByteArray("X-API-Key"),
|
||||
QByteArray(m_s3Settings.xApiKey().toLocal8Bit()));
|
||||
}
|
||||
m_NetworkAMGetCreds->get(requestCreds);
|
||||
```
|
||||
|
||||
Shell example:
|
||||
```shell script
|
||||
curl --location --request GET "https://api.img.examples.flameshot.org/v2/image/" \
|
||||
--header "X-API-Key: aws-secret-key"
|
||||
```
|
||||
|
||||
Response example:
|
||||
```json
|
||||
{
|
||||
"formData": {
|
||||
"url": "https://screenshots-example-flameshot.org.s3-accelerate.amazonaws.com",
|
||||
"fields": {
|
||||
"acl": "private",
|
||||
"Content-Type": "image/png",
|
||||
"Key": "some-key.png",
|
||||
"tagging": "<Tagging><TagSet><Tag><Key>deleteToken</Key><Value>some-value</Value></Tag></TagSet></Tagging>",
|
||||
"bucket": "screenshots-example-flameshot.org",
|
||||
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
|
||||
"X-Amz-Credential": "some-data/eu-central-1/s3/aws4_request",
|
||||
"X-Amz-Date": "20200929T100000Z",
|
||||
"X-Amz-Security-Token": "some-security-token",
|
||||
"Policy": "some-policy",
|
||||
"X-Amz-Signature": "some-signature"
|
||||
}
|
||||
},
|
||||
"resultURL": "https://img.examples.flameshot.org/some-key.png",
|
||||
"deleteToken": "some-delete-token-x"
|
||||
}
|
||||
```
|
||||
|
||||
* `resultURL` - url to s3 bucket to upload image directly to Amazon
|
||||
* `deleteToken` - contains token which will be required for implementing `DELETE` operation.
|
||||
|
||||
### Step 2 - do direct multi-part upload to the s3 bucket
|
||||
Upload to S3 bucket
|
||||
|
||||
Send `POST` request to Amazon S3, based on the results from the `Step 1`.
|
||||
|
||||
C++ example:
|
||||
```c++
|
||||
void ImgS3Uploader::uploadToS3(QJsonDocument& response)
|
||||
{
|
||||
// set paramets from "fields"
|
||||
QHttpMultiPart* multiPart =
|
||||
new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
// read JSON response
|
||||
QJsonObject json = response.object();
|
||||
QString resultUrl = json["resultURL"].toString();
|
||||
QJsonObject formData = json["formData"].toObject();
|
||||
QString url = formData["url"].toString();
|
||||
m_deleteToken = json["deleteToken"].toString();
|
||||
|
||||
QJsonObject fields = formData["fields"].toObject();
|
||||
foreach (auto key, fields.keys()) {
|
||||
QString field = fields[key].toString();
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"" + key + "\""));
|
||||
part.setBody(field.toLatin1());
|
||||
multiPart->append(part);
|
||||
}
|
||||
|
||||
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);
|
||||
pixmap().save(&buffer, "PNG");
|
||||
|
||||
imagePart.setBody(byteArray);
|
||||
multiPart->append(imagePart);
|
||||
|
||||
setImageUrl(QUrl(resultUrl));
|
||||
|
||||
QUrl qUrl(url);
|
||||
QNetworkRequest request(qUrl);
|
||||
|
||||
// upload
|
||||
m_NetworkAMUpload->post(request, multiPart);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# Delete
|
||||
|
||||
Shell example:
|
||||
```shell script
|
||||
curl --location --request DELETE 'https://api.img.rnd.namecheap.net/v2/image/sH5M3zETezZgA95mmKCMfq.png' \
|
||||
--header 'X-API-Key: aws-secret-key' \
|
||||
--header 'Authorization: Bearer some-delete-token-x'
|
||||
```
|
||||
Where `some-delete-token-x` is a value from the request from the `step 1`
|
||||
|
||||
C++ example:
|
||||
```c++
|
||||
QNetworkRequest request;
|
||||
m_storageImageName = fileName;
|
||||
m_deleteToken = deleteToken;
|
||||
request.setUrl(m_s3Settings.credsUrl().toUtf8() + fileName);
|
||||
request.setRawHeader("X-API-Key", m_s3Settings.xApiKey().toLatin1());
|
||||
request.setRawHeader("Authorization", "Bearer " + deleteToken.toLatin1());
|
||||
m_NetworkAMRemove->deleteResource(request);
|
||||
```
|
||||
@@ -1,25 +0,0 @@
|
||||
[General]
|
||||
; Lock storage selection for the enterprise users
|
||||
; (it will lock to the default storage)
|
||||
STORAGE_LOCK=true
|
||||
|
||||
; PROXY SETTINGS
|
||||
;HTTP_PROXY_HOST=0.0.0.0
|
||||
;HTTP_PROXY_PORT=3128
|
||||
|
||||
; No authentification USER and PASSWORD should be empty
|
||||
;HTTP_PROXY_USER=
|
||||
;HTTP_PROXY_PASSWORD=
|
||||
|
||||
;HTTP_PROXY_TYPE=3
|
||||
; Proxy Types (3 is default):
|
||||
; 0 Proxy is determined based on the application proxy set using setApplicationProxy()
|
||||
; 1 Socks5 proxying is used
|
||||
; 3 HTTP transparent proxying is used
|
||||
; 4 Proxying for HTTP requests only
|
||||
; 5 Proxying for FTP requests only
|
||||
|
||||
[S3]
|
||||
S3_URL=https://api.flameshot.org/
|
||||
S3_CREDS_URL=https://api.img.flameshot.org/
|
||||
S3_X_API_KEY=amazon-secret-key
|
||||
@@ -1 +0,0 @@
|
||||
tests/*
|
||||
@@ -1,122 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const uuid = require('short-uuid');
|
||||
const AWS = require('aws-sdk');
|
||||
AWS.config.update({ region: process.env.AWS_REGION || 'us-east-1' });
|
||||
const s3 = new AWS.S3();
|
||||
const cloudfront = new AWS.CloudFront();
|
||||
|
||||
const allowedImageType = 'png';
|
||||
|
||||
// Main Lambda entry point
|
||||
exports.handler = async (event) => {
|
||||
console.log('Event: ', event);
|
||||
|
||||
let result;
|
||||
if (event.resource === '/v2/image/{fileName}' && event.httpMethod === 'DELETE') {
|
||||
let token = (event.headers.Authorization && event.headers.Authorization.split(' ')[1]) || '';
|
||||
result = await deleteObject(event.pathParameters.fileName, token);
|
||||
if (result === false) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
isBase64Encoded: false,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
},
|
||||
body: 'Bad request'
|
||||
};
|
||||
}
|
||||
} else {
|
||||
result = await getUploadDetails(event.resource === '/v2/image' ? 2 : 1);
|
||||
}
|
||||
|
||||
console.log('Result: ', result);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
isBase64Encoded: false,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
},
|
||||
body: JSON.stringify(result)
|
||||
};
|
||||
};
|
||||
|
||||
const getUploadDetails = async function(version) {
|
||||
const actionId = uuid.generate();
|
||||
const deleteToken = uuid.generate();
|
||||
|
||||
const s3Params = {
|
||||
Bucket: process.env.UploadBucket,
|
||||
Fields: {
|
||||
Key: `${actionId}.${allowedImageType}`,
|
||||
},
|
||||
Conditions: [
|
||||
[ 'eq', '$acl', 'private' ],
|
||||
[ 'eq', '$Content-Type', `image/${allowedImageType}` ],
|
||||
[ 'content-length-range', 0, 10485760 ], //allows a file size from 0B to 10 MiB
|
||||
],
|
||||
Expires: 60,
|
||||
};
|
||||
|
||||
if (version === 2) {
|
||||
s3Params.Fields.tagging = getDeleteTags(deleteToken);
|
||||
}
|
||||
|
||||
console.log('getUploadURL: ', s3Params);
|
||||
|
||||
const signedForm = await createPresignedPost(s3Params);
|
||||
signedForm.url = `https://${process.env.UploadBucket}.s3-accelerate.amazonaws.com`;
|
||||
signedForm.fields = Object.assign({
|
||||
acl: 'private',
|
||||
'Content-Type': `image/${allowedImageType}`,
|
||||
}, signedForm.fields);
|
||||
|
||||
const uploadDetails = {
|
||||
formData: signedForm,
|
||||
resultURL: `${process.env.BasePath}${s3Params.Fields.Key}`
|
||||
};
|
||||
|
||||
if (version === 2) {
|
||||
uploadDetails.deleteToken = deleteToken;
|
||||
}
|
||||
|
||||
return uploadDetails;
|
||||
};
|
||||
|
||||
const deleteObject = async (key, token) => {
|
||||
const s3ObjectParams = {Bucket: process.env.UploadBucket, Key: key};
|
||||
const {TagSet: tags} = await s3.getObjectTagging(s3ObjectParams).promise();
|
||||
|
||||
const storedTokenInfo = tags.find(v => v.Key === 'deleteToken');
|
||||
if (storedTokenInfo === undefined) {
|
||||
console.log(`Unable to find storedTokenInfo for requested key "${key}"`);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (storedTokenInfo.Value !== token) {
|
||||
console.log(`storedTokenInfo != passed token: ${storedTokenInfo.Value} != ${token}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
await s3.deleteObject(s3ObjectParams).promise();
|
||||
await cloudfront.createInvalidation({
|
||||
DistributionId: process.env.DistributionId,
|
||||
InvalidationBatch: {
|
||||
CallerReference: uuid.generate(),
|
||||
Paths: {
|
||||
Quantity: 1,
|
||||
Items: [`/${key}`]
|
||||
}
|
||||
}
|
||||
}).promise();
|
||||
|
||||
return {status: 'ok'}
|
||||
};
|
||||
|
||||
const getDeleteTags = (token) => `<Tagging><TagSet><Tag><Key>deleteToken</Key><Value>${token}</Value></Tag></TagSet></Tagging>`;
|
||||
|
||||
const createPresignedPost = params =>
|
||||
new Promise((resolve, reject) =>
|
||||
s3.createPresignedPost( params, (err, data) => err ? reject(err) : resolve(data) )
|
||||
);
|
||||
@@ -1,125 +0,0 @@
|
||||
{
|
||||
"name": "none",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"any-base": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
|
||||
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
|
||||
},
|
||||
"aws-sdk": {
|
||||
"version": "2.700.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.700.0.tgz",
|
||||
"integrity": "sha512-faBkr/D3IavfL2mwst4/thiKsHkN8YCwU9927Mkiushbe7n4UXxlcNf7LnVxFyjr3WIf4KfziSw4bajRAiAjYA==",
|
||||
"requires": {
|
||||
"buffer": "4.9.2",
|
||||
"events": "1.1.1",
|
||||
"ieee754": "1.1.13",
|
||||
"jmespath": "0.15.0",
|
||||
"querystring": "0.2.0",
|
||||
"sax": "1.2.1",
|
||||
"url": "0.10.3",
|
||||
"uuid": "3.3.2",
|
||||
"xml2js": "0.4.19"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
||||
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"base64-js": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
|
||||
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
|
||||
},
|
||||
"buffer": {
|
||||
"version": "4.9.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
||||
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4",
|
||||
"isarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"events": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
|
||||
"integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
|
||||
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
},
|
||||
"jmespath": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
|
||||
"integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
|
||||
},
|
||||
"punycode": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
|
||||
"integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
"integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
||||
},
|
||||
"short-uuid": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/short-uuid/-/short-uuid-3.1.1.tgz",
|
||||
"integrity": "sha512-7dI69xtJYpTIbg44R6JSgrbDtZFuZ9vAwwmnF/L0PinykbFrhQ7V8omKsQcVw1TP0nYJ7uQp1PN6/aVMkzQFGQ==",
|
||||
"requires": {
|
||||
"any-base": "^1.1.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
|
||||
"integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
|
||||
"requires": {
|
||||
"punycode": "1.3.2",
|
||||
"querystring": "0.2.0"
|
||||
}
|
||||
},
|
||||
"xml2js": {
|
||||
"version": "0.4.19",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
|
||||
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
|
||||
"requires": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~9.0.1"
|
||||
}
|
||||
},
|
||||
"xmlbuilder": {
|
||||
"version": "9.0.7",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
|
||||
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"name": "flameshot-storage-s3",
|
||||
"author": {
|
||||
"name": "Namecheap, Inc.",
|
||||
"address": "https://www.namecheap.com/"
|
||||
},
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "AWS Lambda functions for the Flameshot S3 Storage.",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
"start": "node testHarness.js",
|
||||
"pack": "zip -r ../.infrastructure/lambda.zip ./",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"license": "GPL v3",
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.478.0",
|
||||
"short-uuid": "^3.1.1"
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
without restriction, including without limitation the rights to use, copy, modify,
|
||||
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// For local testing
|
||||
|
||||
const { handler } = require('./app')
|
||||
|
||||
const main = async () => {
|
||||
await handler()
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
#include "imgs3settings.h"
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
|
||||
ImgS3Settings::ImgS3Settings()
|
||||
{
|
||||
initSettings();
|
||||
|
||||
// get s3 credentials
|
||||
m_settings->beginGroup("S3");
|
||||
m_credsUrl = m_settings->value("S3_CREDS_URL").toString();
|
||||
m_credsUrl =
|
||||
m_credsUrl +
|
||||
((m_credsUrl.length() > 0 && m_credsUrl[m_credsUrl.length() - 1] == '/')
|
||||
? ""
|
||||
: "/") +
|
||||
S3_API_IMG_PATH;
|
||||
|
||||
m_xApiKey = m_settings->value("S3_X_API_KEY").toString();
|
||||
|
||||
m_url = m_settings->value("S3_URL").toString();
|
||||
m_url =
|
||||
m_url +
|
||||
((m_url.length() > 0 && m_url[m_url.length() - 1] == '/') ? "" : "/");
|
||||
|
||||
m_settings->endGroup();
|
||||
}
|
||||
|
||||
QSettings* ImgS3Settings::settings()
|
||||
{
|
||||
return m_settings;
|
||||
}
|
||||
|
||||
void ImgS3Settings::initSettings()
|
||||
{
|
||||
// get s3 settings
|
||||
QString configIniPath = QDir(QDir::currentPath()).filePath("config.ini");
|
||||
if (!(QFileInfo::exists(configIniPath) &&
|
||||
QFileInfo(configIniPath).isFile())) {
|
||||
#if defined(Q_OS_LINUX) || defined(Q_OS_UNIX)
|
||||
configIniPath = "/etc/flameshot/config.ini";
|
||||
#elif defined(Q_OS_WIN)
|
||||
// calculate workdir for flameshot on startup if is not set yet
|
||||
QSettings bootUpSettings(
|
||||
"HKEY_CURRENT_"
|
||||
"USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
|
||||
QSettings::NativeFormat);
|
||||
QFileInfo fi(bootUpSettings.value("Flameshot").toString());
|
||||
configIniPath = QDir(fi.absolutePath()).filePath("config.ini");
|
||||
#endif
|
||||
}
|
||||
m_settings = new QSettings(configIniPath, QSettings::IniFormat);
|
||||
}
|
||||
|
||||
const QString& ImgS3Settings::credsUrl()
|
||||
{
|
||||
return m_credsUrl;
|
||||
}
|
||||
|
||||
const QString& ImgS3Settings::xApiKey()
|
||||
{
|
||||
return m_xApiKey;
|
||||
}
|
||||
|
||||
const QString& ImgS3Settings::url()
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef IMGS3SETTINGS_H
|
||||
#define IMGS3SETTINGS_H
|
||||
|
||||
#define S3_API_IMG_PATH "v2/image/"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class QSettings;
|
||||
|
||||
class ImgS3Settings
|
||||
{
|
||||
public:
|
||||
ImgS3Settings();
|
||||
|
||||
const QString& credsUrl();
|
||||
const QString& xApiKey();
|
||||
const QString& url();
|
||||
QSettings* settings();
|
||||
|
||||
private:
|
||||
void initSettings();
|
||||
|
||||
// class members
|
||||
QSettings* m_settings;
|
||||
QString m_credsUrl;
|
||||
QString m_xApiKey;
|
||||
QString m_url;
|
||||
};
|
||||
|
||||
#endif // IMGS3SETTINGS_H
|
||||
@@ -1,397 +0,0 @@
|
||||
// Copyright(c) 2017-2019 Alejandro Sirgo Rica & Contributors
|
||||
// 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 "imgs3settings.h"
|
||||
#include "src/core/controller.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "src/utils/history.h"
|
||||
#include "src/utils/systemnotification.h"
|
||||
#include "src/widgets/imagelabel.h"
|
||||
#include "src/widgets/loadspinner.h"
|
||||
#include "src/widgets/notificationwidget.h"
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QClipboard>
|
||||
#include <QDir>
|
||||
#include <QHttpMultiPart>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QMimeData>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QPushButton>
|
||||
#include <QShortcut>
|
||||
#include <QUrlQuery>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ImgS3Uploader::ImgS3Uploader(const QPixmap& capture, QWidget* parent)
|
||||
: ImgUploader(capture, parent)
|
||||
{
|
||||
init(tr("Upload image to S3"), tr("Uploading Image"));
|
||||
}
|
||||
|
||||
ImgS3Uploader::ImgS3Uploader(QWidget* parent)
|
||||
: ImgUploader(parent)
|
||||
{
|
||||
init(tr("Delete image from S3"), tr("Deleting image..."));
|
||||
}
|
||||
|
||||
ImgS3Uploader::~ImgS3Uploader()
|
||||
{
|
||||
clearProxy();
|
||||
}
|
||||
|
||||
void ImgS3Uploader::init(const QString& title, const QString& label)
|
||||
{
|
||||
m_proxy = nullptr;
|
||||
m_NetworkAMUpload = nullptr;
|
||||
m_NetworkAMGetCreds = nullptr;
|
||||
m_NetworkAMRemove = nullptr;
|
||||
|
||||
resultStatus = false;
|
||||
setWindowTitle(title);
|
||||
setWindowIcon(QIcon(":img/app/flameshot.svg"));
|
||||
}
|
||||
|
||||
QNetworkProxy* ImgS3Uploader::proxy()
|
||||
{
|
||||
if (m_proxy == nullptr) {
|
||||
initProxy();
|
||||
}
|
||||
return m_proxy;
|
||||
}
|
||||
|
||||
QNetworkProxy* ImgS3Uploader::initProxy()
|
||||
{
|
||||
// get s3 settings
|
||||
ImgS3Settings imgS3Settings;
|
||||
|
||||
// get proxy settings from "config.ini" file
|
||||
QSettings* settings = imgS3Settings.settings();
|
||||
QString httpProxyHost = settings->value("HTTP_PROXY_HOST").toString();
|
||||
|
||||
if (httpProxyHost.length() > 0) {
|
||||
m_proxy = new QNetworkProxy();
|
||||
if (settings->contains("HTTP_PROXY_TYPE")) {
|
||||
switch (settings->value("HTTP_PROXY_TYPE").toInt()) {
|
||||
case 0:
|
||||
m_proxy->setType(QNetworkProxy::DefaultProxy);
|
||||
break;
|
||||
case 1:
|
||||
m_proxy->setType(QNetworkProxy::Socks5Proxy);
|
||||
break;
|
||||
case 2:
|
||||
m_proxy->setType(QNetworkProxy::NoProxy);
|
||||
break;
|
||||
case 4:
|
||||
m_proxy->setType(QNetworkProxy::HttpCachingProxy);
|
||||
break;
|
||||
case 5:
|
||||
m_proxy->setType(QNetworkProxy::FtpCachingProxy);
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
m_proxy->setType(QNetworkProxy::HttpProxy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_proxy->setHostName(httpProxyHost);
|
||||
int nProxyPort = 3128;
|
||||
if (settings->contains("HTTP_PROXY_PORT")) {
|
||||
nProxyPort = settings->value("HTTP_PROXY_PORT").toInt();
|
||||
}
|
||||
m_proxy->setPort(nProxyPort);
|
||||
|
||||
if (settings->contains("HTTP_PROXY_USER")) {
|
||||
qDebug() << "Proxy user"
|
||||
<< settings->value("HTTP_PROXY_PASSWORD").toString();
|
||||
m_proxy->setUser(settings->value("HTTP_PROXY_USER").toString());
|
||||
}
|
||||
if (settings->contains("HTTP_PROXY_PASSWORD")) {
|
||||
qDebug() << "Proxy password is not empty";
|
||||
m_proxy->setPassword(
|
||||
settings->value("HTTP_PROXY_PASSWORD").toString());
|
||||
}
|
||||
} else {
|
||||
// Get proxy settings from OS settings
|
||||
QNetworkProxyQuery q(QUrl(m_s3Settings.credsUrl().toUtf8()));
|
||||
q.setQueryType(QNetworkProxyQuery::UrlRequest);
|
||||
q.setProtocolTag("http");
|
||||
|
||||
QList<QNetworkProxy> proxies =
|
||||
QNetworkProxyFactory::systemProxyForQuery(q);
|
||||
if (proxies.size() > 0 && proxies[0].type() != QNetworkProxy::NoProxy) {
|
||||
m_proxy = new QNetworkProxy();
|
||||
m_proxy->setHostName(proxies[0].hostName());
|
||||
m_proxy->setPort(proxies[0].port());
|
||||
m_proxy->setType(proxies[0].type());
|
||||
m_proxy->setUser(proxies[0].user());
|
||||
m_proxy->setPassword(proxies[0].password());
|
||||
}
|
||||
}
|
||||
#ifdef QT_DEBUG
|
||||
if (m_proxy != nullptr) {
|
||||
qDebug() << "Using proxy server";
|
||||
qDebug() << "proxy host:" << m_proxy->hostName();
|
||||
qDebug() << "proxy port:" << m_proxy->port();
|
||||
qDebug() << "proxy type:" << m_proxy->type();
|
||||
qDebug() << "proxy user:"
|
||||
<< (m_proxy->user().length() > 0 ? m_proxy->user()
|
||||
: "no user");
|
||||
qDebug() << "proxy password:"
|
||||
<< (m_proxy->password().length() > 0 ? "***" : "no password");
|
||||
} else {
|
||||
qDebug() << "No proxy";
|
||||
}
|
||||
#endif
|
||||
return m_proxy;
|
||||
}
|
||||
|
||||
void ImgS3Uploader::clearProxy()
|
||||
{
|
||||
if (m_proxy != nullptr) {
|
||||
delete m_proxy;
|
||||
m_proxy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ImgS3Uploader::handleReplyUpload(QNetworkReply* reply)
|
||||
{
|
||||
hideSpinner();
|
||||
m_storageImageName.clear();
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
// save history
|
||||
QString imageName = imageUrl().toString();
|
||||
int lastSlash = imageName.lastIndexOf("/");
|
||||
if (lastSlash >= 0) {
|
||||
imageName = imageName.mid(lastSlash + 1);
|
||||
}
|
||||
m_storageImageName = imageName;
|
||||
|
||||
// save image to history
|
||||
History history;
|
||||
imageName = history.packFileName(
|
||||
SCREENSHOT_STORAGE_TYPE_S3, m_deleteToken, imageName);
|
||||
history.save(pixmap(), imageName);
|
||||
resultStatus = true;
|
||||
|
||||
// Copy url to clipboard if required
|
||||
if (ConfigHandler().copyAndCloseAfterUploadEnabled()) {
|
||||
QApplication::clipboard()->setText(imageUrl().toString());
|
||||
SystemNotification().sendMessage(tr("URL copied to clipboard."));
|
||||
Controller::getInstance()->updateRecentScreenshots();
|
||||
close();
|
||||
} else {
|
||||
onUploadOk();
|
||||
}
|
||||
} else {
|
||||
QString reason =
|
||||
reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute)
|
||||
.toString();
|
||||
setInfoLabelText(reply->errorString());
|
||||
}
|
||||
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
|
||||
}
|
||||
|
||||
void ImgS3Uploader::handleReplyDeleteResource(QNetworkReply* reply)
|
||||
{
|
||||
auto replyError = reply->error();
|
||||
if (replyError == QNetworkReply::NoError) {
|
||||
removeImagePreview();
|
||||
} else {
|
||||
hide();
|
||||
|
||||
// generate error message
|
||||
QString message =
|
||||
tr("Unable to remove screenshot from the remote storage.");
|
||||
if (replyError == QNetworkReply::UnknownNetworkError) {
|
||||
message += "\n" + tr("Network error");
|
||||
} else if (replyError == QNetworkReply::UnknownServerError) {
|
||||
message += "\n" + tr("Possibly it doesn't exist anymore");
|
||||
}
|
||||
message += "\n\n" + reply->errorString();
|
||||
message +=
|
||||
"\n\n" +
|
||||
tr("Do you want to remove screenshot from local history anyway?");
|
||||
|
||||
if (QMessageBox::Yes ==
|
||||
QMessageBox::question(NULL,
|
||||
tr("Remove screenshot from history?"),
|
||||
message,
|
||||
QMessageBox::Yes | QMessageBox::No)) {
|
||||
removeImagePreview();
|
||||
}
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
void ImgS3Uploader::handleReplyGetCreds(QNetworkReply* reply)
|
||||
{
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
|
||||
uploadToS3(response);
|
||||
} else {
|
||||
if (m_s3Settings.credsUrl().length() == 0) {
|
||||
setInfoLabelText(
|
||||
tr("S3 Creds URL is not found in your configuration file"));
|
||||
} else {
|
||||
setInfoLabelText(reply->errorString());
|
||||
}
|
||||
}
|
||||
new QShortcut(Qt::Key_Escape, this, SLOT(close()));
|
||||
}
|
||||
|
||||
void ImgS3Uploader::uploadToS3(QJsonDocument& response)
|
||||
{
|
||||
// set paramets from "fields"
|
||||
QHttpMultiPart* multiPart =
|
||||
new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
// read JSON response
|
||||
QJsonObject json = response.object();
|
||||
QString resultUrl = json["resultURL"].toString();
|
||||
QJsonObject formData = json["formData"].toObject();
|
||||
QString url = formData["url"].toString();
|
||||
m_deleteToken = json["deleteToken"].toString();
|
||||
|
||||
QJsonObject fields = formData["fields"].toObject();
|
||||
foreach (auto key, fields.keys()) {
|
||||
QString field = fields[key].toString();
|
||||
QHttpPart part;
|
||||
part.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant("form-data; name=\"" + key + "\""));
|
||||
part.setBody(field.toLatin1());
|
||||
multiPart->append(part);
|
||||
}
|
||||
|
||||
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);
|
||||
pixmap().save(&buffer, "PNG");
|
||||
|
||||
imagePart.setBody(byteArray);
|
||||
multiPart->append(imagePart);
|
||||
|
||||
setImageUrl(QUrl(resultUrl));
|
||||
|
||||
QUrl qUrl(url);
|
||||
QNetworkRequest request(qUrl);
|
||||
|
||||
// upload
|
||||
m_NetworkAMUpload->post(request, multiPart);
|
||||
}
|
||||
|
||||
void ImgS3Uploader::deleteResource(const QString& fileName,
|
||||
const QString& deleteToken)
|
||||
{
|
||||
// read network settings on each call to simplify configuration management
|
||||
// without restarting
|
||||
clearProxy();
|
||||
if (m_NetworkAMRemove != nullptr) {
|
||||
delete m_NetworkAMRemove;
|
||||
m_NetworkAMRemove = nullptr;
|
||||
}
|
||||
m_NetworkAMRemove = new QNetworkAccessManager(this);
|
||||
connect(m_NetworkAMRemove,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&ImgS3Uploader::handleReplyDeleteResource);
|
||||
if (proxy() != nullptr) {
|
||||
m_NetworkAMRemove->setProxy(*proxy());
|
||||
}
|
||||
|
||||
QNetworkRequest request;
|
||||
m_storageImageName = fileName;
|
||||
m_deleteToken = deleteToken;
|
||||
request.setUrl(m_s3Settings.credsUrl().toUtf8() + fileName);
|
||||
request.setRawHeader("X-API-Key", m_s3Settings.xApiKey().toLatin1());
|
||||
request.setRawHeader("Authorization", "Bearer " + deleteToken.toLatin1());
|
||||
m_NetworkAMRemove->deleteResource(request);
|
||||
}
|
||||
|
||||
void ImgS3Uploader::upload()
|
||||
{
|
||||
m_deleteToken.clear();
|
||||
m_storageImageName.clear();
|
||||
|
||||
// read network settings on each call to simplify configuration management
|
||||
// without restarting init creds and upload network access managers
|
||||
clearProxy();
|
||||
if (m_NetworkAMGetCreds != nullptr) {
|
||||
delete m_NetworkAMGetCreds;
|
||||
m_NetworkAMGetCreds = nullptr;
|
||||
}
|
||||
m_NetworkAMGetCreds = new QNetworkAccessManager(this);
|
||||
connect(m_NetworkAMGetCreds,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&ImgS3Uploader::handleReplyGetCreds);
|
||||
|
||||
if (m_NetworkAMUpload != nullptr) {
|
||||
delete m_NetworkAMUpload;
|
||||
m_NetworkAMUpload = nullptr;
|
||||
}
|
||||
m_NetworkAMUpload = new QNetworkAccessManager(this);
|
||||
connect(m_NetworkAMUpload,
|
||||
&QNetworkAccessManager::finished,
|
||||
this,
|
||||
&ImgS3Uploader::handleReplyUpload);
|
||||
if (proxy() != nullptr) {
|
||||
m_NetworkAMGetCreds->setProxy(*proxy());
|
||||
m_NetworkAMUpload->setProxy(*proxy());
|
||||
}
|
||||
|
||||
// get creads
|
||||
QUrl creds(m_s3Settings.credsUrl());
|
||||
QNetworkRequest requestCreds(creds);
|
||||
if (m_s3Settings.xApiKey().length() > 0) {
|
||||
requestCreds.setRawHeader(
|
||||
QByteArray("X-API-Key"),
|
||||
QByteArray(m_s3Settings.xApiKey().toLocal8Bit()));
|
||||
}
|
||||
m_NetworkAMGetCreds->get(requestCreds);
|
||||
}
|
||||
|
||||
void ImgS3Uploader::removeImagePreview()
|
||||
{
|
||||
// remove local file
|
||||
History history;
|
||||
QString packedFileName = history.packFileName(
|
||||
SCREENSHOT_STORAGE_TYPE_S3, m_deleteToken, m_storageImageName);
|
||||
QString fullFileName = history.path() + packedFileName;
|
||||
|
||||
QFile file(fullFileName);
|
||||
if (file.exists()) {
|
||||
file.remove();
|
||||
}
|
||||
m_deleteToken.clear();
|
||||
m_storageImageName.clear();
|
||||
resultStatus = true;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
// 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
|
||||
|
||||
#define S3_API_IMG_PATH "v2/image/"
|
||||
|
||||
#include "../imguploader.h"
|
||||
#include "imgs3settings.h"
|
||||
#include <QUrl>
|
||||
#include <QWidget>
|
||||
|
||||
class QNetworkReply;
|
||||
class QNetworkProxy;
|
||||
class QNetworkAccessManager;
|
||||
class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QUrl;
|
||||
class NotificationWidget;
|
||||
class ImageLabel;
|
||||
|
||||
class ImgS3Uploader : public ImgUploader
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ImgS3Uploader(const QPixmap& capture, QWidget* parent = nullptr);
|
||||
explicit ImgS3Uploader(QWidget* parent = nullptr);
|
||||
~ImgS3Uploader();
|
||||
void upload();
|
||||
void deleteResource(const QString&, const QString&);
|
||||
|
||||
private slots:
|
||||
void handleReplyUpload(QNetworkReply* reply);
|
||||
void handleReplyGetCreds(QNetworkReply* reply);
|
||||
void handleReplyDeleteResource(QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
void init(const QString& title, const QString& label);
|
||||
void uploadToS3(QJsonDocument& response);
|
||||
void removeImagePreview();
|
||||
|
||||
QNetworkProxy* initProxy();
|
||||
void clearProxy();
|
||||
QNetworkProxy* proxy();
|
||||
|
||||
// class members
|
||||
private:
|
||||
ImgS3Settings m_s3Settings;
|
||||
|
||||
QNetworkProxy* m_proxy;
|
||||
QNetworkAccessManager* m_NetworkAMUpload;
|
||||
QNetworkAccessManager* m_NetworkAMGetCreds;
|
||||
QNetworkAccessManager* m_NetworkAMRemove;
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
// 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)
|
||||
: ImgUploaderTool(parent)
|
||||
{}
|
||||
|
||||
QString ImgS3UploaderTool::description() const
|
||||
{
|
||||
return tr("Upload the selection to S3 bucket");
|
||||
}
|
||||
|
||||
QWidget* ImgS3UploaderTool::widget()
|
||||
{
|
||||
ImgS3Uploader* p = new ImgS3Uploader(capture());
|
||||
p->upload();
|
||||
return p;
|
||||
}
|
||||
|
||||
CaptureTool* ImgS3UploaderTool::copy(QObject* parent)
|
||||
{
|
||||
return new ImgS3UploaderTool(parent);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// 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/storage/imguploadertool.h"
|
||||
|
||||
class ImgS3UploaderTool : public ImgUploaderTool
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ImgS3UploaderTool(QObject* parent = nullptr);
|
||||
|
||||
QString description() const override;
|
||||
|
||||
QWidget* widget() override;
|
||||
|
||||
CaptureTool* copy(QObject* parent = nullptr) override;
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
#include "storagemanager.h"
|
||||
#include "imguploader.h"
|
||||
#include "imgur/imguruploadertool.h"
|
||||
#include "s3/imgs3settings.h"
|
||||
#include "s3/imgs3uploadertool.h"
|
||||
#include "src/tools/capturetool.h"
|
||||
#include <QSettings>
|
||||
|
||||
StorageManager::StorageManager() {}
|
||||
|
||||
CaptureTool* StorageManager::imgUploaderTool(const QString& imgUploaderType,
|
||||
QObject* parent)
|
||||
{
|
||||
if (imgUploaderType == SCREENSHOT_STORAGE_TYPE_S3) {
|
||||
return new ImgS3UploaderTool(parent);
|
||||
} else if (imgUploaderType == SCREENSHOT_STORAGE_TYPE_IMGUR) {
|
||||
return new ImgurUploaderTool(parent);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QString& StorageManager::storageUrl(const QString& imgUploaderType)
|
||||
{
|
||||
if (imgUploaderType == SCREENSHOT_STORAGE_TYPE_S3) {
|
||||
ImgS3Settings s3Settings;
|
||||
m_qstr = s3Settings.url();
|
||||
} else if (imgUploaderType == SCREENSHOT_STORAGE_TYPE_IMGUR) {
|
||||
m_qstr = "https://i.imgur.com/";
|
||||
}
|
||||
return m_qstr;
|
||||
}
|
||||
|
||||
const QString& StorageManager::storageDefault()
|
||||
{
|
||||
ImgS3Settings imgS3Settings;
|
||||
if (!imgS3Settings.xApiKey().isEmpty()) {
|
||||
m_qstr = SCREENSHOT_STORAGE_TYPE_S3;
|
||||
} else {
|
||||
m_qstr = SCREENSHOT_STORAGE_TYPE_IMGUR;
|
||||
}
|
||||
return m_qstr;
|
||||
}
|
||||
|
||||
bool StorageManager::storageLocked()
|
||||
{
|
||||
// TODO - move this to some common config file, not a storage specific
|
||||
// configuration file
|
||||
bool res = false;
|
||||
ImgS3Settings imgS3Settings;
|
||||
if (imgS3Settings.settings()->contains("STORAGE_LOCK")) {
|
||||
res = imgS3Settings.settings()
|
||||
->value(QStringLiteral("STORAGE_LOCK"))
|
||||
.toBool();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef STORAGEMANAGER_H
|
||||
#define STORAGEMANAGER_H
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
|
||||
class QObject;
|
||||
class ImgUploader;
|
||||
class CaptureTool;
|
||||
|
||||
class StorageManager
|
||||
{
|
||||
public:
|
||||
explicit StorageManager();
|
||||
|
||||
CaptureTool* imgUploaderTool(const QString& imgUploaderType,
|
||||
QObject* parent = nullptr);
|
||||
const QString& storageUrl(const QString& imgUploaderType);
|
||||
const QString& storageDefault();
|
||||
bool storageLocked();
|
||||
|
||||
private:
|
||||
// class members
|
||||
QString m_qstr;
|
||||
};
|
||||
|
||||
#endif // STORAGEMANAGER_H
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "copy/copytool.h"
|
||||
#include "exit/exittool.h"
|
||||
#include "launcher/applaunchertool.h"
|
||||
#include "imgur/imguruploadertool.h"
|
||||
#include "line/linetool.h"
|
||||
#include "marker/markertool.h"
|
||||
#include "move/movetool.h"
|
||||
@@ -34,7 +35,6 @@
|
||||
#include "selection/selectiontool.h"
|
||||
#include "sizeindicator/sizeindicatortool.h"
|
||||
#include "src/utils/confighandler.h"
|
||||
#include "storage/storagemanager.h"
|
||||
#include "text/texttool.h"
|
||||
#include "undo/undotool.h"
|
||||
|
||||
@@ -45,7 +45,6 @@ ToolFactory::ToolFactory(QObject* parent)
|
||||
CaptureTool* ToolFactory::CreateTool(CaptureToolButton::ButtonType t,
|
||||
QObject* parent)
|
||||
{
|
||||
StorageManager storageManager;
|
||||
CaptureTool* tool;
|
||||
switch (t) {
|
||||
case CaptureToolButton::TYPE_ARROW:
|
||||
@@ -61,8 +60,7 @@ CaptureTool* ToolFactory::CreateTool(CaptureToolButton::ButtonType t,
|
||||
tool = new ExitTool(parent);
|
||||
break;
|
||||
case CaptureToolButton::TYPE_IMAGEUPLOADER:
|
||||
tool = storageManager.imgUploaderTool(
|
||||
ConfigHandler().uploadStorage(), parent);
|
||||
tool = new ImgurUploaderTool(parent);
|
||||
break;
|
||||
case CaptureToolButton::TYPE_DRAWER:
|
||||
tool = new LineTool(parent);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "confighandler.h"
|
||||
#include "src/tools/capturetool.h"
|
||||
#include "src/tools/storage/storagemanager.h"
|
||||
#include "src/utils/configshortcuts.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
@@ -87,11 +86,8 @@ QVector<QColor> ConfigHandler::getUserColors()
|
||||
{
|
||||
QVector<QColor> colors;
|
||||
const QVector<QColor>& defaultColors = {
|
||||
Qt::white, Qt::red, Qt::green, Qt::blue,
|
||||
Qt::black, Qt::darkRed, Qt::darkGreen, Qt::darkBlue,
|
||||
Qt::darkGray, Qt::cyan, Qt::magenta, Qt::yellow,
|
||||
Qt::lightGray, Qt::darkCyan, Qt::darkMagenta, Qt::darkYellow,
|
||||
QColor()
|
||||
Qt::darkRed, Qt::red, Qt::yellow, Qt::green, Qt::darkGreen,
|
||||
Qt::cyan, Qt::blue, Qt::magenta, Qt::darkMagenta, QColor()
|
||||
};
|
||||
|
||||
if (m_settings.contains(QStringLiteral("userColors"))) {
|
||||
@@ -456,34 +452,6 @@ void ConfigHandler::setCopyPathAfterSaveEnabled(const bool value)
|
||||
m_settings.setValue(QStringLiteral("copyPathAfterSave"), value);
|
||||
}
|
||||
|
||||
void ConfigHandler::setUploadStorage(const QString& uploadStorage)
|
||||
{
|
||||
StorageManager storageManager;
|
||||
if (storageManager.storageLocked()) {
|
||||
m_settings.setValue(QStringLiteral("uploadStorage"),
|
||||
storageManager.storageDefault());
|
||||
} else {
|
||||
m_settings.setValue(QStringLiteral("uploadStorage"), uploadStorage);
|
||||
}
|
||||
}
|
||||
|
||||
const QString& ConfigHandler::uploadStorage()
|
||||
{
|
||||
StorageManager storageManager;
|
||||
// check for storage lock
|
||||
if (storageManager.storageLocked()) {
|
||||
setUploadStorage(storageManager.storageDefault());
|
||||
}
|
||||
|
||||
// get storage
|
||||
m_strRes = m_settings.value(QStringLiteral("uploadStorage")).toString();
|
||||
if (m_strRes.isEmpty()) {
|
||||
StorageManager storageManager;
|
||||
m_strRes = storageManager.storageDefault();
|
||||
setUploadStorage(m_strRes);
|
||||
}
|
||||
return m_strRes;
|
||||
}
|
||||
|
||||
QString ConfigHandler::saveAfterCopyPathValue()
|
||||
{
|
||||
|
||||
@@ -93,9 +93,6 @@ public:
|
||||
bool copyPathAfterSaveEnabled();
|
||||
void setCopyPathAfterSaveEnabled(const bool);
|
||||
|
||||
void setUploadStorage(const QString&);
|
||||
const QString& uploadStorage();
|
||||
|
||||
void setDefaults();
|
||||
void setAllTheButtons();
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "capturewidget.h"
|
||||
#include "src/core/controller.h"
|
||||
#include "src/tools/storage/storagemanager.h"
|
||||
#include "src/tools/toolfactory.h"
|
||||
#include "src/utils/colorutils.h"
|
||||
#include "src/utils/screengrabber.h"
|
||||
@@ -1094,16 +1093,6 @@ void CaptureWidget::childLeave()
|
||||
update();
|
||||
}
|
||||
|
||||
void CaptureWidget::uploadScreenshot()
|
||||
{
|
||||
StorageManager storageManager;
|
||||
m_activeTool =
|
||||
storageManager.imgUploaderTool(ConfigHandler().uploadStorage());
|
||||
m_activeTool->setCapture(pixmap());
|
||||
handleButtonSignal(CaptureTool::REQ_ADD_EXTERNAL_WIDGETS);
|
||||
close();
|
||||
}
|
||||
|
||||
void CaptureWidget::copyScreenshot()
|
||||
{
|
||||
m_captureDone = true;
|
||||
|
||||
@@ -73,7 +73,6 @@ private slots:
|
||||
// TODO replace with tools
|
||||
void copyScreenshot();
|
||||
void saveScreenshot();
|
||||
void uploadScreenshot();
|
||||
void undo();
|
||||
void redo();
|
||||
void togglePanel();
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#include "historywidget.h"
|
||||
#include "src/tools/storage/imguploader.h"
|
||||
#include "src/tools/storage/s3/imgs3uploader.h"
|
||||
#include "src/tools/storage/storagemanager.h"
|
||||
#include "src/utils/history.h"
|
||||
#include "src/widgets/notificationwidget.h"
|
||||
#include <QApplication>
|
||||
@@ -99,9 +96,6 @@ void HistoryWidget::addLine(const QString& path, const QString& fileName)
|
||||
|
||||
QString url;
|
||||
|
||||
StorageManager storageManager;
|
||||
url = storageManager.storageUrl(unpackFileName.type) + unpackFileName.file;
|
||||
|
||||
// load pixmap
|
||||
QPixmap pixmap;
|
||||
pixmap.load(fullFileName, "png");
|
||||
@@ -155,24 +149,11 @@ void HistoryWidget::addLine(const QString& path, const QString& fileName)
|
||||
buttonDelete->setIcon(QIcon(":/img/material/black/delete.svg"));
|
||||
buttonDelete->setMinimumHeight(HISTORYPIXMAP_MAX_PREVIEW_HEIGHT);
|
||||
connect(buttonDelete, &QPushButton::clicked, this, [=]() {
|
||||
// TODO - remove dependency injection (s3 & imgur)
|
||||
if (unpackFileName.type.compare(SCREENSHOT_STORAGE_TYPE_S3) == 0) {
|
||||
if (unpackFileName.token.length() > 0) {
|
||||
removeItem(phbl, unpackFileName.file, unpackFileName.token);
|
||||
} else {
|
||||
// for compatibility with previous versions and to be able to
|
||||
// remove previous screenshots
|
||||
removeCacheFile(fullFileName);
|
||||
removeLayoutItem(phbl);
|
||||
}
|
||||
} else if (unpackFileName.type.compare(SCREENSHOT_STORAGE_TYPE_IMGUR) ==
|
||||
0) {
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QStringLiteral("https://imgur.com/delete/%1")
|
||||
.arg(unpackFileName.token)));
|
||||
removeCacheFile(fullFileName);
|
||||
removeLayoutItem(phbl);
|
||||
}
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QStringLiteral("https://imgur.com/delete/%1")
|
||||
.arg(unpackFileName.token)));
|
||||
removeCacheFile(fullFileName);
|
||||
removeLayoutItem(phbl);
|
||||
});
|
||||
|
||||
// layout
|
||||
@@ -196,17 +177,17 @@ void HistoryWidget::removeItem(QLayout* pl,
|
||||
const QString& fileName,
|
||||
const QString& deleteToken)
|
||||
{
|
||||
hide();
|
||||
ImgS3Uploader* imgUploader = new ImgS3Uploader();
|
||||
imgUploader->show();
|
||||
imgUploader->deleteResource(fileName, deleteToken);
|
||||
connect(imgUploader, &QWidget::destroyed, this, [=]() {
|
||||
if (imgUploader->resultStatus) {
|
||||
removeLayoutItem(pl);
|
||||
}
|
||||
imgUploader->deleteLater();
|
||||
show();
|
||||
});
|
||||
/* hide();
|
||||
ImgS3Uploader* imgUploader = new ImgS3Uploader();
|
||||
imgUploader->show();
|
||||
imgUploader->deleteResource(fileName, deleteToken);
|
||||
connect(imgUploader, &QWidget::destroyed, this, [=]() {
|
||||
if (imgUploader->resultStatus) {
|
||||
removeLayoutItem(pl);
|
||||
}
|
||||
imgUploader->deleteLater();
|
||||
show();
|
||||
});*/
|
||||
}
|
||||
|
||||
void HistoryWidget::removeLayoutItem(QLayout* pl)
|
||||
|
||||
Reference in New Issue
Block a user