Image hosting code refactoring (#1032)

* 将图床单独提取出来成为一个类

* Split the image hosting code into two classes

* change null to parent

* delect empty line,add p_,rename file and so on
This commit is contained in:
冯文华 2019-11-08 22:17:53 +08:00 committed by Le Tan
parent c828ef00c4
commit a85c39aa26
6 changed files with 836 additions and 713 deletions

View File

@ -1,9 +1,9 @@
[global] [global]
; Wechat ImageBed ; Wechat Image Hosting
wechat_appid= wechat_appid=
wechat_secret= wechat_secret=
wechat_markdown_to_wechat_tool_url= wechat_markdown_to_wechat_tool_url=
; Github ImageBed ; Github Image Hosting
github_personal_access_token= github_personal_access_token=
github_repos_name= github_repos_name=
github_user_name= github_user_name=

View File

@ -28,6 +28,7 @@ TRANSLATIONS += translations/vnote_zh_CN.ts \
} }
SOURCES += main.cpp\ SOURCES += main.cpp\
vimagehosting.cpp \
vmainwindow.cpp \ vmainwindow.cpp \
vdirectorytree.cpp \ vdirectorytree.cpp \
vnote.cpp \ vnote.cpp \
@ -165,6 +166,7 @@ SOURCES += main.cpp\
HEADERS += vmainwindow.h \ HEADERS += vmainwindow.h \
vdirectorytree.h \ vdirectorytree.h \
vimagehosting.h \
vnote.h \ vnote.h \
vnotebook.h \ vnotebook.h \
dialog/vnewdirdialog.h \ dialog/vnewdirdialog.h \

692
src/vimagehosting.cpp Normal file
View File

