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 { } else {
QApplication::exit(RESTART_CODE);
QMessageBox::information( QMessageBox::information(
nullptr, _("A serious error has occurred"), nullptr, _("A serious error has occurred"),
_("Oh no! GpgFrontend caught a serious error in the software, so it " _("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(./settings UI_SOURCE)
aux_source_directory(./function UI_SOURCE) aux_source_directory(./function UI_SOURCE)
aux_source_directory(./details UI_SOURCE) aux_source_directory(./details UI_SOURCE)
aux_source_directory(./data_struct UI_SOURCE)
if (SMTP_SUPPORT) if (SMTP_SUPPORT)
aux_source_directory(./smtp UI_SOURCE) aux_source_directory(./smtp UI_SOURCE)

View File

@ -371,8 +371,16 @@ void KeyMgmt::slotExportKeyToKeyPackage() {
} }
void KeyMgmt::slotExportKeyToClipboard() { void KeyMgmt::slotExportKeyToClipboard() {
ByteArrayPtr key_export_data = nullptr;
auto keys_checked = key_list_->getChecked(); 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, if (!GpgKeyImportExporter::GetInstance().ExportKeys(keys_checked,
key_export_data)) { key_export_data)) {
return; return;

View File

@ -117,12 +117,7 @@ void MainWindow::init() noexcept {
emit loaded(); emit loaded();
#ifdef RELEASE #ifdef RELEASE
QString baseUrl = auto version_thread = new VersionCheckThread();
"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);
connect(version_thread, SIGNAL(finished()), version_thread, connect(version_thread, SIGNAL(finished()), version_thread,
SLOT(deleteLater())); SLOT(deleteLater()));

View File

@ -244,8 +244,7 @@ class MainWindow : public QMainWindow {
/** /**
* @details called when need to upgrade. * @details called when need to upgrade.
*/ */
void slotVersionUpgrade(const QString& currentVersion, void slotVersionUpgrade(const SoftwareVersion& version);
const QString& latestVersion);
private: 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 "VersionCheckThread.h"
#include <iterator> #include <QMetaType>
#include <regex>
#include "GpgFrontendBuildInfo.h" #include "GpgFrontendBuildInfo.h"
#include "json/json.hpp" #include "json/json.hpp"
@ -33,45 +32,97 @@
namespace GpgFrontend::UI { namespace GpgFrontend::UI {
void VersionCheckThread::run() { void VersionCheckThread::run() {
using namespace nlohmann;
LOG(INFO) << "get latest version from Github";
auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) + auto current_version = std::string("v") + std::to_string(VERSION_MAJOR) +
"." + std::to_string(VERSION_MINOR) + "." + "." + std::to_string(VERSION_MINOR) + "." +
std::to_string(VERSION_PATCH); std::to_string(VERSION_PATCH);
while (mNetworkReply->isRunning()) { auto manager = new QNetworkAccessManager(nullptr);
QApplication::processEvents();
}
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"; LOG(ERROR) << "network error";
manager->deleteLater();
return; return;
} }
auto bytes = mNetworkReply->readAll(); latest_reply_bytes_ = reply->readAll();
reply = manager->get(current_request);
auto reply_json = nlohmann::json::parse(bytes.toStdString()); while (reply->isRunning()) QApplication::processEvents();
current_reply_bytes_ = reply->readAll();
std::string latest_version = reply_json["tag_name"]; if (reply->error() != QNetworkReply::NoError) {
LOG(ERROR) << "network error";
LOG(INFO) << "latest version from Github" << latest_version; manager->deleteLater();
return;
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";
} }
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) VersionCheckThread::VersionCheckThread() : QThread(nullptr) {
: mNetworkReply(networkReply) {} qRegisterMetaType<SoftwareVersion>("SoftwareVersion");
};
} // namespace GpgFrontend::UI } // namespace GpgFrontend::UI

View File

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

View File

@ -163,14 +163,6 @@ UpdateTab::UpdateTab(QWidget* parent) : QWidget(parent) {
latestVersionLabel->setWordWrap(true); latestVersionLabel->setWordWrap(true);
upgradeLabel = new QLabel(); 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->setWordWrap(true);
upgradeLabel->setOpenExternalLinks(true); upgradeLabel->setOpenExternalLinks(true);
upgradeLabel->setHidden(true); upgradeLabel->setHidden(true);
@ -196,11 +188,7 @@ void UpdateTab::getLatestVersion() {
LOG(INFO) << _("try to get latest version"); LOG(INFO) << _("try to get latest version");
QString base_url = auto version_thread = new VersionCheckThread();
"https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
QNetworkRequest request;
request.setUrl(QUrl(base_url));
auto version_thread = new VersionCheckThread(manager->get(request));
connect(version_thread, SIGNAL(finished()), version_thread, connect(version_thread, SIGNAL(finished()), version_thread,
SLOT(deleteLater())); SLOT(deleteLater()));
@ -210,16 +198,33 @@ void UpdateTab::getLatestVersion() {
version_thread->start(); version_thread->start();
} }
void UpdateTab::slotShowVersionStatus(const QString& current, void UpdateTab::slotShowVersionStatus(const SoftwareVersion& version) {
const QString& server) {
this->pb->setHidden(true); this->pb->setHidden(true);
latestVersionLabel->setText("<center><b>" + latestVersionLabel->setText("<center><b>" +
QString(_("Latest Version From Github")) + ": " + 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(); 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 "gpg/GpgContext.h"
#include "ui/GpgFrontendUI.h" #include "ui/GpgFrontendUI.h"
#include "ui/data_struct/SoftwareVersion.h"
namespace GpgFrontend::UI { namespace GpgFrontend::UI {
/** /**
@ -73,7 +75,7 @@ class UpdateTab : public QWidget {
void getLatestVersion(); void getLatestVersion();
private slots: private slots:
void slotShowVersionStatus(const QString& current, const QString& server); void slotShowVersionStatus(const SoftwareVersion& version);
signals: signals:
void replyFromUpdateServer(QByteArray data); void replyFromUpdateServer(QByteArray data);

View File

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

View File

@ -451,16 +451,6 @@
</property> </property>
</spacer> </spacer>
</item> </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"> <item alignment="Qt::AlignRight">
<widget class="QPushButton" name="sendMailButton"> <widget class="QPushButton" name="sendMailButton">
<property name="text"> <property name="text">