1
0

<fix, feature>(core, ui): version system upgrade.

1. can notice user withdraw version now.
2. fix software not restart when signal caught.
3. improve ui.
This commit is contained in:
Saturneric 2022-01-04 06:10:04 +08:00
parent 5cc72a35de
commit 2f64e4300b
13 changed files with 215 additions and 84 deletions

View File

@ -177,6 +177,7 @@ int main(int argc, char* argv[]) {
}
} else {
QApplication::exit(RESTART_CODE);
QMessageBox::information(
nullptr, _("A serious error has occurred"),
_("Oh no! GpgFrontend caught a serious error in the software, so it "

View File

@ -8,6 +8,7 @@ aux_source_directory(./help UI_SOURCE)
aux_source_directory(./settings UI_SOURCE)
aux_source_directory(./function UI_SOURCE)
aux_source_directory(./details UI_SOURCE)
aux_source_directory(./data_struct UI_SOURCE)
if (SMTP_SUPPORT)
aux_source_directory(./smtp UI_SOURCE)

View File

@ -371,8 +371,16 @@ void KeyMgmt::slotExportKeyToKeyPackage() {
}
void KeyMgmt::slotExportKeyToClipboard() {
ByteArrayPtr key_export_data = nullptr;
auto keys_checked = key_list_->getChecked();
if (keys_checked->empty()) {
QMessageBox::critical(
this, _("Forbidden"),
_("Please check some keys before doing this operation."));
return;
}
ByteArrayPtr key_export_data = nullptr;
if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked,
key_export_data)) {
return;

View File

@ -117,12 +117,7 @@ void MainWindow::init() noexcept {
emit loaded();
#ifdef RELEASE
QString baseUrl =
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
QNetworkRequest request;
request.setUrl(QUrl(baseUrl));
auto* replay = networkAccessManager->get(request);
auto version_thread = new VersionCheckThread(replay);
auto version_thread = new VersionCheckThread();
connect(version_thread, SIGNAL(finished()), version_thread,
SLOT(deleteLater()));

View File

@ -244,8 +244,7 @@ class MainWindow : public QMainWindow {
/**
* @details called when need to upgrade.
*/
void slotVersionUpgrade(const QString& currentVersion,
const QString& latestVersion);
void slotVersionUpgrade(const SoftwareVersion& version);
private:
/**

View File

@ -0,0 +1,25 @@
/**
* This file is part of GpgFrontend.
*
* GpgFrontend 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.
*
* Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
*
* The initial version of the source code is inherited from gpg4usb-team.
* Their source code version also complies with GNU General Public License.
*
* The source code version of this software was modified and released
* by Saturneric<eric@bktus.com> starting on May 12, 2021.
*
*/
#include "SoftwareVersion.h"

View File

@ -0,0 +1,53 @@
/**
* This file is part of GpgFrontend.
*
* GpgFrontend 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.
*
* Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
*
* The initial version of the source code is inherited from gpg4usb-team.
* Their source code version also complies with GNU General Public License.
*
* The source code version of this software was modified and released
* by Saturneric<eric@bktus.com> starting on May 12, 2021.
*
*/
#ifndef GPGFRONTEND_SOFTWAREVERSION_H
#define GPGFRONTEND_SOFTWAREVERSION_H
#include <boost/date_time.hpp>
namespace GpgFrontend::UI {
struct SoftwareVersion {
std::string latest_version;
std::string current_version;
bool latest_prerelease = false;
bool latest_draft = false;
bool current_prerelease = false;
bool current_draft = false;
bool load_info_done = false;
std::string publish_date;
std::string release_note;
[[nodiscard]] bool NeedUpgrade() const {
return load_info_done && !latest_prerelease && !latest_draft &&
current_version < latest_version;
}
[[nodiscard]] bool VersionWithDrawn() const {
return load_info_done && current_prerelease && !current_draft;
}
};
} // namespace GpgFrontend::UI
#endif // GPGFRONTEND_SOFTWAREVERSION_H

View File

@ -24,8 +24,7 @@
#include "VersionCheckThread.h"
#include <iterator>
#include <regex>
#include <QMetaType>
#include "GpgFrontendBuildInfo.h"
#include "json/json.hpp"
@ -33,45 +32,97 @@
namespace GpgFrontend::UI {
void VersionCheckThread::run() {
using namespace nlohmann;
LOG(INFO) << "get latest version from Github";
auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) +
"." + std::to_string(VERSION_MINOR) + "." +
std::to_string(VERSION_PATCH);
while (mNetworkReply->isRunning()) {
QApplication::processEvents();
}
auto manager = new QNetworkAccessManager(nullptr);
if (mNetworkReply->error() != QNetworkReply::NoError) {
LOG(INFO) << "current version" << current_version;
std::string latest_version_url =
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
std::string current_version_url =
"https://api.github.com/repos/saturneric/gpgfrontend/releases/tags/" +
current_version;
QNetworkRequest latest_request, current_request;
latest_request.setUrl(QUrl(latest_version_url.c_str()));
current_request.setUrl(QUrl(current_version_url.c_str()));
auto reply = manager->get(latest_request);
while (reply->isRunning()) QApplication::processEvents();
if (reply->error() != QNetworkReply::NoError) {
LOG(ERROR) << "network error";
manager->deleteLater();
return;
}
auto bytes = mNetworkReply->readAll();
auto reply_json = nlohmann::json::parse(bytes.toStdString());
std::string latest_version = reply_json["tag_name"];
LOG(INFO) << "latest version from Github" << latest_version;
QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
auto version_match = re.match(latest_version.c_str());
if (version_match.hasMatch()) {
latest_version = version_match.captured(0).toStdString();
LOG(INFO) << "latest version matched" << latest_version;
} else {
latest_version = current_version;
LOG(WARNING) << "latest version unknown";
latest_reply_bytes_ = reply->readAll();
reply = manager->get(current_request);
while (reply->isRunning()) QApplication::processEvents();
current_reply_bytes_ = reply->readAll();
if (reply->error() != QNetworkReply::NoError) {
LOG(ERROR) << "network error";
manager->deleteLater();
return;
}
emit upgradeVersion(current_version.c_str(), latest_version.c_str());
SoftwareVersion version;
version.current_version = current_version;
try {
using namespace nlohmann;
auto latest_reply_json =
nlohmann::json::parse(latest_reply_bytes_.toStdString());
auto current_reply_json =
nlohmann::json::parse(current_reply_bytes_.toStdString());
std::string latest_version = latest_reply_json["tag_name"];
LOG(INFO) << "latest version from Github" << latest_version;
QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
auto version_match = re.match(latest_version.c_str());
if (version_match.hasMatch()) {
latest_version = version_match.captured(0).toStdString();
LOG(INFO) << "latest version matched" << latest_version;
} else {
latest_version = current_version;
LOG(WARNING) << "latest version unknown";
}
bool prerelease = latest_reply_json["prerelease"],
draft = latest_reply_json["draft"];
std::string publish_date = latest_reply_json["published_at"];
std::string release_note = latest_reply_json["body"];
version.latest_version = latest_version;
version.latest_prerelease = prerelease;
version.latest_draft = draft;
version.publish_date = publish_date;
version.release_note = release_note;
bool current_prerelease = current_reply_json["prerelease"],
current_draft = current_reply_json["draft"];
version.latest_prerelease = current_prerelease;
version.latest_draft = current_draft;
// loading done
version.load_info_done = true;
} catch (...) {
LOG(INFO) << "error occurred";
version.load_info_done = false;
}
manager->deleteLater();
emit upgradeVersion(version);
}
VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply)
: mNetworkReply(networkReply) {}
VersionCheckThread::VersionCheckThread() : QThread(nullptr) {
qRegisterMetaType<SoftwareVersion>("SoftwareVersion");
};
} // namespace GpgFrontend::UI

View File

@ -26,6 +26,7 @@
#define GPGFRONTEND_VERSIONCHECKTHREAD_H
#include "ui/GpgFrontendUI.h"
#include "ui/data_struct/SoftwareVersion.h"
namespace GpgFrontend::UI {
@ -33,18 +34,17 @@ class VersionCheckThread : public QThread {
Q_OBJECT
public:
explicit VersionCheckThread(QNetworkReply* networkReply);
explicit VersionCheckThread();
signals:
void upgradeVersion(const QString& currentVersion,
const QString& latestVersion);
void upgradeVersion(SoftwareVersion version);
protected:
void run() override;
private:
QNetworkReply* mNetworkReply;
QByteArray latest_reply_bytes_, current_reply_bytes_;
};
} // namespace GpgFrontend::UI

View File

@ -163,14 +163,6 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) {
latestVersionLabel->setWordWrap(true);
upgradeLabel = new QLabel();
upgradeLabel->setText(
"<center>" +
QString(_("The current version is less than the latest version on "
"github.")) +
"</center><center>" + _("Please click") +
" <a "
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
_("Here") + "</a> " + _("to download the latest version.") + "</center>");
upgradeLabel->setWordWrap(true);
upgradeLabel->setOpenExternalLinks(true);
upgradeLabel->setHidden(true);
@ -196,11 +188,7 @@ void UpdateTab::getLatestVersion() {
LOG(INFO) << _("try to get latest version");
QString base_url =
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
QNetworkRequest request;
request.setUrl(QUrl(base_url));
auto version_thread = new VersionCheckThread(manager->get(request));
auto version_thread = new VersionCheckThread();
connect(version_thread, SIGNAL(finished()), version_thread,
SLOT(deleteLater()));
@ -210,16 +198,33 @@ void UpdateTab::getLatestVersion() {
version_thread->start();
}
void UpdateTab::slotShowVersionStatus(const QString& current,
const QString& server) {
void UpdateTab::slotShowVersionStatus(const SoftwareVersion& version) {
this->pb->setHidden(true);
latestVersionLabel->setText("<center><b>" +
QString(_("Latest Version From Github")) + ": " +
server + "</b></center>");
version.latest_version.c_str() + "</b></center>");
if (current < server) {
if (version.NeedUpgrade()) {
upgradeLabel->setText(
"<center>" +
QString(_("The current version is less than the latest version on "
"github.")) +
"</center><center>" + _("Please click") +
" <a "
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
_("Here") + "</a> " + _("to download the latest stable version.") +
"</center>");
upgradeLabel->show();
} else if (version.VersionWithDrawn()) {
upgradeLabel->setText(
"<center>" +
QString(_("This version has serious problems and has been withdrawn. "
"Please stop using it immediately.")) +
"</center><center>" + _("Please click") +
" <a "
"href=\"https://github.com/saturneric/GpgFrontend/releases\">" +
_("Here") + "</a> " + _("to download the latest stable version.") +
"</center>");
}
}

View File

@ -27,6 +27,8 @@
#include "gpg/GpgContext.h"
#include "ui/GpgFrontendUI.h"
#include "ui/data_struct/SoftwareVersion.h"
namespace GpgFrontend::UI {
/**
@ -73,7 +75,7 @@ class UpdateTab : public QWidget {
void getLatestVersion();
private slots:
void slotShowVersionStatus(const QString& current, const QString& server);
void slotShowVersionStatus(const SoftwareVersion& version);
signals:
void replyFromUpdateServer(QByteArray data);

View File

@ -499,13 +499,12 @@ void MainWindow::uploadKeyToServer() {
void MainWindow::slotOpenFile(QString& path) { edit->slotOpenFile(path); }
void MainWindow::slotVersionUpgrade(const QString& currentVersion,
const QString& latestVersion) {
void MainWindow::slotVersionUpgrade(const SoftwareVersion& version) {
LOG(INFO) << _("called");
if (currentVersion < latestVersion) {
if (version.NeedUpgrade()) {
statusBar()->showMessage(
QString(_("GpgFrontend Upgradeable (New Version: %1)."))
.arg(latestVersion),
.arg(version.latest_version.c_str()),
30000);
auto update_button = new QPushButton("Update GpgFrontend", this);
connect(update_button, &QPushButton::clicked, [=]() {
@ -513,17 +512,19 @@ void MainWindow::slotVersionUpgrade(const QString& currentVersion,
about_dialog->show();
});
statusBar()->addPermanentWidget(update_button, 0);
} else if (currentVersion > latestVersion) {
} else if (version.VersionWithDrawn()) {
QMessageBox::warning(
this, _("Unreleased Version"),
this, _("Withdrawn Version"),
QString(
_("This version(%1) has not been officially released and is not "
"recommended for use in a production environment. <br/>"))
.arg(currentVersion) +
QString(
_("You can download the latest version(%1) on Github Releases "
"Page.<br/>"))
.arg(latestVersion));
_("This version(%1) may have been withdrawn by the developer due "
"to serious problems. Please stop using this version "
"immediately and use the latest stable version."))
.arg(version.current_version.c_str()) +
"<br/>" +
QString(_("You can download the latest stable version(%1) on "
"Github Releases "
"Page.<br/>"))
.arg(version.latest_version.c_str()));
}
}

View File

@ -451,16 +451,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="saveDraftButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Save Draft</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QPushButton" name="sendMailButton">
<property name="text">