mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-05-25 06:58:23 -05:00
dbhub: Make network code less centralised
This adds the possibility to handle network replies individually instead of routing all of them through a central handler routine. The centralised approach made the code more complicated than necessary and would inevitably lead to confusion when sending similar requests simultaneously.
This commit is contained in:
+13
-3
@@ -96,10 +96,21 @@ void MainWindow::init()
|
||||
|
||||
// Automatic update check
|
||||
#ifdef CHECKNEWVERSION
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::networkReady, []() {
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::networkReady, [this]() {
|
||||
// Check for a new version if automatic update check aren't disabled in the settings dialog
|
||||
if(Settings::getValue("checkversion", "enabled").toBool())
|
||||
RemoteNetwork::get().fetch(QUrl("https://download.sqlitebrowser.org/currentrelease"), RemoteNetwork::RequestTypeNewVersionCheck);
|
||||
{
|
||||
RemoteNetwork::get().fetch(QUrl("https://download.sqlitebrowser.org/currentrelease"), RemoteNetwork::RequestTypeCustom,
|
||||
QString(), QVariant(), [this](const QByteArray& reply) {
|
||||
QList<QByteArray> info = reply.split('\n');
|
||||
if(info.size() >= 2)
|
||||
{
|
||||
QString version = info.at(0).trimmed();
|
||||
QString url = info.at(1).trimmed();
|
||||
checkNewVersion(version, url);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
@@ -386,7 +397,6 @@ void MainWindow::init()
|
||||
connect(ui->dbTreeWidget->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::changeTreeSelection);
|
||||
connect(ui->dockEdit, &QDockWidget::visibilityChanged, this, &MainWindow::toggleEditDock);
|
||||
connect(remoteDock, SIGNAL(openFile(QString)), this, SLOT(fileOpen(QString)));
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::gotCurrentVersion, this, &MainWindow::checkNewVersion);
|
||||
connect(ui->actionDropQualifiedCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropQualifiedNames);
|
||||
connect(ui->actionEnquoteNamesCheck, &QAction::toggled, dbStructureModel, &DbStructureModel::setDropEnquotedNames);
|
||||
connect(&db, &DBBrowserDB::databaseInUseChanged, this, &MainWindow::updateDatabaseBusyStatus);
|
||||
|
||||
+22
-18
@@ -6,6 +6,8 @@
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
#include <json.hpp>
|
||||
|
||||
#include "RemoteDock.h"
|
||||
#include "ui_RemoteDock.h"
|
||||
#include "Settings.h"
|
||||
@@ -17,6 +19,8 @@
|
||||
#include "RemotePushDialog.h"
|
||||
#include "PreferencesDialog.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
RemoteDock::RemoteDock(MainWindow* parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::RemoteDock),
|
||||
@@ -46,9 +50,6 @@ RemoteDock::RemoteDock(MainWindow* parent)
|
||||
// Whenever a new directory listing has been parsed, check if it was a new root dir and, if so, open the user's directory
|
||||
connect(remoteModel, &RemoteModel::directoryListingParsed, this, &RemoteDock::newDirectoryNode);
|
||||
|
||||
// Show metadata for a database when we get it
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::gotMetadata, this, &RemoteDock::showMetadata);
|
||||
|
||||
// When the Preferences link is clicked in the no-certificates-label, open the preferences dialog. For other links than the ones we know,
|
||||
// just open them in a web browser
|
||||
connect(ui->labelNoCert, &QLabel::linkActivated, [this](const QString& link) {
|
||||
@@ -448,30 +449,33 @@ void RemoteDock::fileOpened(const QString& filename)
|
||||
|
||||
void RemoteDock::refreshMetadata(const QString& username, const QString& dbname)
|
||||
{
|
||||
// Make request for meta data
|
||||
QUrl url(RemoteNetwork::get().getInfoFromClientCert(remoteModel->currentClientCertificate(), RemoteNetwork::CertInfoServer) + "/metadata/get");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("username", username);
|
||||
query.addQueryItem("folder", "/");
|
||||
query.addQueryItem("dbname", dbname);
|
||||
url.setQuery(query);
|
||||
RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeMetadata, remoteModel->currentClientCertificate());
|
||||
}
|
||||
RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, remoteModel->currentClientCertificate(), [this](const QByteArray& reply) {
|
||||
// Read and check results
|
||||
json obj = json::parse(reply, nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
return;
|
||||
|
||||
void RemoteDock::showMetadata(const std::vector<RemoteMetadataBranchInfo>& branches, const std::string& commits,
|
||||
const std::vector<RemoteMetadataReleaseInfo>& /*releases*/, const std::vector<RemoteMetadataReleaseInfo>& /*tags*/,
|
||||
const std::string& /*default_branch*/, const std::string& web_page)
|
||||
{
|
||||
// Store all the commit information as-is
|
||||
current_commit_json = commits;
|
||||
// Store all the commit information as-is
|
||||
json obj_commits = obj["commits"];
|
||||
current_commit_json = obj_commits.dump();
|
||||
|
||||
// Store the link to the web page in the action for opening that link in a browser
|
||||
ui->actionDatabaseOpenBrowser->setData(QString::fromStdString(web_page));
|
||||
// Store the link to the web page in the action for opening that link in a browser
|
||||
ui->actionDatabaseOpenBrowser->setData(QString::fromStdString(obj["web_page"]));
|
||||
|
||||
// Fill branches combo box
|
||||
ui->comboDatabaseBranch->clear();
|
||||
for(const auto& branch : branches)
|
||||
ui->comboDatabaseBranch->addItem(QString::fromStdString(branch.name), QString::fromStdString(branch.commit_id));
|
||||
ui->comboDatabaseBranch->setCurrentIndex(ui->comboDatabaseBranch->findText(ui->editDatabaseBranch->text()));
|
||||
// Fill branches combo box
|
||||
json obj_branches = obj["branches"];
|
||||
ui->comboDatabaseBranch->clear();
|
||||
for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it)
|
||||
ui->comboDatabaseBranch->addItem(QString::fromStdString(it.key()), QString::fromStdString(it.value()["commit"]));
|
||||
ui->comboDatabaseBranch->setCurrentIndex(ui->comboDatabaseBranch->findText(ui->editDatabaseBranch->text()));
|
||||
});
|
||||
}
|
||||
|
||||
void RemoteDock::deleteLocalDatabase(const QModelIndex& index)
|
||||
|
||||
@@ -44,9 +44,6 @@ private slots:
|
||||
void newDirectoryNode(const QModelIndex& parent);
|
||||
void switchToMainView();
|
||||
void openLocalFile(const QModelIndex& idx);
|
||||
void showMetadata(const std::vector<RemoteMetadataBranchInfo>& branches, const std::string& commits,
|
||||
const std::vector<RemoteMetadataReleaseInfo>& releases, const std::vector<RemoteMetadataReleaseInfo>& tags,
|
||||
const std::string& default_branch, const std::string& web_page);
|
||||
void deleteLocalDatabase(const QModelIndex& index);
|
||||
void openCurrentDatabaseInBrowser() const;
|
||||
void refresh();
|
||||
|
||||
+7
-6
@@ -103,8 +103,6 @@ RemoteModel::RemoteModel(QObject* parent) :
|
||||
headerList({tr("Name"), tr("Last modified"), tr("Size"), tr("Commit")}),
|
||||
rootItem(new RemoteModelItem())
|
||||
{
|
||||
// Set up signals
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::gotDirList, this, &RemoteModel::parseDirectoryListing);
|
||||
}
|
||||
|
||||
RemoteModel::~RemoteModel()
|
||||
@@ -128,10 +126,12 @@ void RemoteModel::setNewRootDir(const QString& url, const QString& cert)
|
||||
void RemoteModel::refresh()
|
||||
{
|
||||
// Fetch root directory and put the reply data under the root item
|
||||
RemoteNetwork::get().fetch(currentRootDirectory, RemoteNetwork::RequestTypeDirectory, currentClientCert, QModelIndex());
|
||||
RemoteNetwork::get().fetch(currentRootDirectory, RemoteNetwork::RequestTypeCustom, currentClientCert, [this](const QByteArray& reply) {
|
||||
parseDirectoryListing(reply, QModelIndex());
|
||||
});
|
||||
}
|
||||
|
||||
void RemoteModel::parseDirectoryListing(const QString& text, const QVariant& userdata)
|
||||
void RemoteModel::parseDirectoryListing(const QString& text, QModelIndex parent)
|
||||
{
|
||||
// Load new JSON root document assuming it's an array
|
||||
json array = json::parse(text.toStdString(), nullptr, false);
|
||||
@@ -139,7 +139,6 @@ void RemoteModel::parseDirectoryListing(const QString& text, const QVariant& use
|
||||
return;
|
||||
|
||||
// Get model index to store the new data under
|
||||
QModelIndex parent = userdata.toModelIndex();
|
||||
RemoteModelItem* parentItem = const_cast<RemoteModelItem*>(modelIndexToItem(parent));
|
||||
|
||||
// An invalid model index indicates that this is a new root item. This means the old one needs to be entirely deleted first.
|
||||
@@ -306,7 +305,9 @@ void RemoteModel::fetchMore(const QModelIndex& parent)
|
||||
|
||||
// Fetch item URL
|
||||
item->setFetchedDirectoryList(true);
|
||||
RemoteNetwork::get().fetch(item->value(RemoteModelColumnUrl).toUrl(), RemoteNetwork::RequestTypeDirectory, currentClientCert, parent);
|
||||
RemoteNetwork::get().fetch(item->value(RemoteModelColumnUrl).toUrl(), RemoteNetwork::RequestTypeCustom, currentClientCert, [this, parent](const QByteArray& reply) {
|
||||
parseDirectoryListing(reply, parent);
|
||||
});
|
||||
}
|
||||
|
||||
const QString& RemoteModel::currentClientCertificate() const
|
||||
|
||||
+2
-3
@@ -92,9 +92,8 @@ signals:
|
||||
void directoryListingParsed(QModelIndex parent);
|
||||
|
||||
private slots:
|
||||
// This is called whenever a network reply containing a directory listing arrives. json contains the reply data, userdata
|
||||
// contains some custom data passed to the request. In this case we expect this to be the model index of the parent tree item.
|
||||
void parseDirectoryListing(const QString& text, const QVariant& userdata);
|
||||
// This is called whenever a network reply containing a directory listing arrives
|
||||
void parseDirectoryListing(const QString& text, QModelIndex parent);
|
||||
|
||||
private:
|
||||
// The header list is a list of column titles
|
||||
|
||||
+38
-117
@@ -53,7 +53,6 @@ RemoteNetwork::RemoteNetwork() :
|
||||
reloadSettings();
|
||||
|
||||
// Set up signals
|
||||
connect(m_manager, &QNetworkAccessManager::finished, this, &RemoteNetwork::gotReply);
|
||||
connect(m_manager, &QNetworkAccessManager::encrypted, this, &RemoteNetwork::gotEncrypted);
|
||||
connect(m_manager, &QNetworkAccessManager::sslErrors, this, &RemoteNetwork::gotError);
|
||||
}
|
||||
@@ -161,35 +160,6 @@ void RemoteNetwork::gotEncrypted(QNetworkReply* reply)
|
||||
|
||||
void RemoteNetwork::gotReply(QNetworkReply* reply)
|
||||
{
|
||||
// Check if request was successful
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
// Do not show error message when operation was cancelled on purpose
|
||||
if(reply->error() != QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
QMessageBox::warning(nullptr, qApp->applicationName(),
|
||||
reply->errorString() + "\n" + reply->readAll());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for redirect
|
||||
QString redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toString();
|
||||
if(!redirectUrl.isEmpty())
|
||||
{
|
||||
// Avoid redirect loop
|
||||
if(reply->url() == redirectUrl)
|
||||
{
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
fetch(redirectUrl, static_cast<RequestType>(reply->property("type").toInt()), reply->property("certfile").toString(), reply->property("userdata"));
|
||||
reply->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// What type of data is this?
|
||||
RequestType type = static_cast<RequestType>(reply->property("type").toInt());
|
||||
|
||||
@@ -222,56 +192,6 @@ void RemoteNetwork::gotReply(QNetworkReply* reply)
|
||||
reply);
|
||||
}
|
||||
break;
|
||||
case RequestTypeDirectory:
|
||||
emit gotDirList(reply->readAll(), reply->property("userdata"));
|
||||
break;
|
||||
case RequestTypeNewVersionCheck:
|
||||
{
|
||||
QString version = reply->readLine().trimmed();
|
||||
QString url = reply->readLine().trimmed();
|
||||
emit gotCurrentVersion(version, url);
|
||||
break;
|
||||
}
|
||||
case RequestTypeLicenceList:
|
||||
{
|
||||
// Read and check results
|
||||
json obj = json::parse(reply->readAll(), nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
break;
|
||||
|
||||
// Parse data and build ordered licence map: order -> (short name, long name)
|
||||
std::map<int, std::pair<std::string, std::string>> licences;
|
||||
for(auto it=obj.cbegin();it!=obj.cend();++it)
|
||||
licences.insert({it.value()["order"], {it.key(), it.value()["full_name"]}});
|
||||
|
||||
// Convert the map into an ordered vector and send it to anyone who's interested
|
||||
std::vector<std::pair<std::string, std::string>> licence_list;
|
||||
std::transform(licences.begin(), licences.end(), std::back_inserter(licence_list), [](const std::pair<int, std::pair<std::string, std::string>>& it) {
|
||||
return it.second;
|
||||
});
|
||||
emit gotLicenceList(licence_list);
|
||||
break;
|
||||
}
|
||||
case RequestTypeBranchList:
|
||||
{
|
||||
// Read and check results
|
||||
json obj = json::parse(reply->readAll(), nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
break;
|
||||
json obj_branches = obj["branches"];
|
||||
|
||||
// Parse data and assemble branch list
|
||||
std::vector<std::string> branches;
|
||||
for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it)
|
||||
branches.push_back(it.key());
|
||||
|
||||
// Get default branch
|
||||
std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "master";
|
||||
|
||||
// Send branch list to anyone who is interested
|
||||
emit gotBranchList(branches, default_branch);
|
||||
break;
|
||||
}
|
||||
case RequestTypePush:
|
||||
{
|
||||
// Read and check results
|
||||
@@ -288,41 +208,6 @@ void RemoteNetwork::gotReply(QNetworkReply* reply)
|
||||
reply->property("source_file").toString());
|
||||
break;
|
||||
}
|
||||
case RequestTypeMetadata:
|
||||
{
|
||||
// Read and check results
|
||||
json obj = json::parse(reply->readAll(), nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
break;
|
||||
|
||||
// Extract and convert data
|
||||
json obj_branches = obj["branches"];
|
||||
json obj_commits = obj["commits"];
|
||||
json obj_releases = obj["releases"];
|
||||
json obj_tags = obj["tags"];
|
||||
std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "master";
|
||||
std::vector<RemoteMetadataBranchInfo> branches;
|
||||
for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it)
|
||||
branches.emplace_back(it.key(), it.value()["commit"], it.value()["description"], it.value()["commit_count"]);
|
||||
std::vector<RemoteMetadataReleaseInfo> releases;
|
||||
for(auto it=obj_releases.cbegin();it!=obj_releases.cend();++it)
|
||||
{
|
||||
releases.emplace_back(it.key(), it.value()["commit"], it.value()["date"],
|
||||
it.value()["description"], it.value()["email"],
|
||||
it.value()["name"], it.value()["size"]);
|
||||
}
|
||||
std::vector<RemoteMetadataReleaseInfo> tags;
|
||||
for(auto it=obj_tags.cbegin();it!=obj_tags.cend();++it)
|
||||
{
|
||||
tags.emplace_back(it.key(), it.value()["commit"], it.value()["date"],
|
||||
it.value()["description"], it.value()["email"],
|
||||
it.value()["name"], 0);
|
||||
}
|
||||
|
||||
// Send data list to anyone who is interested
|
||||
emit gotMetadata(branches, obj_commits.dump(), releases, tags, default_branch, obj["web_page"]);
|
||||
break;
|
||||
}
|
||||
case RequestTypeDownload:
|
||||
{
|
||||
// It's a download
|
||||
@@ -496,7 +381,8 @@ void RemoteNetwork::prepareProgressDialog(QNetworkReply* reply, bool upload, con
|
||||
connect(reply, &QNetworkReply::downloadProgress, this, &RemoteNetwork::updateProgress);
|
||||
}
|
||||
|
||||
void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clientCert, QVariant userdata)
|
||||
void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clientCert,
|
||||
std::function<void(QByteArray)> when_finished)
|
||||
{
|
||||
// Check if network is accessible. If not, abort right here
|
||||
if(m_manager->networkAccessible() == QNetworkAccessManager::NotAccessible)
|
||||
@@ -509,6 +395,9 @@ void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clie
|
||||
QNetworkRequest request;
|
||||
request.setUrl(url);
|
||||
request.setRawHeader("User-Agent", QString("%1 %2").arg(qApp->organizationName(), APP_VERSION).toUtf8());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
|
||||
request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
|
||||
#endif
|
||||
|
||||
// Set SSL configuration when trying to access a file via the HTTPS protocol.
|
||||
// Skip this step when no client certificate was specified. In this case the default HTTPS configuration is used.
|
||||
@@ -527,7 +416,20 @@ void RemoteNetwork::fetch(const QUrl& url, RequestType type, const QString& clie
|
||||
QNetworkReply* reply = m_manager->get(request);
|
||||
reply->setProperty("type", type);
|
||||
reply->setProperty("certfile", clientCert);
|
||||
reply->setProperty("userdata", userdata);
|
||||
|
||||
// Hook up custom handler when there is one and global handler otherwise
|
||||
if(when_finished)
|
||||
{
|
||||
connect(reply, &QNetworkReply::finished, reply, [this, when_finished, reply]() {
|
||||
if(handleReply(reply))
|
||||
when_finished(reply->readAll());
|
||||
});
|
||||
} else {
|
||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||
if(handleReply(reply))
|
||||
gotReply(reply);
|
||||
});
|
||||
}
|
||||
|
||||
// Initialise the progress dialog for this request, but only if this is a database file or a download.
|
||||
// Directory listing and similar are small enough to be loaded without progress dialog.
|
||||
@@ -633,3 +535,22 @@ void RemoteNetwork::clearAccessCache(const QString& clientCert)
|
||||
m_manager->clearAccessCache();
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteNetwork::handleReply(QNetworkReply* reply)
|
||||
{
|
||||
// Check if request was successful
|
||||
if(reply->error() != QNetworkReply::NoError)
|
||||
{
|
||||
// Do not show error message when operation was cancelled on purpose
|
||||
if(reply->error() != QNetworkReply::OperationCanceledError)
|
||||
{
|
||||
QMessageBox::warning(nullptr, qApp->applicationName(),
|
||||
reply->errorString() + "\n" + reply->readAll());
|
||||
}
|
||||
|
||||
reply->deleteLater();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+7
-62
@@ -4,6 +4,7 @@
|
||||
#include <QObject>
|
||||
#include <QtNetwork/QSslConfiguration>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
class QNetworkAccessManager;
|
||||
@@ -14,52 +15,6 @@ class QNetworkRequest;
|
||||
class QHttpMultiPart;
|
||||
class QFile;
|
||||
|
||||
class RemoteMetadataBranchInfo
|
||||
{
|
||||
public:
|
||||
RemoteMetadataBranchInfo(const std::string& _name, const std::string& _commit_id, const std::string& _description, unsigned int _commit_count) :
|
||||
name(_name),
|
||||
commit_id(_commit_id),
|
||||
description(_description),
|
||||
commit_count(_commit_count)
|
||||
{}
|
||||
RemoteMetadataBranchInfo() :
|
||||
commit_count(0)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
std::string commit_id;
|
||||
std::string description;
|
||||
unsigned int commit_count;
|
||||
};
|
||||
|
||||
class RemoteMetadataReleaseInfo
|
||||
{
|
||||
public:
|
||||
RemoteMetadataReleaseInfo(const std::string& _name, const std::string& _commit_id, const std::string& _date,
|
||||
const std::string& _description, const std::string& _email,
|
||||
const std::string& _user_name, unsigned int _size) :
|
||||
name(_name),
|
||||
commit_id(_commit_id),
|
||||
date(_date),
|
||||
description(_description),
|
||||
email(_email),
|
||||
user_name(_user_name),
|
||||
size(_size)
|
||||
{}
|
||||
RemoteMetadataReleaseInfo() :
|
||||
size(0)
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
std::string commit_id;
|
||||
std::string date;
|
||||
std::string description;
|
||||
std::string email;
|
||||
std::string user_name;
|
||||
unsigned long size;
|
||||
};
|
||||
|
||||
class RemoteNetwork : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -85,17 +40,13 @@ public:
|
||||
|
||||
enum RequestType
|
||||
{
|
||||
RequestTypeCustom,
|
||||
RequestTypeDatabase,
|
||||
RequestTypeDirectory,
|
||||
RequestTypeNewVersionCheck,
|
||||
RequestTypePush,
|
||||
RequestTypeLicenceList,
|
||||
RequestTypeBranchList,
|
||||
RequestTypeMetadata,
|
||||
RequestTypeDownload,
|
||||
};
|
||||
|
||||
void fetch(const QUrl& url, RequestType type, const QString& clientCert = QString(), QVariant userdata = QVariant());
|
||||
void fetch(const QUrl& url, RequestType type, const QString& clientCert = QString(), std::function<void(QByteArray)> when_finished = {});
|
||||
void push(const QString& filename, const QUrl& url, const QString& clientCert, const QString& remotename,
|
||||
const QString& commitMessage = QString(), const QString& licence = QString(), bool isPublic = false,
|
||||
const QString& branch = QString("master"), bool forcePush = false, const QString& last_commit = QString());
|
||||
@@ -105,16 +56,6 @@ signals:
|
||||
// which might otherwise fail.
|
||||
void networkReady();
|
||||
|
||||
// These signals are emitted when the fetch() calls are finished that are not requesting a remote database but other data, like
|
||||
// a directory listing or the licence list.
|
||||
void gotDirList(QString json, QVariant userdata);
|
||||
void gotCurrentVersion(QString version, QString url);
|
||||
void gotLicenceList(std::vector<std::pair<std::string, std::string>> licences);
|
||||
void gotBranchList(std::vector<std::string> branches, std::string default_branch);
|
||||
void gotMetadata(std::vector<RemoteMetadataBranchInfo> branches, std::string commits,
|
||||
std::vector<RemoteMetadataReleaseInfo> releases, std::vector<RemoteMetadataReleaseInfo> tags,
|
||||
std::string default_branch, std::string web_page);
|
||||
|
||||
// The fetchFinished() signal is emitted when a fetch() call for a database is finished
|
||||
void fetchFinished(QString filename, QString identity, const QUrl& url, std::string new_commit_id, std::string branch,
|
||||
QDateTime last_modified, QIODevice* device);
|
||||
@@ -141,6 +82,10 @@ private:
|
||||
// object. Otherwise Qt might reuse the old certificate if the requested URL has been used before.
|
||||
void clearAccessCache(const QString& clientCert);
|
||||
|
||||
// This function is called for all network replies we get whether they are handled globally or individually.
|
||||
// It mainly does some error checking and returns true if the actual handler should be called.
|
||||
bool handleReply(QNetworkReply* reply);
|
||||
|
||||
QNetworkAccessManager* m_manager;
|
||||
QNetworkConfigurationManager* m_configurationManager;
|
||||
QProgressDialog* m_progress;
|
||||
|
||||
+55
-48
@@ -2,17 +2,20 @@
|
||||
#include <QUrlQuery>
|
||||
#include <QRegExpValidator>
|
||||
|
||||
#include <json.hpp>
|
||||
|
||||
#include "RemotePushDialog.h"
|
||||
#include "ui_RemotePushDialog.h"
|
||||
#include "RemoteNetwork.h"
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
RemotePushDialog::RemotePushDialog(QWidget* parent, const QString& host, const QString& clientCert,
|
||||
const QString& name, const QString& branch) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RemotePushDialog),
|
||||
m_host(host),
|
||||
m_clientCert(clientCert),
|
||||
m_suggestedBranch(branch),
|
||||
m_nameValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\.,\\-,\\_,\\(,\\),\\+,\\ ]+$"), this)),
|
||||
m_branchValidator(new QRegExpValidator(QRegExp("^[a-z,A-Z,0-9,\\^,\\.,\\-,\\_,\\/,\\(,\\),\\:,\\&,\\ )]+$"), this))
|
||||
{
|
||||
@@ -28,12 +31,58 @@ RemotePushDialog::RemotePushDialog(QWidget* parent, const QString& host, const Q
|
||||
checkInput();
|
||||
|
||||
// Fetch list of available licences
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::gotLicenceList, this, &RemotePushDialog::fillInLicences);
|
||||
RemoteNetwork::get().fetch(host + "licence/list", RemoteNetwork::RequestTypeLicenceList, clientCert);
|
||||
RemoteNetwork::get().fetch(host + "licence/list", RemoteNetwork::RequestTypeCustom, clientCert, [this](const QByteArray& reply) {
|
||||
// Clear licence list
|
||||
ui->comboLicence->clear();
|
||||
|
||||
// Prepare fetching list of available branches
|
||||
connect(&RemoteNetwork::get(), &RemoteNetwork::gotBranchList, this, &RemotePushDialog::fillInBranches);
|
||||
reloadBranchList();
|
||||
// Read and check results
|
||||
json obj = json::parse(reply, nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
return;
|
||||
|
||||
// Parse data and build ordered licence map: order -> (short name, long name)
|
||||
std::map<int, std::pair<std::string, std::string>> licences;
|
||||
for(auto it=obj.cbegin();it!=obj.cend();++it)
|
||||
licences.insert({it.value()["order"], {it.key(), it.value()["full_name"]}});
|
||||
|
||||
// Parse licence list and fill combo box. Show the full name to the user and use the short name as user data.
|
||||
for(auto it=licences.begin();it!=licences.end();++it)
|
||||
ui->comboLicence->addItem(QString::fromStdString(it->second.second), QString::fromStdString(it->second.first));
|
||||
});
|
||||
|
||||
// Fetch list of exsisting branches
|
||||
QUrl url(m_host + "branch/list");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("username", RemoteNetwork::get().getInfoFromClientCert(m_clientCert, RemoteNetwork::CertInfoUser));
|
||||
query.addQueryItem("folder", "/");
|
||||
query.addQueryItem("dbname", ui->editName->text());
|
||||
url.setQuery(query);
|
||||
RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeCustom, m_clientCert, [this, branch](const QByteArray& reply) {
|
||||
// Read and check results
|
||||
json obj = json::parse(reply, nullptr, false);
|
||||
if(obj.is_discarded() || !obj.is_object())
|
||||
return;
|
||||
json obj_branches = obj["branches"];
|
||||
|
||||
// Get default branch
|
||||
std::string default_branch = (obj.contains("default_branch") && !obj["default_branch"].empty()) ? obj["default_branch"] : "master";
|
||||
|
||||
// Clear branch list and add the default branch
|
||||
ui->comboBranch->clear();
|
||||
ui->comboBranch->addItem(QString::fromStdString(default_branch));
|
||||
|
||||
// Parse data and assemble branch list
|
||||
std::vector<std::string> branches;
|
||||
for(auto it=obj_branches.cbegin();it!=obj_branches.cend();++it)
|
||||
{
|
||||
if(it.key() != default_branch)
|
||||
ui->comboBranch->addItem(QString::fromStdString(it.key()));
|
||||
}
|
||||
|
||||
// If a branch was suggested, select it now
|
||||
if(!branch.isEmpty())
|
||||
ui->comboBranch->setCurrentIndex(ui->comboBranch->findText(branch));
|
||||
});
|
||||
}
|
||||
|
||||
RemotePushDialog::~RemotePushDialog()
|
||||
@@ -104,45 +153,3 @@ bool RemotePushDialog::forcePush() const
|
||||
{
|
||||
return ui->checkForce->isChecked();
|
||||
}
|
||||
|
||||
void RemotePushDialog::fillInLicences(const std::vector<std::pair<std::string, std::string>>& licences)
|
||||
{
|
||||
// Clear licence list
|
||||
ui->comboLicence->clear();
|
||||
|
||||
// Parse licence list and fill combo box. Show the full name to the user and use the short name as user data.
|
||||
for(const auto& it : licences)
|
||||
ui->comboLicence->addItem(QString::fromStdString(it.second), QString::fromStdString(it.first));
|
||||
}
|
||||
|
||||
void RemotePushDialog::fillInBranches(const std::vector<std::string>& branches, const std::string& default_branch)
|
||||
{
|
||||
// Clear branch list and add the default branch
|
||||
ui->comboBranch->clear();
|
||||
ui->comboBranch->addItem(QString::fromStdString(default_branch));
|
||||
|
||||
// Add rest of the branch list to the combo box
|
||||
for(const std::string& branch : branches)
|
||||
{
|
||||
if(branch != default_branch)
|
||||
ui->comboBranch->addItem(QString::fromStdString(branch));
|
||||
}
|
||||
|
||||
// If a branch was suggested, select it now
|
||||
if(!m_suggestedBranch.isEmpty())
|
||||
ui->comboBranch->setCurrentIndex(ui->comboBranch->findText(m_suggestedBranch));
|
||||
}
|
||||
|
||||
void RemotePushDialog::reloadBranchList()
|
||||
{
|
||||
// Assemble query URL
|
||||
QUrl url(m_host + "branch/list");
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("username", RemoteNetwork::get().getInfoFromClientCert(m_clientCert, RemoteNetwork::CertInfoUser));
|
||||
query.addQueryItem("folder", "/");
|
||||
query.addQueryItem("dbname", ui->editName->text());
|
||||
url.setQuery(query);
|
||||
|
||||
// Send request
|
||||
RemoteNetwork::get().fetch(url.toString(), RemoteNetwork::RequestTypeBranchList, m_clientCert);
|
||||
}
|
||||
|
||||
@@ -32,9 +32,6 @@ private:
|
||||
QString m_host;
|
||||
QString m_clientCert;
|
||||
|
||||
// Suggested branch to preselect
|
||||
QString m_suggestedBranch;
|
||||
|
||||
// Validators
|
||||
QRegExpValidator* m_nameValidator;
|
||||
QRegExpValidator* m_branchValidator;
|
||||
@@ -42,11 +39,6 @@ private:
|
||||
protected slots:
|
||||
void checkInput();
|
||||
void accept() override;
|
||||
|
||||
void reloadBranchList();
|
||||
|
||||
void fillInLicences(const std::vector<std::pair<std::string, std::string>>& licences);
|
||||
void fillInBranches(const std::vector<std::string>& branches, const std::string& default_branch);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user