@ -0,0 +1,692 @@
#include "vimagehosting.h"
#include "utils/vutils.h"
#include "vedittab.h"
extern VConfigManager *g_config;
VGithubImageHosting::VGithubImageHosting(VFile *p_file, QWidget *p_parent)
:QObject(p_parent),
m_file(p_file)
{
reply = Q_NULLPTR;
imageUploaded = false;
}
void VGithubImageHosting::handleUploadImageToGithubRequested()
{
qDebug() << "Start processing the image upload request to GitHub";
if(g_config->getpersonalAccessToken().isEmpty() || g_config->getReposName().isEmpty() || g_config->getUserName().isEmpty())
{
qDebug() << "Please configure the GitHub image hosting first!";
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Please configure the GitHub image hosting first!"));
return;
}
authenticateGithubImageHosting(g_config->getpersonalAccessToken());
}
void VGithubImageHosting::authenticateGithubImageHosting(QString p_token)
{
qDebug() << "start the authentication process ";
QApplication::setOverrideCursor(Qt::WaitCursor);
QNetworkRequest request;
QUrl url = QUrl("https://api.github.com");
QString ptoken = "token " + p_token;
request.setRawHeader("Authorization", ptoken.toLocal8Bit());
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &VGithubImageHosting::githubImageBedAuthFinished);
}
void VGithubImageHosting::githubImageBedAuthFinished()
{
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
if(bytes.contains("Bad credentials")){
qDebug() << "Authentication failed";
QApplication::restoreOverrideCursor(); // Recovery pointer
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Bad credentials!! ") +
tr("Please check your Github Image Hosting parameters !!"));
return;
}else{
qDebug() << "Authentication completed";
qDebug() << "The current article path is: " << m_file->fetchPath();
imageBasePath = m_file->fetchBasePath();
newFileContent = m_file->getContent();
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(m_file,ImageLink::LocalRelativeInternal);
QApplication::restoreOverrideCursor(); // Recovery pointer
if(images.size() > 0)
{
proDlg = new QProgressDialog(tr("Uploading images to github..."),
tr("Abort"),
0,
images.size(),
NULL);
proDlg->setWindowModality(Qt::WindowModal);
proDlg->setWindowTitle(tr("Uploading Images To Github"));
proDlg->setMinimumDuration(1);
uploadImageCount = images.size();
uploadImageCountIndex = uploadImageCount;
for(int i=0;i<images.size() ;i++)
{
if(images[i].m_url.contains(".png") || images[i].m_url.contains(".jpg")|| images[i].m_url.contains(".gif")){
imageUrlMap.insert(images[i].m_url,"");
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QFileInfo fileInfo(images[i].m_path.toLocal8Bit());
QString fileSuffix = fileInfo.suffix();
QString info = tr("Unsupported type: ") + fileSuffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
}
githubImageBedUploadManager();
}
else
{
qDebug() << m_file->getName() << " No images to upload";
QString info = m_file->getName() + " No pictures to upload";
QMessageBox::information(NULL, tr("Github Image Hosting"), info);
}
}
break;
}
default:
{
QApplication::restoreOverrideCursor(); // Recovery pointer
qDebug() << "Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Network error: ") + reply->errorString();
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}
}
void VGithubImageHosting::githubImageBedUploadManager()
{
uploadImageCountIndex--;
QString imageToUpload;
QMapIterator<QString, QString> it(imageUrlMap);
while(it.hasNext())
{
it.next();
if(it.value() == ""){
imageToUpload = it.key();
proDlg->setValue(uploadImageCount - 1 - uploadImageCountIndex);
proDlg->setLabelText(tr("Uploaading image: %1").arg(imageToUpload));
break;
}
}
if(imageToUpload == ""){
qDebug() << "All images have been uploaded";
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
return;
}
if(g_config->getpersonalAccessToken().isEmpty() ||
g_config->getReposName().isEmpty() ||
g_config->getUserName().isEmpty())
{
qDebug() << "Please configure the GitHub image hosting first!";
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Please configure the GitHub image hosting first!"));
imageUrlMap.clear();
return;
}
QString path = imageBasePath + QDir::separator();
path += imageToUpload;
githubImageBedUploadImage(g_config->getUserName(),
g_config->getReposName(),
path,
g_config->getpersonalAccessToken());
}
void VGithubImageHosting::githubImageBedUploadImage(const QString &p_username,
const QString &p_repository,
const QString &p_image_path,
const QString &p_token)
{
QFileInfo fileInfo(p_image_path.toLocal8Bit());
if(!fileInfo.exists()){
qDebug() << "The picture does not exist in this path: " << p_image_path.toLocal8Bit();
QString info = tr("The picture does not exist in this path: ") + p_image_path.toLocal8Bit();
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
imageUrlMap.clear();
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
QString fileSuffix = fileInfo.suffix(); // file extension
QString fileName = fileInfo.fileName(); // filename
QString uploadUrl; // Image upload URL
uploadUrl = "https://api.github.com/repos/" + p_username + "/" + p_repository + "/contents/" +
QString::number(QDateTime::currentDateTime().toTime_t()) +"_" + fileName;
if(fileSuffix != QString::fromLocal8Bit("jpg") && fileSuffix != QString::fromLocal8Bit("png")
&& fileSuffix != QString::fromLocal8Bit("gif")){
qDebug() << "Unsupported type...";
QString info = tr("Unsupported type: ") + fileSuffix;
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
imageUrlMap.clear();
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
QNetworkRequest request;
QUrl url = QUrl(uploadUrl);
QString ptoken = "token " + p_token;
request.setRawHeader("Authorization", ptoken.toLocal8Bit());
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
QString param = githubImageBedGenerateParam(p_image_path);
QByteArray postData;
postData.append(param);
reply = manager.put(request, postData);
qDebug() << "Start uploading images: " + p_image_path + " Waiting for upload to complete";
uploadImageStatus = true;
currentUploadImage = p_image_path;
connect(reply, &QNetworkReply::finished, this, &VGithubImageHosting::githubImageBedUploadFinished);
}
void VGithubImageHosting::githubImageBedUploadFinished()
{
if (proDlg->wasCanceled()) {
qDebug() << "User stops uploading";
reply->abort(); // Stop network request
imageUrlMap.clear();
// The ones that have been uploaded successfully before still need to stay
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if(httpStatus == 201){
qDebug() << "Upload success";
QString downloadUrl;
QString imageName;
QJsonDocument doucment = QJsonDocument::fromJson(bytes);
if (!doucment.isNull() )
{
if (doucment.isObject()) {
QJsonObject object = doucment.object();
if (object.contains("content")) {
QJsonValue value = object.value("content");
if (value.isObject()) {
QJsonObject obj = value.toObject();
if (obj.contains("download_url")) {
QJsonValue value = obj.value("download_url");
if (value.isString()) {
downloadUrl = value.toString();
qDebug() << "json decode: download_url : " << downloadUrl;
imageUploaded = true; // On behalf of successfully uploaded images
proDlg->setValue(uploadImageCount);
}
}
if(obj.contains("name")){
QJsonValue value = obj.value("name");
if(value.isString()){
imageName = value.toString();
}
}
// Traverse key in imageurlmap
QList<QString> klist = imageUrlMap.keys();
QString temp;
for(int i=0;i<klist.count();i++)
{
temp = klist[i].split("/")[1];
if(imageName.contains(temp))
{
// You can assign values in the map
imageUrlMap.insert(klist[i], downloadUrl);
// Replace the link in the original
newFileContent.replace(klist[i], downloadUrl);
break;
}
}
// Start calling the method.
// Whether the value in the map is empty determines whether to stop.
githubImageBedUploadManager();
}
}
}
}
else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}else{
// If status is not 201, it means there is a problem.
delete proDlg;
imageUrlMap.clear();
qDebug() << "Upload failure";
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("github status code != 201, Please contact the developer~");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
break;
}
default:
{
delete proDlg;
imageUrlMap.clear();
qDebug()<<"network error: " << reply->errorString() << " error " << reply->error();
QByteArray bytes = reply->readAll();
qDebug() << bytes;
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "status: " << httpStatus;
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("Uploading ") + currentUploadImage + tr(" \n\nNetwork error: ") +
reply->errorString() + tr("\n\nPlease check the network or image size");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}
}
void VGithubImageHosting::githubImageBedReplaceLink(const QString p_fileContent, const QString p_filePath)
{
// This function must be executed when the upload is completed or fails in the middle.
// Write content to file.
QFile file(p_filePath);
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.write(p_fileContent.toUtf8());
file.close();
// Reset.
imageUrlMap.clear();
imageUploaded = false;
}
QString VGithubImageHosting::githubImageBedGenerateParam(const QString p_image_path){
// According to the requirements of GitHub interface, pictures must be in Base64 format.
// Image to base64.
QByteArray hexed;
QFile imgFile(p_image_path);
imgFile.open(QIODevice::ReadOnly);
hexed = imgFile.readAll().toBase64();
QString imgBase64 = hexed;
QJsonObject json;
json.insert("message", QString("updatetest"));
json.insert("content", imgBase64);
QJsonDocument document;
document.setObject(json);
QByteArray byteArray = document.toJson(QJsonDocument::Compact);
QString jsonStr(byteArray);
return jsonStr;
}
VWechatImageHosting::VWechatImageHosting(VFile *p_file, QWidget *p_parent)
:QObject(p_parent),
m_file(p_file)
{
reply = Q_NULLPTR;
imageUploaded = false;
}
void VWechatImageHosting::handleUploadImageToWechatRequested()
{
qDebug() << "Start processing image upload request to wechat";
QString appid = g_config->getAppid();
QString secret = g_config->getSecret();
if(appid.isEmpty() || secret.isEmpty())
{
qDebug() << "Please configure the Wechat image hosting first!";
QMessageBox::warning(NULL, tr("Wechat Image Hosting"),
tr("Please configure the Wechat image hosting first!"));
return;
}
authenticateWechatImageHosting(appid, secret);
}
void VWechatImageHosting::authenticateWechatImageHosting(const QString p_appid, const QString p_secret)
{
qDebug() << "Start certification";
// Set the mouse to wait
QApplication::setOverrideCursor(Qt::WaitCursor);
QNetworkRequest request;
QString auth_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+
p_appid.toLocal8Bit() + "&secret=" + p_secret.toLocal8Bit();
QUrl url = QUrl(auth_url);
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &VWechatImageHosting::wechatImageBedAuthFinished);
}
void VWechatImageHosting::wechatImageBedAuthFinished()
{
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
QJsonDocument document = QJsonDocument::fromJson(bytes);
if(!document.isNull()){
if(document.isObject()){
QJsonObject object = document.object();
if(object.contains("access_token")){
QJsonValue value = object.value("access_token");
if(value.isString()){
qDebug() << "Authentication successful, get token";
// Parsing token.
wechatAccessToken = value.toString();
qDebug() << "The current article path is: " << m_file->fetchPath();
imageBasePath = m_file->fetchBasePath();
newFileContent = m_file->getContent();
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(m_file,ImageLink::LocalRelativeInternal);
QApplication::restoreOverrideCursor(); // Recovery pointer
if(images.size() > 0)
{
proDlg = new QProgressDialog(tr("Uploading images to github..."),
tr("Abort"),
0,
images.size(),
NULL);
proDlg->setWindowModality(Qt::WindowModal);
proDlg->setWindowTitle(tr("Uploading Images To Github"));
proDlg->setMinimumDuration(1);
uploadImageCount = images.size();
uploadImageCountIndex = uploadImageCount;
for(int i=0;i<images.size() ;i++)
{
if(images[i].m_url.contains(".png") || images[i].m_url.contains(".jpg")){
imageUrlMap.insert(images[i].m_url,"");
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QFileInfo file_info(images[i].m_path.toLocal8Bit());
QString file_suffix = file_info.suffix();
QString info = tr("Unsupported type: ") + file_suffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
}
wechatImageBedUploadManager();
}
else
{
qDebug() << m_file->getName() << " No pictures to upload";
QString info = m_file->getName() + tr(" No pictures to upload");
QMessageBox::information(NULL, tr("Wechat Image Hosting"), info);
}
}
}else{
qDebug() << "Authentication failed";
QString string = bytes;
qDebug() << string;
// You can refine the error here.
QApplication::restoreOverrideCursor();
if(string.contains("invalid ip")){
QString ip = string.split(" ")[2];
QClipboard *board = QApplication::clipboard();
board->setText(ip);
QMessageBox::warning(NULL, tr("Wechat Image Hosting"),
tr("Your ip address was set to the Clipboard!") +
tr("\nPlease add the IP address: ") +
ip + tr(" to the wechat ip whitelist!"));
}else{
QMessageBox::warning(NULL, tr("Wechat Image Hosting"),
tr("Please check your Wechat Image Hosting parameters !!\n") +
string);
}
return;
}
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
break;
}
default:
{
QApplication::restoreOverrideCursor();
qDebug() << "Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Network error: ") + reply->errorString();
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}
void VWechatImageHosting::wechatImageBedUploadManager()
{
uploadImageCountIndex--;
QString image_to_upload = "";
QMapIterator<QString, QString> it(imageUrlMap);
while(it.hasNext())
{
it.next();
if(it.value() == ""){
image_to_upload = it.key();
proDlg->setValue(uploadImageCount - 1 - uploadImageCountIndex);
proDlg->setLabelText(tr("Uploaading image: %1").arg(image_to_upload));
break;
}
}
if(image_to_upload == ""){
qDebug() << "All pictures have been uploaded";
// Copy content to clipboard.
wechatImageBedReplaceLink(newFileContent);
return;
}
QString path = imageBasePath + QDir::separator();
path += image_to_upload;
currentUploadRelativeImagePah = image_to_upload;
wechatImageBedUploadImage(path, wechatAccessToken);
}
void VWechatImageHosting::wechatImageBedUploadImage(const QString p_image_path, const QString p_token)
{
qDebug() << "To deal with: " << p_image_path;
QFileInfo fileInfo(p_image_path.toLocal8Bit());
if(!fileInfo.exists()){
delete proDlg;
imageUrlMap.clear();
qDebug() << "The picture does not exist in this path: " << p_image_path.toLocal8Bit();
QString info = tr("The picture does not exist in this path: ") + p_image_path.toLocal8Bit();
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
QString file_suffix = fileInfo.suffix(); // File extension.
QString file_name = fileInfo.fileName(); // Filename.
if(file_suffix != QString::fromLocal8Bit("jpg") && file_suffix != QString::fromLocal8Bit("png")){
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QString info = tr("Unsupported type: ") + file_suffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
qint64 file_size = fileInfo.size(); // Unit is byte.
qDebug() << "Image size: " << file_size;
if(file_size > 1024*1024){
delete proDlg;
imageUrlMap.clear();
qDebug() << "The size of the picture is more than 1M";
QString info = tr("The size of the picture is more than 1M! Wechat API does not support!!");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
QString upload_img_url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + p_token;
QNetworkRequest request;
request.setUrl(upload_img_url);
if(reply != Q_NULLPTR){
reply->deleteLater();
}
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
QString filename = p_image_path.split(QDir::separator()).last();
QString contentVariant = QString("form-data; name=\"media\"; filename=\"%1\";").arg(filename);
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(contentVariant));
QFile *file = new QFile(p_image_path);
if(!file->open(QIODevice::ReadOnly)){
qDebug() << "File open failed";
}
imagePart.setBodyDevice(file);
file->setParent(multiPart);
multiPart->append(imagePart);
// Set boundary
// Because boundary is quoted by QNetworkAccessManager, the wechat api is not recognized...
QByteArray m_boundary;
m_boundary.append("multipart/form-data; boundary=");
m_boundary.append(multiPart->boundary());
request.setRawHeader(QByteArray("Content-Type"), m_boundary);
reply = manager.post(request, multiPart);
multiPart->setParent(reply);
qDebug() << "Start uploading images: " + p_image_path + " Waiting for upload to complete";
uploadImageStatus=true;
currentUploadImage = p_image_path;
connect(reply, &QNetworkReply::finished, this, &VWechatImageHosting::wechatImageBedUploadFinished);
}
void VWechatImageHosting::wechatImageBedUploadFinished()
{
if(proDlg->wasCanceled()){
qDebug() << "User stops uploading";
reply->abort();
// If the upload was successful, don't use it!!!
imageUrlMap.clear();
return;
}
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
QJsonDocument document = QJsonDocument::fromJson(bytes);
if(!document.isNull()){
if(document.isObject()){
QJsonObject object = document.object();
if(object.contains("url")){
QJsonValue value = object.value("url");
if(value.isString()){
qDebug() << "Authentication successful, get online link";
imageUploaded = true;
proDlg->setValue(uploadImageCount);
imageUrlMap.insert(currentUploadRelativeImagePah, value.toString());
newFileContent.replace(currentUploadRelativeImagePah, value.toString());
// Start calling the method.
// Whether the value in the map is empty determines whether to stop
wechatImageBedUploadManager();
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Upload failure: ";
QString error = bytes;
qDebug() << bytes;
QString info = tr("upload failed! Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
break;
}
default:
{
delete proDlg;
qDebug()<<"Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Uploading ") + currentUploadImage + tr(" \n\nNetwork error: ") +
reply->errorString() + tr("\n\nPlease check the network or image size");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}
void VWechatImageHosting::wechatImageBedReplaceLink(const QString p_file_content)
{
// Write content to clipboard.
QClipboard *board = QApplication::clipboard();
board->setText(p_file_content);
QString url = g_config->getMarkdown2WechatToolUrl();
if(url.isEmpty()){
QMessageBox::warning(NULL, tr("Wechat Image Hosting"),
tr("The article has been copied to the clipboard. Please find a text file and save it!!"));
}else{
QMessageBox::StandardButton result;
result = QMessageBox::question(NULL, tr("Wechat Image Hosting"),
tr("The article has been copied to the clipboard.") +
tr("Do you want to open the tool link of mark down to wechat?"),
QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
if(result == QMessageBox::Yes){
QDesktopServices::openUrl(QUrl(url));
}
}
imageUrlMap.clear();
imageUploaded = false; // Reset.
}

131
src/vimagehosting.h Normal file
View File

@ -0,0 +1,131 @@
#ifndef VGITHUBIMAGEHOSTING_H
#define VGITHUBIMAGEHOSTING_H
#include <QObject>
#include <QtNetwork>
#include <QProgressDialog>
#include <QDesktopServices>
#include <QUrl>
#include <QByteArray>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QApplication>
#include <vfile.h>
#include <QClipboard>
class VGithubImageHosting : public QObject
{
Q_OBJECT
public:
explicit VGithubImageHosting(VFile *p_file, QWidget *p_parent = nullptr);
// GitHub identity authentication.
void authenticateGithubImageHosting(QString p_token);
// Upload a single image.
void githubImageBedUploadImage(const QString &p_username,
const QString &p_repository,
const QString &p_image_path,
const QString &p_token);
// Parameters needed to generate uploaded images.
QString githubImageBedGenerateParam(const QString p_image_path);
// Control image to upload.
void githubImageBedUploadManager();
// Replace old links with new ones for images.
void githubImageBedReplaceLink(const QString p_file_content, const QString p_file_path);
// Process the image upload request to GitHub.
void handleUploadImageToGithubRequested();
public slots:
// GitHub image hosting identity authentication completed.
void githubImageBedAuthFinished();
// GitHub image hosting upload completed.
void githubImageBedUploadFinished();
private:
QNetworkAccessManager manager;
QNetworkReply *reply;
QMap<QString, QString> imageUrlMap;
// Similar to "_v_image/".
QString imageBasePath;
// Replace the file content with the new link.
QString newFileContent;
// Whether the picture has been uploaded successfully.
bool imageUploaded;
// Image upload progress bar.
QProgressDialog *proDlg;
// Total number of images to upload.
int uploadImageCount;
int uploadImageCountIndex;
// Currently uploaded picture name.
QString currentUploadImage;
// Image upload status.
bool uploadImageStatus;
// Token returned after successful wechat authentication.
QString wechatAccessToken;
// Relative image path currently Uploaded.
QString currentUploadRelativeImagePah;
VFile *m_file;
};
class VWechatImageHosting : public QObject
{
Q_OBJECT
public:
explicit VWechatImageHosting(VFile *p_file, QWidget *p_parent = nullptr);
// Wechat identity authentication.
void authenticateWechatImageHosting(const QString p_appid, const QString p_secret);
// Control image to upload.
void wechatImageBedUploadManager();
// Replace old links with new ones for images.
void wechatImageBedReplaceLink(const QString p_file_content);
// Upload a single image.
void wechatImageBedUploadImage(const QString p_image_path, const QString p_token);
// Process image upload request to wechat.
void handleUploadImageToWechatRequested();
public slots:
// Wechat mage hosting identity authentication completed.
void wechatImageBedAuthFinished();
// Wechat image hosting upload completed.
void wechatImageBedUploadFinished();
private:
QNetworkAccessManager manager;
QNetworkReply *reply;
QMap<QString, QString> imageUrlMap;
// Similar to "_v_image/".
QString imageBasePath;
// Replace the file content with the new link.
QString newFileContent;
// Whether the picture has been uploaded successfully.
bool imageUploaded;
// Image upload progress bar.
QProgressDialog *proDlg;
// Total number of images to upload.
int uploadImageCount;
int uploadImageCountIndex;
// Currently uploaded picture name.
QString currentUploadImage;
// Image upload status
bool uploadImageStatus;
// Token returned after successful wechat authentication.
QString wechatAccessToken;
// Relative image path currently Uploaded.
QString currentUploadRelativeImagePah;
VFile *m_file;
};
#endif // VGITHUBIMAGEHOSTING_H

View File

@ -113,8 +113,9 @@ void VMdTab::setupUI()
// Setup editor when we really need it. // Setup editor when we really need it.
m_editor = NULL; m_editor = NULL;
reply = Q_NULLPTR; // The following is the image hosting initialization
imageUploaded = false; vGithubImageHosting = new VGithubImageHosting(m_file, this);
vWechatImageHosting = new VWechatImageHosting(m_file, this);
QVBoxLayout *layout = new QVBoxLayout(); QVBoxLayout *layout = new QVBoxLayout();
layout->addWidget(m_splitter); layout->addWidget(m_splitter);
@ -446,6 +447,7 @@ void VMdTab::setupMarkdownViewer()
this, &VMdTab::handleWebSelectionChanged); this, &VMdTab::handleWebSelectionChanged);
connect(m_webViewer, &VWebView::requestExpandRestorePreviewArea, connect(m_webViewer, &VWebView::requestExpandRestorePreviewArea,
this, &VMdTab::expandRestorePreviewArea); this, &VMdTab::expandRestorePreviewArea);
connect(m_webViewer, &VWebView::requestUploadImageToGithub, connect(m_webViewer, &VWebView::requestUploadImageToGithub,
this, &VMdTab::handleUploadImageToGithubRequested); this, &VMdTab::handleUploadImageToGithubRequested);
connect(m_webViewer, &VWebView::requestUploadImageToWechat, connect(m_webViewer, &VWebView::requestUploadImageToWechat,
@ -1512,661 +1514,12 @@ void VMdTab::handleSavePageRequested()
void VMdTab::handleUploadImageToGithubRequested() void VMdTab::handleUploadImageToGithubRequested()
{ {
qDebug() << "Start processing the image upload request to GitHub"; vGithubImageHosting->handleUploadImageToGithubRequested();
if(g_config->getpersonalAccessToken().isEmpty() || g_config->getReposName().isEmpty() || g_config->getUserName().isEmpty())
{
qDebug() << "Please configure the GitHub image hosting first!";
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Please configure the GitHub image hosting first!"));
return;
}
authenticateGithubImageHosting(g_config->getpersonalAccessToken());
}
void VMdTab::authenticateGithubImageHosting(QString p_token)
{
qDebug() << "start the authentication process ";
QApplication::setOverrideCursor(Qt::WaitCursor);
QNetworkRequest request;
QUrl url = QUrl("https://api.github.com");
QString ptoken = "token " + p_token;
request.setRawHeader("Authorization", ptoken.toLocal8Bit());
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &VMdTab::githubImageBedAuthFinished);
}
void VMdTab::githubImageBedAuthFinished()
{
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
if(bytes.contains("Bad credentials")){
qDebug() << "Authentication failed";
QApplication::restoreOverrideCursor(); // Recovery pointer
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Bad credentials!! Please check your Github Image Hosting parameters !!"));
return;
}else{
qDebug() << "Authentication completed";
qDebug() << "The current article path is: " << m_file->fetchPath();
imageBasePath = m_file->fetchBasePath();
newFileContent = m_file->getContent();
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(m_file,ImageLink::LocalRelativeInternal);
QApplication::restoreOverrideCursor(); // Recovery pointer
if(images.size() > 0)
{
proDlg = new QProgressDialog(tr("Uploading images to github..."),
tr("Abort"),
0,
images.size(),
this);
proDlg->setWindowModality(Qt::WindowModal);
proDlg->setWindowTitle(tr("Uploading Images To Github"));
proDlg->setMinimumDuration(1);
uploadImageCount = images.size();
uploadImageCountIndex = uploadImageCount;
for(int i=0;i<images.size() ;i++)
{
if(images[i].m_url.contains(".png") || images[i].m_url.contains(".jpg")|| images[i].m_url.contains(".gif")){
imageUrlMap.insert(images[i].m_url,"");
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QFileInfo fileInfo(images[i].m_path.toLocal8Bit());
QString fileSuffix = fileInfo.suffix();
QString info = tr("Unsupported type: ") + fileSuffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
}
githubImageBedUploadManager();
}
else
{
qDebug() << m_file->getName() << " No images to upload";
QString info = m_file->getName() + " No pictures to upload";
QMessageBox::information(NULL, tr("Github Image Hosting"), info);
}
}
break;
}
default:
{
QApplication::restoreOverrideCursor(); // Recovery pointer
qDebug() << "Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Network error: ") + reply->errorString();
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}
}
void VMdTab::githubImageBedUploadManager()
{
uploadImageCountIndex--;
QString imageToUpload = "";
QMapIterator<QString, QString> it(imageUrlMap);
while(it.hasNext())
{
it.next();
if(it.value() == ""){
imageToUpload = it.key();
proDlg->setValue(uploadImageCount - 1 - uploadImageCountIndex);
proDlg->setLabelText(tr("Uploaading image: %1").arg(imageToUpload));
break;
}
}
if(imageToUpload == ""){
qDebug() << "All images have been uploaded";
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
return;
}
if(g_config->getpersonalAccessToken().isEmpty() || g_config->getReposName().isEmpty() || g_config->getUserName().isEmpty())
{
qDebug() << "Please configure the GitHub image hosting first!";
QMessageBox::warning(NULL, tr("Github Image Hosting"), tr("Please configure the GitHub image hosting first!"));
imageUrlMap.clear();
return;
}
QString path = imageBasePath + QDir::separator();
path += imageToUpload;
githubImageBedUploadImage(g_config->getUserName(), g_config->getReposName(), path, g_config->getpersonalAccessToken());
}
void VMdTab::githubImageBedUploadImage(QString username, QString repository, QString imagePath, QString token)
{
QFileInfo fileInfo(imagePath.toLocal8Bit());
if(!fileInfo.exists()){
qDebug() << "The picture does not exist in this path: " << imagePath.toLocal8Bit();
QString info = tr("The picture does not exist in this path: ") + imagePath.toLocal8Bit();
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
imageUrlMap.clear();
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
QString fileSuffix = fileInfo.suffix(); // file extension
QString fileName = fileInfo.fileName(); // filename
QString uploadUrl; // Image upload URL
uploadUrl = "https://api.github.com/repos/" + username + "/" + repository + "/contents/" + QString::number(QDateTime::currentDateTime().toTime_t()) +"_" + fileName;
if(fileSuffix != QString::fromLocal8Bit("jpg") && fileSuffix != QString::fromLocal8Bit("png") && fileSuffix != QString::fromLocal8Bit("gif")){
qDebug() << "Unsupported type...";
QString info = tr("Unsupported type: ") + fileSuffix;
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
imageUrlMap.clear();
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
QNetworkRequest request;
QUrl url = QUrl(uploadUrl);
QString ptoken = "token " + token;
request.setRawHeader("Authorization", ptoken.toLocal8Bit());
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
QString param = githubImageBedGenerateParam(imagePath);
QByteArray postData;
postData.append(param);
reply = manager.put(request, postData);
qDebug() << "Start uploading images: " + imagePath + " Waiting for upload to complete";
uploadImageStatus = true;
currentUploadImage = imagePath;
connect(reply, &QNetworkReply::finished, this, &VMdTab::githubImageBedUploadFinished);
}
void VMdTab::githubImageBedUploadFinished()
{
if (proDlg->wasCanceled()) {
qDebug() << "User stops uploading";
reply->abort(); // Stop network request
imageUrlMap.clear();
// The ones that have been uploaded successfully before still need to stay
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
return;
}
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if(httpStatus == 201){
qDebug() << "Upload success";
QString downloadUrl;
QString imageName;
QJsonDocument doucment = QJsonDocument::fromJson(bytes);
if (!doucment.isNull() )
{
if (doucment.isObject()) {
QJsonObject object = doucment.object();
if (object.contains("content")) {
QJsonValue value = object.value("content");
if (value.isObject()) {
QJsonObject obj = value.toObject();
if (obj.contains("download_url")) {
QJsonValue value = obj.value("download_url");
if (value.isString()) {
downloadUrl = value.toString();
qDebug() << "json decode: download_url : " << downloadUrl;
imageUploaded = true; // On behalf of successfully uploaded images
proDlg->setValue(uploadImageCount);
}
}
if(obj.contains("name")){
QJsonValue value = obj.value("name");
if(value.isString()){
imageName = value.toString();
}
}
// Traverse key in imageurlmap
QList<QString> klist = imageUrlMap.keys();
QString temp;
for(int i=0;i<klist.count();i++)
{
temp = klist[i].split("/")[1];
if(imageName.contains(temp))
{
// You can assign values in the map
imageUrlMap.insert(klist[i], downloadUrl);
// Replace the link in the original
newFileContent.replace(klist[i], downloadUrl);
break;
}
}
// Start calling the method. Whether the value in the map is empty determines whether to stop
githubImageBedUploadManager();
}
}
}
}
else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}else{
// If status is not 201, it means there is a problem
delete proDlg;
imageUrlMap.clear();
qDebug() << "Upload failure";
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("github status code != 201, Please contact the developer~");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
break;
}
default:
{
delete proDlg;
imageUrlMap.clear();
qDebug()<<"network error: " << reply->errorString() << " error " << reply->error();
QByteArray bytes = reply->readAll();
qDebug() << bytes;
int httpStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
qDebug() << "status: " << httpStatus;
if(imageUploaded){
githubImageBedReplaceLink(newFileContent, m_file->fetchPath());
}
QString info = tr("Uploading ") + currentUploadImage + tr(" \n\nNetwork error: ") + reply->errorString() + tr("\n\nPlease check the network or image size");
QMessageBox::warning(NULL, tr("Github Image Hosting"), info);
}
}
}
void VMdTab::githubImageBedReplaceLink(QString fileContent, QString filePath)
{
// This function must be executed when the upload is completed or fails in the middle
// Write content to file
QFile file(filePath);
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.write(fileContent.toUtf8());
file.close();
// Reset
imageUrlMap.clear();
imageUploaded = false;
}
QString VMdTab::githubImageBedGenerateParam(QString imagePath){
// According to the requirements of GitHub interface, pictures must be in Base64 format
// img to base64
QByteArray hexed;
QFile imgFile(imagePath);
imgFile.open(QIODevice::ReadOnly);
hexed = imgFile.readAll().toBase64();
QString imgBase64 = hexed; // Base64 encoding of images
QJsonObject json;
json.insert("message", QString("updatetest"));
json.insert("content", imgBase64);
QJsonDocument document;
document.setObject(json);
QByteArray byteArray = document.toJson(QJsonDocument::Compact);
QString jsonStr(byteArray);
return jsonStr;
} }
void VMdTab::handleUploadImageToWechatRequested() void VMdTab::handleUploadImageToWechatRequested()
{ {
qDebug() << "Start processing image upload request to wechat"; vWechatImageHosting->handleUploadImageToWechatRequested();
QString appid = g_config->getAppid();
QString secret = g_config->getSecret();
if(appid.isEmpty() || secret.isEmpty())
{
qDebug() << "Please configure the Wechat image hosting first!";
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), tr("Please configure the Wechat image hosting first!"));
return;
}
authenticateWechatImageHosting(appid, secret);
}
void VMdTab::authenticateWechatImageHosting(QString appid, QString secret)
{
qDebug() << "Start certification";
QApplication::setOverrideCursor(Qt::WaitCursor); // Set the mouse to wait
QNetworkRequest request;
QString auth_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+ appid.toLocal8Bit() + "&secret=" + secret.toLocal8Bit();
QUrl url = QUrl(auth_url);
// request.setRawHeader("grant_type", "client_credential");
// request.setRawHeader("appid", appid.toLocal8Bit());
// request.setRawHeader("secret", secret.toLocal8Bit());
request.setUrl(url);
if(reply != Q_NULLPTR) {
reply->deleteLater();
}
reply = manager.get(request);
connect(reply, &QNetworkReply::finished, this, &VMdTab::wechatImageBedAuthFinished);
}
void VMdTab::wechatImageBedAuthFinished()
{
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
QJsonDocument document = QJsonDocument::fromJson(bytes);
if(!document.isNull()){
if(document.isObject()){
QJsonObject object = document.object();
if(object.contains("access_token")){
QJsonValue value = object.value("access_token");
if(value.isString()){
qDebug() << "Authentication successful, get token";
// Parsing token
wechatAccessToken = value.toString();
qDebug() << "The current article path is: " << m_file->fetchPath();
imageBasePath = m_file->fetchBasePath();
newFileContent = m_file->getContent();
QVector<ImageLink> images = VUtils::fetchImagesFromMarkdownFile(m_file,ImageLink::LocalRelativeInternal);
QApplication::restoreOverrideCursor(); // Recovery pointer
if(images.size() > 0)
{
proDlg = new QProgressDialog(tr("Uploading images to github..."),
tr("Abort"),
0,
images.size(),
this);
proDlg->setWindowModality(Qt::WindowModal);
proDlg->setWindowTitle(tr("Uploading Images To Github"));
proDlg->setMinimumDuration(1);
uploadImageCount = images.size();
uploadImageCountIndex = uploadImageCount;
for(int i=0;i<images.size() ;i++)
{
if(images[i].m_url.contains(".png") || images[i].m_url.contains(".jpg")){
imageUrlMap.insert(images[i].m_url,"");
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QFileInfo file_info(images[i].m_path.toLocal8Bit());
QString file_suffix = file_info.suffix();
QString info = tr("Unsupported type: ") + file_suffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
}
wechatImageBedUploadManager();
}
else
{
qDebug() << m_file->getName() << " No pictures to upload";
QString info = m_file->getName() + tr(" No pictures to upload");
QMessageBox::information(NULL, tr("Wechat Image Hosting"), info);
}
}
}else{
qDebug() << "Authentication failed";
QString string = bytes;
qDebug() << string;
// You can refine the error here
QApplication::restoreOverrideCursor();
if(string.contains("invalid ip")){
QString ip = string.split(" ")[2];
QClipboard *board = QApplication::clipboard();
board->setText(ip);
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), tr("Your ip address was set to the Clipboard! \nPlease add the IP address: ") + ip + tr(" to the wechat ip whitelist!"));
}else{
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), tr("Please check your Wechat Image Hosting parameters !!\n") + string);
}
return;
}
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
break;
}
default:
{
QApplication::restoreOverrideCursor();
qDebug() << "Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Network error: ") + reply->errorString();
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}
void VMdTab::wechatImageBedUploadManager()
{
uploadImageCountIndex--;
QString image_to_upload = "";
QMapIterator<QString, QString> it(imageUrlMap);
while(it.hasNext())
{
it.next();
if(it.value() == ""){
image_to_upload = it.key();
proDlg->setValue(uploadImageCount - 1 - uploadImageCountIndex);
proDlg->setLabelText(tr("Uploaading image: %1").arg(image_to_upload));
break;
}
}
if(image_to_upload == ""){
qDebug() << "All pictures have been uploaded";
// Copy content to clipboard
wechatImageBedReplaceLink(newFileContent, m_file->fetchPath());
return;
}
QString path = imageBasePath + QDir::separator();
path += image_to_upload;
currentUploadRelativeImagePah = image_to_upload;
wechatImageBedUploadImage(path, wechatAccessToken);
}
void VMdTab::wechatImageBedUploadImage(QString image_path, QString token)
{
qDebug() << "To deal with: " << image_path;
QFileInfo fileInfo(image_path.toLocal8Bit());
if(!fileInfo.exists()){
delete proDlg;
imageUrlMap.clear();
qDebug() << "The picture does not exist in this path: " << image_path.toLocal8Bit();
QString info = tr("The picture does not exist in this path: ") + image_path.toLocal8Bit();
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
QString file_suffix = fileInfo.suffix(); // File extension
QString file_name = fileInfo.fileName(); // filename
if(file_suffix != QString::fromLocal8Bit("jpg") && file_suffix != QString::fromLocal8Bit("png")){
delete proDlg;
imageUrlMap.clear();
qDebug() << "Unsupported type...";
QString info = tr("Unsupported type: ") + file_suffix;
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
qint64 file_size = fileInfo.size(); // Unit is byte
qDebug() << "Image size: " << file_size;
if(file_size > 1024*1024){
delete proDlg;
imageUrlMap.clear();
qDebug() << "The size of the picture is more than 1M";
QString info = tr("The size of the picture is more than 1M! Wechat API does not support!!");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
return;
}
QString upload_img_url = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=" + token;
QNetworkRequest request;
request.setUrl(upload_img_url);
if(reply != Q_NULLPTR){
reply->deleteLater();
}
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png"));
QString filename = image_path.split(QDir::separator()).last();
QString contentVariant = QString("form-data; name=\"media\"; filename=\"%1\";").arg(filename);
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(contentVariant));
QFile *file = new QFile(image_path);
if(!file->open(QIODevice::ReadOnly)){
qDebug() << "File open failed";
}
imagePart.setBodyDevice(file);
file->setParent(multiPart);
multiPart->append(imagePart);
// Set boundary
// Because boundary is quoted by QNetworkAccessManager, the wechat api is not recognized...
QByteArray m_boundary;
m_boundary.append("multipart/form-data; boundary=");
m_boundary.append(multiPart->boundary());
request.setRawHeader(QByteArray("Content-Type"), m_boundary);
reply = manager.post(request, multiPart);
multiPart->setParent(reply);
qDebug() << "Start uploading images: " + image_path + " Waiting for upload to complete";
uploadImageStatus=true;
currentUploadImage = image_path;
connect(reply, &QNetworkReply::finished, this, &VMdTab::wechatImageBedUploadFinished);
}
void VMdTab::wechatImageBedUploadFinished()
{
if(proDlg->wasCanceled()){
qDebug() << "User stops uploading";
reply->abort();
// If the upload was successful, don't use it!!!
imageUrlMap.clear();
return;
}
switch (reply->error()) {
case QNetworkReply::NoError:
{
QByteArray bytes = reply->readAll();
//qDebug() << "The returned contents are as follows: ";
//QString a = bytes;
//qDebug() << qPrintable(a);
QJsonDocument document = QJsonDocument::fromJson(bytes);
if(!document.isNull()){
if(document.isObject()){
QJsonObject object = document.object();
if(object.contains("url")){
QJsonValue value = object.value("url");
if(value.isString()){
qDebug() << "Authentication successful, get online link";
imageUploaded = true;
proDlg->setValue(uploadImageCount);
imageUrlMap.insert(currentUploadRelativeImagePah, value.toString());
newFileContent.replace(currentUploadRelativeImagePah, value.toString());
// Start calling the method. Whether the value in the map is empty determines whether to stop
wechatImageBedUploadManager();
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Upload failure: ";
QString error = bytes;
qDebug() << bytes;
QString info = tr("upload failed! Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}else{
delete proDlg;
imageUrlMap.clear();
qDebug() << "Resolution failure!";
qDebug() << "Resolution failure's json: " << bytes;
QString info = tr("Json decode error, Please contact the developer~");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
break;
}
default:
{
delete proDlg;
qDebug()<<"Network error: " << reply->errorString() << " error " << reply->error();
QString info = tr("Uploading ") + currentUploadImage + tr(" \n\nNetwork error: ") + reply->errorString() + tr("\n\nPlease check the network or image size");
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), info);
}
}
}
void VMdTab::wechatImageBedReplaceLink(QString file_content, QString file_path)
{
// Write content to clipboard
QClipboard *board = QApplication::clipboard();
board->setText(file_content);
QString url = g_config->getMarkdown2WechatToolUrl();
if(url.isEmpty()){
QMessageBox::warning(NULL, tr("Wechat Image Hosting"), tr("The article has been copied to the clipboard. Please find a text file and save it!!"));
}else{
QMessageBox::StandardButton result;
result = QMessageBox::question(this, tr("Wechat Image Hosting"), tr("The article has been copied to the clipboard. Do you want to open the tool link of mark down to wechat?"), QMessageBox::Yes|QMessageBox::No,QMessageBox::Yes);
if(result == QMessageBox::Yes){
QDesktopServices::openUrl(QUrl(url));
}
}
imageUrlMap.clear();
imageUploaded = false; // reset
} }
VWordCountInfo VMdTab::fetchWordCountInfo(bool p_editMode) const VWordCountInfo VMdTab::fetchWordCountInfo(bool p_editMode) const

View File

@ -1,16 +1,14 @@
#ifndef VMDTAB_H #ifndef VMDTAB_H
#define VMDTAB_H #define VMDTAB_H
#include <QtNetwork>
#include <QString> #include <QString>
#include <QPointer> #include <QPointer>
#include <QSharedPointer> #include <QSharedPointer>
#include <QProgressDialog>
#include <QDesktopServices>
#include "vedittab.h" #include "vedittab.h"
#include "vconstants.h" #include "vconstants.h"
#include "vmarkdownconverter.h" #include "vmarkdownconverter.h"
#include "vconfigmanager.h" #include "vconfigmanager.h"
#include "vimagehosting.h"
class VWebView; class VWebView;
class VDocument; class VDocument;
@ -110,27 +108,6 @@ public:
bool expandRestorePreviewArea(); bool expandRestorePreviewArea();
// github image hosting
// GitHub identity authentication
void authenticateGithubImageHosting(QString p_token);
// Upload a single image
void githubImageBedUploadImage(QString username,QString repository,QString image_path,QString token);
// Parameters needed to generate uploaded images
QString githubImageBedGenerateParam(QString image_path);
// Control image upload
void githubImageBedUploadManager();
// Replace old links with new ones for images
void githubImageBedReplaceLink(QString file_content, QString file_path);
// wechat image hosting
void authenticateWechatImageHosting(QString appid, QString secret);
// Control image upload
void wechatImageBedUploadManager();
// Replace old links with new ones for images
void wechatImageBedReplaceLink(QString file_content, QString file_path);
// Upload a single image
void wechatImageBedUploadImage(QString image_path,QString token);
public slots: public slots:
// Enter edit mode. // Enter edit mode.
void editFile() Q_DECL_OVERRIDE; void editFile() Q_DECL_OVERRIDE;
@ -188,21 +165,9 @@ private slots:
// Process the image upload request to GitHub // Process the image upload request to GitHub
void handleUploadImageToGithubRequested(); void handleUploadImageToGithubRequested();
// GitHub image hosting identity authentication completed
void githubImageBedAuthFinished();
// GitHub image hosting upload completed
void githubImageBedUploadFinished();
// Process image upload request to wechat // Process image upload request to wechat
void handleUploadImageToWechatRequested(); void handleUploadImageToWechatRequested();
// Wechat mage hosting identity authentication completed
void wechatImageBedAuthFinished();
// Wechat image hosting upload completed
void wechatImageBedUploadFinished();
private: private:
enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 }; enum TabReady { None = 0, ReadMode = 0x1, EditMode = 0x2 };
@ -320,28 +285,8 @@ private:
int m_documentID; int m_documentID;
QNetworkAccessManager manager; VGithubImageHosting *vGithubImageHosting;
QNetworkReply *reply; VWechatImageHosting *vWechatImageHosting;
QMap<QString, QString> imageUrlMap;
// Similar to _v_image/
QString imageBasePath;
// Replace the file content with the new link
QString newFileContent;
// Whether the picture has been uploaded successfully
bool imageUploaded;
// Image upload progress bar
QProgressDialog *proDlg;
// Total number of images to upload
int uploadImageCount;
int uploadImageCountIndex;
// Currently uploaded picture name
QString currentUploadImage;
// Image upload status
bool uploadImageStatus;
// Token returned after successful wechat authentication
QString wechatAccessToken;
// Relative image path currently Uploaded
QString currentUploadRelativeImagePah;
}; };
inline VMdEditor *VMdTab::getEditor() inline VMdEditor *VMdTab::getEditor()