1#include "GitQlientUpdater.h"
2
3#include <GitQlientStyles.h>
4#include <QLogger.h>
5
6#include <QFile>
7#include <QJsonDocument>
8#include <QJsonObject>
9#include <QMessageBox>
10#include <QNetworkAccessManager>
11#include <QNetworkReply>
12#include <QNetworkRequest>
13#include <QProgressDialog>
14#include <QStandardPaths>
15#include <QTimer>
16
17using namespace QLogger;
18
19GitQlientUpdater::GitQlientUpdater(QObject *parent)
20 : QObject(parent)
21 , mManager(new QNetworkAccessManager())
22{
23}
24
25GitQlientUpdater::~GitQlientUpdater()
26{
27 delete mManager;
28}
29
30void GitQlientUpdater::checkNewGitQlientVersion()
31{
32 QNetworkRequest request;
33 request.setRawHeader("User-Agent", "GitQlient");
34 request.setRawHeader("X-Custom-User-Agent", "GitQlient");
35 request.setRawHeader("Content-Type", "application/json");
36 request.setUrl(QUrl("https://github.com/francescmm/ci-utils/releases/download/gq_update/updates.json"));
37 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
38
39 const auto reply = mManager->get(request);
40 connect(reply, &QNetworkReply::finished, this, &GitQlientUpdater::processUpdateFile);
41}
42
43void GitQlientUpdater::showInfoMessage()
44{
45 QMessageBox msgBox(
46 QMessageBox::Information, tr("New version of GitQlient!"),
47 QString(tr("There is a new version of GitQlient available. Your current version is {%1} and the new "
48 "one is {%2}. You can read more about the new changes in the detailed description."))
49 .arg(VER, mLatestGitQlient),
50 QMessageBox::Ok | QMessageBox::Close, qobject_cast<QWidget *>(parent()));
51 msgBox.setButtonText(QMessageBox::Ok, tr("Download"));
52 msgBox.setDetailedText(mChangeLog);
53 msgBox.setStyleSheet(GitQlientStyles::getStyles());
54
55 if (msgBox.exec() == QMessageBox::Ok)
56 downloadFile();
57}
58
59void GitQlientUpdater::processUpdateFile()
60{
61 const auto reply = qobject_cast<QNetworkReply *>(sender());
62 const auto data = reply->readAll();
63 const auto jsonDoc = QJsonDocument::fromJson(data);
64
65 if (jsonDoc.isNull())
66 {
67 QLog_Error("Ui", QString("Error when parsing Json. Current data:\n%1").arg(QString::fromUtf8(data)));
68 return;
69 }
70
71 const auto json = jsonDoc.object();
72
73 mLatestGitQlient = json["latest-version"].toString();
74 const auto changeLogUrl = json["changelog"].toString();
75
76 QJsonObject os;
77 auto platformSupported = true;
78#if defined(Q_OS_WIN)
79 os = json["windows"].toObject();
80#elif defined(Q_OS_LINUX)
81 os = json["linux"].toObject();
82#elif defined(Q_OS_OSX)
83 os = json["osx"].toObject();
84#else
85 platformSupported = false;
86 QLog_Error("Ui", QString("Platform not supported for updates"));
87#endif
88
89 const auto curVersion = QString("%1").arg(VER).split(".");
90
91 if (curVersion.count() == 1)
92 return;
93
94 const auto newVersion = mLatestGitQlient.split(".");
95 const auto nv = newVersion.at(0).toInt() * 10000 + newVersion.at(1).toInt() * 100 + newVersion.at(2).toInt();
96 const auto cv = curVersion.at(0).toInt() * 10000 + curVersion.at(1).toInt() * 100 + curVersion.at(2).toInt();
97
98 if (nv > cv)
99 {
100 if (!platformSupported)
101 {
102 QMessageBox::information(
103 qobject_cast<QWidget *>(parent()), tr("New version available!"),
104 tr("There is a new version of GitQlient available but your OS doesn't have a binary built. If you want to "
105 "get the latest version, please <a href='https://github.com/francescmm/GitQlient/releases/tag/v%1'>get "
106 "the source code from GitHub</a>.")
107 .arg(mLatestGitQlient));
108 }
109 else
110 {
111 mGitQlientDownloadUrl = os["download-url"].toString();
112 emit newVersionAvailable();
113
114 QTimer::singleShot(200, this, [this, changeLogUrl] {
115 QNetworkRequest request;
116 request.setRawHeader("User-Agent", "GitQlient");
117 request.setRawHeader("X-Custom-User-Agent", "GitQlient");
118 request.setRawHeader("Content-Type", "application/json");
119 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
120 request.setUrl(QUrl(changeLogUrl));
121
122 const auto reply = mManager->get(request);
123
124 connect(reply, &QNetworkReply::finished, this, &GitQlientUpdater::processChangeLog);
125 });
126 }
127 }
128}
129
130void GitQlientUpdater::processChangeLog()
131{
132 const auto reply = qobject_cast<QNetworkReply *>(sender());
133 mChangeLog = QString::fromUtf8(reply->readAll());
134}
135
136void GitQlientUpdater::downloadFile()
137{
138 QNetworkRequest request;
139 request.setRawHeader("User-Agent", "GitQlient");
140 request.setRawHeader("X-Custom-User-Agent", "GitQlient");
141 request.setRawHeader("Content-Type", "application/octet-stream");
142 request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, true);
143 request.setUrl(QUrl(mGitQlientDownloadUrl));
144
145 const auto fileName = mGitQlientDownloadUrl.split("/").last();
146
147 const auto reply = mManager->get(request);
148
149 connect(reply, &QNetworkReply::downloadProgress, this, [this](qint64 read, qint64 total) {
150 if (mDownloadLog == nullptr)
151 {
152 mDownloadLog
153 = new QProgressDialog(tr("Downloading..."), tr("Close"), 0, total, qobject_cast<QWidget *>(parent()));
154 mDownloadLog->setAttribute(Qt::WA_DeleteOnClose);
155 mDownloadLog->setAutoClose(false);
156 mDownloadLog->setAutoReset(false);
157 mDownloadLog->setMaximum(total);
158 mDownloadLog->setCancelButton(nullptr);
159 mDownloadLog->setWindowFlag(Qt::FramelessWindowHint);
160
161 connect(mDownloadLog, &QProgressDialog::destroyed, this, [this]() { mDownloadLog = nullptr; });
162 }
163
164 mDownloadLog->setValue(read);
165 mDownloadLog->show();
166 });
167
168 connect(reply, &QNetworkReply::finished, this, [this, reply, fileName]() {
169 mDownloadLog->close();
170 mDownloadLog = nullptr;
171
172 const auto b = reply->readAll();
173 const auto destination = QString("%1/%2").arg(
174 QStandardPaths::standardLocations(QStandardPaths::DownloadLocation).constFirst(), fileName);
175 QFile file(destination);
176 if (file.open(QIODevice::WriteOnly))
177 {
178 QDataStream out(&file);
179 out << b;
180
181 file.close();
182 }
183
184 reply->deleteLater();
185 });
186}
187